diff --git a/.changeset/stupid-trains-change.md b/.changeset/stupid-trains-change.md new file mode 100644 index 00000000..1a4fed9c --- /dev/null +++ b/.changeset/stupid-trains-change.md @@ -0,0 +1,5 @@ +--- +"@quassel/backend": patch +--- + +Add authentication and authorization diff --git a/apps/backend/migrations/.snapshot-postgres.json b/apps/backend/db/migrations/.snapshot-postgres.json similarity index 98% rename from apps/backend/migrations/.snapshot-postgres.json rename to apps/backend/db/migrations/.snapshot-postgres.json index 7197beed..294e0668 100644 --- a/apps/backend/migrations/.snapshot-postgres.json +++ b/apps/backend/db/migrations/.snapshot-postgres.json @@ -659,6 +659,16 @@ "name": "user", "schema": "public", "indexes": [ + { + "columnNames": [ + "email" + ], + "composite": false, + "keyName": "user_email_unique", + "constraint": true, + "primary": false, + "unique": true + }, { "keyName": "user_pkey", "columnNames": [ diff --git a/apps/backend/migrations/Migration20240930145428.ts b/apps/backend/db/migrations/Migration20240930145428.ts similarity index 100% rename from apps/backend/migrations/Migration20240930145428.ts rename to apps/backend/db/migrations/Migration20240930145428.ts diff --git a/apps/backend/migrations/Migration20241021081154.ts b/apps/backend/db/migrations/Migration20241021081154.ts similarity index 100% rename from apps/backend/migrations/Migration20241021081154.ts rename to apps/backend/db/migrations/Migration20241021081154.ts diff --git a/apps/backend/migrations/Migration20241021081906.ts b/apps/backend/db/migrations/Migration20241021081906.ts similarity index 100% rename from apps/backend/migrations/Migration20241021081906.ts rename to apps/backend/db/migrations/Migration20241021081906.ts diff --git a/apps/backend/migrations/Migration20241024070050.ts b/apps/backend/db/migrations/Migration20241024070050.ts similarity index 100% rename from apps/backend/migrations/Migration20241024070050.ts rename to apps/backend/db/migrations/Migration20241024070050.ts diff --git a/apps/backend/db/migrations/Migration20241025082939.ts b/apps/backend/db/migrations/Migration20241025082939.ts new file mode 100644 index 00000000..1637425b --- /dev/null +++ b/apps/backend/db/migrations/Migration20241025082939.ts @@ -0,0 +1,11 @@ +import { Migration } from "@mikro-orm/migrations"; + +export class Migration20241025082939 extends Migration { + override async up(): Promise { + this.addSql(`alter table "user" add constraint "user_email_unique" unique ("email");`); + } + + override async down(): Promise { + this.addSql(`alter table "user" drop constraint "user_email_unique";`); + } +} diff --git a/apps/backend/db/seeds/DatabaseSeeder.ts b/apps/backend/db/seeds/DatabaseSeeder.ts new file mode 100644 index 00000000..27eb515d --- /dev/null +++ b/apps/backend/db/seeds/DatabaseSeeder.ts @@ -0,0 +1,16 @@ +import type { EntityManager } from "@mikro-orm/core"; +import { Seeder } from "@mikro-orm/seeder"; +import { User, UserRole } from "../../src/users/entities/user.entity"; +import { bcrypt } from "hash-wasm"; + +export class DatabaseSeeder extends Seeder { + async run(em: EntityManager): Promise { + const salt = new Uint8Array(16); + crypto.getRandomValues(salt); + em.create(User, { + role: UserRole.ADMIN, + email: "administrator@example.ch", + password: await bcrypt({ password: "quassel*1234", salt, costFactor: 10 }), + }); + } +} diff --git a/apps/backend/mikro-orm.config.ts b/apps/backend/mikro-orm.config.ts index d673ee9d..2c2be8ba 100644 --- a/apps/backend/mikro-orm.config.ts +++ b/apps/backend/mikro-orm.config.ts @@ -1,18 +1,26 @@ import { defineConfig, PostgreSqlDriver } from "@mikro-orm/postgresql"; import { Migrator } from "@mikro-orm/migrations"; import { TsMorphMetadataProvider } from "@mikro-orm/reflection"; +import { SeedManager } from "@mikro-orm/seeder"; +import { configuration } from "./src/config/configuration"; + +const c = configuration(); export default defineConfig({ - entities: ["./dist/src/entities"], - entitiesTs: ["./src/entities"], - host: "db", - dbName: "postgres", - password: "postgres", - user: "postgres", + entities: ["./dist/src/**/*.entity.js"], + entitiesTs: ["./src/**/*.entity.ts"], + host: c.database.host, + port: c.database.port, + dbName: c.database.name, + user: c.database.user, + password: c.database.password, driver: PostgreSqlDriver, metadataProvider: TsMorphMetadataProvider, - extensions: [Migrator], + extensions: [Migrator, SeedManager], migrations: { - pathTs: "./migrations", + pathTs: "./db/migrations", + }, + seeder: { + pathTs: "./db/seeds", }, }); diff --git a/apps/backend/package.json b/apps/backend/package.json index 092c1df2..10de58e7 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -12,6 +12,7 @@ "start": "nest start", "dev": "nest start --watch --preserveWatchOutput", "db": "mikro-orm", + "nest": "nest", "start:dev": "nest start --watch", "start:debug": "nest start --debug --watch", "start:prod": "node dist/main", @@ -23,24 +24,32 @@ "test:e2e": "jest --config ./test/jest-e2e.json" }, "dependencies": { + "@fastify/secure-session": "^7.5.1", + "@fastify/static": "^7.0.4", "@mikro-orm/core": "^6.3.11", "@mikro-orm/nestjs": "^6.0.2", "@mikro-orm/postgresql": "^6.3.11", "@mikro-orm/reflection": "^6.3.11", "@nestjs/common": "^10.4.4", + "@nestjs/config": "^3.3.0", "@nestjs/core": "^10.4.4", - "@nestjs/platform-express": "^10.4.4", + "@nestjs/jwt": "^10.2.0", + "@nestjs/platform-fastify": "^10.4.6", "@nestjs/swagger": "^7.4.2", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.1", + "fastify": "^4.28.0", + "hash-wasm": "^4.11.0", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1" }, "devDependencies": { "@mikro-orm/cli": "^6.3.11", "@mikro-orm/migrations": "^6.3.11", + "@mikro-orm/seeder": "^6.3.13", "@nestjs/cli": "^10.0.0", "@nestjs/schematics": "^10.2.2", "@nestjs/testing": "^10.4.4", - "@types/express": "^4.17.17", "@types/jest": "^29.5.2", "@types/node": "^20.17.0", "@types/supertest": "^6.0.0", diff --git a/apps/backend/src/app.controller.spec.ts b/apps/backend/src/app.controller.spec.ts deleted file mode 100644 index f643a709..00000000 --- a/apps/backend/src/app.controller.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { AppController } from "./app.controller"; -import { AppService } from "./app.service"; - -describe("AppController", () => { - let appController: AppController; - - beforeEach(async () => { - const app: TestingModule = await Test.createTestingModule({ - controllers: [AppController], - providers: [AppService], - }).compile(); - - appController = app.get(AppController); - }); - - describe("root", () => { - it('should return "Hello World!"', () => { - expect(appController.getHello()).toBe("Hello World!"); - }); - }); -}); diff --git a/apps/backend/src/app.controller.ts b/apps/backend/src/app.controller.ts deleted file mode 100644 index 1e7e6283..00000000 --- a/apps/backend/src/app.controller.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Controller, Get } from "@nestjs/common"; -import { AppService } from "./app.service"; - -@Controller() -export class AppController { - constructor(private readonly appService: AppService) {} - - @Get() - getHello(): string { - return this.appService.getHello(); - } -} diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts index cd48f50f..491227d9 100644 --- a/apps/backend/src/app.module.ts +++ b/apps/backend/src/app.module.ts @@ -1,12 +1,9 @@ import { Module } from "@nestjs/common"; -import { AppController } from "./app.controller"; -import { AppService } from "./app.service"; import { MikroOrmModule } from "@mikro-orm/nestjs"; -import { UserModule } from "./user/user.module"; +import { ConfigModule } from "./config/config.module"; +import { UsersModule } from "./users/users.module"; @Module({ - imports: [MikroOrmModule.forRoot(), UserModule], - controllers: [AppController], - providers: [AppService], + imports: [MikroOrmModule.forRoot(), ConfigModule, UsersModule], }) export class AppModule {} diff --git a/apps/backend/src/app.service.ts b/apps/backend/src/app.service.ts deleted file mode 100644 index b00a6679..00000000 --- a/apps/backend/src/app.service.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Injectable } from "@nestjs/common"; - -@Injectable() -export class AppService { - getHello(): string { - return "Hello World!"; - } -} diff --git a/apps/backend/src/entities/base.entity.ts b/apps/backend/src/common/entities/base.entity.ts similarity index 100% rename from apps/backend/src/entities/base.entity.ts rename to apps/backend/src/common/entities/base.entity.ts diff --git a/apps/backend/src/config/config.module.ts b/apps/backend/src/config/config.module.ts new file mode 100644 index 00000000..3013fe03 --- /dev/null +++ b/apps/backend/src/config/config.module.ts @@ -0,0 +1,11 @@ +import { Module } from "@nestjs/common"; +import { configuration } from "./configuration"; +import { ConfigModule as NestConfigModule } from "@nestjs/config"; +import { ConfigService } from "./config.service"; + +@Module({ + imports: [NestConfigModule.forRoot({ load: [configuration] })], + providers: [ConfigService], + exports: [ConfigService], +}) +export class ConfigModule {} diff --git a/apps/backend/src/config/config.service.ts b/apps/backend/src/config/config.service.ts new file mode 100644 index 00000000..dade0cf8 --- /dev/null +++ b/apps/backend/src/config/config.service.ts @@ -0,0 +1,12 @@ +import { Injectable } from "@nestjs/common"; +import { ConfigService as NestConfigService } from "@nestjs/config"; +import { Configuration } from "./configuration"; + +@Injectable() +export class ConfigService { + constructor(private configService: NestConfigService) {} + + get>(propertyPath: T): LeaveTypes { + return this.configService.get(propertyPath); + } +} diff --git a/apps/backend/src/config/configuration.ts b/apps/backend/src/config/configuration.ts new file mode 100644 index 00000000..85dca1d0 --- /dev/null +++ b/apps/backend/src/config/configuration.ts @@ -0,0 +1,16 @@ +export const configuration = () => ({ + port: parseInt(process.env.PORT) || 3000, + session: { + secret: process.env.SESSION_SECRET || "2722badd029fa3bbe29f7ebeee0dcaeb82a91c1088d348354c6e7172996368fd", + salt: process.env.SESSION_SALT || "332535f60da28f8f", + }, + database: { + host: process.env.DATABASE_HOST || "db", + port: parseInt(process.env.DATABASE_PORT) || 5432, + name: process.env.DATABASE_NAME || "postgres", + user: process.env.DATABASE_USER || "postgres", + password: process.env.DATABASE_PASSWORD || "postgres", + }, +}); + +export type Configuration = ReturnType; diff --git a/apps/backend/src/entities/carer.entity.ts b/apps/backend/src/entities/carer.entity.ts index 8351cf37..385ba8ff 100644 --- a/apps/backend/src/entities/carer.entity.ts +++ b/apps/backend/src/entities/carer.entity.ts @@ -1,5 +1,5 @@ import { Collection, Entity, ManyToOne, OneToMany, Property } from "@mikro-orm/core"; -import { BaseEntity } from "./base.entity"; +import { BaseEntity } from "../common/entities/base.entity"; import { Participant } from "./participant.entity"; import { Entry } from "./entry.entity"; diff --git a/apps/backend/src/entities/entry.entity.ts b/apps/backend/src/entities/entry.entity.ts index 42bebd10..33dc36de 100644 --- a/apps/backend/src/entities/entry.entity.ts +++ b/apps/backend/src/entities/entry.entity.ts @@ -1,5 +1,5 @@ import { Check, Collection, Entity, ManyToOne, OneToMany, Opt, Property } from "@mikro-orm/core"; -import { BaseEntity } from "./base.entity"; +import { BaseEntity } from "../common/entities/base.entity"; import { EntryLanguage } from "./entryLanguage.entity"; import { Carer } from "./carer.entity"; import { Questionnaire } from "./questionnaire.entity"; diff --git a/apps/backend/src/entities/entryLanguage.entity.ts b/apps/backend/src/entities/entryLanguage.entity.ts index 0078277c..9e5e05ff 100644 --- a/apps/backend/src/entities/entryLanguage.entity.ts +++ b/apps/backend/src/entities/entryLanguage.entity.ts @@ -1,5 +1,5 @@ import { Check, Entity, ManyToOne, Property } from "@mikro-orm/core"; -import { BaseEntity } from "./base.entity"; +import { BaseEntity } from "../common/entities/base.entity"; import { Entry } from "./entry.entity"; import { Language } from "./language.entity"; diff --git a/apps/backend/src/entities/language.entity.ts b/apps/backend/src/entities/language.entity.ts index a56a4f8e..7ecdb263 100644 --- a/apps/backend/src/entities/language.entity.ts +++ b/apps/backend/src/entities/language.entity.ts @@ -1,5 +1,5 @@ import { Collection, Entity, ManyToOne, OneToMany, Property } from "@mikro-orm/core"; -import { BaseEntity } from "./base.entity"; +import { BaseEntity } from "../common/entities/base.entity"; import { Participant } from "./participant.entity"; import { EntryLanguage } from "./entryLanguage.entity"; diff --git a/apps/backend/src/entities/participant.entity.ts b/apps/backend/src/entities/participant.entity.ts index 004c132d..d8d4d1ab 100644 --- a/apps/backend/src/entities/participant.entity.ts +++ b/apps/backend/src/entities/participant.entity.ts @@ -1,5 +1,5 @@ import { Collection, Entity, OneToMany, Property } from "@mikro-orm/core"; -import { BaseEntity } from "./base.entity"; +import { BaseEntity } from "../common/entities/base.entity"; import { Questionnaire } from "./questionnaire.entity"; import { Carer } from "./carer.entity"; import { Language } from "./language.entity"; diff --git a/apps/backend/src/entities/questionnaire.entity.ts b/apps/backend/src/entities/questionnaire.entity.ts index f54d9154..ac645688 100644 --- a/apps/backend/src/entities/questionnaire.entity.ts +++ b/apps/backend/src/entities/questionnaire.entity.ts @@ -1,5 +1,5 @@ import { Collection, Entity, ManyToOne, OneToMany, Property } from "@mikro-orm/core"; -import { BaseEntity } from "./base.entity"; +import { BaseEntity } from "../common/entities/base.entity"; import { Study } from "./study.entity"; import { Participant } from "./participant.entity"; import { Entry } from "./entry.entity"; diff --git a/apps/backend/src/entities/study.entity.ts b/apps/backend/src/entities/study.entity.ts index 038a6b76..52534fe7 100644 --- a/apps/backend/src/entities/study.entity.ts +++ b/apps/backend/src/entities/study.entity.ts @@ -1,5 +1,5 @@ import { Collection, Entity, OneToMany, Property } from "@mikro-orm/core"; -import { BaseEntity } from "./base.entity"; +import { BaseEntity } from "../common/entities/base.entity"; import { Questionnaire } from "./questionnaire.entity"; @Entity() diff --git a/apps/backend/src/main.ts b/apps/backend/src/main.ts index 3617baf8..bba161ca 100644 --- a/apps/backend/src/main.ts +++ b/apps/backend/src/main.ts @@ -1,15 +1,29 @@ -import { NestFactory } from "@nestjs/core"; +import { NestFactory, Reflector } from "@nestjs/core"; import { AppModule } from "./app.module"; import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger"; +import { version } from "../package.json"; +import { ClassSerializerInterceptor, ValidationPipe } from "@nestjs/common"; +import { FastifyAdapter, NestFastifyApplication } from "@nestjs/platform-fastify"; +import { fastifySecureSession } from "@fastify/secure-session"; +import { ConfigService } from "./config/config.service"; async function bootstrap() { - const app = await NestFactory.create(AppModule, { cors: true }); + const app = await NestFactory.create(AppModule, new FastifyAdapter()); + const configService = app.get(ConfigService); + app.enableCors(); + app.useGlobalPipes(new ValidationPipe()); + app.useGlobalInterceptors(new ClassSerializerInterceptor(app.get(Reflector))); - const config = new DocumentBuilder().build(); + await app.register(fastifySecureSession, { + secret: configService.get("session.secret"), + salt: configService.get("session.salt"), + }); + + const config = new DocumentBuilder().setTitle("Quassel API").setVersion(version).setDescription("Gather language exposure data").build(); const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup("api", app, document); - await app.listen(3000); + await app.listen({ port: configService.get("port") }); } bootstrap(); diff --git a/apps/backend/src/types.d.ts b/apps/backend/src/types.d.ts new file mode 100644 index 00000000..86aa4b4a --- /dev/null +++ b/apps/backend/src/types.d.ts @@ -0,0 +1,28 @@ +import { SessionData as FastifySessionData } from "@fastify/secure-session"; +import { User } from "./users/entities/user.entity"; + +declare module "@fastify/secure-session" { + interface SessionData extends FastifySessionData { + userId?: number; + } +} + +declare module "fastify" { + interface FastifyRequest { + user?: User; + } +} + +declare global { + type Leaves = T extends object + ? { [K in keyof T]: `${Exclude}${Leaves extends never ? "" : `.${Leaves}`}` }[keyof T] + : never; + + type LeaveTypes = S extends `${infer T1}.${infer T2}` + ? T1 extends keyof T + ? LeaveTypes + : never + : S extends keyof T + ? T[S] + : never; +} diff --git a/apps/backend/src/user/user.controller.ts b/apps/backend/src/user/user.controller.ts deleted file mode 100644 index 66da470d..00000000 --- a/apps/backend/src/user/user.controller.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { EntityManager, EntityRepository } from "@mikro-orm/core"; -import { InjectRepository } from "@mikro-orm/nestjs"; -import { Body, Controller, Delete, Get, Param, Post } from "@nestjs/common"; -import { User } from "src/entities/user.entity"; - -@Controller("/users") -export class UserController { - constructor( - @InjectRepository(User) - private readonly userRepository: EntityRepository, - private readonly entityManager: EntityManager - ) {} - - @Get(":id") - async findOne(@Param("id") id: number): Promise { - return this.userRepository.findOneOrFail({ id }); - } - - @Get() - async findMany(): Promise { - return this.userRepository.findAll(); - } - - @Post() - async create(@Body() userInput: Omit): Promise { - const user = this.userRepository.create(userInput); - await this.entityManager.flush(); - - return user; - } - - @Delete(":id") - async delete(@Param("id") id: number): Promise { - return this.userRepository.nativeDelete({ id }); - } -} diff --git a/apps/backend/src/user/user.module.ts b/apps/backend/src/user/user.module.ts deleted file mode 100644 index 9b3a667e..00000000 --- a/apps/backend/src/user/user.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Module } from "@nestjs/common"; -import { UserController } from "./user.controller"; -import { MikroOrmModule } from "@mikro-orm/nestjs"; -import { User } from "src/entities/user.entity"; - -@Module({ - imports: [MikroOrmModule.forFeature([User])], - controllers: [UserController], -}) -export class UserModule {} diff --git a/apps/backend/src/users/decorators/public.decorator.ts b/apps/backend/src/users/decorators/public.decorator.ts new file mode 100644 index 00000000..7beff6f4 --- /dev/null +++ b/apps/backend/src/users/decorators/public.decorator.ts @@ -0,0 +1,4 @@ +import { SetMetadata } from "@nestjs/common"; + +export const IS_PUBLIC_KEY = "isPublic"; +export const Public = () => SetMetadata(IS_PUBLIC_KEY, true); diff --git a/apps/backend/src/users/decorators/roles.decorator.ts b/apps/backend/src/users/decorators/roles.decorator.ts new file mode 100644 index 00000000..24244f84 --- /dev/null +++ b/apps/backend/src/users/decorators/roles.decorator.ts @@ -0,0 +1,5 @@ +import { SetMetadata } from "@nestjs/common"; +import { UserRole } from "../entities/user.entity"; + +export const ROLES_KEY = "roles"; +export const Roles = (...roles: UserRole[]) => SetMetadata(ROLES_KEY, roles); diff --git a/apps/backend/src/users/dto/create-session.dto.ts b/apps/backend/src/users/dto/create-session.dto.ts new file mode 100644 index 00000000..3acb1f9a --- /dev/null +++ b/apps/backend/src/users/dto/create-session.dto.ts @@ -0,0 +1,14 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsEmail, IsNotEmpty, IsString } from "class-validator"; + +export class CreateSessionDto { + @ApiProperty({ example: "administrator@example.ch", description: "The email of the user" }) + @IsEmail() + @IsNotEmpty() + email: string; + + @ApiProperty({ example: "quassel*1234", description: "The password of the user" }) + @IsString() + @IsNotEmpty() + password: string; +} diff --git a/apps/backend/src/users/dto/create-user.dto.ts b/apps/backend/src/users/dto/create-user.dto.ts new file mode 100644 index 00000000..64831233 --- /dev/null +++ b/apps/backend/src/users/dto/create-user.dto.ts @@ -0,0 +1,19 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { Equals, IsEmail, IsNotEmpty, IsString, MinLength } from "class-validator"; + +export class CreateUserDto { + @ApiProperty({ example: "bart.simpson@example.ch", description: "The email of the user" }) + @IsEmail() + @IsNotEmpty() + email: string; + + @ApiProperty({ example: "bart*macht*keine*Hausaufgaben", description: "The password of the user" }) + @IsString() + @MinLength(8) + @IsNotEmpty() + password: string; + + @ApiProperty({ example: "bart*macht*keine*Hausaufgaben", description: "The password confirmation of the user" }) + @Equals("password") + passwordConfirmation: string; +} diff --git a/apps/backend/src/users/dto/update-user.dto.ts b/apps/backend/src/users/dto/update-user.dto.ts new file mode 100644 index 00000000..ef737eb8 --- /dev/null +++ b/apps/backend/src/users/dto/update-user.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from "@nestjs/swagger"; +import { CreateUserDto } from "./create-user.dto"; + +export class UpdateUserDto extends PartialType(CreateUserDto) {} diff --git a/apps/backend/src/entities/user.entity.ts b/apps/backend/src/users/entities/user.entity.ts similarity index 65% rename from apps/backend/src/entities/user.entity.ts rename to apps/backend/src/users/entities/user.entity.ts index 85e36af6..4fea9626 100644 --- a/apps/backend/src/entities/user.entity.ts +++ b/apps/backend/src/users/entities/user.entity.ts @@ -1,17 +1,19 @@ import { Entity, Enum, Opt, Property } from "@mikro-orm/core"; -import { BaseEntity } from "./base.entity"; +import { BaseEntity } from "../../common/entities/base.entity"; +import { Exclude } from "class-transformer"; -enum UserRole { +export enum UserRole { ASSISTANT = "ASSISTANT", ADMIN = "ADMIN", } @Entity() export class User extends BaseEntity { - @Property() + @Property({ unique: true }) email!: string; @Property() + @Exclude() password!: string; @Enum({ items: () => UserRole, nativeEnumName: "UserRole", default: UserRole.ASSISTANT }) diff --git a/apps/backend/src/users/guards/roles.guard.ts b/apps/backend/src/users/guards/roles.guard.ts new file mode 100644 index 00000000..fbabf3e8 --- /dev/null +++ b/apps/backend/src/users/guards/roles.guard.ts @@ -0,0 +1,19 @@ +import { Injectable, CanActivate, ExecutionContext } from "@nestjs/common"; +import { Reflector } from "@nestjs/core"; +import { ROLES_KEY } from "../decorators/roles.decorator"; +import { UserRole } from "../entities/user.entity"; +import { FastifyRequest } from "fastify"; + +@Injectable() +export class RolesGuard implements CanActivate { + constructor(private reflector: Reflector) {} + + canActivate(context: ExecutionContext): boolean { + const requiredRoles = this.reflector.getAllAndOverride(ROLES_KEY, [context.getHandler(), context.getClass()]); + if (!requiredRoles) { + return true; + } + const { user } = context.switchToHttp().getRequest(); + return requiredRoles.some((role) => user.role?.includes(role)); + } +} diff --git a/apps/backend/src/users/guards/session.guard.ts b/apps/backend/src/users/guards/session.guard.ts new file mode 100644 index 00000000..062d8a72 --- /dev/null +++ b/apps/backend/src/users/guards/session.guard.ts @@ -0,0 +1,34 @@ +import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from "@nestjs/common"; +import { FastifyRequest } from "fastify"; +import { UsersService } from "../users.service"; +import { instanceToInstance } from "class-transformer"; +import { Reflector } from "@nestjs/core"; +import { IS_PUBLIC_KEY } from "../decorators/public.decorator"; + +@Injectable() +export class SessionGuard implements CanActivate { + constructor( + private usersService: UsersService, + private reflector: Reflector + ) {} + + async canActivate(context: ExecutionContext) { + const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [context.getHandler(), context.getClass()]); + + if (isPublic) { + return true; + } + + const request = context.switchToHttp().getRequest(); + const userId = request.session.get("userId"); + + try { + const user = await this.usersService.findOne(userId); + request.user = instanceToInstance(user); + + return true; + } catch { + throw new UnauthorizedException(); + } + } +} diff --git a/apps/backend/src/users/session.controller.spec.ts b/apps/backend/src/users/session.controller.spec.ts new file mode 100644 index 00000000..a943f48e --- /dev/null +++ b/apps/backend/src/users/session.controller.spec.ts @@ -0,0 +1,23 @@ +import { Test, TestingModule } from "@nestjs/testing"; +import { SessionController } from "./session.controller"; +import { SessionService } from "./session.service"; + +describe("SessionController", () => { + let controller: SessionController; + let service: SessionService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [SessionController], + providers: [{ provide: SessionService, useValue: {} }], + }).compile(); + + controller = module.get(SessionController); + service = module.get(SessionService); + }); + + it("should be defined", () => { + expect(controller).toBeDefined(); + expect(service).toBeDefined(); + }); +}); diff --git a/apps/backend/src/users/session.controller.ts b/apps/backend/src/users/session.controller.ts new file mode 100644 index 00000000..f05e30c3 --- /dev/null +++ b/apps/backend/src/users/session.controller.ts @@ -0,0 +1,31 @@ +import { Body, Controller, Delete, Get, Post, Session } from "@nestjs/common"; +import { ApiOperation, ApiTags } from "@nestjs/swagger"; +import { SessionService } from "./session.service"; +import { CreateSessionDto } from "./dto/create-session.dto"; +import { Session as FastifySession } from "@fastify/secure-session"; +import { Public } from "./decorators/public.decorator"; + +@ApiTags("Session") +@Controller("session") +export class SessionController { + constructor(private sessionService: SessionService) {} + + @Public() + @Post() + @ApiOperation({ summary: "Create a session (sign in, log in, ..)" }) + create(@Body() credentials: CreateSessionDto, @Session() session: FastifySession) { + return this.sessionService.signIn(credentials, session); + } + + @Get() + @ApiOperation({ summary: "Get the current session (who am I, ..)" }) + get(@Session() session: FastifySession) { + return this.sessionService.whoAmI(session.get("userId")); + } + + @Delete() + @ApiOperation({ summary: "Delete a session (sign out, log out, ..)" }) + delete(@Session() session: FastifySession) { + session.delete(); + } +} diff --git a/apps/backend/src/users/session.service.spec.ts b/apps/backend/src/users/session.service.spec.ts new file mode 100644 index 00000000..aeb7b7aa --- /dev/null +++ b/apps/backend/src/users/session.service.spec.ts @@ -0,0 +1,22 @@ +import { Test, TestingModule } from "@nestjs/testing"; +import { SessionService } from "./session.service"; +import { UsersService } from "./users.service"; + +describe("SessionService", () => { + let sessionService: SessionService; + let usersService: UsersService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [SessionService, { provide: UsersService, useValue: {} }], + }).compile(); + + sessionService = module.get(SessionService); + usersService = module.get(UsersService); + }); + + it("should be defined", () => { + expect(sessionService).toBeDefined(); + expect(usersService).toBeDefined(); + }); +}); diff --git a/apps/backend/src/users/session.service.ts b/apps/backend/src/users/session.service.ts new file mode 100644 index 00000000..8cd3e10b --- /dev/null +++ b/apps/backend/src/users/session.service.ts @@ -0,0 +1,32 @@ +import { Injectable, UnauthorizedException } from "@nestjs/common"; +import { UsersService } from "./users.service"; +import { bcryptVerify } from "hash-wasm"; +import { CreateSessionDto } from "./dto/create-session.dto"; +import { Session as FastifySession } from "@fastify/secure-session"; + +@Injectable() +export class SessionService { + constructor(private usersService: UsersService) {} + + async signIn({ email, password }: CreateSessionDto, session: FastifySession) { + try { + const user = await this.usersService.findBy({ email }); + + if (await bcryptVerify({ password, hash: user.password })) { + session.set("userId", user.id); + return user; + } + return new UnauthorizedException(); + } catch { + return new UnauthorizedException(); + } + } + + async whoAmI(userId: number) { + try { + return await this.usersService.findOne(userId); + } catch { + return new UnauthorizedException(); + } + } +} diff --git a/apps/backend/src/users/users.controller.spec.ts b/apps/backend/src/users/users.controller.spec.ts new file mode 100644 index 00000000..ee2a1572 --- /dev/null +++ b/apps/backend/src/users/users.controller.spec.ts @@ -0,0 +1,69 @@ +import { Test, TestingModule } from "@nestjs/testing"; +import { UsersController } from "./users.controller"; +import { UsersService } from "./users.service"; +import { CreateUserDto } from "./dto/create-user.dto"; + +const createUserDto: CreateUserDto = { + email: "hans@example.ch", + password: "kanns-noch-immer", + passwordConfirmation: "kanns-noch-immer", +}; + +describe("UsersController", () => { + let controller: UsersController; + let service: UsersService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [UsersController], + providers: [ + { + provide: UsersService, + useValue: { + create: jest.fn().mockImplementation((user: CreateUserDto) => Promise.resolve({ id: "3", ...user })), + findAll: jest.fn().mockResolvedValue([ + { + id: "1", + email: "jessica@example.com", + password: "$2a$10$dbae5sMC7oH0icr/rDto..iMqylCbkF5u6N4WyiUsO4v52cRpPnfW", + }, + { + id: "2", + email: "aaron@example.com", + password: "$2a$10$uupGsF.gs4iDGmnZbOzpN.OnM5p60Y3gmCMW17UEUwH.yaYZ/QSUK", + }, + ]), + findOne: jest.fn().mockImplementation((id: string) => + Promise.resolve({ + email: "jessica@example.com", + password: "$2a$10$dbae5sMC7oH0icr/rDto..iMqylCbkF5u6N4WyiUsO4v52cRpPnfW", + id, + }) + ), + update: jest.fn().mockImplementation((id: string, user: CreateUserDto) => { + return Promise.resolve({ id, ...user }); + }), + remove: jest.fn(), + }, + }, + ], + }).compile(); + + controller = module.get(UsersController); + service = module.get(UsersService); + }); + + it("should be defined", () => { + expect(controller).toBeDefined(); + }); + + describe("create()", () => { + it("should create a user", () => { + expect(controller.create(createUserDto)).resolves.toEqual({ + id: "3", + ...createUserDto, + }); + expect(service.create).toHaveBeenCalledWith(createUserDto); + }); + }); +}); diff --git a/apps/backend/src/users/users.controller.ts b/apps/backend/src/users/users.controller.ts new file mode 100644 index 00000000..25d43ea1 --- /dev/null +++ b/apps/backend/src/users/users.controller.ts @@ -0,0 +1,44 @@ +import { Controller, Get, Post, Body, Patch, Param, Delete } from "@nestjs/common"; +import { UsersService } from "./users.service"; +import { CreateUserDto } from "./dto/create-user.dto"; +import { UpdateUserDto } from "./dto/update-user.dto"; +import { ApiOperation, ApiTags } from "@nestjs/swagger"; +import { Roles } from "./decorators/roles.decorator"; +import { UserRole } from "./entities/user.entity"; + +@ApiTags("Users") +@Controller("users") +export class UsersController { + constructor(private readonly usersService: UsersService) {} + + @Post() + @ApiOperation({ summary: "Create a user" }) + create(@Body() user: CreateUserDto) { + return this.usersService.create(user); + } + + @Get() + @ApiOperation({ summary: "Get all users" }) + index() { + return this.usersService.findAll(); + } + + @Get(":id") + @ApiOperation({ summary: "Get a user by ID" }) + get(@Param("id") id: string) { + return this.usersService.findOne(+id); + } + + @Patch(":id") + @ApiOperation({ summary: "Update a user by ID" }) + update(@Param("id") id: string, @Body() user: UpdateUserDto) { + return this.usersService.update(+id, user); + } + + @Delete(":id") + @ApiOperation({ summary: "Delete a user by ID" }) + @Roles(UserRole.ADMIN) + delete(@Param("id") id: string) { + return this.usersService.remove(+id); + } +} diff --git a/apps/backend/src/users/users.module.ts b/apps/backend/src/users/users.module.ts new file mode 100644 index 00000000..0cb38889 --- /dev/null +++ b/apps/backend/src/users/users.module.ts @@ -0,0 +1,17 @@ +import { Module } from "@nestjs/common"; +import { UsersService } from "./users.service"; +import { UsersController } from "./users.controller"; +import { MikroOrmModule } from "@mikro-orm/nestjs"; +import { User } from "./entities/user.entity"; +import { SessionService } from "./session.service"; +import { SessionController } from "./session.controller"; +import { APP_GUARD } from "@nestjs/core"; +import { SessionGuard } from "./guards/session.guard"; +import { RolesGuard } from "./guards/roles.guard"; + +@Module({ + imports: [MikroOrmModule.forFeature([User])], + controllers: [UsersController, SessionController], + providers: [UsersService, SessionService, { provide: APP_GUARD, useClass: SessionGuard }, { provide: APP_GUARD, useClass: RolesGuard }], +}) +export class UsersModule {} diff --git a/apps/backend/src/users/users.service.spec.ts b/apps/backend/src/users/users.service.spec.ts new file mode 100644 index 00000000..59d15e0b --- /dev/null +++ b/apps/backend/src/users/users.service.spec.ts @@ -0,0 +1,67 @@ +import { Test, TestingModule } from "@nestjs/testing"; +import { UsersService } from "./users.service"; +import { getRepositoryToken } from "@mikro-orm/nestjs"; +import { User } from "./entities/user.entity"; +import { EntityManager } from "@mikro-orm/core"; + +const userArray = [ + { + id: "1", + email: "jessica@example.com", + password: "$2a$10$dbae5sMC7oH0icr/rDto..iMqylCbkF5u6N4WyiUsO4v52cRpPnfW", + }, + { + id: "2", + email: "aaron@example.com", + password: "$2a$10$uupGsF.gs4iDGmnZbOzpN.OnM5p60Y3gmCMW17UEUwH.yaYZ/QSUK", + }, +]; + +const firstUser = userArray[0]; + +describe("UsersService", () => { + let service: UsersService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ + UsersService, + { + provide: getRepositoryToken(User), + useValue: { + find: jest.fn().mockResolvedValue(userArray), + findOneBy: jest.fn().mockResolvedValue(firstUser), + create: jest.fn().mockImplementation((user: User) => Promise.resolve({ id: "3", ...user })), + }, + }, + { + provide: EntityManager, + useValue: { + remove: jest.fn(), + persist: jest.fn(), + }, + }, + ], + }).compile(); + + service = module.get(UsersService); + }); + + it("should be defined", () => { + expect(service).toBeDefined(); + }); + + describe("create()", () => { + it("should successfully insert a user", async () => { + const user = await service.create({ + email: "hans@example.ch", + password: "kanns-noch-immer", + passwordConfirmation: "kanns-noch-immer", + }); + + expect(user.id).toBe("3"); + expect(user.email).toBe("hans@example.ch"); + expect(user.password).toHaveLength(60); + }); + }); +}); diff --git a/apps/backend/src/users/users.service.ts b/apps/backend/src/users/users.service.ts new file mode 100644 index 00000000..21c72036 --- /dev/null +++ b/apps/backend/src/users/users.service.ts @@ -0,0 +1,60 @@ +import { ClassSerializerInterceptor, Injectable, UseInterceptors } from "@nestjs/common"; +import { CreateUserDto } from "./dto/create-user.dto"; +import { UpdateUserDto } from "./dto/update-user.dto"; +import { InjectRepository } from "@mikro-orm/nestjs"; +import { User } from "./entities/user.entity"; +import { EntityManager, EntityRepository, FilterQuery, wrap } from "@mikro-orm/core"; +import { bcrypt } from "hash-wasm"; + +@UseInterceptors(ClassSerializerInterceptor) +@Injectable() +export class UsersService { + constructor( + @InjectRepository(User) + private readonly userRepository: EntityRepository, + private readonly em: EntityManager + ) {} + + async create(createUserDto: CreateUserDto) { + const salt = new Uint8Array(16); + crypto.getRandomValues(salt); + + const user = new User(); + user.email = createUserDto.email; + user.password = await bcrypt({ password: createUserDto.password, salt, costFactor: 10 }); + + return this.userRepository.create(user); + } + + findAll() { + return this.userRepository.findAll(); + } + + findOne(id: number) { + return this.userRepository.findOneOrFail(id); + } + + findBy(filter: FilterQuery) { + return this.userRepository.findOneOrFail(filter); + } + + async update(id: number, updateUserDto: UpdateUserDto) { + const user = await this.userRepository.findOneOrFail(id); + + if (updateUserDto.password) { + const salt = new Uint8Array(16); + crypto.getRandomValues(salt); + updateUserDto.password = await bcrypt({ password: updateUserDto.password, salt, costFactor: 10 }); + } + + wrap(user).assign(updateUserDto); + + await this.em.persist(user).flush(); + + return user; + } + + remove(id: number) { + return this.em.remove(this.userRepository.getReference(id)).flush(); + } +} diff --git a/apps/backend/tsconfig.json b/apps/backend/tsconfig.json index 95f5641c..043e68ec 100644 --- a/apps/backend/tsconfig.json +++ b/apps/backend/tsconfig.json @@ -3,6 +3,7 @@ "module": "commonjs", "declaration": true, "removeComments": true, + "resolveJsonModule": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "allowSyntheticDefaultImports": true, diff --git a/docs/developer.md b/docs/developer.md index bc98d6c0..887f9231 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -2,6 +2,15 @@ This guide covers the tasks and hints for developers. +## Services + +After running `pnpm dev` the following services should come up: + +- [localhost:3000](http://localhost:3000): Backend + - [localhost:3000/api](http://localhost:3000/api): API documentation +- [localhost:3001](http://localhost:3001): Frontend +- [localhost:3002](http://localhost:3002): Mockup + ## Tasks - **Upgrade dependencies** with `pnpm upgrade -ri`. If you use `-L` aswell you can upgrade major package version, but make sure you don't upgrade to dependencies that require Node 22. @@ -9,3 +18,5 @@ This guide covers the tasks and hints for developers. - **Connect to the development database** with `psql -h db -U postgres` and the password `postgres`. - **Run db tasks** by using `pnpm --filter @quassel/backend run db`. - **Migrate up to the latest version** with `pnpm --filter @quassel/backend run db migration:up`. +- **Run nest tasks** by using `pnpm --filter @quassel/backend run nest`. + - **Generate ressources** with `pnpm --filter @quassel/backend run nest g`. diff --git a/package.json b/package.json index 04e69949..307fc9db 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "quassel", "version": "0.0.0", "private": true, + "description": "Quassel: Gather language exposure data ", "scripts": { "build": "pnpm exec nx run-many --nx-bail --target=build --parallel --output-style stream", "changeset": "changeset", @@ -28,7 +29,7 @@ "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "5.1.0-rc-fb9a90fa48-20240614", - "eslint-plugin-react-refresh": "^0.4.13", + "eslint-plugin-react-refresh": "^0.4.14", "globals": "^15.9.0", "nx": "20.0.6", "typescript-eslint": "^8.11.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e9d0e804..7f86d190 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,8 +39,8 @@ importers: specifier: 5.1.0-rc-fb9a90fa48-20240614 version: 5.1.0-rc-fb9a90fa48-20240614(eslint@9.13.0) eslint-plugin-react-refresh: - specifier: ^0.4.13 - version: 0.4.13(eslint@9.13.0) + specifier: ^0.4.14 + version: 0.4.14(eslint@9.13.0) globals: specifier: ^15.9.0 version: 15.11.0 @@ -53,12 +53,18 @@ importers: apps/backend: dependencies: + '@fastify/secure-session': + specifier: ^7.5.1 + version: 7.5.1 + '@fastify/static': + specifier: ^7.0.4 + version: 7.0.4 '@mikro-orm/core': specifier: ^6.3.11 version: 6.3.13 '@mikro-orm/nestjs': specifier: ^6.0.2 - version: 6.0.2(@mikro-orm/core@6.3.13)(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6) + version: 6.0.2(@mikro-orm/core@6.3.13)(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6) '@mikro-orm/postgresql': specifier: ^6.3.11 version: 6.3.13(@mikro-orm/core@6.3.13) @@ -67,16 +73,34 @@ importers: version: 6.3.13(@mikro-orm/core@6.3.13) '@nestjs/common': specifier: ^10.4.4 - version: 10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1) + version: 10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/config': + specifier: ^3.3.0 + version: 3.3.0(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(rxjs@7.8.1) '@nestjs/core': specifier: ^10.4.4 - version: 10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/platform-express': - specifier: ^10.4.4 - version: 10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6) + version: 10.4.6(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/jwt': + specifier: ^10.2.0 + version: 10.2.0(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)) + '@nestjs/platform-fastify': + specifier: ^10.4.6 + version: 10.4.6(@fastify/static@7.0.4)(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6) '@nestjs/swagger': specifier: ^7.4.2 - version: 7.4.2(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)(reflect-metadata@0.2.2) + version: 7.4.2(@fastify/static@7.0.4)(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2) + class-transformer: + specifier: ^0.5.1 + version: 0.5.1 + class-validator: + specifier: ^0.14.1 + version: 0.14.1 + fastify: + specifier: ^4.28.0 + version: 4.28.1 + hash-wasm: + specifier: ^4.11.0 + version: 4.11.0 reflect-metadata: specifier: ^0.2.0 version: 0.2.2 @@ -90,6 +114,9 @@ importers: '@mikro-orm/migrations': specifier: ^6.3.11 version: 6.3.13(@mikro-orm/core@6.3.13)(@types/node@20.17.0)(pg@8.13.0) + '@mikro-orm/seeder': + specifier: ^6.3.13 + version: 6.3.13(@mikro-orm/core@6.3.13) '@nestjs/cli': specifier: ^10.0.0 version: 10.4.5 @@ -98,10 +125,7 @@ importers: version: 10.2.2(chokidar@3.6.0)(typescript@5.6.3) '@nestjs/testing': specifier: ^10.4.4 - version: 10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)(@nestjs/platform-express@10.4.6) - '@types/express': - specifier: ^4.17.17 - version: 4.17.21 + version: 10.4.6(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)(@nestjs/platform-express@10.4.6) '@types/jest': specifier: ^29.5.2 version: 29.5.14 @@ -971,10 +995,48 @@ packages: resolution: {integrity: sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@fastify/accept-negotiator@1.1.0': + resolution: {integrity: sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==} + engines: {node: '>=14'} + + '@fastify/ajv-compiler@3.6.0': + resolution: {integrity: sha512-LwdXQJjmMD+GwLOkP7TVC68qa+pSSogeWWmznRJ/coyTcfe9qA05AHFSe1eZFwK6q+xVRpChnvFUkf1iYaSZsQ==} + '@fastify/busboy@2.1.1': resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} + '@fastify/cookie@9.4.0': + resolution: {integrity: sha512-Th+pt3kEkh4MQD/Q2q1bMuJIB5NX/D5SwSpOKu3G/tjoGbwfpurIMJsWSPS0SJJ4eyjtmQ8OipDQspf8RbUOlg==} + + '@fastify/cors@9.0.1': + resolution: {integrity: sha512-YY9Ho3ovI+QHIL2hW+9X4XqQjXLjJqsU+sMV/xFsxZkE8p3GNnYVFpoOxF7SsP5ZL76gwvbo3V9L+FIekBGU4Q==} + + '@fastify/error@3.4.1': + resolution: {integrity: sha512-wWSvph+29GR783IhmvdwWnN4bUxTD01Vm5Xad4i7i1VuAOItLvbPAb69sb0IQ2N57yprvhNIwAP5B6xfKTmjmQ==} + + '@fastify/fast-json-stringify-compiler@4.3.0': + resolution: {integrity: sha512-aZAXGYo6m22Fk1zZzEUKBvut/CIIQe/BapEORnxiD5Qr0kPHqqI69NtEMCme74h+at72sPhbkb4ZrLd1W3KRLA==} + + '@fastify/formbody@7.4.0': + resolution: {integrity: sha512-H3C6h1GN56/SMrZS8N2vCT2cZr7mIHzBHzOBa5OPpjfB/D6FzP9mMpE02ZzrFX0ANeh0BAJdoXKOF2e7IbV+Og==} + + '@fastify/merge-json-schemas@0.1.1': + resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==} + + '@fastify/middie@8.3.3': + resolution: {integrity: sha512-+WHavMQr9CNTZoy2cjoDxoWp76kZ3JKjAtZj5sXNlxX5XBzHig0TeCPfPc+1+NQmliXtndT3PFwAjrQHE/6wnQ==} + + '@fastify/secure-session@7.5.1': + resolution: {integrity: sha512-3xnTmlI4rhboyLtXtGDnrAXz8MLbrkwn9Owo4CZ2/GC9H3Eux0D5QWwKowxmn4VaFadj2wC67RoycFFi/46xaw==} + hasBin: true + + '@fastify/send@2.1.0': + resolution: {integrity: sha512-yNYiY6sDkexoJR0D8IDy3aRP3+L4wdqCpvx5WP+VtEU58sn7USmKynBzDQex5X42Zzvw2gNzzYgP90UfWShLFA==} + + '@fastify/static@7.0.4': + resolution: {integrity: sha512-p2uKtaf8BMOZWLs6wu+Ihg7bWNBdjNgCwDza4MJtTqg+5ovKmcbgbR9Xs5/smZ1YISfzKOCNYmZV8LaCj+eJ1Q==} + '@floating-ui/core@1.6.8': resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==} @@ -1125,6 +1187,10 @@ packages: resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} engines: {node: '>=8'} + '@lukeed/ms@2.0.2': + resolution: {integrity: sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==} + engines: {node: '>=8'} + '@mantine/core@7.13.4': resolution: {integrity: sha512-9I6+SqTq90pnI3WPmOQzQ1PL7IkhQg/5ft8Awhgut8tvk1VaKruDm/K5ysUG3ncHrP+QTI2UHYjNlUrux6HKlw==} peerDependencies: @@ -1212,6 +1278,12 @@ packages: peerDependencies: '@mikro-orm/core': ^6.0.0 + '@mikro-orm/seeder@6.3.13': + resolution: {integrity: sha512-J7WQhcM/y9+rmuQMPsero20TS/1oLh/gwtb00ykiLeze0AnA82+eXuOtCYa23N+LuV963XD1EgKWRn8yDQAYpw==} + engines: {node: '>= 18.12.0'} + peerDependencies: + '@mikro-orm/core': ^6.0.0 + '@nanostores/i18n@0.12.2': resolution: {integrity: sha512-BZNDNB83qwfU8YGYEI5zwstBZGPRUfifhZcw0SqaiGLqUBe4onpQ/NCr4cRg0khlsvPtJ37MQ/XZaT7dN+/RvA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -1260,6 +1332,12 @@ packages: class-validator: optional: true + '@nestjs/config@3.3.0': + resolution: {integrity: sha512-pdGTp8m9d0ZCrjTpjkUbZx6gyf2IKf+7zlkrPNMsJzYZ4bFRRTpXrnj+556/5uiI6AfL5mMrJc2u7dB6bvM+VA==} + peerDependencies: + '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 + rxjs: ^7.1.0 + '@nestjs/core@10.4.6': resolution: {integrity: sha512-zXVPxCNRfO6gAy0yvEDjUxE/8gfZICJFpsl2lZAUH31bPb6m+tXuhUq2mVCTEltyMYQ+DYtRe+fEYM2v152N1g==} peerDependencies: @@ -1277,6 +1355,11 @@ packages: '@nestjs/websockets': optional: true + '@nestjs/jwt@10.2.0': + resolution: {integrity: sha512-x8cG90SURkEiLOehNaN2aRlotxT0KZESUliOPKKnjWiyJOcWurkF3w345WOX0P4MgFzUjGoZ1Sy0aZnxeihT0g==} + peerDependencies: + '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 + '@nestjs/mapped-types@2.0.5': resolution: {integrity: sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg==} peerDependencies: @@ -1296,6 +1379,19 @@ packages: '@nestjs/common': ^10.0.0 '@nestjs/core': ^10.0.0 + '@nestjs/platform-fastify@10.4.6': + resolution: {integrity: sha512-0KnpilaXnAAaBeNTYvP1p4iJU2JFJPk3c+gXWh/NAOLCe+MuaprgvkNX/YUOycirvWr3qVTCgICO+xejgJyhhw==} + peerDependencies: + '@fastify/static': ^6.0.0 || ^7.0.0 + '@fastify/view': ^7.0.0 || ^8.0.0 + '@nestjs/common': ^10.0.0 + '@nestjs/core': ^10.0.0 + peerDependenciesMeta: + '@fastify/static': + optional: true + '@fastify/view': + optional: true + '@nestjs/schematics@10.1.4': resolution: {integrity: sha512-QpY8ez9cTvXXPr3/KBrtSgXQHMSV6BkOUYy2c2TTe6cBqriEdGnCYqGl8cnfrQl3632q3lveQPaZ/c127dHsEw==} peerDependencies: @@ -1848,30 +1944,15 @@ packages: '@types/babel__traverse@7.20.6': resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} - '@types/body-parser@1.19.5': - resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} - - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - '@types/cookiejar@2.1.5': resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - '@types/express-serve-static-core@4.19.6': - resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} - - '@types/express@4.17.21': - resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} - '@types/graceful-fs@4.1.9': resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - '@types/http-errors@2.0.4': - resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} - '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -1887,12 +1968,12 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/jsonwebtoken@9.0.5': + resolution: {integrity: sha512-VRLSGzik+Unrup6BsouBeHsf4d1hOEgYWTm/7Nmw1sXoN1+tRly/Gy/po3yeahnP4jfnQWWAhQAqcNfH7ngOkA==} + '@types/methods@1.1.4': resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} - '@types/mime@1.3.5': - resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} @@ -1905,24 +1986,12 @@ packages: '@types/prop-types@15.7.13': resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} - '@types/qs@6.9.16': - resolution: {integrity: sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==} - - '@types/range-parser@1.2.7': - resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - '@types/react-dom@18.3.1': resolution: {integrity: sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==} '@types/react@18.3.12': resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==} - '@types/send@0.17.4': - resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} - - '@types/serve-static@1.15.7': - resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} - '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -1932,6 +2001,9 @@ packages: '@types/supertest@6.0.2': resolution: {integrity: sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==} + '@types/validator@13.12.2': + resolution: {integrity: sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==} + '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -2134,6 +2206,9 @@ packages: resolution: {integrity: sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==} hasBin: true + abstract-logging@2.0.1: + resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} + accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -2310,10 +2385,17 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + avvio@8.4.0: + resolution: {integrity: sha512-CDSwaxINFy59iNwhYnkvALBwZiTydGkOecZyPkqBpABYR1KqGEsET0VOOYDwtleZSUIdeY36DC2bSZ24CO1igA==} + axios@1.7.7: resolution: {integrity: sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==} @@ -2400,6 +2482,9 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -2509,6 +2594,12 @@ packages: cjs-module-lexer@1.4.1: resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} + class-transformer@0.5.1: + resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} + + class-validator@0.14.1: + resolution: {integrity: sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==} + cli-boxes@3.0.0: resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} engines: {node: '>=10'} @@ -2653,6 +2744,10 @@ packages: cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + cookie-signature@1.2.1: + resolution: {integrity: sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==} + engines: {node: '>=6.6.0'} + cookie@0.7.1: resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} engines: {node: '>= 0.6'} @@ -2854,6 +2949,10 @@ packages: dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dotenv-expand@10.0.0: + resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} + engines: {node: '>=12'} + dotenv-expand@11.0.6: resolution: {integrity: sha512-8NHi73otpWsZGBSZwwknTXS5pqMOrk9+Ssrna8xCaxkzEpU9OTf9R5ArQGVw03//Zmk9MOwLPng9WwndvpAJ5g==} engines: {node: '>=12'} @@ -2865,6 +2964,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -3008,8 +3110,8 @@ packages: peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - eslint-plugin-react-refresh@0.4.13: - resolution: {integrity: sha512-f1EppwrpJRWmqDTyvAyomFVDYRtrS7iTEqv3nokETnMiMzs2SSTmKRTACce4O2p4jYyowiSMvpdwC/RLcMFhuQ==} + eslint-plugin-react-refresh@0.4.14: + resolution: {integrity: sha512-aXvzCTK7ZBv1e7fahFuR3Z/fyQQSIQ711yPgYRj+Oj64tyTgO4iQIDmYXDBqvSWQ/FA4OSCsXOStlF+noU0/NA==} peerDependencies: eslint: '>=7' @@ -3115,6 +3217,12 @@ packages: resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} engines: {node: '>=4'} + fast-content-type-parse@1.1.0: + resolution: {integrity: sha512-fBHHqSTFLVnR61C+gltJuE5GkVQMV0S2nqUO8TJ+5Z3qAKG8vAx4FKai1s5jq/inV1+sREynIWSuQ6HgoSXpDQ==} + + fast-decode-uri-component@1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -3128,12 +3236,31 @@ packages: fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + fast-json-stringify@5.16.1: + resolution: {integrity: sha512-KAdnLvy1yu/XrRtP+LJnxbBGrhN+xXu+gt3EUvZhYGKCr3lFHq/7UFJHHFgmJKoqlh6B40bZLEv7w46B0mqn1g==} + fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-querystring@1.1.2: + resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} + + fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} + fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + fast-uri@2.4.0: + resolution: {integrity: sha512-ypuAmmMKInk5q7XcepxlnUWDLWv4GFtaJqAzWKqn62IpQ3pejtr5dTVbt3vwqVaMKmkNR55sTT+CqUKIaT21BA==} + + fastify-plugin@4.5.1: + resolution: {integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==} + + fastify@4.28.1: + resolution: {integrity: sha512-kFWUtpNr4i7t5vY2EJPCN2KgMVpuqfU4NjnJNCgiNB900oiDeYqaNDRcAfeBbOF5hGixixxcKnOU4KN9z6QncQ==} + fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} @@ -3164,6 +3291,10 @@ packages: resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} + find-my-way@8.2.2: + resolution: {integrity: sha512-Dobi7gcTEq8yszimcfp/R7+owiT4WncAJ7VTTgFH1jYJ5GaG1FbhjwDG820hptN0QDFvzVY3RfCzdInvGPGzjA==} + engines: {node: '>=14'} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -3387,6 +3518,9 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} + hash-wasm@4.11.0: + resolution: {integrity: sha512-HVusNXlVqHe0fzIzdQOGolnFN6mX/fqcrSAOcTBXdvzrXVHwTz11vXeKRmkR5gTuwVpvHZEIyKoePDvuAR+XwQ==} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -3870,6 +4004,9 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-ref-resolver@1.0.1: + resolution: {integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -3899,10 +4036,20 @@ packages: jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + jsonwebtoken@9.0.2: + resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} + engines: {node: '>=12', npm: '>=6'} + jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} + jwa@1.4.1: + resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} + + jws@3.2.2: + resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -3953,6 +4100,15 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + libphonenumber-js@1.11.12: + resolution: {integrity: sha512-QkJn9/D7zZ1ucvT++TQSvZuSA2xAWeUytU+DiEQwbPKLyrDpvbul2AFs1CGbRAPpSCCk47aRAb5DX5mmcayp4g==} + + light-my-request@5.14.0: + resolution: {integrity: sha512-aORPWntbpH5esaYpGOOmri0OHDOe3wC5M2MQxZ9dvMLZm6DnaAn0kJlcbU9hwsQgLzmZyReKwFwwPkR+nHu5kA==} + + light-my-request@6.1.0: + resolution: {integrity: sha512-+NFuhlOGoEwxeQfJ/pobkVFxcnKyDtiX847hLjuB/IzBxIl3q4VJeFI8uRCgb3AlTWL1lgOr+u5+8QdUcr33ng==} + lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -3976,15 +4132,36 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + lodash.isequal@4.5.0: resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + + lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} @@ -4098,6 +4275,11 @@ packages: engines: {node: '>=4.0.0'} hasBin: true + mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -4143,6 +4325,9 @@ packages: mlly@1.7.2: resolution: {integrity: sha512-tN3dvVHYVz4DhSXinXIk7u9syPYaJvio118uomkovAtWBT+RdbP6Lfh/5Lvo519YMmwBafwlh20IPTXIStscpA==} + mnemonist@0.39.6: + resolution: {integrity: sha512-A/0v5Z59y63US00cRSLiloEIw3t5G+MiKz4BhX21FI+YBJXBOGW0ohFxTxO08dsOYlzxo87T7vGfZKYp2bcAWA==} + moment-timezone@0.5.46: resolution: {integrity: sha512-ZXm9b36esbe7OmdABqIWJuBBiLLwAjrN7CE+7sYdCCx82Nabt1wHDj8TVseS59QIlfFPbOoiBPm6ca9BioG4hw==} @@ -4213,6 +4398,10 @@ packages: encoding: optional: true + node-gyp-build@4.8.2: + resolution: {integrity: sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==} + hasBin: true + node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -4273,6 +4462,13 @@ packages: resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} engines: {node: '>= 0.4'} + obliterator@2.0.4: + resolution: {integrity: sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==} + + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -4417,6 +4613,9 @@ packages: path-to-regexp@3.3.0: resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -4483,6 +4682,16 @@ packages: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + + pino-std-serializers@7.0.0: + resolution: {integrity: sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==} + + pino@9.5.0: + resolution: {integrity: sha512-xSEmD4pLnV54t0NOUN16yCl7RIB1c5UUOse5HSyEXtBp+FgFQyPeDutc+Q2ZO7/22vImV7VfEjH/1zV2QuqvYw==} + hasBin: true + pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} @@ -4567,6 +4776,12 @@ packages: process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + process-warning@3.0.0: + resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} + + process-warning@4.0.0: + resolution: {integrity: sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw==} + prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -4601,6 +4816,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -4699,6 +4917,10 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + rechoir@0.8.0: resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} engines: {node: '>= 10.13.0'} @@ -4771,10 +4993,17 @@ packages: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} + ret@0.4.3: + resolution: {integrity: sha512-0f4Memo5QP7WQyUEAYUO3esD/XjOc3Zjjg5CPsAq1p8sIu0XPeMbHJemKA0BO7tV0X7+A0FoEpbmHXWxPyD3wQ==} + engines: {node: '>=10'} + reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rollup@4.24.2: resolution: {integrity: sha512-do/DFGq5g6rdDhdpPq5qb2ecoczeK6y+2UAjdJ5trjQJj5f1AiVdLRWRc9A9/fFukfvJRgM0UXzxBIYMovm5ww==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -4811,6 +5040,13 @@ packages: resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} engines: {node: '>= 0.4'} + safe-regex2@3.1.0: + resolution: {integrity: sha512-RAAZAGbap2kBfbVhvmnTFv73NWLMvDGOITFYTZBAaY8eR+Ir4ef7Up/e7amo+y1+AH+3PtLkrt9mvcTsG9LXug==} + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -4825,6 +5061,9 @@ packages: resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} engines: {node: '>= 10.13.0'} + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true @@ -4858,6 +5097,9 @@ packages: engines: {node: '>= 14'} hasBin: true + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -4909,6 +5151,12 @@ packages: snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + sodium-native@4.2.2: + resolution: {integrity: sha512-/gYaDtIK76FRcW0oBhIKJvLCDp706rJugd8wxJUBdbutgWrDlviG4tp8k+HfIRdy0Z+MbQE32ZGr4RPu1vXSsw==} + + sonic-boom@4.2.0: + resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -5127,6 +5375,9 @@ packages: text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} @@ -5184,6 +5435,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toad-cache@3.7.0: + resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} + engines: {node: '>=12'} + toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -5474,6 +5729,10 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} + validator@13.12.0: + resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==} + engines: {node: '>= 0.10'} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -6484,8 +6743,71 @@ snapshots: dependencies: levn: 0.4.1 + '@fastify/accept-negotiator@1.1.0': {} + + '@fastify/ajv-compiler@3.6.0': + dependencies: + ajv: 8.13.0 + ajv-formats: 2.1.1(ajv@8.13.0) + fast-uri: 2.4.0 + '@fastify/busboy@2.1.1': {} + '@fastify/cookie@9.4.0': + dependencies: + cookie-signature: 1.2.1 + fastify-plugin: 4.5.1 + + '@fastify/cors@9.0.1': + dependencies: + fastify-plugin: 4.5.1 + mnemonist: 0.39.6 + + '@fastify/error@3.4.1': {} + + '@fastify/fast-json-stringify-compiler@4.3.0': + dependencies: + fast-json-stringify: 5.16.1 + + '@fastify/formbody@7.4.0': + dependencies: + fast-querystring: 1.1.2 + fastify-plugin: 4.5.1 + + '@fastify/merge-json-schemas@0.1.1': + dependencies: + fast-deep-equal: 3.1.3 + + '@fastify/middie@8.3.3': + dependencies: + '@fastify/error': 3.4.1 + fastify-plugin: 4.5.1 + path-to-regexp: 6.3.0 + reusify: 1.0.4 + + '@fastify/secure-session@7.5.1': + dependencies: + '@fastify/cookie': 9.4.0 + fastify-plugin: 4.5.1 + sodium-native: 4.2.2 + + '@fastify/send@2.1.0': + dependencies: + '@lukeed/ms': 2.0.2 + escape-html: 1.0.3 + fast-decode-uri-component: 1.0.1 + http-errors: 2.0.0 + mime: 3.0.0 + + '@fastify/static@7.0.4': + dependencies: + '@fastify/accept-negotiator': 1.1.0 + '@fastify/send': 2.1.0 + content-disposition: 0.5.4 + fastify-plugin: 4.5.1 + fastq: 1.17.1 + glob: 10.4.2 + '@floating-ui/core@1.6.8': dependencies: '@floating-ui/utils': 0.2.8 @@ -6742,6 +7064,8 @@ snapshots: '@lukeed/csprng@1.1.0': {} + '@lukeed/ms@2.0.2': {} + '@mantine/core@7.13.4(@mantine/hooks@7.13.4(react@18.3.1))(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@floating-ui/react': 0.26.25(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -6881,11 +7205,11 @@ snapshots: - supports-color - tedious - '@mikro-orm/nestjs@6.0.2(@mikro-orm/core@6.3.13)(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)': + '@mikro-orm/nestjs@6.0.2(@mikro-orm/core@6.3.13)(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)': dependencies: '@mikro-orm/core': 6.3.13 - '@nestjs/common': 10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/common': 10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.6(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@mikro-orm/postgresql@6.3.13(@mikro-orm/core@6.3.13)': dependencies: @@ -6912,6 +7236,12 @@ snapshots: globby: 11.1.0 ts-morph: 23.0.0 + '@mikro-orm/seeder@6.3.13(@mikro-orm/core@6.3.13)': + dependencies: + '@mikro-orm/core': 6.3.13 + fs-extra: 11.2.0 + globby: 11.1.0 + '@nanostores/i18n@0.12.2(nanostores@0.11.3)': dependencies: nanostores: 0.11.3 @@ -6957,17 +7287,28 @@ snapshots: - uglify-js - webpack-cli - '@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1)': + '@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1)': dependencies: iterare: 1.2.1 reflect-metadata: 0.2.2 rxjs: 7.8.1 tslib: 2.7.0 uid: 2.0.2 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.1 - '@nestjs/core@10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1)': + '@nestjs/config@3.3.0(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(rxjs@7.8.1)': dependencies: - '@nestjs/common': 10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/common': 10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + dotenv: 16.4.5 + dotenv-expand: 10.0.0 + lodash: 4.17.21 + rxjs: 7.8.1 + + '@nestjs/core@10.4.6(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1)': + dependencies: + '@nestjs/common': 10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nuxtjs/opencollective': 0.3.2 fast-safe-stringify: 2.1.1 iterare: 1.2.1 @@ -6977,19 +7318,28 @@ snapshots: tslib: 2.7.0 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6) + '@nestjs/platform-express': 10.4.6(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6) transitivePeerDependencies: - encoding - '@nestjs/mapped-types@2.0.5(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)': + '@nestjs/jwt@10.2.0(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))': dependencies: - '@nestjs/common': 10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/common': 10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@types/jsonwebtoken': 9.0.5 + jsonwebtoken: 9.0.2 + + '@nestjs/mapped-types@2.0.5(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)': + dependencies: + '@nestjs/common': 10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) reflect-metadata: 0.2.2 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.1 - '@nestjs/platform-express@10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)': + '@nestjs/platform-express@10.4.6(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)': dependencies: - '@nestjs/common': 10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/common': 10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.6(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) body-parser: 1.20.3 cors: 2.8.5 express: 4.21.1 @@ -6997,6 +7347,21 @@ snapshots: tslib: 2.7.0 transitivePeerDependencies: - supports-color + optional: true + + '@nestjs/platform-fastify@10.4.6(@fastify/static@7.0.4)(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)': + dependencies: + '@fastify/cors': 9.0.1 + '@fastify/formbody': 7.4.0 + '@fastify/middie': 8.3.3 + '@nestjs/common': 10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.6(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) + fastify: 4.28.1 + light-my-request: 6.1.0 + path-to-regexp: 3.3.0 + tslib: 2.7.0 + optionalDependencies: + '@fastify/static': 7.0.4 '@nestjs/schematics@10.1.4(chokidar@3.6.0)(typescript@5.3.3)': dependencies: @@ -7020,25 +7385,29 @@ snapshots: transitivePeerDependencies: - chokidar - '@nestjs/swagger@7.4.2(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)(reflect-metadata@0.2.2)': + '@nestjs/swagger@7.4.2(@fastify/static@7.0.4)(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)': dependencies: '@microsoft/tsdoc': 0.15.0 - '@nestjs/common': 10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/mapped-types': 2.0.5(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2) + '@nestjs/common': 10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.6(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/mapped-types': 2.0.5(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2) js-yaml: 4.1.0 lodash: 4.17.21 path-to-regexp: 3.3.0 reflect-metadata: 0.2.2 swagger-ui-dist: 5.17.14 + optionalDependencies: + '@fastify/static': 7.0.4 + class-transformer: 0.5.1 + class-validator: 0.14.1 - '@nestjs/testing@10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)(@nestjs/platform-express@10.4.6)': + '@nestjs/testing@10.4.6(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6)(@nestjs/platform-express@10.4.6)': dependencies: - '@nestjs/common': 10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1) - '@nestjs/core': 10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/common': 10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1) + '@nestjs/core': 10.4.6(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.4.6)(reflect-metadata@0.2.2)(rxjs@7.8.1) tslib: 2.7.0 optionalDependencies: - '@nestjs/platform-express': 10.4.6(@nestjs/common@10.4.6(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6) + '@nestjs/platform-express': 10.4.6(@nestjs/common@10.4.6(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@10.4.6) '@nodelib/fs.scandir@2.1.5': dependencies: @@ -7615,39 +7984,14 @@ snapshots: dependencies: '@babel/types': 7.25.8 - '@types/body-parser@1.19.5': - dependencies: - '@types/connect': 3.4.38 - '@types/node': 20.17.0 - - '@types/connect@3.4.38': - dependencies: - '@types/node': 20.17.0 - '@types/cookiejar@2.1.5': {} '@types/estree@1.0.6': {} - '@types/express-serve-static-core@4.19.6': - dependencies: - '@types/node': 20.17.0 - '@types/qs': 6.9.16 - '@types/range-parser': 1.2.7 - '@types/send': 0.17.4 - - '@types/express@4.17.21': - dependencies: - '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 4.19.6 - '@types/qs': 6.9.16 - '@types/serve-static': 1.15.7 - '@types/graceful-fs@4.1.9': dependencies: '@types/node': 20.17.0 - '@types/http-errors@2.0.4': {} - '@types/istanbul-lib-coverage@2.0.6': {} '@types/istanbul-lib-report@3.0.3': @@ -7665,9 +8009,11 @@ snapshots: '@types/json-schema@7.0.15': {} - '@types/methods@1.1.4': {} + '@types/jsonwebtoken@9.0.5': + dependencies: + '@types/node': 20.17.0 - '@types/mime@1.3.5': {} + '@types/methods@1.1.4': {} '@types/node@12.20.55': {} @@ -7681,10 +8027,6 @@ snapshots: '@types/prop-types@15.7.13': {} - '@types/qs@6.9.16': {} - - '@types/range-parser@1.2.7': {} - '@types/react-dom@18.3.1': dependencies: '@types/react': 18.3.12 @@ -7694,17 +8036,6 @@ snapshots: '@types/prop-types': 15.7.13 csstype: 3.1.3 - '@types/send@0.17.4': - dependencies: - '@types/mime': 1.3.5 - '@types/node': 20.17.0 - - '@types/serve-static@1.15.7': - dependencies: - '@types/http-errors': 2.0.4 - '@types/node': 20.17.0 - '@types/send': 0.17.4 - '@types/stack-utils@2.0.3': {} '@types/superagent@8.1.9': @@ -7719,6 +8050,8 @@ snapshots: '@types/methods': 1.1.4 '@types/superagent': 8.1.9 + '@types/validator@13.12.2': {} + '@types/yargs-parser@21.0.3': {} '@types/yargs@17.0.33': @@ -8013,6 +8346,8 @@ snapshots: dependencies: argparse: 2.0.1 + abstract-logging@2.0.1: {} + accepts@1.3.8: dependencies: mime-types: 2.1.35 @@ -8046,6 +8381,10 @@ snapshots: optionalDependencies: ajv: 8.12.0 + ajv-formats@2.1.1(ajv@8.13.0): + optionalDependencies: + ajv: 8.13.0 + ajv-formats@3.0.1(ajv@8.13.0): optionalDependencies: ajv: 8.13.0 @@ -8106,7 +8445,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 - append-field@1.0.0: {} + append-field@1.0.0: + optional: true arch@2.2.0: {} @@ -8129,7 +8469,8 @@ snapshots: call-bind: 1.0.7 is-array-buffer: 3.0.4 - array-flatten@1.1.1: {} + array-flatten@1.1.1: + optional: true array-includes@3.1.8: dependencies: @@ -8194,10 +8535,17 @@ snapshots: asynckit@0.4.0: {} + atomic-sleep@1.0.0: {} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 + avvio@8.4.0: + dependencies: + '@fastify/error': 3.4.1 + fastq: 1.17.1 + axios@1.7.7: dependencies: follow-redirects: 1.15.9 @@ -8304,6 +8652,7 @@ snapshots: unpipe: 1.0.0 transitivePeerDependencies: - supports-color + optional: true boxen@7.0.0: dependencies: @@ -8351,6 +8700,8 @@ snapshots: dependencies: node-int64: 0.4.0 + buffer-equal-constant-time@1.0.1: {} + buffer-from@1.1.2: {} buffer@5.7.1: @@ -8361,10 +8712,12 @@ snapshots: busboy@1.6.0: dependencies: streamsearch: 1.1.0 + optional: true bytes@3.0.0: {} - bytes@3.1.2: {} + bytes@3.1.2: + optional: true cac@6.7.14: {} @@ -8448,6 +8801,14 @@ snapshots: cjs-module-lexer@1.4.1: {} + class-transformer@0.5.1: {} + + class-validator@0.14.1: + dependencies: + '@types/validator': 13.12.2 + libphonenumber-js: 1.11.12 + validator: 13.12.0 + cli-boxes@3.0.0: {} cli-cursor@3.1.0: @@ -8562,6 +8923,7 @@ snapshots: inherits: 2.0.4 readable-stream: 2.3.8 typedarray: 0.0.6 + optional: true confbox@0.1.8: {} @@ -8573,11 +8935,15 @@ snapshots: dependencies: safe-buffer: 5.2.1 - content-type@1.0.5: {} + content-type@1.0.5: + optional: true convert-source-map@2.0.0: {} - cookie-signature@1.0.6: {} + cookie-signature@1.0.6: + optional: true + + cookie-signature@1.2.1: {} cookie@0.7.1: {} @@ -8591,6 +8957,7 @@ snapshots: dependencies: object-assign: 4.1.1 vary: 1.1.2 + optional: true cosmiconfig@8.3.6(typescript@5.3.3): dependencies: @@ -8728,7 +9095,8 @@ snapshots: dequal@2.0.3: {} - destroy@1.2.0: {} + destroy@1.2.0: + optional: true detect-indent@6.1.0: {} @@ -8762,6 +9130,8 @@ snapshots: no-case: 3.0.4 tslib: 2.8.0 + dotenv-expand@10.0.0: {} + dotenv-expand@11.0.6: dependencies: dotenv: 16.4.5 @@ -8770,7 +9140,12 @@ snapshots: eastasianwidth@0.2.0: {} - ee-first@1.1.1: {} + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + + ee-first@1.1.1: + optional: true ejs@3.1.10: dependencies: @@ -8786,9 +9161,11 @@ snapshots: emoji-regex@9.2.2: {} - encodeurl@1.0.2: {} + encodeurl@1.0.2: + optional: true - encodeurl@2.0.0: {} + encodeurl@2.0.0: + optional: true end-of-stream@1.4.4: dependencies: @@ -8988,7 +9365,7 @@ snapshots: dependencies: eslint: 9.13.0 - eslint-plugin-react-refresh@0.4.13(eslint@9.13.0): + eslint-plugin-react-refresh@0.4.14(eslint@9.13.0): dependencies: eslint: 9.13.0 @@ -9098,7 +9475,8 @@ snapshots: esutils@2.0.3: {} - etag@1.8.1: {} + etag@1.8.1: + optional: true events@3.3.0: {} @@ -9159,6 +9537,7 @@ snapshots: vary: 1.1.2 transitivePeerDependencies: - supports-color + optional: true extendable-error@0.1.7: {} @@ -9168,6 +9547,10 @@ snapshots: iconv-lite: 0.4.24 tmp: 0.0.33 + fast-content-type-parse@1.1.0: {} + + fast-decode-uri-component@1.0.1: {} + fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} @@ -9182,10 +9565,49 @@ snapshots: fast-json-stable-stringify@2.1.0: {} + fast-json-stringify@5.16.1: + dependencies: + '@fastify/merge-json-schemas': 0.1.1 + ajv: 8.13.0 + ajv-formats: 3.0.1(ajv@8.13.0) + fast-deep-equal: 3.1.3 + fast-uri: 2.4.0 + json-schema-ref-resolver: 1.0.1 + rfdc: 1.4.1 + fast-levenshtein@2.0.6: {} + fast-querystring@1.1.2: + dependencies: + fast-decode-uri-component: 1.0.1 + + fast-redact@3.5.0: {} + fast-safe-stringify@2.1.1: {} + fast-uri@2.4.0: {} + + fastify-plugin@4.5.1: {} + + fastify@4.28.1: + dependencies: + '@fastify/ajv-compiler': 3.6.0 + '@fastify/error': 3.4.1 + '@fastify/fast-json-stringify-compiler': 4.3.0 + abstract-logging: 2.0.1 + avvio: 8.4.0 + fast-content-type-parse: 1.1.0 + fast-json-stringify: 5.16.1 + find-my-way: 8.2.2 + light-my-request: 5.14.0 + pino: 9.5.0 + process-warning: 3.0.0 + proxy-addr: 2.0.7 + rfdc: 1.4.1 + secure-json-parse: 2.7.0 + semver: 7.6.3 + toad-cache: 3.7.0 + fastq@1.17.1: dependencies: reusify: 1.0.4 @@ -9223,6 +9645,13 @@ snapshots: unpipe: 1.0.0 transitivePeerDependencies: - supports-color + optional: true + + find-my-way@8.2.2: + dependencies: + fast-deep-equal: 3.1.3 + fast-querystring: 1.1.2 + safe-regex2: 3.1.0 find-up@4.1.0: dependencies: @@ -9285,7 +9714,8 @@ snapshots: forwarded@0.2.0: {} - fresh@0.5.2: {} + fresh@0.5.2: + optional: true front-matter@4.0.2: dependencies: @@ -9454,6 +9884,8 @@ snapshots: dependencies: has-symbols: 1.0.3 + hash-wasm@4.11.0: {} + hasown@2.0.2: dependencies: function-bind: 1.1.2 @@ -9705,7 +10137,8 @@ snapshots: dependencies: is-docker: 2.2.1 - isarray@1.0.0: {} + isarray@1.0.0: + optional: true isarray@2.0.5: {} @@ -10147,6 +10580,10 @@ snapshots: json-parse-even-better-errors@2.3.1: {} + json-schema-ref-resolver@1.0.1: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} @@ -10171,6 +10608,19 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonwebtoken@9.0.2: + dependencies: + jws: 3.2.2 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.6.3 + jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.8 @@ -10178,6 +10628,17 @@ snapshots: object.assign: 4.1.5 object.values: 1.2.0 + jwa@1.4.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@3.2.2: + dependencies: + jwa: 1.4.1 + safe-buffer: 5.2.1 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -10216,6 +10677,20 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + libphonenumber-js@1.11.12: {} + + light-my-request@5.14.0: + dependencies: + cookie: 0.7.1 + process-warning: 3.0.0 + set-cookie-parser: 2.7.1 + + light-my-request@6.1.0: + dependencies: + cookie: 0.7.1 + process-warning: 4.0.0 + set-cookie-parser: 2.7.1 + lines-and-columns@1.2.4: {} lines-and-columns@2.0.3: {} @@ -10235,12 +10710,26 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash.includes@4.3.0: {} + + lodash.isboolean@3.0.3: {} + lodash.isequal@4.5.0: {} + lodash.isinteger@4.0.4: {} + + lodash.isnumber@3.0.3: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + lodash.memoize@4.1.2: {} lodash.merge@4.6.2: {} + lodash.once@4.1.1: {} + lodash.startcase@4.4.0: {} lodash@4.17.21: {} @@ -10301,13 +10790,15 @@ snapshots: dependencies: tmpl: 1.0.5 - media-typer@0.3.0: {} + media-typer@0.3.0: + optional: true memfs@3.5.3: dependencies: fs-monkey: 1.0.6 - merge-descriptors@1.0.3: {} + merge-descriptors@1.0.3: + optional: true merge-stream@2.0.0: {} @@ -10334,10 +10825,13 @@ snapshots: dependencies: mime-db: 1.52.0 - mime@1.6.0: {} + mime@1.6.0: + optional: true mime@2.6.0: {} + mime@3.0.0: {} + mimic-fn@2.1.0: {} min-indent@1.0.1: {} @@ -10369,6 +10863,7 @@ snapshots: mkdirp@0.5.6: dependencies: minimist: 1.2.8 + optional: true mkdirp@3.0.1: {} @@ -10379,6 +10874,10 @@ snapshots: pkg-types: 1.2.1 ufo: 1.5.4 + mnemonist@0.39.6: + dependencies: + obliterator: 2.0.4 + moment-timezone@0.5.46: dependencies: moment: 2.30.1 @@ -10404,6 +10903,7 @@ snapshots: object-assign: 4.1.1 type-is: 1.6.18 xtend: 4.0.2 + optional: true mute-stream@0.0.8: {} @@ -10434,6 +10934,8 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-gyp-build@4.8.2: {} + node-int64@0.4.0: {} node-machine-id@1.1.12: {} @@ -10528,9 +11030,14 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.0.0 + obliterator@2.0.4: {} + + on-exit-leak-free@2.1.2: {} + on-finished@2.4.1: dependencies: ee-first: 1.1.1 + optional: true on-headers@1.0.2: {} @@ -10659,7 +11166,8 @@ snapshots: dependencies: entities: 4.5.0 - parseurl@1.3.3: {} + parseurl@1.3.3: + optional: true path-browserify@1.0.1: {} @@ -10678,10 +11186,13 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 - path-to-regexp@0.1.10: {} + path-to-regexp@0.1.10: + optional: true path-to-regexp@3.3.0: {} + path-to-regexp@6.3.0: {} + path-type@4.0.0: {} pathe@1.1.2: {} @@ -10735,6 +11246,26 @@ snapshots: pify@4.0.1: {} + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + + pino-std-serializers@7.0.0: {} + + pino@9.5.0: + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.0.0 + process-warning: 4.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.0 + thread-stream: 3.1.0 + pirates@4.0.6: {} pkg-dir@4.2.0: @@ -10797,7 +11328,12 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 - process-nextick-args@2.0.1: {} + process-nextick-args@2.0.1: + optional: true + + process-warning@3.0.0: {} + + process-warning@4.0.0: {} prompts@2.4.2: dependencies: @@ -10831,13 +11367,16 @@ snapshots: queue-microtask@1.2.3: {} + quick-format-unescaped@4.0.4: {} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 range-parser@1.2.0: {} - range-parser@1.2.1: {} + range-parser@1.2.1: + optional: true raw-body@2.5.2: dependencies: @@ -10845,6 +11384,7 @@ snapshots: http-errors: 2.0.0 iconv-lite: 0.4.24 unpipe: 1.0.0 + optional: true rc@1.2.8: dependencies: @@ -10929,6 +11469,7 @@ snapshots: safe-buffer: 5.1.2 string_decoder: 1.1.1 util-deprecate: 1.0.2 + optional: true readable-stream@3.6.2: dependencies: @@ -10940,6 +11481,8 @@ snapshots: dependencies: picomatch: 2.3.1 + real-require@0.2.0: {} + rechoir@0.8.0: dependencies: resolve: 1.22.8 @@ -11014,8 +11557,12 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 + ret@0.4.3: {} + reusify@1.0.4: {} + rfdc@1.4.1: {} + rollup@4.24.2: dependencies: '@types/estree': 1.0.6 @@ -11071,6 +11618,12 @@ snapshots: es-errors: 1.3.0 is-regex: 1.1.4 + safe-regex2@3.1.0: + dependencies: + ret: 0.4.3 + + safe-stable-stringify@2.5.0: {} + safer-buffer@2.1.2: {} saxes@6.0.0: @@ -11087,6 +11640,8 @@ snapshots: ajv: 6.12.6 ajv-keywords: 3.5.2(ajv@6.12.6) + secure-json-parse@2.7.0: {} + semver@6.3.1: {} semver@7.5.4: @@ -11112,6 +11667,7 @@ snapshots: statuses: 2.0.1 transitivePeerDependencies: - supports-color + optional: true serialize-javascript@6.0.2: dependencies: @@ -11135,6 +11691,7 @@ snapshots: send: 0.19.0 transitivePeerDependencies: - supports-color + optional: true serve@14.2.4: dependencies: @@ -11152,6 +11709,8 @@ snapshots: transitivePeerDependencies: - supports-color + set-cookie-parser@2.7.1: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -11204,6 +11763,14 @@ snapshots: dot-case: 3.0.4 tslib: 2.8.0 + sodium-native@4.2.2: + dependencies: + node-gyp-build: 4.8.2 + + sonic-boom@4.2.0: + dependencies: + atomic-sleep: 1.0.0 + source-map-js@1.2.1: {} source-map-support@0.5.13: @@ -11241,7 +11808,8 @@ snapshots: std-env@3.7.0: {} - streamsearch@1.1.0: {} + streamsearch@1.1.0: + optional: true string-argv@0.3.2: {} @@ -11304,6 +11872,7 @@ snapshots: string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 + optional: true string_decoder@1.3.0: dependencies: @@ -11379,7 +11948,7 @@ snapshots: synckit@0.9.2: dependencies: '@pkgr/core': 0.1.1 - tslib: 2.7.0 + tslib: 2.8.0 tabbable@6.2.0: {} @@ -11427,6 +11996,10 @@ snapshots: text-table@0.2.0: {} + thread-stream@3.1.0: + dependencies: + real-require: 0.2.0 + through@2.3.8: {} tildify@2.0.0: {} @@ -11465,6 +12038,8 @@ snapshots: dependencies: is-number: 7.0.0 + toad-cache@3.7.0: {} + toidentifier@1.0.1: {} tough-cookie@5.0.0: @@ -11576,6 +12151,7 @@ snapshots: dependencies: media-typer: 0.3.0 mime-types: 2.1.35 + optional: true typed-array-buffer@1.0.2: dependencies: @@ -11609,7 +12185,8 @@ snapshots: is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 - typedarray@0.0.6: {} + typedarray@0.0.6: + optional: true typescript-eslint@8.11.0(eslint@9.13.0)(typescript@5.3.3): dependencies: @@ -11666,7 +12243,8 @@ snapshots: universalify@2.0.1: {} - unpipe@1.0.0: {} + unpipe@1.0.0: + optional: true unplugin@1.14.1(webpack-sources@3.2.3): dependencies: @@ -11736,7 +12314,8 @@ snapshots: util-deprecate@1.0.2: {} - utils-merge@1.0.1: {} + utils-merge@1.0.1: + optional: true v8-compile-cache-lib@3.0.1: {} @@ -11746,6 +12325,8 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + validator@13.12.0: {} + vary@1.1.2: {} vite-node@2.1.3(@types/node@22.7.9)(terser@5.34.1):