From b32de93b65c470c29dbaeb150d101ca864e3db62 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 23 Jul 2024 01:59:41 +0200 Subject: [PATCH 01/23] feat: add email functionality --- .../common_nestjs_remix/apps/api/package.json | 1 + .../api/src/common/configuration/email.ts | 25 +++++++++++++++++++ .../api/src/common/emails/email.interface.ts | 7 ++++++ .../api/src/common/emails/emails.service.ts | 12 +++++++++ examples/common_nestjs_remix/pnpm-lock.yaml | 3 +++ 5 files changed, 48 insertions(+) create mode 100644 examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts create mode 100644 examples/common_nestjs_remix/apps/api/src/common/emails/email.interface.ts create mode 100644 examples/common_nestjs_remix/apps/api/src/common/emails/emails.service.ts diff --git a/examples/common_nestjs_remix/apps/api/package.json b/examples/common_nestjs_remix/apps/api/package.json index c0fb898..59b88ed 100644 --- a/examples/common_nestjs_remix/apps/api/package.json +++ b/examples/common_nestjs_remix/apps/api/package.json @@ -43,6 +43,7 @@ "drizzle-typebox": "^0.1.1", "lodash": "^4.17.21", "nestjs-typebox": "3.0.0-next.8", + "nodemailer": "^6.9.14", "passport": "^0.7.0", "passport-jwt": "^4.0.1", "passport-local": "^1.0.0", diff --git a/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts new file mode 100644 index 0000000..1fa7335 --- /dev/null +++ b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts @@ -0,0 +1,25 @@ +import { registerAs } from "@nestjs/config"; +import { Static, Type } from "@sinclair/typebox"; +import { Value } from "@sinclair/typebox/value"; + +const schema = Type.Object({ + SMTP_HOST: Type.String(), + SMTP_PORT: Type.Number(), + SMTP_USER: Type.String(), + SMTP_PASSWORD: Type.String(), + USE_MAILHOG: Type.Boolean({ default: false }), +}); + +type DatabaseConfig = Static; + +export default registerAs("email", (): DatabaseConfig => { + const values = { + SMTP_HOST: process.env.SMTP_HOST, + SMTP_PORT: parseInt(process.env.SMTP_PORT ?? "465", 10), + SMTP_USER: process.env.SMTP_USER, + SMTP_PASSWORD: process.env.SMTP_PASSWORD, + USE_MAILHOG: process.env.USE_MAILHOG === "true", + }; + + return Value.Decode(schema, values); +}); diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/email.interface.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/email.interface.ts new file mode 100644 index 0000000..28c1399 --- /dev/null +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/email.interface.ts @@ -0,0 +1,7 @@ +export interface Email { + to: string; + from: string; + subject: string; + text?: string; + html?: string; +} diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/emails.service.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.service.ts new file mode 100644 index 0000000..6daf4ea --- /dev/null +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.service.ts @@ -0,0 +1,12 @@ +import { Injectable } from "@nestjs/common"; +import { Email } from "./email.interface"; +import { EmailAdapter } from "./adapters/email.adapter"; + +@Injectable() +export class EmailService { + constructor(private emailAdapter: EmailAdapter) {} + + async sendEmail(email: Email): Promise { + await this.emailAdapter.sendMail(email); + } +} diff --git a/examples/common_nestjs_remix/pnpm-lock.yaml b/examples/common_nestjs_remix/pnpm-lock.yaml index 40b34a0..6416759 100644 --- a/examples/common_nestjs_remix/pnpm-lock.yaml +++ b/examples/common_nestjs_remix/pnpm-lock.yaml @@ -80,6 +80,9 @@ importers: nestjs-typebox: specifier: 3.0.0-next.8 version: 3.0.0-next.8(@nestjs/common@10.0.0)(@nestjs/core@10.0.0)(@nestjs/swagger@7.4.0)(@sinclair/typebox@0.32.34)(rxjs@7.8.1) + nodemailer: + specifier: ^6.9.14 + version: 6.9.14 passport: specifier: ^0.7.0 version: 0.7.0 From e279bc35d1ed1b17c9d63691d583d9d954375307 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 23 Jul 2024 01:59:41 +0200 Subject: [PATCH 02/23] feat: integrate email module into auth module --- examples/common_nestjs_remix/apps/api/package.json | 1 + examples/common_nestjs_remix/apps/api/src/app.module.ts | 5 ++++- .../common_nestjs_remix/apps/api/src/auth/auth.module.ts | 3 ++- .../apps/api/src/auth/auth.service.ts | 9 +++++++++ examples/common_nestjs_remix/docker-compose.yml | 5 +++++ 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/examples/common_nestjs_remix/apps/api/package.json b/examples/common_nestjs_remix/apps/api/package.json index 59b88ed..256eedc 100644 --- a/examples/common_nestjs_remix/apps/api/package.json +++ b/examples/common_nestjs_remix/apps/api/package.json @@ -64,6 +64,7 @@ "@types/jest": "^29.5.2", "@types/lodash": "^4.17.6", "@types/node": "^20.3.1", + "@types/nodemailer": "^6.4.15", "@types/passport-jwt": "^4.0.1", "@types/passport-local": "^1.0.38", "@types/supertest": "^6.0.0", diff --git a/examples/common_nestjs_remix/apps/api/src/app.module.ts b/examples/common_nestjs_remix/apps/api/src/app.module.ts index 2c63833..ba3ca45 100644 --- a/examples/common_nestjs_remix/apps/api/src/app.module.ts +++ b/examples/common_nestjs_remix/apps/api/src/app.module.ts @@ -7,13 +7,15 @@ import { AuthModule } from "./auth/auth.module"; import { UsersModule } from "./users/users.module"; import { JwtModule } from "@nestjs/jwt"; import jwtConfig from "./common/configuration/jwt"; +import emailConfig from "./common/configuration/email"; import { APP_GUARD } from "@nestjs/core"; import { JwtAuthGuard } from "./common/guards/jwt-auth-guard"; +import { EmailModule } from "./common/emails/emails.module"; @Module({ imports: [ ConfigModule.forRoot({ - load: [database, jwtConfig], + load: [database, jwtConfig, emailConfig], isGlobal: true, }), DrizzlePostgresModule.registerAsync({ @@ -47,6 +49,7 @@ import { JwtAuthGuard } from "./common/guards/jwt-auth-guard"; }), AuthModule, UsersModule, + EmailModule, ], controllers: [], providers: [ diff --git a/examples/common_nestjs_remix/apps/api/src/auth/auth.module.ts b/examples/common_nestjs_remix/apps/api/src/auth/auth.module.ts index 5a430cb..582a29d 100644 --- a/examples/common_nestjs_remix/apps/api/src/auth/auth.module.ts +++ b/examples/common_nestjs_remix/apps/api/src/auth/auth.module.ts @@ -6,9 +6,10 @@ import { JwtStrategy } from "./strategy/jwt.strategy"; import { LocalStrategy } from "./strategy/local.strategy"; import { TokenService } from "./token.service"; import { UsersService } from "src/users/users.service"; +import { EmailModule } from "src/common/emails/emails.module"; @Module({ - imports: [PassportModule], + imports: [PassportModule, EmailModule], controllers: [AuthController], providers: [ AuthService, diff --git a/examples/common_nestjs_remix/apps/api/src/auth/auth.service.ts b/examples/common_nestjs_remix/apps/api/src/auth/auth.service.ts index 685d64a..9647d85 100644 --- a/examples/common_nestjs_remix/apps/api/src/auth/auth.service.ts +++ b/examples/common_nestjs_remix/apps/api/src/auth/auth.service.ts @@ -12,6 +12,7 @@ import { DatabasePg, UUIDType } from "src/common"; import { credentials, users } from "../storage/schema"; import { UsersService } from "../users/users.service"; import hashPassword from "src/common/helpers/hashPassword"; +import { EmailService } from "src/common/emails/emails.service"; @Injectable() export class AuthService { @@ -20,6 +21,7 @@ export class AuthService { private jwtService: JwtService, private usersService: UsersService, private configService: ConfigService, + private emailService: EmailService, ) {} public async register(email: string, password: string) { @@ -41,6 +43,13 @@ export class AuthService { .insert(credentials) .values({ userId: newUser.id, password: hashedPassword }); + await this.emailService.sendEmail({ + to: email, + subject: "Welcome to our platform", + text: "You have successfully registered", + from: "godfather@selleo.com", + }); + return newUser; }); } diff --git a/examples/common_nestjs_remix/docker-compose.yml b/examples/common_nestjs_remix/docker-compose.yml index dd14984..6d66a39 100644 --- a/examples/common_nestjs_remix/docker-compose.yml +++ b/examples/common_nestjs_remix/docker-compose.yml @@ -9,6 +9,11 @@ services: - guidebook-db-data:/var/lib/postgresql/data ports: - 5432:5432 + mailhog: + image: mailhog/mailhog + ports: + - 1025:1025 + - 8025:8025 volumes: guidebook-db-data: From c9e7c42acde90ada962066007ea3619080645342 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 23 Jul 2024 01:59:41 +0200 Subject: [PATCH 03/23] feat: add nodemailer adapter and email configuration --- .../common_nestjs_remix/apps/api/.env.example | 6 ++++ .../src/auth/__tests__/auth.service.spec.ts | 6 ++++ .../api/src/common/configuration/email.ts | 6 ++-- .../common/emails/adapters/email.adapter.ts | 5 ++++ .../emails/adapters/nodemailer.adapter.ts | 21 ++++++++++++++ .../api/src/common/emails/email.config.ts | 29 +++++++++++++++++++ .../api/src/common/emails/emails.module.ts | 20 +++++++++++++ examples/common_nestjs_remix/pnpm-lock.yaml | 14 +++++++++ 8 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 examples/common_nestjs_remix/apps/api/src/common/emails/adapters/email.adapter.ts create mode 100644 examples/common_nestjs_remix/apps/api/src/common/emails/adapters/nodemailer.adapter.ts create mode 100644 examples/common_nestjs_remix/apps/api/src/common/emails/email.config.ts create mode 100644 examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts diff --git a/examples/common_nestjs_remix/apps/api/.env.example b/examples/common_nestjs_remix/apps/api/.env.example index f534ea5..591052a 100644 --- a/examples/common_nestjs_remix/apps/api/.env.example +++ b/examples/common_nestjs_remix/apps/api/.env.example @@ -1,4 +1,10 @@ DATABASE_URL="postgres://postgres:guidebook@localhost:5432/guidebook" JWT_SECRET= JWT_REFRESH_SECRET= +JWT_EXPIRATION_TIME= CORS_ORIGIN= +SMTP_HOST= +SMTP_PORT= +SMTP_USER= +SMTP_PASSWORD= +USE_MAILHOG=true diff --git a/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts b/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts index b23c989..52a81df 100644 --- a/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts +++ b/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts @@ -15,6 +15,12 @@ import { omit } from "lodash"; import hashPassword from "src/common/helpers/hashPassword"; import { truncateAllTables } from "test/helpers/test-helpers"; +jest.mock("../../common/emails/emails.service", () => ({ + EmailService: jest.fn().mockImplementation(() => ({ + sendEmail: jest.fn().mockResolvedValue(undefined), + })), +})); + describe("AuthService", () => { let testContext: TestContext; let authService: AuthService; diff --git a/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts index 1fa7335..bf0544a 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts @@ -7,12 +7,12 @@ const schema = Type.Object({ SMTP_PORT: Type.Number(), SMTP_USER: Type.String(), SMTP_PASSWORD: Type.String(), - USE_MAILHOG: Type.Boolean({ default: false }), + USE_MAILHOG: Type.Boolean(), }); -type DatabaseConfig = Static; +type EmailConfig = Static; -export default registerAs("email", (): DatabaseConfig => { +export default registerAs("email", (): EmailConfig => { const values = { SMTP_HOST: process.env.SMTP_HOST, SMTP_PORT: parseInt(process.env.SMTP_PORT ?? "465", 10), diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/email.adapter.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/email.adapter.ts new file mode 100644 index 0000000..73cf038 --- /dev/null +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/email.adapter.ts @@ -0,0 +1,5 @@ +import { Email } from "../email.interface"; + +export abstract class EmailAdapter { + abstract sendMail(email: Email): Promise; +} diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/nodemailer.adapter.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/nodemailer.adapter.ts new file mode 100644 index 0000000..28be4fc --- /dev/null +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/nodemailer.adapter.ts @@ -0,0 +1,21 @@ +import { Injectable } from "@nestjs/common"; +import * as nodemailer from "nodemailer"; +import { Email } from "../email.interface"; +import { EmailAdapter } from "./email.adapter"; +import { EmailConfig } from "../email.config"; + +@Injectable() +export class NodemailerAdapter extends EmailAdapter { + private transporter: nodemailer.Transporter; + + constructor(private config: EmailConfig) { + super(); + this.transporter = nodemailer.createTransport( + this.config.getNodemailerOptions(), + ); + } + + async sendMail(email: Email): Promise { + await this.transporter.sendMail(email); + } +} diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/email.config.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/email.config.ts new file mode 100644 index 0000000..2846234 --- /dev/null +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/email.config.ts @@ -0,0 +1,29 @@ +import { Injectable } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; + +@Injectable() +export class EmailConfig { + constructor(private configService: ConfigService) {} + + getNodemailerOptions() { + const useMailhog = this.configService.get("email.USE_MAILHOG"); + + if (useMailhog) { + return { + host: "localhost", + port: 1025, + ignoreTLS: true, + }; + } + + return { + host: this.configService.get("email.SMTP_HOST"), + port: this.configService.get("email.SMTP_PORT"), + secure: true, + auth: { + user: this.configService.get("email.SMTP_USER"), + pass: this.configService.get("email.SMTP_PASSWORD"), + }, + }; + } +} diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts new file mode 100644 index 0000000..f2c10f3 --- /dev/null +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts @@ -0,0 +1,20 @@ +import { Module } from "@nestjs/common"; +import { ConfigModule } from "@nestjs/config"; +import { EmailService } from "./emails.service"; +import { EmailConfig } from "./email.config"; +import { NodemailerAdapter } from "./adapters/nodemailer.adapter"; +import { EmailAdapter } from "./adapters/email.adapter"; + +@Module({ + imports: [ConfigModule], + providers: [ + EmailService, + EmailConfig, + { + provide: EmailAdapter, + useClass: NodemailerAdapter, + }, + ], + exports: [EmailService], +}) +export class EmailModule {} diff --git a/examples/common_nestjs_remix/pnpm-lock.yaml b/examples/common_nestjs_remix/pnpm-lock.yaml index 6416759..2a42db9 100644 --- a/examples/common_nestjs_remix/pnpm-lock.yaml +++ b/examples/common_nestjs_remix/pnpm-lock.yaml @@ -138,6 +138,9 @@ importers: '@types/node': specifier: ^20.3.1 version: 20.11.24 + '@types/nodemailer': + specifier: ^6.4.15 + version: 6.4.15 '@types/passport-jwt': specifier: ^4.0.1 version: 4.0.1 @@ -3634,6 +3637,12 @@ packages: dependencies: undici-types: 5.26.5 + /@types/nodemailer@6.4.15: + resolution: {integrity: sha512-0EBJxawVNjPkng1zm2vopRctuWVCxk34JcIlRuXSf54habUWdz1FB7wHDqOqvDa8Mtpt0Q3LTXQkAs2LNyK5jQ==} + dependencies: + '@types/node': 20.14.10 + dev: true + /@types/parse-json@4.0.2: resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} dev: true @@ -9519,6 +9528,11 @@ packages: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} dev: true + /nodemailer@6.9.14: + resolution: {integrity: sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==} + engines: {node: '>=6.0.0'} + dev: false + /nopt@5.0.0: resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} engines: {node: '>=6'} From 7f50fd26be107215addefe9d544ca928c961565d Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 23 Jul 2024 12:35:11 +0200 Subject: [PATCH 04/23] feat: add email adapter factory and local adapter --- .../common_nestjs_remix/apps/api/.env.example | 2 +- .../common_nestjs_remix/apps/api/package.json | 1 + .../api/src/common/configuration/email.ts | 2 ++ .../common/emails/adapters/local.adapter.ts | 22 +++++++++++++ .../emails/adapters/nodemailer.adapter.ts | 20 +++++++++--- .../api/src/common/emails/email.config.ts | 29 ----------------- .../api/src/common/emails/emails.module.ts | 14 ++++++--- .../emails/factory/EmailAdaptersFactory.ts | 31 +++++++++++++++++++ examples/common_nestjs_remix/pnpm-lock.yaml | 3 ++ 9 files changed, 84 insertions(+), 40 deletions(-) create mode 100644 examples/common_nestjs_remix/apps/api/src/common/emails/adapters/local.adapter.ts delete mode 100644 examples/common_nestjs_remix/apps/api/src/common/emails/email.config.ts create mode 100644 examples/common_nestjs_remix/apps/api/src/common/emails/factory/EmailAdaptersFactory.ts diff --git a/examples/common_nestjs_remix/apps/api/.env.example b/examples/common_nestjs_remix/apps/api/.env.example index 591052a..faac660 100644 --- a/examples/common_nestjs_remix/apps/api/.env.example +++ b/examples/common_nestjs_remix/apps/api/.env.example @@ -7,4 +7,4 @@ SMTP_HOST= SMTP_PORT= SMTP_USER= SMTP_PASSWORD= -USE_MAILHOG=true +EMAIL_ADAPTER="mailhog" diff --git a/examples/common_nestjs_remix/apps/api/package.json b/examples/common_nestjs_remix/apps/api/package.json index 256eedc..b6c8112 100644 --- a/examples/common_nestjs_remix/apps/api/package.json +++ b/examples/common_nestjs_remix/apps/api/package.json @@ -50,6 +50,7 @@ "postgres": "^3.4.4", "reflect-metadata": "^0.2.0", "rxjs": "^7.8.1", + "ts-pattern": "^5.2.0", "uuid": "^10.0.0" }, "devDependencies": { diff --git a/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts index bf0544a..19b6c24 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts @@ -8,6 +8,7 @@ const schema = Type.Object({ SMTP_USER: Type.String(), SMTP_PASSWORD: Type.String(), USE_MAILHOG: Type.Boolean(), + EMAIL_ADAPTER: Type.String(), }); type EmailConfig = Static; @@ -19,6 +20,7 @@ export default registerAs("email", (): EmailConfig => { SMTP_USER: process.env.SMTP_USER, SMTP_PASSWORD: process.env.SMTP_PASSWORD, USE_MAILHOG: process.env.USE_MAILHOG === "true", + EMAIL_ADAPTER: process.env.EMAIL_ADAPTER, }; return Value.Decode(schema, values); diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/local.adapter.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/local.adapter.ts new file mode 100644 index 0000000..4648068 --- /dev/null +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/local.adapter.ts @@ -0,0 +1,22 @@ +import { Injectable } from "@nestjs/common"; +import * as nodemailer from "nodemailer"; +import { Email } from "../email.interface"; +import { EmailAdapter } from "./email.adapter"; + +@Injectable() +export class LocalAdapter extends EmailAdapter { + private transporter: nodemailer.Transporter; + + constructor() { + super(); + this.transporter = nodemailer.createTransport({ + host: "localhost", + port: 1025, + ignoreTLS: true, + }); + } + + async sendMail(email: Email): Promise { + await this.transporter.sendMail(email); + } +} diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/nodemailer.adapter.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/nodemailer.adapter.ts index 28be4fc..13ff2a2 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/nodemailer.adapter.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/nodemailer.adapter.ts @@ -1,21 +1,31 @@ import { Injectable } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; import * as nodemailer from "nodemailer"; import { Email } from "../email.interface"; import { EmailAdapter } from "./email.adapter"; -import { EmailConfig } from "../email.config"; @Injectable() export class NodemailerAdapter extends EmailAdapter { private transporter: nodemailer.Transporter; - constructor(private config: EmailConfig) { + constructor(private configService: ConfigService) { super(); - this.transporter = nodemailer.createTransport( - this.config.getNodemailerOptions(), - ); + this.transporter = nodemailer.createTransport(this.getNodemailerOptions()); } async sendMail(email: Email): Promise { await this.transporter.sendMail(email); } + + private getNodemailerOptions() { + return { + host: this.configService.get("email.SMTP_HOST"), + port: this.configService.get("email.SMTP_PORT"), + secure: true, + auth: { + user: this.configService.get("email.SMTP_USER"), + pass: this.configService.get("email.SMTP_PASSWORD"), + }, + }; + } } diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/email.config.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/email.config.ts deleted file mode 100644 index 2846234..0000000 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/email.config.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Injectable } from "@nestjs/common"; -import { ConfigService } from "@nestjs/config"; - -@Injectable() -export class EmailConfig { - constructor(private configService: ConfigService) {} - - getNodemailerOptions() { - const useMailhog = this.configService.get("email.USE_MAILHOG"); - - if (useMailhog) { - return { - host: "localhost", - port: 1025, - ignoreTLS: true, - }; - } - - return { - host: this.configService.get("email.SMTP_HOST"), - port: this.configService.get("email.SMTP_PORT"), - secure: true, - auth: { - user: this.configService.get("email.SMTP_USER"), - pass: this.configService.get("email.SMTP_PASSWORD"), - }, - }; - } -} diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts index f2c10f3..5aa0f7a 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts @@ -1,18 +1,22 @@ import { Module } from "@nestjs/common"; import { ConfigModule } from "@nestjs/config"; -import { EmailService } from "./emails.service"; -import { EmailConfig } from "./email.config"; -import { NodemailerAdapter } from "./adapters/nodemailer.adapter"; import { EmailAdapter } from "./adapters/email.adapter"; +import { NodemailerAdapter } from "./adapters/nodemailer.adapter"; +import { LocalAdapter } from "./adapters/local.adapter"; +import { EmailAdapterFactory } from "./factory/EmailAdaptersFactory"; +import { EmailService } from "./emails.service"; @Module({ imports: [ConfigModule], providers: [ EmailService, - EmailConfig, + NodemailerAdapter, + LocalAdapter, + EmailAdapterFactory, { provide: EmailAdapter, - useClass: NodemailerAdapter, + useFactory: (factory: EmailAdapterFactory) => factory.createAdapter(), + inject: [EmailAdapterFactory], }, ], exports: [EmailService], diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/factory/EmailAdaptersFactory.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/factory/EmailAdaptersFactory.ts new file mode 100644 index 0000000..3734827 --- /dev/null +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/factory/EmailAdaptersFactory.ts @@ -0,0 +1,31 @@ +import { Injectable } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; +import { EmailAdapter } from "../adapters/email.adapter"; +import { NodemailerAdapter } from "../adapters/nodemailer.adapter"; +import { LocalAdapter } from "../adapters/local.adapter"; +import { match, P } from "ts-pattern"; + +type AdapterType = "mailhog" | "smtp"; + +@Injectable() +export class EmailAdapterFactory { + constructor( + private configService: ConfigService, + private localAdapter: LocalAdapter, + private nodemailerAdapter: NodemailerAdapter, + ) {} + + createAdapter(): EmailAdapter { + const adapterType = this.configService.get("EMAIL_ADAPTER"); + + return match(adapterType) + .with("mailhog", () => this.localAdapter) + .with("smtp", () => this.nodemailerAdapter) + .with(P.nullish, () => { + throw new Error("EMAIL_ADAPTER is not defined in configuration"); + }) + .otherwise((type) => { + throw new Error(`Unknown email adapter type: ${type}`); + }); + } +} diff --git a/examples/common_nestjs_remix/pnpm-lock.yaml b/examples/common_nestjs_remix/pnpm-lock.yaml index 2a42db9..b4da30d 100644 --- a/examples/common_nestjs_remix/pnpm-lock.yaml +++ b/examples/common_nestjs_remix/pnpm-lock.yaml @@ -101,6 +101,9 @@ importers: rxjs: specifier: ^7.8.1 version: 7.8.1 + ts-pattern: + specifier: ^5.2.0 + version: 5.2.0 uuid: specifier: ^10.0.0 version: 10.0.0 From 48e42c67a0547b2a90549ba08a7319681583f941 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 23 Jul 2024 13:16:47 +0200 Subject: [PATCH 05/23] feat: add EmailTestingAdapter for testing email functionality --- .../src/auth/__tests__/auth.service.spec.ts | 32 ++++++++++++++++- .../api/src/common/emails/emails.module.ts | 2 +- ...rsFactory.ts => email-adapters.factory.ts} | 0 .../api/test/helpers/test-email.adapter.ts | 35 +++++++++++++++++++ 4 files changed, 67 insertions(+), 2 deletions(-) rename examples/common_nestjs_remix/apps/api/src/common/emails/factory/{EmailAdaptersFactory.ts => email-adapters.factory.ts} (100%) create mode 100644 examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts diff --git a/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts b/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts index 52a81df..cdaf014 100644 --- a/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts +++ b/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts @@ -14,10 +14,15 @@ import { createUserFactory } from "test/factory/user.factory"; import { omit } from "lodash"; import hashPassword from "src/common/helpers/hashPassword"; import { truncateAllTables } from "test/helpers/test-helpers"; +import { EmailTestingAdapter } from "test/helpers/test-email.adapter"; + +const mockEmailTestingAdapter = new EmailTestingAdapter(); jest.mock("../../common/emails/emails.service", () => ({ EmailService: jest.fn().mockImplementation(() => ({ - sendEmail: jest.fn().mockResolvedValue(undefined), + sendEmail: jest + .fn() + .mockImplementation((email) => mockEmailTestingAdapter.sendMail(email)), })), })); @@ -38,6 +43,8 @@ describe("AuthService", () => { afterEach(async () => { await truncateAllTables(db); + mockEmailTestingAdapter.resetEmailOverride(); + mockEmailTestingAdapter.clearEmails(); }); describe("register", () => { @@ -66,6 +73,29 @@ describe("AuthService", () => { ); }); + it("should send a welcome email after successful registration", async () => { + const user = userFactory.build(); + const password = "password123"; + const subject = "Hello there!"; + const text = "General Kenobi"; + const html = "You are a bold one"; + + mockEmailTestingAdapter.setEmailOverride({ + subject, + text, + html, + }); + + await authService.register(user.email, password); + const lastEmail = mockEmailTestingAdapter.getLastEmail(); + + expect(lastEmail).toBeDefined(); + expect(lastEmail?.to).toBe(user.email); + expect(lastEmail?.subject).toBe(subject); + expect(lastEmail?.text).toBe(text); + expect(lastEmail?.html).toBe(html); + }); + it("should throw ConflictException if user already exists", async () => { const email = "existing@example.com"; const user = await userFactory.create({ email }); diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts index 5aa0f7a..15974c7 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts @@ -3,7 +3,7 @@ import { ConfigModule } from "@nestjs/config"; import { EmailAdapter } from "./adapters/email.adapter"; import { NodemailerAdapter } from "./adapters/nodemailer.adapter"; import { LocalAdapter } from "./adapters/local.adapter"; -import { EmailAdapterFactory } from "./factory/EmailAdaptersFactory"; +import { EmailAdapterFactory } from "./factory/email-adapters.factory"; import { EmailService } from "./emails.service"; @Module({ diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/factory/EmailAdaptersFactory.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts similarity index 100% rename from examples/common_nestjs_remix/apps/api/src/common/emails/factory/EmailAdaptersFactory.ts rename to examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts diff --git a/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts b/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts new file mode 100644 index 0000000..8f625df --- /dev/null +++ b/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts @@ -0,0 +1,35 @@ +import { EmailAdapter } from "../../src/common/emails/adapters/email.adapter"; +import { Email } from "../../src/common/emails/email.interface"; +import { last } from "lodash"; + +export class EmailTestingAdapter extends EmailAdapter { + private sentEmails: Email[] = []; + private emailOverride: Partial | null = null; + + async sendMail(email: Email): Promise { + const finalEmail = this.emailOverride + ? { ...email, ...this.emailOverride } + : email; + this.sentEmails.push(finalEmail); + } + + setEmailOverride(override: Partial): void { + this.emailOverride = override; + } + + resetEmailOverride(): void { + this.emailOverride = null; + } + + getAllEmails(): Email[] { + return this.sentEmails; + } + + getLastEmail(): Email | undefined { + return last(this.sentEmails); + } + + clearEmails(): void { + this.sentEmails = []; + } +} From c65b1bab6990dd41bc78852e07be360303424dde Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 23 Jul 2024 13:25:33 +0200 Subject: [PATCH 06/23] refactor: update email adapter type and configuration schema --- .../apps/api/src/common/configuration/email.ts | 6 +++--- .../api/src/common/emails/factory/email-adapters.factory.ts | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts index 19b6c24..7b884b0 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts @@ -8,12 +8,12 @@ const schema = Type.Object({ SMTP_USER: Type.String(), SMTP_PASSWORD: Type.String(), USE_MAILHOG: Type.Boolean(), - EMAIL_ADAPTER: Type.String(), + EMAIL_ADAPTER: Type.Union([Type.Literal("mailhog"), Type.Literal("smtp")]), }); -type EmailConfig = Static; +export type EmailConfigSchema = Static; -export default registerAs("email", (): EmailConfig => { +export default registerAs("email", (): EmailConfigSchema => { const values = { SMTP_HOST: process.env.SMTP_HOST, SMTP_PORT: parseInt(process.env.SMTP_PORT ?? "465", 10), diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts index 3734827..0be6d93 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts @@ -4,8 +4,9 @@ import { EmailAdapter } from "../adapters/email.adapter"; import { NodemailerAdapter } from "../adapters/nodemailer.adapter"; import { LocalAdapter } from "../adapters/local.adapter"; import { match, P } from "ts-pattern"; +import { EmailConfigSchema } from "src/common/configuration/email"; -type AdapterType = "mailhog" | "smtp"; +type AdapterType = EmailConfigSchema["EMAIL_ADAPTER"]; @Injectable() export class EmailAdapterFactory { From 46a9c29559c5ff8d03edfdc5f49404f96ebb4bcd Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 23 Jul 2024 15:51:25 +0200 Subject: [PATCH 07/23] feat: add sas email adapter --- .../common_nestjs_remix/apps/api/.env.example | 16 +- .../common_nestjs_remix/apps/api/package.json | 1 + .../apps/api/src/app.module.ts | 3 +- .../apps/api/src/common/configuration/aws.ts | 21 + .../api/src/common/configuration/email.ts | 6 +- .../src/common/emails/adapters/ses.adapter.ts | 65 ++ .../api/src/common/emails/emails.module.ts | 2 + .../emails/factory/email-adapters.factory.ts | 3 + examples/common_nestjs_remix/pnpm-lock.yaml | 880 ++++++++++++++++++ 9 files changed, 993 insertions(+), 4 deletions(-) create mode 100644 examples/common_nestjs_remix/apps/api/src/common/configuration/aws.ts create mode 100644 examples/common_nestjs_remix/apps/api/src/common/emails/adapters/ses.adapter.ts diff --git a/examples/common_nestjs_remix/apps/api/.env.example b/examples/common_nestjs_remix/apps/api/.env.example index faac660..ce744b7 100644 --- a/examples/common_nestjs_remix/apps/api/.env.example +++ b/examples/common_nestjs_remix/apps/api/.env.example @@ -1,10 +1,22 @@ +# GENERAL +CORS_ORIGIN="https://app.guidebook.localhost" +EMAIL_ADAPTER="mailhog" + +# DATABASE DATABASE_URL="postgres://postgres:guidebook@localhost:5432/guidebook" + +# JWT JWT_SECRET= JWT_REFRESH_SECRET= JWT_EXPIRATION_TIME= -CORS_ORIGIN= + +# MAILS SMTP_HOST= SMTP_PORT= SMTP_USER= SMTP_PASSWORD= -EMAIL_ADAPTER="mailhog" + +# AWS +AWS_REGION= +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= diff --git a/examples/common_nestjs_remix/apps/api/package.json b/examples/common_nestjs_remix/apps/api/package.json index b6c8112..5d0b224 100644 --- a/examples/common_nestjs_remix/apps/api/package.json +++ b/examples/common_nestjs_remix/apps/api/package.json @@ -24,6 +24,7 @@ "db:generate": "drizzle-kit generate" }, "dependencies": { + "@aws-sdk/client-ses": "^3.616.0", "@knaadh/nestjs-drizzle-postgres": "^1.0.0", "@nestjs/common": "^10.0.0", "@nestjs/config": "^3.2.3", diff --git a/examples/common_nestjs_remix/apps/api/src/app.module.ts b/examples/common_nestjs_remix/apps/api/src/app.module.ts index ba3ca45..7d9f985 100644 --- a/examples/common_nestjs_remix/apps/api/src/app.module.ts +++ b/examples/common_nestjs_remix/apps/api/src/app.module.ts @@ -8,6 +8,7 @@ import { UsersModule } from "./users/users.module"; import { JwtModule } from "@nestjs/jwt"; import jwtConfig from "./common/configuration/jwt"; import emailConfig from "./common/configuration/email"; +import awsConfig from "./common/configuration/aws"; import { APP_GUARD } from "@nestjs/core"; import { JwtAuthGuard } from "./common/guards/jwt-auth-guard"; import { EmailModule } from "./common/emails/emails.module"; @@ -15,7 +16,7 @@ import { EmailModule } from "./common/emails/emails.module"; @Module({ imports: [ ConfigModule.forRoot({ - load: [database, jwtConfig, emailConfig], + load: [database, jwtConfig, emailConfig, awsConfig], isGlobal: true, }), DrizzlePostgresModule.registerAsync({ diff --git a/examples/common_nestjs_remix/apps/api/src/common/configuration/aws.ts b/examples/common_nestjs_remix/apps/api/src/common/configuration/aws.ts new file mode 100644 index 0000000..9593391 --- /dev/null +++ b/examples/common_nestjs_remix/apps/api/src/common/configuration/aws.ts @@ -0,0 +1,21 @@ +import { registerAs } from "@nestjs/config"; +import { Static, Type } from "@sinclair/typebox"; +import { Value } from "@sinclair/typebox/value"; + +const schema = Type.Object({ + AWS_REGION: Type.String(), + AWS_ACCESS_KEY_ID: Type.String(), + AWS_SECRET_ACCESS_KEY: Type.String(), +}); + +type AWSConfigSchema = Static; + +export default registerAs("aws", (): AWSConfigSchema => { + const values = { + AWS_REGION: process.env.AWS_REGION, + AWS_ACCESS_KEY_ID: process.env.AWS_ACCESS_KEY_ID, + AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY, + }; + + return Value.Decode(schema, values); +}); diff --git a/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts index 7b884b0..4f93b24 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts @@ -8,7 +8,11 @@ const schema = Type.Object({ SMTP_USER: Type.String(), SMTP_PASSWORD: Type.String(), USE_MAILHOG: Type.Boolean(), - EMAIL_ADAPTER: Type.Union([Type.Literal("mailhog"), Type.Literal("smtp")]), + EMAIL_ADAPTER: Type.Union([ + Type.Literal("mailhog"), + Type.Literal("smtp"), + Type.Literal("ses"), + ]), }); export type EmailConfigSchema = Static; diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/ses.adapter.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/ses.adapter.ts new file mode 100644 index 0000000..2e1d39a --- /dev/null +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/ses.adapter.ts @@ -0,0 +1,65 @@ +import { Injectable } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; +import { SES, SESClientConfig } from "@aws-sdk/client-ses"; +import { EmailAdapter } from "./email.adapter"; +import { Email } from "../email.interface"; + +@Injectable() +export class AWSSESAdapter extends EmailAdapter { + private ses: SES; + + constructor(private configService: ConfigService) { + super(); + const config: SESClientConfig = this.getAWSConfig(); + this.ses = new SES(config); + } + + private getAWSConfig(): SESClientConfig { + const region = this.configService.get("aws.AWS_REGION"); + const accessKeyId = this.configService.get("aws.AWS_ACCESS_KEY_ID"); + const secretAccessKey = this.configService.get( + "aws.AWS_SECRET_ACCESS_KEY", + ); + + if (!region || !accessKeyId || !secretAccessKey) { + throw new Error("Missing AWS configuration"); + } + + return { + region, + credentials: { + accessKeyId, + secretAccessKey, + }, + }; + } + + async sendMail(email: Email): Promise { + const params = { + Source: email.from, + Destination: { + ToAddresses: [email.to], + }, + Message: { + Subject: { + Data: email.subject, + }, + Body: { + Text: { + Data: email.text, + }, + Html: { + Data: email.html, + }, + }, + }, + }; + + try { + await this.ses.sendEmail(params); + } catch (error) { + console.error("Error sending email via AWS SES:", error); + throw error; + } + } +} diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts index 15974c7..206208f 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts @@ -5,6 +5,7 @@ import { NodemailerAdapter } from "./adapters/nodemailer.adapter"; import { LocalAdapter } from "./adapters/local.adapter"; import { EmailAdapterFactory } from "./factory/email-adapters.factory"; import { EmailService } from "./emails.service"; +import { AWSSESAdapter } from "./adapters/ses.adapter"; @Module({ imports: [ConfigModule], @@ -12,6 +13,7 @@ import { EmailService } from "./emails.service"; EmailService, NodemailerAdapter, LocalAdapter, + AWSSESAdapter, EmailAdapterFactory, { provide: EmailAdapter, diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts index 0be6d93..67972f9 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts @@ -5,6 +5,7 @@ import { NodemailerAdapter } from "../adapters/nodemailer.adapter"; import { LocalAdapter } from "../adapters/local.adapter"; import { match, P } from "ts-pattern"; import { EmailConfigSchema } from "src/common/configuration/email"; +import { AWSSESAdapter } from "../adapters/ses.adapter"; type AdapterType = EmailConfigSchema["EMAIL_ADAPTER"]; @@ -14,6 +15,7 @@ export class EmailAdapterFactory { private configService: ConfigService, private localAdapter: LocalAdapter, private nodemailerAdapter: NodemailerAdapter, + private awsSesAdapter: AWSSESAdapter, ) {} createAdapter(): EmailAdapter { @@ -22,6 +24,7 @@ export class EmailAdapterFactory { return match(adapterType) .with("mailhog", () => this.localAdapter) .with("smtp", () => this.nodemailerAdapter) + .with("ses", () => this.awsSesAdapter) .with(P.nullish, () => { throw new Error("EMAIL_ADAPTER is not defined in configuration"); }) diff --git a/examples/common_nestjs_remix/pnpm-lock.yaml b/examples/common_nestjs_remix/pnpm-lock.yaml index b4da30d..f55eba1 100644 --- a/examples/common_nestjs_remix/pnpm-lock.yaml +++ b/examples/common_nestjs_remix/pnpm-lock.yaml @@ -23,6 +23,9 @@ importers: apps/api: dependencies: + '@aws-sdk/client-ses': + specifier: ^3.616.0 + version: 3.616.0 '@knaadh/nestjs-drizzle-postgres': specifier: ^1.0.0 version: 1.0.0(@nestjs/common@10.0.0)(drizzle-orm@0.31.2)(postgres@3.4.4) @@ -485,6 +488,473 @@ packages: - chokidar dev: true + /@aws-crypto/sha256-browser@5.2.0: + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.609.0 + '@aws-sdk/util-locate-window': 3.568.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.6.3 + dev: false + + /@aws-crypto/sha256-js@5.2.0: + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.609.0 + tslib: 2.6.3 + dev: false + + /@aws-crypto/supports-web-crypto@5.2.0: + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + dependencies: + tslib: 2.6.3 + dev: false + + /@aws-crypto/util@5.2.0: + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + dependencies: + '@aws-sdk/types': 3.609.0 + '@smithy/util-utf8': 2.3.0 + tslib: 2.6.3 + dev: false + + /@aws-sdk/client-ses@3.616.0: + resolution: {integrity: sha512-GrN5zWLE3gBb9UqSlOkRO/a2NOKODqM8MblGBIRiuLm/thdvzvlUuZOXGzEydhOHq0CqgCiFudYc37ahIKrDWQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.616.0(@aws-sdk/client-sts@3.616.0) + '@aws-sdk/client-sts': 3.616.0 + '@aws-sdk/core': 3.616.0 + '@aws-sdk/credential-provider-node': 3.616.0(@aws-sdk/client-sso-oidc@3.616.0)(@aws-sdk/client-sts@3.616.0) + '@aws-sdk/middleware-host-header': 3.616.0 + '@aws-sdk/middleware-logger': 3.609.0 + '@aws-sdk/middleware-recursion-detection': 3.616.0 + '@aws-sdk/middleware-user-agent': 3.616.0 + '@aws-sdk/region-config-resolver': 3.614.0 + '@aws-sdk/types': 3.609.0 + '@aws-sdk/util-endpoints': 3.614.0 + '@aws-sdk/util-user-agent-browser': 3.609.0 + '@aws-sdk/util-user-agent-node': 3.614.0 + '@smithy/config-resolver': 3.0.5 + '@smithy/core': 2.2.8 + '@smithy/fetch-http-handler': 3.2.2 + '@smithy/hash-node': 3.0.3 + '@smithy/invalid-dependency': 3.0.3 + '@smithy/middleware-content-length': 3.0.4 + '@smithy/middleware-endpoint': 3.0.5 + '@smithy/middleware-retry': 3.0.11 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.4 + '@smithy/node-http-handler': 3.1.3 + '@smithy/protocol-http': 4.0.4 + '@smithy/smithy-client': 3.1.9 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.11 + '@smithy/util-defaults-mode-node': 3.0.11 + '@smithy/util-endpoints': 2.0.5 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.3 + '@smithy/util-utf8': 3.0.0 + '@smithy/util-waiter': 3.1.2 + tslib: 2.6.3 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/client-sso-oidc@3.616.0(@aws-sdk/client-sts@3.616.0): + resolution: {integrity: sha512-YY1hpYS/G1uRGjQf88dL8VLHkP/IjGxKeXdhy+JnzMdCkAWl3V9j0fEALw40NZe0x79gr6R2KUOUH/IKYQfUmg==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.616.0 + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sts': 3.616.0 + '@aws-sdk/core': 3.616.0 + '@aws-sdk/credential-provider-node': 3.616.0(@aws-sdk/client-sso-oidc@3.616.0)(@aws-sdk/client-sts@3.616.0) + '@aws-sdk/middleware-host-header': 3.616.0 + '@aws-sdk/middleware-logger': 3.609.0 + '@aws-sdk/middleware-recursion-detection': 3.616.0 + '@aws-sdk/middleware-user-agent': 3.616.0 + '@aws-sdk/region-config-resolver': 3.614.0 + '@aws-sdk/types': 3.609.0 + '@aws-sdk/util-endpoints': 3.614.0 + '@aws-sdk/util-user-agent-browser': 3.609.0 + '@aws-sdk/util-user-agent-node': 3.614.0 + '@smithy/config-resolver': 3.0.5 + '@smithy/core': 2.2.8 + '@smithy/fetch-http-handler': 3.2.2 + '@smithy/hash-node': 3.0.3 + '@smithy/invalid-dependency': 3.0.3 + '@smithy/middleware-content-length': 3.0.4 + '@smithy/middleware-endpoint': 3.0.5 + '@smithy/middleware-retry': 3.0.11 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.4 + '@smithy/node-http-handler': 3.1.3 + '@smithy/protocol-http': 4.0.4 + '@smithy/smithy-client': 3.1.9 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.11 + '@smithy/util-defaults-mode-node': 3.0.11 + '@smithy/util-endpoints': 2.0.5 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.3 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/client-sso@3.616.0: + resolution: {integrity: sha512-hwW0u1f8U4dSloAe61/eupUiGd5Q13B72BuzGxvRk0cIpYX/2m0KBG8DDl7jW1b2QQ+CflTLpG2XUf2+vRJxGA==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.616.0 + '@aws-sdk/middleware-host-header': 3.616.0 + '@aws-sdk/middleware-logger': 3.609.0 + '@aws-sdk/middleware-recursion-detection': 3.616.0 + '@aws-sdk/middleware-user-agent': 3.616.0 + '@aws-sdk/region-config-resolver': 3.614.0 + '@aws-sdk/types': 3.609.0 + '@aws-sdk/util-endpoints': 3.614.0 + '@aws-sdk/util-user-agent-browser': 3.609.0 + '@aws-sdk/util-user-agent-node': 3.614.0 + '@smithy/config-resolver': 3.0.5 + '@smithy/core': 2.2.8 + '@smithy/fetch-http-handler': 3.2.2 + '@smithy/hash-node': 3.0.3 + '@smithy/invalid-dependency': 3.0.3 + '@smithy/middleware-content-length': 3.0.4 + '@smithy/middleware-endpoint': 3.0.5 + '@smithy/middleware-retry': 3.0.11 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.4 + '@smithy/node-http-handler': 3.1.3 + '@smithy/protocol-http': 4.0.4 + '@smithy/smithy-client': 3.1.9 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.11 + '@smithy/util-defaults-mode-node': 3.0.11 + '@smithy/util-endpoints': 2.0.5 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.3 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/client-sts@3.616.0: + resolution: {integrity: sha512-FP7i7hS5FpReqnysQP1ukQF1OUWy8lkomaOnbu15H415YUrfCp947SIx6+BItjmx+esKxPkEjh/fbCVzw2D6hQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/client-sso-oidc': 3.616.0(@aws-sdk/client-sts@3.616.0) + '@aws-sdk/core': 3.616.0 + '@aws-sdk/credential-provider-node': 3.616.0(@aws-sdk/client-sso-oidc@3.616.0)(@aws-sdk/client-sts@3.616.0) + '@aws-sdk/middleware-host-header': 3.616.0 + '@aws-sdk/middleware-logger': 3.609.0 + '@aws-sdk/middleware-recursion-detection': 3.616.0 + '@aws-sdk/middleware-user-agent': 3.616.0 + '@aws-sdk/region-config-resolver': 3.614.0 + '@aws-sdk/types': 3.609.0 + '@aws-sdk/util-endpoints': 3.614.0 + '@aws-sdk/util-user-agent-browser': 3.609.0 + '@aws-sdk/util-user-agent-node': 3.614.0 + '@smithy/config-resolver': 3.0.5 + '@smithy/core': 2.2.8 + '@smithy/fetch-http-handler': 3.2.2 + '@smithy/hash-node': 3.0.3 + '@smithy/invalid-dependency': 3.0.3 + '@smithy/middleware-content-length': 3.0.4 + '@smithy/middleware-endpoint': 3.0.5 + '@smithy/middleware-retry': 3.0.11 + '@smithy/middleware-serde': 3.0.3 + '@smithy/middleware-stack': 3.0.3 + '@smithy/node-config-provider': 3.1.4 + '@smithy/node-http-handler': 3.1.3 + '@smithy/protocol-http': 4.0.4 + '@smithy/smithy-client': 3.1.9 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-base64': 3.0.0 + '@smithy/util-body-length-browser': 3.0.0 + '@smithy/util-body-length-node': 3.0.0 + '@smithy/util-defaults-mode-browser': 3.0.11 + '@smithy/util-defaults-mode-node': 3.0.11 + '@smithy/util-endpoints': 2.0.5 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.3 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + transitivePeerDependencies: + - aws-crt + dev: false + + /@aws-sdk/core@3.616.0: + resolution: {integrity: sha512-O/urkh2kECs/IqZIVZxyeyHZ7OR2ZWhLNK7btsVQBQvJKrEspLrk/Fp20Qfg5JDerQfBN83ZbyRXLJOOucdZpw==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/core': 2.2.8 + '@smithy/protocol-http': 4.0.4 + '@smithy/signature-v4': 4.0.0 + '@smithy/smithy-client': 3.1.9 + '@smithy/types': 3.3.0 + fast-xml-parser: 4.2.5 + tslib: 2.6.3 + dev: false + + /@aws-sdk/credential-provider-env@3.609.0: + resolution: {integrity: sha512-v69ZCWcec2iuV9vLVJMa6fAb5xwkzN4jYIT8yjo2c4Ia/j976Q+TPf35Pnz5My48Xr94EFcaBazrWedF+kwfuQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.609.0 + '@smithy/property-provider': 3.1.3 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@aws-sdk/credential-provider-http@3.616.0: + resolution: {integrity: sha512-1rgCkr7XvEMBl7qWCo5BKu3yAxJs71dRaZ55Xnjte/0ZHH6Oc93ZrHzyYy6UH6t0nZrH+FAuw7Yko2YtDDwDeg==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.609.0 + '@smithy/fetch-http-handler': 3.2.2 + '@smithy/node-http-handler': 3.1.3 + '@smithy/property-provider': 3.1.3 + '@smithy/protocol-http': 4.0.4 + '@smithy/smithy-client': 3.1.9 + '@smithy/types': 3.3.0 + '@smithy/util-stream': 3.1.1 + tslib: 2.6.3 + dev: false + + /@aws-sdk/credential-provider-ini@3.616.0(@aws-sdk/client-sso-oidc@3.616.0)(@aws-sdk/client-sts@3.616.0): + resolution: {integrity: sha512-5gQdMr9cca3xV7FF2SxpxWGH2t6+t4o+XBGiwsHm8muEjf4nUmw7Ij863x25Tjt2viPYV0UStczSb5Sihp7bkA==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.616.0 + dependencies: + '@aws-sdk/client-sts': 3.616.0 + '@aws-sdk/credential-provider-env': 3.609.0 + '@aws-sdk/credential-provider-http': 3.616.0 + '@aws-sdk/credential-provider-process': 3.614.0 + '@aws-sdk/credential-provider-sso': 3.616.0(@aws-sdk/client-sso-oidc@3.616.0) + '@aws-sdk/credential-provider-web-identity': 3.609.0(@aws-sdk/client-sts@3.616.0) + '@aws-sdk/types': 3.609.0 + '@smithy/credential-provider-imds': 3.1.4 + '@smithy/property-provider': 3.1.3 + '@smithy/shared-ini-file-loader': 3.1.4 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + dev: false + + /@aws-sdk/credential-provider-node@3.616.0(@aws-sdk/client-sso-oidc@3.616.0)(@aws-sdk/client-sts@3.616.0): + resolution: {integrity: sha512-Se+u6DAxjDPjKE3vX1X2uxjkWgGq69BTo0uTB0vDUiWwBVgh16s9BsBhSAlKEH1CCbbJHvOg4YdTrzjwzqyClg==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/credential-provider-env': 3.609.0 + '@aws-sdk/credential-provider-http': 3.616.0 + '@aws-sdk/credential-provider-ini': 3.616.0(@aws-sdk/client-sso-oidc@3.616.0)(@aws-sdk/client-sts@3.616.0) + '@aws-sdk/credential-provider-process': 3.614.0 + '@aws-sdk/credential-provider-sso': 3.616.0(@aws-sdk/client-sso-oidc@3.616.0) + '@aws-sdk/credential-provider-web-identity': 3.609.0(@aws-sdk/client-sts@3.616.0) + '@aws-sdk/types': 3.609.0 + '@smithy/credential-provider-imds': 3.1.4 + '@smithy/property-provider': 3.1.3 + '@smithy/shared-ini-file-loader': 3.1.4 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - '@aws-sdk/client-sts' + - aws-crt + dev: false + + /@aws-sdk/credential-provider-process@3.614.0: + resolution: {integrity: sha512-Q0SI0sTRwi8iNODLs5+bbv8vgz8Qy2QdxbCHnPk/6Cx6LMf7i3dqmWquFbspqFRd8QiqxStrblwxrUYZi09tkA==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.609.0 + '@smithy/property-provider': 3.1.3 + '@smithy/shared-ini-file-loader': 3.1.4 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@aws-sdk/credential-provider-sso@3.616.0(@aws-sdk/client-sso-oidc@3.616.0): + resolution: {integrity: sha512-3rsWs9GBi8Z8Gps5ROwqguxtw+J6OIg1vawZMLRNMqqZoBvbOToe9wEnpid8ylU+27+oG8uibJNlNuRyXApUjw==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/client-sso': 3.616.0 + '@aws-sdk/token-providers': 3.614.0(@aws-sdk/client-sso-oidc@3.616.0) + '@aws-sdk/types': 3.609.0 + '@smithy/property-provider': 3.1.3 + '@smithy/shared-ini-file-loader': 3.1.4 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + transitivePeerDependencies: + - '@aws-sdk/client-sso-oidc' + - aws-crt + dev: false + + /@aws-sdk/credential-provider-web-identity@3.609.0(@aws-sdk/client-sts@3.616.0): + resolution: {integrity: sha512-U+PG8NhlYYF45zbr1km3ROtBMYqyyj/oK8NRp++UHHeuavgrP+4wJ4wQnlEaKvJBjevfo3+dlIBcaeQ7NYejWg==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sts': ^3.609.0 + dependencies: + '@aws-sdk/client-sts': 3.616.0 + '@aws-sdk/types': 3.609.0 + '@smithy/property-provider': 3.1.3 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@aws-sdk/middleware-host-header@3.616.0: + resolution: {integrity: sha512-mhNfHuGhCDZwYCABebaOvTgOM44UCZZRq2cBpgPZLVKP0ydAv5aFHXv01goexxXHqgHoEGx0uXWxlw0s2EpFDg==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.609.0 + '@smithy/protocol-http': 4.0.4 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@aws-sdk/middleware-logger@3.609.0: + resolution: {integrity: sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.609.0 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@aws-sdk/middleware-recursion-detection@3.616.0: + resolution: {integrity: sha512-LQKAcrZRrR9EGez4fdCIVjdn0Ot2HMN12ChnoMGEU6oIxnQ2aSC7iASFFCV39IYfeMh7iSCPj7Wopqw8rAouzg==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.609.0 + '@smithy/protocol-http': 4.0.4 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@aws-sdk/middleware-user-agent@3.616.0: + resolution: {integrity: sha512-iMcAb4E+Z3vuEcrDsG6T2OBNiqWAquwahP9qepHqfmnmJqHr1mSHtXDYTGBNid31+621sUQmneUQ+fagpGAe4w==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.609.0 + '@aws-sdk/util-endpoints': 3.614.0 + '@smithy/protocol-http': 4.0.4 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@aws-sdk/region-config-resolver@3.614.0: + resolution: {integrity: sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.609.0 + '@smithy/node-config-provider': 3.1.4 + '@smithy/types': 3.3.0 + '@smithy/util-config-provider': 3.0.0 + '@smithy/util-middleware': 3.0.3 + tslib: 2.6.3 + dev: false + + /@aws-sdk/token-providers@3.614.0(@aws-sdk/client-sso-oidc@3.616.0): + resolution: {integrity: sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@aws-sdk/client-sso-oidc': ^3.614.0 + dependencies: + '@aws-sdk/client-sso-oidc': 3.616.0(@aws-sdk/client-sts@3.616.0) + '@aws-sdk/types': 3.609.0 + '@smithy/property-provider': 3.1.3 + '@smithy/shared-ini-file-loader': 3.1.4 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@aws-sdk/types@3.609.0: + resolution: {integrity: sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@aws-sdk/util-endpoints@3.614.0: + resolution: {integrity: sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==} + engines: {node: '>=16.0.0'} + dependencies: + '@aws-sdk/types': 3.609.0 + '@smithy/types': 3.3.0 + '@smithy/util-endpoints': 2.0.5 + tslib: 2.6.3 + dev: false + + /@aws-sdk/util-locate-window@3.568.0: + resolution: {integrity: sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.6.3 + dev: false + + /@aws-sdk/util-user-agent-browser@3.609.0: + resolution: {integrity: sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==} + dependencies: + '@aws-sdk/types': 3.609.0 + '@smithy/types': 3.3.0 + bowser: 2.11.0 + tslib: 2.6.3 + dev: false + + /@aws-sdk/util-user-agent-node@3.614.0: + resolution: {integrity: sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==} + engines: {node: '>=16.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + dependencies: + '@aws-sdk/types': 3.609.0 + '@smithy/node-config-provider': 3.1.4 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + /@babel/code-frame@7.24.7: resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} engines: {node: '>=6.9.0'} @@ -3298,6 +3768,401 @@ packages: '@sinonjs/commons': 3.0.1 dev: true + /@smithy/abort-controller@3.1.1: + resolution: {integrity: sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/config-resolver@3.0.5: + resolution: {integrity: sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/node-config-provider': 3.1.4 + '@smithy/types': 3.3.0 + '@smithy/util-config-provider': 3.0.0 + '@smithy/util-middleware': 3.0.3 + tslib: 2.6.3 + dev: false + + /@smithy/core@2.2.8: + resolution: {integrity: sha512-1Y0XX0Ucyg0LWTfTVLWpmvSRtFRniykUl3dQ0os1sTd03mKDudR6mVyX+2ak1phwPXx2aEWMAAdW52JNi0mc3A==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/middleware-endpoint': 3.0.5 + '@smithy/middleware-retry': 3.0.11 + '@smithy/middleware-serde': 3.0.3 + '@smithy/protocol-http': 4.0.4 + '@smithy/smithy-client': 3.1.9 + '@smithy/types': 3.3.0 + '@smithy/util-middleware': 3.0.3 + tslib: 2.6.3 + dev: false + + /@smithy/credential-provider-imds@3.1.4: + resolution: {integrity: sha512-NKyH01m97Xa5xf3pB2QOF3lnuE8RIK0hTVNU5zvZAwZU8uspYO4DHQVlK+Y5gwSrujTfHvbfd1D9UFJAc0iYKQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/node-config-provider': 3.1.4 + '@smithy/property-provider': 3.1.3 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + tslib: 2.6.3 + dev: false + + /@smithy/fetch-http-handler@3.2.2: + resolution: {integrity: sha512-3LaWlBZObyGrOOd7e5MlacnAKEwFBmAeiW/TOj2eR9475Vnq30uS2510+tnKbxrGjROfNdOhQqGo5j3sqLT6bA==} + dependencies: + '@smithy/protocol-http': 4.0.4 + '@smithy/querystring-builder': 3.0.3 + '@smithy/types': 3.3.0 + '@smithy/util-base64': 3.0.0 + tslib: 2.6.3 + dev: false + + /@smithy/hash-node@3.0.3: + resolution: {integrity: sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.3.0 + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + dev: false + + /@smithy/invalid-dependency@3.0.3: + resolution: {integrity: sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==} + dependencies: + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/is-array-buffer@2.2.0: + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + dependencies: + tslib: 2.6.3 + dev: false + + /@smithy/is-array-buffer@3.0.0: + resolution: {integrity: sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.6.3 + dev: false + + /@smithy/middleware-content-length@3.0.4: + resolution: {integrity: sha512-wySGje/KfhsnF8YSh9hP16pZcl3C+X6zRsvSfItQGvCyte92LliilU3SD0nR7kTlxnAJwxY8vE/k4Eoezj847Q==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/protocol-http': 4.0.4 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/middleware-endpoint@3.0.5: + resolution: {integrity: sha512-V4acqqrh5tDxUEGVTOgf2lYMZqPQsoGntCrjrJZEeBzEzDry2d2vcI1QCXhGltXPPY+BMc6eksZMguA9fIY8vA==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/middleware-serde': 3.0.3 + '@smithy/node-config-provider': 3.1.4 + '@smithy/shared-ini-file-loader': 3.1.4 + '@smithy/types': 3.3.0 + '@smithy/url-parser': 3.0.3 + '@smithy/util-middleware': 3.0.3 + tslib: 2.6.3 + dev: false + + /@smithy/middleware-retry@3.0.11: + resolution: {integrity: sha512-/TIRWmhwMpv99JCGuMhJPnH7ggk/Lah7s/uNDyr7faF02BxNsyD/fz9Tw7pgCf9tYOKgjimm2Qml1Aq1pbkt6g==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/node-config-provider': 3.1.4 + '@smithy/protocol-http': 4.0.4 + '@smithy/service-error-classification': 3.0.3 + '@smithy/smithy-client': 3.1.9 + '@smithy/types': 3.3.0 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-retry': 3.0.3 + tslib: 2.6.3 + uuid: 9.0.1 + dev: false + + /@smithy/middleware-serde@3.0.3: + resolution: {integrity: sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/middleware-stack@3.0.3: + resolution: {integrity: sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/node-config-provider@3.1.4: + resolution: {integrity: sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/property-provider': 3.1.3 + '@smithy/shared-ini-file-loader': 3.1.4 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/node-http-handler@3.1.3: + resolution: {integrity: sha512-UiKZm8KHb/JeOPzHZtRUfyaRDO1KPKPpsd7iplhiwVGOeVdkiVJ5bVe7+NhWREMOKomrDIDdSZyglvMothLg0Q==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/abort-controller': 3.1.1 + '@smithy/protocol-http': 4.0.4 + '@smithy/querystring-builder': 3.0.3 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/property-provider@3.1.3: + resolution: {integrity: sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/protocol-http@4.0.4: + resolution: {integrity: sha512-fAA2O4EFyNRyYdFLVIv5xMMeRb+3fRKc/Rt2flh5k831vLvUmNFXcydeg7V3UeEhGURJI4c1asmGJBjvmF6j8Q==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/querystring-builder@3.0.3: + resolution: {integrity: sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.3.0 + '@smithy/util-uri-escape': 3.0.0 + tslib: 2.6.3 + dev: false + + /@smithy/querystring-parser@3.0.3: + resolution: {integrity: sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/service-error-classification@3.0.3: + resolution: {integrity: sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.3.0 + dev: false + + /@smithy/shared-ini-file-loader@3.1.4: + resolution: {integrity: sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/signature-v4@4.0.0: + resolution: {integrity: sha512-ervYjQ+ZvmNG51Ui77IOTPri7nOyo8Kembzt9uwwlmtXJPmFXvslOahbA1blvAVs7G0KlYMiOBog1rAt7RVXxg==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/is-array-buffer': 3.0.0 + '@smithy/types': 3.3.0 + '@smithy/util-hex-encoding': 3.0.0 + '@smithy/util-middleware': 3.0.3 + '@smithy/util-uri-escape': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + dev: false + + /@smithy/smithy-client@3.1.9: + resolution: {integrity: sha512-My2RaInZ4gSwJUPMaiLR/Nk82+c4LlvqpXA+n7lonGYgCZq23Tg+/xFhgmiejJ6XPElYJysTPyV90vKyp17+1g==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/middleware-endpoint': 3.0.5 + '@smithy/middleware-stack': 3.0.3 + '@smithy/protocol-http': 4.0.4 + '@smithy/types': 3.3.0 + '@smithy/util-stream': 3.1.1 + tslib: 2.6.3 + dev: false + + /@smithy/types@3.3.0: + resolution: {integrity: sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.6.3 + dev: false + + /@smithy/url-parser@3.0.3: + resolution: {integrity: sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==} + dependencies: + '@smithy/querystring-parser': 3.0.3 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/util-base64@3.0.0: + resolution: {integrity: sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + dev: false + + /@smithy/util-body-length-browser@3.0.0: + resolution: {integrity: sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==} + dependencies: + tslib: 2.6.3 + dev: false + + /@smithy/util-body-length-node@3.0.0: + resolution: {integrity: sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.6.3 + dev: false + + /@smithy/util-buffer-from@2.2.0: + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.6.3 + dev: false + + /@smithy/util-buffer-from@3.0.0: + resolution: {integrity: sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/is-array-buffer': 3.0.0 + tslib: 2.6.3 + dev: false + + /@smithy/util-config-provider@3.0.0: + resolution: {integrity: sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.6.3 + dev: false + + /@smithy/util-defaults-mode-browser@3.0.11: + resolution: {integrity: sha512-O3s9DGb3bmRvEKmT8RwvSWK4A9r6svfd+MnJB+UMi9ZcCkAnoRtliulOnGF0qCMkKF9mwk2tkopBBstalPY/vg==} + engines: {node: '>= 10.0.0'} + dependencies: + '@smithy/property-provider': 3.1.3 + '@smithy/smithy-client': 3.1.9 + '@smithy/types': 3.3.0 + bowser: 2.11.0 + tslib: 2.6.3 + dev: false + + /@smithy/util-defaults-mode-node@3.0.11: + resolution: {integrity: sha512-qd4a9qtyOa/WY14aHHOkMafhh9z8D2QTwlcBoXMTPnEwtcY+xpe1JyFm9vya7VsB8hHsfn3XodEtwqREiu4ygQ==} + engines: {node: '>= 10.0.0'} + dependencies: + '@smithy/config-resolver': 3.0.5 + '@smithy/credential-provider-imds': 3.1.4 + '@smithy/node-config-provider': 3.1.4 + '@smithy/property-provider': 3.1.3 + '@smithy/smithy-client': 3.1.9 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/util-endpoints@2.0.5: + resolution: {integrity: sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/node-config-provider': 3.1.4 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/util-hex-encoding@3.0.0: + resolution: {integrity: sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.6.3 + dev: false + + /@smithy/util-middleware@3.0.3: + resolution: {integrity: sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/util-retry@3.0.3: + resolution: {integrity: sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/service-error-classification': 3.0.3 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + + /@smithy/util-stream@3.1.1: + resolution: {integrity: sha512-EhRnVvl3AhoHAT2rGQ5o+oSDRM/BUSMPLZZdRJZLcNVUsFAjOs4vHaPdNQivTSzRcFxf5DA4gtO46WWU2zimaw==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/fetch-http-handler': 3.2.2 + '@smithy/node-http-handler': 3.1.3 + '@smithy/types': 3.3.0 + '@smithy/util-base64': 3.0.0 + '@smithy/util-buffer-from': 3.0.0 + '@smithy/util-hex-encoding': 3.0.0 + '@smithy/util-utf8': 3.0.0 + tslib: 2.6.3 + dev: false + + /@smithy/util-uri-escape@3.0.0: + resolution: {integrity: sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==} + engines: {node: '>=16.0.0'} + dependencies: + tslib: 2.6.3 + dev: false + + /@smithy/util-utf8@2.3.0: + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.6.3 + dev: false + + /@smithy/util-utf8@3.0.0: + resolution: {integrity: sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/util-buffer-from': 3.0.0 + tslib: 2.6.3 + dev: false + + /@smithy/util-waiter@3.1.2: + resolution: {integrity: sha512-4pP0EV3iTsexDx+8PPGAKCQpd/6hsQBaQhqWzU4hqKPHN5epPsxKbvUTIiYIHTxaKt6/kEaqPBpu/ufvfbrRzw==} + engines: {node: '>=16.0.0'} + dependencies: + '@smithy/abort-controller': 3.1.1 + '@smithy/types': 3.3.0 + tslib: 2.6.3 + dev: false + /@tanstack/query-core@5.40.0: resolution: {integrity: sha512-eD8K8jsOIq0Z5u/QbvOmfvKKE/XC39jA7yv4hgpl/1SRiU+J8QCIwgM/mEHuunQsL87dcvnHqSVLmf9pD4CiaA==} dev: false @@ -4877,6 +5742,10 @@ packages: transitivePeerDependencies: - supports-color + /bowser@2.11.0: + resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + dev: false + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -6788,6 +7657,13 @@ packages: /fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + /fast-xml-parser@4.2.5: + resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==} + hasBin: true + dependencies: + strnum: 1.0.5 + dev: false + /fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} dependencies: @@ -11338,6 +12214,10 @@ packages: engines: {node: '>=8'} dev: true + /strnum@1.0.5: + resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + dev: false + /style-to-object@0.4.4: resolution: {integrity: sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==} dependencies: From 90cd7cef0a19d9b162c5286ee1872dd444891660 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 23 Jul 2024 17:00:12 +0200 Subject: [PATCH 08/23] feat: add react email templates --- .../common_nestjs_remix/apps/api/package.json | 1 + .../packages/email-templates/index.ts | 2 + .../packages/email-templates/package.json | 31 + .../packages/email-templates/plugin.js | 101 + .../email-templates/src/email-content.ts | 4 + .../email-templates/src/email-factory.ts | 26 + .../src/templates/WelcomeEmail.tsx | 21 + .../packages/email-templates/tsconfig.json | 16 + .../packages/email-templates/tsup.config.ts | 10 + .../packages/email-templates/turbo.json | 12 + examples/common_nestjs_remix/pnpm-lock.yaml | 2467 +++++++++++++++-- 11 files changed, 2406 insertions(+), 285 deletions(-) create mode 100644 examples/common_nestjs_remix/packages/email-templates/index.ts create mode 100644 examples/common_nestjs_remix/packages/email-templates/package.json create mode 100644 examples/common_nestjs_remix/packages/email-templates/plugin.js create mode 100644 examples/common_nestjs_remix/packages/email-templates/src/email-content.ts create mode 100644 examples/common_nestjs_remix/packages/email-templates/src/email-factory.ts create mode 100644 examples/common_nestjs_remix/packages/email-templates/src/templates/WelcomeEmail.tsx create mode 100644 examples/common_nestjs_remix/packages/email-templates/tsconfig.json create mode 100644 examples/common_nestjs_remix/packages/email-templates/tsup.config.ts create mode 100644 examples/common_nestjs_remix/packages/email-templates/turbo.json diff --git a/examples/common_nestjs_remix/apps/api/package.json b/examples/common_nestjs_remix/apps/api/package.json index 5d0b224..c20fa09 100644 --- a/examples/common_nestjs_remix/apps/api/package.json +++ b/examples/common_nestjs_remix/apps/api/package.json @@ -24,6 +24,7 @@ "db:generate": "drizzle-kit generate" }, "dependencies": { + "@repo/email-templates": "workspace:*", "@aws-sdk/client-ses": "^3.616.0", "@knaadh/nestjs-drizzle-postgres": "^1.0.0", "@nestjs/common": "^10.0.0", diff --git a/examples/common_nestjs_remix/packages/email-templates/index.ts b/examples/common_nestjs_remix/packages/email-templates/index.ts new file mode 100644 index 0000000..db96f05 --- /dev/null +++ b/examples/common_nestjs_remix/packages/email-templates/index.ts @@ -0,0 +1,2 @@ +export { emailFactory } from "./src/email-factory"; +export { WelcomeEmail } from "./src/templates/WelcomeEmail"; diff --git a/examples/common_nestjs_remix/packages/email-templates/package.json b/examples/common_nestjs_remix/packages/email-templates/package.json new file mode 100644 index 0000000..64042cc --- /dev/null +++ b/examples/common_nestjs_remix/packages/email-templates/package.json @@ -0,0 +1,31 @@ +{ + "name": "@repo/email-templates", + "version": "0.1.0", + "description": "Email templates", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "private": true, + "scripts": { + "build": "tsup", + "clean": "rm -rf dist", + "dev": "email dev -p 3001 --dir ./src/templates", + "export": "email export --dir ./src/templates" + }, + "dependencies": { + "@react-email/components": "^0.0.17", + "react": "^18.2.0", + "react-email": "^2.1.4" + }, + "devDependencies": { + "@babel/generator": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7", + "@repo/typescript-config": "*", + "@types/react": "^18.2.61", + "tsup": "^8.0.2", + "typescript": "^5.4.5" + } +} diff --git a/examples/common_nestjs_remix/packages/email-templates/plugin.js b/examples/common_nestjs_remix/packages/email-templates/plugin.js new file mode 100644 index 0000000..bfdb4b1 --- /dev/null +++ b/examples/common_nestjs_remix/packages/email-templates/plugin.js @@ -0,0 +1,101 @@ +import path from "path"; +import fs from "fs"; +import * as parser from "@babel/parser"; +import * as traverse from "@babel/traverse"; // Correct import +import * as generate from "@babel/generator"; +import template from "@babel/template"; +import { + importDeclaration, + importDefaultSpecifier, + exportNamedDeclaration, + variableDeclaration, + variableDeclarator, + callExpression, + identifier, + stringLiteral, // Import stringLiteral +} from "@babel/types"; + +module.exports = function myTsupPlugin() { + const xd = template.default(`import UserDialog from "./user-dialog";`, { + sourceType: "module", + }); + + const xdd = generate.default.default( + xd, + { + /* options */ + }, + xd.code, + ); + + console.log(xdd.code); + + // console.log( + // "myTsupPlugin", + // ); + return { + name: "dynamic-template-exports", + buildEnd: () => { + const templatesDir = path.resolve(__dirname, "src", "templates"); // Adjust path if needed + const indexFilePath = path.resolve(__dirname, "index.ts"); + + const templateFiles = fs + .readdirSync(templatesDir) + .filter((file) => file.endsWith(".tsx") && file !== "index.ts"); + + const ast = parser.parse(fs.readFileSync(indexFilePath, "utf-8"), { + sourceType: "module", + plugins: ["typescript"], // Ensure TypeScript parsing + }); + + traverse.default.default(ast, { + Program(path) { + const body = path.get("body"); + + templateFiles.forEach((templateFile) => { + const templateName = templateFile.replace(".tsx", ""); + const variableName = + templateName.charAt(0).toUpperCase() + templateName.slice(1); + + // Create the import declaration AST node (Corrected) + const importSpecifier = importDefaultSpecifier( + identifier(`${variableName}Template`), + ); + const importDeclarationNode = importDeclaration( + [importSpecifier], + stringLiteral(`./templates/${templateName}`), // Use stringLiteral here + ); + + // Create the export declaration AST node + const exportDeclarationNode = exportNamedDeclaration( + variableDeclaration("const", [ + variableDeclarator( + identifier(variableName), + callExpression(identifier("emailTemplateFactory"), [ + identifier(`${variableName}Template`), + ]), + ), + ]), + [], + ); + + body.push(importDeclarationNode); + body.push(exportDeclarationNode); + }); + }, + }); + + console.log(ast); + + const output = generate.default.default( + ast, + { + /* options */ + }, + ast.code, + ); + + fs.writeFileSync(indexFilePath, output.code, "utf-8"); + }, + }; +}; diff --git a/examples/common_nestjs_remix/packages/email-templates/src/email-content.ts b/examples/common_nestjs_remix/packages/email-templates/src/email-content.ts new file mode 100644 index 0000000..4922cb2 --- /dev/null +++ b/examples/common_nestjs_remix/packages/email-templates/src/email-content.ts @@ -0,0 +1,4 @@ +export interface EmailContent { + text: string; + html: string; +} diff --git a/examples/common_nestjs_remix/packages/email-templates/src/email-factory.ts b/examples/common_nestjs_remix/packages/email-templates/src/email-factory.ts new file mode 100644 index 0000000..0164826 --- /dev/null +++ b/examples/common_nestjs_remix/packages/email-templates/src/email-factory.ts @@ -0,0 +1,26 @@ +import { render } from "@react-email/components"; +import { EmailContent } from "./email-content"; + +export function emailFactory( + template: (...args: T) => Parameters[0], +): new (...args: T) => EmailContent { + return class implements EmailContent { + private readonly args: T; + + constructor(...args: T) { + this.args = args; + } + + get props(): T { + return this.args; + } + + get text(): string { + return render(template(...this.props), { plainText: true }); + } + + get html(): string { + return render(template(...this.props)); + } + }; +} diff --git a/examples/common_nestjs_remix/packages/email-templates/src/templates/WelcomeEmail.tsx b/examples/common_nestjs_remix/packages/email-templates/src/templates/WelcomeEmail.tsx new file mode 100644 index 0000000..10a5ad4 --- /dev/null +++ b/examples/common_nestjs_remix/packages/email-templates/src/templates/WelcomeEmail.tsx @@ -0,0 +1,21 @@ +import { Button, Html } from "@react-email/components"; + +export type WelcomeEmailProps = { + email: string; + name: string; +}; + +export const WelcomeEmail = ({ email, name }: WelcomeEmailProps) => { + return ( + + + + ); +}; + +export default WelcomeEmail; diff --git a/examples/common_nestjs_remix/packages/email-templates/tsconfig.json b/examples/common_nestjs_remix/packages/email-templates/tsconfig.json new file mode 100644 index 0000000..b521138 --- /dev/null +++ b/examples/common_nestjs_remix/packages/email-templates/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "@repo/typescript-config/base.json", + "include": [ + "." + ], + "exclude": [ + "dist", + "build", + "node_modules" + ], + "compilerOptions": { + "strict": true, + "jsx": "react-jsx", + "allowJs": true + } +} diff --git a/examples/common_nestjs_remix/packages/email-templates/tsup.config.ts b/examples/common_nestjs_remix/packages/email-templates/tsup.config.ts new file mode 100644 index 0000000..38af578 --- /dev/null +++ b/examples/common_nestjs_remix/packages/email-templates/tsup.config.ts @@ -0,0 +1,10 @@ +import { defineConfig, type Options } from "tsup"; +const plugin = require("./plugin"); + +export default defineConfig((options: Options) => ({ + entry: ["./index.ts"], + format: ["cjs", "esm"], + dts: true, + plugins: [plugin()], + ...options, +})); diff --git a/examples/common_nestjs_remix/packages/email-templates/turbo.json b/examples/common_nestjs_remix/packages/email-templates/turbo.json new file mode 100644 index 0000000..52e8c76 --- /dev/null +++ b/examples/common_nestjs_remix/packages/email-templates/turbo.json @@ -0,0 +1,12 @@ +{ + "extends": [ + "//" + ], + "tasks": { + "build": { + "outputs": [ + "dist/**" + ] + } + } +} diff --git a/examples/common_nestjs_remix/pnpm-lock.yaml b/examples/common_nestjs_remix/pnpm-lock.yaml index f55eba1..48d1d4a 100644 --- a/examples/common_nestjs_remix/pnpm-lock.yaml +++ b/examples/common_nestjs_remix/pnpm-lock.yaml @@ -53,6 +53,9 @@ importers: '@nestjs/swagger': specifier: ^7.4.0 version: 7.4.0(@nestjs/common@10.0.0)(@nestjs/core@10.0.0)(reflect-metadata@0.2.0) + '@repo/email-templates': + specifier: workspace:* + version: link:../../packages/email-templates '@sinclair/typebox': specifier: ^0.32.34 version: 0.32.34 @@ -373,6 +376,46 @@ importers: specifier: ^4.2.1 version: 4.2.1(typescript@5.3.3)(vite@5.1.0) + packages/email-templates: + dependencies: + '@react-email/components': + specifier: ^0.0.17 + version: 0.0.17(@types/react@18.2.61)(react@18.3.1) + react: + specifier: ^18.2.0 + version: 18.3.1 + react-email: + specifier: ^2.1.4 + version: 2.1.4(eslint@8.57.0) + devDependencies: + '@babel/generator': + specifier: ^7.24.7 + version: 7.24.7 + '@babel/parser': + specifier: ^7.24.7 + version: 7.24.7 + '@babel/template': + specifier: ^7.24.7 + version: 7.24.7 + '@babel/traverse': + specifier: ^7.24.7 + version: 7.24.7 + '@babel/types': + specifier: ^7.24.7 + version: 7.24.7 + '@repo/typescript-config': + specifier: '*' + version: link:../typescript-config + '@types/react': + specifier: ^18.2.61 + version: 18.2.61 + tsup: + specifier: ^8.0.2 + version: 8.0.2(postcss@8.4.38)(typescript@5.5.3) + typescript: + specifier: ^5.4.5 + version: 5.5.3 + packages/eslint-config: devDependencies: '@typescript-eslint/eslint-plugin': @@ -441,7 +484,6 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - dev: true /@angular-devkit/core@16.1.0(chokidar@3.5.3): resolution: {integrity: sha512-mrWpuDvttmhrCGcLc68RIXKtTzUhkBTsE5ZZFZNO1+FSC+vO/ZpyCpPd6C+6coM68NfXYjHlms5XF6KbxeGn/Q==} @@ -961,12 +1003,33 @@ packages: dependencies: '@babel/highlight': 7.24.7 picocolors: 1.0.1 - dev: true /@babel/compat-data@7.24.7: resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==} engines: {node: '>=6.9.0'} - dev: true + + /@babel/core@7.24.5: + resolution: {integrity: sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.5) + '@babel/helpers': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/template': 7.24.7 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + convert-source-map: 2.0.0 + debug: 4.3.5 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: false /@babel/core@7.24.7: resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==} @@ -999,7 +1062,6 @@ packages: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 - dev: true /@babel/helper-annotate-as-pure@7.24.7: resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==} @@ -1017,7 +1079,6 @@ packages: browserslist: 4.23.1 lru-cache: 5.1.1 semver: 6.3.1 - dev: true /@babel/helper-create-class-features-plugin@7.24.7(@babel/core@7.24.7): resolution: {integrity: sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==} @@ -1044,7 +1105,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.7 - dev: true /@babel/helper-function-name@7.24.7: resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} @@ -1052,14 +1112,12 @@ packages: dependencies: '@babel/template': 7.24.7 '@babel/types': 7.24.7 - dev: true /@babel/helper-hoist-variables@7.24.7: resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.7 - dev: true /@babel/helper-member-expression-to-functions@7.24.7: resolution: {integrity: sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==} @@ -1079,7 +1137,22 @@ packages: '@babel/types': 7.24.7 transitivePeerDependencies: - supports-color - dev: true + + /@babel/helper-module-transforms@7.24.7(@babel/core@7.24.5): + resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + transitivePeerDependencies: + - supports-color + dev: false /@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7): resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==} @@ -1131,7 +1204,6 @@ packages: '@babel/types': 7.24.7 transitivePeerDependencies: - supports-color - dev: true /@babel/helper-skip-transparent-expression-wrappers@7.24.7: resolution: {integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==} @@ -1148,22 +1220,18 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.24.7 - dev: true /@babel/helper-string-parser@7.24.7: resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-validator-identifier@7.24.7: resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-validator-option@7.24.7: resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==} engines: {node: '>=6.9.0'} - dev: true /@babel/helpers@7.24.7: resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==} @@ -1171,7 +1239,6 @@ packages: dependencies: '@babel/template': 7.24.7 '@babel/types': 7.24.7 - dev: true /@babel/highlight@7.24.7: resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} @@ -1181,7 +1248,14 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.0.1 - dev: true + + /@babel/parser@7.24.5: + resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.24.7 + dev: false /@babel/parser@7.24.7: resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} @@ -1189,7 +1263,6 @@ packages: hasBin: true dependencies: '@babel/types': 7.24.7 - dev: true /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.7): resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} @@ -1388,7 +1461,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 - dev: true /@babel/template@7.24.7: resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==} @@ -1397,7 +1469,6 @@ packages: '@babel/code-frame': 7.24.7 '@babel/parser': 7.24.7 '@babel/types': 7.24.7 - dev: true /@babel/traverse@7.24.7: resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==} @@ -1415,7 +1486,6 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color - dev: true /@babel/types@7.24.7: resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} @@ -1424,7 +1494,6 @@ packages: '@babel/helper-string-parser': 7.24.7 '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 - dev: true /@balena/dockerignore@1.0.2: resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} @@ -1452,6 +1521,20 @@ packages: resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} dev: true + /@emotion/is-prop-valid@0.8.8: + resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} + requiresBuild: true + dependencies: + '@emotion/memoize': 0.7.4 + dev: false + optional: true + + /@emotion/memoize@0.7.4: + resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==} + requiresBuild: true + dev: false + optional: true + /@esbuild-kit/core-utils@3.3.2: resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} dependencies: @@ -1466,6 +1549,15 @@ packages: get-tsconfig: 4.7.5 dev: false + /@esbuild/aix-ppc64@0.19.11: + resolution: {integrity: sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: false + optional: true + /@esbuild/aix-ppc64@0.19.12: resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} engines: {node: '>=12'} @@ -1492,6 +1584,15 @@ packages: dev: false optional: true + /@esbuild/android-arm64@0.19.11: + resolution: {integrity: sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + /@esbuild/android-arm64@0.19.12: resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} engines: {node: '>=12'} @@ -1518,6 +1619,15 @@ packages: dev: false optional: true + /@esbuild/android-arm@0.19.11: + resolution: {integrity: sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false + optional: true + /@esbuild/android-arm@0.19.12: resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} engines: {node: '>=12'} @@ -1544,6 +1654,15 @@ packages: dev: false optional: true + /@esbuild/android-x64@0.19.11: + resolution: {integrity: sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: false + optional: true + /@esbuild/android-x64@0.19.12: resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} engines: {node: '>=12'} @@ -1570,6 +1689,15 @@ packages: dev: false optional: true + /@esbuild/darwin-arm64@0.19.11: + resolution: {integrity: sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@esbuild/darwin-arm64@0.19.12: resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} engines: {node: '>=12'} @@ -1596,6 +1724,15 @@ packages: dev: false optional: true + /@esbuild/darwin-x64@0.19.11: + resolution: {integrity: sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@esbuild/darwin-x64@0.19.12: resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} engines: {node: '>=12'} @@ -1622,6 +1759,15 @@ packages: dev: false optional: true + /@esbuild/freebsd-arm64@0.19.11: + resolution: {integrity: sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/freebsd-arm64@0.19.12: resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} engines: {node: '>=12'} @@ -1648,6 +1794,15 @@ packages: dev: false optional: true + /@esbuild/freebsd-x64@0.19.11: + resolution: {integrity: sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/freebsd-x64@0.19.12: resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} engines: {node: '>=12'} @@ -1674,6 +1829,15 @@ packages: dev: false optional: true + /@esbuild/linux-arm64@0.19.11: + resolution: {integrity: sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-arm64@0.19.12: resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} engines: {node: '>=12'} @@ -1700,6 +1864,15 @@ packages: dev: false optional: true + /@esbuild/linux-arm@0.19.11: + resolution: {integrity: sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-arm@0.19.12: resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} engines: {node: '>=12'} @@ -1726,6 +1899,15 @@ packages: dev: false optional: true + /@esbuild/linux-ia32@0.19.11: + resolution: {integrity: sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-ia32@0.19.12: resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} engines: {node: '>=12'} @@ -1752,6 +1934,15 @@ packages: dev: false optional: true + /@esbuild/linux-loong64@0.19.11: + resolution: {integrity: sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-loong64@0.19.12: resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} engines: {node: '>=12'} @@ -1778,6 +1969,15 @@ packages: dev: false optional: true + /@esbuild/linux-mips64el@0.19.11: + resolution: {integrity: sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-mips64el@0.19.12: resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} engines: {node: '>=12'} @@ -1804,6 +2004,15 @@ packages: dev: false optional: true + /@esbuild/linux-ppc64@0.19.11: + resolution: {integrity: sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-ppc64@0.19.12: resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} engines: {node: '>=12'} @@ -1830,6 +2039,15 @@ packages: dev: false optional: true + /@esbuild/linux-riscv64@0.19.11: + resolution: {integrity: sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-riscv64@0.19.12: resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} engines: {node: '>=12'} @@ -1856,6 +2074,15 @@ packages: dev: false optional: true + /@esbuild/linux-s390x@0.19.11: + resolution: {integrity: sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-s390x@0.19.12: resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} engines: {node: '>=12'} @@ -1882,6 +2109,15 @@ packages: dev: false optional: true + /@esbuild/linux-x64@0.19.11: + resolution: {integrity: sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-x64@0.19.12: resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} engines: {node: '>=12'} @@ -1908,6 +2144,15 @@ packages: dev: false optional: true + /@esbuild/netbsd-x64@0.19.11: + resolution: {integrity: sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/netbsd-x64@0.19.12: resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} engines: {node: '>=12'} @@ -1934,6 +2179,15 @@ packages: dev: false optional: true + /@esbuild/openbsd-x64@0.19.11: + resolution: {integrity: sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/openbsd-x64@0.19.12: resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} engines: {node: '>=12'} @@ -1960,6 +2214,15 @@ packages: dev: false optional: true + /@esbuild/sunos-x64@0.19.11: + resolution: {integrity: sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: false + optional: true + /@esbuild/sunos-x64@0.19.12: resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} engines: {node: '>=12'} @@ -1986,6 +2249,15 @@ packages: dev: false optional: true + /@esbuild/win32-arm64@0.19.11: + resolution: {integrity: sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@esbuild/win32-arm64@0.19.12: resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} engines: {node: '>=12'} @@ -2012,6 +2284,15 @@ packages: dev: false optional: true + /@esbuild/win32-ia32@0.19.11: + resolution: {integrity: sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@esbuild/win32-ia32@0.19.12: resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} engines: {node: '>=12'} @@ -2038,6 +2319,15 @@ packages: dev: false optional: true + /@esbuild/win32-x64@0.19.11: + resolution: {integrity: sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@esbuild/win32-x64@0.19.12: resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} engines: {node: '>=12'} @@ -2054,12 +2344,10 @@ packages: dependencies: eslint: 8.57.0 eslint-visitor-keys: 3.4.3 - dev: true /@eslint-community/regexpp@4.11.0: resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true /@eslint/eslintrc@2.1.4: resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} @@ -2076,12 +2364,10 @@ packages: strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - dev: true /@eslint/js@8.57.0: resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true /@exodus/schemasafe@1.3.0: resolution: {integrity: sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==} @@ -2138,17 +2424,14 @@ packages: minimatch: 3.1.2 transitivePeerDependencies: - supports-color - dev: true /@humanwhocodes/module-importer@1.0.1: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - dev: true /@humanwhocodes/object-schema@2.0.3: resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead - dev: true /@isaacs/cliui@8.0.2: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -2412,7 +2695,6 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - dev: true /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} @@ -2746,10 +3028,95 @@ packages: tslib: 2.5.3 dev: true - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - dependencies: + /@next/env@14.1.4: + resolution: {integrity: sha512-e7X7bbn3Z6DWnDi75UWn+REgAbLEqxI8Tq2pkFOFAMpWAWApz/YCUhtWMWn410h8Q2fYiYL7Yg5OlxMOCfFjJQ==} + dev: false + + /@next/swc-darwin-arm64@14.1.4: + resolution: {integrity: sha512-ubmUkbmW65nIAOmoxT1IROZdmmJMmdYvXIe8211send9ZYJu+SqxSnJM4TrPj9wmL6g9Atvj0S/2cFmMSS99jg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@next/swc-darwin-x64@14.1.4: + resolution: {integrity: sha512-b0Xo1ELj3u7IkZWAKcJPJEhBop117U78l70nfoQGo4xUSvv0PJSTaV4U9xQBLvZlnjsYkc8RwQN1HoH/oQmLlQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@next/swc-linux-arm64-gnu@14.1.4: + resolution: {integrity: sha512-457G0hcLrdYA/u1O2XkRMsDKId5VKe3uKPvrKVOyuARa6nXrdhJOOYU9hkKKyQTMru1B8qEP78IAhf/1XnVqKA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@next/swc-linux-arm64-musl@14.1.4: + resolution: {integrity: sha512-l/kMG+z6MB+fKA9KdtyprkTQ1ihlJcBh66cf0HvqGP+rXBbOXX0dpJatjZbHeunvEHoBBS69GYQG5ry78JMy3g==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@next/swc-linux-x64-gnu@14.1.4: + resolution: {integrity: sha512-BapIFZ3ZRnvQ1uWbmqEGJuPT9cgLwvKtxhK/L2t4QYO7l+/DxXuIGjvp1x8rvfa/x1FFSsipERZK70pewbtJtw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@next/swc-linux-x64-musl@14.1.4: + resolution: {integrity: sha512-mqVxTwk4XuBl49qn2A5UmzFImoL1iLm0KQQwtdRJRKl21ylQwwGCxJtIYo2rbfkZHoSKlh/YgztY0qH3wG1xIg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@next/swc-win32-arm64-msvc@14.1.4: + resolution: {integrity: sha512-xzxF4ErcumXjO2Pvg/wVGrtr9QQJLk3IyQX1ddAC/fi6/5jZCZ9xpuL9Tzc4KPWMFq8GGWFVDMshZOdHGdkvag==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@next/swc-win32-ia32-msvc@14.1.4: + resolution: {integrity: sha512-WZiz8OdbkpRw6/IU/lredZWKKZopUMhcI2F+XiMAcPja0uZYdMTZQRoQ0WZcvinn9xZAidimE7tN9W5v9Yyfyw==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@next/swc-win32-x64-msvc@14.1.4: + resolution: {integrity: sha512-4Rto21sPfw555sZ/XNLqfxDUNeLhNYGO2dlPqsnuCg8N8a2a9u1ltqBOPQ4vj1Gf7eJC0W2hHG2eYUHuiXgY2w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 @@ -2820,6 +3187,10 @@ packages: transitivePeerDependencies: - encoding + /@one-ini/wasm@0.1.1: + resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + dev: false + /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -2831,10 +3202,41 @@ packages: engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} dev: true + /@radix-ui/colors@1.0.1: + resolution: {integrity: sha512-xySw8f0ZVsAEP+e7iLl3EvcBXX7gsIlC1Zso/sPBW9gIWerBTgz6axrjU+MZ39wD+WFi5h5zdWpsg3+hwt2Qsg==} + dev: false + + /@radix-ui/primitive@1.0.1: + resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} + dependencies: + '@babel/runtime': 7.24.7 + dev: false + /@radix-ui/primitive@1.1.0: resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==} dev: false + /@radix-ui/react-arrow@1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /@radix-ui/react-arrow@1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==} peerDependencies: @@ -2878,6 +3280,58 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@radix-ui/react-collapsible@1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /@radix-ui/react-collection@1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==} peerDependencies: @@ -2901,6 +3355,20 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + /@radix-ui/react-compose-refs@1.1.0(@types/react@18.2.61)(react@18.3.1): resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} peerDependencies: @@ -2914,6 +3382,20 @@ packages: react: 18.3.1 dev: false + /@radix-ui/react-context@1.0.1(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + /@radix-ui/react-context@1.1.0(@types/react@18.2.61)(react@18.3.1): resolution: {integrity: sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==} peerDependencies: @@ -2960,6 +3442,20 @@ packages: react-remove-scroll: 2.5.7(@types/react@18.2.61)(react@18.3.1) dev: false + /@radix-ui/react-direction@1.0.1(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + /@radix-ui/react-direction@1.1.0(@types/react@18.2.61)(react@18.3.1): resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} peerDependencies: @@ -2973,6 +3469,31 @@ packages: react: 18.3.1 dev: false + /@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==} peerDependencies: @@ -3023,6 +3544,20 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + /@radix-ui/react-focus-guards@1.1.0(@types/react@18.2.61)(react@18.3.1): resolution: {integrity: sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==} peerDependencies: @@ -3036,6 +3571,29 @@ packages: react: 18.3.1 dev: false + /@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==} peerDependencies: @@ -3058,6 +3616,21 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@radix-ui/react-id@1.0.1(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + /@radix-ui/react-id@1.1.0(@types/react@18.2.61)(react@18.3.1): resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} peerDependencies: @@ -3162,58 +3735,73 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-popper@1.2.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==} + /@radix-ui/react-popover@1.0.7(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-shtvVnlsxT6faMnK/a7n0wptwBD23xc1Z5mdrtKLwVEfsEMXodS0r5s0/g5P0hX//EKYZS2sxUjqfzlg52ZSnQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: '@types/react': optional: true '@types/react-dom': optional: true dependencies: - '@floating-ui/react-dom': 2.1.1(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-arrow': 1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.61)(react@18.3.1) - '@radix-ui/react-context': 1.1.0(@types/react@18.2.61)(react@18.3.1) - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.61)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.61)(react@18.3.1) - '@radix-ui/react-use-rect': 1.1.0(@types/react@18.2.61)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.0(@types/react@18.2.61)(react@18.3.1) - '@radix-ui/rect': 1.1.0 + '@babel/runtime': 7.24.7 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.61)(react@18.3.1) '@types/react': 18.2.61 '@types/react-dom': 18.2.19 + aria-hidden: 1.2.4 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.5.5(@types/react@18.2.61)(react@18.3.1) dev: false - /@radix-ui/react-portal@1.1.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==} + /@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: '@types/react': optional: true '@types/react-dom': optional: true dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@babel/runtime': 7.24.7 + '@floating-ui/react-dom': 2.1.1(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/rect': 1.0.1 '@types/react': 18.2.61 '@types/react-dom': 18.2.19 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-presence@1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==} + /@radix-ui/react-popper@1.2.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -3225,36 +3813,179 @@ packages: '@types/react-dom': optional: true dependencies: + '@floating-ui/react-dom': 2.1.1(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-arrow': 1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.61)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-use-rect': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/rect': 1.1.0 '@types/react': 18.2.61 '@types/react-dom': 18.2.19 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-primitive@2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==} + /@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: '@types/react': optional: true '@types/react-dom': optional: true dependencies: - '@radix-ui/react-slot': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@babel/runtime': 7.24.7 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) '@types/react': 18.2.61 '@types/react-dom': 18.2.19 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-roving-focus@1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==} + /@radix-ui/react-portal@1.1.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-presence@1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-primitive@2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-slot': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-roving-focus@1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -3281,6 +4012,21 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /@radix-ui/react-slot@1.0.2(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + /@radix-ui/react-slot@1.1.0(@types/react@18.2.61)(react@18.3.1): resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} peerDependencies: @@ -3295,6 +4041,102 @@ packages: react: 18.3.1 dev: false + /@radix-ui/react-toggle-group@1.0.4(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-context': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-toggle': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-toggle@1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-tooltip@1.0.7(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-lPh5iKNFVQ/jav/j6ZrWq3blfDJ0OH9R6FlNUHPMqdLuQ9vwDgFsRxvl8b7Asuy5c8xmoojHUxKHQSOAvMHxyw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + /@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.2.61)(react@18.3.1): resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} peerDependencies: @@ -3304,114 +4146,430 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.61 + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-previous@1.1.0(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/rect': 1.0.1 + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-rect@1.1.0(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/rect': 1.1.0 + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-size@1.0.1(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-size@1.1.0(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.61)(react@18.3.1) + '@types/react': 18.2.61 + react: 18.3.1 + dev: false + + /@radix-ui/react-visually-hidden@1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.7 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/rect@1.0.1: + resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} + dependencies: + '@babel/runtime': 7.24.7 + dev: false + + /@radix-ui/rect@1.1.0: + resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} + dev: false + + /@react-email/body@0.0.8(react@18.3.1): + resolution: {integrity: sha512-gqdkNYlIaIw0OdpWu8KjIcQSIFvx7t2bZpXVxMMvBS859Ia1+1X3b5RNbjI3S1ZqLddUf7owOHkO4MiXGE+nxg==} + peerDependencies: + react: ^18.2.0 + dependencies: + react: 18.3.1 + dev: false + + /@react-email/button@0.0.15(react@18.3.1): + resolution: {integrity: sha512-9Zi6SO3E8PoHYDfcJTecImiHLyitYWmIRs0HE3Ogra60ZzlWP2EXu+AZqwQnhXuq+9pbgwBWNWxB5YPetNPTNA==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.2.0 + dependencies: + react: 18.3.1 + dev: false + + /@react-email/code-block@0.0.4(react@18.3.1): + resolution: {integrity: sha512-xjVLi/9dFNJ70N7hYme+21eQWa3b9/kgp4V+FKQJkQCuIMobxPRCIGM5jKD/0Vo2OqrE5chYv/dkg/aP8a8sPg==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.2.0 + dependencies: + prismjs: 1.29.0 + react: 18.3.1 + dev: false + + /@react-email/code-inline@0.0.2(react@18.3.1): + resolution: {integrity: sha512-0cmgbbibFeOJl0q04K9jJlPDuJ+SEiX/OG6m3Ko7UOkG3TqjRD8Dtvkij6jNDVfUh/zESpqJCP2CxrCLLMUjdA==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.2.0 + dependencies: + react: 18.3.1 + dev: false + + /@react-email/column@0.0.10(react@18.3.1): + resolution: {integrity: sha512-MnP8Mnwipr0X3XtdD6jMLckb0sI5/IlS6Kl/2F6/rsSWBJy5Gg6nizlekTdkwDmy0kNSe3/1nGU0Zqo98pl63Q==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.2.0 + dependencies: + react: 18.3.1 + dev: false + + /@react-email/components@0.0.17(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-x5gGQaK0QchbwHvUrCBVnE8GCWdO5osTVuTSA54Fwzels6ZDeNTHEYRx9gI3Nwcf/dkoVYkVH4rzWST0SF0MLA==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.2.0 + dependencies: + '@react-email/body': 0.0.8(react@18.3.1) + '@react-email/button': 0.0.15(react@18.3.1) + '@react-email/code-block': 0.0.4(react@18.3.1) + '@react-email/code-inline': 0.0.2(react@18.3.1) + '@react-email/column': 0.0.10(react@18.3.1) + '@react-email/container': 0.0.12(react@18.3.1) + '@react-email/font': 0.0.6(react@18.3.1) + '@react-email/head': 0.0.8(react@18.3.1) + '@react-email/heading': 0.0.12(@types/react@18.2.61)(react@18.3.1) + '@react-email/hr': 0.0.8(react@18.3.1) + '@react-email/html': 0.0.8(react@18.3.1) + '@react-email/img': 0.0.8(react@18.3.1) + '@react-email/link': 0.0.8(react@18.3.1) + '@react-email/markdown': 0.0.10(react@18.3.1) + '@react-email/preview': 0.0.9(react@18.3.1) + '@react-email/render': 0.0.13 + '@react-email/row': 0.0.8(react@18.3.1) + '@react-email/section': 0.0.12(react@18.3.1) + '@react-email/tailwind': 0.0.16(react@18.3.1) + '@react-email/text': 0.0.8(react@18.3.1) + react: 18.3.1 + transitivePeerDependencies: + - '@types/react' + dev: false + + /@react-email/container@0.0.12(react@18.3.1): + resolution: {integrity: sha512-HFu8Pu5COPFfeZxSL+wKv/TV5uO/sp4zQ0XkRCdnGkj/xoq0lqOHVDL4yC2Pu6fxXF/9C3PHDA++5uEYV5WVJw==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.2.0 + dependencies: + react: 18.3.1 + dev: false + + /@react-email/font@0.0.6(react@18.3.1): + resolution: {integrity: sha512-sZZFvEZ4U3vNCAZ8wXqIO3DuGJR2qE/8m2fEH+tdqwa532zGO3zW+UlCTg0b9455wkJSzEBeaWik0IkNvjXzxw==} + peerDependencies: + react: ^18.2.0 + dependencies: + react: 18.3.1 + dev: false + + /@react-email/head@0.0.8(react@18.3.1): + resolution: {integrity: sha512-8/NI0gtQmLIilAe6rebK1TWw3IXHxtrR02rInkQq8yQ7zKbYbzx7Q/FhmsJgAk+uYh2Er/KhgYJ0sHZyDhfMTQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.2.0 + dependencies: + react: 18.3.1 + dev: false + + /@react-email/heading@0.0.12(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-eB7mpnAvDmwvQLoPuwEiPRH4fPXWe6ltz6Ptbry2BlI88F0a2k11Ghb4+sZHBqg7vVw/MKbqEgtLqr3QJ/KfCQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.2.0 + dependencies: + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.61)(react@18.3.1) + react: 18.3.1 + transitivePeerDependencies: + - '@types/react' + dev: false + + /@react-email/hr@0.0.8(react@18.3.1): + resolution: {integrity: sha512-JLVvpCg2wYKEB+n/PGCggWG9fRU5e4lxsGdpK5SDLsCL0ic3OLKSpHMfeE+ZSuw0GixAVVQN7F64PVJHQkd4MQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.2.0 + dependencies: + react: 18.3.1 + dev: false + + /@react-email/html@0.0.8(react@18.3.1): + resolution: {integrity: sha512-arII3wBNLpeJtwyIJXPaILm5BPKhA+nvdC1F9QkuKcOBJv2zXctn8XzPqyGqDfdplV692ulNJP7XY55YqbKp6w==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.2.0 + dependencies: + react: 18.3.1 + dev: false + + /@react-email/img@0.0.8(react@18.3.1): + resolution: {integrity: sha512-jx/rPuKo31tV18fu7P5rRqelaH5wkhg83Dq7uLwJpfqhbi4KFBGeBfD0Y3PiLPPoh+WvYf+Adv9W2ghNW8nOMQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.2.0 + dependencies: + react: 18.3.1 + dev: false + + /@react-email/link@0.0.8(react@18.3.1): + resolution: {integrity: sha512-nVikuTi8WJHa6Baad4VuRUbUCa/7EtZ1Qy73TRejaCHn+vhetc39XGqHzKLNh+Z/JFL8Hv9g+4AgG16o2R0ogQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^18.2.0 + dependencies: react: 18.3.1 dev: false - /@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.2.61)(react@18.3.1): - resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} + /@react-email/markdown@0.0.10(react@18.3.1): + resolution: {integrity: sha512-MH0xO+NJ4IuJcx9nyxbgGKAMXyudFjCZ0A2GQvuWajemW9qy2hgnJ3mW3/z5lwcenG+JPn7JyO/iZpizQ7u1tA==} + engines: {node: '>=18.0.0'} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + react: ^18.2.0 dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.61)(react@18.3.1) - '@types/react': 18.2.61 + md-to-react-email: 5.0.2(react@18.3.1) react: 18.3.1 dev: false - /@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.2.61)(react@18.3.1): - resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} + /@react-email/preview@0.0.9(react@18.3.1): + resolution: {integrity: sha512-2fyAA/zzZYfYmxfyn3p2YOIU30klyA6Dq4ytyWq4nfzQWWglt5hNDE0cMhObvRtfjM9ghMSVtoELAb0MWiF/kw==} + engines: {node: '>=18.0.0'} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + react: ^18.2.0 dependencies: - '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.2.61)(react@18.3.1) - '@types/react': 18.2.61 react: 18.3.1 dev: false - /@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.2.61)(react@18.3.1): - resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + /@react-email/render@0.0.13: + resolution: {integrity: sha512-lmBizrV+rQeSa3GjiL8/kPU0gENqO/wv+4xrlWANabp9UY3lTLXzy7HMRSE8YFBES9AbxP5VX1iRKuEnsoBDew==} + engines: {node: '>=18.0.0'} dependencies: - '@types/react': 18.2.61 + html-to-text: 9.0.5 + js-beautify: 1.15.1 react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) dev: false - /@radix-ui/react-use-previous@1.1.0(@types/react@18.2.61)(react@18.3.1): - resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==} + /@react-email/row@0.0.8(react@18.3.1): + resolution: {integrity: sha512-JsB6pxs/ZyjYpEML3nbwJRGAerjcN/Pa/QG48XUwnT/MioDWrUuyQuefw+CwCrSUZ2P1IDrv2tUD3/E3xzcoKw==} + engines: {node: '>=18.0.0'} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + react: ^18.2.0 dependencies: - '@types/react': 18.2.61 react: 18.3.1 dev: false - /@radix-ui/react-use-rect@1.1.0(@types/react@18.2.61)(react@18.3.1): - resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} + /@react-email/section@0.0.12(react@18.3.1): + resolution: {integrity: sha512-UCD/N/BeOTN4h3VZBUaFdiSem6HnpuxD1Q51TdBFnqeNqS5hBomp8LWJJ9s4gzwHWk1XPdNfLA3I/fJwulJshg==} + engines: {node: '>=18.0.0'} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + react: ^18.2.0 dependencies: - '@radix-ui/rect': 1.1.0 - '@types/react': 18.2.61 react: 18.3.1 dev: false - /@radix-ui/react-use-size@1.1.0(@types/react@18.2.61)(react@18.3.1): - resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==} + /@react-email/tailwind@0.0.16(react@18.3.1): + resolution: {integrity: sha512-uMifPxCEHaHLhpS1kVCMGyTeEL+aMYzHT4bgj8CkgCiBoF9wNNfIVMUlHGzHUTv4ZTEPaMfZgC/Hi8RqzL/Ogw==} + engines: {node: '>=18.0.0'} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + react: ^18.2.0 dependencies: - '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.61)(react@18.3.1) - '@types/react': 18.2.61 react: 18.3.1 dev: false - /@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1): - resolution: {integrity: sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==} + /@react-email/text@0.0.8(react@18.3.1): + resolution: {integrity: sha512-uvN2TNWMrfC9wv/LLmMLbbEN1GrMWZb9dBK14eYxHHAEHCeyvGb5ePZZ2MPyzO7Y5yTC+vFEnCEr76V+hWMxCQ==} + engines: {node: '>=18.0.0'} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + react: ^18.2.0 dependencies: - '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) - '@types/react': 18.2.61 - '@types/react-dom': 18.2.19 react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - dev: false - - /@radix-ui/rect@1.1.0: - resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} dev: false /@remix-run/dev@2.9.2(@remix-run/react@2.9.2)(typescript@5.3.3)(vite@5.1.0): @@ -3743,6 +4901,13 @@ packages: dev: true optional: true + /@selderee/plugin-htmlparser2@0.11.0: + resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} + dependencies: + domhandler: 5.0.3 + selderee: 0.11.0 + dev: false + /@sinclair/typebox@0.27.8: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} dev: true @@ -4163,6 +5328,141 @@ packages: tslib: 2.6.3 dev: false + /@socket.io/component-emitter@3.1.2: + resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} + dev: false + + /@swc/core-darwin-arm64@1.3.101: + resolution: {integrity: sha512-mNFK+uHNPRXSnfTOG34zJOeMl2waM4hF4a2NY7dkMXrPqw9CoJn4MwTXJcyMiSz1/BnNjjTCHF3Yhj0jPxmkzQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@swc/core-darwin-x64@1.3.101: + resolution: {integrity: sha512-B085j8XOx73Fg15KsHvzYWG262bRweGr3JooO1aW5ec5pYbz5Ew9VS5JKYS03w2UBSxf2maWdbPz2UFAxg0whw==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-arm-gnueabihf@1.3.101: + resolution: {integrity: sha512-9xLKRb6zSzRGPqdz52Hy5GuB1lSjmLqa0lST6MTFads3apmx4Vgs8Y5NuGhx/h2I8QM4jXdLbpqQlifpzTlSSw==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-arm64-gnu@1.3.101: + resolution: {integrity: sha512-oE+r1lo7g/vs96Weh2R5l971dt+ZLuhaUX+n3BfDdPxNHfObXgKMjO7E+QS5RbGjv/AwiPCxQmbdCp/xN5ICJA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-arm64-musl@1.3.101: + resolution: {integrity: sha512-OGjYG3H4BMOTnJWJyBIovCez6KiHF30zMIu4+lGJTCrxRI2fAjGLml3PEXj8tC3FMcud7U2WUn6TdG0/te2k6g==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-x64-gnu@1.3.101: + resolution: {integrity: sha512-/kBMcoF12PRO/lwa8Z7w4YyiKDcXQEiLvM+S3G9EvkoKYGgkkz4Q6PSNhF5rwg/E3+Hq5/9D2R+6nrkF287ihg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-x64-musl@1.3.101: + resolution: {integrity: sha512-kDN8lm4Eew0u1p+h1l3JzoeGgZPQ05qDE0czngnjmfpsH2sOZxVj1hdiCwS5lArpy7ktaLu5JdRnx70MkUzhXw==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-win32-arm64-msvc@1.3.101: + resolution: {integrity: sha512-9Wn8TTLWwJKw63K/S+jjrZb9yoJfJwCE2RV5vPCCWmlMf3U1AXj5XuWOLUX+Rp2sGKau7wZKsvywhheWm+qndQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@swc/core-win32-ia32-msvc@1.3.101: + resolution: {integrity: sha512-onO5KvICRVlu2xmr4//V2je9O2XgS1SGKpbX206KmmjcJhXN5EYLSxW9qgg+kgV5mip+sKTHTAu7IkzkAtElYA==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@swc/core-win32-x64-msvc@1.3.101: + resolution: {integrity: sha512-T3GeJtNQV00YmiVw/88/nxJ/H43CJvFnpvBHCVn17xbahiVUOPOduh3rc9LgAkKiNt/aV8vU3OJR+6PhfMR7UQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@swc/core@1.3.101: + resolution: {integrity: sha512-w5aQ9qYsd/IYmXADAnkXPGDMTqkQalIi+kfFf/MHRKTpaOL7DHjMXwPp/n8hJ0qNjRvchzmPtOqtPBiER50d8A==} + engines: {node: '>=10'} + requiresBuild: true + peerDependencies: + '@swc/helpers': ^0.5.0 + peerDependenciesMeta: + '@swc/helpers': + optional: true + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.12 + optionalDependencies: + '@swc/core-darwin-arm64': 1.3.101 + '@swc/core-darwin-x64': 1.3.101 + '@swc/core-linux-arm-gnueabihf': 1.3.101 + '@swc/core-linux-arm64-gnu': 1.3.101 + '@swc/core-linux-arm64-musl': 1.3.101 + '@swc/core-linux-x64-gnu': 1.3.101 + '@swc/core-linux-x64-musl': 1.3.101 + '@swc/core-win32-arm64-msvc': 1.3.101 + '@swc/core-win32-ia32-msvc': 1.3.101 + '@swc/core-win32-x64-msvc': 1.3.101 + dev: false + + /@swc/counter@0.1.3: + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + dev: false + + /@swc/helpers@0.5.2: + resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} + dependencies: + tslib: 2.6.3 + dev: false + + /@swc/types@0.1.12: + resolution: {integrity: sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==} + dependencies: + '@swc/counter': 0.1.3 + dev: false + /@tanstack/query-core@5.40.0: resolution: {integrity: sha512-eD8K8jsOIq0Z5u/QbvOmfvKKE/XC39jA7yv4hgpl/1SRiU+J8QCIwgM/mEHuunQsL87dcvnHqSVLmf9pD4CiaA==} dev: false @@ -4303,6 +5603,10 @@ packages: '@types/express': 4.17.20 dev: true + /@types/cookie@0.4.1: + resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} + dev: false + /@types/cookie@0.6.0: resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} @@ -4310,6 +5614,12 @@ packages: resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} dev: true + /@types/cors@2.8.17: + resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} + dependencies: + '@types/node': 20.14.10 + dev: false + /@types/debug@4.1.12: resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} dependencies: @@ -4336,14 +5646,12 @@ packages: dependencies: '@types/eslint': 8.56.10 '@types/estree': 1.0.5 - dev: true /@types/eslint@8.56.10: resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==} dependencies: '@types/estree': 1.0.5 '@types/json-schema': 7.0.15 - dev: true /@types/eslint@8.56.5: resolution: {integrity: sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==} @@ -4360,7 +5668,6 @@ packages: /@types/estree@1.0.5: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - dev: true /@types/express-serve-static-core@4.19.5: resolution: {integrity: sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==} @@ -4435,7 +5742,6 @@ packages: /@types/json-schema@7.0.15: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - dev: true /@types/json5@0.0.29: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} @@ -4543,6 +5849,10 @@ packages: '@types/express': 4.17.20 dev: true + /@types/prismjs@1.26.4: + resolution: {integrity: sha512-rlAnzkW2sZOjbqZ743IHUhFcvzaGbqijwOu8QZnZCjfQzBqFE3s4lOTJEsxikImav9uzz/42I+O7YUs1mWgMlg==} + dev: false + /@types/prop-types@15.7.12: resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} @@ -4649,6 +5959,19 @@ packages: resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} dev: true + /@types/webpack@5.28.5(@swc/core@1.3.101)(esbuild@0.19.11): + resolution: {integrity: sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw==} + dependencies: + '@types/node': 20.14.10 + tapable: 2.2.1 + webpack: 5.92.1(@swc/core@1.3.101)(esbuild@0.19.11) + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + - webpack-cli + dev: false + /@types/yargs-parser@21.0.3: resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} dev: true @@ -4924,7 +6247,6 @@ packages: /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - dev: true /@vanilla-extract/babel-plugin-debug-ids@1.0.6: resolution: {integrity: sha512-C188vUEYmw41yxg3QooTs8r1IdbDQQ2mH7L5RkORBnHx74QlmsNfqVmKwAVTgrlYt8JoRaWMtPfGm/Ql0BNQrA==} @@ -4992,19 +6314,15 @@ packages: dependencies: '@webassemblyjs/helper-numbers': 1.11.6 '@webassemblyjs/helper-wasm-bytecode': 1.11.6 - dev: true /@webassemblyjs/floating-point-hex-parser@1.11.6: resolution: {integrity: sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==} - dev: true /@webassemblyjs/helper-api-error@1.11.6: resolution: {integrity: sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==} - dev: true /@webassemblyjs/helper-buffer@1.12.1: resolution: {integrity: sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==} - dev: true /@webassemblyjs/helper-numbers@1.11.6: resolution: {integrity: sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==} @@ -5012,11 +6330,9 @@ packages: '@webassemblyjs/floating-point-hex-parser': 1.11.6 '@webassemblyjs/helper-api-error': 1.11.6 '@xtuc/long': 4.2.2 - dev: true /@webassemblyjs/helper-wasm-bytecode@1.11.6: resolution: {integrity: sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==} - dev: true /@webassemblyjs/helper-wasm-section@1.12.1: resolution: {integrity: sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==} @@ -5025,23 +6341,19 @@ packages: '@webassemblyjs/helper-buffer': 1.12.1 '@webassemblyjs/helper-wasm-bytecode': 1.11.6 '@webassemblyjs/wasm-gen': 1.12.1 - dev: true /@webassemblyjs/ieee754@1.11.6: resolution: {integrity: sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==} dependencies: '@xtuc/ieee754': 1.2.0 - dev: true /@webassemblyjs/leb128@1.11.6: resolution: {integrity: sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==} dependencies: '@xtuc/long': 4.2.2 - dev: true /@webassemblyjs/utf8@1.11.6: resolution: {integrity: sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==} - dev: true /@webassemblyjs/wasm-edit@1.12.1: resolution: {integrity: sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==} @@ -5054,7 +6366,6 @@ packages: '@webassemblyjs/wasm-opt': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 '@webassemblyjs/wast-printer': 1.12.1 - dev: true /@webassemblyjs/wasm-gen@1.12.1: resolution: {integrity: sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==} @@ -5064,7 +6375,6 @@ packages: '@webassemblyjs/ieee754': 1.11.6 '@webassemblyjs/leb128': 1.11.6 '@webassemblyjs/utf8': 1.11.6 - dev: true /@webassemblyjs/wasm-opt@1.12.1: resolution: {integrity: sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==} @@ -5073,7 +6383,6 @@ packages: '@webassemblyjs/helper-buffer': 1.12.1 '@webassemblyjs/wasm-gen': 1.12.1 '@webassemblyjs/wasm-parser': 1.12.1 - dev: true /@webassemblyjs/wasm-parser@1.12.1: resolution: {integrity: sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==} @@ -5084,22 +6393,18 @@ packages: '@webassemblyjs/ieee754': 1.11.6 '@webassemblyjs/leb128': 1.11.6 '@webassemblyjs/utf8': 1.11.6 - dev: true /@webassemblyjs/wast-printer@1.12.1: resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==} dependencies: '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 - dev: true /@xtuc/ieee754@1.2.0: resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} - dev: true /@xtuc/long@4.2.2: resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} - dev: true /@zxing/text-encoding@0.9.0: resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==} @@ -5110,6 +6415,11 @@ packages: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} dev: false + /abbrev@2.0.0: + resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: false + /abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -5137,7 +6447,6 @@ packages: acorn: ^8 dependencies: acorn: 8.12.1 - dev: true /acorn-jsx@5.3.2(acorn@8.12.1): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -5145,7 +6454,6 @@ packages: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: acorn: 8.12.1 - dev: true /acorn-walk@8.3.3: resolution: {integrity: sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==} @@ -5158,7 +6466,6 @@ packages: resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} engines: {node: '>=0.4.0'} hasBin: true - dev: true /add@2.0.6: resolution: {integrity: sha512-j5QzrmsokwWWp6kUcJQySpbG+xfOBqqKnup3OIk1pz+kB/80SLorZ9V8zHFLO92Lcd+hbvq8bT+zOGoPkmBV0Q==} @@ -5207,7 +6514,6 @@ packages: ajv: ^6.9.1 dependencies: ajv: 6.12.6 - dev: true /ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -5216,7 +6522,6 @@ packages: fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - dev: true /ajv@8.12.0: resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} @@ -5252,7 +6557,6 @@ packages: engines: {node: '>=4'} dependencies: color-convert: 1.9.3 - dev: true /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} @@ -5495,6 +6799,22 @@ packages: /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + /autoprefixer@10.4.14(postcss@8.4.38): + resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.23.1 + caniuse-lite: 1.0.30001640 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.0.1 + postcss: 8.4.38 + postcss-value-parser: 4.2.0 + dev: false + /autoprefixer@10.4.19(postcss@8.4.38): resolution: {integrity: sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==} engines: {node: ^10 || ^12 || >=14} @@ -5660,7 +6980,11 @@ packages: /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - dev: true + + /base64id@2.0.0: + resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} + engines: {node: ^4.5.0 || >= 5.9} + dev: false /basic-auth@2.0.1: resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} @@ -5702,7 +7026,6 @@ packages: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.2 - dev: true /body-parser@1.20.1: resolution: {integrity: sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==} @@ -5778,7 +7101,6 @@ packages: electron-to-chromium: 1.4.818 node-releases: 2.0.14 update-browserslist-db: 1.1.0(browserslist@4.23.1) - dev: true /bs-logger@0.2.6: resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} @@ -5809,7 +7131,6 @@ packages: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - dev: true /buildcheck@0.0.6: resolution: {integrity: sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==} @@ -5818,6 +7139,16 @@ packages: dev: true optional: true + /bundle-require@4.2.1(esbuild@0.19.12): + resolution: {integrity: sha512-7Q/6vkyYAwOmQNRw75x+4yRtZCZJXUDmHHlFdkiV0wgv/reNjtJwpu1jPJ0w2kbEpIM0uoKI3S4/f39dU7AjSA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.17' + dependencies: + esbuild: 0.19.12 + load-tsconfig: 0.2.5 + dev: true + /busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -5878,7 +7209,6 @@ packages: /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - dev: true /camel-case@3.0.0: resolution: {integrity: sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==} @@ -5903,7 +7233,6 @@ packages: /caniuse-lite@1.0.30001640: resolution: {integrity: sha512-lA4VMpW0PSUrFnkmVuEKBUovSWKhj7puyCg8StBChgu298N1AtuF1sKWEvfDuimSEDbhlb/KqPKC3fs1HbuQUA==} - dev: true /ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -5916,7 +7245,6 @@ packages: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 - dev: true /chalk@3.0.0: resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} @@ -5994,7 +7322,6 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: true /chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} @@ -6021,7 +7348,6 @@ packages: /chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} - dev: true /ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} @@ -6048,12 +7374,10 @@ packages: engines: {node: '>=8'} dependencies: restore-cursor: 3.1.0 - dev: true /cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - dev: true /cli-table3@0.6.3: resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} @@ -6069,6 +7393,10 @@ packages: engines: {node: '>= 10'} dev: true + /client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + dev: false + /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -6081,13 +7409,22 @@ packages: /clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} - dev: true + + /clsx@1.2.1: + resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} + engines: {node: '>=6'} + dev: false /clsx@2.0.0: resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} engines: {node: '>=6'} dev: false + /clsx@2.1.0: + resolution: {integrity: sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==} + engines: {node: '>=6'} + dev: false + /clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -6106,7 +7443,6 @@ packages: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 - dev: true /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -6116,7 +7452,6 @@ packages: /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -6139,11 +7474,14 @@ packages: /commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} - dev: true + + /commander@11.1.0: + resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} + engines: {node: '>=16'} + dev: false /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - dev: true /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} @@ -6212,6 +7550,13 @@ packages: resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} dev: true + /config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + dev: false + /consola@2.15.3: resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==} @@ -6238,7 +7583,6 @@ packages: /convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true /cookie-parser@1.4.6: resolution: {integrity: sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==} @@ -6430,6 +7774,11 @@ packages: is-data-view: 1.0.1 dev: true + /debounce@2.0.0: + resolution: {integrity: sha512-xRetU6gL1VJbs85Mc4FoEGSjQxzpdxRyFhe3lmWFyy2EzydIcD4xzUvRJMD+NPDfMwKNhxa3PvsIOU32luIWeA==} + engines: {node: '>=18'} + dev: false + /debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -6484,7 +7833,6 @@ packages: /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true /deep-object-diff@1.1.9: resolution: {integrity: sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==} @@ -6493,13 +7841,11 @@ packages: /deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} - dev: true /defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: clone: 1.0.4 - dev: true /define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} @@ -6653,7 +7999,33 @@ packages: engines: {node: '>=6.0.0'} dependencies: esutils: 2.0.3 - dev: true + + /dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + dev: false + + /domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: false + + /domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: false + + /domutils@3.1.0: + resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: false /dot-case@2.1.1: resolution: {integrity: sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==} @@ -6669,7 +8041,6 @@ packages: /dotenv@16.0.3: resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} engines: {node: '>=12'} - dev: true /dotenv@16.4.5: resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} @@ -6800,12 +8171,22 @@ packages: safe-buffer: 5.2.1 dev: false + /editorconfig@1.0.4: + resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} + engines: {node: '>=14'} + hasBin: true + dependencies: + '@one-ini/wasm': 0.1.1 + commander: 10.0.1 + minimatch: 9.0.1 + semver: 7.6.2 + dev: false + /ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} /electron-to-chromium@1.4.818: resolution: {integrity: sha512-eGvIk2V0dGImV9gWLq8fDfTTsCAeMDwZqEPMr+jMInxZdnp9Us8UpovYpRCf9NQ7VOFgrN2doNSgvISbsbNpxA==} - dev: true /emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -6832,13 +8213,56 @@ packages: once: 1.4.0 dev: true + /engine.io-client@6.5.4: + resolution: {integrity: sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==} + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.5 + engine.io-parser: 5.2.3 + ws: 8.17.1 + xmlhttprequest-ssl: 2.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /engine.io-parser@5.2.3: + resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} + engines: {node: '>=10.0.0'} + dev: false + + /engine.io@6.5.5: + resolution: {integrity: sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==} + engines: {node: '>=10.2.0'} + dependencies: + '@types/cookie': 0.4.1 + '@types/cors': 2.8.17 + '@types/node': 20.14.10 + accepts: 1.3.8 + base64id: 2.0.0 + cookie: 0.4.1 + cors: 2.8.5 + debug: 4.3.5 + engine.io-parser: 5.2.3 + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /enhanced-resolve@5.17.0: resolution: {integrity: sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==} engines: {node: '>=10.13.0'} dependencies: graceful-fs: 4.2.11 tapable: 2.2.1 - dev: true + + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: false /env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} @@ -6939,7 +8363,6 @@ packages: /es-module-lexer@1.5.4: resolution: {integrity: sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==} - dev: true /es-object-atoms@1.0.0: resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} @@ -7059,6 +8482,37 @@ packages: '@esbuild/win32-x64': 0.18.20 dev: false + /esbuild@0.19.11: + resolution: {integrity: sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.19.11 + '@esbuild/android-arm': 0.19.11 + '@esbuild/android-arm64': 0.19.11 + '@esbuild/android-x64': 0.19.11 + '@esbuild/darwin-arm64': 0.19.11 + '@esbuild/darwin-x64': 0.19.11 + '@esbuild/freebsd-arm64': 0.19.11 + '@esbuild/freebsd-x64': 0.19.11 + '@esbuild/linux-arm': 0.19.11 + '@esbuild/linux-arm64': 0.19.11 + '@esbuild/linux-ia32': 0.19.11 + '@esbuild/linux-loong64': 0.19.11 + '@esbuild/linux-mips64el': 0.19.11 + '@esbuild/linux-ppc64': 0.19.11 + '@esbuild/linux-riscv64': 0.19.11 + '@esbuild/linux-s390x': 0.19.11 + '@esbuild/linux-x64': 0.19.11 + '@esbuild/netbsd-x64': 0.19.11 + '@esbuild/openbsd-x64': 0.19.11 + '@esbuild/sunos-x64': 0.19.11 + '@esbuild/win32-arm64': 0.19.11 + '@esbuild/win32-ia32': 0.19.11 + '@esbuild/win32-x64': 0.19.11 + dev: false + /esbuild@0.19.12: resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} engines: {node: '>=12'} @@ -7092,7 +8546,6 @@ packages: /escalade@3.1.2: resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} engines: {node: '>=6'} - dev: true /escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} @@ -7100,7 +8553,6 @@ packages: /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} - dev: true /escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} @@ -7110,7 +8562,6 @@ packages: /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - dev: true /escodegen@2.1.0: resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} @@ -7124,6 +8575,15 @@ packages: source-map: 0.6.1 dev: true + /eslint-config-prettier@9.0.0(eslint@8.57.0): + resolution: {integrity: sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + dependencies: + eslint: 8.57.0 + dev: false + /eslint-config-prettier@9.1.0(eslint@8.57.0): resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} hasBin: true @@ -7133,6 +8593,15 @@ packages: eslint: 8.57.0 dev: true + /eslint-config-turbo@1.10.12(eslint@8.57.0): + resolution: {integrity: sha512-z3jfh+D7UGYlzMWGh+Kqz++hf8LOE96q3o5R8X4HTjmxaBWlLAWG+0Ounr38h+JLR2TJno0hU9zfzoPNkR9BdA==} + peerDependencies: + eslint: '>6.6.0' + dependencies: + eslint: 8.57.0 + eslint-plugin-turbo: 1.10.12(eslint@8.57.0) + dev: false + /eslint-config-turbo@1.12.4(eslint@8.57.0): resolution: {integrity: sha512-5hqEaV6PNmAYLL4RTmq74OcCt8pgzOLnfDVPG/7PUXpQ0Mpz0gr926oCSFukywKKXjdum3VHD84S7Z9A/DqTAw==} peerDependencies: @@ -7325,6 +8794,15 @@ packages: string.prototype.matchall: 4.0.11 dev: true + /eslint-plugin-turbo@1.10.12(eslint@8.57.0): + resolution: {integrity: sha512-uNbdj+ohZaYo4tFJ6dStRXu2FZigwulR1b3URPXe0Q8YaE7thuekKNP+54CHtZPH9Zey9dmDx5btAQl9mfzGOw==} + peerDependencies: + eslint: '>6.6.0' + dependencies: + dotenv: 16.0.3 + eslint: 8.57.0 + dev: false + /eslint-plugin-turbo@1.12.4(eslint@8.57.0): resolution: {integrity: sha512-3AGmXvH7E4i/XTWqBrcgu+G7YKZJV/8FrEn79kTd50ilNsv+U3nS2IlcCrQB6Xm2m9avGD9cadLzKDR1/UF2+g==} peerDependencies: @@ -7340,7 +8818,6 @@ packages: dependencies: esrecurse: 4.3.0 estraverse: 4.3.0 - dev: true /eslint-scope@7.2.2: resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} @@ -7348,12 +8825,10 @@ packages: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 - dev: true /eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true /eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} @@ -7400,7 +8875,6 @@ packages: text-table: 0.2.0 transitivePeerDependencies: - supports-color - dev: true /espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} @@ -7409,7 +8883,6 @@ packages: acorn: 8.12.1 acorn-jsx: 5.3.2(acorn@8.12.1) eslint-visitor-keys: 3.4.3 - dev: true /esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} @@ -7422,24 +8895,20 @@ packages: engines: {node: '>=0.10'} dependencies: estraverse: 5.3.0 - dev: true /esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} dependencies: estraverse: 5.3.0 - dev: true /estraverse@4.3.0: resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} engines: {node: '>=4.0'} - dev: true /estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} - dev: true /estree-util-attach-comments@2.1.1: resolution: {integrity: sha512-+5Ba/xGGS6mnwFbXIuQiDPTbuTxuMCooq3arVv7gPZtYpjp+VXH/NkHAP35OOefPhNG/UGqU3vt/LTABwcHX0w==} @@ -7494,7 +8963,6 @@ packages: /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - dev: true /eta@2.2.0: resolution: {integrity: sha512-UVQ72Rqjy/ZKQalzV5dCCJP80GrmPrMxh6NlNf+erV6ObL0ZFkhCstWRawS85z3smdr3d2wXPsZEY7rDPfGd2g==} @@ -7520,7 +8988,6 @@ packages: /events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - dev: true /execa@4.1.0: resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} @@ -7626,7 +9093,6 @@ packages: /fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true /fast-diff@1.3.0: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} @@ -7648,11 +9114,9 @@ packages: /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true /fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} @@ -7693,7 +9157,6 @@ packages: engines: {node: ^10.12.0 || >=12.0.0} dependencies: flat-cache: 3.2.0 - dev: true /fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} @@ -7729,7 +9192,6 @@ packages: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - dev: true /fishery@2.2.2: resolution: {integrity: sha512-jeU0nDhPHJkupmjX+r9niKgVMTBDB8X+U/pktoGHAiWOSyNlMd0HhmqnjrpjUOCDPJYaSSu4Ze16h6dZOKSp2w==} @@ -7744,11 +9206,9 @@ packages: flatted: 3.3.1 keyv: 4.5.4 rimraf: 3.0.2 - dev: true /flatted@3.3.1: resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} - dev: true /follow-redirects@1.15.6: resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} @@ -7823,7 +9283,24 @@ packages: /fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} - dev: true + + /framer-motion@10.17.4(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-CYBSs6cWfzcasAX8aofgKFZootmkQtR4qxbfTOksBLny/lbUfkGbQAFOS3qnl6Uau1N9y8tUpI7mVIrHgkFjLQ==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + tslib: 2.6.3 + optionalDependencies: + '@emotion/is-prop-valid': 0.8.8 + dev: false /fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} @@ -7920,7 +9397,6 @@ packages: /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - dev: true /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} @@ -8004,7 +9480,18 @@ packages: /glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - dev: true + + /glob@10.3.4: + resolution: {integrity: sha512-6LFElP3A+i/Q8XQKEvZjkEWEOTgAIALR9AO2rwT8bgPhDd1anmqDJDZ6lLddI4ehxxxR1S5RIqKe1uapMQfYaQ==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + foreground-child: 3.2.1 + jackspeak: 2.3.6 + minimatch: 9.0.5 + minipass: 7.1.2 + path-scurry: 1.11.1 + dev: false /glob@10.4.3: resolution: {integrity: sha512-Q38SGlYRpVtDBPSWEylRyctn7uDeTp4NQERTLiCT1FqA9JXPYWqAVmQU6qh4r/zMM5ehxTcbaO8EjhWnvEhmyg==} @@ -8042,14 +9529,12 @@ packages: /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - dev: true /globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 - dev: true /globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} @@ -8096,7 +9581,6 @@ packages: /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true /gradient-string@2.0.2: resolution: {integrity: sha512-rEDCuqUQ4tbD78TpzsMtt5OIf0cBCSDWSJtUDaF6JsAh+k0v9r++NzxNEG87oDZx9ZwGhD8DaezR2L/yrw0Jdw==} @@ -8108,7 +9592,6 @@ packages: /graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: true /gunzip-maybe@1.4.2: resolution: {integrity: sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==} @@ -8142,7 +9625,6 @@ packages: /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} - dev: true /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -8236,6 +9718,26 @@ packages: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} dev: true + /html-to-text@9.0.5: + resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==} + engines: {node: '>=14'} + dependencies: + '@selderee/plugin-htmlparser2': 0.11.0 + deepmerge: 4.3.1 + dom-serializer: 2.0.0 + htmlparser2: 8.0.2 + selderee: 0.11.0 + dev: false + + /htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.1.0 + entities: 4.5.0 + dev: false + /http-errors@2.0.0: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} @@ -8307,12 +9809,10 @@ packages: /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - dev: true /ignore@5.3.1: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} - dev: true /import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} @@ -8320,7 +9820,6 @@ packages: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - dev: true /import-local@3.1.0: resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} @@ -8334,7 +9833,6 @@ packages: /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - dev: true /indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} @@ -8353,7 +9851,6 @@ packages: /ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - dev: true /inline-style-parser@0.1.1: resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==} @@ -8453,7 +9950,6 @@ packages: /interpret@1.4.0: resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} engines: {node: '>= 0.10'} - dev: true /invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} @@ -8610,7 +10106,6 @@ packages: /is-interactive@1.0.0: resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} engines: {node: '>=8'} - dev: true /is-lower-case@1.1.3: resolution: {integrity: sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==} @@ -8647,7 +10142,6 @@ packages: /is-path-inside@3.0.3: resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} engines: {node: '>=8'} - dev: true /is-plain-obj@3.0.0: resolution: {integrity: sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==} @@ -8713,7 +10207,6 @@ packages: /is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} - dev: true /is-upper-case@1.1.2: resolution: {integrity: sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==} @@ -8833,6 +10326,15 @@ packages: set-function-name: 2.0.2 dev: true + /jackspeak@2.3.6: + resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} + engines: {node: '>=14'} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: false + /jackspeak@3.4.1: resolution: {integrity: sha512-U23pQPDnmYybVkYjObcuYMk43VRlMLLqLI+RdZy8s8WV8WsxO9SnqSroKaluuvcNOdCAlauKszDwd+umbot5Mg==} engines: {node: '>=18'} @@ -9232,7 +10734,6 @@ packages: '@types/node': 20.14.10 merge-stream: 2.0.0 supports-color: 8.1.1 - dev: true /jest-worker@29.7.0: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} @@ -9269,6 +10770,28 @@ packages: resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} hasBin: true + /joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + dev: true + + /js-beautify@1.15.1: + resolution: {integrity: sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==} + engines: {node: '>=14'} + hasBin: true + dependencies: + config-chain: 1.1.13 + editorconfig: 1.0.4 + glob: 10.4.3 + js-cookie: 3.0.5 + nopt: 7.2.1 + dev: false + + /js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + dev: false + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -9294,7 +10817,6 @@ packages: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} hasBin: true - dev: true /jsesc@3.0.2: resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} @@ -9304,11 +10826,9 @@ packages: /json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - dev: true /json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: true /json-parse-even-better-errors@3.0.2: resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} @@ -9317,7 +10837,6 @@ packages: /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true /json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} @@ -9325,7 +10844,6 @@ packages: /json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true /json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} @@ -9338,7 +10856,6 @@ packages: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true - dev: true /jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} @@ -9397,7 +10914,6 @@ packages: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} dependencies: json-buffer: 3.0.1 - dev: true /kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} @@ -9426,6 +10942,10 @@ packages: readable-stream: 2.3.8 dev: true + /leac@0.6.0: + resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} + dev: false + /leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -9437,7 +10957,6 @@ packages: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 - dev: true /lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} @@ -9450,10 +10969,14 @@ packages: /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + /load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /loader-runner@4.3.0: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} engines: {node: '>=6.11.5'} - dev: true /loader-utils@3.3.1: resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==} @@ -9480,7 +11003,6 @@ packages: engines: {node: '>=10'} dependencies: p-locate: 5.0.0 - dev: true /lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} @@ -9539,7 +11061,6 @@ packages: /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true /lodash.mergewith@4.6.2: resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} @@ -9549,6 +11070,10 @@ packages: resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} dev: false + /lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + dev: true + /lodash.union@4.6.0: resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} dev: true @@ -9569,7 +11094,6 @@ packages: dependencies: chalk: 4.1.2 is-unicode-supported: 0.1.0 - dev: true /longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -9599,7 +11123,6 @@ packages: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: yallist: 3.1.1 - dev: true /lru-cache@7.18.3: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} @@ -9655,6 +11178,21 @@ packages: engines: {node: '>=0.10.0'} dev: true + /marked@7.0.4: + resolution: {integrity: sha512-t8eP0dXRJMtMvBojtkcsA7n48BkauktUKzfkPSCq85ZMTJ0v76Rke4DYz01omYpPTUh4p/f7HePgRo3ebG8+QQ==} + engines: {node: '>= 16'} + hasBin: true + dev: false + + /md-to-react-email@5.0.2(react@18.3.1): + resolution: {integrity: sha512-x6kkpdzIzUhecda/yahltfEl53mH26QdWu4abUF9+S0Jgam8P//Ciro8cdhyMHnT5MQUJYrIbO6ORM2UxPiNNA==} + peerDependencies: + react: 18.x + dependencies: + marked: 7.0.4 + react: 18.3.1 + dev: false + /mdast-util-definitions@5.1.2: resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==} dependencies: @@ -9806,7 +11344,6 @@ packages: /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} @@ -10118,7 +11655,6 @@ packages: /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - dev: true /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -10139,6 +11675,13 @@ packages: brace-expansion: 2.0.1 dev: true + /minimatch@9.0.1: + resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: false + /minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} @@ -10297,7 +11840,6 @@ packages: /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true /negotiator@0.6.3: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} @@ -10305,7 +11847,6 @@ packages: /neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - dev: true /nestjs-typebox@3.0.0-next.8(@nestjs/common@10.0.0)(@nestjs/core@10.0.0)(@nestjs/swagger@7.4.0)(@sinclair/typebox@0.32.34)(rxjs@7.8.1): resolution: {integrity: sha512-iOOgf3jq23MrG87YU5/LLj92wji9FhW8p7PPKooqI2unVnJDMImNkRd74eHwmGs03GT7QBEp2iQkuG+TRtcpyg==} @@ -10328,6 +11869,45 @@ packages: engines: {node: '>= 0.4.0'} dev: true + /next@14.1.4(@babel/core@7.24.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-1WTaXeSrUwlz/XcnhGTY7+8eiaFvdet5z9u3V2jb+Ek1vFo0VhHKSAIJvDWfQpttWjnyw14kBeq28TPq7bTeEQ==} + engines: {node: '>=18.17.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + sass: + optional: true + dependencies: + '@next/env': 14.1.4 + '@swc/helpers': 0.5.2 + busboy: 1.6.0 + caniuse-lite: 1.0.30001640 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + styled-jsx: 5.1.1(@babel/core@7.24.5)(react@18.3.1) + optionalDependencies: + '@next/swc-darwin-arm64': 14.1.4 + '@next/swc-darwin-x64': 14.1.4 + '@next/swc-linux-arm64-gnu': 14.1.4 + '@next/swc-linux-arm64-musl': 14.1.4 + '@next/swc-linux-x64-gnu': 14.1.4 + '@next/swc-linux-x64-musl': 14.1.4 + '@next/swc-win32-arm64-msvc': 14.1.4 + '@next/swc-win32-ia32-msvc': 14.1.4 + '@next/swc-win32-x64-msvc': 14.1.4 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + dev: false + /no-case@2.3.2: resolution: {integrity: sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==} dependencies: @@ -10405,7 +11985,6 @@ packages: /node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - dev: true /nodemailer@6.9.14: resolution: {integrity: sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==} @@ -10420,6 +11999,14 @@ packages: abbrev: 1.1.1 dev: false + /nopt@7.2.1: + resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true + dependencies: + abbrev: 2.0.0 + dev: false + /normalize-package-data@5.0.0: resolution: {integrity: sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -10437,7 +12024,6 @@ packages: /normalize-range@0.1.2: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} - dev: true /npm-install-checks@6.3.0: resolution: {integrity: sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==} @@ -10631,7 +12217,6 @@ packages: engines: {node: '>=6'} dependencies: mimic-fn: 2.1.0 - dev: true /optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} @@ -10643,7 +12228,6 @@ packages: prelude-ls: 1.2.1 type-check: 0.4.0 word-wrap: 1.2.5 - dev: true /ora@4.1.1: resolution: {integrity: sha512-sjYP8QyVWBpBZWD6Vr1M/KwknSw6kJOz41tvGMlwWeClHBtYKTbHMki1PsLZnxKpXMPbTKv9b3pjQu3REib96A==} @@ -10672,7 +12256,6 @@ packages: log-symbols: 4.1.0 strip-ansi: 6.0.1 wcwidth: 1.0.1 - dev: true /os-name@4.0.1: resolution: {integrity: sha512-xl9MAoU97MH1Xt5K9ERft2YfCAoaO6msy1OBA0ozxEC0x0TmIoE6K3QvgJMMZA9yKGLmHXNY/YZoDbiGDj4zYw==} @@ -10703,7 +12286,6 @@ packages: engines: {node: '>=10'} dependencies: yocto-queue: 0.1.0 - dev: true /p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} @@ -10717,7 +12299,6 @@ packages: engines: {node: '>=10'} dependencies: p-limit: 3.1.0 - dev: true /p-map@3.0.0: resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} @@ -10780,7 +12361,6 @@ packages: engines: {node: '>=6'} dependencies: callsites: 3.1.0 - dev: true /parse-entities@4.0.1: resolution: {integrity: sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==} @@ -10810,6 +12390,13 @@ packages: engines: {node: '>=6'} dev: true + /parseley@0.12.1: + resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==} + dependencies: + leac: 0.6.0 + peberminta: 0.9.0 + dev: false + /parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -10858,7 +12445,6 @@ packages: /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - dev: true /path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} @@ -10897,6 +12483,10 @@ packages: resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==} dev: false + /peberminta@0.9.0: + resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} + dev: false + /peek-stream@1.1.3: resolution: {integrity: sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==} dependencies: @@ -11079,6 +12669,15 @@ packages: /postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.1 + source-map-js: 1.2.0 + dev: false + /postcss@8.4.38: resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} engines: {node: ^10 || ^12 || >=14} @@ -11095,7 +12694,6 @@ packages: /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - dev: true /prettier-linter-helpers@1.0.0: resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} @@ -11138,6 +12736,21 @@ packages: parse-ms: 2.1.0 dev: true + /prism-react-renderer@2.1.0(react@18.3.1): + resolution: {integrity: sha512-I5cvXHjA1PVGbGm1MsWCpvBCRrYyxEri0MC7/JbfIfYfcXAxHyO5PaUjs3A8H5GW6kJcLhTHxxMaOZZpRZD2iQ==} + peerDependencies: + react: '>=16.0.0' + dependencies: + '@types/prismjs': 1.26.4 + clsx: 1.2.1 + react: 18.3.1 + dev: false + + /prismjs@1.29.0: + resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} + engines: {node: '>=6'} + dev: false + /proc-log@3.0.0: resolution: {integrity: sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -11198,6 +12811,10 @@ packages: resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} dev: true + /proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + dev: false + /proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -11249,7 +12866,6 @@ packages: /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - dev: true /pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} @@ -11279,7 +12895,6 @@ packages: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} dependencies: safe-buffer: 5.2.1 - dev: true /range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} @@ -11322,6 +12937,66 @@ packages: react: 18.3.1 scheduler: 0.23.2 + /react-email@2.1.4(eslint@8.57.0): + resolution: {integrity: sha512-YKZ4jhkalWcNyaw4qyI//+QeTeUxe/ptqI+wSc4wVIoHzqffAWoV5x/jBpFex3FQ636xVIDFrvGq39rUVL7zSQ==} + engines: {node: '>=18.0.0'} + hasBin: true + dependencies: + '@babel/core': 7.24.5 + '@babel/parser': 7.24.5 + '@radix-ui/colors': 1.0.1 + '@radix-ui/react-collapsible': 1.0.3(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-popover': 1.0.7(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.61)(react@18.3.1) + '@radix-ui/react-toggle-group': 1.0.4(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-tooltip': 1.0.7(@types/react-dom@18.2.19)(@types/react@18.2.61)(react-dom@18.3.1)(react@18.3.1) + '@swc/core': 1.3.101 + '@types/react': 18.2.61 + '@types/react-dom': 18.2.19 + '@types/webpack': 5.28.5(@swc/core@1.3.101)(esbuild@0.19.11) + autoprefixer: 10.4.14(postcss@8.4.38) + chalk: 4.1.2 + chokidar: 3.5.3 + clsx: 2.1.0 + commander: 11.1.0 + debounce: 2.0.0 + esbuild: 0.19.11 + eslint-config-prettier: 9.0.0(eslint@8.57.0) + eslint-config-turbo: 1.10.12(eslint@8.57.0) + framer-motion: 10.17.4(react-dom@18.3.1)(react@18.3.1) + glob: 10.3.4 + log-symbols: 4.1.0 + mime-types: 2.1.35 + next: 14.1.4(@babel/core@7.24.5)(react-dom@18.3.1)(react@18.3.1) + normalize-path: 3.0.0 + ora: 5.4.1 + postcss: 8.4.38 + prism-react-renderer: 2.1.0(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + shelljs: 0.8.5 + socket.io: 4.7.3 + socket.io-client: 4.7.3 + sonner: 1.3.1(react-dom@18.3.1)(react@18.3.1) + source-map-js: 1.0.2 + stacktrace-parser: 0.1.10 + tailwind-merge: 2.2.0 + tailwindcss: 3.4.0 + typescript: 5.1.6 + transitivePeerDependencies: + - '@opentelemetry/api' + - '@swc/helpers' + - babel-plugin-macros + - bufferutil + - eslint + - sass + - supports-color + - ts-node + - uglify-js + - utf-8-validate + - webpack-cli + dev: false + /react-hook-form@7.52.1(react@18.3.1): resolution: {integrity: sha512-uNKIhaoICJ5KQALYZ4TOaOLElyM+xipord+Ha3crEFhTntdLvWZqVY49Wqd/0GiVCA/f9NjemLeiNPjG7Hpurg==} engines: {node: '>=12.22.0'} @@ -11360,6 +13035,25 @@ packages: tslib: 2.6.3 dev: false + /react-remove-scroll@2.5.5(@types/react@18.2.61)(react@18.3.1): + resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.61 + react: 18.3.1 + react-remove-scroll-bar: 2.3.6(@types/react@18.2.61)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.2.61)(react@18.3.1) + tslib: 2.6.3 + use-callback-ref: 1.3.2(@types/react@18.2.61)(react@18.3.1) + use-sidecar: 1.1.2(@types/react@18.2.61)(react@18.3.1) + dev: false + /react-remove-scroll@2.5.7(@types/react@18.2.61)(react@18.3.1): resolution: {integrity: sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==} engines: {node: '>=10'} @@ -11464,7 +13158,6 @@ packages: engines: {node: '>= 0.10'} dependencies: resolve: 1.22.8 - dev: true /reflect-metadata@0.2.0: resolution: {integrity: sha512-vUN0wuk3MuhSVMfU/ImnPQAK8QZcXJ339DtVsP3jDscxCe6dT+PsOe3J1BYS9Ec2Fd4oC6ry6bCBebzTya0IYw==} @@ -11489,7 +13182,6 @@ packages: /regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - dev: true /regexp.prototype.flags@1.5.2: resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} @@ -11591,7 +13283,6 @@ packages: /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - dev: true /resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} @@ -11629,7 +13320,6 @@ packages: dependencies: onetime: 5.1.2 signal-exit: 3.0.7 - dev: true /retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} @@ -11750,7 +13440,12 @@ packages: '@types/json-schema': 7.0.15 ajv: 6.12.6 ajv-keywords: 3.5.2(ajv@6.12.6) - dev: true + + /selderee@0.11.0: + resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==} + dependencies: + parseley: 0.12.1 + dev: false /semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} @@ -11792,7 +13487,6 @@ packages: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} dependencies: randombytes: 2.1.0 - dev: true /serve-static@1.15.0: resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} @@ -11854,7 +13548,6 @@ packages: glob: 7.2.3 interpret: 1.4.0 rechoir: 0.6.2 - dev: true /should-equal@2.0.0: resolution: {integrity: sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==} @@ -11937,6 +13630,58 @@ packages: no-case: 2.3.2 dev: true + /socket.io-adapter@2.5.5: + resolution: {integrity: sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==} + dependencies: + debug: 4.3.5 + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /socket.io-client@4.7.3: + resolution: {integrity: sha512-nU+ywttCyBitXIl9Xe0RSEfek4LneYkJxCeNnKCuhwoH4jGXO1ipIUw/VA/+Vvv2G1MTym11fzFC0SxkrcfXDw==} + engines: {node: '>=10.0.0'} + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.5 + engine.io-client: 6.5.4 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /socket.io-parser@4.2.4: + resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} + engines: {node: '>=10.0.0'} + dependencies: + '@socket.io/component-emitter': 3.1.2 + debug: 4.3.5 + transitivePeerDependencies: + - supports-color + dev: false + + /socket.io@4.7.3: + resolution: {integrity: sha512-SE+UIQXBQE+GPG2oszWMlsEmWtHVqw/h1VrYJGK5/MC7CH5p58N448HwIrtREcvR4jfdOJAY4ieQfxMr55qbbw==} + engines: {node: '>=10.2.0'} + dependencies: + accepts: 1.3.8 + base64id: 2.0.0 + cors: 2.8.5 + debug: 4.3.5 + engine.io: 6.5.5 + socket.io-adapter: 2.5.5 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /socks-proxy-agent@8.0.4: resolution: {integrity: sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==} engines: {node: '>= 14'} @@ -11956,6 +13701,16 @@ packages: smart-buffer: 4.2.0 dev: true + /sonner@1.3.1(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-+rOAO56b2eI3q5BtgljERSn2umRk63KFIvgb2ohbZ5X+Eb5u+a/7/0ZgswYqgBMg8dyl7n6OXd9KasA8QF9ToA==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + /sonner@1.5.0(react-dom@18.3.1)(react@18.3.1): resolution: {integrity: sha512-FBjhG/gnnbN6FY0jaNnqZOMmB73R+5IiyYAw8yBj7L54ER7HB3fOSE5OFiQiE2iXWxeXKvg6fIP4LtVppHEdJA==} peerDependencies: @@ -11966,6 +13721,11 @@ packages: react-dom: 18.3.1(react@18.3.1) dev: false + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: false + /source-map-js@1.2.0: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} @@ -11991,6 +13751,13 @@ packages: resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} engines: {node: '>= 8'} + /source-map@0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + dependencies: + whatwg-url: 7.1.0 + dev: true + /space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} dev: true @@ -12062,6 +13829,13 @@ packages: escape-string-regexp: 2.0.0 dev: true + /stacktrace-parser@0.1.10: + resolution: {integrity: sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg==} + engines: {node: '>=6'} + dependencies: + type-fest: 0.7.1 + dev: false + /statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} @@ -12212,7 +13986,6 @@ packages: /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - dev: true /strnum@1.0.5: resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} @@ -12224,6 +13997,24 @@ packages: inline-style-parser: 0.1.1 dev: true + /styled-jsx@5.1.1(@babel/core@7.24.5)(react@18.3.1): + resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + dependencies: + '@babel/core': 7.24.5 + client-only: 0.0.1 + react: 18.3.1 + dev: false + /sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -12271,7 +14062,6 @@ packages: engines: {node: '>=4'} dependencies: has-flag: 3.0.0 - dev: true /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -12284,7 +14074,6 @@ packages: engines: {node: '>=10'} dependencies: has-flag: 4.0.0 - dev: true /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} @@ -12358,6 +14147,12 @@ packages: tslib: 2.6.3 dev: true + /tailwind-merge@2.2.0: + resolution: {integrity: sha512-SqqhhaL0T06SW59+JVNfAqKdqLs0497esifRrZ7jOaefP3o64fdFNDMrAQWZFMxTLJPiHVjRLUywT8uFz1xNWQ==} + dependencies: + '@babel/runtime': 7.24.7 + dev: false + /tailwind-merge@2.4.0: resolution: {integrity: sha512-49AwoOQNKdqKPd9CViyH5wJoSKsCDjUlzL8DxuGp3P1FsGY36NJDAa18jLZcaHAUUuTj+JB8IAo8zWgBNvBF7A==} dev: false @@ -12370,6 +14165,37 @@ packages: tailwindcss: 3.4.4 dev: false + /tailwindcss@3.4.0: + resolution: {integrity: sha512-VigzymniH77knD1dryXbyxR+ePHihHociZbXnLZHUyzf2MMs2ZVqlUrZ3FvpXP8pno9JzmILt1sZPD19M3IxtA==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.6 + lilconfig: 2.1.0 + micromatch: 4.0.7 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.1 + postcss: 8.4.38 + postcss-import: 15.1.0(postcss@8.4.38) + postcss-js: 4.0.1(postcss@8.4.38) + postcss-load-config: 4.0.2(postcss@8.4.38) + postcss-nested: 6.0.1(postcss@8.4.38) + postcss-selector-parser: 6.1.0 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + dev: false + /tailwindcss@3.4.4: resolution: {integrity: sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==} engines: {node: '>=14.0.0'} @@ -12403,7 +14229,6 @@ packages: /tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} - dev: true /tar-fs@2.0.1: resolution: {integrity: sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==} @@ -12510,8 +14335,7 @@ packages: schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.31.1 - webpack: 5.92.1(esbuild@0.19.12) - dev: true + webpack: 5.92.1(@swc/core@1.3.101)(esbuild@0.19.11) /terser@5.31.1: resolution: {integrity: sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==} @@ -12522,7 +14346,6 @@ packages: acorn: 8.12.1 commander: 2.20.3 source-map-support: 0.5.21 - dev: true /test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} @@ -12564,7 +14387,6 @@ packages: /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true /thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} @@ -12625,7 +14447,6 @@ packages: /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} - dev: true /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} @@ -12644,6 +14465,12 @@ packages: /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + /tr46@1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + dependencies: + punycode: 2.3.1 + dev: true + /tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -12716,7 +14543,7 @@ packages: micromatch: 4.0.7 semver: 7.6.2 typescript: 5.3.3 - webpack: 5.92.1(esbuild@0.19.12) + webpack: 5.92.1(@swc/core@1.3.101)(esbuild@0.19.11) dev: true /ts-node@10.9.1(@types/node@20.11.24)(typescript@5.3.3): @@ -12835,6 +14662,46 @@ packages: /tslib@2.6.3: resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} + /tsup@8.0.2(postcss@8.4.38)(typescript@5.5.3): + resolution: {integrity: sha512-NY8xtQXdH7hDUAZwcQdY/Vzlw9johQsaqf7iwZ6g1DOUlFYQ5/AtVAjTvihhEyeRlGo4dLRVHtrRaL35M1daqQ==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + dependencies: + bundle-require: 4.2.1(esbuild@0.19.12) + cac: 6.7.14 + chokidar: 3.6.0 + debug: 4.3.5 + esbuild: 0.19.12 + execa: 5.1.1 + globby: 11.1.0 + joycon: 3.1.1 + postcss: 8.4.38 + postcss-load-config: 4.0.2(postcss@8.4.38) + resolve-from: 5.0.0 + rollup: 4.18.0 + source-map: 0.8.0-beta.0 + sucrase: 3.35.0 + tree-kill: 1.2.2 + typescript: 5.5.3 + transitivePeerDependencies: + - supports-color + - ts-node + dev: true + /turbo-darwin-64@2.0.6: resolution: {integrity: sha512-XpgBwWj3Ggmz/gQVqXdMKXHC1iFPMDiuwugLwSzE7Ih0O13JuNtYZKhQnopvbDQnFQCeRq2Vsm5OTWabg/oB/g==} cpu: [x64] @@ -12907,7 +14774,6 @@ packages: engines: {node: '>= 0.8.0'} dependencies: prelude-ls: 1.2.1 - dev: true /type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} @@ -12917,13 +14783,17 @@ packages: /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} - dev: true /type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} dev: true + /type-fest@0.7.1: + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} + dev: false + /type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -12984,6 +14854,12 @@ packages: hasBin: true dev: true + /typescript@5.1.6: + resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==} + engines: {node: '>=14.17'} + hasBin: true + dev: false + /typescript@5.3.3: resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} engines: {node: '>=14.17'} @@ -13128,7 +15004,6 @@ packages: browserslist: 4.23.1 escalade: 3.1.2 picocolors: 1.0.1 - dev: true /update-check@1.5.4: resolution: {integrity: sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==} @@ -13151,7 +15026,6 @@ packages: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: punycode: 2.3.1 - dev: true /use-callback-ref@1.3.2(@types/react@18.2.61)(react@18.3.1): resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} @@ -13359,13 +15233,11 @@ packages: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - dev: true /wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: defaults: 1.0.4 - dev: true /web-encoding@1.1.5: resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==} @@ -13381,6 +15253,10 @@ packages: /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + /webidl-conversions@4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + dev: true + /webpack-node-externals@3.0.0: resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==} engines: {node: '>=6'} @@ -13389,7 +15265,6 @@ packages: /webpack-sources@3.2.3: resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} engines: {node: '>=10.13.0'} - dev: true /webpack@5.87.0(esbuild@0.19.12): resolution: {integrity: sha512-GOu1tNbQ7p1bDEoFRs2YPcfyGs8xq52yyPBZ3m2VGnXGtV9MxjrkABHm4V9Ia280OefsSLzvbVoXcfLxjKY/Iw==} @@ -13431,7 +15306,7 @@ packages: - uglify-js dev: true - /webpack@5.92.1(esbuild@0.19.12): + /webpack@5.92.1(@swc/core@1.3.101)(esbuild@0.19.11): resolution: {integrity: sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==} engines: {node: '>=10.13.0'} hasBin: true @@ -13469,7 +15344,6 @@ packages: - '@swc/core' - esbuild - uglify-js - dev: true /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -13477,6 +15351,14 @@ packages: tr46: 0.0.3 webidl-conversions: 3.0.1 + /whatwg-url@7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + dev: true + /which-boxed-primitive@1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: @@ -13556,7 +15438,6 @@ packages: /word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - dev: true /wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} @@ -13611,6 +15492,24 @@ packages: optional: true dev: true + /ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + + /xmlhttprequest-ssl@2.0.0: + resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==} + engines: {node: '>=0.4.0'} + dev: false + /xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -13622,7 +15521,6 @@ packages: /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} @@ -13663,7 +15561,6 @@ packages: /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - dev: true /zip-stream@4.1.1: resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} From c2a380a98863e69c89b80b5f3cdfb734cd2cf3d3 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Wed, 24 Jul 2024 16:21:44 +0200 Subject: [PATCH 09/23] feat: react emails package --- .../apps/api/src/auth/auth.service.ts | 6 +- examples/common_nestjs_remix/package.json | 1 + .../packages/email-templates/index.ts | 2 - .../packages/email-templates/package.json | 7 +- .../packages/email-templates/plugin.js | 101 ------------------ .../packages/email-templates/plugin.mjs | 90 ++++++++++++++++ .../email-templates/src/email-factory.ts | 4 +- .../packages/email-templates/src/index.ts | 5 + .../src/templates/WelcomeEmailTwo.tsx | 21 ++++ .../packages/email-templates/tsconfig.json | 32 ++++-- .../packages/email-templates/tsup.config.ts | 18 ++-- examples/common_nestjs_remix/pnpm-lock.yaml | 73 ++++++++++--- 12 files changed, 221 insertions(+), 139 deletions(-) delete mode 100644 examples/common_nestjs_remix/packages/email-templates/index.ts delete mode 100644 examples/common_nestjs_remix/packages/email-templates/plugin.js create mode 100644 examples/common_nestjs_remix/packages/email-templates/plugin.mjs create mode 100644 examples/common_nestjs_remix/packages/email-templates/src/index.ts create mode 100644 examples/common_nestjs_remix/packages/email-templates/src/templates/WelcomeEmailTwo.tsx diff --git a/examples/common_nestjs_remix/apps/api/src/auth/auth.service.ts b/examples/common_nestjs_remix/apps/api/src/auth/auth.service.ts index 9647d85..091e1d3 100644 --- a/examples/common_nestjs_remix/apps/api/src/auth/auth.service.ts +++ b/examples/common_nestjs_remix/apps/api/src/auth/auth.service.ts @@ -13,6 +13,7 @@ import { credentials, users } from "../storage/schema"; import { UsersService } from "../users/users.service"; import hashPassword from "src/common/helpers/hashPassword"; import { EmailService } from "src/common/emails/emails.service"; +import { WelcomeEmail } from "@repo/email-templates"; @Injectable() export class AuthService { @@ -43,10 +44,13 @@ export class AuthService { .insert(credentials) .values({ userId: newUser.id, password: hashedPassword }); + const emailTemplate = new WelcomeEmail({ email, name: email }); + await this.emailService.sendEmail({ to: email, subject: "Welcome to our platform", - text: "You have successfully registered", + text: emailTemplate.text, + html: emailTemplate.html, from: "godfather@selleo.com", }); diff --git a/examples/common_nestjs_remix/package.json b/examples/common_nestjs_remix/package.json index 3e7d622..fb97564 100644 --- a/examples/common_nestjs_remix/package.json +++ b/examples/common_nestjs_remix/package.json @@ -7,6 +7,7 @@ "lint": "turbo lint", "format": "prettier --write \"**/*.{ts,tsx,md}\"", "generate:client": "pnpm run --filter=web generate:client", + "generate:emails": "pnpm run --filter=email-templates build", "db:generate": "pnpm run --filter=api db:generate", "db:migrate": "pnpm run --filter=api db:migrate" }, diff --git a/examples/common_nestjs_remix/packages/email-templates/index.ts b/examples/common_nestjs_remix/packages/email-templates/index.ts deleted file mode 100644 index db96f05..0000000 --- a/examples/common_nestjs_remix/packages/email-templates/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { emailFactory } from "./src/email-factory"; -export { WelcomeEmail } from "./src/templates/WelcomeEmail"; diff --git a/examples/common_nestjs_remix/packages/email-templates/package.json b/examples/common_nestjs_remix/packages/email-templates/package.json index 64042cc..92b6821 100644 --- a/examples/common_nestjs_remix/packages/email-templates/package.json +++ b/examples/common_nestjs_remix/packages/email-templates/package.json @@ -1,10 +1,10 @@ { "name": "@repo/email-templates", "version": "0.1.0", + "type": "module", "description": "Email templates", - "main": "./dist/index.js", - "module": "./dist/index.mjs", - "types": "./dist/index.d.ts", + "main": "./dist/index.cjs", + "types": "./dist/index.d.cts", "private": true, "scripts": { "build": "tsup", @@ -24,6 +24,7 @@ "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7", "@repo/typescript-config": "*", + "@types/node": "^20.14.12", "@types/react": "^18.2.61", "tsup": "^8.0.2", "typescript": "^5.4.5" diff --git a/examples/common_nestjs_remix/packages/email-templates/plugin.js b/examples/common_nestjs_remix/packages/email-templates/plugin.js deleted file mode 100644 index bfdb4b1..0000000 --- a/examples/common_nestjs_remix/packages/email-templates/plugin.js +++ /dev/null @@ -1,101 +0,0 @@ -import path from "path"; -import fs from "fs"; -import * as parser from "@babel/parser"; -import * as traverse from "@babel/traverse"; // Correct import -import * as generate from "@babel/generator"; -import template from "@babel/template"; -import { - importDeclaration, - importDefaultSpecifier, - exportNamedDeclaration, - variableDeclaration, - variableDeclarator, - callExpression, - identifier, - stringLiteral, // Import stringLiteral -} from "@babel/types"; - -module.exports = function myTsupPlugin() { - const xd = template.default(`import UserDialog from "./user-dialog";`, { - sourceType: "module", - }); - - const xdd = generate.default.default( - xd, - { - /* options */ - }, - xd.code, - ); - - console.log(xdd.code); - - // console.log( - // "myTsupPlugin", - // ); - return { - name: "dynamic-template-exports", - buildEnd: () => { - const templatesDir = path.resolve(__dirname, "src", "templates"); // Adjust path if needed - const indexFilePath = path.resolve(__dirname, "index.ts"); - - const templateFiles = fs - .readdirSync(templatesDir) - .filter((file) => file.endsWith(".tsx") && file !== "index.ts"); - - const ast = parser.parse(fs.readFileSync(indexFilePath, "utf-8"), { - sourceType: "module", - plugins: ["typescript"], // Ensure TypeScript parsing - }); - - traverse.default.default(ast, { - Program(path) { - const body = path.get("body"); - - templateFiles.forEach((templateFile) => { - const templateName = templateFile.replace(".tsx", ""); - const variableName = - templateName.charAt(0).toUpperCase() + templateName.slice(1); - - // Create the import declaration AST node (Corrected) - const importSpecifier = importDefaultSpecifier( - identifier(`${variableName}Template`), - ); - const importDeclarationNode = importDeclaration( - [importSpecifier], - stringLiteral(`./templates/${templateName}`), // Use stringLiteral here - ); - - // Create the export declaration AST node - const exportDeclarationNode = exportNamedDeclaration( - variableDeclaration("const", [ - variableDeclarator( - identifier(variableName), - callExpression(identifier("emailTemplateFactory"), [ - identifier(`${variableName}Template`), - ]), - ), - ]), - [], - ); - - body.push(importDeclarationNode); - body.push(exportDeclarationNode); - }); - }, - }); - - console.log(ast); - - const output = generate.default.default( - ast, - { - /* options */ - }, - ast.code, - ); - - fs.writeFileSync(indexFilePath, output.code, "utf-8"); - }, - }; -}; diff --git a/examples/common_nestjs_remix/packages/email-templates/plugin.mjs b/examples/common_nestjs_remix/packages/email-templates/plugin.mjs new file mode 100644 index 0000000..2c70885 --- /dev/null +++ b/examples/common_nestjs_remix/packages/email-templates/plugin.mjs @@ -0,0 +1,90 @@ +import path from "path"; +import fs from "fs"; +import * as parser from "@babel/parser"; +import _traverse from "@babel/traverse"; +import _generate from "@babel/generator"; +import * as t from "@babel/types"; + +const traverse = _traverse.default; +const generate = _generate.default; + +const generateIndexContent = () => { + const templatesDir = path.resolve(process.cwd(), "src", "templates"); + + const templateFiles = fs + .readdirSync(templatesDir) + .filter((file) => file.endsWith(".tsx") && file !== "index.ts"); + + const ast = parser.parse( + "import { emailTemplateFactory } from './email-factory';\n", + { + sourceType: "module", + plugins: ["typescript"], + } + ); + + traverse(ast, { + Program(path) { + templateFiles.forEach((templateFile) => { + const templateName = templateFile.replace(".tsx", ""); + const variableName = + templateName.charAt(0).toUpperCase() + templateName.slice(1); + + const importDeclaration = t.importDeclaration( + [t.importDefaultSpecifier(t.identifier(`${variableName}Template`))], + t.stringLiteral(`./templates/${templateName}`) + ); + + const exportDeclaration = t.exportNamedDeclaration( + t.variableDeclaration("const", [ + t.variableDeclarator( + t.identifier(variableName), + t.callExpression(t.identifier("emailTemplateFactory"), [ + t.identifier(`${variableName}Template`), + ]) + ), + ]) + ); + + path.pushContainer("body", importDeclaration); + path.pushContainer("body", exportDeclaration); + }); + }, + }); + + const output = generate( + ast, + { + retainLines: false, + concise: false, + decoratorsBeforeExport: true, + jsescOption: { + minimal: true, + }, + }, + ast.program + ); + + return output.code; +}; + +const tsupPlugin = () => { + return { + name: "dynamic-template-exports", + buildEnd: () => { + const indexFilePath = path.resolve(process.cwd(), "src", "index.ts"); + const content = generateIndexContent(); + + fs.writeFileSync(indexFilePath, content, "utf-8"); + console.log(`Generated ${indexFilePath}.`); + + const savedContent = fs.readFileSync(indexFilePath, "utf-8"); + + if (content !== savedContent) { + console.error("Error: Saved content does not match generated content!"); + } + }, + }; +}; + +export default tsupPlugin; diff --git a/examples/common_nestjs_remix/packages/email-templates/src/email-factory.ts b/examples/common_nestjs_remix/packages/email-templates/src/email-factory.ts index 0164826..e315a88 100644 --- a/examples/common_nestjs_remix/packages/email-templates/src/email-factory.ts +++ b/examples/common_nestjs_remix/packages/email-templates/src/email-factory.ts @@ -1,8 +1,8 @@ import { render } from "@react-email/components"; import { EmailContent } from "./email-content"; -export function emailFactory( - template: (...args: T) => Parameters[0], +export function emailTemplateFactory( + template: (...args: T) => Parameters[0] ): new (...args: T) => EmailContent { return class implements EmailContent { private readonly args: T; diff --git a/examples/common_nestjs_remix/packages/email-templates/src/index.ts b/examples/common_nestjs_remix/packages/email-templates/src/index.ts new file mode 100644 index 0000000..01d861b --- /dev/null +++ b/examples/common_nestjs_remix/packages/email-templates/src/index.ts @@ -0,0 +1,5 @@ +import { emailTemplateFactory } from './email-factory'; +import WelcomeEmailTemplate from "./templates/WelcomeEmail"; +export const WelcomeEmail = emailTemplateFactory(WelcomeEmailTemplate); +import WelcomeEmailTwoTemplate from "./templates/WelcomeEmailTwo"; +export const WelcomeEmailTwo = emailTemplateFactory(WelcomeEmailTwoTemplate); \ No newline at end of file diff --git a/examples/common_nestjs_remix/packages/email-templates/src/templates/WelcomeEmailTwo.tsx b/examples/common_nestjs_remix/packages/email-templates/src/templates/WelcomeEmailTwo.tsx new file mode 100644 index 0000000..cebce63 --- /dev/null +++ b/examples/common_nestjs_remix/packages/email-templates/src/templates/WelcomeEmailTwo.tsx @@ -0,0 +1,21 @@ +import { Button, Html } from "@react-email/components"; + +export type WelcomeEmailProps = { + email: string; + name: string; +}; + +export const WelcomeEmailTwo = ({ email, name }: WelcomeEmailProps) => { + return ( + + + + ); +}; + +export default WelcomeEmailTwo; diff --git a/examples/common_nestjs_remix/packages/email-templates/tsconfig.json b/examples/common_nestjs_remix/packages/email-templates/tsconfig.json index b521138..966f057 100644 --- a/examples/common_nestjs_remix/packages/email-templates/tsconfig.json +++ b/examples/common_nestjs_remix/packages/email-templates/tsconfig.json @@ -1,16 +1,28 @@ { - "extends": "@repo/typescript-config/base.json", - "include": [ - "." - ], - "exclude": [ - "dist", - "build", - "node_modules" - ], + "extends": "@repo/typescript-config/base.json", + "include": ["src/**/*", "index.ts"], + "exclude": ["dist", "build", "node_modules"], "compilerOptions": { "strict": true, "jsx": "react-jsx", - "allowJs": true + "allowJs": true, + "moduleResolution": "Node", + "target": "ES2020", + "module": "CommonJS", + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "isolatedModules": true, + "baseUrl": "./src" + }, + "ts-node": { + "compilerOptions": { + "module": "CommonJS" + } } } diff --git a/examples/common_nestjs_remix/packages/email-templates/tsup.config.ts b/examples/common_nestjs_remix/packages/email-templates/tsup.config.ts index 38af578..7f0eda1 100644 --- a/examples/common_nestjs_remix/packages/email-templates/tsup.config.ts +++ b/examples/common_nestjs_remix/packages/email-templates/tsup.config.ts @@ -1,10 +1,12 @@ import { defineConfig, type Options } from "tsup"; -const plugin = require("./plugin"); +import tsupPlugin from "./plugin.mjs"; -export default defineConfig((options: Options) => ({ - entry: ["./index.ts"], - format: ["cjs", "esm"], - dts: true, - plugins: [plugin()], - ...options, -})); +export default defineConfig(async (options: Options) => { + return { + entry: ["./src/index.ts"], + format: ["cjs", "esm"], + plugins: [tsupPlugin()], + dts: true, + ...options, + }; +}); diff --git a/examples/common_nestjs_remix/pnpm-lock.yaml b/examples/common_nestjs_remix/pnpm-lock.yaml index 48d1d4a..500ffe5 100644 --- a/examples/common_nestjs_remix/pnpm-lock.yaml +++ b/examples/common_nestjs_remix/pnpm-lock.yaml @@ -406,6 +406,9 @@ importers: '@repo/typescript-config': specifier: '*' version: link:../typescript-config + '@types/node': + specifier: ^20.14.12 + version: 20.14.12 '@types/react': specifier: ^18.2.61 version: 18.2.61 @@ -2486,14 +2489,14 @@ packages: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.11.24 + '@types/node': 20.14.10 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@20.11.24)(ts-node@10.9.1) + jest-config: 29.7.0(@types/node@20.14.10)(ts-node@10.9.1) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -2669,7 +2672,7 @@ packages: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.11.24 + '@types/node': 20.14.10 '@types/yargs': 17.0.32 chalk: 4.1.2 dev: true @@ -5582,7 +5585,7 @@ packages: resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} dependencies: '@types/connect': 3.4.38 - '@types/node': 20.11.24 + '@types/node': 20.14.10 dev: true /@types/compression@1.7.5: @@ -5617,7 +5620,7 @@ packages: /@types/cors@2.8.17: resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.12 dev: false /@types/debug@4.1.12: @@ -5672,7 +5675,7 @@ packages: /@types/express-serve-static-core@4.19.5: resolution: {integrity: sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==} dependencies: - '@types/node': 20.11.24 + '@types/node': 20.14.10 '@types/qs': 6.9.15 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -5811,6 +5814,11 @@ packages: dependencies: undici-types: 5.26.5 + /@types/node@20.14.12: + resolution: {integrity: sha512-r7wNXakLeSsGT0H1AU863vS2wa5wBOK4bWMjZz2wj+8nBx+m5PeIn0k8AloSLpRuiwdRQZwarZqHE4FNArPuJQ==} + dependencies: + undici-types: 5.26.5 + /@types/nodemailer@6.4.15: resolution: {integrity: sha512-0EBJxawVNjPkng1zm2vopRctuWVCxk34JcIlRuXSf54habUWdz1FB7wHDqOqvDa8Mtpt0Q3LTXQkAs2LNyK5jQ==} dependencies: @@ -5894,7 +5902,7 @@ packages: resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} dependencies: '@types/http-errors': 2.0.4 - '@types/node': 20.11.24 + '@types/node': 20.14.10 '@types/send': 0.17.4 dev: true @@ -5926,7 +5934,7 @@ packages: dependencies: '@types/cookiejar': 2.1.5 '@types/methods': 1.1.4 - '@types/node': 20.11.24 + '@types/node': 20.14.10 dev: true /@types/supertest@6.0.0: @@ -5962,7 +5970,7 @@ packages: /@types/webpack@5.28.5(@swc/core@1.3.101)(esbuild@0.19.11): resolution: {integrity: sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw==} dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.12 tapable: 2.2.1 webpack: 5.92.1(@swc/core@1.3.101)(esbuild@0.19.11) transitivePeerDependencies: @@ -8238,7 +8246,7 @@ packages: dependencies: '@types/cookie': 0.4.1 '@types/cors': 2.8.17 - '@types/node': 20.14.10 + '@types/node': 20.14.12 accepts: 1.3.8 base64id: 2.0.0 cookie: 0.4.1 @@ -10454,6 +10462,47 @@ packages: - supports-color dev: true + /jest-config@29.7.0(@types/node@20.14.10)(ts-node@10.9.1): + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.24.7 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 20.14.10 + babel-jest: 29.7.0(@babel/core@7.24.7) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.7 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + ts-node: 10.9.1(@types/node@20.11.24)(typescript@5.3.3) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + dev: true + /jest-diff@29.7.0: resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -10694,7 +10743,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.6.3 - '@types/node': 20.11.24 + '@types/node': 20.14.10 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 @@ -10731,7 +10780,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 20.14.10 + '@types/node': 20.14.12 merge-stream: 2.0.0 supports-color: 8.1.1 From 8621ad8380f28fb4e314ec489033fe788d65931e Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Wed, 24 Jul 2024 17:37:02 +0200 Subject: [PATCH 10/23] refactor: update AST parsing for email templates --- .../packages/email-templates/plugin.mjs | 22 +++++++++++++------ .../packages/email-templates/src/index.ts | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/examples/common_nestjs_remix/packages/email-templates/plugin.mjs b/examples/common_nestjs_remix/packages/email-templates/plugin.mjs index 2c70885..fc28ef1 100644 --- a/examples/common_nestjs_remix/packages/email-templates/plugin.mjs +++ b/examples/common_nestjs_remix/packages/email-templates/plugin.mjs @@ -15,16 +15,24 @@ const generateIndexContent = () => { .readdirSync(templatesDir) .filter((file) => file.endsWith(".tsx") && file !== "index.ts"); - const ast = parser.parse( - "import { emailTemplateFactory } from './email-factory';\n", - { - sourceType: "module", - plugins: ["typescript"], - } - ); + const ast = parser.parse("", { + sourceType: "module", + plugins: ["typescript"], + }); traverse(ast, { Program(path) { + const factoryImport = t.importDeclaration( + [ + t.importSpecifier( + t.identifier("emailTemplateFactory"), + t.identifier("emailTemplateFactory") + ), + ], + t.stringLiteral("./email-factory") + ); + path.pushContainer("body", factoryImport); + templateFiles.forEach((templateFile) => { const templateName = templateFile.replace(".tsx", ""); const variableName = diff --git a/examples/common_nestjs_remix/packages/email-templates/src/index.ts b/examples/common_nestjs_remix/packages/email-templates/src/index.ts index 01d861b..3ba71a1 100644 --- a/examples/common_nestjs_remix/packages/email-templates/src/index.ts +++ b/examples/common_nestjs_remix/packages/email-templates/src/index.ts @@ -1,4 +1,4 @@ -import { emailTemplateFactory } from './email-factory'; +import { emailTemplateFactory } from "./email-factory"; import WelcomeEmailTemplate from "./templates/WelcomeEmail"; export const WelcomeEmail = emailTemplateFactory(WelcomeEmailTemplate); import WelcomeEmailTwoTemplate from "./templates/WelcomeEmailTwo"; From 5731c842cc21f711e4f844c64ba6bfec143448ed Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 30 Jul 2024 13:10:23 +0200 Subject: [PATCH 11/23] feat: implement email adapter changes --- .../emails/adapters/{nodemailer.adapter.ts => smtp.adapter.ts} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename examples/common_nestjs_remix/apps/api/src/common/emails/adapters/{nodemailer.adapter.ts => smtp.adapter.ts} (94%) diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/nodemailer.adapter.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/smtp.adapter.ts similarity index 94% rename from examples/common_nestjs_remix/apps/api/src/common/emails/adapters/nodemailer.adapter.ts rename to examples/common_nestjs_remix/apps/api/src/common/emails/adapters/smtp.adapter.ts index 13ff2a2..40157be 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/nodemailer.adapter.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/smtp.adapter.ts @@ -5,7 +5,7 @@ import { Email } from "../email.interface"; import { EmailAdapter } from "./email.adapter"; @Injectable() -export class NodemailerAdapter extends EmailAdapter { +export class SmtpAdapter extends EmailAdapter { private transporter: nodemailer.Transporter; constructor(private configService: ConfigService) { From 0e6fe0f6e72e4302a42f0b4f1b398852371d9eeb Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 30 Jul 2024 13:10:23 +0200 Subject: [PATCH 12/23] refactor: update email interface and AuthService tests --- .../api/src/auth/__tests__/auth.service.spec.ts | 11 +---------- .../api/src/common/emails/email.interface.ts | 12 +++++++++--- .../emails/factory/email-adapters.factory.ts | 17 ++++++++++++----- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts b/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts index cdaf014..4dcc04a 100644 --- a/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts +++ b/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts @@ -16,22 +16,13 @@ import hashPassword from "src/common/helpers/hashPassword"; import { truncateAllTables } from "test/helpers/test-helpers"; import { EmailTestingAdapter } from "test/helpers/test-email.adapter"; -const mockEmailTestingAdapter = new EmailTestingAdapter(); - -jest.mock("../../common/emails/emails.service", () => ({ - EmailService: jest.fn().mockImplementation(() => ({ - sendEmail: jest - .fn() - .mockImplementation((email) => mockEmailTestingAdapter.sendMail(email)), - })), -})); - describe("AuthService", () => { let testContext: TestContext; let authService: AuthService; let jwtService: JwtService; let db: DatabasePg; let userFactory: ReturnType; + let emailAdapter: EmailTestingAdapter; beforeAll(async () => { testContext = await createUnitTest(); diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/email.interface.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/email.interface.ts index 28c1399..cbd0949 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/email.interface.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/email.interface.ts @@ -1,7 +1,13 @@ -export interface Email { +interface BaseEmail { to: string; from: string; subject: string; - text?: string; - html?: string; } + +type RequireAtLeastOne = { + [K in keyof T]-?: Required> & + Partial>>; +}[keyof T]; + +export type Email = RequireAtLeastOne<{ text: string; html: string }> & + BaseEmail; diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts index 67972f9..9f8a47d 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts @@ -1,10 +1,11 @@ import { Injectable } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; +import { EmailConfigSchema } from "src/common/configuration/email"; +import { EmailTestingAdapter } from "test/helpers/test-email.adapter"; +import { match, P } from "ts-pattern"; import { EmailAdapter } from "../adapters/email.adapter"; -import { NodemailerAdapter } from "../adapters/nodemailer.adapter"; import { LocalAdapter } from "../adapters/local.adapter"; -import { match, P } from "ts-pattern"; -import { EmailConfigSchema } from "src/common/configuration/email"; +import { SmtpAdapter } from "../adapters/smtp.adapter"; import { AWSSESAdapter } from "../adapters/ses.adapter"; type AdapterType = EmailConfigSchema["EMAIL_ADAPTER"]; @@ -14,16 +15,22 @@ export class EmailAdapterFactory { constructor( private configService: ConfigService, private localAdapter: LocalAdapter, - private nodemailerAdapter: NodemailerAdapter, + private smtpAdapter: SmtpAdapter, private awsSesAdapter: AWSSESAdapter, + private emailTestAdapter: EmailTestingAdapter, ) {} createAdapter(): EmailAdapter { const adapterType = this.configService.get("EMAIL_ADAPTER"); + const env = this.configService.get("NODE_ENV"); + + if (env === "test") { + return this.emailTestAdapter; + } return match(adapterType) .with("mailhog", () => this.localAdapter) - .with("smtp", () => this.nodemailerAdapter) + .with("smtp", () => this.smtpAdapter) .with("ses", () => this.awsSesAdapter) .with(P.nullish, () => { throw new Error("EMAIL_ADAPTER is not defined in configuration"); From 7f031e537c385513541783832d7b2be2e758f166 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 30 Jul 2024 13:10:24 +0200 Subject: [PATCH 13/23] test: refactor AuthService tests to use EmailTestingAdapter --- .../apps/api/src/auth/__tests__/auth.service.spec.ts | 8 ++++---- .../apps/api/src/common/emails/emails.module.ts | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts b/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts index 4dcc04a..d1aecf2 100644 --- a/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts +++ b/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts @@ -30,12 +30,12 @@ describe("AuthService", () => { jwtService = testContext.module.get(JwtService); db = testContext.db; userFactory = createUserFactory(db); + emailAdapter = testContext.module.get(EmailTestingAdapter); }, 30000); afterEach(async () => { await truncateAllTables(db); - mockEmailTestingAdapter.resetEmailOverride(); - mockEmailTestingAdapter.clearEmails(); + emailAdapter.clearEmails(); }); describe("register", () => { @@ -71,14 +71,14 @@ describe("AuthService", () => { const text = "General Kenobi"; const html = "You are a bold one"; - mockEmailTestingAdapter.setEmailOverride({ + emailAdapter.setEmailOverride({ subject, text, html, }); await authService.register(user.email, password); - const lastEmail = mockEmailTestingAdapter.getLastEmail(); + const lastEmail = emailAdapter.getLastEmail(); expect(lastEmail).toBeDefined(); expect(lastEmail?.to).toBe(user.email); diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts index 206208f..a49113a 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts @@ -1,20 +1,22 @@ import { Module } from "@nestjs/common"; import { ConfigModule } from "@nestjs/config"; import { EmailAdapter } from "./adapters/email.adapter"; -import { NodemailerAdapter } from "./adapters/nodemailer.adapter"; +import { SmtpAdapter } from "./adapters/smtp.adapter"; import { LocalAdapter } from "./adapters/local.adapter"; import { EmailAdapterFactory } from "./factory/email-adapters.factory"; import { EmailService } from "./emails.service"; import { AWSSESAdapter } from "./adapters/ses.adapter"; +import { EmailTestingAdapter } from "test/helpers/test-email.adapter"; @Module({ imports: [ConfigModule], providers: [ EmailService, - NodemailerAdapter, + SmtpAdapter, LocalAdapter, AWSSESAdapter, EmailAdapterFactory, + EmailTestingAdapter, { provide: EmailAdapter, useFactory: (factory: EmailAdapterFactory) => factory.createAdapter(), From 8d1dcdc9945f7019db4ab34433c7ce3d15f7f19e Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 30 Jul 2024 15:07:16 +0200 Subject: [PATCH 14/23] feat: add and use EmailAdapter in tests --- .../apps/api/src/auth/__tests__/auth.service.spec.ts | 3 ++- .../common_nestjs_remix/apps/api/test/create-unit-test.ts | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts b/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts index d1aecf2..1fa71ef 100644 --- a/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts +++ b/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts @@ -15,6 +15,7 @@ import { omit } from "lodash"; import hashPassword from "src/common/helpers/hashPassword"; import { truncateAllTables } from "test/helpers/test-helpers"; import { EmailTestingAdapter } from "test/helpers/test-email.adapter"; +import { EmailAdapter } from "src/common/emails/adapters/email.adapter"; describe("AuthService", () => { let testContext: TestContext; @@ -30,7 +31,7 @@ describe("AuthService", () => { jwtService = testContext.module.get(JwtService); db = testContext.db; userFactory = createUserFactory(db); - emailAdapter = testContext.module.get(EmailTestingAdapter); + emailAdapter = testContext.module.get(EmailAdapter); }, 30000); afterEach(async () => { diff --git a/examples/common_nestjs_remix/apps/api/test/create-unit-test.ts b/examples/common_nestjs_remix/apps/api/test/create-unit-test.ts index 4dd0719..93d948b 100644 --- a/examples/common_nestjs_remix/apps/api/test/create-unit-test.ts +++ b/examples/common_nestjs_remix/apps/api/test/create-unit-test.ts @@ -4,6 +4,8 @@ import { StartedTestContainer } from "testcontainers"; import { AppModule } from "../src/app.module"; import { DatabasePg } from "../src/common"; import { setupTestDatabase } from "./test-database"; +import { EmailAdapter } from "src/common/emails/adapters/email.adapter"; +import { EmailTestingAdapter } from "./helpers/test-email.adapter"; export interface TestContext { module: TestingModule; @@ -22,7 +24,10 @@ export async function createUnitTest( const module: TestingModule = await Test.createTestingModule({ imports: [AppModule], providers: [...customProviders], - }).compile(); + }) + .overrideProvider(EmailAdapter) + .useClass(EmailTestingAdapter) + .compile(); const teardown = async () => { if (container) { From 50282dc02050db27a6afb3ce2f3914726c0825b0 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Tue, 30 Jul 2024 15:07:16 +0200 Subject: [PATCH 15/23] feat: update EmailAdapterFactory to dynamically create email adapter --- .../emails/factory/email-adapters.factory.ts | 23 +++++++------------ .../api/test/helpers/test-email.adapter.ts | 4 ---- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts index 9f8a47d..1c03c39 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts @@ -1,42 +1,35 @@ import { Injectable } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import { EmailConfigSchema } from "src/common/configuration/email"; -import { EmailTestingAdapter } from "test/helpers/test-email.adapter"; import { match, P } from "ts-pattern"; import { EmailAdapter } from "../adapters/email.adapter"; import { LocalAdapter } from "../adapters/local.adapter"; import { SmtpAdapter } from "../adapters/smtp.adapter"; import { AWSSESAdapter } from "../adapters/ses.adapter"; +import { ModuleRef } from "@nestjs/core"; type AdapterType = EmailConfigSchema["EMAIL_ADAPTER"]; @Injectable() export class EmailAdapterFactory { constructor( + private moduleRef: ModuleRef, private configService: ConfigService, - private localAdapter: LocalAdapter, - private smtpAdapter: SmtpAdapter, - private awsSesAdapter: AWSSESAdapter, - private emailTestAdapter: EmailTestingAdapter, ) {} createAdapter(): EmailAdapter { const adapterType = this.configService.get("EMAIL_ADAPTER"); - const env = this.configService.get("NODE_ENV"); - - if (env === "test") { - return this.emailTestAdapter; - } - - return match(adapterType) - .with("mailhog", () => this.localAdapter) - .with("smtp", () => this.smtpAdapter) - .with("ses", () => this.awsSesAdapter) + const adapter = match(adapterType) + .with("mailhog", () => LocalAdapter) + .with("smtp", () => SmtpAdapter) + .with("ses", () => AWSSESAdapter) .with(P.nullish, () => { throw new Error("EMAIL_ADAPTER is not defined in configuration"); }) .otherwise((type) => { throw new Error(`Unknown email adapter type: ${type}`); }); + + return this.moduleRef.get(adapter, { strict: false }); } } diff --git a/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts b/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts index 8f625df..18b42bc 100644 --- a/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts +++ b/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts @@ -17,10 +17,6 @@ export class EmailTestingAdapter extends EmailAdapter { this.emailOverride = override; } - resetEmailOverride(): void { - this.emailOverride = null; - } - getAllEmails(): Email[] { return this.sentEmails; } From 7e9485e461ad2c94ba053a763880ca6d4a0e1dd0 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Wed, 31 Jul 2024 10:03:21 +0200 Subject: [PATCH 16/23] feat: add config validation for email and database --- .../apps/api/src/common/configuration/aws.ts | 4 ++-- .../apps/api/src/common/configuration/database.ts | 6 ++++-- .../apps/api/src/common/configuration/email.ts | 3 +-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/common_nestjs_remix/apps/api/src/common/configuration/aws.ts b/examples/common_nestjs_remix/apps/api/src/common/configuration/aws.ts index 9593391..4c9d8de 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/configuration/aws.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/configuration/aws.ts @@ -1,6 +1,6 @@ import { registerAs } from "@nestjs/config"; import { Static, Type } from "@sinclair/typebox"; -import { Value } from "@sinclair/typebox/value"; +import { configValidator } from "src/utils/configValidator"; const schema = Type.Object({ AWS_REGION: Type.String(), @@ -17,5 +17,5 @@ export default registerAs("aws", (): AWSConfigSchema => { AWS_SECRET_ACCESS_KEY: process.env.AWS_SECRET_ACCESS_KEY, }; - return Value.Decode(schema, values); + return validateAwsConfig(values); }); diff --git a/examples/common_nestjs_remix/apps/api/src/common/configuration/database.ts b/examples/common_nestjs_remix/apps/api/src/common/configuration/database.ts index d555fe0..952558f 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/configuration/database.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/configuration/database.ts @@ -1,6 +1,6 @@ import { registerAs } from "@nestjs/config"; import { Static, Type } from "@sinclair/typebox"; -import { Value } from "@sinclair/typebox/value"; +import { configValidator } from "src/utils/configValidator"; const schema = Type.Object({ url: Type.String(), @@ -8,10 +8,12 @@ const schema = Type.Object({ type DatabaseConfig = Static; +const validateDatabaseConfig = configValidator(schema); + export default registerAs("database", (): DatabaseConfig => { const values = { url: process.env.DATABASE_URL, }; - return Value.Decode(schema, values); + return validateDatabaseConfig(values); }); diff --git a/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts index 4f93b24..db7d592 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts @@ -1,13 +1,12 @@ import { registerAs } from "@nestjs/config"; import { Static, Type } from "@sinclair/typebox"; -import { Value } from "@sinclair/typebox/value"; +import { configValidator } from "src/utils/configValidator"; const schema = Type.Object({ SMTP_HOST: Type.String(), SMTP_PORT: Type.Number(), SMTP_USER: Type.String(), SMTP_PASSWORD: Type.String(), - USE_MAILHOG: Type.Boolean(), EMAIL_ADAPTER: Type.Union([ Type.Literal("mailhog"), Type.Literal("smtp"), From 5c6fc6bbfd4e67954c42d66dd9f523728b0e44b9 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Wed, 31 Jul 2024 10:03:22 +0200 Subject: [PATCH 17/23] feat: refactor email configuration to use configValidator --- .../apps/api/src/common/configuration/aws.ts | 2 ++ .../apps/api/src/common/configuration/email.ts | 7 ++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/common_nestjs_remix/apps/api/src/common/configuration/aws.ts b/examples/common_nestjs_remix/apps/api/src/common/configuration/aws.ts index 4c9d8de..8efe118 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/configuration/aws.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/configuration/aws.ts @@ -10,6 +10,8 @@ const schema = Type.Object({ type AWSConfigSchema = Static; +const validateAwsConfig = configValidator(schema); + export default registerAs("aws", (): AWSConfigSchema => { const values = { AWS_REGION: process.env.AWS_REGION, diff --git a/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts index db7d592..c6b1fac 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/configuration/email.ts @@ -16,15 +16,16 @@ const schema = Type.Object({ export type EmailConfigSchema = Static; +const valdateEmailConfig = configValidator(schema); + export default registerAs("email", (): EmailConfigSchema => { const values = { SMTP_HOST: process.env.SMTP_HOST, - SMTP_PORT: parseInt(process.env.SMTP_PORT ?? "465", 10), + SMTP_PORT: parseInt(process.env.SMTP_PORT || "465", 10), SMTP_USER: process.env.SMTP_USER, SMTP_PASSWORD: process.env.SMTP_PASSWORD, - USE_MAILHOG: process.env.USE_MAILHOG === "true", EMAIL_ADAPTER: process.env.EMAIL_ADAPTER, }; - return Value.Decode(schema, values); + return valdateEmailConfig(values); }); From 086c024059c9fd73aee76ae29b98f82fca263fe0 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Wed, 31 Jul 2024 10:03:23 +0200 Subject: [PATCH 18/23] feat: create configValidator for validating configuration --- .../common/emails/adapters/smtp.adapter.ts | 28 +++++++++++++------ .../emails/factory/email-adapters.factory.ts | 4 +-- .../apps/api/src/utils/configValidator.ts | 19 +++++++++++++ .../api/test/helpers/test-email.adapter.ts | 2 ++ 4 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 examples/common_nestjs_remix/apps/api/src/utils/configValidator.ts diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/smtp.adapter.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/smtp.adapter.ts index 40157be..8c1aef5 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/smtp.adapter.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/adapters/smtp.adapter.ts @@ -10,22 +10,32 @@ export class SmtpAdapter extends EmailAdapter { constructor(private configService: ConfigService) { super(); - this.transporter = nodemailer.createTransport(this.getNodemailerOptions()); - } - - async sendMail(email: Email): Promise { - await this.transporter.sendMail(email); + const config = this.getNodemailerOptions(); + this.transporter = nodemailer.createTransport(config); } private getNodemailerOptions() { + const host = this.configService.get("email.SMTP_HOST"); + const port = this.configService.get("email.SMTP_PORT"); + const user = this.configService.get("email.SMTP_USER"); + const pass = this.configService.get("email.SMTP_PASSWORD"); + + if (!host || !port || !user || !pass) { + throw new Error("Missing SMTP configuration"); + } + return { - host: this.configService.get("email.SMTP_HOST"), - port: this.configService.get("email.SMTP_PORT"), + host, + port, secure: true, auth: { - user: this.configService.get("email.SMTP_USER"), - pass: this.configService.get("email.SMTP_PASSWORD"), + user, + pass, }, }; } + + async sendMail(email: Email): Promise { + await this.transporter.sendMail(email); + } } diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts index 1c03c39..aa745c1 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/factory/email-adapters.factory.ts @@ -17,7 +17,7 @@ export class EmailAdapterFactory { private configService: ConfigService, ) {} - createAdapter(): EmailAdapter { + async createAdapter(): Promise { const adapterType = this.configService.get("EMAIL_ADAPTER"); const adapter = match(adapterType) .with("mailhog", () => LocalAdapter) @@ -30,6 +30,6 @@ export class EmailAdapterFactory { throw new Error(`Unknown email adapter type: ${type}`); }); - return this.moduleRef.get(adapter, { strict: false }); + return await this.moduleRef.create(adapter); } } diff --git a/examples/common_nestjs_remix/apps/api/src/utils/configValidator.ts b/examples/common_nestjs_remix/apps/api/src/utils/configValidator.ts new file mode 100644 index 0000000..c982fd6 --- /dev/null +++ b/examples/common_nestjs_remix/apps/api/src/utils/configValidator.ts @@ -0,0 +1,19 @@ +import { Static, TObject } from "@sinclair/typebox"; +import { TypeCompiler } from "@sinclair/typebox/compiler"; + +export function configValidator(schema: T) { + type ConfigSchema = Static; + const validator = TypeCompiler.Compile(schema); + + return function validateConfig( + values: Record, + ): ConfigSchema { + if (validator.Check(values)) { + return values; + } else { + const errors = [...validator.Errors(values)]; + console.error("Configuration errors:", errors); + throw new Error("Invalid configuration"); + } + }; +} diff --git a/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts b/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts index 18b42bc..da03d92 100644 --- a/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts +++ b/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts @@ -1,7 +1,9 @@ +import { Injectable } from "@nestjs/common"; import { EmailAdapter } from "../../src/common/emails/adapters/email.adapter"; import { Email } from "../../src/common/emails/email.interface"; import { last } from "lodash"; +@Injectable() export class EmailTestingAdapter extends EmailAdapter { private sentEmails: Email[] = []; private emailOverride: Partial | null = null; From c17047e82c0d1fd634d964f7d2b97f84ae787b16 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Wed, 31 Jul 2024 10:03:23 +0200 Subject: [PATCH 19/23] feat: add config validation for jwt --- .../apps/api/src/common/configuration/jwt.ts | 6 ++++-- .../apps/api/src/common/emails/emails.module.ts | 10 +--------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/examples/common_nestjs_remix/apps/api/src/common/configuration/jwt.ts b/examples/common_nestjs_remix/apps/api/src/common/configuration/jwt.ts index 2607ac7..65da10f 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/configuration/jwt.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/configuration/jwt.ts @@ -1,6 +1,6 @@ import { registerAs } from "@nestjs/config"; import { Static, Type } from "@sinclair/typebox"; -import { Value } from "@sinclair/typebox/value"; +import { configValidator } from "src/utils/configValidator"; const schema = Type.Object({ secret: Type.String(), @@ -10,6 +10,8 @@ const schema = Type.Object({ type JWTConfig = Static; +const valdateJWTConfig = configValidator(schema); + export default registerAs("jwt", (): JWTConfig => { const values = { secret: process.env.JWT_SECRET, @@ -17,5 +19,5 @@ export default registerAs("jwt", (): JWTConfig => { expirationTime: process.env.JWT_EXPIRATION_TIME, }; - return Value.Decode(schema, values); + return valdateJWTConfig(values); }); diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts index a49113a..f9aa5c8 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/emails.module.ts @@ -1,22 +1,14 @@ import { Module } from "@nestjs/common"; import { ConfigModule } from "@nestjs/config"; import { EmailAdapter } from "./adapters/email.adapter"; -import { SmtpAdapter } from "./adapters/smtp.adapter"; -import { LocalAdapter } from "./adapters/local.adapter"; -import { EmailAdapterFactory } from "./factory/email-adapters.factory"; import { EmailService } from "./emails.service"; -import { AWSSESAdapter } from "./adapters/ses.adapter"; -import { EmailTestingAdapter } from "test/helpers/test-email.adapter"; +import { EmailAdapterFactory } from "./factory/email-adapters.factory"; @Module({ imports: [ConfigModule], providers: [ EmailService, - SmtpAdapter, - LocalAdapter, - AWSSESAdapter, EmailAdapterFactory, - EmailTestingAdapter, { provide: EmailAdapter, useFactory: (factory: EmailAdapterFactory) => factory.createAdapter(), From 40be8e96be93a6bcc9a2b52295c4aff64d8f42a3 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Wed, 31 Jul 2024 10:18:56 +0200 Subject: [PATCH 20/23] feat: update turbo.json for build and lint tasks --- examples/common_nestjs_remix/turbo.json | 28 ++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/examples/common_nestjs_remix/turbo.json b/examples/common_nestjs_remix/turbo.json index 2f62659..6e40b19 100644 --- a/examples/common_nestjs_remix/turbo.json +++ b/examples/common_nestjs_remix/turbo.json @@ -1,18 +1,36 @@ { "$schema": "https://turbo.build/schema.json", - "globalDependencies": ["**/.env.*local"], + "globalDependencies": [ + "**/.env.*local" + ], "ui": "tui", "tasks": { "build": { - "dependsOn": ["^build"], - "outputs": [".next/**", "!.next/cache/**"] + "dependsOn": [ + "^build" + ], + "outputs": [ + ".next/**", + "!.next/cache/**" + ] }, "lint": { - "dependsOn": ["^lint"] + "dependsOn": [ + "^lint" + ] }, "dev": { "cache": false, - "persistent": true + "persistent": true, + "dependsOn": [ + "@repo/email-templates#build" + ] + }, + "@repo/email-templates#build": { + "cache": false, + "outputs": [ + "dist/**" + ] } } } From af86c9832338fc4c90375a19541dcaeb8e8c4cb1 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Wed, 31 Jul 2024 10:50:06 +0200 Subject: [PATCH 21/23] chore: add clean option to tsup configuration --- .../common_nestjs_remix/packages/email-templates/tsup.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/common_nestjs_remix/packages/email-templates/tsup.config.ts b/examples/common_nestjs_remix/packages/email-templates/tsup.config.ts index 7f0eda1..088d0ef 100644 --- a/examples/common_nestjs_remix/packages/email-templates/tsup.config.ts +++ b/examples/common_nestjs_remix/packages/email-templates/tsup.config.ts @@ -6,6 +6,7 @@ export default defineConfig(async (options: Options) => { entry: ["./src/index.ts"], format: ["cjs", "esm"], plugins: [tsupPlugin()], + clean: true, dts: true, ...options, }; From fc3696c39c280098f5027b82fa999df2926140d9 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Thu, 1 Aug 2024 14:57:57 +0200 Subject: [PATCH 22/23] chore: update package.json scripts --- examples/common_nestjs_remix/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/common_nestjs_remix/package.json b/examples/common_nestjs_remix/package.json index fb97564..3e7d622 100644 --- a/examples/common_nestjs_remix/package.json +++ b/examples/common_nestjs_remix/package.json @@ -7,7 +7,6 @@ "lint": "turbo lint", "format": "prettier --write \"**/*.{ts,tsx,md}\"", "generate:client": "pnpm run --filter=web generate:client", - "generate:emails": "pnpm run --filter=email-templates build", "db:generate": "pnpm run --filter=api db:generate", "db:migrate": "pnpm run --filter=api db:migrate" }, From 31bafb80e01b5d467496e64bbd7cefc86ee1a1aa Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Thu, 1 Aug 2024 15:54:14 +0200 Subject: [PATCH 23/23] refactor: update email interface and email sending test --- .../src/auth/__tests__/auth.service.spec.ts | 20 ++++--------------- .../api/src/common/emails/email.interface.ts | 16 ++++++--------- .../api/test/helpers/test-email.adapter.ts | 10 +--------- 3 files changed, 11 insertions(+), 35 deletions(-) diff --git a/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts b/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts index 1fa71ef..c3960b0 100644 --- a/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts +++ b/examples/common_nestjs_remix/apps/api/src/auth/__tests__/auth.service.spec.ts @@ -68,24 +68,12 @@ describe("AuthService", () => { it("should send a welcome email after successful registration", async () => { const user = userFactory.build(); const password = "password123"; - const subject = "Hello there!"; - const text = "General Kenobi"; - const html = "You are a bold one"; - - emailAdapter.setEmailOverride({ - subject, - text, - html, - }); - await authService.register(user.email, password); - const lastEmail = emailAdapter.getLastEmail(); + const allEmails = emailAdapter.getAllEmails(); - expect(lastEmail).toBeDefined(); - expect(lastEmail?.to).toBe(user.email); - expect(lastEmail?.subject).toBe(subject); - expect(lastEmail?.text).toBe(text); - expect(lastEmail?.html).toBe(html); + expect(allEmails).toHaveLength(0); + await authService.register(user.email, password); + expect(allEmails).toHaveLength(1); }); it("should throw ConflictException if user already exists", async () => { diff --git a/examples/common_nestjs_remix/apps/api/src/common/emails/email.interface.ts b/examples/common_nestjs_remix/apps/api/src/common/emails/email.interface.ts index cbd0949..90385b0 100644 --- a/examples/common_nestjs_remix/apps/api/src/common/emails/email.interface.ts +++ b/examples/common_nestjs_remix/apps/api/src/common/emails/email.interface.ts @@ -1,13 +1,9 @@ -interface BaseEmail { +export type Email = { to: string; from: string; subject: string; -} - -type RequireAtLeastOne = { - [K in keyof T]-?: Required> & - Partial>>; -}[keyof T]; - -export type Email = RequireAtLeastOne<{ text: string; html: string }> & - BaseEmail; +} & ( + | { html: string; text?: never } + | { text: string; html?: never } + | { text: string; html: string } +); diff --git a/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts b/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts index da03d92..61274af 100644 --- a/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts +++ b/examples/common_nestjs_remix/apps/api/test/helpers/test-email.adapter.ts @@ -6,17 +6,9 @@ import { last } from "lodash"; @Injectable() export class EmailTestingAdapter extends EmailAdapter { private sentEmails: Email[] = []; - private emailOverride: Partial | null = null; async sendMail(email: Email): Promise { - const finalEmail = this.emailOverride - ? { ...email, ...this.emailOverride } - : email; - this.sentEmails.push(finalEmail); - } - - setEmailOverride(override: Partial): void { - this.emailOverride = override; + this.sentEmails.push(email); } getAllEmails(): Email[] {