diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f898e8827..90b882e41 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -14,7 +14,12 @@ // Set *default* container specific settings.json values on container create. "settings": {}, // Add the IDs of extensions you want installed when the container is created. - "extensions": ["dbaeumer.vscode-eslint", "svelte.svelte-vscode"], + "extensions": [ + "dbaeumer.vscode-eslint", + "svelte.svelte-vscode", + "ardenivanov.svelte-intellisense", + "Prisma.prisma" + ], // Use 'forwardPorts' to make a list of ports inside the container available locally. "forwardPorts": [3000], // Use 'postCreateCommand' to run commands after the container is created. diff --git a/.github/workflows/github-actions.yml b/.github/workflows/production-release.yml similarity index 56% rename from .github/workflows/github-actions.yml rename to .github/workflows/production-release.yml index b0b7028d6..2076895b4 100644 --- a/.github/workflows/github-actions.yml +++ b/.github/workflows/production-release.yml @@ -1,34 +1,28 @@ -name: release-coolify +name: production-release on: release: - types: published + types: [published] jobs: - make-it-coolifyed: + making-something-cool: runs-on: ubuntu-latest steps: - - - name: Checkout + - name: Checkout uses: actions/checkout@v2 - - - name: Set up QEMU + - name: Set up QEMU uses: docker/setup-qemu-action@v1 - - - name: Set up Docker Buildx + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - - name: Login to DockerHub - uses: docker/login-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - - - name: Get current package version - uses: martinbeentjes/npm-get-version-action@v1.2.3 - id: package-version - - - name: Build and push + - name: Get current package version + uses: martinbeentjes/npm-get-version-action@v1.2.3 + id: package-version + - name: Build and push uses: docker/build-push-action@v2 with: context: . @@ -37,3 +31,7 @@ jobs: tags: coollabsio/coolify:latest,coollabsio/coolify:${{steps.package-version.outputs.current-version}} cache-from: type=registry,ref=coollabsio/coolify:buildcache cache-to: type=registry,ref=coollabsio/coolify:buildcache,mode=max + - uses: sarisia/actions-status-discord@v1 + if: always() + with: + webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_CHANNEL }} diff --git a/.github/workflows/staging-release.yml b/.github/workflows/staging-release.yml new file mode 100644 index 000000000..dda360f8a --- /dev/null +++ b/.github/workflows/staging-release.yml @@ -0,0 +1,35 @@ +name: staging-release + +on: + push: + branches: + - next + +jobs: + staging-release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Set up QEMU + uses: docker/setup-qemu-action@v1 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + platforms: linux/amd64 + push: true + tags: coollabsio/coolify:next + cache-from: type=registry,ref=coollabsio/coolify:buildcache-next + cache-to: type=registry,ref=coollabsio/coolify:buildcache-next,mode=max + - uses: sarisia/actions-status-discord@v1 + if: always() + with: + webhook: ${{ secrets.DISCORD_WEBHOOK_DEV_CHANNEL }} diff --git a/apps/api/nodemon.json b/apps/api/nodemon.json index b19da37f0..796707b71 100644 --- a/apps/api/nodemon.json +++ b/apps/api/nodemon.json @@ -2,6 +2,6 @@ "watch": ["src"], "ignore": ["src/**/*.test.ts"], "ext": "ts,mjs,json,graphql", - "exec": "rimraf build && esbuild `find src \\( -name '*.ts' \\) | grep -v client/` --platform=node --outdir=build --format=cjs && node build", + "exec": "rimraf build && esbuild `find src \\( -name '*.ts' \\)` --minify=true --platform=node --outdir=build --format=cjs && node build", "legacyWatch": true } \ No newline at end of file diff --git a/apps/api/package.json b/apps/api/package.json index 8aacd775f..9a37a9366 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -15,11 +15,11 @@ }, "dependencies": { "@breejs/ts-worker": "2.0.0", - "@fastify/autoload": "5.0.0", - "@fastify/cookie": "7.0.0", + "@fastify/autoload": "5.1.0", + "@fastify/cookie": "7.1.0", "@fastify/cors": "8.0.0", "@fastify/env": "4.0.0", - "@fastify/jwt": "6.2.0", + "@fastify/jwt": "6.3.1", "@fastify/static": "6.4.0", "@iarna/toml": "2.2.5", "@prisma/client": "3.15.2", @@ -32,8 +32,8 @@ "dayjs": "1.11.3", "dockerode": "3.3.2", "dotenv-extended": "2.9.0", - "fastify": "4.2.0", - "fastify-plugin": "3.0.1", + "fastify": "4.2.1", + "fastify-plugin": "4.0.0", "generate-password": "1.7.0", "get-port": "6.1.2", "got": "12.1.0", @@ -47,11 +47,11 @@ "unique-names-generator": "4.7.1" }, "devDependencies": { - "@types/node": "18.0.3", + "@types/node": "18.0.4", "@types/node-os-utils": "1.3.0", - "@typescript-eslint/eslint-plugin": "5.30.5", - "@typescript-eslint/parser": "5.30.5", - "esbuild": "0.14.48", + "@typescript-eslint/eslint-plugin": "5.30.6", + "@typescript-eslint/parser": "5.30.6", + "esbuild": "0.14.49", "eslint": "8.19.0", "eslint-config-prettier": "8.5.0", "eslint-plugin-prettier": "4.2.1", diff --git a/apps/api/prisma/schema.prisma b/apps/api/prisma/schema.prisma index 862c34e14..8d1e0bbfe 100644 --- a/apps/api/prisma/schema.prisma +++ b/apps/api/prisma/schema.prisma @@ -313,6 +313,7 @@ model Service { umami Umami? hasura Hasura? fider Fider? + moodle Moodle? } model PlausibleAnalytics { @@ -451,3 +452,20 @@ model Fider { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } + +model Moodle { + id String @id @default(cuid()) + serviceId String @unique + defaultUsername String + defaultPassword String + defaultEmail String + mariadbUser String + mariadbPassword String + mariadbRootUser String + mariadbRootUserPassword String + mariadbDatabase String + mariadbPublicPort Int? + service Service @relation(fields: [serviceId], references: [id]) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt +} diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts index 073732c5f..e302df635 100644 --- a/apps/api/src/index.ts +++ b/apps/api/src/index.ts @@ -77,7 +77,7 @@ if (!isDev) { root: path.join(__dirname, './public'), preCompressed: true }); - fastify.setNotFoundHandler({}, function (request, reply) { + fastify.setNotFoundHandler(async function (request, reply) { if (request.raw.url && request.raw.url.startsWith('/api')) { return reply.status(404).send({ success: false diff --git a/apps/api/src/jobs/deployApplication.ts b/apps/api/src/jobs/deployApplication.ts index d553e69c9..b5dbe24d9 100644 --- a/apps/api/src/jobs/deployApplication.ts +++ b/apps/api/src/jobs/deployApplication.ts @@ -189,7 +189,7 @@ import * as buildpacks from '../lib/buildPacks'; let imageFound = false; try { await image.inspect(); - imageFound = false; + imageFound = true; } catch (error) { // } @@ -235,7 +235,7 @@ import * as buildpacks from '../lib/buildPacks'; throw new Error(`Build pack ${buildPack} not found.`); } } else { - await saveBuildLog({ line: 'Nothing changed.', buildId, applicationId }); + await saveBuildLog({ line: 'Build image already available - no rebuild required.', buildId, applicationId }); } try { await asyncExecShell(`DOCKER_HOST=${host} docker stop -t 0 ${imageId}`); diff --git a/apps/api/src/lib/common.ts b/apps/api/src/lib/common.ts index 06a06d21c..b18bfd003 100644 --- a/apps/api/src/lib/common.ts +++ b/apps/api/src/lib/common.ts @@ -14,9 +14,8 @@ import cuid from 'cuid'; import { checkContainer, getEngine, removeContainer } from './docker'; import { day } from './dayjs'; import * as serviceFields from './serviceFields' -import axios from 'axios'; -export const version = '3.1.2'; +export const version = '3.1.3'; export const isDev = process.env.NODE_ENV === 'development'; const algorithm = 'aes-256-ctr'; @@ -69,7 +68,7 @@ export const include: any = { meiliSearch: true, umami: true, hasura: true, - fider: true + fider: true, }; export const uniqueName = (): string => uniqueNamesGenerator(customConfig); @@ -112,6 +111,168 @@ export const encrypt = (text: string) => { }); } }; + +export const supportedServiceTypesAndVersions = [ + { + name: 'plausibleanalytics', + fancyName: 'Plausible Analytics', + baseImage: 'plausible/analytics', + images: ['bitnami/postgresql:13.2.0', 'yandex/clickhouse-server:21.3.2.5'], + versions: ['latest', 'stable'], + recommendedVersion: 'stable', + ports: { + main: 8000 + } + }, + { + name: 'nocodb', + fancyName: 'NocoDB', + baseImage: 'nocodb/nocodb', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 8080 + } + }, + { + name: 'minio', + fancyName: 'MinIO', + baseImage: 'minio/minio', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 9001 + } + }, + { + name: 'vscodeserver', + fancyName: 'VSCode Server', + baseImage: 'codercom/code-server', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 8080 + } + }, + { + name: 'wordpress', + fancyName: 'Wordpress', + baseImage: 'wordpress', + images: ['bitnami/mysql:5.7'], + versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'], + recommendedVersion: 'latest', + ports: { + main: 80 + } + }, + { + name: 'vaultwarden', + fancyName: 'Vaultwarden', + baseImage: 'vaultwarden/server', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 80 + } + }, + { + name: 'languagetool', + fancyName: 'LanguageTool', + baseImage: 'silviof/docker-languagetool', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 8010 + } + }, + { + name: 'n8n', + fancyName: 'n8n', + baseImage: 'n8nio/n8n', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 5678 + } + }, + { + name: 'uptimekuma', + fancyName: 'Uptime Kuma', + baseImage: 'louislam/uptime-kuma', + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 3001 + } + }, + { + name: 'ghost', + fancyName: 'Ghost', + baseImage: 'bitnami/ghost', + images: ['bitnami/mariadb'], + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 2368 + } + }, + { + name: 'meilisearch', + fancyName: 'Meilisearch', + baseImage: 'getmeili/meilisearch', + images: [], + versions: ['latest'], + recommendedVersion: 'latest', + ports: { + main: 7700 + } + }, + { + name: 'umami', + fancyName: 'Umami', + baseImage: 'ghcr.io/mikecao/umami', + images: ['postgres:12-alpine'], + versions: ['postgresql-latest'], + recommendedVersion: 'postgresql-latest', + ports: { + main: 3000 + } + }, + { + name: 'hasura', + fancyName: 'Hasura', + baseImage: 'hasura/graphql-engine', + images: ['postgres:12-alpine'], + versions: ['latest', 'v2.5.1'], + recommendedVersion: 'v2.5.1', + ports: { + main: 8080 + } + }, + { + name: 'fider', + fancyName: 'Fider', + baseImage: 'getfider/fider', + images: ['postgres:12-alpine'], + versions: ['stable'], + recommendedVersion: 'stable', + ports: { + main: 3000 + } + }, + // { + // name: 'moodle', + // fancyName: 'Moodle', + // baseImage: 'bitnami/moodle', + // images: [], + // versions: ['latest', 'v4.0.2'], + // recommendedVersion: 'latest', + // ports: { + // main: 8080 + // } + // } +]; + export async function checkDoubleBranch(branch: string, projectId: number): Promise { const applications = await prisma.application.findMany({ where: { branch, projectId } }); return applications.length > 1; @@ -308,167 +469,6 @@ export const supportedDatabaseTypesAndVersions = [ }, { name: 'couchdb', fancyName: 'CouchDB', baseImage: 'bitnami/couchdb', versions: ['3.2.1'] } ]; -export const supportedServiceTypesAndVersions = [ - { - name: 'plausibleanalytics', - fancyName: 'Plausible Analytics', - baseImage: 'plausible/analytics', - images: ['bitnami/postgresql:13.2.0', 'yandex/clickhouse-server:21.3.2.5'], - versions: ['latest', 'stable'], - recommendedVersion: 'stable', - ports: { - main: 8000 - } - }, - { - name: 'nocodb', - fancyName: 'NocoDB', - baseImage: 'nocodb/nocodb', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 8080 - } - }, - { - name: 'minio', - fancyName: 'MinIO', - baseImage: 'minio/minio', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 9001 - } - }, - { - name: 'vscodeserver', - fancyName: 'VSCode Server', - baseImage: 'codercom/code-server', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 8080 - } - }, - { - name: 'wordpress', - fancyName: 'Wordpress', - baseImage: 'wordpress', - images: ['bitnami/mysql:5.7'], - versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'], - recommendedVersion: 'latest', - ports: { - main: 80 - } - }, - { - name: 'vaultwarden', - fancyName: 'Vaultwarden', - baseImage: 'vaultwarden/server', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 80 - } - }, - { - name: 'languagetool', - fancyName: 'LanguageTool', - baseImage: 'silviof/docker-languagetool', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 8010 - } - }, - { - name: 'n8n', - fancyName: 'n8n', - baseImage: 'n8nio/n8n', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 5678 - } - }, - { - name: 'uptimekuma', - fancyName: 'Uptime Kuma', - baseImage: 'louislam/uptime-kuma', - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 3001 - } - }, - { - name: 'ghost', - fancyName: 'Ghost', - baseImage: 'bitnami/ghost', - images: ['bitnami/mariadb'], - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 2368 - } - }, - { - name: 'meilisearch', - fancyName: 'Meilisearch', - baseImage: 'getmeili/meilisearch', - images: [], - versions: ['latest'], - recommendedVersion: 'latest', - ports: { - main: 7700 - } - }, - { - name: 'umami', - fancyName: 'Umami', - baseImage: 'ghcr.io/mikecao/umami', - images: ['postgres:12-alpine'], - versions: ['postgresql-latest'], - recommendedVersion: 'postgresql-latest', - ports: { - main: 3000 - } - }, - { - name: 'hasura', - fancyName: 'Hasura', - baseImage: 'hasura/graphql-engine', - images: ['postgres:12-alpine'], - versions: ['latest', 'v2.8.3'], - recommendedVersion: 'v2.8.3', - ports: { - main: 8080 - } - }, - { - name: 'fider', - fancyName: 'Fider', - baseImage: 'getfider/fider', - images: ['postgres:12-alpine'], - versions: ['stable'], - recommendedVersion: 'stable', - ports: { - main: 3000 - } - // }, - // { - // name: 'appwrite', - // fancyName: 'AppWrite', - // baseImage: 'appwrite/appwrite', - // images: ['appwrite/influxdb', 'appwrite/telegraf', 'mariadb:10.7', 'redis:6.0-alpine3.12'], - // versions: ['latest', '0.13.0'], - // recommendedVersion: '0.13.0', - // ports: { - // main: 3000 - // } - // } - } -]; export async function startTraefikProxy(engine: string): Promise { const host = getEngine(engine); @@ -825,7 +825,7 @@ export type ComposeFileService = { context: string; dockerfile: string; args?: Record; - }; + } | string; deploy?: { restart_policy?: { condition?: string; @@ -1347,6 +1347,40 @@ export async function configureServiceType({ } } }); + } else if (type === 'moodle') { + const defaultUsername = cuid(); + const defaultPassword = encrypt(generatePassword()); + const defaultEmail = `${cuid()}@example.com`; + const mariadbUser = cuid(); + const mariadbPassword = encrypt(generatePassword()); + const mariadbDatabase = 'moodle_db'; + const mariadbRootUser = cuid(); + const mariadbRootUserPassword = encrypt(generatePassword()); + await prisma.service.update({ + where: { id }, + data: { + type, + moodle: { + create: { + defaultUsername, + defaultPassword, + defaultEmail, + mariadbUser, + mariadbPassword, + mariadbDatabase, + mariadbRootUser, + mariadbRootUserPassword + } + } + } + }); + } else { + await prisma.service.update({ + where: { id }, + data: { + type + } + }); } } @@ -1502,10 +1536,10 @@ export function convertTolOldVolumeNames(type) { return 'nc' } } -export async function getAvailableServices(): Promise { - const { data } = await axios.get(`https://gist.githubusercontent.com/andrasbacsai/4aac36d8d6214dbfc34fa78110554a50/raw/291a957ee6ac01d480465623e183a30230ad921f/availableServices.json`) - return data -} +// export async function getAvailableServices(): Promise { +// const { data } = await axios.get(`https://gist.githubusercontent.com/andrasbacsai/4aac36d8d6214dbfc34fa78110554a50/raw/5b27e6c37d78aaeedc1148d797112c827a2f43cf/availableServices.json`) +// return data +// } export async function cleanupDockerStorage(host, lowDiskSpace, force) { // Cleanup old coolify images try { diff --git a/apps/api/src/lib/serviceFields.ts b/apps/api/src/lib/serviceFields.ts index dadbc6713..7a6b00a85 100644 --- a/apps/api/src/lib/serviceFields.ts +++ b/apps/api/src/lib/serviceFields.ts @@ -15,7 +15,7 @@ export const plausibleAnalytics = [{ isNumber: false, isBoolean: false, isEncrypted: false -},{ +}, { name: 'username', isEditable: true, isLowerCase: false, @@ -86,7 +86,7 @@ export const minio = [{ isNumber: false, isBoolean: false, isEncrypted: false -},{ +}, { name: 'rootUser', isEditable: false, isLowerCase: false, @@ -325,7 +325,7 @@ export const fider = [{ isNumber: false, isBoolean: false, isEncrypted: true -},{ +}, { name: 'postgreslUser', isEditable: false, isLowerCase: false, @@ -412,4 +412,68 @@ export const fider = [{ isNumber: false, isBoolean: false, isEncrypted: false +}] +export const moodle = [{ + name: 'defaultEmail', + isEditable: true, + isLowerCase: true, + isNumber: false, + isBoolean: false, + isEncrypted: false +}, +{ + name: 'defaultUsername', + isEditable: true, + isLowerCase: false, + isNumber: false, + isBoolean: false, + isEncrypted: false +}, +{ + name: 'defaultPassword', + isEditable: false, + isLowerCase: false, + isNumber: false, + isBoolean: false, + isEncrypted: true +}, +{ + name: 'mariadbUser', + isEditable: false, + isLowerCase: false, + isNumber: false, + isBoolean: false, + isEncrypted: false +}, +{ + name: 'mariadbPassword', + isEditable: false, + isLowerCase: false, + isNumber: false, + isBoolean: false, + isEncrypted: true +}, +{ + name: 'mariadbRootUser', + isEditable: false, + isLowerCase: false, + isNumber: false, + isBoolean: false, + isEncrypted: false +}, +{ + name: 'mariadbRootUserPassword', + isEditable: false, + isLowerCase: false, + isNumber: false, + isBoolean: false, + isEncrypted: true +}, +{ + name: 'mariadbDatabase', + isEditable: true, + isLowerCase: false, + isNumber: false, + isBoolean: false, + isEncrypted: false }] \ No newline at end of file diff --git a/apps/api/src/routes/api/v1/applications/handlers.ts b/apps/api/src/routes/api/v1/applications/handlers.ts index b5e235335..5cb32db22 100644 --- a/apps/api/src/routes/api/v1/applications/handlers.ts +++ b/apps/api/src/routes/api/v1/applications/handlers.ts @@ -2,18 +2,16 @@ import cuid from 'cuid'; import crypto from 'node:crypto' import jsonwebtoken from 'jsonwebtoken'; import axios from 'axios'; -import { day } from '../../../../lib/dayjs'; - - -import type { FastifyRequest } from 'fastify'; import { FastifyReply } from 'fastify'; - -import { CheckDNS, DeleteApplication, DeployApplication, GetApplication, SaveApplication, SaveApplicationSettings } from '.'; +import { day } from '../../../../lib/dayjs'; import { setDefaultBaseImage, setDefaultConfiguration } from '../../../../lib/buildPacks/common'; import { asyncExecShell, checkDomainsIsValidInDNS, checkDoubleBranch, decrypt, encrypt, errorHandler, generateSshKeyPair, getContainerUsage, getDomain, isDev, isDomainConfigured, prisma, stopBuild, uniqueName } from '../../../../lib/common'; import { checkContainer, dockerInstance, getEngine, isContainerExited, removeContainer } from '../../../../lib/docker'; import { scheduler } from '../../../../lib/scheduler'; +import type { FastifyRequest } from 'fastify'; +import type { GetImages, CancelDeployment, CheckDNS, CheckRepository, DeleteApplication, DeleteSecret, DeleteStorage, GetApplicationLogs, GetBuildIdLogs, GetBuildLogs, SaveApplication, SaveApplicationSettings, SaveApplicationSource, SaveDeployKey, SaveDestination, SaveSecret, SaveStorage, DeployApplication } from './types'; +import { OnlyId } from '../../../../types'; export async function listApplications(request: FastifyRequest) { try { @@ -31,7 +29,7 @@ export async function listApplications(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function getImages(request: FastifyRequest) { +export async function getImages(request: FastifyRequest) { try { const { buildPack, deploymentType } = request.body let publishDirectory = undefined; @@ -65,14 +63,14 @@ export async function getImages(request: FastifyRequest) { } } -export async function getApplication(request: FastifyRequest) { +export async function getApplication(request: FastifyRequest) { try { const { id } = request.params const { teamId } = request.user const appId = process.env['COOLIFY_APP_ID']; let isRunning = false; let isExited = false; - const application = await getApplicationFromDB(id, teamId); + const application: any = await getApplicationFromDB(id, teamId); if (application?.destinationDockerId && application.destinationDocker?.engine) { isRunning = await checkContainer(application.destinationDocker.engine, id); isExited = await isContainerExited(application.destinationDocker.engine, id); @@ -281,11 +279,11 @@ export async function saveApplicationSettings(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params const { teamId } = request.user - const application = await getApplicationFromDB(id, teamId); + const application: any = await getApplicationFromDB(id, teamId); if (application?.destinationDockerId && application.destinationDocker?.engine) { const { engine } = application.destinationDocker; const found = await checkContainer(engine, id); @@ -373,8 +371,9 @@ export async function getUsage(request) { try { const { id } = request.params const teamId = request.user?.teamId; - const application = await getApplicationFromDB(id, teamId); let usage = {}; + + const application: any = await getApplicationFromDB(id, teamId); if (application.destinationDockerId) { [usage] = await Promise.all([getContainerUsage(application.destinationDocker.engine, id)]); } @@ -389,7 +388,6 @@ export async function deployApplication(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params const { gitSourceId } = request.body @@ -464,11 +462,11 @@ export async function saveApplicationSource(request: FastifyRequest, reply: Fast } } -export async function getGitHubToken(request: FastifyRequest, reply: FastifyReply) { +export async function getGitHubToken(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params const { teamId } = request.user - const application = await getApplicationFromDB(id, teamId); + const application: any = await getApplicationFromDB(id, teamId); const payload = { iat: Math.round(new Date().getTime() / 1000), exp: Math.round(new Date().getTime() / 1000 + 60), @@ -490,7 +488,7 @@ export async function getGitHubToken(request: FastifyRequest, reply: FastifyRepl } } -export async function checkRepository(request: FastifyRequest) { +export async function checkRepository(request: FastifyRequest) { try { const { id } = request.params const { repository, branch } = request.query @@ -537,7 +535,7 @@ export async function saveRepository(request, reply) { } } -export async function saveDestination(request: FastifyRequest, reply: FastifyReply) { +export async function saveDestination(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params const { destinationId } = request.body @@ -555,7 +553,7 @@ export async function getBuildPack(request) { try { const { id } = request.params const teamId = request.user?.teamId; - const application = await getApplicationFromDB(id, teamId); + const application: any = await getApplicationFromDB(id, teamId); return { type: application.gitSource.type, projectId: application.projectId, @@ -579,7 +577,7 @@ export async function saveBuildPack(request, reply) { } } -export async function getSecrets(request: FastifyRequest) { +export async function getSecrets(request: FastifyRequest) { try { const { id } = request.params let secrets = await prisma.secret.findMany({ @@ -601,7 +599,7 @@ export async function getSecrets(request: FastifyRequest) { } } -export async function saveSecret(request: FastifyRequest, reply: FastifyReply) { +export async function saveSecret(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params let { name, value, isBuildSecret, isPRMRSecret, isNew } = request.body @@ -636,7 +634,7 @@ export async function saveSecret(request: FastifyRequest, reply: FastifyReply) { return errorHandler({ status, message }) } } -export async function deleteSecret(request: FastifyRequest) { +export async function deleteSecret(request: FastifyRequest) { try { const { id } = request.params const { name } = request.body @@ -647,7 +645,7 @@ export async function deleteSecret(request: FastifyRequest) { } } -export async function getStorages(request: FastifyRequest) { +export async function getStorages(request: FastifyRequest) { try { const { id } = request.params const persistentStorages = await prisma.applicationPersistentStorage.findMany({ where: { applicationId: id } }); @@ -659,7 +657,7 @@ export async function getStorages(request: FastifyRequest) { } } -export async function saveStorage(request: FastifyRequest, reply: FastifyReply) { +export async function saveStorage(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params const { path, newStorage, storageId } = request.body @@ -680,7 +678,7 @@ export async function saveStorage(request: FastifyRequest, reply: FastifyReply) } } -export async function deleteStorage(request: FastifyRequest) { +export async function deleteStorage(request: FastifyRequest) { try { const { id } = request.params const { path } = request.body @@ -691,7 +689,7 @@ export async function deleteStorage(request: FastifyRequest) { } } -export async function getPreviews(request: FastifyRequest) { +export async function getPreviews(request: FastifyRequest) { try { const { id } = request.params const { teamId } = request.user @@ -739,7 +737,7 @@ export async function getPreviews(request: FastifyRequest) { } } -export async function getApplicationLogs(request: FastifyRequest) { +export async function getApplicationLogs(request: FastifyRequest) { try { const { id } = request.params let { since = 0 } = request.query @@ -783,7 +781,7 @@ export async function getApplicationLogs(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function getBuildLogs(request: FastifyRequest) { +export async function getBuildLogs(request: FastifyRequest) { try { const { id } = request.params let { buildId, skip = 0 } = request.query @@ -820,9 +818,9 @@ export async function getBuildLogs(request: FastifyRequest) { } } -export async function getBuildIdLogs(request: FastifyRequest) { +export async function getBuildIdLogs(request: FastifyRequest) { try { - const { id, buildId } = request.params + const { buildId } = request.params let { sequence = 0 } = request.query if (typeof sequence !== 'number') { sequence = Number(sequence) @@ -841,7 +839,7 @@ export async function getBuildIdLogs(request: FastifyRequest) { } } -export async function getGitLabSSHKey(request: FastifyRequest) { +export async function getGitLabSSHKey(request: FastifyRequest) { try { const { id } = request.params const application = await prisma.application.findUnique({ @@ -854,7 +852,7 @@ export async function getGitLabSSHKey(request: FastifyRequest) { } } -export async function saveGitLabSSHKey(request: FastifyRequest, reply: FastifyReply) { +export async function saveGitLabSSHKey(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params const application = await prisma.application.findUnique({ @@ -876,7 +874,7 @@ export async function saveGitLabSSHKey(request: FastifyRequest, reply: FastifyRe } } -export async function saveDeployKey(request: FastifyRequest, reply: FastifyReply) { +export async function saveDeployKey(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params let { deployKeyId } = request.body; @@ -896,9 +894,8 @@ export async function saveDeployKey(request: FastifyRequest, reply: FastifyReply } } -export async function cancelDeployment(request: FastifyRequest, reply: FastifyReply) { +export async function cancelDeployment(request: FastifyRequest, reply: FastifyReply) { try { - const { id } = request.params const { buildId, applicationId } = request.body; if (!buildId) { throw { status: 500, message: 'buildId is required' } diff --git a/apps/api/src/routes/api/v1/applications/index.ts b/apps/api/src/routes/api/v1/applications/index.ts index 224bacc22..aa359f973 100644 --- a/apps/api/src/routes/api/v1/applications/index.ts +++ b/apps/api/src/routes/api/v1/applications/index.ts @@ -1,90 +1,60 @@ import { FastifyPluginAsync } from 'fastify'; +import { OnlyId } from '../../../../types'; import { cancelDeployment, checkDNS, checkRepository, deleteApplication, deleteSecret, deleteStorage, deployApplication, getApplication, getApplicationLogs, getBuildIdLogs, getBuildLogs, getBuildPack, getGitHubToken, getGitLabSSHKey, getImages, getPreviews, getSecrets, getStorages, getUsage, listApplications, newApplication, saveApplication, saveApplicationSettings, saveApplicationSource, saveBuildPack, saveDeployKey, saveDestination, saveGitLabSSHKey, saveRepository, saveSecret, saveStorage, stopApplication } from './handlers'; -export interface GetApplication { - Params: { id: string; } -} +import type { CancelDeployment, CheckDNS, CheckRepository, DeleteApplication, DeleteSecret, DeleteStorage, DeployApplication, GetApplicationLogs, GetBuildIdLogs, GetBuildLogs, GetImages, SaveApplication, SaveApplicationSettings, SaveApplicationSource, SaveDeployKey, SaveDestination, SaveSecret, SaveStorage } from './types'; -export interface SaveApplication { - Params: { id: string; }, - Body: any -} - -export interface SaveApplicationSettings { - Params: { id: string; }; - Querystring: { domain: string; }; - Body: { debug: boolean; previews: boolean; dualCerts: boolean; autodeploy: boolean; branch: string; projectId: number; }; -} - -export interface DeleteApplication { - Params: { id: string; }; - Querystring: { domain: string; }; -} - -export interface CheckDNS { - Params: { id: string; }; - Querystring: { domain: string; }; -} - -export interface DeployApplication { - Params: { id: string }, - Querystring: { domain: string } - Body: { pullmergeRequestId: string | null, branch: string } -} - -const root: FastifyPluginAsync = async (fastify, opts): Promise => { - fastify.addHook('onRequest', async (request, reply) => { +const root: FastifyPluginAsync = async (fastify): Promise => { + fastify.addHook('onRequest', async (request) => { return await request.jwtVerify() }) fastify.get('/', async (request) => await listApplications(request)); - fastify.post('/images', async (request) => await getImages(request)); + fastify.post('/images', async (request) => await getImages(request)); fastify.post('/new', async (request, reply) => await newApplication(request, reply)); - fastify.get('/:id', async (request) => await getApplication(request)); + fastify.get('/:id', async (request) => await getApplication(request)); fastify.post('/:id', async (request, reply) => await saveApplication(request, reply)); fastify.delete('/:id', async (request, reply) => await deleteApplication(request, reply)); - fastify.post('/:id/stop', async (request, reply) => await stopApplication(request, reply)); + fastify.post('/:id/stop', async (request, reply) => await stopApplication(request, reply)); fastify.post('/:id/settings', async (request, reply) => await saveApplicationSettings(request, reply)); - fastify.post('/:id/check', async (request) => await checkDNS(request)); + fastify.post('/:id/check', async (request) => await checkDNS(request)); - fastify.get('/:id/secrets', async (request) => await getSecrets(request)); - fastify.post('/:id/secrets', async (request, reply) => await saveSecret(request, reply)); - fastify.delete('/:id/secrets', async (request) => await deleteSecret(request)); + fastify.get('/:id/secrets', async (request) => await getSecrets(request)); + fastify.post('/:id/secrets', async (request, reply) => await saveSecret(request, reply)); + fastify.delete('/:id/secrets', async (request) => await deleteSecret(request)); - fastify.get('/:id/storages', async (request) => await getStorages(request)); - fastify.post('/:id/storages', async (request, reply) => await saveStorage(request, reply)); - fastify.delete('/:id/storages', async (request) => await deleteStorage(request)); + fastify.get('/:id/storages', async (request) => await getStorages(request)); + fastify.post('/:id/storages', async (request, reply) => await saveStorage(request, reply)); + fastify.delete('/:id/storages', async (request) => await deleteStorage(request)); - fastify.get('/:id/previews', async (request) => await getPreviews(request)); + fastify.get('/:id/previews', async (request) => await getPreviews(request)); - fastify.get('/:id/logs', async (request) => await getApplicationLogs(request)); - fastify.get('/:id/logs/build', async (request) => await getBuildLogs(request)); - fastify.get('/:id/logs/build/:buildId', async (request) => await getBuildIdLogs(request)); + fastify.get('/:id/logs', async (request) => await getApplicationLogs(request)); + fastify.get('/:id/logs/build', async (request) => await getBuildLogs(request)); + fastify.get('/:id/logs/build/:buildId', async (request) => await getBuildIdLogs(request)); - fastify.get('/:id/usage', async (request) => await getUsage(request)) + fastify.get('/:id/usage', async (request) => await getUsage(request)) fastify.post('/:id/deploy', async (request) => await deployApplication(request)) - fastify.post('/:id/cancel', async (request, reply) => await cancelDeployment(request, reply)); + fastify.post('/:id/cancel', async (request, reply) => await cancelDeployment(request, reply)); - fastify.post('/:id/configuration/source', async (request, reply) => await saveApplicationSource(request, reply)); + fastify.post('/:id/configuration/source', async (request, reply) => await saveApplicationSource(request, reply)); - fastify.get('/:id/configuration/repository', async (request) => await checkRepository(request)); + fastify.get('/:id/configuration/repository', async (request) => await checkRepository(request)); fastify.post('/:id/configuration/repository', async (request, reply) => await saveRepository(request, reply)); - fastify.post('/:id/configuration/destination', async (request, reply) => await saveDestination(request, reply)); + fastify.post('/:id/configuration/destination', async (request, reply) => await saveDestination(request, reply)); fastify.get('/:id/configuration/buildpack', async (request) => await getBuildPack(request)); fastify.post('/:id/configuration/buildpack', async (request, reply) => await saveBuildPack(request, reply)); - fastify.get('/:id/configuration/sshkey', async (request) => await getGitLabSSHKey(request)); - fastify.post('/:id/configuration/sshkey', async (request, reply) => await saveGitLabSSHKey(request, reply)); + fastify.get('/:id/configuration/sshkey', async (request) => await getGitLabSSHKey(request)); + fastify.post('/:id/configuration/sshkey', async (request, reply) => await saveGitLabSSHKey(request, reply)); - fastify.post('/:id/configuration/deploykey', async (request, reply) => await saveDeployKey(request, reply)); + fastify.post('/:id/configuration/deploykey', async (request, reply) => await saveDeployKey(request, reply)); - - - fastify.get('/:id/configuration/githubToken', async (request, reply) => await getGitHubToken(request, reply)); + fastify.get('/:id/configuration/githubToken', async (request, reply) => await getGitHubToken(request, reply)); }; export default root; diff --git a/apps/api/src/routes/api/v1/applications/types.ts b/apps/api/src/routes/api/v1/applications/types.ts new file mode 100644 index 000000000..2d9b9913d --- /dev/null +++ b/apps/api/src/routes/api/v1/applications/types.ts @@ -0,0 +1,117 @@ +import type { OnlyId } from "../../../../types"; + +export interface SaveApplication extends OnlyId { + Body: { + name: string, + buildPack: string, + fqdn: string, + port: number, + exposePort: number, + installCommand: string, + buildCommand: string, + startCommand: string, + baseDirectory: string, + publishDirectory: string, + pythonWSGI: string, + pythonModule: string, + pythonVariable: string, + dockerFileLocation: string, + denoMainFile: string, + denoOptions: string, + baseImage: string, + baseBuildImage: string, + deploymentType: string + } +} +export interface SaveApplicationSettings extends OnlyId { + Querystring: { domain: string; }; + Body: { debug: boolean; previews: boolean; dualCerts: boolean; autodeploy: boolean; branch: string; projectId: number; }; +} +export interface DeleteApplication extends OnlyId { + Querystring: { domain: string; }; +} +export interface CheckDNS extends OnlyId { + Querystring: { domain: string; }; + Body: { + exposePort: number, + fqdn: string, + forceSave: boolean, + dualCerts: boolean + } +} +export interface DeployApplication { + Querystring: { domain: string } + Body: { pullmergeRequestId: string | null, branch: string } +} +export interface GetImages { + Body: { buildPack: string, deploymentType: string } +} +export interface SaveApplicationSource extends OnlyId { + Body: { gitSourceId: string } +} +export interface CheckRepository extends OnlyId { + Querystring: { repository: string, branch: string } +} +export interface SaveDestination extends OnlyId { + Body: { destinationId: string } +} +export interface SaveSecret extends OnlyId { + Body: { + name: string, + value: string, + isBuildSecret: boolean, + isPRMRSecret: boolean, + isNew: boolean + } +} +export interface DeleteSecret extends OnlyId { + Body: { name: string } +} +export interface SaveStorage extends OnlyId { + Body: { + path: string, + newStorage: boolean, + storageId: string + } +} +export interface DeleteStorage extends OnlyId { + Body: { + path: string, + } +} +export interface GetApplicationLogs extends OnlyId { + Querystring: { + since: number, + } +} +export interface GetBuildLogs extends OnlyId { + Querystring: { + buildId: string + skip: number, + } +} +export interface GetBuildIdLogs { + Params: { + buildId: string + }, + Querystring: { + sequence: number + } +} +export interface SaveDeployKey extends OnlyId { + Body: { + deployKeyId: number + } +} +export interface CancelDeployment { + Body: { + buildId: string, + applicationId: string + } +} +export interface DeployApplication extends OnlyId { + Body: { + pullmergeRequestId: string | null, + branch: string + } +} diff --git a/apps/api/src/routes/api/v1/base/index.ts b/apps/api/src/routes/api/v1/base/index.ts index 37972a1a7..9eaa8c40a 100644 --- a/apps/api/src/routes/api/v1/base/index.ts +++ b/apps/api/src/routes/api/v1/base/index.ts @@ -1,8 +1,8 @@ import { FastifyPluginAsync } from 'fastify'; import { errorHandler, version } from '../../../../lib/common'; -const root: FastifyPluginAsync = async (fastify, opts): Promise => { - fastify.get('/', async (request) => { +const root: FastifyPluginAsync = async (fastify): Promise => { + fastify.get('/', async () => { try { return { version, diff --git a/apps/api/src/routes/api/v1/databases/handlers.ts b/apps/api/src/routes/api/v1/databases/handlers.ts index 52110b8b7..8d05bb3a5 100644 --- a/apps/api/src/routes/api/v1/databases/handlers.ts +++ b/apps/api/src/routes/api/v1/databases/handlers.ts @@ -6,10 +6,11 @@ import fs from 'fs/promises'; import { asyncExecShell, ComposeFile, createDirectories, decrypt, encrypt, errorHandler, generateDatabaseConfiguration, generatePassword, getContainerUsage, getDatabaseImage, getDatabaseVersions, getFreePort, listSettings, makeLabelForStandaloneDatabase, prisma, startTcpProxy, startTraefikTCPProxy, stopDatabaseContainer, stopTcpHttpProxy, supportedDatabaseTypesAndVersions, uniqueName, updatePasswordInDb } from '../../../../lib/common'; import { dockerInstance, getEngine } from '../../../../lib/docker'; import { day } from '../../../../lib/dayjs'; +import { GetDatabaseLogs, OnlyId, SaveDatabase, SaveDatabaseDestination, SaveDatabaseSettings, SaveVersion } from '../../../../types'; +import { SaveDatabaseType } from './types'; export async function listDatabases(request: FastifyRequest) { try { - const userId = request.user.userId; const teamId = request.user.teamId; let databases = [] if (teamId === '0') { @@ -55,7 +56,7 @@ export async function newDatabase(request: FastifyRequest, reply: FastifyReply) return errorHandler({ status, message }) } } -export async function getDatabase(request: FastifyRequest) { +export async function getDatabase(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -107,7 +108,7 @@ export async function getDatabaseTypes(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function saveDatabaseType(request: FastifyRequest, reply: FastifyReply) { +export async function saveDatabaseType(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params; const { type } = request.body; @@ -120,7 +121,7 @@ export async function saveDatabaseType(request: FastifyRequest, reply: FastifyRe return errorHandler({ status, message }) } } -export async function getVersions(request: FastifyRequest) { +export async function getVersions(request: FastifyRequest) { try { const teamId = request.user.teamId; const { id } = request.params; @@ -135,7 +136,7 @@ export async function getVersions(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function saveVersion(request: FastifyRequest, reply: FastifyReply) { +export async function saveVersion(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params; const { version } = request.body; @@ -144,7 +145,6 @@ export async function saveVersion(request: FastifyRequest, reply: FastifyReply) where: { id }, data: { version, - } }); return reply.code(201).send({}) @@ -152,7 +152,7 @@ export async function saveVersion(request: FastifyRequest, reply: FastifyReply) return errorHandler({ status, message }) } } -export async function saveDatabaseDestination(request: FastifyRequest, reply: FastifyReply) { +export async function saveDatabaseDestination(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params; const { destinationId } = request.body; @@ -181,7 +181,7 @@ export async function saveDatabaseDestination(request: FastifyRequest, reply: Fa return errorHandler({ status, message }) } } -export async function getDatabaseUsage(request: FastifyRequest) { +export async function getDatabaseUsage(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -203,7 +203,7 @@ export async function getDatabaseUsage(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function startDatabase(request: FastifyRequest) { +export async function startDatabase(request: FastifyRequest) { try { const teamId = request.user.teamId; const { id } = request.params; @@ -226,7 +226,6 @@ export async function startDatabase(request: FastifyRequest) { const network = destinationDockerId && destinationDocker.network; const host = getEngine(destinationDocker.engine); - const engine = destinationDocker.engine; const volumeName = volume.split(':')[0]; const labels = await makeLabelForStandaloneDatabase({ id, image, volume }); @@ -285,7 +284,7 @@ export async function startDatabase(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function stopDatabase(request: FastifyRequest) { +export async function stopDatabase(request: FastifyRequest) { try { const teamId = request.user.teamId; const { id } = request.params; @@ -310,7 +309,7 @@ export async function stopDatabase(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function getDatabaseLogs(request: FastifyRequest) { +export async function getDatabaseLogs(request: FastifyRequest) { try { const teamId = request.user.teamId; const { id } = request.params; @@ -361,7 +360,7 @@ export async function getDatabaseLogs(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function deleteDatabase(request: FastifyRequest) { +export async function deleteDatabase(request: FastifyRequest) { try { const teamId = request.user.teamId; const { id } = request.params; @@ -382,7 +381,7 @@ export async function deleteDatabase(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function saveDatabase(request: FastifyRequest, reply: FastifyReply) { +export async function saveDatabase(request: FastifyRequest, reply: FastifyReply) { try { const teamId = request.user.teamId; const { id } = request.params; @@ -428,7 +427,7 @@ export async function saveDatabase(request: FastifyRequest, reply: FastifyReply) return errorHandler({ status, message }) } } -export async function saveDatabaseSettings(request: FastifyRequest) { +export async function saveDatabaseSettings(request: FastifyRequest) { try { const teamId = request.user.teamId; const { id } = request.params; diff --git a/apps/api/src/routes/api/v1/databases/index.ts b/apps/api/src/routes/api/v1/databases/index.ts index cd4a8c159..0c52938f8 100644 --- a/apps/api/src/routes/api/v1/databases/index.ts +++ b/apps/api/src/routes/api/v1/databases/index.ts @@ -1,32 +1,35 @@ import { FastifyPluginAsync } from 'fastify'; import { deleteDatabase, getDatabase, getDatabaseLogs, getDatabaseTypes, getDatabaseUsage, getVersions, listDatabases, newDatabase, saveDatabase, saveDatabaseDestination, saveDatabaseSettings, saveDatabaseType, saveVersion, startDatabase, stopDatabase } from './handlers'; -const root: FastifyPluginAsync = async (fastify, opts): Promise => { - fastify.addHook('onRequest', async (request, reply) => { +import type { GetDatabaseLogs, OnlyId, SaveDatabase, SaveDatabaseDestination, SaveDatabaseSettings, SaveVersion } from '../../../../types'; +import type { SaveDatabaseType } from './types'; + +const root: FastifyPluginAsync = async (fastify): Promise => { + fastify.addHook('onRequest', async (request) => { return await request.jwtVerify() }) fastify.get('/', async (request) => await listDatabases(request)); fastify.post('/new', async (request, reply) => await newDatabase(request, reply)); - fastify.get('/:id', async (request) => await getDatabase(request)); - fastify.post('/:id', async (request, reply) => await saveDatabase(request, reply)); - fastify.delete('/:id', async (request) => await deleteDatabase(request)); + fastify.get('/:id', async (request) => await getDatabase(request)); + fastify.post('/:id', async (request, reply) => await saveDatabase(request, reply)); + fastify.delete('/:id', async (request) => await deleteDatabase(request)); - fastify.post('/:id/settings', async (request) => await saveDatabaseSettings(request)); + fastify.post('/:id/settings', async (request) => await saveDatabaseSettings(request)); fastify.get('/:id/configuration/type', async (request) => await getDatabaseTypes(request)); - fastify.post('/:id/configuration/type', async (request, reply) => await saveDatabaseType(request, reply)); + fastify.post('/:id/configuration/type', async (request, reply) => await saveDatabaseType(request, reply)); - fastify.get('/:id/configuration/version', async (request) => await getVersions(request)); - fastify.post('/:id/configuration/version', async (request, reply) => await saveVersion(request, reply)); + fastify.get('/:id/configuration/version', async (request) => await getVersions(request)); + fastify.post('/:id/configuration/version', async (request, reply) => await saveVersion(request, reply)); - fastify.post('/:id/configuration/destination', async (request, reply) => await saveDatabaseDestination(request, reply)); + fastify.post('/:id/configuration/destination', async (request, reply) => await saveDatabaseDestination(request, reply)); - fastify.get('/:id/usage', async (request) => await getDatabaseUsage(request)); - fastify.get('/:id/logs', async (request) => await getDatabaseLogs(request)); + fastify.get('/:id/usage', async (request) => await getDatabaseUsage(request)); + fastify.get('/:id/logs', async (request) => await getDatabaseLogs(request)); - fastify.post('/:id/start', async (request) => await startDatabase(request)); - fastify.post('/:id/stop', async (request) => await stopDatabase(request)); + fastify.post('/:id/start', async (request) => await startDatabase(request)); + fastify.post('/:id/stop', async (request) => await stopDatabase(request)); }; export default root; diff --git a/apps/api/src/routes/api/v1/databases/types.ts b/apps/api/src/routes/api/v1/databases/types.ts new file mode 100644 index 000000000..b7e4c8692 --- /dev/null +++ b/apps/api/src/routes/api/v1/databases/types.ts @@ -0,0 +1,5 @@ +import type { OnlyId } from "../../../../types"; + +export interface SaveDatabaseType extends OnlyId { + Body: { type: string } +} \ No newline at end of file diff --git a/apps/api/src/routes/api/v1/destinations/handlers.ts b/apps/api/src/routes/api/v1/destinations/handlers.ts index dfc7f16ef..40d68a84b 100644 --- a/apps/api/src/routes/api/v1/destinations/handlers.ts +++ b/apps/api/src/routes/api/v1/destinations/handlers.ts @@ -3,6 +3,9 @@ import { FastifyReply } from 'fastify'; import { asyncExecShell, errorHandler, listSettings, prisma, startCoolifyProxy, startTraefikProxy, stopTraefikProxy } from '../../../../lib/common'; import { checkContainer, dockerInstance, getEngine } from '../../../../lib/docker'; +import type { OnlyId } from '../../../../types'; +import type { CheckDestination, NewDestination, Proxy, SaveDestinationSettings } from './types'; + export async function listDestinations(request: FastifyRequest) { try { const teamId = request.user.teamId; @@ -22,7 +25,7 @@ export async function listDestinations(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function checkDestination(request: FastifyRequest) { +export async function checkDestination(request: FastifyRequest) { try { const { network } = request.body; const found = await prisma.destinationDocker.findFirst({ where: { network } }); @@ -36,7 +39,7 @@ export async function checkDestination(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function getDestination(request: FastifyRequest) { +export async function getDestination(request: FastifyRequest) { try { const { id } = request.params const teamId = request.user?.teamId; @@ -74,7 +77,7 @@ export async function getDestination(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function newDestination(request: FastifyRequest, reply: FastifyReply) { +export async function newDestination(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params let { name, network, engine, isCoolifyProxyUsed } = request.body @@ -119,7 +122,7 @@ export async function newDestination(request: FastifyRequest, reply: FastifyRepl return errorHandler({ status, message }) } } -export async function deleteDestination(request: FastifyRequest) { +export async function deleteDestination(request: FastifyRequest) { try { const { id } = request.params const destination = await prisma.destinationDocker.delete({ where: { id } }); @@ -143,7 +146,7 @@ export async function deleteDestination(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function saveDestinationSettings(request: FastifyRequest, reply: FastifyReply) { +export async function saveDestinationSettings(request: FastifyRequest) { try { const { engine, isCoolifyProxyUsed } = request.body; await prisma.destinationDocker.updateMany({ @@ -159,7 +162,7 @@ export async function saveDestinationSettings(request: FastifyRequest, reply: Fa return errorHandler({ status, message }) } } -export async function startProxy(request: FastifyRequest, reply: FastifyReply) { +export async function startProxy(request: FastifyRequest) { const { engine } = request.body; try { await startTraefikProxy(engine); @@ -169,19 +172,16 @@ export async function startProxy(request: FastifyRequest, reply: FastifyReply) { return errorHandler({ status, message }) } } -export async function stopProxy(request: FastifyRequest, reply: FastifyReply) { - const settings = await prisma.setting.findFirst({}); +export async function stopProxy(request: FastifyRequest) { const { engine } = request.body; try { await stopTraefikProxy(engine); - return {} } catch ({ status, message }) { return errorHandler({ status, message }) } } -export async function restartProxy(request: FastifyRequest, reply: FastifyReply) { - const settings = await prisma.setting.findFirst({}); +export async function restartProxy(request: FastifyRequest) { const { engine } = request.body; try { await stopTraefikProxy(engine); diff --git a/apps/api/src/routes/api/v1/destinations/index.ts b/apps/api/src/routes/api/v1/destinations/index.ts index 0e395a787..43440cc1c 100644 --- a/apps/api/src/routes/api/v1/destinations/index.ts +++ b/apps/api/src/routes/api/v1/destinations/index.ts @@ -1,24 +1,24 @@ import { FastifyPluginAsync } from 'fastify'; import { checkDestination, deleteDestination, getDestination, listDestinations, newDestination, restartProxy, saveDestinationSettings, startProxy, stopProxy } from './handlers'; -const root: FastifyPluginAsync = async (fastify, opts): Promise => { - fastify.addHook('onRequest', async (request, reply) => { +import type { OnlyId } from '../../../../types'; +import type { CheckDestination, NewDestination, Proxy, SaveDestinationSettings } from './types'; + +const root: FastifyPluginAsync = async (fastify): Promise => { + fastify.addHook('onRequest', async (request) => { return await request.jwtVerify() }) fastify.get('/', async (request) => await listDestinations(request)); - fastify.post('/check', async (request) => await checkDestination(request)); - - fastify.get('/:id', async (request) => await getDestination(request)); - fastify.post('/:id', async (request, reply) => await newDestination(request, reply)); - fastify.delete('/:id', async (request) => await deleteDestination(request)); - - fastify.post('/:id/settings', async (request, reply) => await saveDestinationSettings(request, reply)); - fastify.post('/:id/start', async (request, reply) => await startProxy(request, reply)); - fastify.post('/:id/stop', async (request, reply) => await stopProxy(request, reply)); - fastify.post('/:id/restart', async (request, reply) => await restartProxy(request, reply)); - + fastify.post('/check', async (request) => await checkDestination(request)); + fastify.get('/:id', async (request) => await getDestination(request)); + fastify.post('/:id', async (request, reply) => await newDestination(request, reply)); + fastify.delete('/:id', async (request) => await deleteDestination(request)); + fastify.post('/:id/settings', async (request, reply) => await saveDestinationSettings(request)); + fastify.post('/:id/start', async (request, reply) => await startProxy(request)); + fastify.post('/:id/stop', async (request, reply) => await stopProxy(request)); + fastify.post('/:id/restart', async (request, reply) => await restartProxy(request)); }; export default root; diff --git a/apps/api/src/routes/api/v1/destinations/types.ts b/apps/api/src/routes/api/v1/destinations/types.ts new file mode 100644 index 000000000..25691b9d8 --- /dev/null +++ b/apps/api/src/routes/api/v1/destinations/types.ts @@ -0,0 +1,26 @@ +import { OnlyId } from "../../../../types" + +export interface CheckDestination { + Body: { + network: string + } +} +export interface NewDestination extends OnlyId { + Body: { + name: string + network: string + engine: string + isCoolifyProxyUsed: boolean + } +} +export interface SaveDestinationSettings extends OnlyId { + Body: { + engine: string + isCoolifyProxyUsed: boolean + } +} +export interface Proxy extends OnlyId { + Body: { + engine: string + } +} \ No newline at end of file diff --git a/apps/api/src/routes/api/v1/handlers.ts b/apps/api/src/routes/api/v1/handlers.ts index c76181294..4b62f3845 100644 --- a/apps/api/src/routes/api/v1/handlers.ts +++ b/apps/api/src/routes/api/v1/handlers.ts @@ -8,7 +8,7 @@ import { asyncExecShell, asyncSleep, cleanupDockerStorage, errorHandler, isDev, import type { FastifyReply, FastifyRequest } from 'fastify'; import type { Login, Update } from '.'; - +import type { GetCurrentUser } from './types'; export async function hashPassword(password: string): Promise { const saltRounds = 15; @@ -25,17 +25,18 @@ export async function cleanupManually() { } export async function checkUpdate(request: FastifyRequest) { try { + const isStaging = request.hostname === 'staging.coolify.io' const currentVersion = version; const { data: versions } = await axios.get( `https://get.coollabs.io/versions.json?appId=${process.env['COOLIFY_APP_ID']}&version=${currentVersion}` ); const latestVersion = - request.hostname === 'staging.coolify.io' + isStaging ? versions['coolify'].next.version : versions['coolify'].main.version; const isUpdateAvailable = compare(latestVersion, currentVersion); return { - isUpdateAvailable: isUpdateAvailable === 1, + isUpdateAvailable: isStaging ? true : isUpdateAvailable === 1, latestVersion }; } catch ({ status, message }) { @@ -253,9 +254,9 @@ export async function login(request: FastifyRequest, reply: FastifyReply) } } -export async function getCurrentUser(request: FastifyRequest, fastify) { +export async function getCurrentUser(request: FastifyRequest, fastify) { let token = null - + const { teamId } = request.query try { const user = await prisma.user.findUnique({ where: { id: request.user.userId } @@ -266,17 +267,17 @@ export async function getCurrentUser(request: FastifyRequest, fastify) { } catch (error) { throw { status: 401, message: error }; } - if (request.query.teamId) { + if (teamId) { try { const user = await prisma.user.findFirst({ - where: { id: request.user.userId, teams: { some: { id: request.query.teamId } } }, + where: { id: request.user.userId, teams: { some: { id: teamId } } }, include: { teams: true, permission: true } }) if (user) { - const permission = user.permission.find(p => p.teamId === request.query.teamId).permission + const permission = user.permission.find(p => p.teamId === teamId).permission const payload = { ...request.user, - teamId: request.query.teamId, + teamId, permission: permission || null, isAdmin: permission === 'owner' || permission === 'admin' diff --git a/apps/api/src/routes/api/v1/iam/handlers.ts b/apps/api/src/routes/api/v1/iam/handlers.ts index 0e3668f64..7009ec794 100644 --- a/apps/api/src/routes/api/v1/iam/handlers.ts +++ b/apps/api/src/routes/api/v1/iam/handlers.ts @@ -3,6 +3,10 @@ import type { FastifyRequest } from 'fastify'; import { FastifyReply } from 'fastify'; import { decrypt, errorHandler, prisma, uniqueName } from '../../../../lib/common'; import { day } from '../../../../lib/dayjs'; + +import type { OnlyId } from '../../../../types'; +import type { BodyId, InviteToTeam, SaveTeam, SetPermission } from './types'; + export async function listTeams(request: FastifyRequest) { try { const userId = request.user.userId; @@ -36,7 +40,7 @@ export async function listTeams(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function deleteTeam(request: FastifyRequest, reply: FastifyReply) { +export async function deleteTeam(request: FastifyRequest, reply: FastifyReply) { try { const userId = request.user.userId; const { id } = request.params; @@ -136,7 +140,7 @@ export async function newTeam(request: FastifyRequest, reply: FastifyReply) { return errorHandler({ status, message }) } } -export async function getTeam(request: FastifyRequest, reply: FastifyReply) { +export async function getTeam(request: FastifyRequest, reply: FastifyReply) { try { const userId = request.user.userId; const teamId = request.user.teamId; @@ -163,7 +167,7 @@ export async function getTeam(request: FastifyRequest, reply: FastifyReply) { return errorHandler({ status, message }) } } -export async function saveTeam(request: FastifyRequest, reply: FastifyReply) { +export async function saveTeam(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params; const { name } = request.body; @@ -263,7 +267,7 @@ export async function saveTeam(request: FastifyRequest, reply: FastifyReply) { // } // } -export async function inviteToTeam(request: FastifyRequest, reply: FastifyReply) { +export async function inviteToTeam(request: FastifyRequest, reply: FastifyReply) { try { const userId = request.user.userId; const { email, permission, teamId, teamName } = request.body; @@ -306,7 +310,7 @@ export async function inviteToTeam(request: FastifyRequest, reply: FastifyReply) } } -export async function acceptInvitation(request: FastifyRequest) { +export async function acceptInvitation(request: FastifyRequest) { try { const userId = request.user.userId; const { id } = request.body; @@ -331,7 +335,7 @@ export async function acceptInvitation(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function revokeInvitation(request: FastifyRequest) { +export async function revokeInvitation(request: FastifyRequest) { try { const { id } = request.body await prisma.teamInvitation.delete({ where: { id } }); @@ -341,15 +345,15 @@ export async function revokeInvitation(request: FastifyRequest) { } } -export async function removeUser(request: FastifyRequest, reply: FastifyReply) { +export async function removeUser(request: FastifyRequest, reply: FastifyReply) { try { - const { uid } = request.body; - const user = await prisma.user.findUnique({ where: { id: uid }, include: { teams: true, permission: true } }); + const { id } = request.body; + const user = await prisma.user.findUnique({ where: { id }, include: { teams: true, permission: true } }); if (user) { const permissions = user.permission; if (permissions.length > 0) { for (const permission of permissions) { - await prisma.permission.deleteMany({ where: { id: permission.id, userId: uid } }); + await prisma.permission.deleteMany({ where: { id: permission.id, userId: id } }); } } const teams = user.teams; @@ -357,7 +361,7 @@ export async function removeUser(request: FastifyRequest, reply: FastifyReply) { for (const team of teams) { const newTeam = await prisma.team.update({ where: { id: team.id }, - data: { users: { disconnect: { id: uid } } }, + data: { users: { disconnect: { id } } }, include: { applications: true, database: true, gitHubApps: true, gitLabApps: true, gitSources: true, destinationDocker: true, service: true, users: true } }); if (newTeam.users.length === 0) { @@ -422,14 +426,14 @@ export async function removeUser(request: FastifyRequest, reply: FastifyReply) { } } } - await prisma.user.delete({ where: { id: uid } }); + await prisma.user.delete({ where: { id } }); return reply.code(201).send() } catch ({ status, message }) { return errorHandler({ status, message }) } } -export async function setPermission(request: FastifyRequest, reply: FastifyReply) { +export async function setPermission(request: FastifyRequest, reply: FastifyReply) { try { const { userId, newPermission, permissionId } = request.body; await prisma.permission.updateMany({ @@ -442,7 +446,7 @@ export async function setPermission(request: FastifyRequest, reply: FastifyReply } } -export async function changePassword(request: FastifyRequest, reply: FastifyReply) { +export async function changePassword(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.body; await prisma.user.update({ where: { id }, data: { password: 'RESETME' } }); diff --git a/apps/api/src/routes/api/v1/iam/index.ts b/apps/api/src/routes/api/v1/iam/index.ts index d82c39878..539586b2d 100644 --- a/apps/api/src/routes/api/v1/iam/index.ts +++ b/apps/api/src/routes/api/v1/iam/index.ts @@ -1,27 +1,28 @@ import { FastifyPluginAsync } from 'fastify'; import { acceptInvitation, changePassword, deleteTeam, getTeam, inviteToTeam, listTeams, newTeam, removeUser, revokeInvitation, saveTeam, setPermission } from './handlers'; +import type { OnlyId } from '../../../../types'; +import type { BodyId, InviteToTeam, SaveTeam, SetPermission } from './types'; -const root: FastifyPluginAsync = async (fastify, opts): Promise => { - fastify.addHook('onRequest', async (request, reply) => { +const root: FastifyPluginAsync = async (fastify): Promise => { + fastify.addHook('onRequest', async (request) => { return await request.jwtVerify() }) fastify.get('/', async (request) => await listTeams(request)); fastify.post('/new', async (request, reply) => await newTeam(request, reply)); - fastify.get('/team/:id', async (request, reply) => await getTeam(request, reply)); - fastify.post('/team/:id', async (request, reply) => await saveTeam(request, reply)); - fastify.delete('/team/:id', async (request, reply) => await deleteTeam(request, reply)); + fastify.get('/team/:id', async (request, reply) => await getTeam(request, reply)); + fastify.post('/team/:id', async (request, reply) => await saveTeam(request, reply)); + fastify.delete('/team/:id', async (request, reply) => await deleteTeam(request, reply)); - fastify.post('/team/:id/invitation/invite', async (request, reply) => await inviteToTeam(request, reply)) - fastify.post('/team/:id/invitation/accept', async (request) => await acceptInvitation(request)); - fastify.post('/team/:id/invitation/revoke', async (request) => await revokeInvitation(request)); + fastify.post('/team/:id/invitation/invite', async (request, reply) => await inviteToTeam(request, reply)) + fastify.post('/team/:id/invitation/accept', async (request) => await acceptInvitation(request)); + fastify.post('/team/:id/invitation/revoke', async (request) => await revokeInvitation(request)); + fastify.post('/team/:id/permission', async (request, reply) => await setPermission(request, reply)); - fastify.post('/team/:id/permission', async (request, reply) => await setPermission(request, reply)); - - fastify.delete('/user/remove', async (request, reply) => await removeUser(request, reply)); - fastify.post('/user/password', async (request, reply) => await changePassword(request, reply)); + fastify.delete('/user/remove', async (request, reply) => await removeUser(request, reply)); + fastify.post('/user/password', async (request, reply) => await changePassword(request, reply)); // fastify.delete('/user', async (request, reply) => await deleteUser(request, reply)); }; diff --git a/apps/api/src/routes/api/v1/iam/types.ts b/apps/api/src/routes/api/v1/iam/types.ts new file mode 100644 index 000000000..26a896b8e --- /dev/null +++ b/apps/api/src/routes/api/v1/iam/types.ts @@ -0,0 +1,27 @@ +import { OnlyId } from "../../../../types" + +export interface SaveTeam extends OnlyId { + Body: { + name: string + } +} +export interface InviteToTeam { + Body: { + email: string, + permission: string, + teamId: string, + teamName: string + } +} +export interface BodyId { + Body: { + id: string + } +} +export interface SetPermission { + Body: { + userId: string, + newPermission: string, + permissionId: string + } +} \ No newline at end of file diff --git a/apps/api/src/routes/api/v1/index.ts b/apps/api/src/routes/api/v1/index.ts index ef81b5792..0d145312d 100644 --- a/apps/api/src/routes/api/v1/index.ts +++ b/apps/api/src/routes/api/v1/index.ts @@ -1,6 +1,6 @@ import { FastifyPluginAsync } from 'fastify'; -import { scheduler } from '../../../lib/scheduler'; import { checkUpdate, login, showDashboard, update, showUsage, getCurrentUser, cleanupManually } from './handlers'; +import { GetCurrentUser } from './types'; export interface Update { Body: { latestVersion: string } @@ -9,7 +9,7 @@ export interface Login { Body: { email: string, password: string, isLogin: boolean } } -const root: FastifyPluginAsync = async (fastify, opts): Promise => { +const root: FastifyPluginAsync = async (fastify): Promise => { fastify.get('/', async function (_request, reply) { return reply.redirect(302, '/'); }); @@ -19,7 +19,7 @@ const root: FastifyPluginAsync = async (fastify, opts): Promise => { return { token, payload } }); - fastify.get('/user', { + fastify.get('/user', { onRequest: [fastify.authenticate] }, async (request) => await getCurrentUser(request, fastify)); diff --git a/apps/api/src/routes/api/v1/services/handlers.ts b/apps/api/src/routes/api/v1/services/handlers.ts index e2fa3404a..74658fc47 100644 --- a/apps/api/src/routes/api/v1/services/handlers.ts +++ b/apps/api/src/routes/api/v1/services/handlers.ts @@ -2,78 +2,148 @@ import type { FastifyReply, FastifyRequest } from 'fastify'; import fs from 'fs/promises'; import yaml from 'js-yaml'; import bcrypt from 'bcryptjs'; -import { prisma, uniqueName, asyncExecShell, getServiceImage, getServiceImages, configureServiceType, getServiceFromDB, getContainerUsage, removeService, isDomainConfigured, saveUpdateableFields, fixType, decrypt, encrypt, getServiceMainPort, createDirectories, ComposeFile, makeLabelForServices, getFreePort, getDomain, errorHandler, supportedServiceTypesAndVersions, generatePassword, isDev, stopTcpHttpProxy, getAvailableServices } from '../../../../lib/common'; +import { prisma, uniqueName, asyncExecShell, getServiceImage, getServiceImages, configureServiceType, getServiceFromDB, getContainerUsage, removeService, isDomainConfigured, saveUpdateableFields, fixType, decrypt, encrypt, getServiceMainPort, createDirectories, ComposeFile, makeLabelForServices, getFreePort, getDomain, errorHandler, generatePassword, isDev, stopTcpHttpProxy, supportedServiceTypesAndVersions } from '../../../../lib/common'; import { day } from '../../../../lib/dayjs'; import { checkContainer, dockerInstance, getEngine, removeContainer } from '../../../../lib/docker'; import cuid from 'cuid'; -async function startServiceNew(request: FastifyRequest) { - try { - const { id } = request.params; - const teamId = request.user.teamId; - const service = await getServiceFromDB({ id, teamId }); - const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } = - service; - const network = destinationDockerId && destinationDocker.network; - const host = getEngine(destinationDocker.engine); - const port = getServiceMainPort(type); +import type { OnlyId } from '../../../../types'; +import type { ActivateWordpressFtp, CheckService, DeleteServiceSecret, DeleteServiceStorage, GetServiceLogs, SaveService, SaveServiceDestination, SaveServiceSecret, SaveServiceSettings, SaveServiceStorage, SaveServiceType, SaveServiceVersion, ServiceStartStop, SetWordpressSettings } from './types'; - const { workdir } = await createDirectories({ repository: type, buildId: id }); - const image = getServiceImage(type); - const config = (await getAvailableServices()).find((name) => name.name === type).compose - const environmentVariables = {} - if (serviceSecret.length > 0) { - serviceSecret.forEach((secret) => { - environmentVariables[secret.name] = secret.value; - }); - } - config.services[id] = JSON.parse(JSON.stringify(config.services[type])) - config.services[id].container_name = id - config.services[id].image = `${image}:${version}` - config.services[id].ports = (exposePort ? [`${exposePort}:${port}`] : []), - config.services[id].restart = "always" - config.services[id].networks = [network] - config.services[id].labels = makeLabelForServices(type) - config.services[id].deploy = { - restart_policy: { - condition: 'on-failure', - delay: '5s', - max_attempts: 3, - window: '120s' - } - } - config.networks = { - [network]: { - external: true - } - } - config.volumes = {} - config.services[id].volumes.forEach((volume, index) => { - let oldVolumeName = volume.split(':')[0] - const path = volume.split(':')[1] - oldVolumeName = convertTolOldVolumeNames(type) - const volumeName = `${id}-${oldVolumeName}` - config.volumes[volumeName] = { - name: volumeName - } - config.services[id].volumes[index] = `${volumeName}:${path}` - }) - delete config.services[type] - config.services[id].environment = environmentVariables - const composeFileDestination = `${workdir}/docker-compose.yaml`; - await fs.writeFile(composeFileDestination, yaml.dump(config)); - await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`); - await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); - return {} - } catch ({ status, message }) { - return errorHandler({ status, message }) - } -} +// async function startServiceNew(request: FastifyRequest) { +// try { +// const { id } = request.params; +// const teamId = request.user.teamId; +// const service = await getServiceFromDB({ id, teamId }); +// const { type, version, destinationDockerId, destinationDocker, serviceSecret, exposePort } = +// service; +// const network = destinationDockerId && destinationDocker.network; +// const host = getEngine(destinationDocker.engine); +// const port = getServiceMainPort(type); +// const { workdir } = await createDirectories({ repository: type, buildId: id }); +// const image = getServiceImage(type); +// const config = (await getAvailableServices()).find((name) => name.name === type).compose +// const environmentVariables = {} +// if (serviceSecret.length > 0) { +// serviceSecret.forEach((secret) => { +// environmentVariables[secret.name] = secret.value; +// }); +// } +// config.newVolumes = {} +// for (const service of Object.entries(config.services)) { +// const name = service[0] +// const details: any = service[1] +// config.services[`${id}-${name}`] = JSON.parse(JSON.stringify(details)) +// config.services[`${id}-${name}`].container_name = `${id}-${name}` +// config.services[`${id}-${name}`].restart = "always" +// config.services[`${id}-${name}`].networks = [network] +// config.services[`${id}-${name}`].labels = makeLabelForServices(type) +// if (name === config.name) { +// config.services[`${id}-${name}`].image = `${details.image.split(':')[0]}:${version}` +// config.services[`${id}-${name}`].ports = (exposePort ? [`${exposePort}:${port}`] : []) +// config.services[`${id}-${name}`].environment = environmentVariables +// } +// config.services[`${id}-${name}`].deploy = { +// restart_policy: { +// condition: 'on-failure', +// delay: '5s', +// max_attempts: 3, +// window: '120s' +// } +// } +// if (config.services[`${id}-${name}`]?.volumes?.length > 0) { +// config.services[`${id}-${name}`].volumes.forEach((volume, index) => { +// let oldVolumeName = volume.split(':')[0] +// const path = volume.split(':')[1] +// // if (config?.volumes[oldVolumeName]) delete config?.volumes[oldVolumeName] +// const newName = convertTolOldVolumeNames(type) +// if (newName) oldVolumeName = newName + +// const volumeName = `${id}-${oldVolumeName}` +// config.newVolumes[volumeName] = { +// name: volumeName +// } +// config.services[`${id}-${name}`].volumes[index] = `${volumeName}:${path}` +// }) +// config.services[`${id}-${config.name}`] = { +// ...config.services[`${id}-${config.name}`], +// environment: environmentVariables +// } +// } +// config.networks = { +// [network]: { +// external: true +// } +// } + +// config.volumes = config.newVolumes + +// // config.services[`${id}-${name}`]?.volumes?.length > 0 && config.services[`${id}-${name}`].volumes.forEach((volume, index) => { +// // let oldVolumeName = volume.split(':')[0] +// // const path = volume.split(':')[1] +// // oldVolumeName = convertTolOldVolumeNames(type) +// // const volumeName = `${id}-${oldVolumeName}` +// // config.volumes[volumeName] = { +// // name: volumeName +// // } +// // config.services[`${id}-${name}`].volumes[index] = `${volumeName}:${path}` +// // }) +// // config.services[`${id}-${config.name}`] = { +// // ...config.services[`${id}-${config.name}`], +// // environment: environmentVariables +// // } +// delete config.services[name] + +// } +// console.log(config.services) +// console.log(config.volumes) + +// // config.services[id] = JSON.parse(JSON.stringify(config.services[type])) +// // config.services[id].container_name = id +// // config.services[id].image = `${image}:${version}` +// // config.services[id].ports = (exposePort ? [`${exposePort}:${port}`] : []), +// // config.services[id].restart = "always" +// // config.services[id].networks = [network] +// // config.services[id].labels = makeLabelForServices(type) +// // config.services[id].deploy = { +// // restart_policy: { +// // condition: 'on-failure', +// // delay: '5s', +// // max_attempts: 3, +// // window: '120s' +// // } +// // } +// // config.networks = { +// // [network]: { +// // external: true +// // } +// // } +// // config.volumes = {} +// // config.services[id].volumes.forEach((volume, index) => { +// // let oldVolumeName = volume.split(':')[0] +// // const path = volume.split(':')[1] +// // oldVolumeName = convertTolOldVolumeNames(type) +// // const volumeName = `${id}-${oldVolumeName}` +// // config.volumes[volumeName] = { +// // name: volumeName +// // } +// // config.services[id].volumes[index] = `${volumeName}:${path}` +// // }) +// // delete config.services[type] +// // config.services[id].environment = environmentVariables +// const composeFileDestination = `${workdir}/docker-compose.yaml`; +// // await fs.writeFile(composeFileDestination, yaml.dump(config)); +// // await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`); +// // await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); +// return {} +// } catch ({ status, message }) { +// return errorHandler({ status, message }) +// } +// } export async function listServices(request: FastifyRequest) { try { - const userId = request.user.userId; const teamId = request.user.teamId; let services = [] if (teamId === '0') { @@ -102,7 +172,7 @@ export async function newService(request: FastifyRequest, reply: FastifyReply) { return errorHandler({ status, message }) } } -export async function getService(request: FastifyRequest) { +export async function getService(request: FastifyRequest) { try { const teamId = request.user.teamId; const { id } = request.params; @@ -155,9 +225,8 @@ export async function getServiceType(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function saveServiceType(request: FastifyRequest, reply: FastifyReply) { +export async function saveServiceType(request: FastifyRequest, reply: FastifyReply) { try { - const teamId = request.user.teamId; const { id } = request.params; const { type } = request.body; await configureServiceType({ id, type }); @@ -166,7 +235,7 @@ export async function saveServiceType(request: FastifyRequest, reply: FastifyRep return errorHandler({ status, message }) } } -export async function getServiceVersions(request: FastifyRequest) { +export async function getServiceVersions(request: FastifyRequest) { try { const teamId = request.user.teamId; const { id } = request.params; @@ -179,9 +248,8 @@ export async function getServiceVersions(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function saveServiceVersion(request: FastifyRequest, reply: FastifyReply) { +export async function saveServiceVersion(request: FastifyRequest, reply: FastifyReply) { try { - const teamId = request.user.teamId; const { id } = request.params; const { version } = request.body; await prisma.service.update({ @@ -193,9 +261,8 @@ export async function saveServiceVersion(request: FastifyRequest, reply: Fastify return errorHandler({ status, message }) } } -export async function saveServiceDestination(request: FastifyRequest, reply: FastifyReply) { +export async function saveServiceDestination(request: FastifyRequest, reply: FastifyReply) { try { - const teamId = request.user.teamId; const { id } = request.params; const { destinationId } = request.body; await prisma.service.update({ @@ -207,7 +274,7 @@ export async function saveServiceDestination(request: FastifyRequest, reply: Fas return errorHandler({ status, message }) } } -export async function getServiceUsage(request: FastifyRequest) { +export async function getServiceUsage(request: FastifyRequest) { try { const teamId = request.user.teamId; const { id } = request.params; @@ -225,9 +292,8 @@ export async function getServiceUsage(request: FastifyRequest) { } } -export async function getServiceLogs(request: FastifyRequest) { +export async function getServiceLogs(request: FastifyRequest) { try { - const teamId = request.user.teamId; const { id } = request.params; let { since = 0 } = request.query if (since !== 0) { @@ -276,7 +342,7 @@ export async function getServiceLogs(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function deleteService(request: FastifyRequest) { +export async function deleteService(request: FastifyRequest) { try { const { id } = request.params; await removeService({ id }); @@ -285,7 +351,7 @@ export async function deleteService(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function saveServiceSettings(request: FastifyRequest, reply: FastifyReply) { +export async function saveServiceSettings(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params; const { dualCerts } = request.body; @@ -298,7 +364,7 @@ export async function saveServiceSettings(request: FastifyRequest, reply: Fastif return errorHandler({ status, message }) } } -export async function checkService(request: FastifyRequest) { +export async function checkService(request: FastifyRequest) { try { const { id } = request.params; let { fqdn, exposePort, otherFqdns } = request.body; @@ -337,7 +403,7 @@ export async function checkService(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function saveService(request: FastifyRequest, reply: FastifyReply) { +export async function saveService(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params; let { name, fqdn, exposePort, type } = request.body; @@ -365,7 +431,7 @@ export async function saveService(request: FastifyRequest, reply: FastifyReply) } } -export async function getServiceSecrets(request: FastifyRequest) { +export async function getServiceSecrets(request: FastifyRequest) { try { const { id } = request.params let secrets = await prisma.serviceSecret.findMany({ @@ -385,10 +451,10 @@ export async function getServiceSecrets(request: FastifyRequest) { } } -export async function saveServiceSecret(request: FastifyRequest, reply: FastifyReply) { +export async function saveServiceSecret(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params - let { name, value, isBuildSecret, isPRMRSecret, isNew } = request.body + let { name, value, isNew } = request.body if (isNew) { const found = await prisma.serviceSecret.findFirst({ where: { name, serviceId: id } }); @@ -420,7 +486,7 @@ export async function saveServiceSecret(request: FastifyRequest, reply: FastifyR return errorHandler({ status, message }) } } -export async function deleteServiceSecret(request: FastifyRequest) { +export async function deleteServiceSecret(request: FastifyRequest) { try { const { id } = request.params const { name } = request.body @@ -431,7 +497,7 @@ export async function deleteServiceSecret(request: FastifyRequest) { } } -export async function getServiceStorages(request: FastifyRequest) { +export async function getServiceStorages(request: FastifyRequest) { try { const { id } = request.params const persistentStorages = await prisma.servicePersistentStorage.findMany({ @@ -445,7 +511,7 @@ export async function getServiceStorages(request: FastifyRequest) { } } -export async function saveServiceStorage(request: FastifyRequest, reply: FastifyReply) { +export async function saveServiceStorage(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params const { path, newStorage, storageId } = request.body @@ -466,7 +532,7 @@ export async function saveServiceStorage(request: FastifyRequest, reply: Fastify } } -export async function deleteServiceStorage(request: FastifyRequest) { +export async function deleteServiceStorage(request: FastifyRequest) { try { const { id } = request.params const { path } = request.body @@ -477,7 +543,7 @@ export async function deleteServiceStorage(request: FastifyRequest) { } } -export async function startService(request: FastifyRequest,) { +export async function startService(request: FastifyRequest) { try { const { type } = request.params if (type === 'plausibleanalytics') { @@ -522,12 +588,15 @@ export async function startService(request: FastifyRequest,) { if (type === 'fider') { return await startFiderService(request) } + if (type === 'moodle') { + return await startMoodleService(request) + } throw `Service type ${type} not supported.` } catch (error) { throw { status: 500, message: error?.message || error } } } -export async function stopService(request: FastifyRequest) { +export async function stopService(request: FastifyRequest) { try { const { type } = request.params if (type === 'plausibleanalytics') { @@ -572,12 +641,15 @@ export async function stopService(request: FastifyRequest) { if (type === 'fider') { return await stopFiderService(request) } + if (type === 'moodle') { + return await stopMoodleService(request) + } throw `Service type ${type} not supported.` } catch (error) { throw { status: 500, message: error?.message || error } } } -export async function setSettingsService(request: FastifyRequest, reply: FastifyReply) { +export async function setSettingsService(request: FastifyRequest, reply: FastifyReply) { try { const { type } = request.params if (type === 'wordpress') { @@ -588,7 +660,7 @@ export async function setSettingsService(request: FastifyRequest, reply: Fastify return errorHandler({ status, message }) } } -async function setWordpressSettings(request: FastifyRequest, reply: FastifyReply) { +async function setWordpressSettings(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params const { ownMysql } = request.body @@ -602,7 +674,7 @@ async function setWordpressSettings(request: FastifyRequest, reply: FastifyReply } } -async function startPlausibleAnalyticsService(request: FastifyRequest) { +async function startPlausibleAnalyticsService(request: FastifyRequest) { try { const { id } = request.params const teamId = request.user.teamId; @@ -796,7 +868,7 @@ COPY ./init-db.sh /docker-entrypoint-initdb.d/init-db.sh`; return errorHandler({ status, message }) } } -async function stopPlausibleAnalyticsService(request: FastifyRequest) { +async function stopPlausibleAnalyticsService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -825,7 +897,7 @@ async function stopPlausibleAnalyticsService(request: FastifyRequest) { } } -async function startNocodbService(request: FastifyRequest) { +async function startNocodbService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -891,7 +963,7 @@ async function startNocodbService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopNocodbService(request: FastifyRequest) { +async function stopNocodbService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -910,7 +982,7 @@ async function stopNocodbService(request: FastifyRequest) { } } -async function startMinioService(request: FastifyRequest) { +async function startMinioService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -994,7 +1066,7 @@ async function startMinioService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopMinioService(request: FastifyRequest) { +async function stopMinioService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1014,7 +1086,7 @@ async function stopMinioService(request: FastifyRequest) { } } -async function startVscodeService(request: FastifyRequest) { +async function startVscodeService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1119,7 +1191,7 @@ async function startVscodeService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopVscodeService(request: FastifyRequest) { +async function stopVscodeService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1138,7 +1210,7 @@ async function stopVscodeService(request: FastifyRequest) { } } -async function startWordpressService(request: FastifyRequest) { +async function startWordpressService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1146,7 +1218,6 @@ async function startWordpressService(request: FastifyRequest) { const { type, version, - fqdn, destinationDockerId, serviceSecret, destinationDocker, @@ -1264,7 +1335,7 @@ async function startWordpressService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopWordpressService(request: FastifyRequest) { +async function stopWordpressService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1313,7 +1384,7 @@ async function stopWordpressService(request: FastifyRequest) { } } -async function startVaultwardenService(request: FastifyRequest) { +async function startVaultwardenService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1380,7 +1451,7 @@ async function startVaultwardenService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopVaultwardenService(request: FastifyRequest) { +async function stopVaultwardenService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1404,7 +1475,7 @@ async function stopVaultwardenService(request: FastifyRequest) { } } -async function startLanguageToolService(request: FastifyRequest) { +async function startLanguageToolService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1472,7 +1543,7 @@ async function startLanguageToolService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopLanguageToolService(request: FastifyRequest) { +async function stopLanguageToolService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1496,7 +1567,7 @@ async function stopLanguageToolService(request: FastifyRequest) { } } -async function startN8nService(request: FastifyRequest) { +async function startN8nService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1564,7 +1635,7 @@ async function startN8nService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopN8nService(request: FastifyRequest) { +async function stopN8nService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1588,7 +1659,7 @@ async function stopN8nService(request: FastifyRequest) { } } -async function startUptimekumaService(request: FastifyRequest) { +async function startUptimekumaService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1655,7 +1726,7 @@ async function startUptimekumaService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopUptimekumaService(request: FastifyRequest) { +async function stopUptimekumaService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1679,7 +1750,7 @@ async function stopUptimekumaService(request: FastifyRequest) { } } -async function startGhostService(request: FastifyRequest) { +async function startGhostService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1708,6 +1779,7 @@ async function startGhostService(request: FastifyRequest) { const { workdir } = await createDirectories({ repository: type, buildId: id }); const image = getServiceImage(type); const domain = getDomain(fqdn); + const port = getServiceMainPort('ghost'); const isHttps = fqdn.startsWith('https://'); const config = { ghost: { @@ -1806,7 +1878,7 @@ async function startGhostService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopGhostService(request: FastifyRequest) { +async function stopGhostService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1834,7 +1906,7 @@ async function stopGhostService(request: FastifyRequest) { } } -async function startMeilisearchService(request: FastifyRequest) { +async function startMeilisearchService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1907,7 +1979,7 @@ async function startMeilisearchService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopMeilisearchService(request: FastifyRequest) { +async function stopMeilisearchService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -1931,7 +2003,7 @@ async function stopMeilisearchService(request: FastifyRequest) { } } -async function startUmamiService(request: FastifyRequest) { +async function startUmamiService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -2126,7 +2198,7 @@ async function startUmamiService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopUmamiService(request: FastifyRequest) { +async function stopUmamiService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -2158,7 +2230,7 @@ async function stopUmamiService(request: FastifyRequest) { } } -async function startHasuraService(request: FastifyRequest) { +async function startHasuraService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -2262,7 +2334,7 @@ async function startHasuraService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopHasuraService(request: FastifyRequest) { +async function stopHasuraService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -2294,7 +2366,7 @@ async function stopHasuraService(request: FastifyRequest) { } } -async function startFiderService(request: FastifyRequest) { +async function startFiderService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -2425,7 +2497,7 @@ async function startFiderService(request: FastifyRequest) { return errorHandler({ status, message }) } } -async function stopFiderService(request: FastifyRequest) { +async function stopFiderService(request: FastifyRequest) { try { const { id } = request.params; const teamId = request.user.teamId; @@ -2457,7 +2529,171 @@ async function stopFiderService(request: FastifyRequest) { } } -export async function activatePlausibleUsers(request: FastifyRequest, reply: FastifyReply) { +async function startMoodleService(request: FastifyRequest) { + try { + const { id } = request.params; + const teamId = request.user.teamId; + const service = await getServiceFromDB({ id, teamId }); + const { + type, + version, + fqdn, + destinationDockerId, + destinationDocker, + serviceSecret, + exposePort, + moodle: { + defaultUsername, + defaultPassword, + defaultEmail, + mariadbRootUser, + mariadbRootUserPassword, + mariadbDatabase, + mariadbPassword, + mariadbUser + } + } = service; + const network = destinationDockerId && destinationDocker.network; + const host = getEngine(destinationDocker.engine); + const port = getServiceMainPort('moodle'); + + const { workdir } = await createDirectories({ repository: type, buildId: id }); + const image = getServiceImage(type); + const domain = getDomain(fqdn); + const config = { + moodle: { + image: `${image}:${version}`, + volume: `${id}-data:/bitnami/moodle`, + environmentVariables: { + MOODLE_USERNAME: defaultUsername, + MOODLE_PASSWORD: defaultPassword, + MOODLE_EMAIL: defaultEmail, + MOODLE_DATABASE_HOST: `${id}-mariadb`, + MOODLE_DATABASE_USER: mariadbUser, + MOODLE_DATABASE_PASSWORD: mariadbPassword, + MOODLE_DATABASE_NAME: mariadbDatabase, + MOODLE_REVERSEPROXY: 'yes' + } + }, + mariadb: { + image: 'bitnami/mariadb:latest', + volume: `${id}-mariadb-data:/bitnami/mariadb`, + environmentVariables: { + MARIADB_USER: mariadbUser, + MARIADB_PASSWORD: mariadbPassword, + MARIADB_DATABASE: mariadbDatabase, + MARIADB_ROOT_USER: mariadbRootUser, + MARIADB_ROOT_PASSWORD: mariadbRootUserPassword + } + } + }; + if (serviceSecret.length > 0) { + serviceSecret.forEach((secret) => { + config.moodle.environmentVariables[secret.name] = secret.value; + }); + } + + const composeFile: ComposeFile = { + version: '3.8', + services: { + [id]: { + container_name: id, + image: config.moodle.image, + environment: config.moodle.environmentVariables, + networks: [network], + volumes: [], + restart: 'always', + labels: makeLabelForServices('moodle'), + ...(exposePort ? { ports: [`${exposePort}:${port}`] } : {}), + deploy: { + restart_policy: { + condition: 'on-failure', + delay: '5s', + max_attempts: 3, + window: '120s' + } + }, + depends_on: [`${id}-mariadb`] + }, + [`${id}-mariadb`]: { + container_name: `${id}-mariadb`, + image: config.mariadb.image, + environment: config.mariadb.environmentVariables, + networks: [network], + volumes: [], + restart: 'always', + deploy: { + restart_policy: { + condition: 'on-failure', + delay: '5s', + max_attempts: 3, + window: '120s' + } + }, + depends_on: [] + } + + }, + networks: { + [network]: { + external: true + } + }, + volumes: { + [config.moodle.volume.split(':')[0]]: { + name: config.moodle.volume.split(':')[0] + }, + [config.mariadb.volume.split(':')[0]]: { + name: config.mariadb.volume.split(':')[0] + } + } + + }; + const composeFileDestination = `${workdir}/docker-compose.yaml`; + await fs.writeFile(composeFileDestination, yaml.dump(composeFile)); + + await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} pull`); + await asyncExecShell(`DOCKER_HOST=${host} docker compose -f ${composeFileDestination} up -d`); + + return {} + } catch ({ status, message }) { + return errorHandler({ status, message }) + } +} +async function stopMoodleService(request: FastifyRequest) { + try { + const { id } = request.params; + const teamId = request.user.teamId; + const service = await getServiceFromDB({ id, teamId }); + const { destinationDockerId, destinationDocker, fqdn } = service; + if (destinationDockerId) { + const engine = destinationDocker.engine; + + try { + const found = await checkContainer(engine, id); + if (found) { + await removeContainer({ id, engine }); + } + } catch (error) { + console.error(error); + } + try { + const found = await checkContainer(engine, `${id}-mariadb`); + if (found) { + await removeContainer({ id: `${id}-mariadb`, engine }); + } + } catch (error) { + console.error(error); + } + } + return {} + } catch ({ status, message }) { + return errorHandler({ status, message }) + } +} + + +export async function activatePlausibleUsers(request: FastifyRequest, reply: FastifyReply) { try { const { id } = request.params const teamId = request.user.teamId; @@ -2482,10 +2718,8 @@ export async function activatePlausibleUsers(request: FastifyRequest, reply: Fas return errorHandler({ status, message }) } } -export async function activateWordpressFtp(request: FastifyRequest, reply: FastifyReply) { +export async function activateWordpressFtp(request: FastifyRequest, reply: FastifyReply) { const { id } = request.params - const teamId = request.user.teamId; - const { ftpEnabled } = request.body; const publicPort = await getFreePort(); diff --git a/apps/api/src/routes/api/v1/services/index.ts b/apps/api/src/routes/api/v1/services/index.ts index be4b7964e..e4fcb20c7 100644 --- a/apps/api/src/routes/api/v1/services/index.ts +++ b/apps/api/src/routes/api/v1/services/index.ts @@ -27,46 +27,49 @@ import { stopService } from './handlers'; -const root: FastifyPluginAsync = async (fastify, opts): Promise => { - fastify.addHook('onRequest', async (request, reply) => { +import type { OnlyId } from '../../../../types'; +import type { ActivateWordpressFtp, CheckService, DeleteServiceSecret, DeleteServiceStorage, GetServiceLogs, SaveService, SaveServiceDestination, SaveServiceSecret, SaveServiceSettings, SaveServiceStorage, SaveServiceType, SaveServiceVersion, ServiceStartStop, SetWordpressSettings } from './types'; + +const root: FastifyPluginAsync = async (fastify): Promise => { + fastify.addHook('onRequest', async (request) => { return await request.jwtVerify() }) fastify.get('/', async (request) => await listServices(request)); fastify.post('/new', async (request, reply) => await newService(request, reply)); - fastify.get('/:id', async (request) => await getService(request)); - fastify.post('/:id', async (request, reply) => await saveService(request, reply)); - fastify.delete('/:id', async (request) => await deleteService(request)); + fastify.get('/:id', async (request) => await getService(request)); + fastify.post('/:id', async (request, reply) => await saveService(request, reply)); + fastify.delete('/:id', async (request) => await deleteService(request)); - fastify.post('/:id/check', async (request) => await checkService(request)); + fastify.post('/:id/check', async (request) => await checkService(request)); - fastify.post('/:id/settings', async (request, reply) => await saveServiceSettings(request, reply)); + fastify.post('/:id/settings', async (request, reply) => await saveServiceSettings(request, reply)); - fastify.get('/:id/secrets', async (request) => await getServiceSecrets(request)); - fastify.post('/:id/secrets', async (request, reply) => await saveServiceSecret(request, reply)); - fastify.delete('/:id/secrets', async (request) => await deleteServiceSecret(request)); + fastify.get('/:id/secrets', async (request) => await getServiceSecrets(request)); + fastify.post('/:id/secrets', async (request, reply) => await saveServiceSecret(request, reply)); + fastify.delete('/:id/secrets', async (request) => await deleteServiceSecret(request)); - fastify.get('/:id/storages', async (request) => await getServiceStorages(request)); - fastify.post('/:id/storages', async (request, reply) => await saveServiceStorage(request, reply)); - fastify.delete('/:id/storages', async (request) => await deleteServiceStorage(request)); + fastify.get('/:id/storages', async (request) => await getServiceStorages(request)); + fastify.post('/:id/storages', async (request, reply) => await saveServiceStorage(request, reply)); + fastify.delete('/:id/storages', async (request) => await deleteServiceStorage(request)); fastify.get('/:id/configuration/type', async (request) => await getServiceType(request)); - fastify.post('/:id/configuration/type', async (request, reply) => await saveServiceType(request, reply)); + fastify.post('/:id/configuration/type', async (request, reply) => await saveServiceType(request, reply)); - fastify.get('/:id/configuration/version', async (request) => await getServiceVersions(request)); - fastify.post('/:id/configuration/version', async (request, reply) => await saveServiceVersion(request, reply)); + fastify.get('/:id/configuration/version', async (request) => await getServiceVersions(request)); + fastify.post('/:id/configuration/version', async (request, reply) => await saveServiceVersion(request, reply)); - fastify.post('/:id/configuration/destination', async (request, reply) => await saveServiceDestination(request, reply)); + fastify.post('/:id/configuration/destination', async (request, reply) => await saveServiceDestination(request, reply)); - fastify.get('/:id/usage', async (request) => await getServiceUsage(request)); - fastify.get('/:id/logs', async (request) => await getServiceLogs(request)); + fastify.get('/:id/usage', async (request) => await getServiceUsage(request)); + fastify.get('/:id/logs', async (request) => await getServiceLogs(request)); - fastify.post('/:id/:type/start', async (request) => await startService(request)); - fastify.post('/:id/:type/stop', async (request) => await stopService(request)); - fastify.post('/:id/:type/settings', async (request, reply) => await setSettingsService(request, reply)); + fastify.post('/:id/:type/start', async (request) => await startService(request)); + fastify.post('/:id/:type/stop', async (request) => await stopService(request)); + fastify.post('/:id/:type/settings', async (request, reply) => await setSettingsService(request, reply)); - fastify.post('/:id/plausibleanalytics/activate', async (request, reply) => await activatePlausibleUsers(request, reply)); - fastify.post('/:id/wordpress/ftp', async (request, reply) => await activateWordpressFtp(request, reply)); + fastify.post('/:id/plausibleanalytics/activate', async (request, reply) => await activatePlausibleUsers(request, reply)); + fastify.post('/:id/wordpress/ftp', async (request, reply) => await activateWordpressFtp(request, reply)); }; export default root; diff --git a/apps/api/src/routes/api/v1/services/types.ts b/apps/api/src/routes/api/v1/services/types.ts new file mode 100644 index 000000000..4ed631998 --- /dev/null +++ b/apps/api/src/routes/api/v1/services/types.ts @@ -0,0 +1,87 @@ +import { OnlyId } from "../../../../types"; + +export interface SaveServiceType extends OnlyId { + Body: { + type: string + } +} +export interface SaveServiceVersion extends OnlyId { + Body: { + version: string + } +} +export interface SaveServiceDestination extends OnlyId { + Body: { + destinationId: string + } +} +export interface GetServiceLogs extends OnlyId { + Querystring: { + since: number + } +} +export interface SaveServiceSettings extends OnlyId { + Body: { + dualCerts: boolean + } +} +export interface CheckService extends OnlyId { + Body: { + fqdn: string, + exposePort: number, + otherFqdns: Array + } +} +export interface SaveService extends OnlyId { + Body: { + name: string, + fqdn: string, + exposePort: number, + type: string + } +} +export interface SaveServiceSecret extends OnlyId { + Body: { + name: string, + value: string, + isNew: string, + } +} +export interface DeleteServiceSecret extends OnlyId { + Body: { + name: string, + } +} +export interface SaveServiceStorage extends OnlyId { + Body: { + path: string, + newStorage: string, + storageId: string, + } +} + +export interface DeleteServiceStorage extends OnlyId { + Body: { + path: string, + } +} +export interface ServiceStartStop { + Params: { + id?: string, + type: string, + } +} +export interface SetWordpressSettings extends OnlyId { + Body: { + ownMysql: boolean + } +} +export interface ActivateWordpressFtp extends OnlyId { + Body: { + ftpEnabled: boolean + } +} + + + + diff --git a/apps/api/src/routes/api/v1/settings/handlers.ts b/apps/api/src/routes/api/v1/settings/handlers.ts index f2bb90812..0c0c727d1 100644 --- a/apps/api/src/routes/api/v1/settings/handlers.ts +++ b/apps/api/src/routes/api/v1/settings/handlers.ts @@ -2,6 +2,7 @@ import { promises as dns } from 'dns'; import type { FastifyReply, FastifyRequest } from 'fastify'; import { checkDomainsIsValidInDNS, errorHandler, getDomain, isDNSValid, isDomainConfigured, listSettings, prisma } from '../../../../lib/common'; +import { CheckDNS, CheckDomain, DeleteDomain, SaveSettings } from './types'; export async function listAllSettings(request: FastifyRequest) { @@ -14,7 +15,7 @@ export async function listAllSettings(request: FastifyRequest) { return errorHandler({ status, message }) } } -export async function saveSettings(request: FastifyRequest, reply: FastifyReply) { +export async function saveSettings(request: FastifyRequest, reply: FastifyReply) { try { const { fqdn, @@ -41,7 +42,7 @@ export async function saveSettings(request: FastifyRequest, reply: FastifyReply) return errorHandler({ status, message }) } } -export async function deleteDomain(request: FastifyRequest, reply: FastifyReply) { +export async function deleteDomain(request: FastifyRequest, reply: FastifyReply) { try { const { fqdn } = request.body let ip; @@ -57,7 +58,7 @@ export async function deleteDomain(request: FastifyRequest, reply: FastifyReply) } } -export async function checkDomain(request: FastifyRequest, reply: FastifyReply) { +export async function checkDomain(request: FastifyRequest) { try { const { id } = request.params; let { fqdn, forceSave, dualCerts, isDNSCheckEnabled } = request.body @@ -74,9 +75,9 @@ export async function checkDomain(request: FastifyRequest, reply: FastifyReply) return errorHandler({ status, message }) } } -export async function checkDNS(request: FastifyRequest, reply: FastifyReply) { +export async function checkDNS(request: FastifyRequest) { try { - const { id, domain } = request.params; + const { domain } = request.params; await isDNSValid(request.hostname, domain); return {} } catch ({ status, message }) { diff --git a/apps/api/src/routes/api/v1/settings/index.ts b/apps/api/src/routes/api/v1/settings/index.ts index 2c7a69738..f5181a14e 100644 --- a/apps/api/src/routes/api/v1/settings/index.ts +++ b/apps/api/src/routes/api/v1/settings/index.ts @@ -1,17 +1,18 @@ import { FastifyPluginAsync } from 'fastify'; import { checkDNS, checkDomain, deleteDomain, listAllSettings, saveSettings } from './handlers'; +import { CheckDNS, CheckDomain, DeleteDomain, SaveSettings } from './types'; -const root: FastifyPluginAsync = async (fastify, opts): Promise => { - fastify.addHook('onRequest', async (request, reply) => { +const root: FastifyPluginAsync = async (fastify): Promise => { + fastify.addHook('onRequest', async (request) => { return await request.jwtVerify() }) fastify.get('/', async (request) => await listAllSettings(request)); - fastify.post('/', async (request, reply) => await saveSettings(request, reply)); - fastify.delete('/', async (request, reply) => await deleteDomain(request, reply)); + fastify.post('/', async (request, reply) => await saveSettings(request, reply)); + fastify.delete('/', async (request, reply) => await deleteDomain(request, reply)); - fastify.get('/check', async (request, reply) => await checkDNS(request, reply)); - fastify.post('/check', async (request, reply) => await checkDomain(request, reply)); + fastify.get('/check', async (request) => await checkDNS(request)); + fastify.post('/check', async (request) => await checkDomain(request)); }; export default root; diff --git a/apps/api/src/routes/api/v1/settings/types.ts b/apps/api/src/routes/api/v1/settings/types.ts new file mode 100644 index 000000000..aa7398804 --- /dev/null +++ b/apps/api/src/routes/api/v1/settings/types.ts @@ -0,0 +1,31 @@ +import { OnlyId } from "../../../../types" + +export interface SaveSettings { + Body: { + fqdn: string, + isRegistrationEnabled: boolean, + dualCerts: boolean, + minPort: number, + maxPort: number, + isAutoUpdateEnabled: boolean, + isDNSCheckEnabled: boolean + } +} +export interface DeleteDomain { + Body: { + fqdn: string + } +} +export interface CheckDomain extends OnlyId { + Body: { + fqdn: string, + forceSave: boolean, + dualCerts: boolean, + isDNSCheckEnabled: boolean, + } +} +export interface CheckDNS { + Params: { + domain: string, + } +} \ No newline at end of file diff --git a/apps/api/src/routes/api/v1/sources/handlers.ts b/apps/api/src/routes/api/v1/sources/handlers.ts index 9bed930d7..8a1c19987 100644 --- a/apps/api/src/routes/api/v1/sources/handlers.ts +++ b/apps/api/src/routes/api/v1/sources/handlers.ts @@ -2,6 +2,8 @@ import cuid from 'cuid'; import type { FastifyRequest } from 'fastify'; import { FastifyReply } from 'fastify'; import { decrypt, encrypt, errorHandler, prisma } from '../../../../lib/common'; +import { OnlyId } from '../../../../types'; +import { CheckGitLabOAuthId, SaveGitHubSource, SaveGitLabSource } from './types'; export async function listSources(request: FastifyRequest) { try { @@ -31,7 +33,7 @@ export async function saveSource(request, reply) { return errorHandler({ status, message }) } } -export async function getSource(request: FastifyRequest) { +export async function getSource(request: FastifyRequest) { try { const { id } = request.params const { teamId } = request.user @@ -97,12 +99,12 @@ export async function deleteSource(request) { } } -export async function saveGitHubSource(request: FastifyRequest, reply: FastifyReply) { +export async function saveGitHubSource(request: FastifyRequest) { try { const { teamId } = request.user const { id } = request.params - let { name, type, htmlUrl, apiUrl, organization, customPort } = request.body + let { name, htmlUrl, apiUrl, organization, customPort } = request.body if (customPort) customPort = Number(customPort) if (id === 'new') { @@ -128,7 +130,7 @@ export async function saveGitHubSource(request: FastifyRequest, reply: FastifyRe return errorHandler({ status, message }) } } -export async function saveGitLabSource(request: FastifyRequest, reply: FastifyReply) { +export async function saveGitLabSource(request: FastifyRequest) { try { const { id } = request.params const { teamId } = request.user @@ -175,7 +177,7 @@ export async function saveGitLabSource(request: FastifyRequest, reply: FastifyRe } } -export async function checkGitLabOAuthID(request: FastifyRequest) { +export async function checkGitLabOAuthID(request: FastifyRequest) { try { const { oauthId } = request.body const found = await prisma.gitlabApp.findFirst({ where: { oauthId: Number(oauthId) } }); diff --git a/apps/api/src/routes/api/v1/sources/index.ts b/apps/api/src/routes/api/v1/sources/index.ts index f741627f3..3d904162f 100644 --- a/apps/api/src/routes/api/v1/sources/index.ts +++ b/apps/api/src/routes/api/v1/sources/index.ts @@ -1,21 +1,22 @@ import { FastifyPluginAsync } from 'fastify'; import { checkGitLabOAuthID, deleteSource, getSource, listSources, saveGitHubSource, saveGitLabSource, saveSource } from './handlers'; +import type { OnlyId } from '../../../../types'; +import type { CheckGitLabOAuthId, SaveGitHubSource, SaveGitLabSource } from './types'; -const root: FastifyPluginAsync = async (fastify, opts): Promise => { - fastify.addHook('onRequest', async (request, reply) => { +const root: FastifyPluginAsync = async (fastify): Promise => { + fastify.addHook('onRequest', async (request) => { return await request.jwtVerify() }) fastify.get('/', async (request) => await listSources(request)); - fastify.get('/:id', async (request) => await getSource(request)); + fastify.get('/:id', async (request) => await getSource(request)); fastify.post('/:id', async (request, reply) => await saveSource(request, reply)); fastify.delete('/:id', async (request) => await deleteSource(request)); - fastify.post('/:id/check', async (request) => await checkGitLabOAuthID(request)); - fastify.post('/:id/github', async (request, reply) => await saveGitHubSource(request, reply)); - fastify.post('/:id/gitlab', async (request, reply) => await saveGitLabSource(request, reply)); - + fastify.post('/:id/check', async (request) => await checkGitLabOAuthID(request)); + fastify.post('/:id/github', async (request) => await saveGitHubSource(request)); + fastify.post('/:id/gitlab', async (request) => await saveGitLabSource(request)); }; export default root; diff --git a/apps/api/src/routes/api/v1/sources/types.ts b/apps/api/src/routes/api/v1/sources/types.ts new file mode 100644 index 000000000..a748b3943 --- /dev/null +++ b/apps/api/src/routes/api/v1/sources/types.ts @@ -0,0 +1,29 @@ +import { OnlyId } from "../../../../types"; + +export interface SaveGitHubSource extends OnlyId { + Body: { + name: string, + htmlUrl: string, + apiUrl: string, + organization: string, + customPort: number, + } +} +export interface SaveGitLabSource extends OnlyId { + Body: { + type: string, + name: string, + htmlUrl: string, + apiUrl: string, + oauthId: number, + appId: string, + appSecret: string, + groupName: string, + customPort: number, + } +} +export interface CheckGitLabOAuthId extends OnlyId { + Body: { + oauthId: number, + } +} \ No newline at end of file diff --git a/apps/api/src/routes/api/v1/types.ts b/apps/api/src/routes/api/v1/types.ts new file mode 100644 index 000000000..945355df7 --- /dev/null +++ b/apps/api/src/routes/api/v1/types.ts @@ -0,0 +1,3 @@ +export interface GetCurrentUser { + Querystring: { teamId: string } +} \ No newline at end of file diff --git a/apps/api/src/routes/webhooks/github/handlers.ts b/apps/api/src/routes/webhooks/github/handlers.ts index 5e9e403ee..cb37029f4 100644 --- a/apps/api/src/routes/webhooks/github/handlers.ts +++ b/apps/api/src/routes/webhooks/github/handlers.ts @@ -1,13 +1,15 @@ import axios from "axios"; import cuid from "cuid"; import crypto from "crypto"; -import type { FastifyReply, FastifyRequest } from "fastify"; -import { encrypt, errorHandler, getAPIUrl, getUIUrl, isDev, prisma } from "../../../lib/common"; +import { encrypt, errorHandler, getUIUrl, isDev, prisma } from "../../../lib/common"; import { checkContainer, removeContainer } from "../../../lib/docker"; import { scheduler } from "../../../lib/scheduler"; -import { getApplicationFromDB, getApplicationFromDBWebhook } from "../../api/v1/applications/handlers"; +import { getApplicationFromDBWebhook } from "../../api/v1/applications/handlers"; -export async function installGithub(request: FastifyRequest, reply: FastifyReply): Promise { +import type { FastifyReply, FastifyRequest } from "fastify"; +import type { GitHubEvents, InstallGithub } from "./types"; + +export async function installGithub(request: FastifyRequest, reply: FastifyReply): Promise { try { const { gitSourceId, installation_id } = request.query; const source = await prisma.gitSource.findUnique({ @@ -63,7 +65,7 @@ export async function configureGitHubApp(request, reply) { return errorHandler({ status, message }) } } -export async function gitHubEvents(request: FastifyRequest, reply: FastifyReply): Promise { +export async function gitHubEvents(request: FastifyRequest): Promise { try { const buildId = cuid(); const allowedGithubEvents = ['push', 'pull_request']; diff --git a/apps/api/src/routes/webhooks/github/index.ts b/apps/api/src/routes/webhooks/github/index.ts index 2af33366a..c4a3afbb9 100644 --- a/apps/api/src/routes/webhooks/github/index.ts +++ b/apps/api/src/routes/webhooks/github/index.ts @@ -1,10 +1,12 @@ import { FastifyPluginAsync } from 'fastify'; import { configureGitHubApp, gitHubEvents, installGithub } from './handlers'; -const root: FastifyPluginAsync = async (fastify, opts): Promise => { +import type { GitHubEvents, InstallGithub } from './types'; + +const root: FastifyPluginAsync = async (fastify): Promise => { fastify.get('/', async (request, reply) => configureGitHubApp(request, reply)); - fastify.get('/install', async (request, reply) => installGithub(request, reply)); - fastify.post('/events', async (request, reply) => gitHubEvents(request, reply)); + fastify.get('/install', async (request, reply) => installGithub(request, reply)); + fastify.post('/events', async (request, reply) => gitHubEvents(request)); }; export default root; diff --git a/apps/api/src/routes/webhooks/github/types.ts b/apps/api/src/routes/webhooks/github/types.ts new file mode 100644 index 000000000..c7502ec6d --- /dev/null +++ b/apps/api/src/routes/webhooks/github/types.ts @@ -0,0 +1,20 @@ +export interface InstallGithub { + Querystring: { + gitSourceId: string, + installation_id: string + } +} +export interface GitHubEvents { + Body: { + number: string, + action: string, + repository: string, + ref: string, + pull_request: { + head: { + ref: string, + repo: string + } + } + } +} \ No newline at end of file diff --git a/apps/api/src/routes/webhooks/gitlab/handlers.ts b/apps/api/src/routes/webhooks/gitlab/handlers.ts index fab40cf05..dfe310ed7 100644 --- a/apps/api/src/routes/webhooks/gitlab/handlers.ts +++ b/apps/api/src/routes/webhooks/gitlab/handlers.ts @@ -2,16 +2,18 @@ import axios from "axios"; import cuid from "cuid"; import crypto from "crypto"; import type { FastifyReply, FastifyRequest } from "fastify"; -import { encrypt, errorHandler, getAPIUrl, isDev, listSettings, prisma } from "../../../lib/common"; +import { errorHandler, getAPIUrl, isDev, listSettings, prisma } from "../../../lib/common"; import { checkContainer, removeContainer } from "../../../lib/docker"; import { scheduler } from "../../../lib/scheduler"; import { getApplicationFromDB, getApplicationFromDBWebhook } from "../../api/v1/applications/handlers"; -export async function configureGitLabApp(request: FastifyRequest, reply: FastifyReply) { +import type { ConfigureGitLabApp, GitLabEvents } from "./types"; + +export async function configureGitLabApp(request: FastifyRequest, reply: FastifyReply) { try { const { code, state } = request.query; const { fqdn } = await listSettings(); - const { gitSource: { gitlabApp: { appId, appSecret }, htmlUrl } } = await getApplicationFromDB(state, undefined); + const { gitSource: { gitlabApp: { appId, appSecret }, htmlUrl } }: any = await getApplicationFromDB(state, undefined); let domain = `http://${request.hostname}`; if (fqdn) domain = fqdn; @@ -36,12 +38,13 @@ export async function configureGitLabApp(request: FastifyRequest, reply: Fastify return errorHandler({ status, message }) } } -export async function gitLabEvents(request: FastifyRequest, reply: FastifyReply) { +export async function gitLabEvents(request: FastifyRequest) { + const { object_kind: objectKind, ref, project_id } = request.body try { const buildId = cuid(); const allowedActions = ['opened', 'reopen', 'close', 'open', 'update']; - const { object_kind: objectKind, ref, project_id } = request.body + const webhookToken = request.headers['x-gitlab-token']; if (!webhookToken) { throw { status: 500, message: 'Invalid webhookToken.' } diff --git a/apps/api/src/routes/webhooks/gitlab/index.ts b/apps/api/src/routes/webhooks/gitlab/index.ts index 22badd03f..77f3067e4 100644 --- a/apps/api/src/routes/webhooks/gitlab/index.ts +++ b/apps/api/src/routes/webhooks/gitlab/index.ts @@ -1,9 +1,11 @@ import { FastifyPluginAsync } from 'fastify'; import { configureGitLabApp, gitLabEvents } from './handlers'; -const root: FastifyPluginAsync = async (fastify, opts): Promise => { - fastify.get('/', async (request, reply) => configureGitLabApp(request, reply)); - fastify.post('/events', async (request, reply) => gitLabEvents(request, reply)); +import type { ConfigureGitLabApp, GitLabEvents } from './types'; + +const root: FastifyPluginAsync = async (fastify): Promise => { + fastify.get('/', async (request, reply) => configureGitLabApp(request, reply)); + fastify.post('/events', async (request) => gitLabEvents(request)); }; export default root; diff --git a/apps/api/src/routes/webhooks/gitlab/types.ts b/apps/api/src/routes/webhooks/gitlab/types.ts new file mode 100644 index 000000000..42af0f6ae --- /dev/null +++ b/apps/api/src/routes/webhooks/gitlab/types.ts @@ -0,0 +1,24 @@ +export interface ConfigureGitLabApp { + Querystring: { + code: string, + state: string + } +} +export interface GitLabEvents { + Body: { + object_attributes: { + work_in_progress: string + isDraft: string + action: string + source_branch: string + target_branch: string + iid: string + }, + project: { + id: string + }, + object_kind: string, + ref: string, + project_id: string + } +} \ No newline at end of file diff --git a/apps/api/src/routes/webhooks/traefik/handlers.ts b/apps/api/src/routes/webhooks/traefik/handlers.ts index 2c91c851d..879ccd960 100644 --- a/apps/api/src/routes/webhooks/traefik/handlers.ts +++ b/apps/api/src/routes/webhooks/traefik/handlers.ts @@ -1,6 +1,7 @@ import { FastifyRequest } from "fastify"; import { asyncExecShell, errorHandler, getDomain, isDev, listServicesWithIncludes, prisma, supportedServiceTypesAndVersions } from "../../../lib/common"; import { getEngine } from "../../../lib/docker"; +import { TraefikOtherConfiguration } from "./types"; function configureMiddleware( { id, container, port, domain, nakedDomain, isHttps, isWWW, isDualCerts, scriptName, type }, @@ -362,7 +363,7 @@ export async function traefikConfiguration(request, reply) { } } -export async function traefikOtherConfiguration(request: FastifyRequest, reply) { +export async function traefikOtherConfiguration(request: FastifyRequest) { try { const { id } = request.query if (id) { diff --git a/apps/api/src/routes/webhooks/traefik/index.ts b/apps/api/src/routes/webhooks/traefik/index.ts index bb79c6b05..1d69be739 100644 --- a/apps/api/src/routes/webhooks/traefik/index.ts +++ b/apps/api/src/routes/webhooks/traefik/index.ts @@ -1,9 +1,10 @@ import { FastifyPluginAsync } from 'fastify'; import { traefikConfiguration, traefikOtherConfiguration } from './handlers'; +import { TraefikOtherConfiguration } from './types'; -const root: FastifyPluginAsync = async (fastify, opts): Promise => { +const root: FastifyPluginAsync = async (fastify): Promise => { fastify.get('/main.json', async (request, reply) => traefikConfiguration(request, reply)); - fastify.get('/other.json', async (request, reply) => traefikOtherConfiguration(request, reply)); + fastify.get('/other.json', async (request, reply) => traefikOtherConfiguration(request)); }; export default root; diff --git a/apps/api/src/routes/webhooks/traefik/types.ts b/apps/api/src/routes/webhooks/traefik/types.ts new file mode 100644 index 000000000..237d746fe --- /dev/null +++ b/apps/api/src/routes/webhooks/traefik/types.ts @@ -0,0 +1,9 @@ +export interface TraefikOtherConfiguration { + Querystring: { + id: string, + privatePort: number, + publicPort: number, + type: string, + address: string + } +} \ No newline at end of file diff --git a/apps/api/src/types.ts b/apps/api/src/types.ts new file mode 100644 index 000000000..71f3db158 --- /dev/null +++ b/apps/api/src/types.ts @@ -0,0 +1,38 @@ +export interface OnlyId { + Params: { id: string }, +} +export interface SaveVersion extends OnlyId { + Body: { + version: string + } +} +export interface SaveDatabaseDestination extends OnlyId { + Body: { + destinationId: string + } +} +export interface GetDatabaseLogs extends OnlyId { + Querystring: { + since: number + } +} +export interface SaveDatabase extends OnlyId { + Body: { + name: string, + defaultDatabase: string, + dbUser: string, + dbUserPassword: string, + rootUser: string, + rootUserPassword: string, + version: string, + isRunning: boolean + } +} +export interface SaveDatabaseSettings extends OnlyId { + Body: { + isPublic: boolean, + appendOnly: boolean + } +} + + diff --git a/apps/ui/package.json b/apps/ui/package.json index 5e069312f..babb6755c 100644 --- a/apps/ui/package.json +++ b/apps/ui/package.json @@ -15,12 +15,11 @@ "format": "prettier --write --plugin-search-dir=. ." }, "devDependencies": { - "@playwright/test": "1.23.1", - "@sveltejs/adapter-auto": "1.0.0-next.53", - "@sveltejs/kit": "1.0.0-next.359", + "@playwright/test": "1.23.3", + "@sveltejs/kit": "1.0.0-next.375", "@types/js-cookie": "3.0.2", - "@typescript-eslint/eslint-plugin": "5.30.5", - "@typescript-eslint/parser": "5.30.5", + "@typescript-eslint/eslint-plugin": "5.30.6", + "@typescript-eslint/parser": "5.30.6", "autoprefixer": "10.4.7", "eslint": "8.19.0", "eslint-config-prettier": "8.5.0", @@ -28,18 +27,18 @@ "postcss": "8.4.14", "prettier": "2.7.1", "prettier-plugin-svelte": "2.7.0", - "svelte": "3.48.0", + "svelte": "3.49.0", "svelte-check": "2.8.0", "svelte-preprocess": "4.10.7", - "tailwindcss": "3.1.4", + "tailwindcss": "3.1.6", "tailwindcss-scrollbar": "0.1.0", "tslib": "2.4.0", "typescript": "4.7.4", - "vite": "^2.9.13" + "vite": "^3.0.0" }, "type": "module", "dependencies": { - "@sveltejs/adapter-static": "1.0.0-next.34", + "@sveltejs/adapter-static": "1.0.0-next.36", "@zerodevx/svelte-toast": "0.7.2", "cuid": "2.1.8", "js-cookie": "3.0.1", diff --git a/apps/ui/src/lib/common.ts b/apps/ui/src/lib/common.ts index 4b0ae7fb4..e0396f19c 100644 --- a/apps/ui/src/lib/common.ts +++ b/apps/ui/src/lib/common.ts @@ -1,264 +1,4 @@ import { toast } from '@zerodevx/svelte-toast'; -export const asyncSleep = (delay: number) => - new Promise((resolve) => setTimeout(resolve, delay)); - -export function errorNotification(error: any): void { - if (error.message) { - if (error.message === 'Cannot read properties of undefined (reading \'postMessage\')') { - toast.push('Currently there is background process in progress. Please try again later.'); - return; - } - toast.push(error.message); - } else { - toast.push('Ooops, something is not okay, are you okay?'); - } - console.error(JSON.stringify(error)); -} - -export function getDomain(domain: string) { - return domain?.replace('https://', '').replace('http://', ''); -} -export function dashify(str: string, options?: any): string { - if (typeof str !== 'string') return str; - return str - .trim() - .replace(/\W/g, (m) => (/[À-ž]/.test(m) ? m : '-')) - .replace(/^-+|-+$/g, '') - .replace(/-{2,}/g, (m) => (options && options.condense ? '-' : m)) - .toLowerCase(); -} - -export const dateOptions: any = { - year: 'numeric', - month: 'short', - day: '2-digit', - hour: 'numeric', - minute: 'numeric', - second: 'numeric', - hour12: false -}; - -export const staticDeployments = [ - 'react', - 'vuejs', - 'static', - 'svelte', - 'gatsby', - 'php', - 'astro', - 'eleventy' -]; -export const notNodeDeployments = ['php', 'docker', 'rust', 'python', 'deno', 'laravel']; - - -export function generateRemoteEngine(destination: any) { - return `ssh://${destination.user}@${destination.ipAddress}:${destination.port}`; -} - -export function changeQueryParams(buildId: string) { - const queryParams = new URLSearchParams(window.location.search); - queryParams.set('buildId', buildId); - // @ts-ignore - return history.pushState(null, null, '?' + queryParams.toString()); -} - -// export const supportedDatabaseTypesAndVersions = [ -// { -// name: 'mongodb', -// fancyName: 'MongoDB', -// baseImage: 'bitnami/mongodb', -// versions: ['5.0', '4.4', '4.2'] -// }, -// { name: 'mysql', fancyName: 'MySQL', baseImage: 'bitnami/mysql', versions: ['8.0', '5.7'] }, -// { -// name: 'mariadb', -// fancyName: 'MariaDB', -// baseImage: 'bitnami/mariadb', -// versions: ['10.7', '10.6', '10.5', '10.4', '10.3', '10.2'] -// }, -// { -// name: 'postgresql', -// fancyName: 'PostgreSQL', -// baseImage: 'bitnami/postgresql', -// versions: ['14.2.0', '13.6.0', '12.10.0 ', '11.15.0', '10.20.0'] -// }, -// { -// name: 'redis', -// fancyName: 'Redis', -// baseImage: 'bitnami/redis', -// versions: ['6.2', '6.0', '5.0'] -// }, -// { name: 'couchdb', fancyName: 'CouchDB', baseImage: 'bitnami/couchdb', versions: ['3.2.1'] } -// ]; -// export const supportedServiceTypesAndVersions = [ -// { -// name: 'plausibleanalytics', -// fancyName: 'Plausible Analytics', -// baseImage: 'plausible/analytics', -// images: ['bitnami/postgresql:13.2.0', 'yandex/clickhouse-server:21.3.2.5'], -// versions: ['latest', 'stable'], -// recommendedVersion: 'stable', -// ports: { -// main: 8000 -// } -// }, -// { -// name: 'nocodb', -// fancyName: 'NocoDB', -// baseImage: 'nocodb/nocodb', -// versions: ['latest'], -// recommendedVersion: 'latest', -// ports: { -// main: 8080 -// } -// }, -// { -// name: 'minio', -// fancyName: 'MinIO', -// baseImage: 'minio/minio', -// versions: ['latest'], -// recommendedVersion: 'latest', -// ports: { -// main: 9001 -// } -// }, -// { -// name: 'vscodeserver', -// fancyName: 'VSCode Server', -// baseImage: 'codercom/code-server', -// versions: ['latest'], -// recommendedVersion: 'latest', -// ports: { -// main: 8080 -// } -// }, -// { -// name: 'wordpress', -// fancyName: 'Wordpress', -// baseImage: 'wordpress', -// images: ['bitnami/mysql:5.7'], -// versions: ['latest', 'php8.1', 'php8.0', 'php7.4', 'php7.3'], -// recommendedVersion: 'latest', -// ports: { -// main: 80 -// } -// }, -// { -// name: 'vaultwarden', -// fancyName: 'Vaultwarden', -// baseImage: 'vaultwarden/server', -// versions: ['latest'], -// recommendedVersion: 'latest', -// ports: { -// main: 80 -// } -// }, -// { -// name: 'languagetool', -// fancyName: 'LanguageTool', -// baseImage: 'silviof/docker-languagetool', -// versions: ['latest'], -// recommendedVersion: 'latest', -// ports: { -// main: 8010 -// } -// }, -// { -// name: 'n8n', -// fancyName: 'n8n', -// baseImage: 'n8nio/n8n', -// versions: ['latest'], -// recommendedVersion: 'latest', -// ports: { -// main: 5678 -// } -// }, -// { -// name: 'uptimekuma', -// fancyName: 'Uptime Kuma', -// baseImage: 'louislam/uptime-kuma', -// versions: ['latest'], -// recommendedVersion: 'latest', -// ports: { -// main: 3001 -// } -// }, -// { -// name: 'ghost', -// fancyName: 'Ghost', -// baseImage: 'bitnami/ghost', -// images: ['bitnami/mariadb'], -// versions: ['latest'], -// recommendedVersion: 'latest', -// ports: { -// main: 2368 -// } -// }, -// { -// name: 'meilisearch', -// fancyName: 'Meilisearch', -// baseImage: 'getmeili/meilisearch', -// images: [], -// versions: ['latest'], -// recommendedVersion: 'latest', -// ports: { -// main: 7700 -// } -// }, -// { -// name: 'umami', -// fancyName: 'Umami', -// baseImage: 'ghcr.io/mikecao/umami', -// images: ['postgres:12-alpine'], -// versions: ['postgresql-latest'], -// recommendedVersion: 'postgresql-latest', -// ports: { -// main: 3000 -// } -// }, -// { -// name: 'hasura', -// fancyName: 'Hasura', -// baseImage: 'hasura/graphql-engine', -// images: ['postgres:12-alpine'], -// versions: ['latest', 'v2.5.1'], -// recommendedVersion: 'v2.5.1', -// ports: { -// main: 8080 -// } -// }, -// { -// name: 'fider', -// fancyName: 'Fider', -// baseImage: 'getfider/fider', -// images: ['postgres:12-alpine'], -// versions: ['stable'], -// recommendedVersion: 'stable', -// ports: { -// main: 3000 -// } -// // }, -// // { -// // name: 'appwrite', -// // fancyName: 'AppWrite', -// // baseImage: 'appwrite/appwrite', -// // images: ['appwrite/influxdb', 'appwrite/telegraf', 'mariadb:10.7', 'redis:6.0-alpine3.12'], -// // versions: ['latest', '0.13.0'], -// // recommendedVersion: '0.13.0', -// // ports: { -// // main: 3000 -// // } -// // } -// } -// ]; - -export const getServiceMainPort = (service: string) => { - const serviceType = supportedServiceTypesAndVersions.find((s) => s.name === service); - if (serviceType) { - return serviceType.ports.main; - } - return null; -}; export const supportedServiceTypesAndVersions = [ { @@ -407,9 +147,122 @@ export const supportedServiceTypesAndVersions = [ ports: { main: 3000 } - } + }, + // { + // name: 'moodle', + // fancyName: 'Moodle', + // baseImage: 'bitnami/moodle', + // images: [], + // versions: ['latest', 'v4.0.2'], + // recommendedVersion: 'latest', + // ports: { + // main: 8080 + // } + // } ]; +export const asyncSleep = (delay: number) => + new Promise((resolve) => setTimeout(resolve, delay)); + +export function errorNotification(error: any): void { + if (error.message) { + if (error.message === 'Cannot read properties of undefined (reading \'postMessage\')') { + toast.push('Currently there is background process in progress. Please try again later.'); + return; + } + toast.push(error.message); + } else { + toast.push('Ooops, something is not okay, are you okay?'); + } + console.error(JSON.stringify(error)); +} + +export function getDomain(domain: string) { + return domain?.replace('https://', '').replace('http://', ''); +} +export function dashify(str: string, options?: any): string { + if (typeof str !== 'string') return str; + return str + .trim() + .replace(/\W/g, (m) => (/[À-ž]/.test(m) ? m : '-')) + .replace(/^-+|-+$/g, '') + .replace(/-{2,}/g, (m) => (options && options.condense ? '-' : m)) + .toLowerCase(); +} + +export const dateOptions: any = { + year: 'numeric', + month: 'short', + day: '2-digit', + hour: 'numeric', + minute: 'numeric', + second: 'numeric', + hour12: false +}; + +export const staticDeployments = [ + 'react', + 'vuejs', + 'static', + 'svelte', + 'gatsby', + 'php', + 'astro', + 'eleventy' +]; +export const notNodeDeployments = ['php', 'docker', 'rust', 'python', 'deno', 'laravel']; + + +export function generateRemoteEngine(destination: any) { + return `ssh://${destination.user}@${destination.ipAddress}:${destination.port}`; +} + +export function changeQueryParams(buildId: string) { + const queryParams = new URLSearchParams(window.location.search); + queryParams.set('buildId', buildId); + // @ts-ignore + return history.pushState(null, null, '?' + queryParams.toString()); +} + +export const supportedDatabaseTypesAndVersions = [ + { + name: 'mongodb', + fancyName: 'MongoDB', + baseImage: 'bitnami/mongodb', + versions: ['5.0', '4.4', '4.2'] + }, + { name: 'mysql', fancyName: 'MySQL', baseImage: 'bitnami/mysql', versions: ['8.0', '5.7'] }, + { + name: 'mariadb', + fancyName: 'MariaDB', + baseImage: 'bitnami/mariadb', + versions: ['10.7', '10.6', '10.5', '10.4', '10.3', '10.2'] + }, + { + name: 'postgresql', + fancyName: 'PostgreSQL', + baseImage: 'bitnami/postgresql', + versions: ['14.2.0', '13.6.0', '12.10.0 ', '11.15.0', '10.20.0'] + }, + { + name: 'redis', + fancyName: 'Redis', + baseImage: 'bitnami/redis', + versions: ['6.2', '6.0', '5.0'] + }, + { name: 'couchdb', fancyName: 'CouchDB', baseImage: 'bitnami/couchdb', versions: ['3.2.1'] } +]; + +export const getServiceMainPort = (service: string) => { + const serviceType = supportedServiceTypesAndVersions.find((s) => s.name === service); + if (serviceType) { + return serviceType.ports.main; + } + return null; +}; + + + export function handlerNotFoundLoad(error: any, url: URL) { if (error?.status === 404) { return { diff --git a/apps/ui/src/lib/components/svg/services/Moodle.svelte b/apps/ui/src/lib/components/svg/services/Moodle.svelte new file mode 100644 index 000000000..ad8aec880 --- /dev/null +++ b/apps/ui/src/lib/components/svg/services/Moodle.svelte @@ -0,0 +1,8 @@ + +moodle logo diff --git a/apps/ui/src/lib/components/svg/services/index.ts b/apps/ui/src/lib/components/svg/services/index.ts new file mode 100644 index 000000000..007ded1ce --- /dev/null +++ b/apps/ui/src/lib/components/svg/services/index.ts @@ -0,0 +1,17 @@ +//@ts-nocheck +export { default as PlausibleAnalytics } from './PlausibleAnalytics.svelte'; +export { default as NocoDb } from './NocoDB.svelte'; +export { default as MinIo } from './MinIO.svelte'; +export { default as VsCodeServer } from './VSCodeServer.svelte'; +export { default as Wordpress } from './Wordpress.svelte'; +export { default as VaultWarden } from './VaultWarden.svelte'; +export { default as LanguageTool } from './LanguageTool.svelte'; +export { default as N8n } from './N8n.svelte'; +export { default as UptimeKuma } from './UptimeKuma.svelte'; +export { default as Ghost } from './Ghost.svelte'; +export { default as MeiliSearch } from './MeiliSearch.svelte'; +export { default as Umami } from './Umami.svelte'; +export { default as Hasura } from './Hasura.svelte'; +export { default as Fider } from './Fider.svelte'; +export { default as Moodle } from './Moodle.svelte'; + diff --git a/apps/ui/src/lib/store.ts b/apps/ui/src/lib/store.ts index 668477fa8..245e8d6eb 100644 --- a/apps/ui/src/lib/store.ts +++ b/apps/ui/src/lib/store.ts @@ -44,7 +44,7 @@ export const status: Writable = writable({ initialLoading: true, loading: false, isRunning: false - }, + }, database: { initialLoading: true, loading: false, @@ -57,3 +57,17 @@ export const features = readable({ beta: window.localStorage.getItem('beta') === 'true', latestVersion: window.localStorage.getItem('latestVersion') }); + +export const location: Writable = writable(null) +export const setLocation = (resource: any) => { + console.log(GITPOD_WORKSPACE_URL) + if (GITPOD_WORKSPACE_URL && resource.exposePort) { + const { href } = new URL(GITPOD_WORKSPACE_URL); + const newURL = href + .replace('https://', `https://${resource.exposePort}-`) + .replace(/\/$/, ''); + location.set(newURL) + } else { + location.set(resource.fqdn) + } +} \ No newline at end of file diff --git a/apps/ui/src/routes/applications/[id]/__layout.svelte b/apps/ui/src/routes/applications/[id]/__layout.svelte index d88e445f9..02a1bd330 100644 --- a/apps/ui/src/routes/applications/[id]/__layout.svelte +++ b/apps/ui/src/routes/applications/[id]/__layout.svelte @@ -62,12 +62,13 @@ import { toast } from '@zerodevx/svelte-toast'; import { onDestroy, onMount } from 'svelte'; import { t } from '$lib/translations'; - import { appSession, disabledButton, status } from '$lib/store'; + import { appSession, disabledButton, status, location, setLocation } from '$lib/store'; import { errorNotification, handlerNotFoundLoad } from '$lib/common'; import Loading from '$lib/components/Loading.svelte'; let loading = false; let statusInterval: any; + $disabledButton = !$appSession.isAdmin || !application.fqdn || @@ -75,6 +76,7 @@ !application.repository || !application.destinationDocker || !application.buildPack; + const { id } = $page.params; async function handleDeploySubmit() { @@ -126,9 +128,12 @@ } onDestroy(() => { $status.application.initialLoading = true; + $location = null; clearInterval(statusInterval); }); onMount(async () => { + setLocation(application); + $status.application.isRunning = false; $status.application.isExited = false; $status.application.loading = false; @@ -147,6 +152,30 @@ {#if loading} {:else} + {#if $location} + + + + + + + {/if} + +
{#if $status.application.isExited} Configuration
- {application.name} + {application.name} - - {#if application.fqdn} + {#if application.gitSource?.htmlUrl && application.repository && application.branch} - - - - - - {/if} - - {#if application.gitSource?.type === 'gitlab'} - - - - {:else if application.gitSource?.type === 'github'} - - + - - {/if} - + fill="#FCA326" + d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z" + /> + + {:else if application.gitSource?.type === 'github'} + + + + {/if} + + {/if}
@@ -349,7 +330,6 @@
{application.name}
- - {#if application.fqdn} + {#if application.gitSource?.htmlUrl && application.repository && application.branch} - - - - - - {/if} - - {#if application.gitSource?.type === 'gitlab'} - - - - {:else if application.gitSource?.type === 'github'} - - + - - {/if} - + fill="#FCA326" + d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z" + /> + + {:else if application.gitSource?.type === 'github'} + + + + {/if} + + {/if}
diff --git a/apps/ui/src/routes/applications/[id]/logs/index.svelte b/apps/ui/src/routes/applications/[id]/logs/index.svelte index e327442bd..74eee8f95 100644 --- a/apps/ui/src/routes/applications/[id]/logs/index.svelte +++ b/apps/ui/src/routes/applications/[id]/logs/index.svelte @@ -104,70 +104,49 @@
{application.name}
- - {#if application.fqdn} + {#if application.gitSource?.htmlUrl && application.repository && application.branch} - - - - - - {/if} - - {#if application.gitSource?.type === 'gitlab'} - - - - {:else if application.gitSource?.type === 'github'} - - + - - {/if} - + fill="#FCA326" + d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z" + /> + + {:else if application.gitSource?.type === 'github'} + + + + {/if} + + {/if}
{#if logs.length === 0} diff --git a/apps/ui/src/routes/applications/[id]/previews.svelte b/apps/ui/src/routes/applications/[id]/previews.svelte index bc1db63cb..4653594bb 100644 --- a/apps/ui/src/routes/applications/[id]/previews.svelte +++ b/apps/ui/src/routes/applications/[id]/previews.svelte @@ -64,70 +64,49 @@
{application.name} - - {#if application.fqdn} + {#if application.gitSource?.htmlUrl && application.repository && application.branch} - - - - - - {/if} - - {#if application.gitSource?.type === 'gitlab'} - - - - {:else if application.gitSource?.type === 'github'} - - + - - {/if} - + fill="#FCA326" + d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z" + /> + + {:else if application.gitSource?.type === 'github'} + + + + {/if} + + {/if}
diff --git a/apps/ui/src/routes/applications/[id]/secrets.svelte b/apps/ui/src/routes/applications/[id]/secrets.svelte index 1206681e2..f5c64ea81 100644 --- a/apps/ui/src/routes/applications/[id]/secrets.svelte +++ b/apps/ui/src/routes/applications/[id]/secrets.svelte @@ -5,7 +5,7 @@ const response = await get(`/applications/${params.id}/secrets`); return { props: { - application: stuff.application, + application: stuff.application, ...response } }; @@ -70,70 +70,49 @@
{application.name}
- - {#if application.fqdn} + {#if application.gitSource?.htmlUrl && application.repository && application.branch} - - - - - - {/if} - - {#if application.gitSource?.type === 'gitlab'} - - - - {:else if application.gitSource?.type === 'github'} - - + - - {/if} - + fill="#FCA326" + d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z" + /> + + {:else if application.gitSource?.type === 'github'} + + + + {/if} + + {/if}
diff --git a/apps/ui/src/routes/applications/[id]/storages.svelte b/apps/ui/src/routes/applications/[id]/storages.svelte index d2184e914..96908fa89 100644 --- a/apps/ui/src/routes/applications/[id]/storages.svelte +++ b/apps/ui/src/routes/applications/[id]/storages.svelte @@ -41,70 +41,49 @@ {application.name} - - {#if application.fqdn} + {#if application.gitSource?.htmlUrl && application.repository && application.branch} - - - - - - {/if} - - {#if application.gitSource?.type === 'gitlab'} - - - - {:else if application.gitSource?.type === 'github'} - - + - - {/if} - + fill="#FCA326" + d="M8.42 50.663L1.384 72.31a4.79 4.79 0 001.74 5.357L64 121.894 8.42 50.664z" + /> + + {:else if application.gitSource?.type === 'github'} + + + + {/if} + + {/if}
diff --git a/apps/ui/src/routes/applications/index.svelte b/apps/ui/src/routes/applications/index.svelte index 7effdbb47..e24ecaf72 100644 --- a/apps/ui/src/routes/applications/index.svelte +++ b/apps/ui/src/routes/applications/index.svelte @@ -140,7 +140,7 @@ {#if application.fqdn}
{getDomain(application.fqdn) || ''}
{/if} - {#if !application.gitSourceId} + {#if !application.gitSourceId || !application.repository || !application.branch}
Git Source Missing
diff --git a/apps/ui/src/routes/iam/index.svelte b/apps/ui/src/routes/iam/index.svelte index 4f000dc16..4e75d98ae 100644 --- a/apps/ui/src/routes/iam/index.svelte +++ b/apps/ui/src/routes/iam/index.svelte @@ -53,7 +53,7 @@ return; } try { - await del(`/iam/user/remove`, { uid: id }); + await del(`/iam/user/remove`, { id }); toast.push('Account deleted.'); const data = await get('/iam'); accounts = data.accounts; diff --git a/apps/ui/src/routes/services/[id]/_ServiceLinks.svelte b/apps/ui/src/routes/services/[id]/_ServiceLinks.svelte index 5b07d38f3..e25f3d2d0 100644 --- a/apps/ui/src/routes/services/[id]/_ServiceLinks.svelte +++ b/apps/ui/src/routes/services/[id]/_ServiceLinks.svelte @@ -1,76 +1,63 @@ {#if service.type === 'plausibleanalytics'} - + {:else if service.type === 'nocodb'} - + {:else if service.type === 'minio'} - + {:else if service.type === 'vscodeserver'} - + {:else if service.type === 'wordpress'} - + {:else if service.type === 'vaultwarden'} - + {:else if service.type === 'languagetool'} - + {:else if service.type === 'n8n'} - + {:else if service.type === 'uptimekuma'} - + {:else if service.type === 'ghost'} - + {:else if service.type === 'umami'} - + {:else if service.type === 'hasura'} - + {:else if service.type === 'fider'} - + + +{:else if service.type === 'moodle'} + + {/if} + diff --git a/apps/ui/src/routes/services/[id]/_Services.svelte b/apps/ui/src/routes/services/[id]/_Services.svelte new file mode 100644 index 000000000..65777df36 --- /dev/null +++ b/apps/ui/src/routes/services/[id]/_Services.svelte @@ -0,0 +1,36 @@ + + +{#if type === 'plausibleanalytics'} + +{:else if type === 'nocodb'} + +{:else if type === 'minio'} + +{:else if type === 'vscodeserver'} + +{:else if type === 'wordpress'} + +{:else if type === 'vaultwarden'} + +{:else if type === 'languagetool'} + +{:else if type === 'n8n'} + +{:else if type === 'uptimekuma'} + +{:else if type === 'ghost'} + +{:else if type === 'meilisearch'} + +{:else if type === 'umami'} + +{:else if type === 'hasura'} + +{:else if type === 'fider'} + +{:else if type === 'moodle'} + +{/if} diff --git a/apps/ui/src/routes/services/[id]/_Services/_Moodle.svelte b/apps/ui/src/routes/services/[id]/_Services/_Moodle.svelte new file mode 100644 index 000000000..6cc8cc1fd --- /dev/null +++ b/apps/ui/src/routes/services/[id]/_Services/_Moodle.svelte @@ -0,0 +1,102 @@ + + +
+
Moodle
+
+
+ + +
+
+ + +
+
+ + +
+
+
MariaDB
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
diff --git a/apps/ui/src/routes/services/[id]/_Services/_Services.svelte b/apps/ui/src/routes/services/[id]/_Services/_Services.svelte index 587ab4acd..d856a9278 100644 --- a/apps/ui/src/routes/services/[id]/_Services/_Services.svelte +++ b/apps/ui/src/routes/services/[id]/_Services/_Services.svelte @@ -13,10 +13,10 @@ import { get, post } from '$lib/api'; import { errorNotification } from '$lib/common'; import { t } from '$lib/translations'; - import { appSession, disabledButton, status } from '$lib/store'; + import { appSession, disabledButton, status, location, setLocation } from '$lib/store'; import CopyPasswordField from '$lib/components/CopyPasswordField.svelte'; import Explainer from '$lib/components/Explainer.svelte'; - import Setting from '$lib/components/Setting.svelte' + import Setting from '$lib/components/Setting.svelte'; import Fider from './_Fider.svelte'; import Ghost from './_Ghost.svelte'; @@ -27,6 +27,7 @@ import Umami from './_Umami.svelte'; import VsCodeServer from './_VSCodeServer.svelte'; import Wordpress from './_Wordpress.svelte'; + import Moodle from './_Moodle.svelte'; const { id } = $page.params; @@ -44,6 +45,7 @@ exposePort: service.exposePort }); await post(`/services/${id}`, { ...service }); + setLocation(service) $disabledButton = false; toast.push('Configuration saved.'); } catch (error) { @@ -97,6 +99,7 @@ } }); +
@@ -271,6 +274,8 @@ {:else if service.type === 'fider'} + {:else if service.type === 'moodle'} + {/if}
diff --git a/apps/ui/src/routes/services/[id]/__layout.svelte b/apps/ui/src/routes/services/[id]/__layout.svelte index 30866b1e7..4ed50ed8c 100644 --- a/apps/ui/src/routes/services/[id]/__layout.svelte +++ b/apps/ui/src/routes/services/[id]/__layout.svelte @@ -47,6 +47,7 @@ } }; } catch (error) { + console.log(error); return handlerNotFoundLoad(error, url); } }; @@ -60,7 +61,7 @@ import { goto } from '$app/navigation'; import { t } from '$lib/translations'; import { errorNotification, handlerNotFoundLoad } from '$lib/common'; - import { appSession, disabledButton, status } from '$lib/store'; + import { appSession, disabledButton, status, location, setLocation } from '$lib/store'; import { onDestroy, onMount } from 'svelte'; const { id } = $page.params; @@ -109,7 +110,7 @@ loading = true; try { await post(`/services/${service.id}/${service.type}/start`, {}); - return window.location.reload() + return window.location.reload(); } catch (error) { return errorNotification(error); } finally { @@ -126,9 +127,11 @@ } onDestroy(() => { $status.service.initialLoading = true; + $location = null; clearInterval(statusInterval); }); onMount(async () => { + setLocation(service); $status.service.isRunning = false; $status.service.loading = false; if (service.type && service.destinationDockerId && service.version && service.fqdn) { @@ -147,6 +150,29 @@ {:else} {#if service.type && service.destinationDockerId && service.version} + {#if $location} + + + + + + +
+ {/if} {#if $status.service.initialLoading}
diff --git a/apps/ui/src/routes/services/[id]/index.svelte b/apps/ui/src/routes/services/[id]/index.svelte index bc6edd71f..c503e3552 100644 --- a/apps/ui/src/routes/services/[id]/index.svelte +++ b/apps/ui/src/routes/services/[id]/index.svelte @@ -57,30 +57,6 @@
{service.name}
- - {#if service.fqdn} - - - - - - - {/if} -
diff --git a/apps/ui/src/routes/services/index.svelte b/apps/ui/src/routes/services/index.svelte index dff275142..a32e11711 100644 --- a/apps/ui/src/routes/services/index.svelte +++ b/apps/ui/src/routes/services/index.svelte @@ -24,22 +24,9 @@ import { t } from '$lib/translations'; import { appSession } from '$lib/store'; - import PlausibleAnalytics from '$lib/components/svg/services/PlausibleAnalytics.svelte'; - import NocoDb from '$lib/components/svg/services/NocoDB.svelte'; - import MinIo from '$lib/components/svg/services/MinIO.svelte'; - import VsCodeServer from '$lib/components/svg/services/VSCodeServer.svelte'; - import Wordpress from '$lib/components/svg/services/Wordpress.svelte'; - import VaultWarden from '$lib/components/svg/services/VaultWarden.svelte'; - import LanguageTool from '$lib/components/svg/services/LanguageTool.svelte'; - - import N8n from '$lib/components/svg/services/N8n.svelte'; - import UptimeKuma from '$lib/components/svg/services/UptimeKuma.svelte'; - import Ghost from '$lib/components/svg/services/Ghost.svelte'; - import MeiliSearch from '$lib/components/svg/services/MeiliSearch.svelte'; - import Umami from '$lib/components/svg/services/Umami.svelte'; - import Hasura from '$lib/components/svg/services/Hasura.svelte'; - import Fider from '$lib/components/svg/services/Fider.svelte'; + import * as Icons from '$lib/components/svg/services'; import { getDomain } from '$lib/common'; + import Services from './[id]/_Services.svelte'; async function newService() { const { id } = await post('/services/new', {}); @@ -88,35 +75,7 @@ {#each ownServices as service}
- {#if service.type === 'plausibleanalytics'} - - {:else if service.type === 'nocodb'} - - {:else if service.type === 'minio'} - - {:else if service.type === 'vscodeserver'} - - {:else if service.type === 'wordpress'} - - {:else if service.type === 'vaultwarden'} - - {:else if service.type === 'languagetool'} - - {:else if service.type === 'n8n'} - - {:else if service.type === 'uptimekuma'} - - {:else if service.type === 'ghost'} - - {:else if service.type === 'meilisearch'} - - {:else if service.type === 'umami'} - - {:else if service.type === 'hasura'} - - {:else if service.type === 'fider'} - - {/if} +
{service.name}
@@ -141,35 +100,7 @@ {#each otherServices as service}
- {#if service.type === 'plausibleanalytics'} - - {:else if service.type === 'nocodb'} - - {:else if service.type === 'minio'} - - {:else if service.type === 'vscodeserver'} - - {:else if service.type === 'wordpress'} - - {:else if service.type === 'vaultwarden'} - - {:else if service.type === 'languagetool'} - - {:else if service.type === 'n8n'} - - {:else if service.type === 'uptimekuma'} - - {:else if service.type === 'ghost'} - - {:else if service.type === 'meilisearch'} - - {:else if service.type === 'umami'} - - {:else if service.type === 'hasura'} - - {:else if service.type === 'fider'} - - {/if} +
{service.name}
diff --git a/apps/ui/src/routes/sources/[id]/_Gitlab.svelte b/apps/ui/src/routes/sources/[id]/_Gitlab.svelte index 77db14eea..694f41c53 100644 --- a/apps/ui/src/routes/sources/[id]/_Gitlab.svelte +++ b/apps/ui/src/routes/sources/[id]/_Gitlab.svelte @@ -225,7 +225,7 @@ disabled={source.gitlabAppId} readonly={source.gitlabAppId} required - value={source.apiUrl} + bind:value={source.apiUrl} />
diff --git a/apps/ui/src/routes/webhooks/success.svelte b/apps/ui/src/routes/webhooks/success.svelte index a216b8276..469e4f8da 100644 --- a/apps/ui/src/routes/webhooks/success.svelte +++ b/apps/ui/src/routes/webhooks/success.svelte @@ -1,6 +1,6 @@ diff --git a/apps/ui/static/moodle.png b/apps/ui/static/moodle.png new file mode 100644 index 000000000..a5cec5be7 Binary files /dev/null and b/apps/ui/static/moodle.png differ diff --git a/apps/ui/vite.config.js b/apps/ui/vite.config.js index f60afcdf9..99685581c 100644 --- a/apps/ui/vite.config.js +++ b/apps/ui/vite.config.js @@ -7,6 +7,7 @@ export default { 'GITPOD_WORKSPACE_URL': JSON.stringify(process.env.GITPOD_WORKSPACE_URL) }, server: { + port: 3000, hmr: process.env.GITPOD_WORKSPACE_URL ? { // Due to port fowarding, we have to replace diff --git a/package.json b/package.json index e6b7f6407..4d7071d38 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "coolify", "description": "An open-source & self-hostable Heroku / Netlify alternative.", - "version": "3.1.2", + "version": "3.1.3", "license": "AGPL-3.0", "scripts": { "db:studio": "pnpm run --filter coolify-api db:studio", @@ -20,7 +20,7 @@ "build:ui": "NODE_ENV=production pnpm run --filter coolify-ui build", "dockerlogin":"echo $DOCKER_PASS | docker login --username=$DOCKER_USER --password-stdin", "release:staging:amd": "cross-var docker buildx build --platform linux/amd64 -t coollabsio/coolify:$npm_package_version --push .", - "release:local":"rm -fr ./local-serve && mkdir ./local-serve && pnpm build && cp -Rp apps/api/build/* ./local-serve && cp -Rp apps/ui/build/ ./local-serve/public && cp -Rp apps/api/prisma/ ./local-serve/prisma && cp -Rp apps/api/package.json ./local-serve && cp .env ./local-serve && cd ./local-serve && pnpm install . && pnpm start" + "release:local":"rm -fr ./local-serve && mkdir ./local-serve && pnpm build && cp -Rp apps/api/build/* ./local-serve && cp -Rp apps/ui/build/ ./local-serve/public && cp -Rp apps/api/prisma/ ./local-serve/prisma && cp -Rp apps/api/package.json ./local-serve && env | grep '^COOLIFY_' > ./local-serve/.env && cd ./local-serve && pnpm install . && pnpm start" }, "devDependencies": { "cross-var": "1.1.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a295a0786..88ef19cd0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,18 +13,18 @@ importers: apps/api: specifiers: '@breejs/ts-worker': 2.0.0 - '@fastify/autoload': 5.0.0 - '@fastify/cookie': 7.0.0 + '@fastify/autoload': 5.1.0 + '@fastify/cookie': 7.1.0 '@fastify/cors': 8.0.0 '@fastify/env': 4.0.0 - '@fastify/jwt': 6.2.0 + '@fastify/jwt': 6.3.1 '@fastify/static': 6.4.0 '@iarna/toml': 2.2.5 '@prisma/client': 3.15.2 - '@types/node': 18.0.3 + '@types/node': 18.0.4 '@types/node-os-utils': 1.3.0 - '@typescript-eslint/eslint-plugin': 5.30.5 - '@typescript-eslint/parser': 5.30.5 + '@typescript-eslint/eslint-plugin': 5.30.6 + '@typescript-eslint/parser': 5.30.6 axios: 0.27.2 bcryptjs: 2.4.3 bree: 9.1.1 @@ -34,12 +34,12 @@ importers: dayjs: 1.11.3 dockerode: 3.3.2 dotenv-extended: 2.9.0 - esbuild: 0.14.48 + esbuild: 0.14.49 eslint: 8.19.0 eslint-config-prettier: 8.5.0 eslint-plugin-prettier: 4.2.1 - fastify: 4.2.0 - fastify-plugin: 3.0.1 + fastify: 4.2.1 + fastify-plugin: 4.0.0 generate-password: 1.7.0 get-port: 6.1.2 got: 12.1.0 @@ -53,17 +53,18 @@ importers: prettier: 2.7.1 prisma: 3.15.2 rimraf: 3.0.2 + shared: workspace:* strip-ansi: 7.0.1 tsconfig-paths: 4.0.0 typescript: 4.7.4 unique-names-generator: 4.7.1 dependencies: - '@breejs/ts-worker': 2.0.0_6iibbo7rh4755pyipjtynkbezq - '@fastify/autoload': 5.0.0 - '@fastify/cookie': 7.0.0 + '@breejs/ts-worker': 2.0.0_t3dw2jfpvj5qtbx4qztd4nt754 + '@fastify/autoload': 5.1.0 + '@fastify/cookie': 7.1.0 '@fastify/cors': 8.0.0 '@fastify/env': 4.0.0 - '@fastify/jwt': 6.2.0 + '@fastify/jwt': 6.3.1 '@fastify/static': 6.4.0 '@iarna/toml': 2.2.5 '@prisma/client': 3.15.2_prisma@3.15.2 @@ -76,8 +77,8 @@ importers: dayjs: 1.11.3 dockerode: 3.3.2 dotenv-extended: 2.9.0 - fastify: 4.2.0 - fastify-plugin: 3.0.1 + fastify: 4.2.1 + fastify-plugin: 4.0.0 generate-password: 1.7.0 get-port: 6.1.2 got: 12.1.0 @@ -87,14 +88,15 @@ importers: node-forge: 1.3.1 node-os-utils: 1.3.7 p-queue: 7.2.0 + shared: link:../shared strip-ansi: 7.0.1 unique-names-generator: 4.7.1 devDependencies: - '@types/node': 18.0.3 + '@types/node': 18.0.4 '@types/node-os-utils': 1.3.0 - '@typescript-eslint/eslint-plugin': 5.30.5_6zdoc3rn4mpiddqwhppni2mnnm - '@typescript-eslint/parser': 5.30.5_4x5o4skxv6sl53vpwefgt23khm - esbuild: 0.14.48 + '@typescript-eslint/eslint-plugin': 5.30.6_2vt5mtrqleafs33qg2bhpmbaqm + '@typescript-eslint/parser': 5.30.6_4x5o4skxv6sl53vpwefgt23khm + esbuild: 0.14.49 eslint: 8.19.0 eslint-config-prettier: 8.5.0_eslint@8.19.0 eslint-plugin-prettier: 4.2.1_7uxdfn2xinezdgvmbammh6ev5i @@ -105,15 +107,24 @@ importers: tsconfig-paths: 4.0.0 typescript: 4.7.4 + apps/shared: + specifiers: + esbuild: 0.14.49 + nodemon: 2.0.19 + rimraf: 3.0.2 + devDependencies: + esbuild: 0.14.49 + nodemon: 2.0.19 + rimraf: 3.0.2 + apps/ui: specifiers: - '@playwright/test': 1.23.1 - '@sveltejs/adapter-auto': 1.0.0-next.53 - '@sveltejs/adapter-static': 1.0.0-next.34 - '@sveltejs/kit': 1.0.0-next.359 + '@playwright/test': 1.23.3 + '@sveltejs/adapter-static': 1.0.0-next.36 + '@sveltejs/kit': 1.0.0-next.375 '@types/js-cookie': 3.0.2 - '@typescript-eslint/eslint-plugin': 5.30.5 - '@typescript-eslint/parser': 5.30.5 + '@typescript-eslint/eslint-plugin': 5.30.6 + '@typescript-eslint/parser': 5.30.6 '@zerodevx/svelte-toast': 0.7.2 autoprefixer: 10.4.7 cuid: 2.1.8 @@ -125,46 +136,47 @@ importers: postcss: 8.4.14 prettier: 2.7.1 prettier-plugin-svelte: 2.7.0 - svelte: 3.48.0 + shared: workspace:* + svelte: 3.49.0 svelte-check: 2.8.0 svelte-preprocess: 4.10.7 svelte-select: 4.4.7 sveltekit-i18n: 2.2.2 - tailwindcss: 3.1.4 + tailwindcss: 3.1.6 tailwindcss-scrollbar: 0.1.0 tslib: 2.4.0 typescript: 4.7.4 - vite: ^2.9.13 + vite: ^3.0.0 dependencies: - '@sveltejs/adapter-static': 1.0.0-next.34 + '@sveltejs/adapter-static': 1.0.0-next.36 '@zerodevx/svelte-toast': 0.7.2 cuid: 2.1.8 js-cookie: 3.0.1 p-limit: 4.0.0 + shared: link:../shared svelte-select: 4.4.7 - sveltekit-i18n: 2.2.2_svelte@3.48.0 + sveltekit-i18n: 2.2.2_svelte@3.49.0 devDependencies: - '@playwright/test': 1.23.1 - '@sveltejs/adapter-auto': 1.0.0-next.53 - '@sveltejs/kit': 1.0.0-next.359_svelte@3.48.0+vite@2.9.13 + '@playwright/test': 1.23.3 + '@sveltejs/kit': 1.0.0-next.375_svelte@3.49.0+vite@3.0.0 '@types/js-cookie': 3.0.2 - '@typescript-eslint/eslint-plugin': 5.30.5_6zdoc3rn4mpiddqwhppni2mnnm - '@typescript-eslint/parser': 5.30.5_4x5o4skxv6sl53vpwefgt23khm + '@typescript-eslint/eslint-plugin': 5.30.6_2vt5mtrqleafs33qg2bhpmbaqm + '@typescript-eslint/parser': 5.30.6_4x5o4skxv6sl53vpwefgt23khm autoprefixer: 10.4.7_postcss@8.4.14 eslint: 8.19.0 eslint-config-prettier: 8.5.0_eslint@8.19.0 - eslint-plugin-svelte3: 4.0.0_m4jpobot6gi3xtcba7bv5cflma + eslint-plugin-svelte3: 4.0.0_jxmmfmurkts274jdspwh3cyqve postcss: 8.4.14 prettier: 2.7.1 - prettier-plugin-svelte: 2.7.0_nakrehnrzdf7fdea5k3a4dfy4m - svelte: 3.48.0 - svelte-check: 2.8.0_s3dopqgs4h45owyu2kxaf6kyfu - svelte-preprocess: 4.10.7_jr4mgafwdbjtobsadg2hrd5qfy - tailwindcss: 3.1.4 - tailwindcss-scrollbar: 0.1.0_tailwindcss@3.1.4 + prettier-plugin-svelte: 2.7.0_o3ioganyptcsrh6x4hnxvjkpqi + svelte: 3.49.0 + svelte-check: 2.8.0_nxvsp6sjiltnatqa6jdm4mr6zu + svelte-preprocess: 4.10.7_bgntxiihuqhg5mwaa7nczjwpga + tailwindcss: 3.1.6 + tailwindcss-scrollbar: 0.1.0_tailwindcss@3.1.6 tslib: 2.4.0 typescript: 4.7.4 - vite: 2.9.13 + vite: 3.0.0 packages: @@ -201,14 +213,14 @@ packages: engines: {node: '>= 10'} dev: false - /@breejs/ts-worker/2.0.0_6iibbo7rh4755pyipjtynkbezq: + /@breejs/ts-worker/2.0.0_t3dw2jfpvj5qtbx4qztd4nt754: resolution: {integrity: sha512-6anHRcmgYlF7mrm/YVRn6rx2cegLuiY3VBxkkimOTWC/dVQeH336imVSuIKEGKTwiuNTPr2hswVdDSneNuXg3A==} engines: {node: '>= 12.11'} peerDependencies: bree: '>=9.0.0' dependencies: bree: 9.1.1 - ts-node: 10.8.2_fxk5i3xm3ivo7fjwhcizcinpla + ts-node: 10.8.2_2zqz24ol5yhbv2blv4fh7akzrq tsconfig-paths: 4.0.0 transitivePeerDependencies: - '@swc/core' @@ -249,15 +261,16 @@ packages: fast-uri: 2.1.0 dev: false - /@fastify/autoload/5.0.0: - resolution: {integrity: sha512-hayrT8U3cUxQDvQSINGb5+TX9n9KPh9wSAB2LxPFXiKPFzfu+G1+lZ2Uh26Ej9trzq9jZlsYbx4xUzEeFVkJZw==} + /@fastify/autoload/5.1.0: + resolution: {integrity: sha512-FcZf3sy/8P6GObc6g2MrRqW1ricDtUm/xDK9i1PNH4Aaqj83DkkmADWTyQvE92OR0gy5EjPGPUcBHY7NzvHRUg==} dependencies: pkg-up: 3.1.0 dev: false - /@fastify/cookie/7.0.0: - resolution: {integrity: sha512-/JQcHR4bsFGRo39esT1GTxB0MsMd3loJxNfHYV0MRduXvdiDJd94okiCBlPOesRxwA5dJCqFNo80J7muHG+T+w==} + /@fastify/cookie/7.1.0: + resolution: {integrity: sha512-ofAlIthvJ2aWOrzdbUen1Lx09AKk2zvdaUrWh2+0aNt+gajRA7KyR8bzwCD2AwS+2nacjEuSRIyckotMHG95hQ==} dependencies: + cookie: 0.5.0 cookie-signature: 1.2.0 fastify-plugin: 3.0.1 dev: false @@ -286,13 +299,13 @@ packages: fast-json-stringify: 5.0.5 dev: false - /@fastify/jwt/6.2.0: - resolution: {integrity: sha512-j2hjMi0XP6WRZGVKUuhDHUeEg7QQ5edJoiKIYFPWON6hDdDRrUcDOsRQkNi2KPbjlzDPFGNq0d5iDK9gFVs2dA==} + /@fastify/jwt/6.3.1: + resolution: {integrity: sha512-JRcm+l7CEsK66aOraxgGGie1VuiQtg/4RALVeQULEPDWvKGL08zK0JXCtibsX3dmdzpaFxYE/9oA8vAbnQ9YTg==} dependencies: + '@fastify/error': 3.0.0 '@lukeed/ms': 2.0.0 fast-jwt: 1.5.4 - fastify-plugin: 3.0.1 - http-errors: 2.0.0 + fastify-plugin: 4.0.0 steed: 1.1.3 dev: false @@ -327,6 +340,7 @@ packages: /@iarna/toml/2.2.5: resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} + dev: false /@jridgewell/resolve-uri/3.0.7: resolution: {integrity: sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==} @@ -335,19 +349,11 @@ packages: /@jridgewell/sourcemap-codec/1.4.13: resolution: {integrity: sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==} - /@jridgewell/trace-mapping/0.3.13: - resolution: {integrity: sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==} - dependencies: - '@jridgewell/resolve-uri': 3.0.7 - '@jridgewell/sourcemap-codec': 1.4.13 - dev: true - /@jridgewell/trace-mapping/0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: '@jridgewell/resolve-uri': 3.0.7 '@jridgewell/sourcemap-codec': 1.4.13 - dev: false /@ladjs/format-util/1.0.4: resolution: {integrity: sha512-hZere0rUga8kTzSTFbHREXpD9E/jwi94+B5RyLAmMIzl/w/EK1z7rFEnMHzPkU4AZkL42JWSsGXoV8LXMihybg==} @@ -358,24 +364,6 @@ packages: engines: {node: '>=8'} dev: false - /@mapbox/node-pre-gyp/1.0.9: - resolution: {integrity: sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==} - hasBin: true - dependencies: - detect-libc: 2.0.1 - https-proxy-agent: 5.0.1 - make-dir: 3.1.0 - node-fetch: 2.6.7 - nopt: 5.0.0 - npmlog: 5.0.1 - rimraf: 3.0.2 - semver: 7.3.7 - tar: 6.1.11 - transitivePeerDependencies: - - encoding - - supports-color - dev: true - /@nodelib/fs.scandir/2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -397,13 +385,13 @@ packages: fastq: 1.13.0 dev: true - /@playwright/test/1.23.1: - resolution: {integrity: sha512-dKplLPSYPZgnsBk1xxOophhpx3ZVg8DveoNJgLPe096lDCfmaIIreLsYF+4hqzy3PG61IP+aEnG5VAOjC3bhbA==} + /@playwright/test/1.23.3: + resolution: {integrity: sha512-kR4vo2UGHC84DGqE6EwvAeaehj3xCAK6LoC1P1eu6ZGdC79rlqRKf8cFDx6q6c9T8MQSL1O9eOlup0BpwqNF0w==} engines: {node: '>=14'} hasBin: true dependencies: - '@types/node': 18.0.1 - playwright-core: 1.23.1 + '@types/node': 18.0.3 + playwright-core: 1.23.3 dev: true /@prisma/client/3.15.2_prisma@3.15.2: @@ -441,74 +429,37 @@ packages: engines: {node: '>=10'} dev: false - /@sveltejs/adapter-auto/1.0.0-next.53: - resolution: {integrity: sha512-LyaeU0rkcymGWvV/3K26AZxqG/+ZQHwa+hrx3xsbmOykjQ2WQPTXRVwmH23zV4A5ABvni76LRMsQOoqWzP3G9Q==} - dependencies: - '@sveltejs/adapter-cloudflare': 1.0.0-next.24 - '@sveltejs/adapter-netlify': 1.0.0-next.66 - '@sveltejs/adapter-vercel': 1.0.0-next.59 - transitivePeerDependencies: - - encoding - - supports-color - dev: true - - /@sveltejs/adapter-cloudflare/1.0.0-next.24: - resolution: {integrity: sha512-g1QSrjWYjM6sfJB+pQn52EIfbVFjpk23GYsj5PLt2Gi3zRNfLRbpkFkPeyAOZbAfT4k/9lUqfLW+pkh+W3yxlg==} - dependencies: - esbuild: 0.14.48 - worktop: 0.8.0-next.14 - dev: true - - /@sveltejs/adapter-netlify/1.0.0-next.66: - resolution: {integrity: sha512-UypTRnTd+R1O6SaDdc8l3A3c9/mQF8xLNoVb3Ay5ipb7uPU5WmjVYjfLVGyeVy67gztFfeFC/9Esu4OI2Ayx1A==} - dependencies: - '@iarna/toml': 2.2.5 - esbuild: 0.14.48 - set-cookie-parser: 2.4.8 - tiny-glob: 0.2.9 - dev: true - - /@sveltejs/adapter-static/1.0.0-next.34: - resolution: {integrity: sha512-XjuMhemme5z0L/B2nTZpA6k+RJjF+b6L96ts6gIQ6ixiCzJQSbBqJhrrBYBCaeLAKvdUMoGEmX8m862JhKjRFg==} + /@sveltejs/adapter-static/1.0.0-next.36: + resolution: {integrity: sha512-1g3W4wHPyBtUGy5zCDBA2nMG3mM36FKTP1zb0vNRBpoUmtNuzVFF74UVsHCpMC1GpPyrgOq9idfjkm4gRabisw==} dependencies: tiny-glob: 0.2.9 dev: false - /@sveltejs/adapter-vercel/1.0.0-next.59: - resolution: {integrity: sha512-1lq5IFLWiLUXmNJVUXjwaInDb07BJg5er43xlMilpFpTA9BZI2hqjYCgtdtk7O6ee5EYJk876b2riM1m+y1M4Q==} - dependencies: - '@vercel/nft': 0.20.1 - esbuild: 0.14.48 - transitivePeerDependencies: - - encoding - - supports-color - dev: true - - /@sveltejs/kit/1.0.0-next.359_svelte@3.48.0+vite@2.9.13: - resolution: {integrity: sha512-3WH198JhOI9rmDlVSPPHlgg+/R/gS4x5cETjYsIw3XckpN2zExDqlYHUBUwk/dEG/12BfPB3rDMNzdZ0QHtubQ==} - engines: {node: '>=16.7'} + /@sveltejs/kit/1.0.0-next.375_svelte@3.49.0+vite@3.0.0: + resolution: {integrity: sha512-9+gKm97TW/xIz6DfWOqdsIwGY4yckUkmMFlsJmEGkjcTy60Q6ZCfrQhMULzL/fILLydF0wZcD/fWE/urAbp2nw==} + engines: {node: '>=16.9'} hasBin: true peerDependencies: svelte: ^3.44.0 - vite: ^2.9.10 + vite: ^3.0.0 dependencies: - '@sveltejs/vite-plugin-svelte': 1.0.0-next.49_svelte@3.48.0+vite@2.9.13 + '@sveltejs/vite-plugin-svelte': 1.0.1_svelte@3.49.0+vite@3.0.0 chokidar: 3.5.3 sade: 1.8.1 - svelte: 3.48.0 - vite: 2.9.13 + svelte: 3.49.0 + vite: 3.0.0 transitivePeerDependencies: - diff-match-patch - supports-color dev: true - /@sveltejs/vite-plugin-svelte/1.0.0-next.49_svelte@3.48.0+vite@2.9.13: - resolution: {integrity: sha512-AKh0Ka8EDgidnxWUs8Hh2iZLZovkETkefO99XxZ4sW4WGJ7VFeBx5kH/NIIGlaNHLcrIvK3CK0HkZwC3Cici0A==} - engines: {node: ^14.13.1 || >= 16} + /@sveltejs/vite-plugin-svelte/1.0.1_svelte@3.49.0+vite@3.0.0: + resolution: {integrity: sha512-PorCgUounn0VXcpeJu+hOweZODKmGuLHsLomwqSj+p26IwjjGffmYQfVHtiTWq+NqaUuuHWWG7vPge6UFw4Aeg==} + engines: {node: ^14.18.0 || >= 16} peerDependencies: diff-match-patch: ^1.0.5 svelte: ^3.44.0 - vite: ^2.9.0 + vite: ^3.0.0 peerDependenciesMeta: diff-match-patch: optional: true @@ -516,21 +467,21 @@ packages: '@rollup/pluginutils': 4.2.1 debug: 4.3.4 deepmerge: 4.2.2 - kleur: 4.1.4 + kleur: 4.1.5 magic-string: 0.26.2 - svelte: 3.48.0 - svelte-hmr: 0.14.12_svelte@3.48.0 - vite: 2.9.13 + svelte: 3.49.0 + svelte-hmr: 0.14.12_svelte@3.49.0 + vite: 3.0.0 transitivePeerDependencies: - supports-color dev: true - /@sveltekit-i18n/base/1.2.1_svelte@3.48.0: + /@sveltekit-i18n/base/1.2.1_svelte@3.49.0: resolution: {integrity: sha512-F8gqG2+KAOeT0o2wYlUrW3TRCX7zaD7rBy/1CEVNw0irfw9TgFf/ODmhubkHHT3+6Zk+SMz8RNgeuffBfAMbJw==} peerDependencies: svelte: ^3.x dependencies: - svelte: 3.48.0 + svelte: 3.49.0 optionalDependencies: '@sveltekit-i18n/parser-default': 1.0.3 dev: false @@ -567,7 +518,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 18.0.3 + '@types/node': 18.0.4 '@types/responselike': 1.0.0 dev: false @@ -590,7 +541,7 @@ packages: /@types/keyv/3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 18.0.3 + '@types/node': 18.0.4 dev: false /@types/lodash/4.14.182: @@ -601,12 +552,12 @@ packages: resolution: {integrity: sha512-XwVteWQx/XkfRPyaGkw8dEbrCAkoRZ73pI3XznUYIpzbCfpQB3UnDlR5TnmdhetlT889tUJGF8QWo9xrgTpsiA==} dev: true - /@types/node/18.0.1: - resolution: {integrity: sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg==} - dev: true - /@types/node/18.0.3: resolution: {integrity: sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==} + dev: true + + /@types/node/18.0.4: + resolution: {integrity: sha512-M0+G6V0Y4YV8cqzHssZpaNCqvYwlCiulmm0PwpNLF55r/+cT8Ol42CHRU1SEaYFH2rTwiiE1aYg/2g2rrtGdPA==} /@types/normalize-package-data/2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} @@ -619,17 +570,17 @@ packages: /@types/responselike/1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 18.0.3 + '@types/node': 18.0.4 dev: false /@types/sass/1.43.1: resolution: {integrity: sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==} dependencies: - '@types/node': 18.0.1 + '@types/node': 18.0.3 dev: true - /@typescript-eslint/eslint-plugin/5.30.5_6zdoc3rn4mpiddqwhppni2mnnm: - resolution: {integrity: sha512-lftkqRoBvc28VFXEoRgyZuztyVUQ04JvUnATSPtIRFAccbXTWL6DEtXGYMcbg998kXw1NLUJm7rTQ9eUt+q6Ig==} + /@typescript-eslint/eslint-plugin/5.30.6_2vt5mtrqleafs33qg2bhpmbaqm: + resolution: {integrity: sha512-J4zYMIhgrx4MgnZrSDD7sEnQp7FmhKNOaqaOpaoQ/SfdMfRB/0yvK74hTnvH+VQxndZynqs5/Hn4t+2/j9bADg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -639,10 +590,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.30.5_4x5o4skxv6sl53vpwefgt23khm - '@typescript-eslint/scope-manager': 5.30.5 - '@typescript-eslint/type-utils': 5.30.5_4x5o4skxv6sl53vpwefgt23khm - '@typescript-eslint/utils': 5.30.5_4x5o4skxv6sl53vpwefgt23khm + '@typescript-eslint/parser': 5.30.6_4x5o4skxv6sl53vpwefgt23khm + '@typescript-eslint/scope-manager': 5.30.6 + '@typescript-eslint/type-utils': 5.30.6_4x5o4skxv6sl53vpwefgt23khm + '@typescript-eslint/utils': 5.30.6_4x5o4skxv6sl53vpwefgt23khm debug: 4.3.4 eslint: 8.19.0 functional-red-black-tree: 1.0.1 @@ -655,8 +606,8 @@ packages: - supports-color dev: true - /@typescript-eslint/parser/5.30.5_4x5o4skxv6sl53vpwefgt23khm: - resolution: {integrity: sha512-zj251pcPXI8GO9NDKWWmygP6+UjwWmrdf9qMW/L/uQJBM/0XbU2inxe5io/234y/RCvwpKEYjZ6c1YrXERkK4Q==} + /@typescript-eslint/parser/5.30.6_4x5o4skxv6sl53vpwefgt23khm: + resolution: {integrity: sha512-gfF9lZjT0p2ZSdxO70Xbw8w9sPPJGfAdjK7WikEjB3fcUI/yr9maUVEdqigBjKincUYNKOmf7QBMiTf719kbrA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -665,9 +616,9 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.30.5 - '@typescript-eslint/types': 5.30.5 - '@typescript-eslint/typescript-estree': 5.30.5_typescript@4.7.4 + '@typescript-eslint/scope-manager': 5.30.6 + '@typescript-eslint/types': 5.30.6 + '@typescript-eslint/typescript-estree': 5.30.6_typescript@4.7.4 debug: 4.3.4 eslint: 8.19.0 typescript: 4.7.4 @@ -675,16 +626,16 @@ packages: - supports-color dev: true - /@typescript-eslint/scope-manager/5.30.5: - resolution: {integrity: sha512-NJ6F+YHHFT/30isRe2UTmIGGAiXKckCyMnIV58cE3JkHmaD6e5zyEYm5hBDv0Wbin+IC0T1FWJpD3YqHUG/Ydg==} + /@typescript-eslint/scope-manager/5.30.6: + resolution: {integrity: sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.30.5 - '@typescript-eslint/visitor-keys': 5.30.5 + '@typescript-eslint/types': 5.30.6 + '@typescript-eslint/visitor-keys': 5.30.6 dev: true - /@typescript-eslint/type-utils/5.30.5_4x5o4skxv6sl53vpwefgt23khm: - resolution: {integrity: sha512-k9+ejlv1GgwN1nN7XjVtyCgE0BTzhzT1YsQF0rv4Vfj2U9xnslBgMYYvcEYAFVdvhuEscELJsB7lDkN7WusErw==} + /@typescript-eslint/type-utils/5.30.6_4x5o4skxv6sl53vpwefgt23khm: + resolution: {integrity: sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -693,7 +644,7 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/utils': 5.30.5_4x5o4skxv6sl53vpwefgt23khm + '@typescript-eslint/utils': 5.30.6_4x5o4skxv6sl53vpwefgt23khm debug: 4.3.4 eslint: 8.19.0 tsutils: 3.21.0_typescript@4.7.4 @@ -702,13 +653,13 @@ packages: - supports-color dev: true - /@typescript-eslint/types/5.30.5: - resolution: {integrity: sha512-kZ80w/M2AvsbRvOr3PjaNh6qEW1LFqs2pLdo2s5R38B2HYXG8Z0PP48/4+j1QHJFL3ssHIbJ4odPRS8PlHrFfw==} + /@typescript-eslint/types/5.30.6: + resolution: {integrity: sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree/5.30.5_typescript@4.7.4: - resolution: {integrity: sha512-qGTc7QZC801kbYjAr4AgdOfnokpwStqyhSbiQvqGBLixniAKyH+ib2qXIVo4P9NgGzwyfD9I0nlJN7D91E1VpQ==} + /@typescript-eslint/typescript-estree/5.30.6_typescript@4.7.4: + resolution: {integrity: sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -716,8 +667,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.30.5 - '@typescript-eslint/visitor-keys': 5.30.5 + '@typescript-eslint/types': 5.30.6 + '@typescript-eslint/visitor-keys': 5.30.6 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 @@ -728,16 +679,16 @@ packages: - supports-color dev: true - /@typescript-eslint/utils/5.30.5_4x5o4skxv6sl53vpwefgt23khm: - resolution: {integrity: sha512-o4SSUH9IkuA7AYIfAvatldovurqTAHrfzPApOZvdUq01hHojZojCFXx06D/aFpKCgWbMPRdJBWAC3sWp3itwTA==} + /@typescript-eslint/utils/5.30.6_4x5o4skxv6sl53vpwefgt23khm: + resolution: {integrity: sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@types/json-schema': 7.0.11 - '@typescript-eslint/scope-manager': 5.30.5 - '@typescript-eslint/types': 5.30.5 - '@typescript-eslint/typescript-estree': 5.30.5_typescript@4.7.4 + '@typescript-eslint/scope-manager': 5.30.6 + '@typescript-eslint/types': 5.30.6 + '@typescript-eslint/typescript-estree': 5.30.6_typescript@4.7.4 eslint: 8.19.0 eslint-scope: 5.1.1 eslint-utils: 3.0.0_eslint@8.19.0 @@ -746,33 +697,14 @@ packages: - typescript dev: true - /@typescript-eslint/visitor-keys/5.30.5: - resolution: {integrity: sha512-D+xtGo9HUMELzWIUqcQc0p2PO4NyvTrgIOK/VnSH083+8sq0tiLozNRKuLarwHYGRuA6TVBQSuuLwJUDWd3aaA==} + /@typescript-eslint/visitor-keys/5.30.6: + resolution: {integrity: sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.30.5 + '@typescript-eslint/types': 5.30.6 eslint-visitor-keys: 3.3.0 dev: true - /@vercel/nft/0.20.1: - resolution: {integrity: sha512-hSLcr64KHOkcNiTAlv154K4p4faEFBwYIi2eIgu1QCDhB1qyQYvFuEhtw3eaapNjA4/7x/2jcclfCAjILua/ag==} - hasBin: true - dependencies: - '@mapbox/node-pre-gyp': 1.0.9 - acorn: 8.7.1 - bindings: 1.5.0 - estree-walker: 2.0.2 - glob: 7.2.3 - graceful-fs: 4.2.10 - micromatch: 4.0.5 - node-gyp-build: 4.4.0 - resolve-from: 5.0.0 - rollup-pluginutils: 2.8.2 - transitivePeerDependencies: - - encoding - - supports-color - dev: true - /@zerodevx/svelte-toast/0.7.2: resolution: {integrity: sha512-vWiY6IqsstcOoQ8PFBuFuxgPkj1JFAGhUF9gC7wLx7c5A9SSfdtxWs/39ekGSIeyJK0yqWhTcmzGrCEWSELzDw==} dev: false @@ -829,15 +761,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - /agent-base/6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - dependencies: - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - /ajv-formats/2.1.1: resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} peerDependenciesMeta: @@ -911,22 +834,10 @@ packages: picomatch: 2.3.1 dev: true - /aproba/2.0.0: - resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} - dev: true - /archy/1.0.0: resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} dev: false - /are-we-there-yet/2.0.0: - resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} - engines: {node: '>=10'} - dependencies: - delegates: 1.0.0 - readable-stream: 3.6.0 - dev: true - /arg/4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} dev: false @@ -984,8 +895,8 @@ packages: peerDependencies: postcss: ^8.1.0 dependencies: - browserslist: 4.20.3 - caniuse-lite: 1.0.30001343 + browserslist: 4.21.2 + caniuse-lite: 1.0.30001366 fraction.js: 4.2.0 normalize-range: 0.1.2 picocolors: 1.0.0 @@ -1729,12 +1640,6 @@ packages: engines: {node: '>=8'} dev: true - /bindings/1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - dependencies: - file-uri-to-path: 1.0.0 - dev: true - /bl/4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} dependencies: @@ -1791,16 +1696,15 @@ packages: resolution: {integrity: sha512-kzXheikaJsBtzUBlyVtPIY5r0soQePzjwVwT4IlDpU2RvfB5Py52gpU98M77rgqMCheoSSZvrcrdj3t6cZ3suA==} dev: false - /browserslist/4.20.3: - resolution: {integrity: sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==} + /browserslist/4.21.2: + resolution: {integrity: sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001343 - electron-to-chromium: 1.4.139 - escalade: 3.1.1 - node-releases: 2.0.5 - picocolors: 1.0.0 + caniuse-lite: 1.0.30001366 + electron-to-chromium: 1.4.191 + node-releases: 2.0.6 + update-browserslist-db: 1.0.4_browserslist@4.21.2 dev: true /bson-objectid/1.3.1: @@ -1883,8 +1787,8 @@ packages: engines: {node: '>=6'} dev: false - /caniuse-lite/1.0.30001343: - resolution: {integrity: sha512-8KeCrAtPMabo/XW14B+R9sZYoClx1n0b+WYgwDKZPtWR3TcdvWzdSy7mPyFEmR5WU1St9v1PW6sdO5dkFOEzfA==} + /caniuse-lite/1.0.30001366: + resolution: {integrity: sha512-yy7XLWCubDobokgzudpkKux8e0UOOnLHE6mlNJBzT3lZJz6s5atSEzjoL+fsCPkI0G8MP5uVdDx1ur/fXEWkZA==} dev: true /chalk/1.1.3: @@ -1933,11 +1837,6 @@ packages: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} dev: false - /chownr/2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} - dev: true - /clf-date/0.2.0: resolution: {integrity: sha512-KmV+reIoSINOik5moU6eOqSUy3r/9t6J6Dbl4TCndg1g0R6Z3S3xHzd3u0ZeoTUSbUFr9hHbpiZ+36MrhlNEHQ==} hasBin: true @@ -1968,11 +1867,6 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true - /color-support/1.1.3: - resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} - hasBin: true - dev: true - /combine-errors/3.0.3: resolution: {integrity: sha512-C8ikRNRMygCwaTx+Ek3Yr+OuZzgZjduCOfSQBjbM8V3MfgcjSTeto/GXP6PAwKvJz/v15b7GHZvx5rOlczFw/Q==} dependencies: @@ -2007,10 +1901,6 @@ packages: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} dev: true - /console-control-strings/1.1.0: - resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} - dev: true - /console-polyfill/0.3.0: resolution: {integrity: sha512-w+JSDZS7XML43Xnwo2x5O5vxB0ID7T5BdqDtyqT6uiCAX2kZAgcWxNaGqT97tZfSHzfOcvrfsDAodKcJ3UvnXQ==} dev: false @@ -2054,7 +1944,7 @@ packages: /core-js/2.6.12: resolution: {integrity: sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==} - deprecated: core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js. + deprecated: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. requiresBuild: true dev: true @@ -2210,10 +2100,6 @@ packages: engines: {node: '>=0.4.0'} dev: false - /delegates/1.0.0: - resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} - dev: true - /depd/2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -2236,11 +2122,6 @@ packages: engines: {node: '>=8'} dev: true - /detect-libc/2.0.1: - resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==} - engines: {node: '>=8'} - dev: true - /detective/5.2.1: resolution: {integrity: sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==} engines: {node: '>=0.8.0'} @@ -2349,12 +2230,8 @@ packages: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} dev: false - /electron-to-chromium/1.4.139: - resolution: {integrity: sha512-lYxzcUCjWxxVug+A7UxBCUiVr13TCjfZFYJS9Lq1VpU/ErwV4a6zUQo9dfojuGpw/L/x9REGuBl6ICQPGgbs3g==} - dev: true - - /emoji-regex/8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + /electron-to-chromium/1.4.191: + resolution: {integrity: sha512-MeEaiuoSFh4G+rrN+Ilm1KJr8pTTZloeLurcZ+PRcthvdK1gWThje+E6baL7/7LoNctrzCncavAG/j/vpES9jg==} dev: true /encodeurl/1.0.2: @@ -2428,8 +2305,8 @@ packages: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} dev: true - /esbuild-android-64/0.14.48: - resolution: {integrity: sha512-3aMjboap/kqwCUpGWIjsk20TtxVoKck8/4Tu19rubh7t5Ra0Yrpg30Mt1QXXlipOazrEceGeWurXKeFJgkPOUg==} + /esbuild-android-64/0.14.49: + resolution: {integrity: sha512-vYsdOTD+yi+kquhBiFWl3tyxnj2qZJsl4tAqwhT90ktUdnyTizgle7TjNx6Ar1bN7wcwWqZ9QInfdk2WVagSww==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -2437,8 +2314,8 @@ packages: dev: true optional: true - /esbuild-android-arm64/0.14.48: - resolution: {integrity: sha512-vptI3K0wGALiDq+EvRuZotZrJqkYkN5282iAfcffjI5lmGG9G1ta/CIVauhY42MBXwEgDJkweiDcDMRLzBZC4g==} + /esbuild-android-arm64/0.14.49: + resolution: {integrity: sha512-g2HGr/hjOXCgSsvQZ1nK4nW/ei8JUx04Li74qub9qWrStlysaVmadRyTVuW32FGIpLQyc5sUjjZopj49eGGM2g==} engines: {node: '>=12'} cpu: [arm64] os: [android] @@ -2446,8 +2323,8 @@ packages: dev: true optional: true - /esbuild-darwin-64/0.14.48: - resolution: {integrity: sha512-gGQZa4+hab2Va/Zww94YbshLuWteyKGD3+EsVon8EWTWhnHFRm5N9NbALNbwi/7hQ/hM1Zm4FuHg+k6BLsl5UA==} + /esbuild-darwin-64/0.14.49: + resolution: {integrity: sha512-3rvqnBCtX9ywso5fCHixt2GBCUsogNp9DjGmvbBohh31Ces34BVzFltMSxJpacNki96+WIcX5s/vum+ckXiLYg==} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -2455,8 +2332,8 @@ packages: dev: true optional: true - /esbuild-darwin-arm64/0.14.48: - resolution: {integrity: sha512-bFjnNEXjhZT+IZ8RvRGNJthLWNHV5JkCtuOFOnjvo5pC0sk2/QVk0Qc06g2PV3J0TcU6kaPC3RN9yy9w2PSLEA==} + /esbuild-darwin-arm64/0.14.49: + resolution: {integrity: sha512-XMaqDxO846srnGlUSJnwbijV29MTKUATmOLyQSfswbK/2X5Uv28M9tTLUJcKKxzoo9lnkYPsx2o8EJcTYwCs/A==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -2464,8 +2341,8 @@ packages: dev: true optional: true - /esbuild-freebsd-64/0.14.48: - resolution: {integrity: sha512-1NOlwRxmOsnPcWOGTB10JKAkYSb2nue0oM1AfHWunW/mv3wERfJmnYlGzL3UAOIUXZqW8GeA2mv+QGwq7DToqA==} + /esbuild-freebsd-64/0.14.49: + resolution: {integrity: sha512-NJ5Q6AjV879mOHFri+5lZLTp5XsO2hQ+KSJYLbfY9DgCu8s6/Zl2prWXVANYTeCDLlrIlNNYw8y34xqyLDKOmQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -2473,8 +2350,8 @@ packages: dev: true optional: true - /esbuild-freebsd-arm64/0.14.48: - resolution: {integrity: sha512-gXqKdO8wabVcYtluAbikDH2jhXp+Klq5oCD5qbVyUG6tFiGhrC9oczKq3vIrrtwcxDQqK6+HDYK8Zrd4bCA9Gw==} + /esbuild-freebsd-arm64/0.14.49: + resolution: {integrity: sha512-lFLtgXnAc3eXYqj5koPlBZvEbBSOSUbWO3gyY/0+4lBdRqELyz4bAuamHvmvHW5swJYL7kngzIZw6kdu25KGOA==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -2482,8 +2359,8 @@ packages: dev: true optional: true - /esbuild-linux-32/0.14.48: - resolution: {integrity: sha512-ghGyDfS289z/LReZQUuuKq9KlTiTspxL8SITBFQFAFRA/IkIvDpnZnCAKTCjGXAmUqroMQfKJXMxyjJA69c/nQ==} + /esbuild-linux-32/0.14.49: + resolution: {integrity: sha512-zTTH4gr2Kb8u4QcOpTDVn7Z8q7QEIvFl/+vHrI3cF6XOJS7iEI1FWslTo3uofB2+mn6sIJEQD9PrNZKoAAMDiA==} engines: {node: '>=12'} cpu: [ia32] os: [linux] @@ -2491,8 +2368,8 @@ packages: dev: true optional: true - /esbuild-linux-64/0.14.48: - resolution: {integrity: sha512-vni3p/gppLMVZLghI7oMqbOZdGmLbbKR23XFARKnszCIBpEMEDxOMNIKPmMItQrmH/iJrL1z8Jt2nynY0bE1ug==} + /esbuild-linux-64/0.14.49: + resolution: {integrity: sha512-hYmzRIDzFfLrB5c1SknkxzM8LdEUOusp6M2TnuQZJLRtxTgyPnZZVtyMeCLki0wKgYPXkFsAVhi8vzo2mBNeTg==} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -2500,8 +2377,8 @@ packages: dev: true optional: true - /esbuild-linux-arm/0.14.48: - resolution: {integrity: sha512-+VfSV7Akh1XUiDNXgqgY1cUP1i2vjI+BmlyXRfVz5AfV3jbpde8JTs5Q9sYgaoq5cWfuKfoZB/QkGOI+QcL1Tw==} + /esbuild-linux-arm/0.14.49: + resolution: {integrity: sha512-iE3e+ZVv1Qz1Sy0gifIsarJMQ89Rpm9mtLSRtG3AH0FPgAzQ5Z5oU6vYzhc/3gSPi2UxdCOfRhw2onXuFw/0lg==} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -2509,8 +2386,8 @@ packages: dev: true optional: true - /esbuild-linux-arm64/0.14.48: - resolution: {integrity: sha512-3CFsOlpoxlKPRevEHq8aAntgYGYkE1N9yRYAcPyng/p4Wyx0tPR5SBYsxLKcgPB9mR8chHEhtWYz6EZ+H199Zw==} + /esbuild-linux-arm64/0.14.49: + resolution: {integrity: sha512-KLQ+WpeuY+7bxukxLz5VgkAAVQxUv67Ft4DmHIPIW+2w3ObBPQhqNoeQUHxopoW/aiOn3m99NSmSV+bs4BSsdA==} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -2518,8 +2395,8 @@ packages: dev: true optional: true - /esbuild-linux-mips64le/0.14.48: - resolution: {integrity: sha512-cs0uOiRlPp6ymknDnjajCgvDMSsLw5mST2UXh+ZIrXTj2Ifyf2aAP3Iw4DiqgnyYLV2O/v/yWBJx+WfmKEpNLA==} + /esbuild-linux-mips64le/0.14.49: + resolution: {integrity: sha512-n+rGODfm8RSum5pFIqFQVQpYBw+AztL8s6o9kfx7tjfK0yIGF6tm5HlG6aRjodiiKkH2xAiIM+U4xtQVZYU4rA==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -2527,8 +2404,8 @@ packages: dev: true optional: true - /esbuild-linux-ppc64le/0.14.48: - resolution: {integrity: sha512-+2F0vJMkuI0Wie/wcSPDCqXvSFEELH7Jubxb7mpWrA/4NpT+/byjxDz0gG6R1WJoeDefcrMfpBx4GFNN1JQorQ==} + /esbuild-linux-ppc64le/0.14.49: + resolution: {integrity: sha512-WP9zR4HX6iCBmMFH+XHHng2LmdoIeUmBpL4aL2TR8ruzXyT4dWrJ5BSbT8iNo6THN8lod6GOmYDLq/dgZLalGw==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -2536,8 +2413,8 @@ packages: dev: true optional: true - /esbuild-linux-riscv64/0.14.48: - resolution: {integrity: sha512-BmaK/GfEE+5F2/QDrIXteFGKnVHGxlnK9MjdVKMTfvtmudjY3k2t8NtlY4qemKSizc+QwyombGWTBDc76rxePA==} + /esbuild-linux-riscv64/0.14.49: + resolution: {integrity: sha512-h66ORBz+Dg+1KgLvzTVQEA1LX4XBd1SK0Fgbhhw4akpG/YkN8pS6OzYI/7SGENiN6ao5hETRDSkVcvU9NRtkMQ==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -2545,8 +2422,8 @@ packages: dev: true optional: true - /esbuild-linux-s390x/0.14.48: - resolution: {integrity: sha512-tndw/0B9jiCL+KWKo0TSMaUm5UWBLsfCKVdbfMlb3d5LeV9WbijZ8Ordia8SAYv38VSJWOEt6eDCdOx8LqkC4g==} + /esbuild-linux-s390x/0.14.49: + resolution: {integrity: sha512-DhrUoFVWD+XmKO1y7e4kNCqQHPs6twz6VV6Uezl/XHYGzM60rBewBF5jlZjG0nCk5W/Xy6y1xWeopkrhFFM0sQ==} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -2554,8 +2431,8 @@ packages: dev: true optional: true - /esbuild-netbsd-64/0.14.48: - resolution: {integrity: sha512-V9hgXfwf/T901Lr1wkOfoevtyNkrxmMcRHyticybBUHookznipMOHoF41Al68QBsqBxnITCEpjjd4yAos7z9Tw==} + /esbuild-netbsd-64/0.14.49: + resolution: {integrity: sha512-BXaUwFOfCy2T+hABtiPUIpWjAeWK9P8O41gR4Pg73hpzoygVGnj0nI3YK4SJhe52ELgtdgWP/ckIkbn2XaTxjQ==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -2563,8 +2440,8 @@ packages: dev: true optional: true - /esbuild-openbsd-64/0.14.48: - resolution: {integrity: sha512-+IHf4JcbnnBl4T52egorXMatil/za0awqzg2Vy6FBgPcBpisDWT2sVz/tNdrK9kAqj+GZG/jZdrOkj7wsrNTKA==} + /esbuild-openbsd-64/0.14.49: + resolution: {integrity: sha512-lP06UQeLDGmVPw9Rg437Btu6J9/BmyhdoefnQ4gDEJTtJvKtQaUcOQrhjTq455ouZN4EHFH1h28WOJVANK41kA==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -2572,8 +2449,8 @@ packages: dev: true optional: true - /esbuild-sunos-64/0.14.48: - resolution: {integrity: sha512-77m8bsr5wOpOWbGi9KSqDphcq6dFeJyun8TA+12JW/GAjyfTwVtOnN8DOt6DSPUfEV+ltVMNqtXUeTeMAxl5KA==} + /esbuild-sunos-64/0.14.49: + resolution: {integrity: sha512-4c8Zowp+V3zIWje329BeLbGh6XI9c/rqARNaj5yPHdC61pHI9UNdDxT3rePPJeWcEZVKjkiAS6AP6kiITp7FSw==} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -2581,8 +2458,8 @@ packages: dev: true optional: true - /esbuild-windows-32/0.14.48: - resolution: {integrity: sha512-EPgRuTPP8vK9maxpTGDe5lSoIBHGKO/AuxDncg5O3NkrPeLNdvvK8oywB0zGaAZXxYWfNNSHskvvDgmfVTguhg==} + /esbuild-windows-32/0.14.49: + resolution: {integrity: sha512-q7Rb+J9yHTeKr9QTPDYkqfkEj8/kcKz9lOabDuvEXpXuIcosWCJgo5Z7h/L4r7rbtTH4a8U2FGKb6s1eeOHmJA==} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -2590,8 +2467,8 @@ packages: dev: true optional: true - /esbuild-windows-64/0.14.48: - resolution: {integrity: sha512-YmpXjdT1q0b8ictSdGwH3M8VCoqPpK1/UArze3X199w6u8hUx3V8BhAi1WjbsfDYRBanVVtduAhh2sirImtAvA==} + /esbuild-windows-64/0.14.49: + resolution: {integrity: sha512-+Cme7Ongv0UIUTniPqfTX6mJ8Deo7VXw9xN0yJEN1lQMHDppTNmKwAM3oGbD/Vqff+07K2gN0WfNkMohmG+dVw==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -2599,8 +2476,8 @@ packages: dev: true optional: true - /esbuild-windows-arm64/0.14.48: - resolution: {integrity: sha512-HHaOMCsCXp0rz5BT2crTka6MPWVno121NKApsGs/OIW5QC0ggC69YMGs1aJct9/9FSUF4A1xNE/cLvgB5svR4g==} + /esbuild-windows-arm64/0.14.49: + resolution: {integrity: sha512-v+HYNAXzuANrCbbLFJ5nmO3m5y2PGZWLe3uloAkLt87aXiO2mZr3BTmacZdjwNkNEHuH3bNtN8cak+mzVjVPfA==} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -2608,32 +2485,32 @@ packages: dev: true optional: true - /esbuild/0.14.48: - resolution: {integrity: sha512-w6N1Yn5MtqK2U1/WZTX9ZqUVb8IOLZkZ5AdHkT6x3cHDMVsYWC7WPdiLmx19w3i4Rwzy5LqsEMtVihG3e4rFzA==} + /esbuild/0.14.49: + resolution: {integrity: sha512-/TlVHhOaq7Yz8N1OJrjqM3Auzo5wjvHFLk+T8pIue+fhnhIMpfAzsG6PLVMbFveVxqD2WOp3QHei+52IMUNmCw==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - esbuild-android-64: 0.14.48 - esbuild-android-arm64: 0.14.48 - esbuild-darwin-64: 0.14.48 - esbuild-darwin-arm64: 0.14.48 - esbuild-freebsd-64: 0.14.48 - esbuild-freebsd-arm64: 0.14.48 - esbuild-linux-32: 0.14.48 - esbuild-linux-64: 0.14.48 - esbuild-linux-arm: 0.14.48 - esbuild-linux-arm64: 0.14.48 - esbuild-linux-mips64le: 0.14.48 - esbuild-linux-ppc64le: 0.14.48 - esbuild-linux-riscv64: 0.14.48 - esbuild-linux-s390x: 0.14.48 - esbuild-netbsd-64: 0.14.48 - esbuild-openbsd-64: 0.14.48 - esbuild-sunos-64: 0.14.48 - esbuild-windows-32: 0.14.48 - esbuild-windows-64: 0.14.48 - esbuild-windows-arm64: 0.14.48 + esbuild-android-64: 0.14.49 + esbuild-android-arm64: 0.14.49 + esbuild-darwin-64: 0.14.49 + esbuild-darwin-arm64: 0.14.49 + esbuild-freebsd-64: 0.14.49 + esbuild-freebsd-arm64: 0.14.49 + esbuild-linux-32: 0.14.49 + esbuild-linux-64: 0.14.49 + esbuild-linux-arm: 0.14.49 + esbuild-linux-arm64: 0.14.49 + esbuild-linux-mips64le: 0.14.49 + esbuild-linux-ppc64le: 0.14.49 + esbuild-linux-riscv64: 0.14.49 + esbuild-linux-s390x: 0.14.49 + esbuild-netbsd-64: 0.14.49 + esbuild-openbsd-64: 0.14.49 + esbuild-sunos-64: 0.14.49 + esbuild-windows-32: 0.14.49 + esbuild-windows-64: 0.14.49 + esbuild-windows-arm64: 0.14.49 dev: true /escalade/3.1.1: @@ -2680,14 +2557,14 @@ packages: prettier-linter-helpers: 1.0.0 dev: true - /eslint-plugin-svelte3/4.0.0_m4jpobot6gi3xtcba7bv5cflma: + /eslint-plugin-svelte3/4.0.0_jxmmfmurkts274jdspwh3cyqve: resolution: {integrity: sha512-OIx9lgaNzD02+MDFNLw0GEUbuovNcglg+wnd/UY0fbZmlQSz7GlQiQ1f+yX0XvC07XPcDOnFcichqI3xCwp71g==} peerDependencies: eslint: '>=8.0.0' svelte: ^3.2.0 dependencies: eslint: 8.19.0 - svelte: 3.48.0 + svelte: 3.49.0 dev: true /eslint-scope/5.1.1: @@ -2803,10 +2680,6 @@ packages: engines: {node: '>=4.0'} dev: true - /estree-walker/0.6.1: - resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} - dev: true - /estree-walker/2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} dev: true @@ -2904,8 +2777,12 @@ packages: resolution: {integrity: sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA==} dev: false - /fastify/4.2.0: - resolution: {integrity: sha512-0QXEp+8ceKc0fwVakeBLM/1Ss/+fc7a3auuygT+1GjbSAgHfwqxSucUuu0rYjziu32UgEZXfjItYN/a89HWKhw==} + /fastify-plugin/4.0.0: + resolution: {integrity: sha512-ZJcXPPcqkj7HFDYqbsCuOIAgIZ/sd2b+OnBxNGyxAcUDUJfIpxp4t23CwxO2E7LZpqUrIliA4TnjxTXG8mLoqw==} + dev: false + + /fastify/4.2.1: + resolution: {integrity: sha512-eyAWHN9+8IPTnhvGz+leseASGV/JZ75Y+jXXV7tid4awUjCMInY1gazZXuTD95xUW+Ve5vfgLjQ2i1i0/XJjdw==} dependencies: '@fastify/ajv-compiler': 3.1.1 '@fastify/error': 3.0.0 @@ -2951,10 +2828,6 @@ packages: flat-cache: 3.0.4 dev: true - /file-uri-to-path/1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - dev: true - /fill-range/7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} @@ -3051,13 +2924,6 @@ packages: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} dev: false - /fs-minipass/2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - dependencies: - minipass: 3.1.6 - dev: true - /fs.realpath/1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -3096,21 +2962,6 @@ packages: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true - /gauge/3.0.2: - resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} - engines: {node: '>=10'} - dependencies: - aproba: 2.0.0 - color-support: 1.1.3 - console-control-strings: 1.1.0 - has-unicode: 2.0.1 - object-assign: 4.1.1 - signal-exit: 3.0.7 - string-width: 4.2.3 - strip-ansi: 6.0.1 - wide-align: 1.1.5 - dev: true - /generate-password/1.7.0: resolution: {integrity: sha512-WPCtlfy0jexf7W5IbwxGUgpIDvsZIohbI2DAq2Q6TSlKKis+G4GT9sxvPxrZUGL8kP6WUXMWNqYnxY6DDKAdFA==} dev: false @@ -3197,6 +3048,7 @@ packages: /globalyzer/0.1.0: resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} + dev: false /globby/11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} @@ -3212,6 +3064,7 @@ packages: /globrex/0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + dev: false /got/12.1.0: resolution: {integrity: sha512-hBv2ty9QN2RdbJJMK3hesmSkFTjVIHyIDDbssCKnSmq62edGgImJWD10Eb1k77TiV1bxloxqcFAVK8+9pkhOig==} @@ -3273,10 +3126,6 @@ packages: has-symbols: 1.0.3 dev: true - /has-unicode/2.0.1: - resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - dev: true - /has/1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} @@ -3328,16 +3177,6 @@ packages: resolve-alpn: 1.2.1 dev: false - /https-proxy-agent/5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - dependencies: - agent-base: 6.0.2 - debug: 4.3.4 - transitivePeerDependencies: - - supports-color - dev: true - /human-interval/2.0.1: resolution: {integrity: sha512-r4Aotzf+OtKIGQCB3odUowy4GfUDTy3aTWTfLd7ZF2gBCy3XW3v/dJLRefZnOFFnjqs5B1TypvS8WarpBkYUNQ==} dependencies: @@ -3473,11 +3312,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /is-fullwidth-code-point/3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true - /is-glob/2.0.1: resolution: {integrity: sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==} engines: {node: '>=0.10.0'} @@ -3691,8 +3525,8 @@ packages: json-buffer: 3.0.1 dev: false - /kleur/4.1.4: - resolution: {integrity: sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==} + /kleur/4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} dev: true @@ -3719,8 +3553,8 @@ packages: set-cookie-parser: 2.4.8 dev: false - /lilconfig/2.0.5: - resolution: {integrity: sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==} + /lilconfig/2.0.6: + resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==} engines: {node: '>=10'} dev: true @@ -3729,7 +3563,7 @@ packages: dev: false /load-json-file/4.0.0: - resolution: {integrity: sha1-L19Fq5HjMhYjT9U62rZo607AmTs=} + resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} engines: {node: '>=4'} dependencies: graceful-fs: 4.2.10 @@ -3881,19 +3715,12 @@ packages: sourcemap-codec: 1.4.8 dev: true - /make-dir/3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} - dependencies: - semver: 6.3.0 - dev: true - /make-error/1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} dev: false /memorystream/0.3.1: - resolution: {integrity: sha1-htcJCzDORV1j+64S3aUaR93K+bI=} + resolution: {integrity: sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==} engines: {node: '>= 0.10.0'} dev: true @@ -3974,21 +3801,6 @@ packages: /minimist/1.2.6: resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} - /minipass/3.1.6: - resolution: {integrity: sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==} - engines: {node: '>=8'} - dependencies: - yallist: 4.0.0 - dev: true - - /minizlib/2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} - dependencies: - minipass: 3.1.6 - yallist: 4.0.0 - dev: true - /mkdirp-classic/0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} dev: false @@ -4000,12 +3812,6 @@ packages: minimist: 1.2.6 dev: true - /mkdirp/1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - dev: true - /mnemonist/0.39.1: resolution: {integrity: sha512-bY13FSvcbKLj+FaJcR2+xFZ3m2R1+BrLpavAh0BMyGSq0iPowbvYllwitlkvVyEowEYSulCMzxDaju9bC4+cow==} dependencies: @@ -4017,11 +3823,6 @@ packages: engines: {node: '>=4'} dev: true - /mrmime/1.0.0: - resolution: {integrity: sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==} - engines: {node: '>=10'} - dev: true - /ms/2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} @@ -4064,34 +3865,17 @@ packages: lower-case: 1.1.4 dev: false - /node-fetch/2.6.7: - resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - dependencies: - whatwg-url: 5.0.0 - dev: true - /node-forge/1.3.1: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} dev: false - /node-gyp-build/4.4.0: - resolution: {integrity: sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==} - hasBin: true - dev: true - /node-os-utils/1.3.7: resolution: {integrity: sha512-fvnX9tZbR7WfCG5BAy3yO/nCLyjVWD6MghEq0z5FDfN+ZXpLWNITBdbifxQkQ25ebr16G0N7eRWJisOcMEHG3Q==} dev: false - /node-releases/2.0.5: - resolution: {integrity: sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==} + /node-releases/2.0.6: + resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} dev: true /nodemon/2.0.19: @@ -4123,14 +3907,6 @@ packages: abbrev: 1.1.1 dev: true - /nopt/5.0.0: - resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} - engines: {node: '>=6'} - hasBin: true - dependencies: - abbrev: 1.1.1 - dev: true - /normalize-package-data/2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: @@ -4145,7 +3921,7 @@ packages: dev: true /normalize-range/0.1.2: - resolution: {integrity: sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=} + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} dev: true @@ -4170,24 +3946,10 @@ packages: string.prototype.padend: 3.1.3 dev: true - /npmlog/5.0.1: - resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} - dependencies: - are-we-there-yet: 2.0.0 - console-control-strings: 1.1.0 - gauge: 3.0.2 - set-blocking: 2.0.0 - dev: true - /numbered/1.1.0: resolution: {integrity: sha512-pv/ue2Odr7IfYOO0byC1KgBI10wo5YDauLhxY6/saNzAdAs0r1SotGCPzzCLNPL0xtrAwWRialLu23AAu9xO1g==} dev: false - /object-assign/4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - dev: true - /object-hash/3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} @@ -4355,7 +4117,7 @@ packages: dev: false /parse-json/4.0.0: - resolution: {integrity: sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=} + resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} engines: {node: '>=4'} dependencies: error-ex: 1.3.2 @@ -4414,7 +4176,7 @@ packages: dev: true /path-key/2.0.1: - resolution: {integrity: sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=} + resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} engines: {node: '>=4'} dev: true @@ -4458,7 +4220,7 @@ packages: dev: true /pify/3.0.0: - resolution: {integrity: sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=} + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} engines: {node: '>=4'} dev: true @@ -4497,8 +4259,8 @@ packages: find-up: 3.0.0 dev: false - /playwright-core/1.23.1: - resolution: {integrity: sha512-9CXsE0gawph4KXl6oUaa0ehHRySZjHvly4TybcBXDvzK3N3o6L/eZ8Q6iVWUiMn0LLS5bRFxo1qEtOETlYJxjw==} + /playwright-core/1.23.3: + resolution: {integrity: sha512-x35yzsXDyo0BIXYimLnUFNyb42c//NadUNH6IPGOteZm96oTGA1kn4Hq6qJTI1/f9wEc1F9O1DsznXIgXMil7A==} engines: {node: '>=14'} hasBin: true dev: true @@ -4512,7 +4274,7 @@ packages: postcss: 8.4.14 postcss-value-parser: 4.2.0 read-cache: 1.0.0 - resolve: 1.22.0 + resolve: 1.22.1 dev: true /postcss-js/4.0.0_postcss@8.4.14: @@ -4537,7 +4299,7 @@ packages: ts-node: optional: true dependencies: - lilconfig: 2.0.5 + lilconfig: 2.0.6 postcss: 8.4.14 yaml: 1.10.2 dev: true @@ -4585,14 +4347,14 @@ packages: fast-diff: 1.2.0 dev: true - /prettier-plugin-svelte/2.7.0_nakrehnrzdf7fdea5k3a4dfy4m: + /prettier-plugin-svelte/2.7.0_o3ioganyptcsrh6x4hnxvjkpqi: resolution: {integrity: sha512-fQhhZICprZot2IqEyoiUYLTRdumULGRvw0o4dzl5jt0jfzVWdGqeYW27QTWAeXhoupEZJULmNoH3ueJwUWFLIA==} peerDependencies: prettier: ^1.16.4 || ^2.0.0 svelte: ^3.2.0 dependencies: prettier: 2.7.1 - svelte: 3.48.0 + svelte: 3.49.0 dev: true /prettier/2.7.1: @@ -4701,7 +4463,7 @@ packages: dev: false /read-pkg/3.0.0: - resolution: {integrity: sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=} + resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==} engines: {node: '>=4'} dependencies: load-json-file: 4.0.0 @@ -4726,6 +4488,7 @@ packages: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 + dev: false /readable-stream/4.0.0: resolution: {integrity: sha512-Mf7ilWBP6AV3tF3MjtBrHMH3roso7wIrpgzCwt9ybvqiJQVWIEBMnp/W+S//yvYSsUUi2cJIwD7q7m57l0AqZw==} @@ -4775,11 +4538,6 @@ packages: functions-have-names: 1.2.3 dev: true - /regexparam/2.0.0: - resolution: {integrity: sha512-gJKwd2MVPWHAIFLsaYDZfyKzHNS4o7E/v8YmNf44vmeV2e4YfVoDToTOKTvE7ab68cRJ++kLuEXJBaEeJVt5ow==} - engines: {node: '>=8'} - dev: true - /regexpp/3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} @@ -4829,11 +4587,6 @@ packages: engines: {node: '>=4'} dev: true - /resolve-from/5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - dev: true - /resolve/1.22.0: resolution: {integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==} hasBin: true @@ -4842,6 +4595,15 @@ packages: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + /resolve/1.22.1: + resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} + hasBin: true + dependencies: + is-core-module: 2.9.0 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + /responselike/2.0.0: resolution: {integrity: sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==} dependencies: @@ -4875,14 +4637,8 @@ packages: glob: 7.2.3 dev: true - /rollup-pluginutils/2.8.2: - resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} - dependencies: - estree-walker: 0.6.1 - dev: true - - /rollup/2.75.7: - resolution: {integrity: sha512-VSE1iy0eaAYNCxEXaleThdFXqZJ42qDBatAwrfnPlENEZ8erQ+0LYX4JXOLPceWfZpV1VtZwZ3dFCuOZiSyFtQ==} + /rollup/2.77.0: + resolution: {integrity: sha512-vL8xjY4yOQEw79DvyXLijhnhh+R/O9zpF/LEgkCebZFtb6ELeN9H3/2T0r8+mp+fFTBHZ5qGpOpW2ela2zRt3g==} engines: {node: '>=10.0.0'} hasBin: true optionalDependencies: @@ -4908,6 +4664,7 @@ packages: /safe-buffer/5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false /safe-regex2/2.0.0: resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==} @@ -4945,11 +4702,6 @@ packages: resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} hasBin: true - /semver/6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} - hasBin: true - dev: true - /semver/7.0.0: resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} hasBin: true @@ -4987,19 +4739,16 @@ packages: resolution: {integrity: sha512-6oGOAj9wPBKEuzJxqrN1sxMHJKbWOg7D2zNYOXaKrDC4lP6FpAw2MVuZd4okp/KqtRxkgLMweEd6HM1+c4m8Yg==} dev: false - /set-blocking/2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - dev: true - /set-cookie-parser/2.4.8: resolution: {integrity: sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg==} + dev: false /setprototypeof/1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} dev: false /shebang-command/1.2.0: - resolution: {integrity: sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=} + resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} engines: {node: '>=0.10.0'} dependencies: shebang-regex: 1.0.0 @@ -5012,7 +4761,7 @@ packages: shebang-regex: 3.0.0 /shebang-regex/1.0.0: - resolution: {integrity: sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=} + resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} engines: {node: '>=0.10.0'} dev: true @@ -5031,10 +4780,6 @@ packages: get-intrinsic: 1.1.1 object-inspect: 1.12.1 - /signal-exit/3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true - /simple-update-notifier/1.0.7: resolution: {integrity: sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==} engines: {node: '>=8.10.0'} @@ -5142,15 +4887,6 @@ packages: reusify: 1.0.4 dev: false - /string-width/4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - dev: true - /string.prototype.padend/3.1.3: resolution: {integrity: sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg==} engines: {node: '>= 0.4'} @@ -5180,6 +4916,7 @@ packages: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} dependencies: safe-buffer: 5.2.1 + dev: false /strip-ansi/3.0.1: resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} @@ -5259,20 +4996,20 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - /svelte-check/2.8.0_s3dopqgs4h45owyu2kxaf6kyfu: + /svelte-check/2.8.0_nxvsp6sjiltnatqa6jdm4mr6zu: resolution: {integrity: sha512-HRL66BxffMAZusqe5I5k26mRWQ+BobGd9Rxm3onh7ZVu0nTk8YTKJ9vu3LVPjUGLU9IX7zS+jmwPVhJYdXJ8vg==} hasBin: true peerDependencies: svelte: ^3.24.0 dependencies: - '@jridgewell/trace-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.9 chokidar: 3.5.3 fast-glob: 3.2.11 import-fresh: 3.3.0 picocolors: 1.0.0 sade: 1.8.1 - svelte: 3.48.0 - svelte-preprocess: 4.10.7_jr4mgafwdbjtobsadg2hrd5qfy + svelte: 3.49.0 + svelte-preprocess: 4.10.7_bgntxiihuqhg5mwaa7nczjwpga typescript: 4.7.4 transitivePeerDependencies: - '@babel/core' @@ -5287,16 +5024,16 @@ packages: - sugarss dev: true - /svelte-hmr/0.14.12_svelte@3.48.0: + /svelte-hmr/0.14.12_svelte@3.49.0: resolution: {integrity: sha512-4QSW/VvXuqVcFZ+RhxiR8/newmwOCTlbYIezvkeN6302YFRE8cXy0naamHcjz8Y9Ce3ITTZtrHrIL0AGfyo61w==} engines: {node: ^12.20 || ^14.13.1 || >= 16} peerDependencies: svelte: '>=3.19.0' dependencies: - svelte: 3.48.0 + svelte: 3.49.0 dev: true - /svelte-preprocess/4.10.7_jr4mgafwdbjtobsadg2hrd5qfy: + /svelte-preprocess/4.10.7_bgntxiihuqhg5mwaa7nczjwpga: resolution: {integrity: sha512-sNPBnqYD6FnmdBrUmBCaqS00RyCsCpj2BG58A1JBswNF7b0OKviwxqVrOL/CKyJrLSClrSeqQv5BXNg2RUbPOw==} engines: {node: '>= 9.11.2'} requiresBuild: true @@ -5344,7 +5081,7 @@ packages: postcss: 8.4.14 sorcery: 0.10.0 strip-indent: 3.0.0 - svelte: 3.48.0 + svelte: 3.49.0 typescript: 4.7.4 dev: true @@ -5352,30 +5089,30 @@ packages: resolution: {integrity: sha512-fIf9Z8rPI6F8naHZ9wjXT0Pv5gLyhdHAFkHFJnCfVVfELE8e82uOoF0xEVQP6Kir+b4Q5yOvNAzZ61WbSU6A0A==} dev: false - /svelte/3.48.0: - resolution: {integrity: sha512-fN2YRm/bGumvjUpu6yI3BpvZnpIm9I6A7HR4oUNYd7ggYyIwSA/BX7DJ+UXXffLp6XNcUijyLvttbPVCYa/3xQ==} + /svelte/3.49.0: + resolution: {integrity: sha512-+lmjic1pApJWDfPCpUUTc1m8azDqYCG1JN9YEngrx/hUyIcFJo6VZhj0A1Ai0wqoHcEIuQy+e9tk+4uDgdtsFA==} engines: {node: '>= 8'} - /sveltekit-i18n/2.2.2_svelte@3.48.0: + /sveltekit-i18n/2.2.2_svelte@3.49.0: resolution: {integrity: sha512-6eygICleGCSL7elY7A3trF8XUhV+mlW56ZSoD0UUKXlw+Y6u0MTTHDq48u1LyY73SfnlbPHXgTarhTjZ0BvUKA==} peerDependencies: svelte: ^3.x dependencies: - '@sveltekit-i18n/base': 1.2.1_svelte@3.48.0 + '@sveltekit-i18n/base': 1.2.1_svelte@3.49.0 '@sveltekit-i18n/parser-default': 1.0.3 - svelte: 3.48.0 + svelte: 3.49.0 dev: false - /tailwindcss-scrollbar/0.1.0_tailwindcss@3.1.4: + /tailwindcss-scrollbar/0.1.0_tailwindcss@3.1.6: resolution: {integrity: sha512-egipxw4ooQDh94x02XQpPck0P0sfwazwoUGfA9SedPATIuYDR+6qe8d31Gl7YsSMRiOKDkkqfI0kBvEw9lT/Hg==} peerDependencies: tailwindcss: '>= 2.x.x' dependencies: - tailwindcss: 3.1.4 + tailwindcss: 3.1.6 dev: true - /tailwindcss/3.1.4: - resolution: {integrity: sha512-NrxbFV4tYsga/hpWbRyUfIaBrNMXDxx5BsHgBS4v5tlyjf+sDsgBg5m9OxjrXIqAS/uR9kicxLKP+bEHI7BSeQ==} + /tailwindcss/3.1.6: + resolution: {integrity: sha512-7skAOY56erZAFQssT1xkpk+kWt2NrO45kORlxFPXUt3CiGsVPhH1smuH5XoDH6sGPXLyBv+zgCKA2HWBsgCytg==} engines: {node: '>=12.13.0'} hasBin: true dependencies: @@ -5388,7 +5125,7 @@ packages: fast-glob: 3.2.11 glob-parent: 6.0.2 is-glob: 4.0.3 - lilconfig: 2.0.5 + lilconfig: 2.0.6 normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.0.0 @@ -5400,7 +5137,7 @@ packages: postcss-selector-parser: 6.0.10 postcss-value-parser: 4.2.0 quick-lru: 5.1.1 - resolve: 1.22.0 + resolve: 1.22.1 transitivePeerDependencies: - ts-node dev: true @@ -5425,18 +5162,6 @@ packages: readable-stream: 3.6.0 dev: false - /tar/6.1.11: - resolution: {integrity: sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==} - engines: {node: '>= 10'} - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 3.1.6 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - dev: true - /text-table/0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -5452,6 +5177,7 @@ packages: dependencies: globalyzer: 0.1.0 globrex: 0.1.2 + dev: false /tiny-lru/8.0.2: resolution: {integrity: sha512-ApGvZ6vVvTNdsmt676grvCkUCGwzG9IqXma5Z07xJgiC5L7akUMof5U8G2JTI9Rz/ovtVhJBlY6mNhEvtjzOIg==} @@ -5486,16 +5212,12 @@ packages: nopt: 1.0.10 dev: true - /tr46/0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - dev: true - /trim-right/1.0.1: resolution: {integrity: sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==} engines: {node: '>=0.10.0'} dev: true - /ts-node/10.8.2_fxk5i3xm3ivo7fjwhcizcinpla: + /ts-node/10.8.2_2zqz24ol5yhbv2blv4fh7akzrq: resolution: {integrity: sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA==} hasBin: true peerDependencies: @@ -5514,7 +5236,7 @@ packages: '@tsconfig/node12': 1.0.9 '@tsconfig/node14': 1.0.1 '@tsconfig/node16': 1.0.2 - '@types/node': 18.0.3 + '@types/node': 18.0.4 acorn: 8.7.1 acorn-walk: 8.2.0 arg: 4.1.3 @@ -5606,6 +5328,17 @@ packages: engines: {node: '>=8'} dev: false + /update-browserslist-db/1.0.4_browserslist@4.21.2: + resolution: {integrity: sha512-jnmO2BEGUjsMOe/Fg9u0oczOe/ppIDZPebzccl1yDWGLFP16Pa1/RM5wEoKYPG2zstNcDuAStejyxsOuKINdGA==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.21.2 + escalade: 3.1.1 + picocolors: 1.0.0 + dev: true + /uri-js/4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: @@ -5640,14 +5373,15 @@ packages: engines: {node: '>= 0.8'} dev: false - /vite/2.9.13: - resolution: {integrity: sha512-AsOBAaT0AD7Mhe8DuK+/kE4aWYFMx/i0ZNi98hJclxb4e0OhQcZYUrvLjIaQ8e59Ui7txcvKMiJC1yftqpQoDw==} - engines: {node: '>=12.2.0'} + /vite/3.0.0: + resolution: {integrity: sha512-M7phQhY3+fRZa0H+1WzI6N+/onruwPTBTMvaj7TzgZ0v2TE+N2sdLKxJOfOv9CckDWt5C4HmyQP81xB4dwRKzA==} + engines: {node: '>=14.18.0'} hasBin: true peerDependencies: less: '*' sass: '*' stylus: '*' + terser: ^5.4.0 peerDependenciesMeta: less: optional: true @@ -5655,26 +5389,17 @@ packages: optional: true stylus: optional: true + terser: + optional: true dependencies: - esbuild: 0.14.48 + esbuild: 0.14.49 postcss: 8.4.14 - resolve: 1.22.0 - rollup: 2.75.7 + resolve: 1.22.1 + rollup: 2.77.0 optionalDependencies: fsevents: 2.3.2 dev: true - /webidl-conversions/3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: true - - /whatwg-url/5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - dev: true - /which-boxed-primitive/1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: @@ -5699,25 +5424,11 @@ packages: dependencies: isexe: 2.0.0 - /wide-align/1.1.5: - resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} - dependencies: - string-width: 4.2.3 - dev: true - /word-wrap/1.2.3: resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} engines: {node: '>=0.10.0'} dev: true - /worktop/0.8.0-next.14: - resolution: {integrity: sha512-RZgqHu1w/JcUdWOE/BUEAzarrUUHh39eWkLdX8XpA6MfgLJF6X5Vl26CV7/wcm4O/UpZvHMGJUtB9eYTqDjc9g==} - engines: {node: '>=12'} - dependencies: - mrmime: 1.0.0 - regexparam: 2.0.0 - dev: true - /wrappy/1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}