From a0d0d1276e4f676195df909529584e5df8faa043 Mon Sep 17 00:00:00 2001 From: Aleksandr Chernigin Date: Sun, 29 Mar 2026 15:47:34 +0300 Subject: [PATCH 1/4] feat: add backend server --- apps/backend/eslint.config.mjs | 13 + apps/backend/nest-cli.json | 8 + apps/backend/package.json | 36 + apps/backend/scripts/generate-api-schemas.ts | 70 + .../backend}/scripts/generate-db-types.ts | 8 +- apps/backend/src/app.controller.ts | 11 + apps/backend/src/app.module.ts | 13 + apps/backend/src/auth/auth.guard.ts | 65 + apps/backend/src/auth/auth.module.ts | 16 + apps/backend/src/auth/public.decorator.ts | 4 + apps/backend/src/main.ts | 60 + .../supabase-client/supabase-client.module.ts | 41 + .../supabase-user-client.token.ts | 6 + apps/backend/src/supabase/supabase.module.ts | 9 + apps/backend/src/supabase/supabase.service.ts | 45 + .../src/types/database.types.public.ts | 10 + apps/backend/src/types/database.types.ts | 268 +++ apps/backend/src/user/dto/update-user.dto.ts | 60 + apps/backend/src/user/user.controller.ts | 51 + apps/backend/src/user/user.module.ts | 11 + apps/backend/src/user/user.service.ts | 32 + .../src/words/dto/add-translations.dto.ts | 25 + apps/backend/src/words/dto/create-word.dto.ts | 36 + .../src/words/dto/delete-translations.dto.ts | 19 + .../backend/src/words/dto/delete-words.dto.ts | 19 + apps/backend/src/words/dto/fetch-words.dto.ts | 99 + .../src/words/dto/update-words-status.dto.ts | 24 + apps/backend/src/words/words.controller.ts | 143 ++ apps/backend/src/words/words.module.ts | 11 + apps/backend/src/words/words.service.ts | 147 ++ apps/backend/tsconfig.json | 28 + apps/web/Dockerfile | 5 +- apps/web/package.json | 3 + apps/web/src/server/main.ts | 21 +- apps/web/src/server/middlewares/user.ts | 20 +- apps/web/src/server/shared/supabase.ts | 3 +- apps/web/src/server/typings.d.ts | 4 +- apps/web/src/shared/project-config.ts | 8 +- apps/web/src/ui/entities/user/types.ts | 4 +- apps/web/src/ui/entities/word/constants.ts | 7 +- .../web/src/ui/entities/word/fields/words.tsx | 14 +- .../word/mutations/useWordMutations.tsx | 15 +- .../ui/entities/word/ui/WordStatusIcon.tsx | 14 +- .../entities/word/ui/WordStatusSelector.tsx | 12 +- .../ui/LearningLanguageSelector.tsx | 1 - .../ui/ThemeSelector/constants.ts | 4 +- .../words/table/hooks/useWordsTableColumns.ts | 6 +- .../words/table/ui/WordsTableFilters/lib.ts | 4 +- .../office/settings/ui/OfficeSettingsPage.tsx | 9 +- apps/web/src/ui/shared/services/api/index.ts | 2 +- apps/web/src/ui/shared/services/api/sdk.ts | 3 +- .../src/ui/shared/services/api/supabase.ts | 11 +- .../stores/SupabaseAuthProvider/constants.ts | 5 +- .../WordsTableActionsPanel.tsx | 4 +- .../WordsTableWithFilters.tsx | 11 +- apps/web/vite.config.ts | 6 + packages/api/scripts/tsconfig.json | 6 - packages/api/src/database.types.public.ts | 9 +- packages/api/src/index.ts | 5 +- packages/api/src/schemas/api.ts | 654 ++++++ packages/api/src/schemas/openapi.json | 1014 +++++++++ packages/api/src/sdk/client.ts | 89 + packages/api/src/sdk/index.ts | 2 - packages/api/src/sdk/sdk.ts | 75 +- packages/api/src/sdk/user/index.ts | 1 - packages/api/src/sdk/user/types.ts | 8 - packages/api/src/sdk/user/user.ts | 28 - packages/api/src/sdk/words/index.ts | 1 - packages/api/src/sdk/words/types.ts | 53 - packages/api/src/sdk/words/words.ts | 110 - packages/api/src/supabase.ts | 5 - pnpm-lock.yaml | 1933 ++++++++++++++++- test.ts | 122 ++ tsconfig.json | 5 +- 74 files changed, 5274 insertions(+), 430 deletions(-) create mode 100644 apps/backend/eslint.config.mjs create mode 100644 apps/backend/nest-cli.json create mode 100644 apps/backend/package.json create mode 100644 apps/backend/scripts/generate-api-schemas.ts rename {packages/api => apps/backend}/scripts/generate-db-types.ts (51%) create mode 100644 apps/backend/src/app.controller.ts create mode 100644 apps/backend/src/app.module.ts create mode 100644 apps/backend/src/auth/auth.guard.ts create mode 100644 apps/backend/src/auth/auth.module.ts create mode 100644 apps/backend/src/auth/public.decorator.ts create mode 100644 apps/backend/src/main.ts create mode 100644 apps/backend/src/supabase-client/supabase-client.module.ts create mode 100644 apps/backend/src/supabase-client/supabase-user-client.token.ts create mode 100644 apps/backend/src/supabase/supabase.module.ts create mode 100644 apps/backend/src/supabase/supabase.service.ts create mode 100644 apps/backend/src/types/database.types.public.ts create mode 100644 apps/backend/src/types/database.types.ts create mode 100644 apps/backend/src/user/dto/update-user.dto.ts create mode 100644 apps/backend/src/user/user.controller.ts create mode 100644 apps/backend/src/user/user.module.ts create mode 100644 apps/backend/src/user/user.service.ts create mode 100644 apps/backend/src/words/dto/add-translations.dto.ts create mode 100644 apps/backend/src/words/dto/create-word.dto.ts create mode 100644 apps/backend/src/words/dto/delete-translations.dto.ts create mode 100644 apps/backend/src/words/dto/delete-words.dto.ts create mode 100644 apps/backend/src/words/dto/fetch-words.dto.ts create mode 100644 apps/backend/src/words/dto/update-words-status.dto.ts create mode 100644 apps/backend/src/words/words.controller.ts create mode 100644 apps/backend/src/words/words.module.ts create mode 100644 apps/backend/src/words/words.service.ts create mode 100644 apps/backend/tsconfig.json delete mode 100644 packages/api/scripts/tsconfig.json create mode 100644 packages/api/src/schemas/api.ts create mode 100644 packages/api/src/schemas/openapi.json create mode 100644 packages/api/src/sdk/client.ts delete mode 100644 packages/api/src/sdk/user/index.ts delete mode 100644 packages/api/src/sdk/user/types.ts delete mode 100644 packages/api/src/sdk/user/user.ts delete mode 100644 packages/api/src/sdk/words/index.ts delete mode 100644 packages/api/src/sdk/words/types.ts delete mode 100644 packages/api/src/sdk/words/words.ts delete mode 100644 packages/api/src/supabase.ts create mode 100644 test.ts diff --git a/apps/backend/eslint.config.mjs b/apps/backend/eslint.config.mjs new file mode 100644 index 0000000..37c50d3 --- /dev/null +++ b/apps/backend/eslint.config.mjs @@ -0,0 +1,13 @@ +import rootConfig from "../../eslint.config.mjs"; + +export default [ + ...rootConfig, + { + files: ["**/*.ts"], + rules: { + // Отключаем правило, которое требует strictNullChecks, так как мы его включили + // но могут быть места, где нужно явно проверять на null/undefined + "@typescript-eslint/no-unnecessary-condition": "off", + }, + }, +]; diff --git a/apps/backend/nest-cli.json b/apps/backend/nest-cli.json new file mode 100644 index 0000000..f9aa683 --- /dev/null +++ b/apps/backend/nest-cli.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/nest-cli", + "collection": "@nestjs/schematics", + "sourceRoot": "src", + "compilerOptions": { + "deleteOutDir": true + } +} diff --git a/apps/backend/package.json b/apps/backend/package.json new file mode 100644 index 0000000..3e11335 --- /dev/null +++ b/apps/backend/package.json @@ -0,0 +1,36 @@ +{ + "name": "app-backend", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "nest build", + "start": "nest start", + "start:dev": "nest start --watch", + "start:prod": "node dist/main.js", + "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", + "typecheck": "tsc --noEmit", + "generate:api-schemas": "ts-node --project tsconfig.json scripts/generate-api-schemas.ts", + "generate-types": "ts-node ./scripts/generate-db-types.ts" + }, + "dependencies": { + "@nestjs/common": "^10.4.8", + "@nestjs/core": "^10.4.8", + "@nestjs/platform-express": "^10.4.8", + "@nestjs/swagger": "^7.4.2", + "@supabase/supabase-js": "2.49.4", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.1", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@nestjs/cli": "^10.4.8", + "@nestjs/schematics": "^10.1.1", + "@types/express": "^5.0.6", + "@types/node": "^22.15.29", + "dotenv": "^16.5.0", + "openapi-typescript": "^7.4.3", + "ts-node": "11.0.0-beta.1", + "typescript": "~5.7.2" + } +} diff --git a/apps/backend/scripts/generate-api-schemas.ts b/apps/backend/scripts/generate-api-schemas.ts new file mode 100644 index 0000000..e49ae2a --- /dev/null +++ b/apps/backend/scripts/generate-api-schemas.ts @@ -0,0 +1,70 @@ +import * as path from "node:path"; +import * as fs from "node:fs"; +import { execSync } from "node:child_process"; +import * as dotenv from "dotenv"; + +// Загрузить .env файл из корня монорепы +const envPath = path.resolve(__dirname, "../../../.env"); +dotenv.config({ path: envPath }); + +const openApiJsonPath = path.resolve(__dirname, "../../../packages/api/src/schemas/openapi.json"); +const apiTypesPath = path.resolve(__dirname, "../../../packages/api/src/schemas/api.ts"); + +console.log("Generating OpenAPI schema..."); + +// Убедиться, что директория существует +const schemasDir = path.dirname(openApiJsonPath); +if (!fs.existsSync(schemasDir)) { + fs.mkdirSync(schemasDir, { recursive: true }); +} + +// Установить переменную окружения для генерации схемы +const env = { + ...process.env, + GENERATE_API_SCHEMA: "true", + PORT: "3002", // Использовать другой порт для генерации +}; + +try { + // Запустить приложение в режиме генерации + // Приложение создаст openapi.json и завершится с exit(0) + execSync(`ts-node --project tsconfig.json src/main.ts`, { + stdio: "inherit", + cwd: path.resolve(__dirname, ".."), + env, + }); +} catch (error: any) { + // Проверить, был ли создан файл (приложение завершится с exit(0)) + if (error.status === 0 && fs.existsSync(openApiJsonPath)) { + console.log("OpenAPI schema generated successfully"); + } else if (!fs.existsSync(openApiJsonPath)) { + console.error("Failed to generate OpenAPI schema"); + console.error("Error:", error.message); + console.error("\nMake sure:"); + console.error("1. Backend dependencies are installed (npm install)"); + console.error("2. Backend can start without errors"); + console.error("3. Swagger is properly configured"); + process.exit(1); + } +} + +// Проверить, что файл создан +if (!fs.existsSync(openApiJsonPath)) { + console.error(`OpenAPI schema file not found at ${openApiJsonPath}`); + console.error("Make sure the backend application can start and generate the schema"); + process.exit(1); +} + +console.log("Generating TypeScript types from OpenAPI schema..."); + +// Использовать openapi-typescript для генерации типов +try { + execSync(`npx openapi-typescript ${openApiJsonPath} -o ${apiTypesPath}`, { + stdio: "inherit", + }); + console.log(`TypeScript types generated at ${apiTypesPath}`); +} catch (error) { + console.error("Failed to generate TypeScript types from OpenAPI schema"); + console.error("Make sure openapi-typescript is installed"); + throw error; +} diff --git a/packages/api/scripts/generate-db-types.ts b/apps/backend/scripts/generate-db-types.ts similarity index 51% rename from packages/api/scripts/generate-db-types.ts rename to apps/backend/scripts/generate-db-types.ts index 6dc7b99..2e470d2 100644 --- a/packages/api/scripts/generate-db-types.ts +++ b/apps/backend/scripts/generate-db-types.ts @@ -1,10 +1,12 @@ import { execSync } from "node:child_process"; import * as path from "node:path"; +import * as fs from "node:fs"; import * as dotenv from "dotenv"; const envPath = path.resolve(__dirname, "../../../.env"); -const dbTypesPath = path.resolve(__dirname, "../src/database.types.ts"); +const dbTypesPath = path.resolve(__dirname, "../src/types/database.types.ts"); +const apiDbTypesPath = path.resolve(__dirname, "../../../packages/api/src/database.types.ts"); dotenv.config({ path: envPath }); @@ -15,3 +17,7 @@ execSync( stdio: "inherit", }, ); + +console.info(`Copying database.types.ts to packages/api/src/...`); +fs.copyFileSync(dbTypesPath, apiDbTypesPath); +console.info(`Database types copied successfully to packages/api/src/database.types.ts`); diff --git a/apps/backend/src/app.controller.ts b/apps/backend/src/app.controller.ts new file mode 100644 index 0000000..8f95c47 --- /dev/null +++ b/apps/backend/src/app.controller.ts @@ -0,0 +1,11 @@ +import { Controller, Get } from "@nestjs/common"; +import { Public } from "./auth/public.decorator"; + +@Controller() +export class AppController { + @Public() + @Get("health") + getHealth() { + return { status: "ok" }; + } +} diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts new file mode 100644 index 0000000..964f052 --- /dev/null +++ b/apps/backend/src/app.module.ts @@ -0,0 +1,13 @@ +import { Module } from "@nestjs/common"; +import { AppController } from "./app.controller"; +import { UserModule } from "./user/user.module"; +import { WordsModule } from "./words/words.module"; +import { SupabaseModule } from "./supabase/supabase.module"; +import { AuthModule } from "./auth/auth.module"; +import { SupabaseClientModule } from "./supabase-client/supabase-client.module"; + +@Module({ + imports: [SupabaseModule, AuthModule, SupabaseClientModule, UserModule, WordsModule], + controllers: [AppController], +}) +export class AppModule {} diff --git a/apps/backend/src/auth/auth.guard.ts b/apps/backend/src/auth/auth.guard.ts new file mode 100644 index 0000000..ae09d17 --- /dev/null +++ b/apps/backend/src/auth/auth.guard.ts @@ -0,0 +1,65 @@ +import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from "@nestjs/common"; +import { Reflector } from "@nestjs/core"; +import { Request } from "express"; +import { SupabaseService } from "../supabase/supabase.service"; +import { IS_PUBLIC_KEY } from "./public.decorator"; + +@Injectable() +export class AuthGuard implements CanActivate { + constructor( + private readonly supabaseService: SupabaseService, + private readonly reflector: Reflector, + ) {} + + async canActivate(context: ExecutionContext): Promise { + // Check if route is marked as public + const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ + context.getHandler(), + context.getClass(), + ]); + + if (isPublic) { + return true; + } + + const request = context.switchToHttp().getRequest(); + + const token = this.extractTokenFromHeader(request); + + if (!token) { + throw new UnauthorizedException("No token provided"); + } + + try { + const supabase = this.supabaseService.getClient(); + const { + data: { user }, + error, + } = await supabase.auth.getUser(token); + + if (error || !user) { + throw new UnauthorizedException("Invalid token"); + } + + // Add user and access token to request (token needed for Supabase RLS) + (request as any).user = { + id: user.id, + email: user.email, + }; + (request as any).accessToken = token; + + return true; + } catch (error) { + if (error instanceof UnauthorizedException) { + throw error; + } + throw new UnauthorizedException("Invalid token"); + } + } + + private extractTokenFromHeader(request: Request): string | undefined { + const [type, token] = request.headers.authorization?.split(" ") ?? []; + + return type === "Bearer" ? token : undefined; + } +} diff --git a/apps/backend/src/auth/auth.module.ts b/apps/backend/src/auth/auth.module.ts new file mode 100644 index 0000000..28c433d --- /dev/null +++ b/apps/backend/src/auth/auth.module.ts @@ -0,0 +1,16 @@ +import { Module } from "@nestjs/common"; +import { APP_GUARD } from "@nestjs/core"; +import { SupabaseModule } from "../supabase/supabase.module"; +import { AuthGuard } from "./auth.guard"; + +@Module({ + imports: [SupabaseModule], + exports: [SupabaseModule], + providers: [ + { + provide: APP_GUARD, + useClass: AuthGuard, + }, + ], +}) +export class AuthModule {} diff --git a/apps/backend/src/auth/public.decorator.ts b/apps/backend/src/auth/public.decorator.ts new file mode 100644 index 0000000..7beff6f --- /dev/null +++ b/apps/backend/src/auth/public.decorator.ts @@ -0,0 +1,4 @@ +import { SetMetadata } from "@nestjs/common"; + +export const IS_PUBLIC_KEY = "isPublic"; +export const Public = () => SetMetadata(IS_PUBLIC_KEY, true); diff --git a/apps/backend/src/main.ts b/apps/backend/src/main.ts new file mode 100644 index 0000000..2a3b441 --- /dev/null +++ b/apps/backend/src/main.ts @@ -0,0 +1,60 @@ +import path from "node:path"; +import { NestFactory } from "@nestjs/core"; +import { ValidationPipe } from "@nestjs/common"; +import { DocumentBuilder, SwaggerModule } from "@nestjs/swagger"; +import * as dotenv from "dotenv"; +import { AppModule } from "./app.module"; + +async function bootstrap() { + // Загрузить .env файл из корня монорепы + dotenv.config({ path: path.resolve(__dirname, "../../../../.env") }); + + const app = await NestFactory.create(AppModule); + app.setGlobalPrefix("api"); + app.enableCors({ + origin: true, + credentials: true, + }); + app.useGlobalPipes( + new ValidationPipe({ + transform: true, + whitelist: true, + forbidNonWhitelisted: false, + }), + ); + + // Swagger configuration + const config = new DocumentBuilder() + .setTitle("Languages Learner API") + .setDescription("API for Languages Learner application") + .setVersion("1.0") + .addBearerAuth() + .build(); + const document = SwaggerModule.createDocument(app, config); + SwaggerModule.setup("api/docs", app, document); + + // Export OpenAPI schema if GENERATE_API_SCHEMA env var is set + if (process.env.GENERATE_API_SCHEMA === "true") { + const fs = await import("node:fs"); + const openApiPath = path.resolve( + __dirname, + "../../../packages/api/src/schemas/openapi.json", + ); + // Ensure directory exists + const openApiDir = path.dirname(openApiPath); + if (!fs.existsSync(openApiDir)) { + fs.mkdirSync(openApiDir, { recursive: true }); + } + fs.writeFileSync(openApiPath, JSON.stringify(document, null, 2), "utf-8"); + console.log(`OpenAPI schema exported to ${openApiPath}`); + await app.close(); + process.exit(0); + } + + const port = process.env.PORT || 3001; + await app.listen(port); + console.log(`Backend server started at http://localhost:${port}`); + console.log(`Swagger docs available at http://localhost:${port}/api/docs`); +} + +bootstrap(); diff --git a/apps/backend/src/supabase-client/supabase-client.module.ts b/apps/backend/src/supabase-client/supabase-client.module.ts new file mode 100644 index 0000000..99872c8 --- /dev/null +++ b/apps/backend/src/supabase-client/supabase-client.module.ts @@ -0,0 +1,41 @@ +import { Global, Module, Scope, UnauthorizedException } from "@nestjs/common"; +import { REQUEST } from "@nestjs/core"; +import { SupabaseModule } from "../supabase/supabase.module"; +import { SupabaseService } from "../supabase/supabase.service"; +import { SUPABASE_USER_CLIENT } from "./supabase-user-client.token"; +import type { Request } from "express"; + +@Global() +@Module({ + imports: [SupabaseModule], + providers: [ + { + provide: SUPABASE_USER_CLIENT, + useFactory: (req: Request, supabaseService: SupabaseService) => { + // First, try to get token from req.accessToken (set by AuthGuard) + // If not available, extract from Authorization header directly + let token = (req as Request & { accessToken?: string }).accessToken; + + if (!token) { + // Extract token from Authorization header (same logic as AuthGuard) + const [type, extractedToken] = req.headers.authorization?.split(" ") ?? []; + if (type === "Bearer" && extractedToken) { + token = extractedToken; + } + } + + if (!token) { + throw new UnauthorizedException( + "No access token provided. Please include Authorization header with Bearer token.", + ); + } + + return supabaseService.getClientForUser(token); + }, + inject: [REQUEST, SupabaseService], + scope: Scope.REQUEST, + }, + ], + exports: [SUPABASE_USER_CLIENT], +}) +export class SupabaseClientModule {} diff --git a/apps/backend/src/supabase-client/supabase-user-client.token.ts b/apps/backend/src/supabase-client/supabase-user-client.token.ts new file mode 100644 index 0000000..930be82 --- /dev/null +++ b/apps/backend/src/supabase-client/supabase-user-client.token.ts @@ -0,0 +1,6 @@ +import type { SupabaseClient } from "@supabase/supabase-js"; +import type { ApiDatabase } from "../types/database.types.public"; + +export const SUPABASE_USER_CLIENT = Symbol("SUPABASE_USER_CLIENT"); + +export type SupabaseUserClient = SupabaseClient; diff --git a/apps/backend/src/supabase/supabase.module.ts b/apps/backend/src/supabase/supabase.module.ts new file mode 100644 index 0000000..b149ac5 --- /dev/null +++ b/apps/backend/src/supabase/supabase.module.ts @@ -0,0 +1,9 @@ +import { Global, Module } from "@nestjs/common"; +import { SupabaseService } from "./supabase.service"; + +@Global() +@Module({ + providers: [SupabaseService], + exports: [SupabaseService], +}) +export class SupabaseModule {} diff --git a/apps/backend/src/supabase/supabase.service.ts b/apps/backend/src/supabase/supabase.service.ts new file mode 100644 index 0000000..519f413 --- /dev/null +++ b/apps/backend/src/supabase/supabase.service.ts @@ -0,0 +1,45 @@ +import { Injectable } from "@nestjs/common"; +import { SupabaseClient, createClient } from "@supabase/supabase-js"; +import type { ApiDatabase } from "../types/database.types.public"; + +@Injectable() +export class SupabaseService { + private client: SupabaseClient; + private readonly supabaseUrl: string; + private readonly supabaseKey: string; + + constructor() { + this.supabaseUrl = + process.env.SUPABASE_PROJECT_URL || process.env.VITE_SUPABASE_PROJECT_URL || ""; + this.supabaseKey = + process.env.SUPABASE_PROJECT_KEY || process.env.VITE_SUPABASE_PROJECT_KEY || ""; + + if (!this.supabaseUrl || !this.supabaseKey) { + throw new Error("Supabase URL and Key must be provided"); + } + + this.client = createClient(this.supabaseUrl, this.supabaseKey); + } + + getClient(): SupabaseClient { + return this.client; + } + + /** + * Returns a Supabase client configured with the user's JWT. + * Use this for queries that must respect RLS policies (user can only access their own data). + * Uses anon key so RLS applies; service role key bypasses RLS. + */ + getClientForUser(accessToken: string): SupabaseClient { + const anonKey = + process.env.SUPABASE_ANON_KEY || + process.env.VITE_SUPABASE_PROJECT_KEY || + this.supabaseKey; + + return createClient(this.supabaseUrl, anonKey, { + global: { + headers: { Authorization: `Bearer ${accessToken}` }, + }, + }); + } +} diff --git a/apps/backend/src/types/database.types.public.ts b/apps/backend/src/types/database.types.public.ts new file mode 100644 index 0000000..e2d5719 --- /dev/null +++ b/apps/backend/src/types/database.types.public.ts @@ -0,0 +1,10 @@ +export type { + Database as ApiDatabase, + Tables as ApiTables, + TablesInsert as ApiTablesInsert, + TablesUpdate as ApiTablesUpdate, + Enums as ApiEnums, + CompositeTypes as ApiCompositeType, +} from "./database.types"; + +export { Constants as ApiConstants } from "./database.types"; diff --git a/apps/backend/src/types/database.types.ts b/apps/backend/src/types/database.types.ts new file mode 100644 index 0000000..598dcb1 --- /dev/null +++ b/apps/backend/src/types/database.types.ts @@ -0,0 +1,268 @@ +export type Json = + | string + | number + | boolean + | null + | { [key: string]: Json | undefined } + | Json[] + +export type Database = { + // Allows to automatically instantiate createClient with right options + // instead of createClient(URL, KEY) + __InternalSupabase: { + PostgrestVersion: "12.2.3 (519615d)" + } + public: { + Tables: { + translations: { + Row: { + created_at: string + id: string + language: string + text: string + updated_at: string + user_id: string + word_id: string + } + Insert: { + created_at?: string + id?: string + language: string + text: string + updated_at?: string + user_id?: string + word_id: string + } + Update: { + created_at?: string + id?: string + language?: string + text?: string + updated_at?: string + user_id?: string + word_id?: string + } + Relationships: [ + { + foreignKeyName: "translations_user_id_fkey" + columns: ["user_id"] + isOneToOne: false + referencedRelation: "user" + referencedColumns: ["id"] + }, + { + foreignKeyName: "translations_word_id_fkey" + columns: ["word_id"] + isOneToOne: false + referencedRelation: "words" + referencedColumns: ["id"] + }, + ] + } + user: { + Row: { + active_learning_language: string + id: string + interface_language: string + native_language: string + theme: Database["public"]["Enums"]["Theme"] + } + Insert: { + active_learning_language?: string + id?: string + interface_language?: string + native_language?: string + theme?: Database["public"]["Enums"]["Theme"] + } + Update: { + active_learning_language?: string + id?: string + interface_language?: string + native_language?: string + theme?: Database["public"]["Enums"]["Theme"] + } + Relationships: [] + } + words: { + Row: { + created_at: string + id: string + language: string + sort_id: number + status: Database["public"]["Enums"]["UserWordStatus"] + text: string + updated_at: string + user_id: string + } + Insert: { + created_at?: string + id?: string + language: string + sort_id?: number + status?: Database["public"]["Enums"]["UserWordStatus"] + text: string + updated_at?: string + user_id?: string + } + Update: { + created_at?: string + id?: string + language?: string + sort_id?: number + status?: Database["public"]["Enums"]["UserWordStatus"] + text?: string + updated_at?: string + user_id?: string + } + Relationships: [ + { + foreignKeyName: "words_user_id_fkey" + columns: ["user_id"] + isOneToOne: false + referencedRelation: "user" + referencedColumns: ["id"] + }, + ] + } + } + Views: { + [_ in never]: never + } + Functions: { + [_ in never]: never + } + Enums: { + Theme: "system" | "dark" | "light" + UserWordStatus: "New" | "Learn" | "Learned" + } + CompositeTypes: { + [_ in never]: never + } + } +} + +type DatabaseWithoutInternals = Omit + +type DefaultSchema = DatabaseWithoutInternals[Extract] + +export type Tables< + DefaultSchemaTableNameOrOptions extends + | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) + : never = never, +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { + Row: infer R + } + ? R + : never + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & + DefaultSchema["Views"]) + ? (DefaultSchema["Tables"] & + DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { + Row: infer R + } + ? R + : never + : never + +export type TablesInsert< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Insert: infer I + } + ? I + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Insert: infer I + } + ? I + : never + : never + +export type TablesUpdate< + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] + : never = never, +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Update: infer U + } + ? U + : never + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Update: infer U + } + ? U + : never + : never + +export type Enums< + DefaultSchemaEnumNameOrOptions extends + | keyof DefaultSchema["Enums"] + | { schema: keyof DatabaseWithoutInternals }, + EnumName extends DefaultSchemaEnumNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] + : never = never, +> = DefaultSchemaEnumNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] + : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] + ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] + : never + +export type CompositeTypes< + PublicCompositeTypeNameOrOptions extends + | keyof DefaultSchema["CompositeTypes"] + | { schema: keyof DatabaseWithoutInternals }, + CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] + : never = never, +> = PublicCompositeTypeNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] + ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] + : never + +export const Constants = { + public: { + Enums: { + Theme: ["system", "dark", "light"], + UserWordStatus: ["New", "Learn", "Learned"], + }, + }, +} as const diff --git a/apps/backend/src/user/dto/update-user.dto.ts b/apps/backend/src/user/dto/update-user.dto.ts new file mode 100644 index 0000000..fc52cbc --- /dev/null +++ b/apps/backend/src/user/dto/update-user.dto.ts @@ -0,0 +1,60 @@ +import { IsEnum, IsObject, IsOptional, IsString } from "class-validator"; +import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; +import { ApiConstants } from "../../types/database.types.public"; +import type { ApiDatabase } from "../../types/database.types.public"; + +export class UpdateUserPayloadDto { + @ApiPropertyOptional({ description: "Active learning language code", example: "en" }) + @IsOptional() + @IsString() + active_learning_language?: string; + + @ApiPropertyOptional({ description: "Interface language code", example: "en" }) + @IsOptional() + @IsString() + interface_language?: string; + + @ApiPropertyOptional({ description: "Native language code", example: "ru" }) + @IsOptional() + @IsString() + native_language?: string; + + @ApiPropertyOptional({ + description: "Theme preference", + enum: ApiConstants.public.Enums.Theme, + example: ApiConstants.public.Enums.Theme[0], + }) + @IsOptional() + @IsEnum(ApiConstants.public.Enums.Theme) + theme?: ApiDatabase["public"]["Enums"]["Theme"]; +} + +export class UpdateUserRequest { + @ApiProperty({ type: UpdateUserPayloadDto, description: "Partial user data to update" }) + @IsObject() + payload!: UpdateUserPayloadDto; +} + +// Response DTOs +export class UpdateUserResponse { + @ApiProperty({ description: "User ID", example: "uuid" }) + id!: string; + + @ApiProperty({ description: "Active learning language code", example: "en" }) + active_learning_language!: string; + + @ApiProperty({ description: "Interface language code", example: "en" }) + interface_language!: string; + + @ApiProperty({ description: "Native language code", example: "ru" }) + native_language!: string; + + @ApiProperty({ + description: "Theme preference", + enum: ApiConstants.public.Enums.Theme, + example: ApiConstants.public.Enums.Theme[0], + }) + theme!: ApiDatabase["public"]["Enums"]["Theme"]; +} + +export class GetUserResponse extends UpdateUserResponse {} diff --git a/apps/backend/src/user/user.controller.ts b/apps/backend/src/user/user.controller.ts new file mode 100644 index 0000000..52d9d96 --- /dev/null +++ b/apps/backend/src/user/user.controller.ts @@ -0,0 +1,51 @@ +import { Body, Controller, Get, Patch, Request } from "@nestjs/common"; +import { + ApiBearerAuth, + ApiBody, + ApiExtraModels, + ApiOperation, + ApiResponse, + ApiTags, +} from "@nestjs/swagger"; +import { UserService } from "./user.service"; +import { + GetUserResponse, + UpdateUserPayloadDto, + UpdateUserRequest, + UpdateUserResponse, +} from "./dto/update-user.dto"; + +@ApiTags("user") +@ApiBearerAuth() +@ApiExtraModels(UpdateUserPayloadDto, UpdateUserResponse, GetUserResponse) +@Controller("user") +export class UserController { + constructor(private readonly userService: UserService) {} + + @Get() + @ApiOperation({ summary: "Get current user" }) + @ApiResponse({ + status: 200, + type: GetUserResponse, + // nullable: true, + description: "User retrieved successfully", + }) + async getUser(@Request() req: any) { + return this.userService.fetchUser(req.user.id); + } + + @Patch() + @ApiOperation({ summary: "Update current user" }) + @ApiBody({ type: UpdateUserRequest }) + @ApiResponse({ + status: 200, + type: UpdateUserResponse, + // nullable: true, + description: "User updated successfully", + }) + async updateUser(@Request() req: any, @Body() dto: UpdateUserRequest) { + console.log(req.user, dto, "dto"); + + return this.userService.updateUser(req.user.id, dto); + } +} diff --git a/apps/backend/src/user/user.module.ts b/apps/backend/src/user/user.module.ts new file mode 100644 index 0000000..9a49bf5 --- /dev/null +++ b/apps/backend/src/user/user.module.ts @@ -0,0 +1,11 @@ +import { Module } from "@nestjs/common"; +import { SupabaseClientModule } from "../supabase-client/supabase-client.module"; +import { UserController } from "./user.controller"; +import { UserService } from "./user.service"; + +@Module({ + imports: [SupabaseClientModule], + controllers: [UserController], + providers: [UserService], +}) +export class UserModule {} diff --git a/apps/backend/src/user/user.service.ts b/apps/backend/src/user/user.service.ts new file mode 100644 index 0000000..b7689cc --- /dev/null +++ b/apps/backend/src/user/user.service.ts @@ -0,0 +1,32 @@ +import { Inject, Injectable } from "@nestjs/common"; +import { SUPABASE_USER_CLIENT } from "../supabase-client/supabase-user-client.token"; +import type { SupabaseUserClient } from "../supabase-client/supabase-user-client.token"; +import type { UpdateUserRequest } from "./dto/update-user.dto"; + +@Injectable() +export class UserService { + constructor(@Inject(SUPABASE_USER_CLIENT) private readonly supabase: SupabaseUserClient) {} + + async fetchUser(userId: string) { + const response = await this.supabase + .from("user") + .select() + .eq("id", userId) + .maybeSingle() + .throwOnError(); + + return response.data; + } + + async updateUser(userId: string, dto: UpdateUserRequest) { + const response = await this.supabase + .from("user") + .update(dto.payload) + .eq("id", userId) + .select() + .maybeSingle() + .throwOnError(); + + return response.data; + } +} diff --git a/apps/backend/src/words/dto/add-translations.dto.ts b/apps/backend/src/words/dto/add-translations.dto.ts new file mode 100644 index 0000000..b7c2472 --- /dev/null +++ b/apps/backend/src/words/dto/add-translations.dto.ts @@ -0,0 +1,25 @@ +import { IsArray, ValidateNested } from "class-validator"; +import { Type } from "class-transformer"; +import { ApiProperty } from "@nestjs/swagger"; +import { TranslationResponseDto } from "./fetch-words.dto"; + +class TranslationDto { + @ApiProperty({ description: "Translation text", example: "привет" }) + text!: string; + + @ApiProperty({ description: "Translation language code", example: "ru" }) + language!: string; +} + +export class AddWordTranslationsRequest { + @ApiProperty({ type: [TranslationDto], description: "Array of translations to add" }) + @IsArray() + @ValidateNested({ each: true }) + @Type(() => TranslationDto) + translations!: TranslationDto[]; +} + +export class AddWordTranslationsResponse { + @ApiProperty({ type: [TranslationResponseDto], description: "Array of added translations" }) + translations!: TranslationResponseDto[]; +} diff --git a/apps/backend/src/words/dto/create-word.dto.ts b/apps/backend/src/words/dto/create-word.dto.ts new file mode 100644 index 0000000..65fb546 --- /dev/null +++ b/apps/backend/src/words/dto/create-word.dto.ts @@ -0,0 +1,36 @@ +import { IsArray, IsObject, ValidateNested } from "class-validator"; +import { Type } from "class-transformer"; +import { ApiProperty } from "@nestjs/swagger"; +import { WordWithTranslationsDto } from "./fetch-words.dto"; + +class WordDto { + @ApiProperty({ description: "Language code", example: "en" }) + language!: string; + + @ApiProperty({ description: "Word text", example: "hello" }) + text!: string; +} + +class TranslationDto { + @ApiProperty({ description: "Translation text", example: "привет" }) + text!: string; + + @ApiProperty({ description: "Translation language code", example: "ru" }) + language!: string; +} + +export class CreateWordRequest { + @ApiProperty({ type: WordDto, description: "Word information" }) + @IsObject() + @ValidateNested() + @Type(() => WordDto) + word!: WordDto; + + @ApiProperty({ type: [TranslationDto], description: "Array of translations" }) + @IsArray() + @ValidateNested({ each: true }) + @Type(() => TranslationDto) + translations!: TranslationDto[]; +} + +export class CreateWordResponse extends WordWithTranslationsDto {} diff --git a/apps/backend/src/words/dto/delete-translations.dto.ts b/apps/backend/src/words/dto/delete-translations.dto.ts new file mode 100644 index 0000000..d3f8a78 --- /dev/null +++ b/apps/backend/src/words/dto/delete-translations.dto.ts @@ -0,0 +1,19 @@ +import { IsArray, IsString } from "class-validator"; +import { ApiProperty } from "@nestjs/swagger"; +import { TranslationResponseDto } from "./fetch-words.dto"; + +export class DeleteWordTranslationsRequest { + @ApiProperty({ + type: [String], + description: "Array of translation IDs to delete", + example: ["uuid1", "uuid2"], + }) + @IsArray() + @IsString({ each: true }) + translationsIds!: string[]; +} + +export class DeleteWordTranslationsResponse { + @ApiProperty({ type: [TranslationResponseDto], description: "Array of deleted translations" }) + translations!: TranslationResponseDto[]; +} diff --git a/apps/backend/src/words/dto/delete-words.dto.ts b/apps/backend/src/words/dto/delete-words.dto.ts new file mode 100644 index 0000000..5a4acb7 --- /dev/null +++ b/apps/backend/src/words/dto/delete-words.dto.ts @@ -0,0 +1,19 @@ +import { IsArray, IsString } from "class-validator"; +import { ApiProperty } from "@nestjs/swagger"; +import { WordResponseDto } from "./fetch-words.dto"; + +export class DeleteWordsRequest { + @ApiProperty({ + type: [String], + description: "Array of word IDs to delete", + example: ["uuid1", "uuid2"], + }) + @IsArray() + @IsString({ each: true }) + wordIds!: string[]; +} + +export class DeleteWordsResponse { + @ApiProperty({ type: [WordResponseDto], description: "Array of deleted words" }) + words!: WordResponseDto[]; +} diff --git a/apps/backend/src/words/dto/fetch-words.dto.ts b/apps/backend/src/words/dto/fetch-words.dto.ts new file mode 100644 index 0000000..b43485b --- /dev/null +++ b/apps/backend/src/words/dto/fetch-words.dto.ts @@ -0,0 +1,99 @@ +import { IsEnum, IsNumber, IsOptional, IsString } from "class-validator"; +import { Transform } from "class-transformer"; +import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger"; +import { ApiConstants } from "../../types/database.types.public"; +import type { ApiDatabase } from "../../types/database.types.public"; + +export class FetchWordsRequest { + @ApiProperty({ description: "Language code", example: "en" }) + @IsString() + language!: string; + + @ApiProperty({ description: "Number of items per page", example: 20 }) + @Transform(({ value }) => parseInt(value, 10)) + @IsNumber() + pageSize!: number; + + @ApiPropertyOptional({ description: "Page token for pagination", example: 10 }) + @IsOptional() + @Transform(({ value }) => (value ? parseInt(value, 10) : undefined)) + @IsNumber() + pageToken?: number; + + @ApiPropertyOptional({ description: "Filter by word text", example: "hello" }) + @IsOptional() + @IsString() + filterText?: string; + + @ApiPropertyOptional({ + description: "Filter by word status", + enum: ApiConstants.public.Enums.UserWordStatus, + example: ApiConstants.public.Enums.UserWordStatus[0], + }) + @IsOptional() + @IsEnum(ApiConstants.public.Enums.UserWordStatus) + filterStatus?: ApiDatabase["public"]["Tables"]["words"]["Row"]["status"]; +} + +// Response DTOs +export class TranslationResponseDto { + @ApiProperty({ description: "Translation ID", example: "uuid" }) + id!: string; + + @ApiProperty({ description: "Translation text", example: "привет" }) + text!: string; + + @ApiProperty({ description: "Translation language code", example: "ru" }) + language!: string; +} + +export class WordResponseDto { + @ApiProperty({ description: "Word ID", example: "uuid" }) + id!: string; + + @ApiProperty({ description: "Creation timestamp", example: "2024-01-01T00:00:00Z" }) + created_at!: string; + + @ApiProperty({ description: "Update timestamp", example: "2024-01-01T00:00:00Z" }) + updated_at!: string; + + @ApiProperty({ description: "User ID", example: "uuid" }) + user_id!: string; + + @ApiProperty({ description: "Word language code", example: "en" }) + language!: string; + + @ApiProperty({ description: "Word text", example: "hello" }) + text!: string; + + @ApiProperty({ description: "Sort ID for ordering", example: 1 }) + sort_id!: number; + + @ApiProperty({ + description: "Word status", + enum: ApiConstants.public.Enums.UserWordStatus, + example: ApiConstants.public.Enums.UserWordStatus[0], + }) + status!: ApiDatabase["public"]["Tables"]["words"]["Row"]["status"]; +} + +export class WordWithTranslationsDto extends WordResponseDto { + @ApiProperty({ type: [TranslationResponseDto], description: "Array of translations" }) + translations!: TranslationResponseDto[]; +} + +export class FetchWordsResponse { + @ApiProperty({ + type: [WordWithTranslationsDto], + description: "Array of words with translations", + }) + words!: WordWithTranslationsDto[]; + + @ApiProperty({ + type: Number, + description: "Token for next page pagination", + example: 10, + nullable: true, + }) + nextPageToken!: number | null; +} diff --git a/apps/backend/src/words/dto/update-words-status.dto.ts b/apps/backend/src/words/dto/update-words-status.dto.ts new file mode 100644 index 0000000..c6cc860 --- /dev/null +++ b/apps/backend/src/words/dto/update-words-status.dto.ts @@ -0,0 +1,24 @@ +import { IsArray, IsString } from "class-validator"; +import { ApiProperty } from "@nestjs/swagger"; +import { ApiConstants } from "../../types/database.types.public"; +import { WordResponseDto } from "./fetch-words.dto"; +import type { ApiDatabase } from "../../types/database.types.public"; + +export class UpdateWordsStatusRequest { + @ApiProperty({ type: [String], description: "Array of word IDs", example: ["uuid1", "uuid2"] }) + @IsArray() + @IsString({ each: true }) + wordsIds!: string[]; + + @ApiProperty({ + description: "New status for words", + enum: ApiConstants.public.Enums.UserWordStatus, + example: ApiConstants.public.Enums.UserWordStatus[0], + }) + status!: ApiDatabase["public"]["Tables"]["words"]["Row"]["status"]; +} + +export class UpdateWordsStatusResponse { + @ApiProperty({ type: [WordResponseDto], description: "Array of updated words" }) + words!: WordResponseDto[]; +} diff --git a/apps/backend/src/words/words.controller.ts b/apps/backend/src/words/words.controller.ts new file mode 100644 index 0000000..c78a02c --- /dev/null +++ b/apps/backend/src/words/words.controller.ts @@ -0,0 +1,143 @@ +import { + Body, + Controller, + Delete, + Get, + Param, + Patch, + Post, + Query, + Request, + UsePipes, + ValidationPipe, +} from "@nestjs/common"; +import { + ApiBearerAuth, + ApiBody, + ApiExtraModels, + ApiOperation, + ApiParam, + ApiQuery, + ApiResponse, + ApiTags, +} from "@nestjs/swagger"; +import { WordsService } from "./words.service"; +import { + FetchWordsRequest, + FetchWordsResponse, + TranslationResponseDto, + WordResponseDto, + WordWithTranslationsDto, +} from "./dto/fetch-words.dto"; +import { UpdateWordsStatusRequest, UpdateWordsStatusResponse } from "./dto/update-words-status.dto"; +import { CreateWordRequest, CreateWordResponse } from "./dto/create-word.dto"; +import { + AddWordTranslationsRequest, + AddWordTranslationsResponse, +} from "./dto/add-translations.dto"; +import { + DeleteWordTranslationsRequest, + DeleteWordTranslationsResponse, +} from "./dto/delete-translations.dto"; +import { DeleteWordsRequest, DeleteWordsResponse } from "./dto/delete-words.dto"; + +@ApiTags("words") +@ApiBearerAuth() +@ApiExtraModels( + FetchWordsResponse, + CreateWordResponse, + UpdateWordsStatusResponse, + DeleteWordsResponse, + AddWordTranslationsResponse, + DeleteWordTranslationsResponse, + WordResponseDto, + TranslationResponseDto, + WordWithTranslationsDto, +) +@Controller("words") +export class WordsController { + constructor(private readonly wordsService: WordsService) {} + + @Get() + @ApiOperation({ summary: "Get words" }) + @ApiQuery({ type: FetchWordsRequest }) + @ApiResponse({ + status: 200, + type: FetchWordsResponse, + description: "Words retrieved successfully", + }) + @UsePipes(new ValidationPipe({ transform: true })) + async getWords(@Query() dto: FetchWordsRequest, @Request() req: any) { + return this.wordsService.fetchWords(dto, req.user.id); + } + + @Post() + @ApiOperation({ summary: "Create word" }) + @ApiBody({ type: CreateWordRequest }) + @ApiResponse({ + status: 201, + type: CreateWordResponse, + description: "Word created successfully", + }) + async createWord(@Body() dto: CreateWordRequest, @Request() req: any) { + return this.wordsService.createWord(dto, req.user.id); + } + + @Patch("status") + @ApiOperation({ summary: "Update words status" }) + @ApiBody({ type: UpdateWordsStatusRequest }) + @ApiResponse({ + status: 200, + type: UpdateWordsStatusResponse, + description: "Words status updated successfully", + }) + async updateWordsStatus(@Body() dto: UpdateWordsStatusRequest, @Request() req: any) { + return this.wordsService.updateWordsStatus(dto, req.user.id); + } + + @Delete() + @ApiOperation({ summary: "Delete words" }) + @ApiBody({ type: DeleteWordsRequest }) + @ApiResponse({ + status: 200, + type: DeleteWordsResponse, + description: "Words deleted successfully", + }) + async deleteWords(@Body() dto: DeleteWordsRequest, @Request() req: any) { + return this.wordsService.deleteWords(dto, req.user.id); + } + + @Post(":wordId/translations") + @ApiOperation({ summary: "Add translations to word" }) + @ApiParam({ name: "wordId", description: "Word ID", example: "uuid" }) + @ApiBody({ type: AddWordTranslationsRequest }) + @ApiResponse({ + status: 201, + type: AddWordTranslationsResponse, + description: "Translations added successfully", + }) + async addWordTranslations( + @Param("wordId") wordId: string, + @Body() dto: AddWordTranslationsRequest, + @Request() req: any, + ) { + return this.wordsService.addWordTranslations(wordId, dto, req.user.id); + } + + @Delete(":wordId/translations") + @ApiOperation({ summary: "Delete translations from word" }) + @ApiParam({ name: "wordId", description: "Word ID", example: "uuid" }) + @ApiBody({ type: DeleteWordTranslationsRequest }) + @ApiResponse({ + status: 200, + type: DeleteWordTranslationsResponse, + description: "Translations deleted successfully", + }) + async deleteWordTranslations( + @Param("wordId") wordId: string, + @Body() dto: DeleteWordTranslationsRequest, + @Request() req: any, + ) { + return this.wordsService.deleteWordTranslations(wordId, dto, req.user.id); + } +} diff --git a/apps/backend/src/words/words.module.ts b/apps/backend/src/words/words.module.ts new file mode 100644 index 0000000..ec79023 --- /dev/null +++ b/apps/backend/src/words/words.module.ts @@ -0,0 +1,11 @@ +import { Module } from "@nestjs/common"; +import { SupabaseClientModule } from "../supabase-client/supabase-client.module"; +import { WordsController } from "./words.controller"; +import { WordsService } from "./words.service"; + +@Module({ + imports: [SupabaseClientModule], + controllers: [WordsController], + providers: [WordsService], +}) +export class WordsModule {} diff --git a/apps/backend/src/words/words.service.ts b/apps/backend/src/words/words.service.ts new file mode 100644 index 0000000..ac7c524 --- /dev/null +++ b/apps/backend/src/words/words.service.ts @@ -0,0 +1,147 @@ +import { Inject, Injectable } from "@nestjs/common"; +import { SUPABASE_USER_CLIENT } from "../supabase-client/supabase-user-client.token"; +import type { SupabaseUserClient } from "../supabase-client/supabase-user-client.token"; +import type { FetchWordsRequest } from "./dto/fetch-words.dto"; +import type { UpdateWordsStatusRequest } from "./dto/update-words-status.dto"; +import type { CreateWordRequest } from "./dto/create-word.dto"; +import type { AddWordTranslationsRequest } from "./dto/add-translations.dto"; +import type { DeleteWordTranslationsRequest } from "./dto/delete-translations.dto"; +import type { DeleteWordsRequest } from "./dto/delete-words.dto"; + +@Injectable() +export class WordsService { + constructor(@Inject(SUPABASE_USER_CLIENT) private readonly supabase: SupabaseUserClient) {} + + async fetchWords(dto: FetchWordsRequest, userId: string) { + const itemsRequest = this.supabase + .from("words") + .select("*, translations (id, text, language)") + .eq("user_id", userId) + .filter("language", "eq", dto.language) + .order("sort_id", { ascending: false }) + .limit(dto.pageSize + 1) + .throwOnError(); + + if (dto.pageToken) { + itemsRequest.filter("sort_id", "lt", dto.pageToken); + } + + if (dto.filterText) { + itemsRequest.filter("text", "like", `%${dto.filterText}%`); + } + if (dto.filterStatus) { + itemsRequest.filter("status", "eq", dto.filterStatus); + } + + const itemsResponse = await itemsRequest; + + const lastItem = itemsResponse.data?.at(-2); + const nextPageToken = + lastItem && itemsResponse.data && itemsResponse.data.length === dto.pageSize + 1 + ? lastItem.sort_id + : null; + + return { + words: itemsResponse.data?.slice(0, dto.pageSize) || [], + nextPageToken, + }; + } + + async updateWordsStatus(dto: UpdateWordsStatusRequest, userId: string) { + const response = await this.supabase + .from("words") + .update({ status: dto.status }) + .in("id", dto.wordsIds) + .eq("user_id", userId) + .select() + .throwOnError(); + + return response.data; + } + + async createWord(dto: CreateWordRequest, userId: string) { + // Get max sort_id for this user + const { data: maxSortData } = await this.supabase + .from("words") + .select("sort_id") + .eq("user_id", userId) + .order("sort_id", { ascending: false }) + .limit(1) + .single(); + + const nextSortId = maxSortData ? (maxSortData.sort_id || 0) + 1 : 1; + + const word = await this.supabase + .from("words") + .insert({ + ...dto.word, + user_id: userId, + sort_id: nextSortId, + }) + .select() + .single() + .throwOnError(); + + await this.supabase + .from("translations") + .insert( + dto.translations.map((translation) => ({ + word_id: word.data.id, + user_id: userId, + ...translation, + })), + ) + .throwOnError(); + + const result = await this.supabase + .from("words") + .select("*, translations (id, text, language)") + .eq("id", word.data.id) + .single() + .throwOnError(); + + return result.data; + } + + async deleteWords(dto: DeleteWordsRequest, userId: string) { + const response = await this.supabase + .from("words") + .delete() + .in("id", dto.wordIds) + .eq("user_id", userId) + .throwOnError(); + + return response.data; + } + + async addWordTranslations(wordId: string, dto: AddWordTranslationsRequest, userId: string) { + const response = await this.supabase + .from("translations") + .insert( + dto.translations.map((translation) => ({ + word_id: wordId, + user_id: userId, + ...translation, + })), + ) + .throwOnError(); + + return response.data; + } + + async deleteWordTranslations( + wordId: string, + dto: DeleteWordTranslationsRequest, + userId: string, + ) { + const response = await this.supabase + .from("translations") + .delete() + .in("id", dto.translationsIds) + .eq("word_id", wordId) + .eq("user_id", userId) + .throwOnError(); + + return response.data; + } +} diff --git a/apps/backend/tsconfig.json b/apps/backend/tsconfig.json new file mode 100644 index 0000000..c7ced09 --- /dev/null +++ b/apps/backend/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "target": "ES2021", + "lib": ["ES2021"], + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "skipLibCheck": true, + "strictNullChecks": true, + "noImplicitAny": false, + "strictBindCallApply": false, + "forceConsistentCasingInFileNames": false, + "noFallthroughCasesInSwitch": false, + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./", + "incremental": true, + "resolveJsonModule": true, + "types": ["node"], + }, + "include": ["src/**/*", "scripts/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile index b3cfc9a..a9f4f3c 100644 --- a/apps/web/Dockerfile +++ b/apps/web/Dockerfile @@ -28,10 +28,13 @@ RUN pnpm install --frozen-lockfile RUN echo "BUNDLE_STATS_BASELINE is $BUNDLE_STATS_BASELINE" RUN pnpm --filter app-web run build +RUN pnpm --filter app-backend run build EXPOSE 8080 ENV PORT=8080 +ENV BACKEND_PORT=3001 ENV NODE_ENV=production -CMD ["pnpm", "--filter", "app-web", "run", "preview"] +# Start both backend and frontend servers (backend on 3001, frontend on 8080) +CMD ["sh", "-c", "PORT=3001 pnpm --filter app-backend run start:prod & PORT=8080 pnpm --filter app-web run preview & wait"] diff --git a/apps/web/package.json b/apps/web/package.json index c627564..c0d7b96 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -17,6 +17,7 @@ "circular-deps": "npm-run-all circular-deps:*", "circular-deps:ui": "madge --circular --extensions ts,tsx --ts-config src/ui/tsconfig.json src/ui", "dev": "nodemon -w src/server -x tsx src/server/main.ts", + "dev:all": "concurrently \"pnpm --filter app-backend run start:dev\" \"pnpm run dev\"", "i18n:extract": "formatjs extract \"src/**/*.{ts,tsx}\" --ignore=\"**/*.d.ts\" --out-file src/locales/extracted.json --id-interpolation-pattern [sha512:contenthash:base64:6]", "i18n:manage": "ts-node scripts/manage-translations.ts", "lint": "eslint --concurrency=auto .", @@ -85,6 +86,8 @@ "cookie-parser": "^1.4.7", "dotenv": "^16.5.0", "express": "^5.1.0", + "concurrently": "^9.1.2", + "http-proxy-middleware": "^3.0.3", "nodemon": "^3.1.10", "rollup-plugin-bundle-stats": "^4.21.0", "sass": "^1.87.0", diff --git a/apps/web/src/server/main.ts b/apps/web/src/server/main.ts index e3f5863..af11d0c 100644 --- a/apps/web/src/server/main.ts +++ b/apps/web/src/server/main.ts @@ -4,6 +4,7 @@ import path from "node:path"; import cookieParser from "cookie-parser"; import * as dotenv from "dotenv"; import express from "express"; +import { createProxyMiddleware } from "http-proxy-middleware"; import { localeMiddleware } from "./middlewares/locale"; import { themeMiddleware } from "./middlewares/theme"; @@ -16,6 +17,7 @@ dotenv.config({ path: path.resolve(__dirname, "../../../../.env") }); const isProduction = process.env.NODE_ENV === "production"; const port = process.env.PORT || 5173; const base = process.env.BASE || "/"; +const backendPort = process.env.BACKEND_PORT || 3001; const createServer = async () => { const templateHtml = isProduction ? await fs.readFile("./dist/client/index.html", "utf-8") : ""; @@ -23,6 +25,15 @@ const createServer = async () => { const app = express(); let vite: ViteDevServer; + // Proxy API requests to backend - MUST BE FIRST to intercept /api/* requests + app.use( + "/api", + createProxyMiddleware({ + target: `http://localhost:${backendPort}/api`, + changeOrigin: true, + }), + ); + if (isProduction) { const compression = (await import("compression")).default; const sirv = (await import("sirv")).default; @@ -31,7 +42,15 @@ const createServer = async () => { } else { const { createServer: createViteServer } = await import("vite"); vite = await createViteServer({ - server: { middlewareMode: true }, + server: { + middlewareMode: true, + proxy: { + "/api": { + target: `http://localhost:${backendPort}`, + changeOrigin: true, + }, + }, + }, appType: "custom", logLevel: "info", base, diff --git a/apps/web/src/server/middlewares/user.ts b/apps/web/src/server/middlewares/user.ts index 5ef1189..c1ce0fe 100644 --- a/apps/web/src/server/middlewares/user.ts +++ b/apps/web/src/server/middlewares/user.ts @@ -1,30 +1,22 @@ import { useSdk } from "../shared/sdk"; -import { useSupabaseClient } from "../shared/supabase"; import type { Response } from "core"; import type { NextFunction, Request } from "express-serve-static-core"; export const userMiddleware = async function (req: Request, res: Response, next: NextFunction) { - // eslint-disable-next-line react-hooks/rules-of-hooks - const { supabaseClient } = useSupabaseClient(req, res); // eslint-disable-next-line react-hooks/rules-of-hooks const { sdk } = useSdk(req, res); try { - const user = await supabaseClient.auth.getUser(); - if (user.data.user) { - res.locals.user = user.data.user; - } + const user = await sdk.user.fetchUser(); + res.locals.user = user; } catch { // TODO: use logger } - try { - const userSettings = await sdk.user.fetchUser(); - - res.locals.userSettings = userSettings; - } catch { - /* empty */ - } + // Note: userSettings are now fetched on the client side via API + // This middleware only handles user authentication for SSR + // If you need userSettings in SSR, you can fetch them from backend API here + // by making an HTTP request to /api/user with the auth token next(); }; diff --git a/apps/web/src/server/shared/supabase.ts b/apps/web/src/server/shared/supabase.ts index 45045e3..4acc26f 100644 --- a/apps/web/src/server/shared/supabase.ts +++ b/apps/web/src/server/shared/supabase.ts @@ -1,11 +1,10 @@ import { createServerClient } from "@supabase/ssr"; -import type { ApiDatabase } from "@languages-learner/api"; import type { Response } from "core"; import type { Request } from "express-serve-static-core"; export const useSupabaseClient = (req: Request, res: Response) => { - const supabaseClient = createServerClient( + const supabaseClient = createServerClient( process.env.VITE_SUPABASE_PROJECT_URL!, process.env.VITE_SUPABASE_PROJECT_KEY!, { diff --git a/apps/web/src/server/typings.d.ts b/apps/web/src/server/typings.d.ts index b304c87..dd95760 100644 --- a/apps/web/src/server/typings.d.ts +++ b/apps/web/src/server/typings.d.ts @@ -1,12 +1,12 @@ declare module "core" { - import type { User } from "@supabase/supabase-js"; + import type { components } from "@languages-learner/api"; import type { Response as BaseResponse } from "express-serve-static-core"; import type { ResolvedTheme } from "../shared/project-config"; import type { ApiDatabase } from "../shared/services/api"; export interface Locals { - user: User; + user: components["schemas"]["GetUserResponse"]; userSettings: ApiDatabase["public"]["Tables"]["user"]["Row"]; locale: string; theme?: ResolvedTheme; diff --git a/apps/web/src/shared/project-config.ts b/apps/web/src/shared/project-config.ts index 64c8f35..f54fb59 100644 --- a/apps/web/src/shared/project-config.ts +++ b/apps/web/src/shared/project-config.ts @@ -1,10 +1,10 @@ -import type { ApiTables } from "@languages-learner/api"; +import type { ApiEnums } from "@languages-learner/api"; export const INTERFACE_LOCALES = ["en", "ru"] as const; export type InterfaceLocale = (typeof INTERFACE_LOCALES)[number]; export const BASE_INTERFACE_LOCALE: InterfaceLocale = "en" as const; -export type ResolvedTheme = Exclude["theme"], "system">; -export type Theme = ApiTables<"user">["theme"]; -export const BASE_THEME: ApiTables<"user">["theme"] = "system"; +export type ResolvedTheme = Exclude, "system">; +export type Theme = ApiEnums<"Theme">; +export const BASE_THEME: ApiEnums<"Theme"> = "system"; export const BASE_RESOLVED_THEME: ResolvedTheme = "light"; diff --git a/apps/web/src/ui/entities/user/types.ts b/apps/web/src/ui/entities/user/types.ts index 59b91af..704701e 100644 --- a/apps/web/src/ui/entities/user/types.ts +++ b/apps/web/src/ui/entities/user/types.ts @@ -1,4 +1,4 @@ -import type { ApiTables } from "@languages-learner/api"; +import type { ApiEnums } from "@languages-learner/api"; export interface User { uid: string; @@ -9,7 +9,7 @@ export interface User { nativeLanguage: string; activeLearningLanguage: string; interfaceLanguage: string; - theme: ApiTables<"user">["theme"]; + theme: ApiEnums<"Theme">; } export interface UserContext { diff --git a/apps/web/src/ui/entities/word/constants.ts b/apps/web/src/ui/entities/word/constants.ts index dd51651..35a9ff3 100644 --- a/apps/web/src/ui/entities/word/constants.ts +++ b/apps/web/src/ui/entities/word/constants.ts @@ -1,11 +1,8 @@ -import type { ApiDatabase } from "@languages-learner/api"; +import type { ApiEnums } from "@languages-learner/api"; import { intl } from "@/shared/i18n"; -export const WORD_STATUS_NAME: Record< - ApiDatabase["public"]["Tables"]["words"]["Row"]["status"], - string -> = { +export const WORD_STATUS_NAME: Record, string> = { New: intl.formatMessage({ defaultMessage: "New", id: "bW7B87", diff --git a/apps/web/src/ui/entities/word/fields/words.tsx b/apps/web/src/ui/entities/word/fields/words.tsx index 031a1be..70f37ec 100644 --- a/apps/web/src/ui/entities/word/fields/words.tsx +++ b/apps/web/src/ui/entities/word/fields/words.tsx @@ -3,7 +3,7 @@ import { Popover, PopoverContent, PopoverTrigger } from "@heroui/popover"; import { selectionColumn } from "@languages-learner/uikit"; import { BiPencil, BiTrash } from "react-icons/bi"; import { WordStatusSelector } from "../ui/WordStatusSelector"; -import type { ApiDatabase, WordWithTranslations } from "@languages-learner/api"; +import type { components } from "@languages-learner/api"; import type { ColumnsDef } from "@languages-learner/uikit"; import type { ColumnDef } from "@tanstack/react-table"; @@ -13,13 +13,13 @@ import { InlineWordTranslationsList } from "@/features/words/inlineWordTranslati import { intl } from "@/shared/i18n"; type BaseColumnCallbackPayload = { - item: WordWithTranslations; + item: components["schemas"]["WordWithTranslationsDto"]; }; export const wordColumns = { - selection: selectionColumn as ColumnDef, + selection: selectionColumn as ColumnDef, textAndTranslationWithEdit: (columnProps: { - editView: (item: WordWithTranslations) => boolean; + editView: (item: components["schemas"]["WordWithTranslationsDto"]) => boolean; onAddWord: ( payload: BaseColumnCallbackPayload & { translation: AddWordTranslationFormType; @@ -71,7 +71,7 @@ export const wordColumns = { maxSize: 600, }), edit: (columnProps: { - editView: (item: WordWithTranslations) => boolean; + editView: (item: components["schemas"]["WordWithTranslationsDto"]) => boolean; onEditClick: (payload: BaseColumnCallbackPayload) => unknown; }) => ({ id: "edit", @@ -94,7 +94,7 @@ export const wordColumns = { status: (columnProps: { onUpdate: ( payload: BaseColumnCallbackPayload & { - status: ApiDatabase["public"]["Tables"]["words"]["Row"]["status"]; + status: components["schemas"]["WordWithTranslationsDto"]["status"]; }, ) => unknown; }) => ({ @@ -153,4 +153,4 @@ export const wordColumns = { minSize: 50, maxSize: 50, }), -} satisfies ColumnsDef; +} satisfies ColumnsDef; diff --git a/apps/web/src/ui/entities/word/mutations/useWordMutations.tsx b/apps/web/src/ui/entities/word/mutations/useWordMutations.tsx index e4f718c..35f0dec 100644 --- a/apps/web/src/ui/entities/word/mutations/useWordMutations.tsx +++ b/apps/web/src/ui/entities/word/mutations/useWordMutations.tsx @@ -2,6 +2,7 @@ import { useDataManager } from "@gravity-ui/data-source"; import { useMutation } from "@tanstack/react-query"; import { wordsDataSource } from "../queries/words"; +import type { components } from "@languages-learner/api"; import { sdk } from "@/shared/services/api"; @@ -27,14 +28,24 @@ export const useWordMutations = () => { }); const addWordTranslations = useMutation({ - mutationFn: sdk.words.addWordTranslations, + mutationFn: ({ + wordId, + ...props + }: { wordId: string } & components["schemas"]["AddWordTranslationsRequest"]) => { + return sdk.words.addWordTranslations(wordId, props); + }, onSuccess: () => { dataManager.invalidateSource(wordsDataSource); }, }); const deleteWordTranslations = useMutation({ - mutationFn: sdk.words.deleteWordTranslations, + mutationFn: ({ + wordId, + ...props + }: { wordId: string } & components["schemas"]["DeleteWordTranslationsRequest"]) => { + return sdk.words.deleteWordTranslations(wordId, props); + }, onSuccess: () => { dataManager.invalidateSource(wordsDataSource); }, diff --git a/apps/web/src/ui/entities/word/ui/WordStatusIcon.tsx b/apps/web/src/ui/entities/word/ui/WordStatusIcon.tsx index 3f0d722..61f00a3 100644 --- a/apps/web/src/ui/entities/word/ui/WordStatusIcon.tsx +++ b/apps/web/src/ui/entities/word/ui/WordStatusIcon.tsx @@ -2,28 +2,22 @@ import { classNames } from "@languages-learner/class-names"; import { BiCheck, BiCheckDouble } from "react-icons/bi"; import type { IconBaseProps, IconType } from "react-icons/lib"; -import type { ApiDatabase } from "@languages-learner/api"; +import type { ApiEnums } from "@languages-learner/api"; -const WORD_STATUS_TO_ICON: Record< - ApiDatabase["public"]["Tables"]["words"]["Row"]["status"], - IconType -> = { +const WORD_STATUS_TO_ICON: Record, IconType> = { New: BiCheck, Learn: BiCheck, Learned: BiCheckDouble, }; -const WORD_STATUS_ICON_CLASS_NAME: Record< - ApiDatabase["public"]["Tables"]["words"]["Row"]["status"], - string -> = { +const WORD_STATUS_ICON_CLASS_NAME: Record, string> = { New: "text-[hsl(var(--app-default-400))]", Learn: "text-[hsl(var(--app-warning))]", Learned: "text-[hsl(var(--app-success))]", }; export interface WordStatusIconProps extends IconBaseProps { - status: ApiDatabase["public"]["Tables"]["words"]["Row"]["status"]; + status: ApiEnums<"UserWordStatus">; } export const WordStatusIcon: React.FC = ({ status, ...iconProps }) => { diff --git a/apps/web/src/ui/entities/word/ui/WordStatusSelector.tsx b/apps/web/src/ui/entities/word/ui/WordStatusSelector.tsx index 2e24407..7e243de 100644 --- a/apps/web/src/ui/entities/word/ui/WordStatusSelector.tsx +++ b/apps/web/src/ui/entities/word/ui/WordStatusSelector.tsx @@ -8,14 +8,14 @@ import { BiEdit } from "react-icons/bi"; import { WORD_STATUS_NAME } from "../constants"; import { WordStatusIcon } from "./WordStatusIcon"; -import type { ApiDatabase } from "@languages-learner/api"; +import type { ApiEnums } from "@languages-learner/api"; import type { WordStatusIconProps } from "./WordStatusIcon"; import { intl } from "@/shared/i18n"; export interface WordStatusSelectorProps { - status?: ApiDatabase["public"]["Tables"]["words"]["Row"]["status"]; - onUpdate: (status: ApiDatabase["public"]["Tables"]["words"]["Row"]["status"]) => unknown; + status?: ApiEnums<"UserWordStatus">; + onUpdate: (status: ApiEnums<"UserWordStatus">) => unknown; variant: "icon" | "button"; classNames?: { trigger?: string; @@ -55,8 +55,6 @@ export const WordStatusSelector: React.FC = ({ })} ); - - return null; }; return ( @@ -70,9 +68,7 @@ export const WordStatusSelector: React.FC = ({ variant="flat" onSelectionChange={(values) => { if (values.currentKey) { - onUpdate( - values.currentKey as ApiDatabase["public"]["Tables"]["words"]["Row"]["status"], - ); + onUpdate(values.currentKey as ApiEnums<"UserWordStatus">); } }} > diff --git a/apps/web/src/ui/features/learning-language/learningLanguageSelector/ui/LearningLanguageSelector.tsx b/apps/web/src/ui/features/learning-language/learningLanguageSelector/ui/LearningLanguageSelector.tsx index 7fb5920..fa2f8d0 100644 --- a/apps/web/src/ui/features/learning-language/learningLanguageSelector/ui/LearningLanguageSelector.tsx +++ b/apps/web/src/ui/features/learning-language/learningLanguageSelector/ui/LearningLanguageSelector.tsx @@ -23,7 +23,6 @@ export const LearningLanguageSelector: React.FC = (value: string) => { withToasts( updateUser.mutateAsync({ - userId: user.uid, payload: { active_learning_language: value, }, diff --git a/apps/web/src/ui/features/theme/themeSelector/ui/ThemeSelector/constants.ts b/apps/web/src/ui/features/theme/themeSelector/ui/ThemeSelector/constants.ts index ecbe111..c140660 100644 --- a/apps/web/src/ui/features/theme/themeSelector/ui/ThemeSelector/constants.ts +++ b/apps/web/src/ui/features/theme/themeSelector/ui/ThemeSelector/constants.ts @@ -1,8 +1,8 @@ -import type { ApiDatabase } from "@languages-learner/api"; +import type { ApiEnums } from "@languages-learner/api"; import { intl } from "@/shared/i18n"; -export const THEME_NAME: Record = { +export const THEME_NAME: Record, string> = { system: intl.formatMessage({ defaultMessage: "System", id: "+CwN9C" }), dark: intl.formatMessage({ defaultMessage: "Dark", id: "tOdNiY" }), light: intl.formatMessage({ defaultMessage: "Light", id: "3cc4Ct" }), diff --git a/apps/web/src/ui/features/words/table/hooks/useWordsTableColumns.ts b/apps/web/src/ui/features/words/table/hooks/useWordsTableColumns.ts index 5058da4..6cfcc57 100644 --- a/apps/web/src/ui/features/words/table/hooks/useWordsTableColumns.ts +++ b/apps/web/src/ui/features/words/table/hooks/useWordsTableColumns.ts @@ -3,7 +3,7 @@ import React from "react"; import { withToasts } from "@languages-learner/uikit"; import type { ColumnDef } from "@tanstack/react-table"; -import type { WordWithTranslations } from "@languages-learner/api"; +import type { components } from "@languages-learner/api"; import { useUserSafe } from "@/entities/user"; import { useWordMutations, wordColumns } from "@/entities/word"; @@ -16,7 +16,9 @@ export const useWordsTableColumns = () => { const { updateWordsStatus, addWordTranslations, deleteWordTranslations, deleteWords } = useWordMutations(); - const wordsTableColumns = React.useMemo[]>(() => { + const wordsTableColumns = React.useMemo< + ColumnDef[] + >(() => { return [ wordColumns.selection, wordColumns.textAndTranslationWithEdit({ diff --git a/apps/web/src/ui/features/words/table/ui/WordsTableFilters/lib.ts b/apps/web/src/ui/features/words/table/ui/WordsTableFilters/lib.ts index 045d250..cfad5dc 100644 --- a/apps/web/src/ui/features/words/table/ui/WordsTableFilters/lib.ts +++ b/apps/web/src/ui/features/words/table/ui/WordsTableFilters/lib.ts @@ -1,8 +1,8 @@ -import type { ApiTables } from "@languages-learner/api"; +import type { ApiEnums } from "@languages-learner/api"; export interface WordsTableFiltersType { text?: string; - status?: ApiTables<"words">["status"]; + status?: ApiEnums<"UserWordStatus">; } export const initialFilters: WordsTableFiltersType = { diff --git a/apps/web/src/ui/pages/workspace/office/settings/ui/OfficeSettingsPage.tsx b/apps/web/src/ui/pages/workspace/office/settings/ui/OfficeSettingsPage.tsx index 690223e..a950a8f 100644 --- a/apps/web/src/ui/pages/workspace/office/settings/ui/OfficeSettingsPage.tsx +++ b/apps/web/src/ui/pages/workspace/office/settings/ui/OfficeSettingsPage.tsx @@ -1,7 +1,7 @@ import { FormRowsContainer } from "@languages-learner/form-components"; import { withToasts } from "@languages-learner/uikit"; import { INTERFACE_LOCALES } from "shared/project-config"; -import type { ApiTables } from "@languages-learner/api"; +import type { ApiEnums } from "@languages-learner/api"; import { useUserMutations, useUserSafe } from "@/entities/user"; import { LanguageSelector } from "@/features/language/languageSelector"; @@ -17,7 +17,6 @@ export const OfficeSettingsPage = () => { const handleUpdateNativeLanguage = (language: string) => { return withToasts( updateUser.mutateAsync({ - userId: user.uid, payload: { native_language: language, }, @@ -38,7 +37,6 @@ export const OfficeSettingsPage = () => { const handleUpdateInterfaceLanguage = (language: string) => { return withToasts( updateUser.mutateAsync({ - userId: user.uid, payload: { interface_language: language, }, @@ -56,10 +54,9 @@ export const OfficeSettingsPage = () => { ); }; - const handleUpdateTheme = (theme: ApiTables<"user">["theme"]) => { + const handleUpdateTheme = (theme: ApiEnums<"Theme">) => { return withToasts( updateUser.mutateAsync({ - userId: user.uid, payload: { theme, }, @@ -130,7 +127,7 @@ export const OfficeSettingsPage = () => { selectedKeys={[user.theme]} onSelectionChange={(value) => { if (value.currentKey) { - handleUpdateTheme(value.currentKey as ApiTables<"user">["theme"]); + handleUpdateTheme(value.currentKey as ApiEnums<"Theme">); } }} /> diff --git a/apps/web/src/ui/shared/services/api/index.ts b/apps/web/src/ui/shared/services/api/index.ts index c9e9113..f954159 100644 --- a/apps/web/src/ui/shared/services/api/index.ts +++ b/apps/web/src/ui/shared/services/api/index.ts @@ -1,2 +1,2 @@ -export { supabase } from "./supabase"; export { sdk } from "./sdk"; +export { supabase } from "./supabase"; diff --git a/apps/web/src/ui/shared/services/api/sdk.ts b/apps/web/src/ui/shared/services/api/sdk.ts index 611433f..5b60281 100644 --- a/apps/web/src/ui/shared/services/api/sdk.ts +++ b/apps/web/src/ui/shared/services/api/sdk.ts @@ -1,5 +1,4 @@ import { createSdk } from "@languages-learner/api"; - import { supabase } from "./supabase"; -export const sdk: ReturnType = createSdk(supabase); +export const sdk = createSdk(supabase); diff --git a/apps/web/src/ui/shared/services/api/supabase.ts b/apps/web/src/ui/shared/services/api/supabase.ts index 8240e86..a6d100d 100644 --- a/apps/web/src/ui/shared/services/api/supabase.ts +++ b/apps/web/src/ui/shared/services/api/supabase.ts @@ -1,10 +1,7 @@ import { createBrowserClient } from "@supabase/ssr"; import type { SupabaseClient } from "@supabase/supabase-js"; -import type { ApiDatabase } from "@languages-learner/api"; - -export const supabase: SupabaseClient = - createBrowserClient( - import.meta.env.VITE_SUPABASE_PROJECT_URL, - import.meta.env.VITE_SUPABASE_PROJECT_KEY, - ); +export const supabase: SupabaseClient = createBrowserClient( + import.meta.env.VITE_SUPABASE_PROJECT_URL, + import.meta.env.VITE_SUPABASE_PROJECT_KEY, +); diff --git a/apps/web/src/ui/shared/services/auth/supabase/stores/SupabaseAuthProvider/constants.ts b/apps/web/src/ui/shared/services/auth/supabase/stores/SupabaseAuthProvider/constants.ts index 96f5b8a..a746cdc 100644 --- a/apps/web/src/ui/shared/services/auth/supabase/stores/SupabaseAuthProvider/constants.ts +++ b/apps/web/src/ui/shared/services/auth/supabase/stores/SupabaseAuthProvider/constants.ts @@ -2,13 +2,10 @@ import React from "react"; import type { Session, SupabaseClient } from "@supabase/supabase-js"; -// import { type } from "@/shared/services/api"; -import type { ApiDatabase } from "@languages-learner/api"; - export interface AuthState { session: Session | null; isLoggedIn: boolean; - supabase: SupabaseClient; + supabase: SupabaseClient; } export const SupabaseAuthContext = React.createContext({} as AuthState); diff --git a/apps/web/src/ui/widgets/words/tableWithFilters/ui/WordsTableWithFilters/WordsTableActionsPanel.tsx b/apps/web/src/ui/widgets/words/tableWithFilters/ui/WordsTableWithFilters/WordsTableActionsPanel.tsx index 3c68a5e..e0142f4 100644 --- a/apps/web/src/ui/widgets/words/tableWithFilters/ui/WordsTableWithFilters/WordsTableActionsPanel.tsx +++ b/apps/web/src/ui/widgets/words/tableWithFilters/ui/WordsTableWithFilters/WordsTableActionsPanel.tsx @@ -1,7 +1,7 @@ import React from "react"; import { ActionsPanel, withToasts } from "@languages-learner/uikit"; -import type { WordWithTranslations } from "@languages-learner/api"; +import type { components } from "@languages-learner/api"; import type { ActionsPanelProps } from "@languages-learner/uikit"; import { WordStatusSelector, useWordMutations } from "@/entities/word"; @@ -11,7 +11,7 @@ export interface WordsTableActionsPanelProps extends Pick< ActionsPanelProps, "className" | "style" > { - selectedWords: WordWithTranslations["translations"]; + selectedWords: components["schemas"]["WordWithTranslationsDto"]["translations"]; onClose: () => unknown; } diff --git a/apps/web/src/ui/widgets/words/tableWithFilters/ui/WordsTableWithFilters/WordsTableWithFilters.tsx b/apps/web/src/ui/widgets/words/tableWithFilters/ui/WordsTableWithFilters/WordsTableWithFilters.tsx index 8ba921f..688af48 100644 --- a/apps/web/src/ui/widgets/words/tableWithFilters/ui/WordsTableWithFilters/WordsTableWithFilters.tsx +++ b/apps/web/src/ui/widgets/words/tableWithFilters/ui/WordsTableWithFilters/WordsTableWithFilters.tsx @@ -14,7 +14,6 @@ import { getCoreRowModel, useReactTable } from "@tanstack/react-table"; import { WordsTableActionsPanel } from "./WordsTableActionsPanel"; import type { WordsTableFiltersType } from "@/features/words/table"; -import type { FetchWordsRequest } from "@languages-learner/api"; import type { ActionsPanelProps } from "@languages-learner/uikit"; import type { RowSelectionState } from "@tanstack/react-table"; @@ -41,12 +40,9 @@ export const WordsTableWithFilters: React.FC = ({ ); const [showAddWordCard, setShowAddWordCard] = React.useState(false); - const requestFilter = React.useMemo(() => { + const requestFilter = React.useMemo(() => { if (debouncedFilters.text || debouncedFilters.status) { - return { - text: debouncedFilters.text, - status: debouncedFilters.status, - }; + return debouncedFilters; } return undefined; @@ -55,7 +51,8 @@ export const WordsTableWithFilters: React.FC = ({ const wordsQuery = useQueryData(wordsDataSource, { pageSize: 100, language: user.activeLearningLanguage, - filter: requestFilter, + filterStatus: requestFilter?.status, + filterText: requestFilter?.text, }); const hasWordsOrUseFilter = wordsQuery.data.length > 0 || requestFilter; diff --git a/apps/web/vite.config.ts b/apps/web/vite.config.ts index 24546d0..8f4107b 100644 --- a/apps/web/vite.config.ts +++ b/apps/web/vite.config.ts @@ -61,5 +61,11 @@ export default defineConfig({ server: { // For docker tests running on DEV server (npm run dev) allowedHosts: ["host.docker.internal"], + proxy: { + "/api": { + target: `http://localhost:${process.env.BACKEND_PORT || 3001}`, + changeOrigin: true, + }, + }, }, }); diff --git a/packages/api/scripts/tsconfig.json b/packages/api/scripts/tsconfig.json deleted file mode 100644 index 584f0a4..0000000 --- a/packages/api/scripts/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "../../../tsconfig.scripts.base.json", - "include": [ - ".", - ] -} diff --git a/packages/api/src/database.types.public.ts b/packages/api/src/database.types.public.ts index e2d5719..312f1dc 100644 --- a/packages/api/src/database.types.public.ts +++ b/packages/api/src/database.types.public.ts @@ -1,10 +1,3 @@ -export type { - Database as ApiDatabase, - Tables as ApiTables, - TablesInsert as ApiTablesInsert, - TablesUpdate as ApiTablesUpdate, - Enums as ApiEnums, - CompositeTypes as ApiCompositeType, -} from "./database.types"; +export type { Enums as ApiEnums } from "./database.types"; export { Constants as ApiConstants } from "./database.types"; diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 7df48d2..553ab2e 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -1,6 +1,7 @@ export type { ApiError, PaginatedResponse, PaginatedRequestParams } from "./types"; +export { getErrorMessage } from "./utils/getErrorMessage"; +export * from "./schemas/api"; export * from "./database.types.public"; export * from "./sdk"; -export { getErrorMessage } from "./utils/getErrorMessage"; // Fixing error: The inferred type of 'useWordMutations' cannot be named without a reference to "@supabase/postgrest-js" -export * from "@supabase/postgrest-js"; +// export * from "@supabase/postgrest-js"; diff --git a/packages/api/src/schemas/api.ts b/packages/api/src/schemas/api.ts new file mode 100644 index 0000000..2ffff94 --- /dev/null +++ b/packages/api/src/schemas/api.ts @@ -0,0 +1,654 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export interface paths { + "/api/health": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get: operations["AppController_getHealth"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/user": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get current user */ + get: operations["UserController_getUser"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** Update current user */ + patch: operations["UserController_updateUser"]; + trace?: never; + }; + "/api/words": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get words */ + get: operations["WordsController_getWords"]; + put?: never; + /** Create word */ + post: operations["WordsController_createWord"]; + /** Delete words */ + delete: operations["WordsController_deleteWords"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/api/words/status": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** Update words status */ + patch: operations["WordsController_updateWordsStatus"]; + trace?: never; + }; + "/api/words/{wordId}/translations": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** Add translations to word */ + post: operations["WordsController_addWordTranslations"]; + /** Delete translations from word */ + delete: operations["WordsController_deleteWordTranslations"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; +} +export type webhooks = Record; +export interface components { + schemas: { + UpdateUserPayloadDto: { + /** + * @description Active learning language code + * @example en + */ + active_learning_language?: string; + /** + * @description Interface language code + * @example en + */ + interface_language?: string; + /** + * @description Native language code + * @example ru + */ + native_language?: string; + /** + * @description Theme preference + * @example system + * @enum {string} + */ + theme?: "system" | "dark" | "light"; + }; + UpdateUserResponse: { + /** + * @description User ID + * @example uuid + */ + id: string; + /** + * @description Active learning language code + * @example en + */ + active_learning_language: string; + /** + * @description Interface language code + * @example en + */ + interface_language: string; + /** + * @description Native language code + * @example ru + */ + native_language: string; + /** + * @description Theme preference + * @example system + * @enum {string} + */ + theme: "system" | "dark" | "light"; + }; + GetUserResponse: { + /** + * @description User ID + * @example uuid + */ + id: string; + /** + * @description Active learning language code + * @example en + */ + active_learning_language: string; + /** + * @description Interface language code + * @example en + */ + interface_language: string; + /** + * @description Native language code + * @example ru + */ + native_language: string; + /** + * @description Theme preference + * @example system + * @enum {string} + */ + theme: "system" | "dark" | "light"; + }; + UpdateUserRequest: { + /** @description Partial user data to update */ + payload: components["schemas"]["UpdateUserPayloadDto"]; + }; + TranslationResponseDto: { + /** + * @description Translation ID + * @example uuid + */ + id: string; + /** + * @description Translation text + * @example привет + */ + text: string; + /** + * @description Translation language code + * @example ru + */ + language: string; + }; + WordWithTranslationsDto: { + /** + * @description Word ID + * @example uuid + */ + id: string; + /** + * @description Creation timestamp + * @example 2024-01-01T00:00:00Z + */ + created_at: string; + /** + * @description Update timestamp + * @example 2024-01-01T00:00:00Z + */ + updated_at: string; + /** + * @description User ID + * @example uuid + */ + user_id: string; + /** + * @description Word language code + * @example en + */ + language: string; + /** + * @description Word text + * @example hello + */ + text: string; + /** + * @description Sort ID for ordering + * @example 1 + */ + sort_id: number; + /** + * @description Word status + * @example New + * @enum {string} + */ + status: "New" | "Learn" | "Learned"; + /** @description Array of translations */ + translations: components["schemas"]["TranslationResponseDto"][]; + }; + FetchWordsResponse: { + /** @description Array of words with translations */ + words: components["schemas"]["WordWithTranslationsDto"][]; + /** + * @description Token for next page pagination + * @example 10 + */ + nextPageToken: number | null; + }; + CreateWordResponse: { + /** + * @description Word ID + * @example uuid + */ + id: string; + /** + * @description Creation timestamp + * @example 2024-01-01T00:00:00Z + */ + created_at: string; + /** + * @description Update timestamp + * @example 2024-01-01T00:00:00Z + */ + updated_at: string; + /** + * @description User ID + * @example uuid + */ + user_id: string; + /** + * @description Word language code + * @example en + */ + language: string; + /** + * @description Word text + * @example hello + */ + text: string; + /** + * @description Sort ID for ordering + * @example 1 + */ + sort_id: number; + /** + * @description Word status + * @example New + * @enum {string} + */ + status: "New" | "Learn" | "Learned"; + /** @description Array of translations */ + translations: components["schemas"]["TranslationResponseDto"][]; + }; + WordResponseDto: { + /** + * @description Word ID + * @example uuid + */ + id: string; + /** + * @description Creation timestamp + * @example 2024-01-01T00:00:00Z + */ + created_at: string; + /** + * @description Update timestamp + * @example 2024-01-01T00:00:00Z + */ + updated_at: string; + /** + * @description User ID + * @example uuid + */ + user_id: string; + /** + * @description Word language code + * @example en + */ + language: string; + /** + * @description Word text + * @example hello + */ + text: string; + /** + * @description Sort ID for ordering + * @example 1 + */ + sort_id: number; + /** + * @description Word status + * @example New + * @enum {string} + */ + status: "New" | "Learn" | "Learned"; + }; + UpdateWordsStatusResponse: { + /** @description Array of updated words */ + words: components["schemas"]["WordResponseDto"][]; + }; + DeleteWordsResponse: { + /** @description Array of deleted words */ + words: components["schemas"]["WordResponseDto"][]; + }; + AddWordTranslationsResponse: { + /** @description Array of added translations */ + translations: components["schemas"]["TranslationResponseDto"][]; + }; + DeleteWordTranslationsResponse: { + /** @description Array of deleted translations */ + translations: components["schemas"]["TranslationResponseDto"][]; + }; + WordDto: { + /** + * @description Language code + * @example en + */ + language: string; + /** + * @description Word text + * @example hello + */ + text: string; + }; + TranslationDto: { + /** + * @description Translation text + * @example привет + */ + text: string; + /** + * @description Translation language code + * @example ru + */ + language: string; + }; + CreateWordRequest: { + /** @description Word information */ + word: components["schemas"]["WordDto"]; + /** @description Array of translations */ + translations: components["schemas"]["TranslationDto"][]; + }; + UpdateWordsStatusRequest: { + /** + * @description Array of word IDs + * @example [ + * "uuid1", + * "uuid2" + * ] + */ + wordsIds: string[]; + /** + * @description New status for words + * @example New + * @enum {string} + */ + status: "New" | "Learn" | "Learned"; + }; + DeleteWordsRequest: { + /** + * @description Array of word IDs to delete + * @example [ + * "uuid1", + * "uuid2" + * ] + */ + wordIds: string[]; + }; + AddWordTranslationsRequest: { + /** @description Array of translations to add */ + translations: components["schemas"]["TranslationDto"][]; + }; + DeleteWordTranslationsRequest: { + /** + * @description Array of translation IDs to delete + * @example [ + * "uuid1", + * "uuid2" + * ] + */ + translationsIds: string[]; + }; + }; + responses: never; + parameters: never; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export interface operations { + AppController_getHealth: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + UserController_getUser: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description User retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["GetUserResponse"]; + }; + }; + }; + }; + UserController_updateUser: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateUserRequest"]; + }; + }; + responses: { + /** @description User updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["UpdateUserResponse"]; + }; + }; + }; + }; + WordsController_getWords: { + parameters: { + query: { + /** @description Language code */ + language: string; + /** @description Number of items per page */ + pageSize: number; + /** @description Page token for pagination */ + pageToken?: number; + /** @description Filter by word text */ + filterText?: string; + /** @description Filter by word status */ + filterStatus?: "New" | "Learn" | "Learned"; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Words retrieved successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["FetchWordsResponse"]; + }; + }; + }; + }; + WordsController_createWord: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CreateWordRequest"]; + }; + }; + responses: { + /** @description Word created successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CreateWordResponse"]; + }; + }; + }; + }; + WordsController_deleteWords: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["DeleteWordsRequest"]; + }; + }; + responses: { + /** @description Words deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DeleteWordsResponse"]; + }; + }; + }; + }; + WordsController_updateWordsStatus: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateWordsStatusRequest"]; + }; + }; + responses: { + /** @description Words status updated successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["UpdateWordsStatusResponse"]; + }; + }; + }; + }; + WordsController_addWordTranslations: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Word ID */ + wordId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["AddWordTranslationsRequest"]; + }; + }; + responses: { + /** @description Translations added successfully */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["AddWordTranslationsResponse"]; + }; + }; + }; + }; + WordsController_deleteWordTranslations: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Word ID */ + wordId: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["DeleteWordTranslationsRequest"]; + }; + }; + responses: { + /** @description Translations deleted successfully */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["DeleteWordTranslationsResponse"]; + }; + }; + }; + }; +} diff --git a/packages/api/src/schemas/openapi.json b/packages/api/src/schemas/openapi.json new file mode 100644 index 0000000..c3b149b --- /dev/null +++ b/packages/api/src/schemas/openapi.json @@ -0,0 +1,1014 @@ +{ + "openapi": "3.0.0", + "paths": { + "/api/health": { + "get": { + "operationId": "AppController_getHealth", + "parameters": [], + "responses": { + "200": { + "description": "" + } + } + } + }, + "/api/user": { + "get": { + "operationId": "UserController_getUser", + "summary": "Get current user", + "parameters": [], + "responses": { + "200": { + "description": "User retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetUserResponse" + } + } + } + } + }, + "tags": [ + "user" + ], + "security": [ + { + "bearer": [] + } + ] + }, + "patch": { + "operationId": "UserController_updateUser", + "summary": "Update current user", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateUserRequest" + } + } + } + }, + "responses": { + "200": { + "description": "User updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateUserResponse" + } + } + } + } + }, + "tags": [ + "user" + ], + "security": [ + { + "bearer": [] + } + ] + } + }, + "/api/words": { + "get": { + "operationId": "WordsController_getWords", + "summary": "Get words", + "parameters": [ + { + "name": "language", + "required": true, + "in": "query", + "description": "Language code", + "schema": { + "example": "en", + "type": "string" + } + }, + { + "name": "pageSize", + "required": true, + "in": "query", + "description": "Number of items per page", + "schema": { + "example": 20, + "type": "number" + } + }, + { + "name": "pageToken", + "required": false, + "in": "query", + "description": "Page token for pagination", + "schema": { + "example": 10, + "type": "number" + } + }, + { + "name": "filterText", + "required": false, + "in": "query", + "description": "Filter by word text", + "schema": { + "example": "hello", + "type": "string" + } + }, + { + "name": "filterStatus", + "required": false, + "in": "query", + "description": "Filter by word status", + "schema": { + "example": "New", + "enum": [ + "New", + "Learn", + "Learned" + ], + "type": "string" + } + }, + { + "description": "Language code", + "name": "language", + "in": "query", + "required": true, + "schema": { + "example": "en", + "type": "string" + } + }, + { + "description": "Number of items per page", + "name": "pageSize", + "in": "query", + "required": true, + "schema": { + "example": 20, + "type": "number" + } + }, + { + "description": "Page token for pagination", + "required": false, + "name": "pageToken", + "in": "query", + "schema": { + "example": 10, + "type": "number" + } + }, + { + "description": "Filter by word text", + "required": false, + "name": "filterText", + "in": "query", + "schema": { + "example": "hello", + "type": "string" + } + }, + { + "description": "Filter by word status", + "required": false, + "name": "filterStatus", + "in": "query", + "schema": { + "example": "New", + "enum": [ + "New", + "Learn", + "Learned" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Words retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FetchWordsResponse" + } + } + } + } + }, + "tags": [ + "words" + ], + "security": [ + { + "bearer": [] + } + ] + }, + "post": { + "operationId": "WordsController_createWord", + "summary": "Create word", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWordRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Word created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWordResponse" + } + } + } + } + }, + "tags": [ + "words" + ], + "security": [ + { + "bearer": [] + } + ] + }, + "delete": { + "operationId": "WordsController_deleteWords", + "summary": "Delete words", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteWordsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Words deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteWordsResponse" + } + } + } + } + }, + "tags": [ + "words" + ], + "security": [ + { + "bearer": [] + } + ] + } + }, + "/api/words/status": { + "patch": { + "operationId": "WordsController_updateWordsStatus", + "summary": "Update words status", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateWordsStatusRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Words status updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateWordsStatusResponse" + } + } + } + } + }, + "tags": [ + "words" + ], + "security": [ + { + "bearer": [] + } + ] + } + }, + "/api/words/{wordId}/translations": { + "post": { + "operationId": "WordsController_addWordTranslations", + "summary": "Add translations to word", + "parameters": [ + { + "name": "wordId", + "required": true, + "in": "path", + "description": "Word ID", + "schema": { + "example": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddWordTranslationsRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Translations added successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddWordTranslationsResponse" + } + } + } + } + }, + "tags": [ + "words" + ], + "security": [ + { + "bearer": [] + } + ] + }, + "delete": { + "operationId": "WordsController_deleteWordTranslations", + "summary": "Delete translations from word", + "parameters": [ + { + "name": "wordId", + "required": true, + "in": "path", + "description": "Word ID", + "schema": { + "example": "uuid", + "type": "string" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteWordTranslationsRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Translations deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DeleteWordTranslationsResponse" + } + } + } + } + }, + "tags": [ + "words" + ], + "security": [ + { + "bearer": [] + } + ] + } + } + }, + "info": { + "title": "Languages Learner API", + "description": "API for Languages Learner application", + "version": "1.0", + "contact": {} + }, + "tags": [], + "servers": [], + "components": { + "securitySchemes": { + "bearer": { + "scheme": "bearer", + "bearerFormat": "JWT", + "type": "http" + } + }, + "schemas": { + "UpdateUserPayloadDto": { + "type": "object", + "properties": { + "active_learning_language": { + "type": "string", + "description": "Active learning language code", + "example": "en" + }, + "interface_language": { + "type": "string", + "description": "Interface language code", + "example": "en" + }, + "native_language": { + "type": "string", + "description": "Native language code", + "example": "ru" + }, + "theme": { + "type": "string", + "description": "Theme preference", + "enum": [ + "system", + "dark", + "light" + ], + "example": "system" + } + } + }, + "UpdateUserResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "User ID", + "example": "uuid" + }, + "active_learning_language": { + "type": "string", + "description": "Active learning language code", + "example": "en" + }, + "interface_language": { + "type": "string", + "description": "Interface language code", + "example": "en" + }, + "native_language": { + "type": "string", + "description": "Native language code", + "example": "ru" + }, + "theme": { + "type": "string", + "description": "Theme preference", + "enum": [ + "system", + "dark", + "light" + ], + "example": "system" + } + }, + "required": [ + "id", + "active_learning_language", + "interface_language", + "native_language", + "theme" + ] + }, + "GetUserResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "User ID", + "example": "uuid" + }, + "active_learning_language": { + "type": "string", + "description": "Active learning language code", + "example": "en" + }, + "interface_language": { + "type": "string", + "description": "Interface language code", + "example": "en" + }, + "native_language": { + "type": "string", + "description": "Native language code", + "example": "ru" + }, + "theme": { + "type": "string", + "description": "Theme preference", + "enum": [ + "system", + "dark", + "light" + ], + "example": "system" + } + }, + "required": [ + "id", + "active_learning_language", + "interface_language", + "native_language", + "theme" + ] + }, + "UpdateUserRequest": { + "type": "object", + "properties": { + "payload": { + "description": "Partial user data to update", + "allOf": [ + { + "$ref": "#/components/schemas/UpdateUserPayloadDto" + } + ] + } + }, + "required": [ + "payload" + ] + }, + "TranslationResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Translation ID", + "example": "uuid" + }, + "text": { + "type": "string", + "description": "Translation text", + "example": "привет" + }, + "language": { + "type": "string", + "description": "Translation language code", + "example": "ru" + } + }, + "required": [ + "id", + "text", + "language" + ] + }, + "WordWithTranslationsDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Word ID", + "example": "uuid" + }, + "created_at": { + "type": "string", + "description": "Creation timestamp", + "example": "2024-01-01T00:00:00Z" + }, + "updated_at": { + "type": "string", + "description": "Update timestamp", + "example": "2024-01-01T00:00:00Z" + }, + "user_id": { + "type": "string", + "description": "User ID", + "example": "uuid" + }, + "language": { + "type": "string", + "description": "Word language code", + "example": "en" + }, + "text": { + "type": "string", + "description": "Word text", + "example": "hello" + }, + "sort_id": { + "type": "number", + "description": "Sort ID for ordering", + "example": 1 + }, + "status": { + "type": "string", + "description": "Word status", + "enum": [ + "New", + "Learn", + "Learned" + ], + "example": "New" + }, + "translations": { + "description": "Array of translations", + "type": "array", + "items": { + "$ref": "#/components/schemas/TranslationResponseDto" + } + } + }, + "required": [ + "id", + "created_at", + "updated_at", + "user_id", + "language", + "text", + "sort_id", + "status", + "translations" + ] + }, + "FetchWordsResponse": { + "type": "object", + "properties": { + "words": { + "description": "Array of words with translations", + "type": "array", + "items": { + "$ref": "#/components/schemas/WordWithTranslationsDto" + } + }, + "nextPageToken": { + "type": "number", + "description": "Token for next page pagination", + "example": 10, + "nullable": true + } + }, + "required": [ + "words", + "nextPageToken" + ] + }, + "CreateWordResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Word ID", + "example": "uuid" + }, + "created_at": { + "type": "string", + "description": "Creation timestamp", + "example": "2024-01-01T00:00:00Z" + }, + "updated_at": { + "type": "string", + "description": "Update timestamp", + "example": "2024-01-01T00:00:00Z" + }, + "user_id": { + "type": "string", + "description": "User ID", + "example": "uuid" + }, + "language": { + "type": "string", + "description": "Word language code", + "example": "en" + }, + "text": { + "type": "string", + "description": "Word text", + "example": "hello" + }, + "sort_id": { + "type": "number", + "description": "Sort ID for ordering", + "example": 1 + }, + "status": { + "type": "string", + "description": "Word status", + "enum": [ + "New", + "Learn", + "Learned" + ], + "example": "New" + }, + "translations": { + "description": "Array of translations", + "type": "array", + "items": { + "$ref": "#/components/schemas/TranslationResponseDto" + } + } + }, + "required": [ + "id", + "created_at", + "updated_at", + "user_id", + "language", + "text", + "sort_id", + "status", + "translations" + ] + }, + "WordResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Word ID", + "example": "uuid" + }, + "created_at": { + "type": "string", + "description": "Creation timestamp", + "example": "2024-01-01T00:00:00Z" + }, + "updated_at": { + "type": "string", + "description": "Update timestamp", + "example": "2024-01-01T00:00:00Z" + }, + "user_id": { + "type": "string", + "description": "User ID", + "example": "uuid" + }, + "language": { + "type": "string", + "description": "Word language code", + "example": "en" + }, + "text": { + "type": "string", + "description": "Word text", + "example": "hello" + }, + "sort_id": { + "type": "number", + "description": "Sort ID for ordering", + "example": 1 + }, + "status": { + "type": "string", + "description": "Word status", + "enum": [ + "New", + "Learn", + "Learned" + ], + "example": "New" + } + }, + "required": [ + "id", + "created_at", + "updated_at", + "user_id", + "language", + "text", + "sort_id", + "status" + ] + }, + "UpdateWordsStatusResponse": { + "type": "object", + "properties": { + "words": { + "description": "Array of updated words", + "type": "array", + "items": { + "$ref": "#/components/schemas/WordResponseDto" + } + } + }, + "required": [ + "words" + ] + }, + "DeleteWordsResponse": { + "type": "object", + "properties": { + "words": { + "description": "Array of deleted words", + "type": "array", + "items": { + "$ref": "#/components/schemas/WordResponseDto" + } + } + }, + "required": [ + "words" + ] + }, + "AddWordTranslationsResponse": { + "type": "object", + "properties": { + "translations": { + "description": "Array of added translations", + "type": "array", + "items": { + "$ref": "#/components/schemas/TranslationResponseDto" + } + } + }, + "required": [ + "translations" + ] + }, + "DeleteWordTranslationsResponse": { + "type": "object", + "properties": { + "translations": { + "description": "Array of deleted translations", + "type": "array", + "items": { + "$ref": "#/components/schemas/TranslationResponseDto" + } + } + }, + "required": [ + "translations" + ] + }, + "WordDto": { + "type": "object", + "properties": { + "language": { + "type": "string", + "description": "Language code", + "example": "en" + }, + "text": { + "type": "string", + "description": "Word text", + "example": "hello" + } + }, + "required": [ + "language", + "text" + ] + }, + "TranslationDto": { + "type": "object", + "properties": { + "text": { + "type": "string", + "description": "Translation text", + "example": "привет" + }, + "language": { + "type": "string", + "description": "Translation language code", + "example": "ru" + } + }, + "required": [ + "text", + "language" + ] + }, + "CreateWordRequest": { + "type": "object", + "properties": { + "word": { + "description": "Word information", + "allOf": [ + { + "$ref": "#/components/schemas/WordDto" + } + ] + }, + "translations": { + "description": "Array of translations", + "type": "array", + "items": { + "$ref": "#/components/schemas/TranslationDto" + } + } + }, + "required": [ + "word", + "translations" + ] + }, + "UpdateWordsStatusRequest": { + "type": "object", + "properties": { + "wordsIds": { + "description": "Array of word IDs", + "example": [ + "uuid1", + "uuid2" + ], + "type": "array", + "items": { + "type": "string" + } + }, + "status": { + "type": "string", + "description": "New status for words", + "enum": [ + "New", + "Learn", + "Learned" + ], + "example": "New" + } + }, + "required": [ + "wordsIds", + "status" + ] + }, + "DeleteWordsRequest": { + "type": "object", + "properties": { + "wordIds": { + "description": "Array of word IDs to delete", + "example": [ + "uuid1", + "uuid2" + ], + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "wordIds" + ] + }, + "AddWordTranslationsRequest": { + "type": "object", + "properties": { + "translations": { + "description": "Array of translations to add", + "type": "array", + "items": { + "$ref": "#/components/schemas/TranslationDto" + } + } + }, + "required": [ + "translations" + ] + }, + "DeleteWordTranslationsRequest": { + "type": "object", + "properties": { + "translationsIds": { + "description": "Array of translation IDs to delete", + "example": [ + "uuid1", + "uuid2" + ], + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "translationsIds" + ] + } + } + } +} \ No newline at end of file diff --git a/packages/api/src/sdk/client.ts b/packages/api/src/sdk/client.ts new file mode 100644 index 0000000..7759657 --- /dev/null +++ b/packages/api/src/sdk/client.ts @@ -0,0 +1,89 @@ +import type { SupabaseClient } from "@supabase/supabase-js"; + +const API_BASE_URL = "/api"; + +export const createApiClient = (supabase: SupabaseClient) => { + const getAuthToken = async (): Promise => { + const { + data: { session }, + } = await supabase.auth.getSession(); + + return session?.access_token || null; + }; + + const request = async (endpoint: string, options: RequestInit = {}): Promise => { + const token = await getAuthToken(); + const url = `${API_BASE_URL}${endpoint}`; + + const headers: HeadersInit = { + "Content-Type": "application/json", + ...options.headers, + }; + + if (token) { + (headers as Record).Authorization = `Bearer ${token}`; + } + + const response = await fetch(url, { + ...options, + headers, + }); + + if (!response.ok) { + const error = await response.json().catch(() => ({ message: response.statusText })); + throw new Error(error.message || `HTTP error! status: ${response.status}`); + } + + // Handle empty responses + const contentType = response.headers.get("content-type"); + if (contentType && contentType.includes("application/json")) { + return response.json(); + } + + return response.text() as unknown as T; + }; + + return { + get: (endpoint: string, options?: { params?: Record }): Promise => { + const queryString = options?.params + ? `?${new URLSearchParams( + Object.entries(options.params).reduce( + (acc, [key, value]) => { + if (value !== undefined && value !== null) { + acc[key] = String(value); + } + + return acc; + }, + {} as Record, + ), + ).toString()}` + : ""; + + return request(`${endpoint}${queryString}`, { + method: "GET", + }); + }, + + post: (endpoint: string, data?: any): Promise => { + return request(endpoint, { + method: "POST", + body: data ? JSON.stringify(data) : undefined, + }); + }, + + patch: (endpoint: string, data?: any): Promise => { + return request(endpoint, { + method: "PATCH", + body: data ? JSON.stringify(data) : undefined, + }); + }, + + delete: (endpoint: string, data?: any): Promise => { + return request(endpoint, { + method: "DELETE", + body: data ? JSON.stringify(data) : undefined, + }); + }, + }; +}; diff --git a/packages/api/src/sdk/index.ts b/packages/api/src/sdk/index.ts index 92e297d..892c32e 100644 --- a/packages/api/src/sdk/index.ts +++ b/packages/api/src/sdk/index.ts @@ -1,3 +1 @@ export { createSdk } from "./sdk"; -export type * from "./words/types"; -export type * from "./user/types"; diff --git a/packages/api/src/sdk/sdk.ts b/packages/api/src/sdk/sdk.ts index 2f7c669..2cf55d1 100644 --- a/packages/api/src/sdk/sdk.ts +++ b/packages/api/src/sdk/sdk.ts @@ -1,14 +1,77 @@ -import { createUserActions } from "./user"; -import { createWordsActions } from "./words"; -import type { SupabaseClient } from "../supabase"; +import { createApiClient } from "./client"; +import type { components, operations } from "../schemas/api"; +import type { SupabaseClient } from "@supabase/supabase-js"; export const createSdk = (supabase: SupabaseClient) => { + const apiClient = createApiClient(supabase); + return { - get user() { - return createUserActions(supabase); + user: { + fetchUser: async (): Promise => { + return apiClient.get("/user"); + }, + updateUser: async (props: components["schemas"]["UpdateUserRequest"]) => { + return apiClient.patch("/user", { + payload: props.payload, + }); + }, }, get words() { - return createWordsActions(supabase); + return { + fetchWords: async ( + props: operations["WordsController_getWords"]["parameters"]["query"], + ) => { + return apiClient.get("/words", { + params: props, + }); + }, + updateWordsStatus: async ( + props: components["schemas"]["UpdateWordsStatusRequest"], + ) => { + return apiClient.patch( + "/words/status", + { + wordsIds: props.wordsIds, + status: props.status, + }, + ); + }, + createWord: async (props: components["schemas"]["CreateWordRequest"]) => { + return apiClient.post("/words", { + word: props.word, + translations: props.translations, + }); + }, + deleteWords: async (props: components["schemas"]["DeleteWordsRequest"]) => { + return apiClient.delete( + "/words", + { + wordIds: props.wordIds, + }, + ); + }, + addWordTranslations: async ( + wordId: string, + props: components["schemas"]["AddWordTranslationsRequest"], + ) => { + return apiClient.post( + `/words/${wordId}/translations`, + { + translations: props.translations, + }, + ); + }, + deleteWordTranslations: async ( + wordId: string, + props: components["schemas"]["DeleteWordTranslationsRequest"], + ) => { + return apiClient.delete< + components["schemas"]["DeleteWordTranslationsResponse"] + >(`/words/${wordId}/translations`, { + translationsIds: props.translationsIds, + }); + }, + }; }, }; }; diff --git a/packages/api/src/sdk/user/index.ts b/packages/api/src/sdk/user/index.ts deleted file mode 100644 index e0b64c4..0000000 --- a/packages/api/src/sdk/user/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { createUserActions } from "./user"; diff --git a/packages/api/src/sdk/user/types.ts b/packages/api/src/sdk/user/types.ts deleted file mode 100644 index fb042a6..0000000 --- a/packages/api/src/sdk/user/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { ApiDatabase } from "../../database.types.public"; - -export type FetchUserResponse = ApiDatabase["public"]["Tables"]["user"]["Row"]; - -export interface UpdateUserParams { - userId: string; - payload: Partial>; -} diff --git a/packages/api/src/sdk/user/user.ts b/packages/api/src/sdk/user/user.ts deleted file mode 100644 index d27bd9f..0000000 --- a/packages/api/src/sdk/user/user.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { SupabaseClient } from "../../supabase"; - -import type { UpdateUserParams } from "./types"; - -export const createUserActions = (supabase: SupabaseClient) => { - const fetchUser = async () => { - const response = await supabase.from("user").select().single().throwOnError(); - - return response.data; - }; - - const updateUser = async (props: UpdateUserParams) => { - const response = await supabase - .from("user") - .update(props.payload) - .eq("id", props.userId) - .select() - .single() - .throwOnError(); - - return response.data; - }; - - return { - fetchUser, - updateUser, - }; -}; diff --git a/packages/api/src/sdk/words/index.ts b/packages/api/src/sdk/words/index.ts deleted file mode 100644 index a37548e..0000000 --- a/packages/api/src/sdk/words/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { createWordsActions } from "./words"; diff --git a/packages/api/src/sdk/words/types.ts b/packages/api/src/sdk/words/types.ts deleted file mode 100644 index 0ef8d64..0000000 --- a/packages/api/src/sdk/words/types.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { ApiDatabase, ApiTables } from "../../database.types.public"; -import type { PaginatedRequestParams, PaginatedResponse } from "../../types"; - -export type FetchWordsNextPageToken = number; - -export interface FetchWordsRequest extends PaginatedRequestParams { - language: string; - filter?: { - text?: string; - status?: ApiDatabase["public"]["Tables"]["words"]["Row"]["status"]; - }; -} - -export interface FetchWordsResponse extends PaginatedResponse { - words: WordWithTranslations[]; -} - -export type WordWithTranslations = ApiDatabase["public"]["Tables"]["words"]["Row"] & { - translations: Pick, "text" | "language" | "id">[]; -}; - -export interface UpdateWordsStatusRequest { - wordsIds: string[]; - status: ApiDatabase["public"]["Tables"]["words"]["Row"]["status"]; -} - -export interface AddWordTranslationsRequest { - wordId: string; - translations: Omit< - ApiTables<"translations">, - "id" | "created_at" | "updated_at" | "user_id" | "word_id" - >[]; -} - -export interface DeleteWordTranslationsRequest { - wordId: string; - translationsIds: string[]; -} - -export interface CreateWordRequest { - word: Omit< - ApiDatabase["public"]["Tables"]["words"]["Row"], - "id" | "created_at" | "status" | "updated_at" | "user_id" | "sort_id" - >; - translations: Omit< - ApiDatabase["public"]["Tables"]["translations"]["Row"], - "id" | "created_at" | "updated_at" | "user_id" | "word_id" - >[]; -} - -export interface DeleteWordsRequest { - wordIds: string[]; -} diff --git a/packages/api/src/sdk/words/words.ts b/packages/api/src/sdk/words/words.ts deleted file mode 100644 index c8aafc3..0000000 --- a/packages/api/src/sdk/words/words.ts +++ /dev/null @@ -1,110 +0,0 @@ -import type { - AddWordTranslationsRequest, - CreateWordRequest, - DeleteWordTranslationsRequest, - DeleteWordsRequest, - FetchWordsNextPageToken, - FetchWordsRequest, - FetchWordsResponse, - UpdateWordsStatusRequest, -} from "./types"; -import type { SupabaseClient } from "../../supabase"; - -export const createWordsActions = (supabase: SupabaseClient) => { - const fetchWords = async (props: FetchWordsRequest): Promise => { - const itemsRequest = supabase - .from("words") - .select("*, translations (id, text, language)") - .filter("language", "eq", props.language) - .order("sort_id", { ascending: false }) - .limit(props.pageSize + 1) - .throwOnError(); - - if (props.pageToken) { - itemsRequest.filter("sort_id", "lt", props.pageToken); - } - - if (props.filter) { - if (props.filter.text) { - itemsRequest.filter("text", "like", `%${props.filter.text}%`); - } - if (props.filter.status) { - itemsRequest.filter("status", "eq", props.filter.status); - } - } - - const itemsResponse = await itemsRequest; - - const lastItem = itemsResponse.data.at(-2); - - const nextPageToken: FetchWordsNextPageToken | null = - lastItem && itemsResponse.data.length === props.pageSize + 1 ? lastItem.sort_id : null; - - return { - words: itemsResponse.data.slice(0, props.pageSize), - nextPageToken, - }; - }; - - const updateWordsStatus = async (props: UpdateWordsStatusRequest) => { - return await supabase - .from("words") - .update({ status: props.status }) - .in("id", props.wordsIds) - .select() - .throwOnError(); - }; - - const addWordTranslations = async (props: AddWordTranslationsRequest) => { - return await supabase - .from("translations") - .insert( - props.translations.map((translation) => ({ - word_id: props.wordId, - ...translation, - })), - ) - .throwOnError(); - }; - - const deleteWordTranslations = async (props: DeleteWordTranslationsRequest) => { - return await supabase - .from("translations") - .delete() - .in("id", props.translationsIds) - .throwOnError(); - }; - - const createWord = async (props: CreateWordRequest) => { - const word = await supabase - .from("words") - .insert(props.word) - .select() - .single() - .throwOnError(); - - await addWordTranslations({ - wordId: word.data.id, - translations: props.translations, - }); - - return await supabase - .from("words") - .select("*, translations (text, language)") - .filter("id", "eq", word.data.id) - .throwOnError(); - }; - - const deleteWords = async (props: DeleteWordsRequest) => { - return await supabase.from("words").delete().in("id", props.wordIds).throwOnError(); - }; - - return { - fetchWords, - updateWordsStatus, - addWordTranslations, - deleteWordTranslations, - createWord, - deleteWords, - }; -}; diff --git a/packages/api/src/supabase.ts b/packages/api/src/supabase.ts deleted file mode 100644 index f383827..0000000 --- a/packages/api/src/supabase.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { SupabaseClient as BaseSupabaseClient } from "@supabase/supabase-js"; - -import type { ApiDatabase } from "./database.types.public"; - -export type SupabaseClient = BaseSupabaseClient; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 310be9f..66eab94 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,7 +34,7 @@ importers: version: link:packages/har-sanitizer '@playwright/experimental-ct-react': specifier: 1.52.0 - version: 1.52.0(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2) + version: 1.52.0(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2) '@tanstack/eslint-config': specifier: ^0.3.3 version: 0.3.3(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1))(typescript@5.7.3) @@ -49,7 +49,7 @@ importers: version: 19.2.3(@types/react@19.2.7) '@vitest/browser': specifier: ^3.1.4 - version: 3.2.4(playwright@1.57.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@3.2.4) + version: 3.2.4(playwright@1.57.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@3.2.4) cross-env: specifier: ^7.0.3 version: 7.0.3 @@ -73,7 +73,7 @@ importers: version: 5.2.0(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-storybook: specifier: ^9.0.3 - version: 9.1.16(eslint@9.39.1(jiti@2.6.1))(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.7.3) + version: 9.1.16(eslint@9.39.1(jiti@2.6.1))(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.7.3) knip: specifier: 5.61.3 version: 5.61.3(@types/node@22.19.1)(typescript@5.7.3) @@ -103,7 +103,7 @@ importers: version: 19.2.0(react@19.2.0) storybook: specifier: ^9.0.3 - version: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) stylelint: specifier: ^16.20.0 version: 16.26.1(typescript@5.7.3) @@ -130,7 +130,65 @@ importers: version: 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.7.3) vitest: specifier: ^3.1.4 - version: 3.2.4(@types/node@22.19.1)(@vitest/browser@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/node@22.19.1)(@vitest/browser@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + + apps/backend: + dependencies: + '@languages-learner/api': + specifier: workspace:* + version: link:../../packages/api + '@nestjs/common': + specifier: ^10.4.8 + version: 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^10.4.8 + version: 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': + specifier: ^10.4.8 + version: 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.22) + '@nestjs/swagger': + specifier: ^7.4.2 + version: 7.4.2(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.22)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + '@supabase/supabase-js': + specifier: 2.49.4 + version: 2.49.4 + class-transformer: + specifier: ^0.5.1 + version: 0.5.1 + class-validator: + specifier: ^0.14.1 + version: 0.14.4 + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + rxjs: + specifier: ^7.8.1 + version: 7.8.2 + devDependencies: + '@nestjs/cli': + specifier: ^10.4.8 + version: 10.4.9 + '@nestjs/schematics': + specifier: ^10.1.1 + version: 10.2.3(chokidar@3.6.0)(typescript@5.7.3) + '@types/express': + specifier: ^5.0.6 + version: 5.0.6 + '@types/node': + specifier: ^22.15.29 + version: 22.19.1 + dotenv: + specifier: ^16.5.0 + version: 16.6.1 + openapi-typescript: + specifier: ^7.4.3 + version: 7.13.0(typescript@5.7.3) + ts-node: + specifier: 11.0.0-beta.1 + version: 11.0.0-beta.1(@types/node@22.19.1)(typescript@5.7.3) + typescript: + specifier: ~5.7.2 + version: 5.7.3 apps/storybook: dependencies: @@ -142,7 +200,7 @@ importers: version: link:../../packages/tailwind '@tailwindcss/vite': specifier: ^4.1.17 - version: 4.1.17(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.17(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) tailwindcss: specifier: ^4.1.17 version: 4.1.17 @@ -152,31 +210,31 @@ importers: version: 2.4.23(tailwindcss@4.1.17) '@storybook/addon-a11y': specifier: ^9.0.3 - version: 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))) + version: 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))) '@storybook/addon-docs': specifier: ^9.0.3 - version: 9.1.16(@types/react@19.2.7)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))) + version: 9.1.16(@types/react@19.2.7)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))) '@storybook/addon-vitest': specifier: ^9.0.8 - version: 9.1.16(@vitest/browser@3.2.4)(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(vitest@3.2.4) + version: 9.1.16(@vitest/browser@3.2.4)(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(vitest@3.2.4) '@storybook/react-vite': specifier: ^9.0.3 - version: 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.3)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.3)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@storybook/theming': specifier: ^8.6.14 - version: 8.6.14(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))) + version: 8.6.14(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.7.0(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.7.0(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@vueless/storybook-dark-mode': specifier: ^9.0.10 version: 9.0.10(react-dom@19.2.0(react@19.2.0))(react@19.2.0) storybook: specifier: ^9.0.3 - version: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) vite: specifier: ^6.3.1 - version: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + version: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) apps/web: dependencies: @@ -263,7 +321,7 @@ importers: version: 2.49.4 '@tailwindcss/vite': specifier: ^4.1.17 - version: 4.1.17(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.17(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@tanstack/react-query': specifier: ^5.90.11 version: 5.90.11(react@19.2.0) @@ -330,10 +388,13 @@ importers: version: 19.2.3(@types/react@19.2.7) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.7.0(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.7.0(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) babel-plugin-formatjs: specifier: ^10.5.39 version: 10.5.41 + concurrently: + specifier: ^9.1.2 + version: 9.2.1 cookie-parser: specifier: ^1.4.7 version: 1.4.7 @@ -343,12 +404,15 @@ importers: express: specifier: ^5.1.0 version: 5.2.1 + http-proxy-middleware: + specifier: ^3.0.3 + version: 3.0.5 nodemon: specifier: ^3.1.10 version: 3.1.11 rollup-plugin-bundle-stats: specifier: ^4.21.0 - version: 4.21.7(core-js@3.47.0)(rollup@4.53.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.21.7(core-js@3.47.0)(rollup@4.53.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) sass: specifier: ^1.87.0 version: 1.94.2 @@ -357,7 +421,7 @@ importers: version: 4.21.0 vite: specifier: ^6.3.1 - version: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + version: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) apps/web-e2e: {} @@ -405,13 +469,13 @@ importers: version: 2.5.1 vitest: specifier: ^3.1.4 - version: 3.2.4(@types/node@22.19.1)(@vitest/browser@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/node@22.19.1)(@vitest/browser@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) packages/component-core-tests-utils: dependencies: '@playwright/experimental-ct-react': specifier: 1.52.0 - version: 1.52.0(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2) + version: 1.52.0(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2) '@playwright/test': specifier: 1.52.0 version: 1.52.0 @@ -448,7 +512,7 @@ importers: devDependencies: vitest: specifier: ^3.1.4 - version: 3.2.4(@types/node@22.19.1)(@vitest/browser@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + version: 3.2.4(@types/node@22.19.1)(@vitest/browser@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) packages/form-components: dependencies: @@ -467,10 +531,10 @@ importers: version: link:../component-core-tests-utils '@storybook/react': specifier: ^9.0.3 - version: 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3) + version: 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3) '@storybook/react-vite': specifier: ^9.0.3 - version: 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.3)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.3)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) react-final-form: specifier: ^6.5.9 version: 6.5.9(final-form@4.20.10)(react@19.2.0) @@ -558,10 +622,10 @@ importers: version: 2.0.17(@heroui/system@2.4.23(@heroui/theme@2.4.23(tailwindcss@4.1.17))(framer-motion@12.23.25(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@heroui/theme@2.4.23(tailwindcss@4.1.17))(framer-motion@12.23.25(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@playwright/experimental-ct-react': specifier: 1.52.0 - version: 1.52.0(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2) + version: 1.52.0(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2) '@tailwindcss/vite': specifier: ^4.1.17 - version: 4.1.17(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 4.1.17(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@tanstack/react-table': specifier: ^8.21.3 version: 8.21.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -589,10 +653,10 @@ importers: version: link:../tailwind '@storybook/react': specifier: ^9.0.3 - version: 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3) + version: 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3) '@storybook/react-vite': specifier: ^9.0.3 - version: 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.3)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + version: 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.3)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) packages/zod: dependencies: @@ -612,6 +676,24 @@ packages: '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} + '@angular-devkit/core@17.3.11': + resolution: {integrity: sha512-vTNDYNsLIWpYk2I969LMQFH29GTsLzxNk/0cLw5q56ARF0v5sIWfHYwGTS88jdDqIpuuettcSczbxeA7EuAmqQ==} + engines: {node: ^18.13.0 || >=20.9.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + chokidar: ^3.5.2 + peerDependenciesMeta: + chokidar: + optional: true + + '@angular-devkit/schematics-cli@17.3.11': + resolution: {integrity: sha512-kcOMqp+PHAKkqRad7Zd7PbpqJ0LqLaNZdY1+k66lLWmkEBozgq8v4ASn/puPWf9Bo0HpCiK+EzLf0VHE8Z/y6Q==} + engines: {node: ^18.13.0 || >=20.9.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + hasBin: true + + '@angular-devkit/schematics@17.3.11': + resolution: {integrity: sha512-I5wviiIqiFwar9Pdk30Lujk8FczEEc18i22A5c6Z9lbmhPQdTroDnEQdsfXjy404wPe8H62s0I15o4pmMGfTYQ==} + engines: {node: ^18.13.0 || >=20.9.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -708,6 +790,9 @@ packages: '@bem-react/classname@1.7.0': resolution: {integrity: sha512-WNZAJEVNHFpQ1eyR3SKxXUDHaXbTyMieFfC65tqEGvGxx9pMcaKf65v/IINdDBe6xIt6WgGu0EHgFQ5KH4lwZQ==} + '@borewit/text-codec@0.2.1': + resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==} + '@bundle-stats/cli-utils@4.21.7': resolution: {integrity: sha512-NJcxaq1TJY1bsYlH5+JWgPOz1o/wO0I53Srad0gQ7iTNRL9W7q5HNOj4EjyLp4QapXK93ggf4P76/0q1LzOjKQ==} engines: {node: '>= 14.0'} @@ -738,6 +823,10 @@ packages: '@cacheable/utils@2.3.2': resolution: {integrity: sha512-8kGE2P+HjfY8FglaOiW+y8qxcaQAfAhVML+i66XJR3YX5FtyDqn6Txctr3K2FrbxLKixRRYYBWMbuGciOhYNDg==} + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -1584,6 +1673,9 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -1602,12 +1694,23 @@ packages: '@keyv/serialize@1.1.1': resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} + '@ljharb/through@2.3.14': + resolution: {integrity: sha512-ajBvlKpWucBB17FuQYUShqpqy8GRgYEpJW0vWJbUu1CV9lWyrDCapy0lScU8T8Z6qn49sSwJB3+M+evYIdGg+A==} + engines: {node: '>= 0.4'} + + '@lukeed/csprng@1.1.0': + resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} + engines: {node: '>=8'} + '@mdx-js/react@3.1.1': resolution: {integrity: sha512-f++rKLQgUVYDAtECQ6fn/is15GkEH9+nZPM3MS0RcxVqoTfawHvDlSCH7JbMhAM6uJ32v3eXLvLmLvjGu7PTQw==} peerDependencies: '@types/react': '>=16' react: ^19.2.0 + '@microsoft/tsdoc@0.15.1': + resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} + '@mrmlnc/readdir-enhanced@2.2.1': resolution: {integrity: sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==} engines: {node: '>=4'} @@ -1621,6 +1724,90 @@ packages: '@napi-rs/wasm-runtime@1.1.0': resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==} + '@nestjs/cli@10.4.9': + resolution: {integrity: sha512-s8qYd97bggqeK7Op3iD49X2MpFtW4LVNLAwXFkfbRxKME6IYT7X0muNTJ2+QfI8hpbNx9isWkrLWIp+g5FOhiA==} + engines: {node: '>= 16.14'} + hasBin: true + peerDependencies: + '@swc/cli': ^0.1.62 || ^0.3.0 || ^0.4.0 || ^0.5.0 + '@swc/core': ^1.3.62 + peerDependenciesMeta: + '@swc/cli': + optional: true + '@swc/core': + optional: true + + '@nestjs/common@10.4.22': + resolution: {integrity: sha512-fxJ4v85nDHaqT1PmfNCQ37b/jcv2OojtXTaK1P2uAXhzLf9qq6WNUOFvxBrV4fhQek1EQoT1o9oj5xAZmv3NRw==} + peerDependencies: + class-transformer: '*' + class-validator: '*' + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + + '@nestjs/core@10.4.22': + resolution: {integrity: sha512-6IX9+VwjiKtCjx+mXVPncpkQ5ZjKfmssOZPFexmT+6T9H9wZ3svpYACAo7+9e7Nr9DZSoRZw3pffkJP7Z0UjaA==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/microservices': ^10.0.0 + '@nestjs/platform-express': ^10.0.0 + '@nestjs/websockets': ^10.0.0 + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + '@nestjs/microservices': + optional: true + '@nestjs/platform-express': + optional: true + '@nestjs/websockets': + optional: true + + '@nestjs/mapped-types@2.0.5': + resolution: {integrity: sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg==} + peerDependencies: + '@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 + class-transformer: ^0.4.0 || ^0.5.0 + class-validator: ^0.13.0 || ^0.14.0 + reflect-metadata: ^0.1.12 || ^0.2.0 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + + '@nestjs/platform-express@10.4.22': + resolution: {integrity: sha512-ySSq7Py/DFozzZdNDH67m/vHoeVdphDniWBnl6q5QVoXldDdrZIHLXLRMPayTDh5A95nt7jjJzmD4qpTbNQ6tA==} + peerDependencies: + '@nestjs/common': ^10.0.0 + '@nestjs/core': ^10.0.0 + + '@nestjs/schematics@10.2.3': + resolution: {integrity: sha512-4e8gxaCk7DhBxVUly2PjYL4xC2ifDFexCqq1/u4TtivLGXotVk0wHdYuPYe1tHTHuR1lsOkRbfOCpkdTnigLVg==} + peerDependencies: + typescript: '>=4.8.2' + + '@nestjs/swagger@7.4.2': + resolution: {integrity: sha512-Mu6TEn1M/owIvAx2B4DUQObQXqo2028R2s9rSZ/hJEgBK95+doTwS0DjmVA2wTeZTyVtXOoN7CsoM5pONBzvKQ==} + peerDependencies: + '@fastify/static': ^6.0.0 || ^7.0.0 + '@nestjs/common': ^9.0.0 || ^10.0.0 + '@nestjs/core': ^9.0.0 || ^10.0.0 + class-transformer: '*' + class-validator: '*' + reflect-metadata: ^0.1.12 || ^0.2.0 + peerDependenciesMeta: + '@fastify/static': + optional: true + class-transformer: + optional: true + class-validator: + optional: true + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1650,6 +1837,11 @@ packages: peerDependencies: '@tanstack/react-query': '>=5.4.3' + '@nuxtjs/opencollective@0.3.2': + resolution: {integrity: sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true + '@nx/nx-darwin-arm64@22.1.3': resolution: {integrity: sha512-4D/jXGsr3jcQ0vBo8aXXZMdfmC3n4OsZ1zjFaOXlF62Ujug+RqI/IvKxycT9r7Lr09PmW2OqBC01NfIWKoBLhg==} cpu: [arm64] @@ -2186,6 +2378,16 @@ packages: peerDependencies: react: ^19.2.0 + '@redocly/ajv@8.11.2': + resolution: {integrity: sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==} + + '@redocly/config@0.22.0': + resolution: {integrity: sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==} + + '@redocly/openapi-core@1.34.10': + resolution: {integrity: sha512-XCBR/9WHJ0cpezuunHMZjuFMl4KqUo7eiFwzrQrvm7lTXt0EBd3No8UY+9OyzXpDfreGEMMtxmaLZ+ksVw378g==} + engines: {node: '>=18.17.0', npm: '>=9.5.0'} + '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} @@ -2590,6 +2792,13 @@ packages: peerDependencies: '@testing-library/dom': '>=7.21.4' + '@tokenizer/inflate@0.2.7': + resolution: {integrity: sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@ts-graphviz/adapter@2.0.6': resolution: {integrity: sha512-kJ10lIMSWMJkLkkCG5gt927SnGZcBuG0s0HHswGzcHTgvtUe7yk5/3zTEr0bafzsodsOq5Gi6FhQeV775nC35Q==} engines: {node: '>=18'} @@ -2665,6 +2874,9 @@ packages: '@types/doctrine@0.0.9': resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==} + '@types/eslint-scope@3.7.7': + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + '@types/eslint@9.6.1': resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} @@ -2691,6 +2903,9 @@ packages: '@types/http-errors@2.0.5': resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + '@types/http-proxy@1.17.17': + resolution: {integrity: sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -2742,6 +2957,9 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/validator@13.15.10': + resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==} + '@types/vfile-message@2.0.0': resolution: {integrity: sha512-GpTIuDpb9u4zIO165fUy9+fXcULdD8HFRNli04GehoMVbeNq7D6OBnqSmg3lxZnC+UvgUhEWKxdKiwYUkGltIw==} deprecated: This is a stub types definition. vfile-message provides its own type definitions, so you do not need this installed. @@ -2984,6 +3202,57 @@ packages: resolution: {integrity: sha512-coAGV22wivHupfxnMHOLvAXdKp6mzk2I7f0tV0zHLW23qIKY2545g1A2LFfSbYx6JwDOvJr/+nFSRbcvxnbuaw==} engines: {node: '>=20'} + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + '@yarnpkg/lockfile@1.1.0': resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} @@ -2995,6 +3264,10 @@ packages: resolution: {integrity: sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==} hasBin: true + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} @@ -3013,9 +3286,34 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-keywords@3.5.2: + resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} + peerDependencies: + ajv: ^6.9.1 + + ajv-keywords@5.1.0: + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} @@ -3023,6 +3321,10 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + ansi-regex@4.1.1: resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} engines: {node: '>=6'} @@ -3061,6 +3363,9 @@ packages: app-module-path@2.2.0: resolution: {integrity: sha512-gkco+qxENJV+8vFcDiiFhuoSvRXb2a/QPqpSoWhVz829VNJfOTnELbBmPmNKFxf3xdNnw4DWCkzkDaavcX/1YQ==} + append-field@1.0.0: + resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} + arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -3097,10 +3402,16 @@ packages: resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} engines: {node: '>=0.10.0'} + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + array-includes@3.1.9: resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} + array-timsort@1.0.3: + resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==} + array-union@1.0.2: resolution: {integrity: sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==} engines: {node: '>=0.10.0'} @@ -3226,6 +3537,10 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + body-parser@1.20.4: + resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@2.2.1: resolution: {integrity: sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==} engines: {node: '>=18'} @@ -3249,9 +3564,16 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -3324,6 +3646,13 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + change-case@5.4.4: + resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + character-entities-html4@1.1.4: resolution: {integrity: sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==} @@ -3336,6 +3665,9 @@ packages: character-reference-invalid@1.1.4: resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} + chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + check-error@2.1.1: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} @@ -3348,10 +3680,20 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + + class-transformer@0.5.1: + resolution: {integrity: sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==} + class-utils@0.3.6: resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} engines: {node: '>=0.10.0'} + class-validator@0.14.4: + resolution: {integrity: sha512-AwNusCCam51q703dW82x95tOqQp6oC9HNUl724KxJJOfnKscI8dOloXFgyez7LbTTKWuRBA37FScqVbJEoq8Yw==} + classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} @@ -3367,6 +3709,18 @@ packages: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + + cli-width@3.0.0: + resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} + engines: {node: '>= 10'} + + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -3416,6 +3770,9 @@ packages: colord@2.9.3: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + colorette@1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -3424,10 +3781,21 @@ packages: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + commander@7.2.0: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} + comment-json@4.2.5: + resolution: {integrity: sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==} + engines: {node: '>= 6'} + comment-parser@1.4.1: resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} engines: {node: '>= 12.0.0'} @@ -3452,6 +3820,22 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + concat-stream@2.0.0: + resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} + engines: {'0': node >= 6.0} + + concurrently@9.2.1: + resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} + engines: {node: '>=18'} + hasBin: true + + consola@2.15.3: + resolution: {integrity: sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==} + + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + content-disposition@1.0.1: resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} engines: {node: '>=18'} @@ -3489,10 +3873,26 @@ packages: core-js@3.47.0: resolution: {integrity: sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + cosmiconfig@5.2.1: resolution: {integrity: sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==} engines: {node: '>=4'} + cosmiconfig@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + cosmiconfig@9.0.0: resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} engines: {node: '>=14'} @@ -3649,6 +4049,10 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + detect-libc@1.0.3: resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} engines: {node: '>=0.10'} @@ -3980,6 +4384,10 @@ packages: eslint: '>=8' storybook: ^9.1.16 + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4019,6 +4427,10 @@ packages: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -4037,6 +4449,13 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + execall@1.0.0: resolution: {integrity: sha512-/J0Q8CvOvlAdpvhfkD/WnTQ4H1eU0exze2nFGPj/RSC7jpQ0NkKe2r28T5eMkhEEs+fzepMZNy1kVRKNlC04nQ==} engines: {node: '>=0.10.0'} @@ -4049,6 +4468,10 @@ packages: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} + express@4.22.1: + resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} + engines: {node: '>= 0.10.0'} + express@5.2.1: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} @@ -4064,6 +4487,10 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + extglob@2.0.4: resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} engines: {node: '>=0.10.0'} @@ -4088,6 +4515,9 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} @@ -4110,6 +4540,9 @@ packages: picomatch: optional: true + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + figures@3.2.0: resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} engines: {node: '>=8'} @@ -4125,6 +4558,10 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + file-type@20.4.1: + resolution: {integrity: sha512-hw9gNZXUfZ02Jo0uafWLaFVPter5/k2rfcrjFJJHX/77xtSDOfJuEFb6oKlFV86FLP1SuyHMW1PSk0U9M5tKkQ==} + engines: {node: '>=18'} + filing-cabinet@5.0.3: resolution: {integrity: sha512-PlPcMwVWg60NQkhvfoxZs4wEHjhlOO/y7OAm4sKM60o1Z9nttRY4mcdQxp/iZ+kg/Vv6Hw1OAaTbYVM9DA9pYg==} engines: {node: '>=18'} @@ -4147,6 +4584,10 @@ packages: resolution: {integrity: sha512-TL48Pi1oNHeMOHrKv1bCJUrWZDcD3DIG6AGYVNOnyZPr7Bd/pStN0pL+lfzF5BNoj/FclaoiaLenk4XUIFVYng==} engines: {node: '>=8'} + finalhandler@1.3.2: + resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} + engines: {node: '>= 0.8'} + finalhandler@2.1.1: resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} engines: {node: '>= 18.0.0'} @@ -4213,6 +4654,13 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + fork-ts-checker-webpack-plugin@9.0.2: + resolution: {integrity: sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==} + engines: {node: '>=12.13.0', yarn: '>=1.0.0'} + peerDependencies: + typescript: '>3.6.0' + webpack: ^5.11.0 + form-data@4.0.5: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} @@ -4244,6 +4692,10 @@ packages: react-dom: optional: true + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + fresh@2.0.0: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} @@ -4254,6 +4706,13 @@ packages: fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fs-monkey@1.1.0: + resolution: {integrity: sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==} + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -4333,6 +4792,14 @@ packages: glob-to-regexp@0.3.0: resolution: {integrity: sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==} + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me @@ -4407,6 +4874,10 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-own-prop@2.0.0: + resolution: {integrity: sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==} + engines: {node: '>=8'} + has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} @@ -4470,6 +4941,22 @@ packages: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} + http-proxy-middleware@3.0.5: + resolution: {integrity: sha512-GLZZm1X38BPY4lkXA01jhwxvDoOkkXqjgVyUzVxiEK4iuRu03PZoYHhHRwxnfhQMDuaxi3vVri0YgSro/1oWqg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + http-proxy@1.18.1: + resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} + engines: {node: '>=8.0.0'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + iconv-lite@0.7.0: resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} @@ -4519,6 +5006,10 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + index-to-position@1.2.0: + resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} + engines: {node: '>=18'} + indexes-of@1.0.1: resolution: {integrity: sha512-bup+4tap3Hympa+JBJUG7XuOsdNQ6fxt0MHyXMKuLBKn0OqsTfvUxkUrroEX1+B2VsSHvCjiIcZVxRtYa4nllA==} @@ -4532,6 +5023,14 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + inquirer@8.2.6: + resolution: {integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==} + engines: {node: '>=12.0.0'} + + inquirer@9.2.15: + resolution: {integrity: sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==} + engines: {node: '>=18'} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -4802,6 +5301,10 @@ packages: resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} engines: {node: '>=0.10.0'} + iterare@1.2.1: + resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} + engines: {node: '>=6'} + iterator.prototype@1.1.5: resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} @@ -4813,10 +5316,18 @@ packages: resolution: {integrity: sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + js-levenshtein@1.1.6: + resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} + engines: {node: '>=0.10.0'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -4827,6 +5338,10 @@ packages: resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true @@ -4866,6 +5381,15 @@ packages: jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + jsonc-parser@3.2.1: + resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==} + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jsonify@0.0.1: resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} @@ -4920,6 +5444,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + libphonenumber-js@1.12.38: + resolution: {integrity: sha512-vwzxmasAy9hZigxtqTbFEwp8ZdZ975TiqVDwj5bKx5sR+zi5ucUQy9mbVTkKM9GzqdLdxux/hTw2nmN5J7POMA==} + lightningcss-android-arm64@1.30.2: resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} engines: {node: '>= 12.0.0'} @@ -5001,6 +5528,10 @@ packages: resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} engines: {node: '>=4'} + loader-runner@4.3.1: + resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} + engines: {node: '>=6.11.5'} + locate-path@2.0.0: resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} engines: {node: '>=4'} @@ -5071,6 +5602,10 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + magic-string@0.30.8: + resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} + engines: {node: '>=12'} + make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} @@ -5119,10 +5654,18 @@ packages: mdn-data@2.25.0: resolution: {integrity: sha512-T2LPsjgUE/tgMmRXREVmwsux89DwWfNjiynOeXuLd2mX6jphGQ2YE3Ukz7LQ2VOFKiVZU/Ee1GqzHiipZCjymw==} + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + media-typer@1.1.0: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} + memfs@3.5.3: + resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} + engines: {node: '>= 4.0.0'} + memoizerific@1.11.3: resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} @@ -5138,14 +5681,24 @@ packages: resolution: {integrity: sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==} engines: {node: '>=6'} + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + micromatch@3.1.10: resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} engines: {node: '>=0.10.0'} @@ -5170,6 +5723,11 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -5185,6 +5743,10 @@ packages: minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} @@ -5238,6 +5800,17 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + multer@2.0.2: + resolution: {integrity: sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==} + engines: {node: '>= 10.16.0'} + + mute-stream@0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + + mute-stream@1.0.0: + resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -5255,6 +5828,10 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + negotiator@0.6.4: resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} engines: {node: '>= 0.6'} @@ -5263,12 +5840,30 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + nice-try@1.0.5: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} + node-abort-controller@3.1.1: + resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-emoji@1.11.0: + resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + node-machine-id@1.1.12: resolution: {integrity: sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==} @@ -5381,6 +5976,12 @@ packages: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} + openapi-typescript@7.13.0: + resolution: {integrity: sha512-EFP392gcqXS7ntPvbhBzbF8TyBA+baIYEm791Hy5YkjDYKTnk/Tn5OQeKm5BIZvJihpp8Zzr4hzx0Irde1LNGQ==} + hasBin: true + peerDependencies: + typescript: ^5.x + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -5393,6 +5994,10 @@ packages: resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} engines: {node: '>=10'} + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + own-keys@1.0.1: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} @@ -5458,6 +6063,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-json@8.3.0: + resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} + engines: {node: '>=18'} + parse-ms@2.1.0: resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} engines: {node: '>=6'} @@ -5504,6 +6113,12 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-to-regexp@0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + + path-to-regexp@3.3.0: + resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} + path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} @@ -5532,6 +6147,10 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.1: + resolution: {integrity: sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==} + engines: {node: '>=12'} + picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} @@ -5821,6 +6440,10 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} + raw-body@2.5.3: + resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} + engines: {node: '>= 0.8'} + raw-body@3.0.2: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} @@ -5941,6 +6564,9 @@ packages: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -5991,6 +6617,9 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + resolve-dependency-path@4.0.1: resolution: {integrity: sha512-YQftIIC4vzO9UMhO/sCgXukNyiwVRCVaxiWskCBy7Zpqkplm8kTAISZ8O1MoKW1ca6xzgLUBjZTcDgypXvXxiQ==} engines: {node: '>=18'} @@ -6098,9 +6727,23 @@ packages: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} + run-async@2.4.1: + resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} + engines: {node: '>=0.12.0'} + + run-async@3.0.0: + resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==} + engines: {node: '>=0.12.0'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} @@ -6138,6 +6781,14 @@ packages: scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + schema-utils@3.3.0: + resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} + engines: {node: '>= 10.13.0'} + + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} + engines: {node: '>= 10.13.0'} + scroll-into-view-if-needed@3.0.10: resolution: {integrity: sha512-t44QCeDKAPf1mtQH3fYpWz8IM/DyvHLjs8wUvvwMYxk5moOqCzrMSxK6HQVD0QVmVjXFavoFIPRVrMuJPKAvtg==} @@ -6154,6 +6805,10 @@ packages: engines: {node: '>=10'} hasBin: true + send@0.19.2: + resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} + engines: {node: '>= 0.8.0'} + send@1.2.0: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} @@ -6161,6 +6816,10 @@ packages: serialize-query-params@2.0.3: resolution: {integrity: sha512-PyDK5dkxtWa9jo9qJDy19x/haAcTQnUfIGsCXIv53HlgTCH5pC2KHIqrtM+VOruqRmH2XwYZZyn7BNHN0W58EQ==} + serve-static@1.16.3: + resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} + engines: {node: '>= 0.8.0'} + serve-static@2.2.0: resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} engines: {node: '>= 18'} @@ -6287,6 +6946,9 @@ packages: resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} deprecated: See https://github.com/lydell/source-map-resolve#deprecated + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map-url@0.4.1: resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} deprecated: See https://github.com/lydell/source-map-url#deprecated @@ -6299,6 +6961,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} @@ -6368,6 +7034,10 @@ packages: stream-to-array@2.3.0: resolution: {integrity: sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==} + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + string-width@3.1.0: resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==} engines: {node: '>=6'} @@ -6456,6 +7126,10 @@ packages: strip-literal@3.1.0: resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + strtok3@10.3.4: + resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} + engines: {node: '>=18'} + style-search@0.1.0: resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==} @@ -6528,6 +7202,10 @@ packages: resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} engines: {node: '>=14.0.0'} + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -6536,6 +7214,10 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + supports-hyperlinks@3.2.0: resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} engines: {node: '>=14.18'} @@ -6547,6 +7229,13 @@ packages: svg-tags@1.0.0: resolution: {integrity: sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==} + swagger-ui-dist@5.17.14: + resolution: {integrity: sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw==} + + symbol-observable@4.0.0: + resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} + engines: {node: '>=0.10'} + synckit@0.11.11: resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} engines: {node: ^14.18.0 || >=16.0.0} @@ -6628,6 +7317,30 @@ packages: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} + terser-webpack-plugin@5.3.17: + resolution: {integrity: sha512-YR7PtUp6GMU91BgSJmlaX/rS2lGDbAF7D+Wtq7hRO+MiljNmodYvqslzCFiYVAgW+Qoaaia/QUIP4lGXufjdZw==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + + terser@5.46.0: + resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} + engines: {node: '>=10'} + hasBin: true + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} @@ -6657,6 +7370,10 @@ packages: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} + tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + tmp@0.2.5: resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} engines: {node: '>=14.14'} @@ -6681,6 +7398,10 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} @@ -6743,6 +7464,10 @@ packages: '@swc/wasm': optional: true + tsconfig-paths-webpack-plugin@4.2.0: + resolution: {integrity: sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==} + engines: {node: '>=10.13.0'} + tsconfig-paths@4.2.0: resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} engines: {node: '>=6'} @@ -6759,6 +7484,18 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + type-is@2.0.1: resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} engines: {node: '>= 0.6'} @@ -6779,6 +7516,9 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} + typedarray@0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + typescript-eslint@8.48.1: resolution: {integrity: sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -6786,6 +7526,11 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' + typescript@5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + typescript@5.7.3: resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} engines: {node: '>=14.17'} @@ -6796,6 +7541,14 @@ packages: engines: {node: '>=14.17'} hasBin: true + uid@2.0.2: + resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==} + engines: {node: '>=8'} + + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -6847,6 +7600,10 @@ packages: unist-util-visit@1.4.1: resolution: {integrity: sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==} + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -6868,6 +7625,9 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + uri-js-replace@1.0.1: + resolution: {integrity: sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -6918,12 +7678,20 @@ packages: resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==} engines: {node: '>= 4'} + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + validator@13.15.26: + resolution: {integrity: sha512-spH26xU080ydGggxRyR1Yhcbgx+j3y5jbNXk/8L+iRvdIEQ4uTRH2Sgf2dokud6Q4oAtsbNvJ1Ft+9xmm6IZcA==} + engines: {node: '>= 0.10'} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -7027,15 +7795,37 @@ packages: resolution: {integrity: sha512-3eBwRyEln6E1MSzcxcVpQIhRG8Q1jLvEqRmCZqS3dsfXEDR/AhOF4d+jHg1qvDCpYaVRZjENPQyrVxAkQqxPgQ==} engines: {node: '>=6.0.0'} + watchpack@2.5.1: + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} + engines: {node: '>=10.13.0'} + wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webpack-node-externals@3.0.0: + resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==} + engines: {node: '>=6'} + + webpack-sources@3.3.4: + resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} + engines: {node: '>=10.13.0'} + webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + webpack@5.97.1: + resolution: {integrity: sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -7073,6 +7863,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -7118,6 +7912,9 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yaml-ast-parser@0.0.43: + resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} + yaml@2.8.2: resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} @@ -7155,6 +7952,38 @@ snapshots: '@adobe/css-tools@4.4.4': {} + '@angular-devkit/core@17.3.11(chokidar@3.6.0)': + dependencies: + ajv: 8.12.0 + ajv-formats: 2.1.1(ajv@8.12.0) + jsonc-parser: 3.2.1 + picomatch: 4.0.1 + rxjs: 7.8.1 + source-map: 0.7.4 + optionalDependencies: + chokidar: 3.6.0 + + '@angular-devkit/schematics-cli@17.3.11(chokidar@3.6.0)': + dependencies: + '@angular-devkit/core': 17.3.11(chokidar@3.6.0) + '@angular-devkit/schematics': 17.3.11(chokidar@3.6.0) + ansi-colors: 4.1.3 + inquirer: 9.2.15 + symbol-observable: 4.0.0 + yargs-parser: 21.1.1 + transitivePeerDependencies: + - chokidar + + '@angular-devkit/schematics@17.3.11(chokidar@3.6.0)': + dependencies: + '@angular-devkit/core': 17.3.11(chokidar@3.6.0) + jsonc-parser: 3.2.1 + magic-string: 0.30.8 + ora: 5.4.1 + rxjs: 7.8.1 + transitivePeerDependencies: + - chokidar + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -7276,6 +8105,8 @@ snapshots: '@bem-react/classname@1.7.0': {} + '@borewit/text-codec@0.2.1': {} + '@bundle-stats/cli-utils@4.21.7(core-js@3.47.0)': dependencies: '@bundle-stats/html-templates': 4.21.7 @@ -7321,6 +8152,9 @@ snapshots: hashery: 1.3.0 keyv: 5.5.4 + '@colors/colors@1.5.0': + optional: true + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 @@ -8192,12 +9026,12 @@ snapshots: dependencies: '@sinclair/typebox': 0.34.41 - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.1(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.1(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: glob: 10.5.0 magic-string: 0.30.21 react-docgen-typescript: 2.4.0(typescript@5.9.3) - vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) optionalDependencies: typescript: 5.9.3 @@ -8213,6 +9047,11 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.31': @@ -8233,12 +9072,20 @@ snapshots: '@keyv/serialize@1.1.1': {} + '@ljharb/through@2.3.14': + dependencies: + call-bind: 1.0.8 + + '@lukeed/csprng@1.1.0': {} + '@mdx-js/react@3.1.1(@types/react@19.2.7)(react@19.2.0)': dependencies: '@types/mdx': 2.0.13 '@types/react': 19.2.7 react: 19.2.0 + '@microsoft/tsdoc@0.15.1': {} + '@mrmlnc/readdir-enhanced@2.2.1': dependencies: call-me-maybe: 1.0.2 @@ -8264,6 +9111,119 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@nestjs/cli@10.4.9': + dependencies: + '@angular-devkit/core': 17.3.11(chokidar@3.6.0) + '@angular-devkit/schematics': 17.3.11(chokidar@3.6.0) + '@angular-devkit/schematics-cli': 17.3.11(chokidar@3.6.0) + '@nestjs/schematics': 10.2.3(chokidar@3.6.0)(typescript@5.7.2) + chalk: 4.1.2 + chokidar: 3.6.0 + cli-table3: 0.6.5 + commander: 4.1.1 + fork-ts-checker-webpack-plugin: 9.0.2(typescript@5.7.2)(webpack@5.97.1) + glob: 10.4.5 + inquirer: 8.2.6 + node-emoji: 1.11.0 + ora: 5.4.1 + tree-kill: 1.2.2 + tsconfig-paths: 4.2.0 + tsconfig-paths-webpack-plugin: 4.2.0 + typescript: 5.7.2 + webpack: 5.97.1 + webpack-node-externals: 3.0.0 + transitivePeerDependencies: + - esbuild + - uglify-js + - webpack-cli + + '@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + file-type: 20.4.1 + iterare: 1.2.1 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.4 + transitivePeerDependencies: + - supports-color + + '@nestjs/core@10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + '@nestjs/common': 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nuxtjs/opencollective': 0.3.2 + fast-safe-stringify: 2.1.1 + iterare: 1.2.1 + path-to-regexp: 3.3.0 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + optionalDependencies: + '@nestjs/platform-express': 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.22) + transitivePeerDependencies: + - encoding + + '@nestjs/mapped-types@2.0.5(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': + dependencies: + '@nestjs/common': 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + reflect-metadata: 0.2.2 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.4 + + '@nestjs/platform-express@10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.22)': + dependencies: + '@nestjs/common': 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2) + body-parser: 1.20.4 + cors: 2.8.5 + express: 4.22.1 + multer: 2.0.2 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@nestjs/schematics@10.2.3(chokidar@3.6.0)(typescript@5.7.2)': + dependencies: + '@angular-devkit/core': 17.3.11(chokidar@3.6.0) + '@angular-devkit/schematics': 17.3.11(chokidar@3.6.0) + comment-json: 4.2.5 + jsonc-parser: 3.3.1 + pluralize: 8.0.0 + typescript: 5.7.2 + transitivePeerDependencies: + - chokidar + + '@nestjs/schematics@10.2.3(chokidar@3.6.0)(typescript@5.7.3)': + dependencies: + '@angular-devkit/core': 17.3.11(chokidar@3.6.0) + '@angular-devkit/schematics': 17.3.11(chokidar@3.6.0) + comment-json: 4.2.5 + jsonc-parser: 3.3.1 + pluralize: 8.0.0 + typescript: 5.7.3 + transitivePeerDependencies: + - chokidar + + '@nestjs/swagger@7.4.2(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@10.4.22)(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)': + dependencies: + '@microsoft/tsdoc': 0.15.1 + '@nestjs/common': 10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 10.4.22(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@10.4.22)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/mapped-types': 2.0.5(@nestjs/common@10.4.22(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.4)(reflect-metadata@0.2.2) + js-yaml: 4.1.0 + lodash: 4.17.21 + path-to-regexp: 3.3.0 + reflect-metadata: 0.2.2 + swagger-ui-dist: 5.17.14 + optionalDependencies: + class-transformer: 0.5.1 + class-validator: 0.14.4 + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -8296,6 +9256,14 @@ snapshots: transitivePeerDependencies: - '@tanstack/query-core' + '@nuxtjs/opencollective@0.3.2': + dependencies: + chalk: 4.1.2 + consola: 2.15.3 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + '@nx/nx-darwin-arm64@22.1.3': optional: true @@ -8454,11 +9422,11 @@ snapshots: '@pkgr/core@0.2.9': {} - '@playwright/experimental-ct-core@1.52.0(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)': + '@playwright/experimental-ct-core@1.52.0(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)': dependencies: playwright: 1.52.0 playwright-core: 1.52.0 - vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - '@types/node' - jiti @@ -8472,10 +9440,10 @@ snapshots: - tsx - yaml - '@playwright/experimental-ct-react@1.52.0(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)': + '@playwright/experimental-ct-react@1.52.0(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(yaml@2.8.2)': dependencies: - '@playwright/experimental-ct-core': 1.52.0(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) - '@vitejs/plugin-react': 4.7.0(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + '@playwright/experimental-ct-core': 1.52.0(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + '@vitejs/plugin-react': 4.7.0(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - '@types/node' - jiti @@ -8959,6 +9927,29 @@ snapshots: '@react-types/shared': 3.32.1(react@19.2.0) react: 19.2.0 + '@redocly/ajv@8.11.2': + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js-replace: 1.0.1 + + '@redocly/config@0.22.0': {} + + '@redocly/openapi-core@1.34.10(supports-color@10.2.2)': + dependencies: + '@redocly/ajv': 8.11.2 + '@redocly/config': 0.22.0 + colorette: 1.4.0 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + js-levenshtein: 1.1.6 + js-yaml: 4.1.1 + minimatch: 5.1.9 + pluralize: 8.0.0 + yaml-ast-parser: 0.0.43 + transitivePeerDependencies: + - supports-color + '@rolldown/pluginutils@1.0.0-beta.27': {} '@rollup/pluginutils@5.3.0(rollup@4.53.3)': @@ -9039,55 +10030,55 @@ snapshots: '@stitches/core@1.2.8': {} - '@storybook/addon-a11y@9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))': + '@storybook/addon-a11y@9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))': dependencies: '@storybook/global': 5.0.0 axe-core: 4.11.0 - storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) - '@storybook/addon-docs@9.1.16(@types/react@19.2.7)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))': + '@storybook/addon-docs@9.1.16(@types/react@19.2.7)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.7)(react@19.2.0) - '@storybook/csf-plugin': 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))) + '@storybook/csf-plugin': 9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))) '@storybook/icons': 1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@storybook/react-dom-shim': 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))) + '@storybook/react-dom-shim': 9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' - '@storybook/addon-vitest@9.1.16(@vitest/browser@3.2.4)(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(vitest@3.2.4)': + '@storybook/addon-vitest@9.1.16(@vitest/browser@3.2.4)(@vitest/runner@4.0.15)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(vitest@3.2.4)': dependencies: '@storybook/global': 5.0.0 '@storybook/icons': 1.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) prompts: 2.4.2 - storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) ts-dedent: 2.2.0 optionalDependencies: - '@vitest/browser': 3.2.4(playwright@1.57.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@3.2.4) + '@vitest/browser': 3.2.4(playwright@1.57.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@3.2.4) '@vitest/runner': 4.0.15 - vitest: 3.2.4(@types/node@22.19.1)(@vitest/browser@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vitest: 3.2.4(@types/node@22.19.1)(@vitest/browser@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - react - react-dom - '@storybook/builder-vite@9.1.19(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))': + '@storybook/builder-vite@9.1.19(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@storybook/csf-plugin': 9.1.19(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))) - storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + '@storybook/csf-plugin': 9.1.19(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))) + storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) ts-dedent: 2.2.0 - vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - '@storybook/csf-plugin@9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))': + '@storybook/csf-plugin@9.1.16(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))': dependencies: - storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) unplugin: 1.16.1 - '@storybook/csf-plugin@9.1.19(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))': + '@storybook/csf-plugin@9.1.19(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))': dependencies: - storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) unplugin: 1.16.1 '@storybook/global@5.0.0': {} @@ -9097,51 +10088,51 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - '@storybook/react-dom-shim@9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))': + '@storybook/react-dom-shim@9.1.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))': dependencies: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) - '@storybook/react-dom-shim@9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))': + '@storybook/react-dom-shim@9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))': dependencies: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) - '@storybook/react-vite@9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.3)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))': + '@storybook/react-vite@9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(rollup@4.53.3)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.1(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.1(typescript@5.9.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@rollup/pluginutils': 5.3.0(rollup@4.53.3) - '@storybook/builder-vite': 9.1.19(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) - '@storybook/react': 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3) + '@storybook/builder-vite': 9.1.19(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) + '@storybook/react': 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3) find-up: 7.0.0 magic-string: 0.30.21 react: 19.2.0 react-docgen: 8.0.2 react-dom: 19.2.0(react@19.2.0) resolve: 1.22.11 - storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) tsconfig-paths: 4.2.0 - vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - rollup - supports-color - typescript - '@storybook/react@9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3)': + '@storybook/react@9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.9.3)': dependencies: '@storybook/global': 5.0.0 - '@storybook/react-dom-shim': 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))) + '@storybook/react-dom-shim': 9.1.19(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) optionalDependencies: typescript: 5.9.3 - '@storybook/theming@8.6.14(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))': + '@storybook/theming@8.6.14(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))': dependencies: - storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@stylistic/eslint-plugin@5.6.1(eslint@9.39.1(jiti@2.6.1))': dependencies: @@ -9278,12 +10269,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 '@tailwindcss/oxide-win32-x64-msvc': 4.1.17 - '@tailwindcss/vite@4.1.17(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))': + '@tailwindcss/vite@4.1.17(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@tailwindcss/node': 4.1.17 '@tailwindcss/oxide': 4.1.17 tailwindcss: 4.1.17 - vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) '@tanstack/eslint-config@0.3.3(@typescript-eslint/utils@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.39.1(jiti@2.6.1))(typescript@5.7.3)': dependencies: @@ -9348,6 +10339,16 @@ snapshots: dependencies: '@testing-library/dom': 10.4.1 + '@tokenizer/inflate@0.2.7': + dependencies: + debug: 4.4.3(supports-color@5.5.0) + fflate: 0.8.2 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + '@ts-graphviz/adapter@2.0.6': dependencies: '@ts-graphviz/common': 2.1.5 @@ -9434,6 +10435,11 @@ snapshots: '@types/doctrine@0.0.9': {} + '@types/eslint-scope@3.7.7': + dependencies: + '@types/eslint': 9.6.1 + '@types/estree': 1.0.8 + '@types/eslint@9.6.1': dependencies: '@types/estree': 1.0.8 @@ -9468,6 +10474,10 @@ snapshots: '@types/http-errors@2.0.5': {} + '@types/http-proxy@1.17.17': + dependencies: + '@types/node': 22.19.1 + '@types/json-schema@7.0.15': {} '@types/lodash@4.17.21': {} @@ -9513,6 +10523,8 @@ snapshots: '@types/unist@3.0.3': {} + '@types/validator@13.15.10': {} + '@types/vfile-message@2.0.0': dependencies: vfile-message: 4.0.3 @@ -9678,7 +10690,7 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))': + '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) @@ -9686,20 +10698,20 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.27 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - supports-color - '@vitest/browser@3.2.4(playwright@1.57.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@3.2.4)': + '@vitest/browser@3.2.4(playwright@1.57.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@3.2.4)': dependencies: '@testing-library/dom': 10.4.1 '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) - '@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/utils': 3.2.4 magic-string: 0.30.21 sirv: 3.0.2 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@22.19.1)(@vitest/browser@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vitest: 3.2.4(@types/node@22.19.1)(@vitest/browser@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) ws: 8.18.3 optionalDependencies: playwright: 1.57.0 @@ -9717,13 +10729,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))': + '@vitest/mocker@3.2.4(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) '@vitest/pretty-format@3.2.4': dependencies: @@ -9810,6 +10822,86 @@ snapshots: - react - react-dom + '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + + '@webassemblyjs/helper-api-error@1.13.2': {} + + '@webassemblyjs/helper-buffer@1.14.1': {} + + '@webassemblyjs/helper-numbers@1.13.2': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + + '@webassemblyjs/helper-wasm-section@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 + + '@webassemblyjs/ieee754@1.13.2': + dependencies: + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.13.2': {} + + '@webassemblyjs/wasm-edit@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + + '@webassemblyjs/wasm-gen@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wasm-opt@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wast-printer@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + '@yarnpkg/lockfile@1.1.0': {} '@yarnpkg/parsers@3.0.2': @@ -9821,6 +10913,11 @@ snapshots: dependencies: argparse: 2.0.1 + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + accepts@2.0.0: dependencies: mime-types: 3.0.2 @@ -9836,6 +10933,25 @@ snapshots: acorn@8.15.0: {} + agent-base@7.1.4: {} + + ajv-formats@2.1.1(ajv@8.12.0): + optionalDependencies: + ajv: 8.12.0 + + ajv-formats@2.1.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + + ajv-keywords@3.5.2(ajv@6.12.6): + dependencies: + ajv: 6.12.6 + + ajv-keywords@5.1.0(ajv@8.17.1): + dependencies: + ajv: 8.17.1 + fast-deep-equal: 3.1.3 + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -9843,6 +10959,13 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.12.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 @@ -9852,6 +10975,10 @@ snapshots: ansi-colors@4.1.3: {} + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + ansi-regex@4.1.1: {} ansi-regex@5.0.1: {} @@ -9879,6 +11006,8 @@ snapshots: app-module-path@2.2.0: {} + append-field@1.0.0: {} + arg@4.1.3: {} argparse@1.0.10: @@ -9906,6 +11035,8 @@ snapshots: array-find-index@1.0.2: {} + array-flatten@1.1.1: {} + array-includes@3.1.9: dependencies: call-bind: 1.0.8 @@ -9917,6 +11048,8 @@ snapshots: is-string: 1.1.1 math-intrinsics: 1.1.0 + array-timsort@1.0.3: {} + array-union@1.0.2: dependencies: array-uniq: 1.0.3 @@ -10008,7 +11141,7 @@ snapshots: axios@1.13.2: dependencies: - follow-redirects: 1.15.11 + follow-redirects: 1.15.11(debug@4.4.3) form-data: 4.0.5 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -10063,6 +11196,23 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + body-parser@1.20.4: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 2.5.3 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + body-parser@2.2.1: dependencies: bytes: 3.1.2 @@ -10113,11 +11263,17 @@ snapshots: node-releases: 2.0.27 update-browserslist-db: 1.1.4(browserslist@4.28.0) + buffer-from@1.1.2: {} + buffer@5.7.1: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + bytes@3.1.2: {} cac@6.7.14: {} @@ -10204,6 +11360,10 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.6.2: {} + + change-case@5.4.4: {} + character-entities-html4@1.1.4: {} character-entities-legacy@1.1.4: {} @@ -10212,6 +11372,8 @@ snapshots: character-reference-invalid@1.1.4: {} + chardet@0.7.0: {} + check-error@2.1.1: {} chokidar@3.6.0: @@ -10230,6 +11392,10 @@ snapshots: dependencies: readdirp: 4.1.2 + chrome-trace-event@1.0.4: {} + + class-transformer@0.5.1: {} + class-utils@0.3.6: dependencies: arr-union: 3.1.0 @@ -10237,6 +11403,12 @@ snapshots: isobject: 3.0.1 static-extend: 0.1.2 + class-validator@0.14.4: + dependencies: + '@types/validator': 13.15.10 + libphonenumber-js: 1.12.38 + validator: 13.15.26 + classnames@2.5.1: {} cli-cursor@3.1.0: @@ -10247,6 +11419,16 @@ snapshots: cli-spinners@2.9.2: {} + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + + cli-width@3.0.0: {} + + cli-width@4.1.0: {} + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -10295,14 +11477,28 @@ snapshots: colord@2.9.3: {} + colorette@1.4.0: {} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 commander@12.1.0: {} + commander@2.20.3: {} + + commander@4.1.1: {} + commander@7.2.0: {} + comment-json@4.2.5: + dependencies: + array-timsort: 1.0.3 + core-util-is: 1.0.3 + esprima: 4.0.1 + has-own-prop: 2.0.0 + repeat-string: 1.6.1 + comment-parser@1.4.1: {} commondir@1.0.1: {} @@ -10329,6 +11525,28 @@ snapshots: concat-map@0.0.1: {} + concat-stream@2.0.0: + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 3.6.2 + typedarray: 0.0.6 + + concurrently@9.2.1: + dependencies: + chalk: 4.1.2 + rxjs: 7.8.2 + shell-quote: 1.8.3 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + + consola@2.15.3: {} + + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + content-disposition@1.0.1: {} content-type@1.0.5: {} @@ -10352,6 +11570,13 @@ snapshots: core-js@3.47.0: {} + core-util-is@1.0.3: {} + + cors@2.8.5: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + cosmiconfig@5.2.1: dependencies: import-fresh: 2.0.0 @@ -10359,6 +11584,15 @@ snapshots: js-yaml: 3.14.2 parse-json: 4.0.0 + cosmiconfig@8.3.6(typescript@5.7.2): + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.1.1 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.7.2 + cosmiconfig@9.0.0(typescript@5.7.3): dependencies: env-paths: 2.2.1 @@ -10430,6 +11664,12 @@ snapshots: ms: 2.1.3 optional: true + debug@4.4.3(supports-color@10.2.2): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 10.2.2 + debug@4.4.3(supports-color@5.5.0): dependencies: ms: 2.1.3 @@ -10501,6 +11741,8 @@ snapshots: dequal@2.0.3: {} + destroy@1.2.0: {} + detect-libc@1.0.3: optional: true @@ -10968,15 +12210,20 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-storybook@9.1.16(eslint@9.39.1(jiti@2.6.1))(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.7.3): + eslint-plugin-storybook@9.1.16(eslint@9.39.1(jiti@2.6.1))(storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)))(typescript@5.7.3): dependencies: '@typescript-eslint/utils': 8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.7.3) eslint: 9.39.1(jiti@2.6.1) - storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + storybook: 9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) transitivePeerDependencies: - supports-color - typescript + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 @@ -11043,6 +12290,8 @@ snapshots: dependencies: estraverse: 5.3.0 + estraverse@4.3.0: {} + estraverse@5.3.0: {} estree-walker@2.0.2: {} @@ -11055,6 +12304,10 @@ snapshots: etag@1.8.1: {} + eventemitter3@4.0.7: {} + + events@3.3.0: {} + execall@1.0.0: dependencies: clone-regexp: 1.0.1 @@ -11073,6 +12326,42 @@ snapshots: expect-type@1.2.2: {} + express@4.22.1: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.4 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.2 + fresh: 0.5.2 + http-errors: 2.0.1 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.12 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.2 + serve-static: 1.16.3 + setprototypeof: 1.2.0 + statuses: 2.0.2 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + express@5.2.1: dependencies: accepts: 2.0.0 @@ -11117,6 +12406,12 @@ snapshots: extend@3.0.2: {} + external-editor@3.1.0: + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + extglob@2.0.4: dependencies: array-unique: 0.3.2 @@ -11157,6 +12452,8 @@ snapshots: fast-levenshtein@2.0.6: {} + fast-safe-stringify@2.1.1: {} + fast-uri@3.1.0: {} fastest-levenshtein@1.0.16: {} @@ -11173,6 +12470,8 @@ snapshots: optionalDependencies: picomatch: 4.0.3 + fflate@0.8.2: {} + figures@3.2.0: dependencies: escape-string-regexp: 1.0.5 @@ -11189,6 +12488,15 @@ snapshots: dependencies: flat-cache: 4.0.1 + file-type@20.4.1: + dependencies: + '@tokenizer/inflate': 0.2.7 + strtok3: 10.3.4 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + filing-cabinet@5.0.3: dependencies: app-module-path: 2.2.0 @@ -11222,6 +12530,18 @@ snapshots: dependencies: '@babel/runtime': 7.28.4 + finalhandler@1.3.2: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + finalhandler@2.1.1: dependencies: debug: 4.4.3(supports-color@5.5.0) @@ -11282,7 +12602,9 @@ snapshots: flatted@3.3.3: {} - follow-redirects@1.15.11: {} + follow-redirects@1.15.11(debug@4.4.3): + optionalDependencies: + debug: 4.4.3(supports-color@5.5.0) for-each@0.3.5: dependencies: @@ -11295,6 +12617,23 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + fork-ts-checker-webpack-plugin@9.0.2(typescript@5.7.2)(webpack@5.97.1): + dependencies: + '@babel/code-frame': 7.27.1 + chalk: 4.1.2 + chokidar: 3.6.0 + cosmiconfig: 8.3.6(typescript@5.7.2) + deepmerge: 4.3.1 + fs-extra: 10.1.0 + memfs: 3.5.3 + minimatch: 3.1.2 + node-abort-controller: 3.1.1 + schema-utils: 3.3.0 + semver: 7.7.3 + tapable: 2.3.0 + typescript: 5.7.2 + webpack: 5.97.1 + form-data@4.0.5: dependencies: asynckit: 0.4.0 @@ -11322,6 +12661,8 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) + fresh@0.5.2: {} + fresh@2.0.0: {} front-matter@4.0.2: @@ -11330,6 +12671,14 @@ snapshots: fs-constants@1.0.0: {} + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-monkey@1.1.0: {} + fs.realpath@1.0.0: {} fsevents@2.3.2: @@ -11411,6 +12760,17 @@ snapshots: glob-to-regexp@0.3.0: {} + glob-to-regexp@0.4.1: {} + + glob@10.4.5: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + glob@10.5.0: dependencies: foreground-child: 3.3.1 @@ -11492,6 +12852,8 @@ snapshots: has-flag@4.0.0: {} + has-own-prop@2.0.0: {} + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.1 @@ -11562,6 +12924,36 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 + http-proxy-middleware@3.0.5: + dependencies: + '@types/http-proxy': 1.17.17 + debug: 4.4.3(supports-color@5.5.0) + http-proxy: 1.18.1(debug@4.4.3) + is-glob: 4.0.3 + is-plain-object: 5.0.0 + micromatch: 4.0.8 + transitivePeerDependencies: + - supports-color + + http-proxy@1.18.1(debug@4.4.3): + dependencies: + eventemitter3: 4.0.7 + follow-redirects: 1.15.11(debug@4.4.3) + requires-port: 1.0.0 + transitivePeerDependencies: + - debug + + https-proxy-agent@7.0.6(supports-color@10.2.2): + dependencies: + agent-base: 7.1.4 + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + iconv-lite@0.7.0: dependencies: safer-buffer: 2.1.2 @@ -11596,6 +12988,8 @@ snapshots: indent-string@4.0.0: {} + index-to-position@1.2.0: {} + indexes-of@1.0.1: {} inflight@1.0.6: @@ -11607,6 +13001,42 @@ snapshots: ini@1.3.8: {} + inquirer@8.2.6: + dependencies: + ansi-escapes: 4.3.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-width: 3.0.0 + external-editor: 3.1.0 + figures: 3.2.0 + lodash: 4.17.21 + mute-stream: 0.0.8 + ora: 5.4.1 + run-async: 2.4.1 + rxjs: 7.8.2 + string-width: 4.2.3 + strip-ansi: 6.0.1 + through: 2.3.8 + wrap-ansi: 6.2.0 + + inquirer@9.2.15: + dependencies: + '@ljharb/through': 2.3.14 + ansi-escapes: 4.3.2 + chalk: 5.6.2 + cli-cursor: 3.1.0 + cli-width: 4.1.0 + external-editor: 3.1.0 + figures: 3.2.0 + lodash: 4.17.21 + mute-stream: 1.0.0 + ora: 5.4.1 + run-async: 3.0.0 + rxjs: 7.8.2 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -11843,6 +13273,8 @@ snapshots: isobject@3.0.1: {} + iterare@1.2.1: {} + iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 @@ -11865,8 +13297,16 @@ snapshots: chalk: 4.1.2 pretty-format: 30.2.0 + jest-worker@27.5.1: + dependencies: + '@types/node': 22.19.1 + merge-stream: 2.0.0 + supports-color: 8.1.1 + jiti@2.6.1: {} + js-levenshtein@1.1.6: {} + js-tokens@4.0.0: {} js-tokens@9.0.1: {} @@ -11876,6 +13316,10 @@ snapshots: argparse: 1.0.10 esprima: 4.0.1 + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + js-yaml@4.1.1: dependencies: argparse: 2.0.1 @@ -11906,6 +13350,16 @@ snapshots: jsonc-parser@3.2.0: {} + jsonc-parser@3.2.1: {} + + jsonc-parser@3.3.1: {} + + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + jsonify@0.0.1: {} jsx-ast-utils@3.3.5: @@ -11966,6 +13420,8 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + libphonenumber-js@1.12.38: {} + lightningcss-android-arm64@1.30.2: optional: true @@ -12026,6 +13482,8 @@ snapshots: pify: 3.0.0 strip-bom: 3.0.0 + loader-runner@4.3.1: {} + locate-path@2.0.0: dependencies: p-locate: 2.0.0 @@ -12102,6 +13560,10 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + magic-string@0.30.8: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + make-dir@3.1.0: dependencies: semver: 6.3.1 @@ -12136,8 +13598,14 @@ snapshots: mdn-data@2.25.0: {} + media-typer@0.3.0: {} + media-typer@1.1.0: {} + memfs@3.5.3: + dependencies: + fs-monkey: 1.1.0 + memoizerific@1.11.3: dependencies: map-or-similar: 1.5.0 @@ -12158,10 +13626,16 @@ snapshots: trim-newlines: 2.0.0 yargs-parser: 10.1.0 + merge-descriptors@1.0.3: {} + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} + merge2@1.4.1: {} + methods@1.1.2: {} + micromatch@3.1.10: dependencies: arr-diff: 4.0.0 @@ -12197,6 +13671,8 @@ snapshots: dependencies: mime-db: 1.54.0 + mime@1.6.0: {} + mimic-fn@2.1.0: {} min-indent@1.0.1: {} @@ -12209,6 +13685,10 @@ snapshots: dependencies: brace-expansion: 1.1.12 + minimatch@5.1.9: + dependencies: + brace-expansion: 2.0.2 + minimatch@9.0.3: dependencies: brace-expansion: 2.0.2 @@ -12259,6 +13739,20 @@ snapshots: ms@2.1.3: {} + multer@2.0.2: + dependencies: + append-field: 1.0.0 + busboy: 1.6.0 + concat-stream: 2.0.0 + mkdirp: 0.5.6 + object-assign: 4.1.1 + type-is: 1.6.18 + xtend: 4.0.2 + + mute-stream@0.0.8: {} + + mute-stream@1.0.0: {} + nanoid@3.3.11: {} nanomatch@1.2.13: @@ -12281,15 +13775,29 @@ snapshots: natural-compare@1.4.0: {} + negotiator@0.6.3: {} + negotiator@0.6.4: {} negotiator@1.0.0: {} + neo-async@2.6.2: {} + nice-try@1.0.5: {} + node-abort-controller@3.1.1: {} + node-addon-api@7.1.1: optional: true + node-emoji@1.11.0: + dependencies: + lodash: 4.17.21 + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + node-machine-id@1.1.12: {} node-releases@2.0.27: {} @@ -12463,6 +13971,16 @@ snapshots: is-docker: 2.2.1 is-wsl: 2.2.0 + openapi-typescript@7.13.0(typescript@5.7.3): + dependencies: + '@redocly/openapi-core': 1.34.10(supports-color@10.2.2) + ansi-colors: 4.1.3 + change-case: 5.4.4 + parse-json: 8.3.0 + supports-color: 10.2.2 + typescript: 5.7.3 + yargs-parser: 21.1.1 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -12495,6 +14013,8 @@ snapshots: strip-ansi: 6.0.1 wcwidth: 1.0.1 + os-tmpdir@1.0.2: {} + own-keys@1.0.1: dependencies: get-intrinsic: 1.3.0 @@ -12587,6 +14107,12 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-json@8.3.0: + dependencies: + '@babel/code-frame': 7.27.1 + index-to-position: 1.2.0 + type-fest: 4.41.0 + parse-ms@2.1.0: {} parseurl@1.3.3: {} @@ -12614,6 +14140,10 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + path-to-regexp@0.1.12: {} + + path-to-regexp@3.3.0: {} + path-to-regexp@8.3.0: {} path-type@3.0.0: @@ -12632,6 +14162,8 @@ snapshots: picomatch@2.3.1: {} + picomatch@4.0.1: {} + picomatch@4.0.3: {} pidtree@0.3.1: {} @@ -12672,13 +14204,13 @@ snapshots: dependencies: htmlparser2: 3.10.1 postcss: 7.0.39 - postcss-syntax: 0.36.2(postcss-html@0.36.0)(postcss-jsx@0.36.4)(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@7.0.39) + postcss-syntax: 0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-scss@2.1.1)(postcss@7.0.39) postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39): dependencies: '@babel/core': 7.28.5 postcss: 7.0.39 - postcss-syntax: 0.36.2(postcss-html@0.36.0)(postcss-jsx@0.36.4)(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@7.0.39) + postcss-syntax: 0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-scss@2.1.1)(postcss@7.0.39) transitivePeerDependencies: - supports-color @@ -12689,7 +14221,7 @@ snapshots: postcss-markdown@0.36.0(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39): dependencies: postcss: 7.0.39 - postcss-syntax: 0.36.2(postcss-html@0.36.0)(postcss-jsx@0.36.4)(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@7.0.39) + postcss-syntax: 0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-scss@2.1.1)(postcss@7.0.39) remark: 10.0.1 unist-util-find-all-after: 1.0.5 @@ -12741,7 +14273,7 @@ snapshots: lodash: 4.17.21 postcss: 7.0.39 - postcss-syntax@0.36.2(postcss-html@0.36.0)(postcss-jsx@0.36.4)(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@7.0.39): + postcss-syntax@0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-scss@2.1.1)(postcss@7.0.39): dependencies: postcss: 7.0.39 optionalDependencies: @@ -12859,6 +14391,13 @@ snapshots: range-parser@1.2.1: {} + raw-body@2.5.3: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + raw-body@3.0.2: dependencies: bytes: 3.1.2 @@ -13003,6 +14542,8 @@ snapshots: indent-string: 4.0.0 strip-indent: 3.0.0 + reflect-metadata@0.2.2: {} + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -13086,6 +14627,8 @@ snapshots: requirejs@2.3.8: {} + requires-port@1.0.0: {} + resolve-dependency-path@4.0.1: {} resolve-from@3.0.0: {} @@ -13125,28 +14668,28 @@ snapshots: dependencies: glob: 7.2.3 - rollup-plugin-bundle-stats@4.21.7(core-js@3.47.0)(rollup@4.53.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)): + rollup-plugin-bundle-stats@4.21.7(core-js@3.47.0)(rollup@4.53.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@bundle-stats/cli-utils': 4.21.7(core-js@3.47.0) - rollup-plugin-webpack-stats: 2.1.8(rollup@4.53.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + rollup-plugin-webpack-stats: 2.1.8(rollup@4.53.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) tslib: 2.8.1 optionalDependencies: rollup: 4.53.3 - vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - core-js - rollup-plugin-stats@1.5.3(rollup@4.53.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)): + rollup-plugin-stats@1.5.3(rollup@4.53.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): optionalDependencies: rollup: 4.53.3 - vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) - rollup-plugin-webpack-stats@2.1.8(rollup@4.53.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)): + rollup-plugin-webpack-stats@2.1.8(rollup@4.53.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): dependencies: - rollup-plugin-stats: 1.5.3(rollup@4.53.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + rollup-plugin-stats: 1.5.3(rollup@4.53.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) optionalDependencies: rollup: 4.53.3 - vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) rollup@4.53.3: dependencies: @@ -13186,10 +14729,22 @@ snapshots: transitivePeerDependencies: - supports-color + run-async@2.4.1: {} + + run-async@3.0.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.1: + dependencies: + tslib: 2.8.1 + + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 @@ -13236,6 +14791,19 @@ snapshots: scheduler@0.27.0: {} + schema-utils@3.3.0: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + + schema-utils@4.3.3: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.17.1 + ajv-formats: 2.1.1(ajv@8.17.1) + ajv-keywords: 5.1.0(ajv@8.17.1) + scroll-into-view-if-needed@3.0.10: dependencies: compute-scroll-into-view: 3.1.1 @@ -13246,6 +14814,24 @@ snapshots: semver@7.7.3: {} + send@0.19.2: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.1 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + send@1.2.0: dependencies: debug: 4.4.3(supports-color@5.5.0) @@ -13264,6 +14850,15 @@ snapshots: serialize-query-params@2.0.3: {} + serve-static@1.16.3: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.2 + transitivePeerDependencies: + - supports-color + serve-static@2.2.0: dependencies: encodeurl: 2.0.0 @@ -13421,12 +15016,19 @@ snapshots: source-map-url: 0.4.1 urix: 0.1.0 + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + source-map-url@0.4.1: {} source-map@0.5.7: {} source-map@0.6.1: {} + source-map@0.7.4: {} + spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 @@ -13469,13 +15071,13 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 - storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)): + storybook@9.1.16(@testing-library/dom@10.4.1)(prettier@3.7.3)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@storybook/global': 5.0.0 '@testing-library/jest-dom': 6.9.1 '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/spy': 3.2.4 better-opn: 3.0.2 esbuild: 0.25.12 @@ -13505,6 +15107,8 @@ snapshots: dependencies: any-promise: 1.3.0 + streamsearch@1.1.0: {} + string-width@3.1.0: dependencies: emoji-regex: 7.0.3 @@ -13623,6 +15227,10 @@ snapshots: dependencies: js-tokens: 9.0.1 + strtok3@10.3.4: + dependencies: + '@tokenizer/token': 0.3.0 + style-search@0.1.0: {} stylelint-config-rational-order@0.1.2: @@ -13760,7 +15368,7 @@ snapshots: postcss-sass: 0.3.5 postcss-scss: 2.1.1 postcss-selector-parser: 3.1.2 - postcss-syntax: 0.36.2(postcss-html@0.36.0)(postcss-jsx@0.36.4)(postcss-less@3.1.4)(postcss-markdown@0.36.0)(postcss-scss@2.1.1)(postcss@7.0.39) + postcss-syntax: 0.36.2(postcss-html@0.36.0(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-jsx@0.36.4(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-less@3.1.4)(postcss-markdown@0.36.0(postcss-syntax@0.36.2(postcss@8.5.6))(postcss@7.0.39))(postcss-scss@2.1.1)(postcss@7.0.39) postcss-value-parser: 3.3.1 resolve-from: 4.0.0 signal-exit: 3.0.7 @@ -13784,6 +15392,8 @@ snapshots: superstruct@2.0.2: {} + supports-color@10.2.2: {} + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -13792,6 +15402,10 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-hyperlinks@3.2.0: dependencies: has-flag: 4.0.0 @@ -13801,6 +15415,10 @@ snapshots: svg-tags@1.0.0: {} + swagger-ui-dist@5.17.14: {} + + symbol-observable@4.0.0: {} + synckit@0.11.11: dependencies: '@pkgr/core': 0.2.9 @@ -13875,6 +15493,23 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + terser-webpack-plugin@5.3.17(webpack@5.97.1): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + jest-worker: 27.5.1 + schema-utils: 4.3.3 + terser: 5.46.0 + webpack: 5.97.1 + + terser@5.46.0: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + through@2.3.8: {} + tiny-invariant@1.3.3: {} tinybench@2.9.0: {} @@ -13895,6 +15530,10 @@ snapshots: tinyspy@4.0.4: {} + tmp@0.0.33: + dependencies: + os-tmpdir: 1.0.2 + tmp@0.2.5: {} to-object-path@0.3.0: @@ -13919,6 +15558,12 @@ snapshots: toidentifier@1.0.1: {} + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.1 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + totalist@3.0.1: {} touch@3.1.1: {} @@ -13969,6 +15614,13 @@ snapshots: typescript: 5.7.3 v8-compile-cache-lib: 3.0.1 + tsconfig-paths-webpack-plugin@4.2.0: + dependencies: + chalk: 4.1.2 + enhanced-resolve: 5.18.3 + tapable: 2.3.0 + tsconfig-paths: 4.2.0 + tsconfig-paths@4.2.0: dependencies: json5: 2.2.3 @@ -13988,6 +15640,15 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-fest@0.21.3: {} + + type-fest@4.41.0: {} + + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + type-is@2.0.1: dependencies: content-type: 1.0.5 @@ -14027,6 +15688,8 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typedarray@0.0.6: {} + typescript-eslint@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.7.3): dependencies: '@typescript-eslint/eslint-plugin': 8.48.1(@typescript-eslint/parser@8.48.1(eslint@9.39.1(jiti@2.6.1))(typescript@5.7.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.7.3) @@ -14038,10 +15701,18 @@ snapshots: transitivePeerDependencies: - supports-color + typescript@5.7.2: {} + typescript@5.7.3: {} typescript@5.9.3: {} + uid@2.0.2: + dependencies: + '@lukeed/csprng': 1.1.0 + + uint8array-extras@1.5.0: {} + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -14108,6 +15779,8 @@ snapshots: dependencies: unist-util-visit-parents: 2.1.2 + universalify@2.0.1: {} + unpipe@1.0.0: {} unplugin@1.16.1: @@ -14150,6 +15823,8 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + uri-js-replace@1.0.1: {} + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -14185,6 +15860,8 @@ snapshots: utility-types@3.11.0: {} + utils-merge@1.0.1: {} + v8-compile-cache-lib@3.0.1: {} validate-npm-package-license@3.0.4: @@ -14192,6 +15869,8 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 + validator@13.15.26: {} + vary@1.1.2: {} vfile-location@2.0.6: {} @@ -14212,13 +15891,13 @@ snapshots: unist-util-stringify-position: 1.1.2 vfile-message: 1.1.1 - vite-node@3.2.4(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2): + vite-node@3.2.4(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: cac: 6.7.14 debug: 4.4.3(supports-color@5.5.0) es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) transitivePeerDependencies: - '@types/node' - jiti @@ -14233,7 +15912,7 @@ snapshots: - tsx - yaml - vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2): + vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) @@ -14248,14 +15927,15 @@ snapshots: lightningcss: 1.30.2 sass: 1.94.2 sugarss: 2.0.0 + terser: 5.46.0 tsx: 4.21.0 yaml: 2.8.2 - vitest@3.2.4(@types/node@22.19.1)(@vitest/browser@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2): + vitest@3.2.4(@types/node@22.19.1)(@vitest/browser@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2)) + '@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -14273,12 +15953,12 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) - vite-node: 3.2.4(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2) + vite: 6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) + vite-node: 3.2.4(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.19.1 - '@vitest/browser': 3.2.4(playwright@1.57.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@3.2.4) + '@vitest/browser': 3.2.4(playwright@1.57.0)(vite@6.4.1(@types/node@22.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(sass@1.94.2)(sugarss@2.0.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2))(vitest@3.2.4) transitivePeerDependencies: - jiti - less @@ -14309,14 +15989,53 @@ snapshots: walkdir@0.4.1: {} + watchpack@2.5.1: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + wcwidth@1.0.1: dependencies: defaults: 1.0.4 webidl-conversions@3.0.1: {} + webpack-node-externals@3.0.0: {} + + webpack-sources@3.3.4: {} + webpack-virtual-modules@0.6.2: {} + webpack@5.97.1: + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.15.0 + browserslist: 4.28.0 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.18.3 + es-module-lexer: 1.7.0 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.1 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 3.3.0 + tapable: 2.3.0 + terser-webpack-plugin: 5.3.17(webpack@5.97.1) + watchpack: 2.5.1 + webpack-sources: 3.3.4 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -14378,6 +16097,12 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -14411,6 +16136,8 @@ snapshots: yallist@3.1.1: {} + yaml-ast-parser@0.0.43: {} + yaml@2.8.2: {} yargs-parser@10.1.0: diff --git a/test.ts b/test.ts new file mode 100644 index 0000000..e43648a --- /dev/null +++ b/test.ts @@ -0,0 +1,122 @@ +type TupleToUnion = T extends [infer L, ...infer R] + ? R extends any[] + ? L | TupleToUnion + : L + : never; + +type Foo = [string, number, boolean]; +type Bar = TupleToUnion; + +type IsEmptyType = T extends null | undefined | {} ? true : false; +type Test = IsEmptyType; + +type StrLength = T extends "" + ? C["length"] + : T extends `${infer L}${infer R}` + ? StrLength + : never; + +type Test2 = StrLength<"asdasd ">; + +type ReplaceAll< + S extends string, + F extends string, + T extends string, +> = S extends `${infer L}${F}${infer R}` ? `${L}${T}${ReplaceAll}` : S; + +type Test3 = ReplaceAll<"bfe.dev", "", "-">; + +// type IsBigger = + +type ToArray = A["length"] extends N + ? A + : ToArray; + +type Slice< + A extends any[], + S extends number = 0, + E extends number = A["length"], + I extends any[] = ToArray, +> = I["length"] extends E + ? [] // end + : I["length"] extends A["length"] + ? [] // end + : A[I["length"]] extends undefined + ? [] + : [A[I["length"]], ...Slice]; + +type Test4 = Slice<[1, 2, 3, 4], 0, 2>; +type E = Slice<[number, boolean, bigint], 5, 6>; // [] + +// type ToArray = L['length'] extends N +// ? L +// : ToArray + +{ + type Divide< + A extends number, + B extends number, + AL extends any[] = ToArray, + BL extends any[] = ToArray, + Result extends any[] = [], + > = BL["length"] extends 0 + ? never + : AL extends [...BL, ...infer AR] + ? Divide + : Result["length"]; + + type A = Divide<1, 0>; // never + type B = Divide<4, 2>; // 2 + type C = Divide<10, 3>; // 3 +} + +{ + type LargerThan< + A extends number, + B extends number, + LA extends any[] = ToArray, + LB extends any[] = ToArray, + > = [...LA] extends [...LB, ...infer L] + ? LA["length"] extends LB["length"] + ? false + : true + : false; + + type AA = [""] extends ["", "", ...infer R] ? "extends" : "not"; + + type A = LargerThan<3, 2>; // false + type B = LargerThan<1, 0>; // true + type C = LargerThan<10, 9>; // true + + type N = L["length"]; + + // [3, 2, 1] + // type Sort< + // T extends number[], + // L extends any[] = [], + // R extends any[] = [""], + // Result extends number[] = [], + // > = + // T extends [infer A, infer B, ...infer C] + // ? + // LargerThan], T[N]> extends true + // ? T extends [...infer LL, T[N], T[N], ...infer RR] + // ? [...LL, T[N], T[N], ...RR] extends number[] + // ? Sort<[...LL, T[N], T[N], ...RR], [], [""], Result> // sort from start + // : "1" + // : "2" + // : N extends N + // ? "3" + // : Sort; + + // type AAA = Sort<[3, 2]>; + + // type Z = T extends [infer A, infer B, ...infer R] ? R : never; + // type ZZ = Z<[0, 1, 2, 3]>; +} + +{ + type Includes = [...T] extends [U, ...infer R] ? true : false; + + type A = Includes<["Kars", "Esidisi", "Wamuu", "Santana"], "Kars">; +} diff --git a/tsconfig.json b/tsconfig.json index 980388f..c9789c8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -25,10 +25,11 @@ "noImplicitAny": false }, "include": [ - "*.config.*" + "*.config.*", + "test.ts" ], "exclude": [ "**/node_modules", "**/dist", ] -} +} \ No newline at end of file From df59e2e8d5d2650ab597ce315d8b42c40919c348 Mon Sep 17 00:00:00 2001 From: Aleksandr Chernigin Date: Tue, 21 Jul 2026 11:01:01 +0300 Subject: [PATCH 2/4] feat: enhance backend with environment configuration, Docker support, and API documentation --- .env.example | 35 ++ .github/workflows/deploy.yml | 12 +- .github/workflows/pull-request.yml | 22 +- CLAUDE.md | 95 ++++ apps/web/Dockerfile => Dockerfile | 6 +- apps/backend/README.md | 98 ++++ apps/backend/eslint.config.mjs | 5 + apps/backend/package.json | 79 +-- apps/backend/src/app.controller.ts | 5 + apps/backend/src/app.module.ts | 36 +- apps/backend/src/auth/auth.guard.ts | 27 +- apps/backend/src/auth/auth.module.ts | 14 +- apps/backend/src/auth/auth.types.ts | 12 + .../src/auth/current-user.decorator.ts | 9 + .../src/auth/extract-bearer-token.test.ts | 28 ++ apps/backend/src/auth/extract-bearer-token.ts | 7 + .../filters/all-exceptions.filter.test.ts | 67 +++ .../common/filters/all-exceptions.filter.ts | 68 +++ apps/backend/src/config/configuration.ts | 36 ++ .../backend/src/config/env.validation.test.ts | 46 ++ apps/backend/src/config/env.validation.ts | 85 ++++ apps/backend/src/main.ts | 64 ++- .../supabase-client/supabase-client.module.ts | 41 -- .../supabase-user-client.token.ts | 6 - apps/backend/src/supabase/supabase.service.ts | 54 ++- .../src/user/dto/update-user.dto.test.ts | 32 ++ apps/backend/src/user/dto/update-user.dto.ts | 7 +- apps/backend/src/user/user.controller.ts | 19 +- apps/backend/src/user/user.module.ts | 2 - apps/backend/src/user/user.service.test.ts | 34 ++ apps/backend/src/user/user.service.ts | 31 +- .../src/words/dto/add-translations.dto.ts | 18 +- apps/backend/src/words/dto/create-word.dto.ts | 31 +- .../src/words/dto/delete-translations.dto.ts | 5 +- .../backend/src/words/dto/delete-words.dto.ts | 5 +- .../src/words/dto/translation-input.dto.ts | 28 ++ .../src/words/dto/update-words-status.dto.ts | 6 +- apps/backend/src/words/dto/validation.test.ts | 100 ++++ apps/backend/src/words/words.controller.ts | 51 +- apps/backend/src/words/words.module.ts | 2 - apps/backend/src/words/words.service.test.ts | 185 +++++++ apps/backend/src/words/words.service.ts | 103 ++-- apps/backend/test/app.e2e.test.ts | 122 +++++ apps/backend/test/nest-app.ts | 64 +++ apps/backend/test/rate-limit.e2e.test.ts | 43 ++ apps/backend/test/setup-env.ts | 6 + apps/backend/test/supabase-fake.ts | 77 +++ apps/backend/tsconfig.build.json | 5 + apps/backend/tsconfig.json | 6 +- apps/backend/vitest.config.ts | 14 + apps/web/package.json | 3 +- apps/web/src/server/main.ts | 26 +- apps/web/src/server/middlewares/user.ts | 21 +- apps/web/src/server/shared/backend.ts | 13 + apps/web/src/server/shared/sdk.ts | 3 +- .../layout/ui/LandingPreferencesControls.tsx | 2 - package.json | 2 + packages/api/package.json | 3 +- packages/api/src/database.types.public.ts | 9 +- packages/api/src/schemas/api.ts | 6 +- packages/api/src/schemas/openapi.json | 6 +- packages/api/src/sdk/client.ts | 35 +- packages/api/src/sdk/index.ts | 2 + packages/api/src/sdk/sdk.ts | 5 +- pnpm-lock.yaml | 459 +++++++++++++++++- 65 files changed, 2197 insertions(+), 351 deletions(-) create mode 100644 CLAUDE.md rename apps/web/Dockerfile => Dockerfile (82%) create mode 100644 apps/backend/README.md create mode 100644 apps/backend/src/auth/auth.types.ts create mode 100644 apps/backend/src/auth/current-user.decorator.ts create mode 100644 apps/backend/src/auth/extract-bearer-token.test.ts create mode 100644 apps/backend/src/auth/extract-bearer-token.ts create mode 100644 apps/backend/src/common/filters/all-exceptions.filter.test.ts create mode 100644 apps/backend/src/common/filters/all-exceptions.filter.ts create mode 100644 apps/backend/src/config/configuration.ts create mode 100644 apps/backend/src/config/env.validation.test.ts create mode 100644 apps/backend/src/config/env.validation.ts delete mode 100644 apps/backend/src/supabase-client/supabase-client.module.ts delete mode 100644 apps/backend/src/supabase-client/supabase-user-client.token.ts create mode 100644 apps/backend/src/user/dto/update-user.dto.test.ts create mode 100644 apps/backend/src/user/user.service.test.ts create mode 100644 apps/backend/src/words/dto/translation-input.dto.ts create mode 100644 apps/backend/src/words/dto/validation.test.ts create mode 100644 apps/backend/src/words/words.service.test.ts create mode 100644 apps/backend/test/app.e2e.test.ts create mode 100644 apps/backend/test/nest-app.ts create mode 100644 apps/backend/test/rate-limit.e2e.test.ts create mode 100644 apps/backend/test/setup-env.ts create mode 100644 apps/backend/test/supabase-fake.ts create mode 100644 apps/backend/tsconfig.build.json create mode 100644 apps/backend/vitest.config.ts create mode 100644 apps/web/src/server/shared/backend.ts diff --git a/.env.example b/.env.example index 00c3de9..94b6fb8 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,43 @@ +; --------------------------------------------------------------------------- +; Supabase project +; --------------------------------------------------------------------------- +; Used by the type generation scripts (supabase gen types). SUPABASE_PROJECT_ID= + +; Exposed to the browser by Vite. Must be the anon (public) key — never a secret. VITE_SUPABASE_PROJECT_URL= VITE_SUPABASE_PROJECT_KEY= +; Read by apps/backend. Same project as above; the backend validates these at +; startup and refuses to boot without them. +; SUPABASE_ANON_KEY is deliberately the *anon* key: every backend query runs +; through a client bound to the caller's JWT so RLS applies. A service role key +; here would bypass RLS entirely, which is why the backend never asks for one. +; In production these two are injected into the Serverless Container at runtime +; via `--environment` (see .github/workflows/deploy.yml), not baked into the image. +SUPABASE_PROJECT_URL= +SUPABASE_ANON_KEY= + +; --------------------------------------------------------------------------- +; Ports +; --------------------------------------------------------------------------- +; Express SSR server (apps/web). +PORT=5173 +; NestJS backend (apps/backend). apps/web proxies /api/* here. +BACKEND_PORT=3001 + +; --------------------------------------------------------------------------- +; Backend hardening (optional — sensible defaults apply when unset) +; --------------------------------------------------------------------------- +; Comma-separated CORS allowlist. Defaults to http://localhost:5173. +CORS_ORIGINS=http://localhost:5173 +; Rate limit window in ms and max requests per window per IP. Defaults: 60000 / 120. +THROTTLE_TTL=60000 +THROTTLE_LIMIT=120 + +; --------------------------------------------------------------------------- ; S3 Access key to static content +; --------------------------------------------------------------------------- AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_DEFAULT_REGION=ru-central1 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index b2d4858..81afd35 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -95,12 +95,10 @@ jobs: - name: Create Docker Image if: inputs.main == false - working-directory: apps/web run: pnpm run build:docker - name: Create Docker Image (main) if: inputs.main == true - working-directory: apps/web run: pnpm run build:baseline:docker - name: Extract bundle-stats @@ -171,12 +169,13 @@ jobs: --container-name ${{ inputs.revision_name }} \ --image "${{ steps.push_docker_image.outputs.docker_image_tag }}" \ --cores 1 \ - --memory 512mb \ + --memory 1gb \ --concurrency 1 \ --execution-timeout 30s \ --cloud-id ${{ inputs.cloud_id }} \ --folder-name "${{ inputs.folder_name }}" \ - --service-account-id ${{ inputs.sa_deployer_id }} + --service-account-id ${{ inputs.sa_deployer_id }} \ + --environment SUPABASE_PROJECT_URL=${{ secrets.SUPABASE_PROJECT_URL }},SUPABASE_ANON_KEY=${{ secrets.SUPABASE_PROJECT_KEY }},NODE_ENV=production - name: Deploy Container Revision (main) if: inputs.main == true @@ -191,7 +190,8 @@ jobs: --cloud-id ${{ inputs.cloud_id }} \ --folder-name "${{ inputs.folder_name }}" \ --service-account-id ${{ inputs.sa_deployer_id }} \ - --min-instances 1 + --min-instances 1 \ + --environment SUPABASE_PROJECT_URL=${{ secrets.SUPABASE_PROJECT_URL }},SUPABASE_ANON_KEY=${{ secrets.SUPABASE_PROJECT_KEY }},NODE_ENV=production - name: Configure Api Gateway id: configure_api_gateway @@ -206,7 +206,7 @@ jobs: gw_info=$(yc serverless api-gateway get \ --name ${{ inputs.revision_name }} \ --cloud-id ${{ inputs.cloud_id }} \ - --folder-name "${{ inputs.folder_name }}" + --folder-name "${{ inputs.folder_name }}" \ --format json 2>/dev/null || true) if [ -n "$gw_info" ]; then diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 0aa8977..47fec7f 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -14,12 +14,12 @@ jobs: name: "pnpm install" uses: ./.github/workflows/pnpm-install.yml - check-web-affected: - name: "Check if app-web is affected" + check-deploy-affected: + name: "Check if a deployable app is affected" runs-on: ubuntu-latest needs: npm-ci outputs: - web-affected: ${{ steps.check.outputs.web-affected }} + deploy-affected: ${{ steps.check.outputs.deploy-affected }} steps: - name: Checkout repository uses: actions/checkout@v4 @@ -36,20 +36,20 @@ jobs: - name: Derive SHAs for base and head uses: nrwl/nx-set-shas@v4 - - name: Check if app-web is affected + - name: Check if a deployable app is affected id: check run: | AFFECTED=$(pnpm nx show projects --affected --json) - WEB_AFFECTED=$(echo "$AFFECTED" | jq -r 'any(. == "app-web")') - echo "web-affected=$WEB_AFFECTED" >> $GITHUB_OUTPUT + DEPLOY_AFFECTED=$(echo "$AFFECTED" | jq -r 'any(. == "app-web" or . == "app-backend")') + echo "deploy-affected=$DEPLOY_AFFECTED" >> $GITHUB_OUTPUT echo "Affected projects: $AFFECTED" - echo "app-web affected: $WEB_AFFECTED" + echo "deployable app affected: $DEPLOY_AFFECTED" deploy: name: "Deploy staging" uses: ./.github/workflows/deploy.yml - needs: [npm-ci, check-web-affected] - if: needs.check-web-affected.outputs.web-affected == 'true' + needs: [npm-ci, check-deploy-affected] + if: needs.check-deploy-affected.outputs.deploy-affected == 'true' secrets: SA_DEPLOYER_PRIVATE_KEY: ${{ secrets.SA_STAGING_DEPLOYER_PRIVATE_KEY }} S3_KEY_ID: ${{ secrets.S3_KEY_ID }} @@ -69,8 +69,8 @@ jobs: bundle-stats: name: "Bundle stats" uses: ./.github/workflows/bundle-stats.yml - needs: [deploy, check-web-affected] - if: needs.check-web-affected.outputs.web-affected == 'true' + needs: [deploy, check-deploy-affected] + if: needs.check-deploy-affected.outputs.deploy-affected == 'true' secrets: S3_KEY_ID: ${{ secrets.S3_KEY_ID }} S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }} diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..7cd2f80 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,95 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Repository + +Nx + pnpm monorepo for **Languages Learner**, a language-learning web app. Workspaces are `apps/*` and `packages/*` (see `pnpm-workspace.yaml`). Node 20 (`.nvmrc`), pnpm 10.6.2 via Corepack. + +`nx.json` is intentionally minimal — Nx infers targets from each package's `package.json` scripts. Root scripts are `nx run-many -t ` fan-outs, so a target only runs where the package defines it. + +## Commands + +Root (all workspaces): + +```bash +pnpm lint # nx run-many -t lint +pnpm typecheck # nx run-many -t typecheck +pnpm test:unit # vitest watch; pnpm test:unit:ci for a single run +pnpm stylelint +pnpm circular-deps # madge, UI code only +pnpm knip # unused files/exports/deps +pnpm deps:check # syncpack — dependency versions consistent across packages +``` + +Single package/app — use pnpm filters with the **package name**, not the folder: + +```bash +pnpm --filter app-web dev # apps/web +pnpm --filter app-backend start:dev # apps/backend +pnpm --filter @languages-learner/uikit typecheck +``` + +Full local stack (SSR web + NestJS backend together): `pnpm --filter app-web dev:all`. + +Single unit test: only `packages/class-names` and `packages/error-utils` define `test:unit`. Run e.g. `pnpm --filter @languages-learner/class-names test:unit -- ` (vitest). Root `vitest.config.ts` only picks up `**/*.test.ts`. + +Component tests (Playwright CT, uikit only) run inside Docker for stable screenshots: + +```bash +pnpm --filter @languages-learner/uikit test:component:docker +pnpm --filter @languages-learner/uikit test:component:update:docker # update snapshots +``` + +Storybook: `pnpm --filter @languages-learner/storybook storybook` (port 6006). + +## Architecture + +### apps/web — custom SSR, not a framework + +Two independent TypeScript projects under `src/`, each with its own `tsconfig.json` and its own build: + +- `src/server/` — Express server (`src/server/main.ts`), built by `tsx`/nodemon in dev. +- `src/ui/` — React app, built by Vite twice: `vite build` (client) and `vite build --ssr src/ui/app/entries/main-server.tsx` (server bundle). + +The server is the SSR orchestrator. In development it runs Vite in `middlewareMode` and loads the render function through `vite.ssrLoadModule`; in production it reads the prebuilt HTML shell and imports `dist/server/main-server.mjs`. It then string-replaces ``, ``, a theme class on ``, and `window.CLIENT = {}` with `res.locals`. + +**`res.locals` is the SSR contract.** Express middlewares (`src/server/middlewares/`: `user`, `locale`, `theme`) populate it, `render(res.locals)` consumes it, and the same object is serialized into `window.CLIENT` for client hydration. Adding server-derived state means touching all three points. + +`/api/*` is proxied to the NestJS backend (`BACKEND_PORT`, default 3001) — the proxy middleware must stay registered before Vite's middlewares. + +### apps/web UI layers (Feature-Sliced Design) + +`src/ui/` follows FSD: `app` → `pages` → `widgets` → `features` → `entities` → `shared`. Imports flow downward only; circular imports are enforced by `madge` (`circular-deps:ui`). Path aliases inside `src/ui`: `@/*` → `src/ui/*`, `@@/*` → repo root, `shared/*` → `src/shared/*` (cross-cutting, server+ui), `locales/*` → `src/locales/*`. The server project deliberately has no aliases yet (relative paths only). + +### Data layer + +Two coexisting systems: **TanStack Query** wrapped by `@normy/react-query`'s `QueryNormalizerProvider` for normalized cache updates, and **Gravity UI DataSource** via the shared `dataManager` from `@languages-learner/data-source` (`DataManagerContext`). Check which one a slice already uses before adding data fetching. + +### apps/backend — NestJS + +Standard Nest module layout (`words`, `user`, `auth`, `supabase`, `config`, `common`). `SupabaseService` is the only place clients are created: `getAuthClient()` verifies tokens, `getClientForUser(token)` returns an RLS-scoped client for the caller. There is deliberately **no service-role key** — a service-role client would bypass RLS on every request. Auth is a global `AuthGuard` (opt out with `@Public()`) that attaches `{ id, email, accessToken }`, read in handlers via `@CurrentUser()`. + +**Keep this provider graph free of `Scope.REQUEST`, and never authenticate inside a provider factory.** A request-scoped Supabase client used to throw `UnauthorizedException` from its factory; because Nest resolves request-scoped providers before guards run, that throw short-circuited the guard chain and the global `ThrottlerGuard` never executed on protected routes. The 401 looked correct, so nothing surfaced it. Covered by `apps/backend/test/rate-limit.e2e.test.ts`. + +Env is validated at startup (`src/config/env.validation.ts`); missing vars exit the process with a readable message instead of failing on the first request. See `apps/backend/README.md`. + +Database types are generated, not hand-written: `generate-types` in `apps/backend` regenerates `database.types.ts` and copies it into `packages/api`. Do not edit those files, and note `lint` runs with `--fix` — the generated types are eslint-ignored so it cannot reformat them. + +**The API contract is generated too.** Backend DTOs → Swagger → `packages/api/src/schemas/openapi.json` → `api.ts` → SDK → `apps/web`. After changing a DTO or a handler's return type, run `pnpm --filter app-backend generate:api-schemas` (needs a valid root `.env`) and commit the regenerated schemas, otherwise `apps/web` typechecks against a stale contract. + +### i18n + +FormatJS + react-intl with **hash-based message IDs** — `formatjs/enforce-id` (ESLint) requires the `[sha512:contenthash:base64:6]` pattern, so IDs are generated, never authored. Workflow: `pnpm --filter app-web i18n:extract` → `src/locales/extracted.json`, then `i18n:manage` extracts, syncs `en.json`/`ru.json`, and compiles into `src/locales/compiled/` (which the app imports directly). Compiled locales are a build input for typecheck too. + +## Conventions + +- Prettier: 4-space indent, 100 columns, trailing commas, LF line endings (`linebreak-style` is an ESLint error on Windows too). Tailwind class sorting via `prettier-plugin-tailwindcss`. +- Type imports must be inline (`import { type Foo }` style enforced by `@typescript-eslint/consistent-type-imports` with `fixStyle: "inline-type-imports"`). +- `newline-before-return` is an error. +- PR titles must be conventional/semantic (`feat:`, `fix:`, `chore:` …) — enforced by `.github/workflows/check-pr-title.yml`. +- Each app and package has its own `README.md` listing its scripts; check it before inventing commands. + +## Notes + +The public tree ships no database migrations and no turnkey local backend — API-dependent work needs your own Supabase project (see `.env.example`) or mocks. diff --git a/apps/web/Dockerfile b/Dockerfile similarity index 82% rename from apps/web/Dockerfile rename to Dockerfile index a9f4f3c..c2a52cd 100644 --- a/apps/web/Dockerfile +++ b/Dockerfile @@ -36,5 +36,7 @@ ENV PORT=8080 ENV BACKEND_PORT=3001 ENV NODE_ENV=production -# Start both backend and frontend servers (backend on 3001, frontend on 8080) -CMD ["sh", "-c", "PORT=3001 pnpm --filter app-backend run start:prod & PORT=8080 pnpm --filter app-web run preview & wait"] +# Start both backend and frontend servers (backend on 3001, frontend on 8080). +# `wait -n` returns as soon as either process exits, and `exit 1` tears the +# container down so the platform replaces it instead of keeping a half-dead one. +CMD ["sh", "-c", "PORT=3001 pnpm --filter app-backend run start:prod & PORT=8080 pnpm --filter app-web run start:prod & wait -n; exit 1"] diff --git a/apps/backend/README.md b/apps/backend/README.md new file mode 100644 index 0000000..4154f21 --- /dev/null +++ b/apps/backend/README.md @@ -0,0 +1,98 @@ +# app-backend + +NestJS API for **Languages Learner**. Serves `/api/*`, verifies Supabase JWTs, and executes +every database query through a client bound to the caller's token so that Row Level Security +decides what the caller can see. + +`apps/web` proxies `/api/*` to this service, so browsers normally never talk to it directly. + +## Scripts + +Run from the monorepo root with `pnpm --filter app-backend