From c251a8ec42445c7884b1aa8af9217a80177dd8dd Mon Sep 17 00:00:00 2001 From: Joaquin Date: Sun, 7 Sep 2025 16:31:16 -0300 Subject: [PATCH 01/17] Create base Turborepo monorepo project Monorepo Setup: Initialized the base project scaffolding and configuration using create-awesome-node-app. Fixed dependency errors. Removed unnecessary package folders to simplify the demo solution. Removed extra configurations like changesets and some Turborepo settings to keep the setup straightforward. Frontend: Bootstrapped the frontend project with create vite@latest --template react-ts. Added shadcn and Tailwind CSS for styling. Backend: Bootstrapped the backend project with create-awesome-node-app. Removed unnecessary files and configurations to simplify the setup. Updated fixed versions and made changes to eslint.config.mjs. Docker & Compose: Added Dockerfiles for development purposes to assist with the review process. Added compose.yml for development and review workflows. Notes: Disabled the example test file app.e2e-spec.ts to avoid unresolved lint errors. This commit focuses on setting up the initial solution --- .editorconfig | 15 + .eslintrc | 11 + .github/copilot-instructions.md | 75 + .gitignore | 41 + .lintstagedrc.json | 3 + .markdownlint.json | 8 + .node-version | 1 + apps/backend/.dockerignore | 5 + apps/backend/.env.example | 0 apps/backend/.eslitignore | 10 + apps/backend/.github/copilot-instructions.md | 76 + apps/backend/.gitignore | 400 + apps/backend/.prettierrc.js | 7 + apps/backend/Dockerfile | 15 + apps/backend/README.md | 98 + apps/backend/docs/README.md | 7 + apps/backend/eslint.config.mjs | 34 + apps/backend/jest.config.js | 11 + apps/backend/nest-cli.json | 8 + apps/backend/package.json | 73 + apps/backend/src/app.controller.spec.ts | 22 + apps/backend/src/app.controller.ts | 12 + apps/backend/src/app.module.ts | 10 + apps/backend/src/app.service.ts | 8 + apps/backend/src/main.ts | 11 + apps/backend/test/app.e2e-spec.ts | 23 + apps/backend/test/jest-e2e.json | 9 + apps/backend/tsconfig.build.json | 4 + apps/backend/tsconfig.json | 22 + apps/frontend/.dockerignore | 5 + apps/frontend/.editorconfig | 15 + apps/frontend/.env.example | 0 apps/frontend/.github/copilot-instructions.md | 71 + apps/frontend/.gitignore | 24 + apps/frontend/.prettierrc.js | 7 + apps/frontend/Dockerfile | 13 + apps/frontend/README.md | 69 + apps/frontend/components.json | 22 + apps/frontend/docs/COMPONENTS_AND_STYLING.md | 89 + apps/frontend/docs/PERFORMANCE.md | 43 + apps/frontend/docs/PROJECT_CONFIGURATION.md | 55 + apps/frontend/docs/PROJECT_STRUCTURE.md | 126 + apps/frontend/docs/README.md | 11 + apps/frontend/docs/STATE_MANAGEMENT.md | 40 + apps/frontend/eslint.config.mjs | 60 + apps/frontend/index.html | 13 + apps/frontend/package.json | 42 + apps/frontend/public/vite.svg | 1 + apps/frontend/src/App.css | 42 + apps/frontend/src/App.tsx | 31 + apps/frontend/src/assets/react.svg | 1 + apps/frontend/src/index.css | 186 + apps/frontend/src/lib/utils.ts | 6 + apps/frontend/src/main.tsx | 10 + apps/frontend/src/vite-env.d.ts | 1 + apps/frontend/tsconfig.app.json | 35 + apps/frontend/tsconfig.json | 10 + apps/frontend/tsconfig.node.json | 25 + apps/frontend/vite.config.ts | 14 + compose.yml | 44 + docs/DEVELOPMENT_WORKFLOW.md | 178 + docs/PROJECT_STRUCTURE.md | 52 + docs/README.md | 27 + package.json | 21 + pnpm-lock.yaml | 8542 +++++++++++++++++ pnpm-workspace.yaml | 2 + turbo.json | 22 + 67 files changed, 10974 insertions(+) create mode 100644 .editorconfig create mode 100644 .eslintrc create mode 100644 .github/copilot-instructions.md create mode 100644 .gitignore create mode 100644 .lintstagedrc.json create mode 100644 .markdownlint.json create mode 100644 .node-version create mode 100644 apps/backend/.dockerignore create mode 100644 apps/backend/.env.example create mode 100644 apps/backend/.eslitignore create mode 100644 apps/backend/.github/copilot-instructions.md create mode 100644 apps/backend/.gitignore create mode 100644 apps/backend/.prettierrc.js create mode 100644 apps/backend/Dockerfile create mode 100644 apps/backend/README.md create mode 100644 apps/backend/docs/README.md create mode 100644 apps/backend/eslint.config.mjs create mode 100644 apps/backend/jest.config.js create mode 100644 apps/backend/nest-cli.json create mode 100644 apps/backend/package.json create mode 100644 apps/backend/src/app.controller.spec.ts create mode 100644 apps/backend/src/app.controller.ts create mode 100644 apps/backend/src/app.module.ts create mode 100644 apps/backend/src/app.service.ts create mode 100644 apps/backend/src/main.ts create mode 100644 apps/backend/test/app.e2e-spec.ts create mode 100644 apps/backend/test/jest-e2e.json create mode 100644 apps/backend/tsconfig.build.json create mode 100644 apps/backend/tsconfig.json create mode 100644 apps/frontend/.dockerignore create mode 100644 apps/frontend/.editorconfig create mode 100644 apps/frontend/.env.example create mode 100644 apps/frontend/.github/copilot-instructions.md create mode 100644 apps/frontend/.gitignore create mode 100644 apps/frontend/.prettierrc.js create mode 100644 apps/frontend/Dockerfile create mode 100644 apps/frontend/README.md create mode 100644 apps/frontend/components.json create mode 100644 apps/frontend/docs/COMPONENTS_AND_STYLING.md create mode 100644 apps/frontend/docs/PERFORMANCE.md create mode 100644 apps/frontend/docs/PROJECT_CONFIGURATION.md create mode 100644 apps/frontend/docs/PROJECT_STRUCTURE.md create mode 100644 apps/frontend/docs/README.md create mode 100644 apps/frontend/docs/STATE_MANAGEMENT.md create mode 100644 apps/frontend/eslint.config.mjs create mode 100644 apps/frontend/index.html create mode 100644 apps/frontend/package.json create mode 100644 apps/frontend/public/vite.svg create mode 100644 apps/frontend/src/App.css create mode 100644 apps/frontend/src/App.tsx create mode 100644 apps/frontend/src/assets/react.svg create mode 100644 apps/frontend/src/index.css create mode 100644 apps/frontend/src/lib/utils.ts create mode 100644 apps/frontend/src/main.tsx create mode 100644 apps/frontend/src/vite-env.d.ts create mode 100644 apps/frontend/tsconfig.app.json create mode 100644 apps/frontend/tsconfig.json create mode 100644 apps/frontend/tsconfig.node.json create mode 100644 apps/frontend/vite.config.ts create mode 100644 compose.yml create mode 100644 docs/DEVELOPMENT_WORKFLOW.md create mode 100644 docs/PROJECT_STRUCTURE.md create mode 100644 docs/README.md create mode 100644 package.json create mode 100644 pnpm-lock.yaml create mode 100644 pnpm-workspace.yaml create mode 100644 turbo.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f1cc3ad --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +# http://editorconfig.org + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..b687353 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,11 @@ +{ + "root": true, + "extends": ["eslint-config-base"], + "parserOptions": { + "sourceType": "module", + "ecmaVersion": 2020, + "ecmaFeatures": { + "jsx": true + } + } +} diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..54e3daf --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,75 @@ +# GitHub Copilot Instructions for Turborepo Monorepo + +## Core Guidelines + +1. **Check Documentation First** + - Always reference the `docs/` folder for technology-specific guides and patterns + - Follow the README.md for setup, testing, and development instructions + - Consult official documentation when uncertain + +2. **Code Quality** + - Run `npm run format` to format code automatically + - Run `npm run lint:fix` to fix linting issues + - Keep code clean, typed, and well-structured + - Use TypeScript properly and avoid `any` types + +3. **Monorepo Structure** + - Follow the established package organization in `apps/` and `packages/` + - Check `docs/PROJECT_STRUCTURE.md` for monorepo patterns + - Keep packages focused and well-defined + - Use workspace dependencies appropriately + +4. **Development Workflow** + - Test changes using the commands in README.md + - Follow the project's established patterns and conventions + - Reference existing code for consistency + - Use Turborepo's caching and task orchestration + +5. **Best Practices** + - Write clean, readable, and maintainable code + - Use proper error handling and validation + - Follow monorepo best practices for scalability + - Implement proper package dependencies + +## When Suggesting Code + +1. **Package Creation** + - Check if similar packages exist in the monorepo + - Look for relevant guides in the `docs/` folder + - Follow established package structure patterns + - Use proper package.json configuration + - Implement appropriate build and export patterns + +2. **Dependency Management** + - Use workspace dependencies for internal packages + - Follow established patterns for external dependencies + - Avoid duplicate dependencies across packages + - Use proper versioning strategies + +3. **Shared Code** + - Create reusable packages in `packages/` directory + - Follow established patterns for shared components + - Implement proper TypeScript exports + - Use consistent naming conventions + +4. **App Development** + - Place applications in `apps/` directory + - Use shared packages appropriately + - Follow established patterns for each app type + - Implement proper build configurations + +5. **Build & Development** + - Use Turborepo's task pipelines effectively + - Implement proper caching strategies + - Follow established build patterns + - Use remote caching when configured + +## Turborepo Specific + +- Leverage Turborepo's parallel execution and caching +- Use proper task dependencies in turbo.json +- Implement incremental builds effectively +- Follow workspace patterns for package dependencies +- Use Turborepo's remote caching when available +- Implement proper change detection for CI/CD +- Follow established patterns for package publishing diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..97a9fb8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +node_modules +.pnp +.pnp.js + +# testing +coverage + +# next.js +.next/ +out/ +build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# turbo +.turbo +dist + +# Storybook +out +storybook-static/ + +app/ diff --git a/.lintstagedrc.json b/.lintstagedrc.json new file mode 100644 index 0000000..1f09bb7 --- /dev/null +++ b/.lintstagedrc.json @@ -0,0 +1,3 @@ +{ + "*": ["prettier -u --write"] +} diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..7c226a0 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,8 @@ +{ + "MD041": false, + "MD042": false, + "MD004": false, + "MD013": false, + "MD033": false, + "MD024": false +} diff --git a/.node-version b/.node-version new file mode 100644 index 0000000..ef220b0 --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +v20.19.4 \ No newline at end of file diff --git a/apps/backend/.dockerignore b/apps/backend/.dockerignore new file mode 100644 index 0000000..ae1db91 --- /dev/null +++ b/apps/backend/.dockerignore @@ -0,0 +1,5 @@ +node_modules +.git +build +dist +tools diff --git a/apps/backend/.env.example b/apps/backend/.env.example new file mode 100644 index 0000000..e69de29 diff --git a/apps/backend/.eslitignore b/apps/backend/.eslitignore new file mode 100644 index 0000000..42ee296 --- /dev/null +++ b/apps/backend/.eslitignore @@ -0,0 +1,10 @@ +# /node_modules/* in the project root is ignored by default +# build artefacts +dist/* +coverage/* +node_modules/* +logs/* +prod/* +.husky/* +.github/* +tools/ \ No newline at end of file diff --git a/apps/backend/.github/copilot-instructions.md b/apps/backend/.github/copilot-instructions.md new file mode 100644 index 0000000..f26abf9 --- /dev/null +++ b/apps/backend/.github/copilot-instructions.md @@ -0,0 +1,76 @@ +# GitHub Copilot Instructions for NestJS Project + +## Core Guidelines + +1. **Check Documentation First** + - Always reference the `docs/` folder for technology-specific guides and patterns + - Follow the README.md for setup, testing, and development instructions + - Consult official documentation when uncertain + +2. **Code Quality** + - Run `npm run format` to format code automatically + - Run `npm run lint:fix` to fix linting issues + - Keep code clean, typed, and well-structured + - Use TypeScript properly and avoid `any` types + +3. **Project Structure** + - Follow NestJS module-based architecture + - Use proper dependency injection patterns + - Keep services, controllers, and modules organized + - Follow NestJS best practices for scalability + +4. **Development Workflow** + - Test changes using the commands in README.md + - Follow the project's established patterns and conventions + - Reference existing code for consistency + - Use proper error handling and validation + +5. **Best Practices** + - Write clean, readable, and maintainable code + - Use proper DTOs for data validation + - Follow REST API and GraphQL conventions + - Implement proper error responses and logging + +## When Suggesting Code + +1. **Module Creation** + - Check if similar modules exist in the codebase + - Look for relevant guides in the `docs/` folder + - Follow NestJS module structure patterns + - Use proper dependency injection + - Implement appropriate guards, interceptors, and pipes + +2. **API Design** + - Use proper HTTP methods and status codes + - Implement comprehensive DTOs with validation + - Follow established API patterns in the project + - Use OpenAPI/Swagger decorators if configured + - Implement proper error handling + +3. **Database Integration** + - Reference `docs/` for ORM/database patterns used in the project + - Follow established entity and repository patterns + - Use proper transaction handling + - Implement data validation and sanitization + +4. **Authentication & Authorization** + - Follow established security patterns + - Use proper JWT handling if implemented + - Implement role-based access control appropriately + - Follow security best practices + +5. **Testing** + - Suggest appropriate unit and integration tests + - Follow testing patterns established in the project + - Mock dependencies properly + - Test both success and error scenarios + +## NestJS Specific + +- Use decorators appropriately (@Injectable, @Controller, etc.) +- Implement proper exception filters +- Use NestJS built-in validation with class-validator +- Follow dependency injection best practices +- Implement proper logging with NestJS logger +- Use configuration management properly +- Implement health checks and monitoring diff --git a/apps/backend/.gitignore b/apps/backend/.gitignore new file mode 100644 index 0000000..5c69b1f --- /dev/null +++ b/apps/backend/.gitignore @@ -0,0 +1,400 @@ +# Created by .ignore support plugin (hsz.mobi) +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff: +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/dictionaries + +# Sensitive or high-churn files: +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.xml +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml + +# Gradle: +.idea/**/gradle.xml +.idea/**/libraries + +# CMake +cmake-build-debug/ + +# Mongo Explorer plugin: +.idea/**/mongoSettings.xml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties +### VisualStudio template +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Typescript v1 declaration files +typings/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ +coverage/ + +### macOS template +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +======= +# Local +.env +dist +.webpack +.serverless/**/*.zip diff --git a/apps/backend/.prettierrc.js b/apps/backend/.prettierrc.js new file mode 100644 index 0000000..13c2be1 --- /dev/null +++ b/apps/backend/.prettierrc.js @@ -0,0 +1,7 @@ +module.exports = { + semi: true, + trailingComma: 'all', + singleQuote: true, + printWidth: 120, + tabWidth: 2, +}; diff --git a/apps/backend/Dockerfile b/apps/backend/Dockerfile new file mode 100644 index 0000000..a235c57 --- /dev/null +++ b/apps/backend/Dockerfile @@ -0,0 +1,15 @@ +FROM node:22-alpine + +WORKDIR /app + +COPY package*.json ./ + +RUN npm install + +COPY . . + +RUN npm run build + +EXPOSE 3000 + +CMD ["npm", "run", "start:dev"] diff --git a/apps/backend/README.md b/apps/backend/README.md new file mode 100644 index 0000000..d30c946 --- /dev/null +++ b/apps/backend/README.md @@ -0,0 +1,98 @@ +

+ Nest Logo +

+ +[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 +[circleci-url]: https://circleci.com/gh/nestjs/nest + +

A progressive Node.js framework for building efficient and scalable server-side applications.

+

+NPM Version +Package License +NPM Downloads +CircleCI +Discord +Backers on Open Collective +Sponsors on Open Collective + Donate us + Support us + Follow us on Twitter +

+ + +## Description + +[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. + +## Project setup + +```bash +$ pnpm install +``` + +## Compile and run the project + +```bash +# development +$ pnpm run start + +# watch mode +$ pnpm run start:dev + +# production mode +$ pnpm run start:prod +``` + +## Run tests + +```bash +# unit tests +$ pnpm run test + +# e2e tests +$ pnpm run test:e2e + +# test coverage +$ pnpm run test:cov +``` + +## Deployment + +When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information. + +If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps: + +```bash +$ pnpm install -g @nestjs/mau +$ mau deploy +``` + +With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure. + +## Resources + +Check out a few resources that may come in handy when working with NestJS: + +- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework. +- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy). +- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/). +- Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks. +- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com). +- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com). +- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs). +- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com). + +## Support + +Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). + +## Stay in touch + +- Author - [Kamil MyΕ›liwiec](https://twitter.com/kammysliwiec) +- Website - [https://nestjs.com](https://nestjs.com/) +- Twitter - [@nestframework](https://twitter.com/nestframework) + +## License + +Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE). diff --git a/apps/backend/docs/README.md b/apps/backend/docs/README.md new file mode 100644 index 0000000..da9e386 --- /dev/null +++ b/apps/backend/docs/README.md @@ -0,0 +1,7 @@ +# Extra Documentation + +This folder contains extra documentation for the project such us project structure, configuration, etc. + +## Resources + +- [NestJS Documentation](https://docs.nestjs.com/) - Official NestJS documentation diff --git a/apps/backend/eslint.config.mjs b/apps/backend/eslint.config.mjs new file mode 100644 index 0000000..786418b --- /dev/null +++ b/apps/backend/eslint.config.mjs @@ -0,0 +1,34 @@ +// @ts-check +import eslint from '@eslint/js'; +import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; +import globals from 'globals'; +import tseslint from 'typescript-eslint'; + +export default [ + { + ignores: ['eslint.config.mjs'], + }, + eslint.configs.recommended, + ...tseslint.configs.recommendedTypeChecked, + eslintPluginPrettierRecommended, + { + languageOptions: { + globals: { + ...globals.node, + ...globals.jest, + }, + sourceType: 'commonjs', + parserOptions: { + projectService: true, + tsconfigRootDir: import.meta.dirname, + }, + }, + }, + { + rules: { + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-floating-promises': 'warn', + '@typescript-eslint/no-unsafe-argument': 'warn', + }, + }, +]; diff --git a/apps/backend/jest.config.js b/apps/backend/jest.config.js new file mode 100644 index 0000000..3b45711 --- /dev/null +++ b/apps/backend/jest.config.js @@ -0,0 +1,11 @@ +export default { + moduleFileExtensions: ['js', 'json', 'ts'], + rootDir: 'src', + testRegex: '.*\\.spec\\.ts$', + transform: { + '^.+\\.(t|j)s$': 'ts-jest', + }, + collectCoverageFrom: ['**/*.(t|j)s'], + coverageDirectory: '../coverage', + testEnvironment: 'node', +}; 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..372f890 --- /dev/null +++ b/apps/backend/package.json @@ -0,0 +1,73 @@ +{ + "name": "backend", + "version": "0.0.1", + "description": "", + "author": "", + "private": true, + "license": "UNLICENSED", + "scripts": { + "build": "nest build", + "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", + "start": "nest start", + "start:dev": "nest start --watch", + "start:debug": "nest start --debug --watch", + "start:prod": "node dist/main", + "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", + "test": "jest", + "test:watch": "jest --watch", + "test:cov": "jest --coverage", + "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", + "test:e2e": "jest --config ./test/jest-e2e.json" + }, + "dependencies": { + "@nestjs/common": "^11.0.1", + "@nestjs/core": "^11.0.1", + "@nestjs/platform-express": "^11.0.1", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.1" + }, + "devDependencies": { + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "^9.33.0", + "@nestjs/cli": "^11.0.0", + "@nestjs/schematics": "^11.0.0", + "@nestjs/testing": "^11.0.1", + "@types/express": "^5.0.0", + "@types/jest": "^30.0.0", + "@types/node": "^22.10.7", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "^8.42.0", + "@typescript-eslint/parser": "^8.42.0", + "eslint": "^9.18.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-prettier": "^5.2.2", + "globals": "^16.0.0", + "jest": "^30.0.0", + "prettier": "^3.4.2", + "source-map-support": "^0.5.21", + "supertest": "^7.0.0", + "ts-jest": "^29.2.5", + "ts-loader": "^9.5.2", + "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.7.3", + "typescript-eslint": "^8.39.1" + }, + "jest": { + "moduleFileExtensions": [ + "js", + "json", + "ts" + ], + "rootDir": "src", + "testRegex": ".*\\.spec\\.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + }, + "collectCoverageFrom": [ + "**/*.(t|j)s" + ], + "coverageDirectory": "../coverage", + "testEnvironment": "node" + } +} diff --git a/apps/backend/src/app.controller.spec.ts b/apps/backend/src/app.controller.spec.ts new file mode 100644 index 0000000..d22f389 --- /dev/null +++ b/apps/backend/src/app.controller.spec.ts @@ -0,0 +1,22 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { AppController } from './app.controller'; +import { AppService } from './app.service'; + +describe('AppController', () => { + let appController: AppController; + + beforeEach(async () => { + const app: TestingModule = await Test.createTestingModule({ + controllers: [AppController], + providers: [AppService], + }).compile(); + + appController = app.get(AppController); + }); + + describe('root', () => { + it('should return "Hello World!"', () => { + expect(appController.getHello()).toBe('Hello World!'); + }); + }); +}); diff --git a/apps/backend/src/app.controller.ts b/apps/backend/src/app.controller.ts new file mode 100644 index 0000000..cce879e --- /dev/null +++ b/apps/backend/src/app.controller.ts @@ -0,0 +1,12 @@ +import { Controller, Get } from '@nestjs/common'; +import { AppService } from './app.service'; + +@Controller() +export class AppController { + constructor(private readonly appService: AppService) {} + + @Get() + getHello(): string { + return this.appService.getHello(); + } +} diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts new file mode 100644 index 0000000..8662803 --- /dev/null +++ b/apps/backend/src/app.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { AppController } from './app.controller'; +import { AppService } from './app.service'; + +@Module({ + imports: [], + controllers: [AppController], + providers: [AppService], +}) +export class AppModule {} diff --git a/apps/backend/src/app.service.ts b/apps/backend/src/app.service.ts new file mode 100644 index 0000000..927d7cc --- /dev/null +++ b/apps/backend/src/app.service.ts @@ -0,0 +1,8 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class AppService { + getHello(): string { + return 'Hello World!'; + } +} diff --git a/apps/backend/src/main.ts b/apps/backend/src/main.ts new file mode 100644 index 0000000..7d0328d --- /dev/null +++ b/apps/backend/src/main.ts @@ -0,0 +1,11 @@ +import { NestFactory } from '@nestjs/core'; +import { AppModule } from './app.module'; + +async function bootstrap() { + const app = await NestFactory.create(AppModule); + await app.listen(process.env.PORT ?? 3000); +} + +bootstrap().catch((err) => { + console.error('Error during bootstrap:', err); +}); diff --git a/apps/backend/test/app.e2e-spec.ts b/apps/backend/test/app.e2e-spec.ts new file mode 100644 index 0000000..ce6ab9f --- /dev/null +++ b/apps/backend/test/app.e2e-spec.ts @@ -0,0 +1,23 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication } from '@nestjs/common'; +// import * as request from 'supertest'; +import { App } from 'supertest/types'; +import { AppModule } from './../src/app.module'; + +describe('AppController (e2e)', () => { + let app: INestApplication; + + beforeEach(async () => { + const moduleFixture: TestingModule = await Test.createTestingModule({ + imports: [AppModule], + }).compile(); + + app = moduleFixture.createNestApplication(); + await app.init(); + }); + + it('/ (GET)', () => { + // return request(app.getHttpServer()).get('/').expect(200).expect('Hello World!'); + return true; + }); +}); diff --git a/apps/backend/test/jest-e2e.json b/apps/backend/test/jest-e2e.json new file mode 100644 index 0000000..e9d912f --- /dev/null +++ b/apps/backend/test/jest-e2e.json @@ -0,0 +1,9 @@ +{ + "moduleFileExtensions": ["js", "json", "ts"], + "rootDir": ".", + "testEnvironment": "node", + "testRegex": ".e2e-spec.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + } +} diff --git a/apps/backend/tsconfig.build.json b/apps/backend/tsconfig.build.json new file mode 100644 index 0000000..09887d3 --- /dev/null +++ b/apps/backend/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "dist", "*coverage", "test", "logs", "scripts", "tools", "**/*spec.ts"] +} diff --git a/apps/backend/tsconfig.json b/apps/backend/tsconfig.json new file mode 100644 index 0000000..d9aad43 --- /dev/null +++ b/apps/backend/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "useDefineForClassFields": false, + "target": "ES2019", + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./", + "skipLibCheck": true, + "allowJs": false, + "esModuleInterop": true, + "moduleResolution": "node", + "resolveJsonModule": true + }, + "include": ["src/**/*", "test/**/*", ".prettierrc.js"], + "exclude": ["node_modules", "dist", "*coverage", "logs", "scripts"] +} diff --git a/apps/frontend/.dockerignore b/apps/frontend/.dockerignore new file mode 100644 index 0000000..ae1db91 --- /dev/null +++ b/apps/frontend/.dockerignore @@ -0,0 +1,5 @@ +node_modules +.git +build +dist +tools diff --git a/apps/frontend/.editorconfig b/apps/frontend/.editorconfig new file mode 100644 index 0000000..f1cc3ad --- /dev/null +++ b/apps/frontend/.editorconfig @@ -0,0 +1,15 @@ +# http://editorconfig.org + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +insert_final_newline = false +trim_trailing_whitespace = false diff --git a/apps/frontend/.env.example b/apps/frontend/.env.example new file mode 100644 index 0000000..e69de29 diff --git a/apps/frontend/.github/copilot-instructions.md b/apps/frontend/.github/copilot-instructions.md new file mode 100644 index 0000000..c907a85 --- /dev/null +++ b/apps/frontend/.github/copilot-instructions.md @@ -0,0 +1,71 @@ +# GitHub Copilot Instructions for React Vite Project + +## Core Guidelines + +1. **Check Documentation First** + - Always reference the `docs/` folder for technology-specific guides and patterns + - Follow the README.md for setup, testing, and development instructions + - Consult official documentation when uncertain + +2. **Code Quality** + - Run `npm run format` to format code automatically + - Run `npm run lint:fix` to fix linting issues + - Keep code clean, typed, and well-structured + - Use TypeScript properly and avoid `any` types + +3. **Project Structure** + - Follow the established Feature-Based Architecture + - Check `docs/PROJECT_STRUCTURE.md` for organization patterns + - Keep features self-contained and modular + - Place components in appropriate feature directories + +4. **Development Workflow** + - Test changes using the commands in README.md + - Follow the project's established patterns and conventions + - Reference existing code for consistency + - Use Vite's development server and HMR effectively + +5. **Best Practices** + - Write clean, readable, and maintainable code + - Use proper error handling and validation + - Follow React and TypeScript best practices + - Implement proper loading and error states + - Optimize for performance with React.memo and useMemo when needed + +## When Suggesting Code + +1. **Component Creation** + - Check if similar components exist in the codebase + - Look for relevant guides in the `docs/` folder + - Follow the established component patterns + - Use TypeScript interfaces for props + - Include proper error boundaries when appropriate + +2. **State Management** + - Reference `docs/` for state management patterns used in the project + - Use React hooks appropriately (useState, useEffect, useContext) + - Follow established patterns for global state if configured + +3. **Styling** + - Check `docs/` for styling approach used in the project + - Follow established CSS/styling patterns + - Use consistent naming conventions + - Implement responsive design patterns + +4. **Testing** + - Suggest appropriate tests if testing is configured + - Follow testing patterns established in the project + - Reference testing guides in `docs/` folder + +5. **Performance** + - Reference `docs/PERFORMANCE.md` for optimization guidelines + - Suggest lazy loading for route components + - Recommend proper bundle splitting techniques + +## React Vite Specific + +- Leverage Vite's fast development server and build optimizations +- Use ES modules and modern JavaScript features +- Take advantage of Vite's plugin ecosystem +- Follow Vite's file naming conventions for assets +- Use dynamic imports for code splitting diff --git a/apps/frontend/.gitignore b/apps/frontend/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/apps/frontend/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/apps/frontend/.prettierrc.js b/apps/frontend/.prettierrc.js new file mode 100644 index 0000000..a2766c1 --- /dev/null +++ b/apps/frontend/.prettierrc.js @@ -0,0 +1,7 @@ +export default { + semi: true, + trailingComma: 'all', + singleQuote: true, + printWidth: 120, + tabWidth: 2, +}; diff --git a/apps/frontend/Dockerfile b/apps/frontend/Dockerfile new file mode 100644 index 0000000..c498b00 --- /dev/null +++ b/apps/frontend/Dockerfile @@ -0,0 +1,13 @@ +FROM node:20-alpine + +WORKDIR /app + +COPY package*.json ./ + +RUN npm install + +COPY . . + +EXPOSE 5173 + +CMD ["npm", "run", "dev"] diff --git a/apps/frontend/README.md b/apps/frontend/README.md new file mode 100644 index 0000000..88a8952 --- /dev/null +++ b/apps/frontend/README.md @@ -0,0 +1,69 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules: + +```js +export default tseslint.config([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + + // Remove tseslint.configs.recommended and replace with this + ...tseslint.configs.recommendedTypeChecked, + // Alternatively, use this for stricter rules + ...tseslint.configs.strictTypeChecked, + // Optionally, add this for stylistic rules + ...tseslint.configs.stylisticTypeChecked, + + // Other configs... + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]); +``` + +You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules: + +```js +// eslint.config.js +import reactX from 'eslint-plugin-react-x'; +import reactDom from 'eslint-plugin-react-dom'; + +export default tseslint.config([ + globalIgnores(['dist']), + { + files: ['**/*.{ts,tsx}'], + extends: [ + // Other configs... + // Enable lint rules for React + reactX.configs['recommended-typescript'], + // Enable lint rules for React DOM + reactDom.configs.recommended, + ], + languageOptions: { + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + // other options... + }, + }, +]); +``` diff --git a/apps/frontend/components.json b/apps/frontend/components.json new file mode 100644 index 0000000..2b0833f --- /dev/null +++ b/apps/frontend/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/index.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} +} diff --git a/apps/frontend/docs/COMPONENTS_AND_STYLING.md b/apps/frontend/docs/COMPONENTS_AND_STYLING.md new file mode 100644 index 0000000..983fe78 --- /dev/null +++ b/apps/frontend/docs/COMPONENTS_AND_STYLING.md @@ -0,0 +1,89 @@ +# 🧱 Components And Styling + +## Components Best Practices + +### Colocate things as close as possible to where it's being used + +Keep components, functions, styles, state, etc. as close as possible to the component where it's being used. This will not only make your codebase more readable and easier to understand but it will also improve your application performance since it will reduce redundant re-renders on state updates. + +### Avoid large components with nested rendering functions + +Do not add multiple rendering functions inside your application, this gets out of control pretty quickly. What you should do instead is if there is a piece of UI that can be considered as a unit, is to extract it in a separate component. + +```javascript +// this is very difficult to maintain as soon as the component starts growing +function Component() { + function renderItems() { + return
    ...
; + } + return
{renderItems()}
; +} + +// extract it in a separate component +function Items() { + return
    ...
; +} + +function Component() { + return ( +
+ +
+ ); +} +``` + +### Stay consistent + +### Limit the number of props a component is accepting as input + +If your component is accepting too many props you might consider splitting it into multiple components or use the composition technique via children or slots. + +### Abstract shared components into a component library + +For larger projects, it is a good idea to build abstractions around all the shared components. It makes the application more consistent and easier to maintain. Identify repetitions before creating the components to avoid wrong abstractions. + +It is a good idea to wrap 3rd party components as well in order to adapt them to the application's needs. It might be easier to make the underlying changes in the future without affecting the application's functionality. + +## Component libraries + +Every project requires some UI components such as modals, tabs, sidebars, menus, etc. Instead of building those from scratch, you might want to use some of the existing, battle-tested component libraries. + +### Fully featured component libraries + +These component libraries come with their components fully styled. + +- [Chakra UI](https://chakra-ui.com/) - great library with probably the best developer experience, allows very fast prototyping with decent design defaults. Plenty of components that are very customizable and flexible with accessibility already configured out of the box. + +- [AntD](https://ant.design/) - another great component library that has a lot of different components. Best suitable for creating admin dashboards. However, it might be a bit difficult to change the styles in order to adapt them to a custom design. + +- [MUI](https://mui.com/) - the most popular component library for React. Has a lot of different components. Can be used as a styled solution by implementing Material Design or as unstyled headless component library. + +### Headless component libraries + +These component libraries come with their components unstyled. If you have a specific design system to implement, it might be easier and better solution to go with headless components that come unstyled than to adapt a styled components library such as Material UI to your needs. Some good options are: + +- [Reakit](https://reakit.io/) +- [Headless UI](https://headlessui.dev/) +- [Radix UI](https://www.radix-ui.com/) +- [react-aria](https://react-spectrum.adobe.com/react-aria/) + +## Styling Solutions + +There are multiple ways to style a react application. Some good options are: + +- [tailwind](https://tailwindcss.com/) +- [styled-components](https://styled-components.com/) +- [emotion](https://emotion.sh/docs/introduction) +- [stitches](https://stitches.dev/) +- [vanilla-extract](https://github.com/seek-oss/vanilla-extract) +- [CSS modules](https://github.com/css-modules/css-modules) +- [linaria](https://github.com/callstack/linaria) + +## Good combinations + +Some good combinations of component library + styling + +- [Chakra UI](https://chakra-ui.com/) + [emotion](https://emotion.sh/docs/introduction) - The best choice for most applications +- [Headless UI](https://headlessui.dev/) + [tailwind](https://tailwindcss.com/) +- [Radix UI](https://www.radix-ui.com/) + [stitches](https://stitches.dev/) diff --git a/apps/frontend/docs/PERFORMANCE.md b/apps/frontend/docs/PERFORMANCE.md new file mode 100644 index 0000000..94e5e4e --- /dev/null +++ b/apps/frontend/docs/PERFORMANCE.md @@ -0,0 +1,43 @@ +# πŸš„ Performance + +## Code Splitting + +Code splitting is a technique of splitting production JavaScript into smaller files, thus allowing the application to be only partially downloaded. Any unused code will not be downloaded until it is required by the application. + +Most of the time code splitting should be done on the routes level, but can also be used for other lazy loaded parts of application. + +Do not code split everything as it might even worsen your application's performance. + +## Component and state optimizations + +- Do not put everything in a single state. That might trigger unnecessary re-renders. Instead split the global state into multiple stores according to where it is being used. + +- Keep the state as close as possible to where it is being used. This will prevent re-rendering components that do not depend on the updated state. + +- If you have a piece of state that is initialized by an expensive computation, use the state initializer function instead of executing it directly because the expensive function will be run only once as it is supposed to. e.g: + +```javascript +import { useState } from 'react'; + +// instead of this which would be executed on every re-render: +const [state, setState] = useState(myExpensiveFn()); + +// prefer this which is executed only once: +const [state, setState] = useState(() => myExpensiveFn()); +``` + +- If you develop an application that requires the state to track many elements at once, you might consider state management libraries with atomic updates such as [recoil](https://recoiljs.org/) or [jotai](https://jotai.pmnd.rs/). + +- If your application is expected to have frequent updates that might affect performance, consider switching from runtime styling solutions ([Chakra UI](https://chakra-ui.com/), [emotion](https://emotion.sh/docs/introduction), [styled-components](https://styled-components.com/) that generate styles during runtime) to zero runtime styling solutions ([tailwind](https://tailwindcss.com/), [linaria](https://github.com/callstack/linaria), [vanilla-extract](https://github.com/seek-oss/vanilla-extract), [CSS modules](https://github.com/css-modules/css-modules) which generate styles during build time). + +## Image optimizations + +Consider lazy loading images that are not in the viewport. + +Use modern image formats such as WEBP for faster image loading. + +Use `srcset` to load the most optimal image for the clients screen size. + +## Web vitals + +Since Google started taking web vitals in account when indexing websites, you should keep an eye on web vitals scores from [Lighthouse](https://web.dev/measure/) and [Pagespeed Insights](https://pagespeed.web.dev/). diff --git a/apps/frontend/docs/PROJECT_CONFIGURATION.md b/apps/frontend/docs/PROJECT_CONFIGURATION.md new file mode 100644 index 0000000..a34342b --- /dev/null +++ b/apps/frontend/docs/PROJECT_CONFIGURATION.md @@ -0,0 +1,55 @@ +# βš™οΈ Project Configuration + +The application has been bootstrapped using [create-awesome-node-app](https://www.npmjs.com/package/create-awesome-node-app) for simplicity reasons. It allows us to create applications quickly without dealing with a complex tooling setup such as bundling, transpiling etc. + +You should always configure and use the following tools: + +## ESLint + +ESLint is a linting tool for JavaScript. By providing specific configuration defined in the`eslint.config.mjs` file it prevents developers from making silly mistakes in their code and enforces consistency in the codebase. + +[ESLint Configuration](../eslint.config.mjs) + +## Prettier + +This is a great tool for formatting code. It enforces a consistent code style across your entire codebase. By utilizing the "format on save" feature in your IDE you can automatically format the code based on the configuration provided in the `.prettierrc` file. It will also give you good feedback when something is wrong with the code. If the auto-format doesn't work, something is wrong with the code. + +[Prettier Configuration](../.prettierrc.js) + +## TypeScript + +ESLint is great for catching some of the bugs related to the language, but since JavaScript is a dynamic language ESLint cannot check data that run through the applications, which can lead to bugs, especially on larger projects. That is why TypeScript should be used. It is very useful during large refactors because it reports any issues you might miss otherwise. When refactoring, change the type declaration first, then fix all the TypeScript errors throughout the project and you are done. One thing you should keep in mind is that TypeScript does not protect your application from failing during runtime, it only does type checking during build time, but it increases development confidence drastically anyways. Here is a [great resource on using TypeScript with React](https://react-typescript-cheatsheet.netlify.app/). + +## Husky + +Husky is a tool for executing git hooks. Use Husky to run your code validations before every commit, thus making sure the code is in the best shape possible at any point of time and no faulty commits get into the repo. It can run linting, code formatting and type checking, etc. before it allows pushing the code. You can check how to configure it [here](https://typicode.github.io/husky/#/?id=usage). + +## Absolute imports + +Absolute imports should always be configured and used because it makes it easier to move files around and avoid messy import paths such as `../../../Component`. Wherever you move the file, all the imports will remain intact. Here is how to configure it: + +For JavaScript (`jsconfig.json`) projects: + +```json +"compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +``` + +For TypeScript (`tsconfig.json`) projects: + +```json +"compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +``` + +[Paths Configuration](../tsconfig.json) + +It is also possible to define multiple paths for various folders(such as `@/components`, `@/hooks`, etc.), but using `@/*` works very well because it is short enough so there is no need to configure multiple paths and it differs from other dependency modules so there is no confusion in what comes from `node_modules` and what is our source folder. That means that anything in the `src` folder can be accessed via `@`, e.g some file that lives in `src/components/MyComponent` can be accessed using `@/components/MyComponents`. diff --git a/apps/frontend/docs/PROJECT_STRUCTURE.md b/apps/frontend/docs/PROJECT_STRUCTURE.md new file mode 100644 index 0000000..e9d0d90 --- /dev/null +++ b/apps/frontend/docs/PROJECT_STRUCTURE.md @@ -0,0 +1,126 @@ +# πŸ—„οΈ Project Structure + +This project follows a Feature-Based Architecture, inspired by the principles of Screaming Architecture and Domain-Driven Design (DDD). The main goal is to organize code around business capabilities rather than technical concerns, making the codebase more maintainable and scalable. + +## Architecture Overview + +The codebase is organized into two main categories: + +1. **Shared Infrastructure** (`src/` root level) +2. **Feature Modules** (`src/features/`) + +### Shared Infrastructure + +The root level of `src/` contains shared resources used across multiple features: + +```sh +src +| ++-- components # shared components used across the entire application +| ++-- features # feature-based modules (MOST IMPORTANT!) +| ++-- hooks # shared hooks used across the entire application +| ++-- layouts # shared layouts used across the entire application +| ++-- libs # shared libs used across the entire application +| ++-- pages # shared pages used across the entire application +| ++-- providers # all of the application providers +| ++-- routes # all of the application routes +| ++-- services # shared services used across the entire application +| ++-- store # global state stores +| ++-- theme # shared theme used across the entire application +| ++-- utils # shared helpers used across the entire application +``` + +### Feature Modules + +Each feature is a self-contained module that encapsulates all the code related to a specific business capability. This follows the principles of: + +- **High Cohesion**: All related code is kept together +- **Low Coupling**: Features interact through well-defined interfaces +- **Domain-Driven Design**: Code organization reflects business capabilities +- **Screaming Architecture**: The structure "screams" the intent of the application + +A feature module structure: + +```sh +src/features/awesome-feature +| ++-- assets # assets used only in this feature +| ++-- components # components used only in this feature +| ++-- hooks # hooks used only in this feature +| ++-- providers # providers used only in this feature +| ++-- services # services used only in this feature +| ++-- store # stores used only in this feature +| ++-- theme # theme used only in this feature +| ++-- utils # helpers used only in this feature +| ++-- index.ts # public API of the feature +``` + +## Key Principles + +1. **Feature Encapsulation** + - Each feature is a self-contained module + - Features should not depend on the internal structure of other features + - All feature exports should go through the `index.ts` file + +2. **Public API** + - Features expose their functionality through a public API (`index.ts`) + - Other parts of the application should only import from the feature's root: + + ```typescript + // βœ… Good + import { AwesomeComponent } from '@/features/awesome-feature'; + + // ❌ Bad + import { AwesomeComponent } from '@/features/awesome-feature/components/AwesomeComponent'; + ``` + +3. **Import Rules** + To enforce these principles, you can add the following ESLint rule: + + ```js + { + rules: { + 'no-restricted-imports': [ + 'error', + { + patterns: ['@/features/*/*'], + }, + ], + } + } + ``` + +## Benefits + +1. **Maintainability**: Changes to a feature are isolated and don't affect other parts of the application +2. **Scalability**: New features can be added without modifying existing code +3. **Clarity**: The codebase structure clearly communicates the application's business capabilities +4. **Reusability**: Features can be reused across different parts of the application +5. **Testability**: Features can be tested in isolation + +## Best Practices + +1. Keep features focused on a single business capability +2. Minimize dependencies between features +3. Use the shared infrastructure for common functionality +4. Document the public API of each feature +5. Keep feature-specific code within the feature module diff --git a/apps/frontend/docs/README.md b/apps/frontend/docs/README.md new file mode 100644 index 0000000..796b82f --- /dev/null +++ b/apps/frontend/docs/README.md @@ -0,0 +1,11 @@ +# Extra Documentation + +This folder contains extra documentation for the project such us project structure, configuration, etc. + +## Resources + +- [Project Structure](./PROJECT_STRUCTURE.md) +- [Project Configuration](./PROJECT_CONFIGURATION.md) +- [Components and Styling](./COMPONENTS_AND_STYLING.md) +- [Performance recommendations](./PERFORMANCE.md) +- [State Management recommendations](./STATE_MANAGEMENT.md) diff --git a/apps/frontend/docs/STATE_MANAGEMENT.md b/apps/frontend/docs/STATE_MANAGEMENT.md new file mode 100644 index 0000000..f73580c --- /dev/null +++ b/apps/frontend/docs/STATE_MANAGEMENT.md @@ -0,0 +1,40 @@ +# πŸ—ƒοΈ State Management + +There is no need to keep all of your state in a single centralized store. There are different needs for different types of state that can be split into several types: + +## Component State + +This is the state that only a component needs, and it is not meant to be shared anywhere else. But you can pass it as prop to children components if needed. Most of the time, you want to start from here and lift the state up if needed elsewhere. For this type of state, you will usually need: + +- [useState](https://reactjs.org/docs/hooks-reference.html#usestate) - for simpler states that are independent +- [useReducer](https://reactjs.org/docs/hooks-reference.html#usereducer) - for more complex states where on a single action you want to update several pieces of state + +## Application State + +This is the state that controls interactive parts of an application. Opening modals, notifications, changing color mode, etc. For best performance and maintainability, keep the state as close as possible to the components that are using it. Don't make everything global out of the box. + +Our recommendation is to use any of the following state management libraries: + +- [jotai](https://github.com/pmndrs/jotai) +- [recoil](https://recoiljs.org/) +- [zustand](https://github.com/pmndrs/zustand) + +## Server Cache State + +This is the state that comes from the server which is being cached on the client for further usage. It is possible to store remote data inside a state management store such as redux, but there are better solutions for that. + +Our recommendation is: + +- [react-query](https://react-query.tanstack.com/) + +## Form State + +This is a state that tracks users inputs in a form. + +Forms in React can be [controlled](https://reactjs.org/docs/forms.html#controlled-components) and [uncontrolled](https://reactjs.org/docs/uncontrolled-components.html). + +Depending on the application needs, they might be pretty complex with many different fields which require validation. + +Although it is possible to build any form using only React, there are pretty good solutions out there that help with handling forms such as: + +- [React Hook Form](https://react-hook-form.com/) diff --git a/apps/frontend/eslint.config.mjs b/apps/frontend/eslint.config.mjs new file mode 100644 index 0000000..9f966cb --- /dev/null +++ b/apps/frontend/eslint.config.mjs @@ -0,0 +1,60 @@ +import globals from 'globals'; +import pluginJs from '@eslint/js'; +import tseslint from 'typescript-eslint'; +import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; +import jsxA11yPlugin from 'eslint-plugin-jsx-a11y'; +import reactX from 'eslint-plugin-react-x'; +import reactDom from 'eslint-plugin-react-dom'; + +export default [ + { + files: ['**/*.{js,mjs,cjs,ts,tsx}'], + }, + { + ignores: [ + 'node_modules', + 'coverage', + 'dist', + 'dev-dist', + 'public', + '__mocks__', + 'src/theme', + 'tools', + '*.d.ts', + 'postcss.config.js', + ], + }, + { + languageOptions: { + globals: { + ...globals.browser, + ...globals.commonjs, + ...globals.node, + ...globals.es2020, + }, + parserOptions: { + tsconfigRootDir: import.meta.dirname, + }, + }, + }, + pluginJs.configs.recommended, + ...tseslint.configs.recommended, + reactX.configs['recommended-typescript'], + reactDom.configs.recommended, + eslintPluginPrettierRecommended, + jsxA11yPlugin.flatConfigs.recommended, + { + rules: { + 'react/prop-types': 'off', + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + // Prevent direct imports from feature subdirectories + 'no-restricted-imports': [ + 'error', + { + patterns: ['@/features/*/*'], + }, + ], + }, + }, +]; diff --git a/apps/frontend/index.html b/apps/frontend/index.html new file mode 100644 index 0000000..e4b78ea --- /dev/null +++ b/apps/frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/apps/frontend/package.json b/apps/frontend/package.json new file mode 100644 index 0000000..a2c8183 --- /dev/null +++ b/apps/frontend/package.json @@ -0,0 +1,42 @@ +{ + "name": "frontend", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite --host 0.0.0.0", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@tailwindcss/vite": "^4.1.13", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide": "^0.542.0", + "lucide-react": "^0.542.0", + "react": "^19.1.1", + "react-dom": "^19.1.1", + "tailwind-merge": "^3.3.1", + "tailwindcss": "^4.1.13" + }, + "devDependencies": { + "@eslint/js": "^9.33.0", + "@types/node": "^22.18.1", + "@types/react": "^19.1.10", + "@types/react-dom": "^19.1.7", + "@vitejs/plugin-react": "^5.0.0", + "eslint": "^9.33.0", + "eslint-plugin-jsx-a11y": "^6.10.2", + "eslint-plugin-prettier": "^5.5.4", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "eslint-plugin-react-dom": "^1.53.0", + "eslint-plugin-react-x": "^1.53.0", + "globals": "^16.3.0", + "tw-animate-css": "^1.3.8", + "typescript": "~5.8.3", + "typescript-eslint": "^8.39.1", + "vite": "^7.1.2" + } +} diff --git a/apps/frontend/public/vite.svg b/apps/frontend/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/apps/frontend/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/frontend/src/App.css b/apps/frontend/src/App.css new file mode 100644 index 0000000..b9d355d --- /dev/null +++ b/apps/frontend/src/App.css @@ -0,0 +1,42 @@ +#root { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.react:hover { + filter: drop-shadow(0 0 2em #61dafbaa); +} + +@keyframes logo-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +@media (prefers-reduced-motion: no-preference) { + a:nth-of-type(2) .logo { + animation: logo-spin infinite 20s linear; + } +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} diff --git a/apps/frontend/src/App.tsx b/apps/frontend/src/App.tsx new file mode 100644 index 0000000..3d37e1b --- /dev/null +++ b/apps/frontend/src/App.tsx @@ -0,0 +1,31 @@ +import { useState } from 'react'; +import reactLogo from './assets/react.svg'; +import viteLogo from '/vite.svg'; +import './App.css'; + +function App() { + const [count, setCount] = useState(0); + + return ( + <> +
+ + Vite logo + + + React logo + +
+

Vite + React

+
+ +

+ Edit src/App.tsx and save to test HMR +

+
+

Click on the Vite and React logos to learn more

+ + ); +} + +export default App; diff --git a/apps/frontend/src/assets/react.svg b/apps/frontend/src/assets/react.svg new file mode 100644 index 0000000..6c87de9 --- /dev/null +++ b/apps/frontend/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/frontend/src/index.css b/apps/frontend/src/index.css new file mode 100644 index 0000000..b5a5386 --- /dev/null +++ b/apps/frontend/src/index.css @@ -0,0 +1,186 @@ +@import "tailwindcss"; +@import "tw-animate-css"; + +@custom-variant dark (&:is(.dark *)); + +:root { + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} + +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/apps/frontend/src/lib/utils.ts b/apps/frontend/src/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/apps/frontend/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/apps/frontend/src/main.tsx b/apps/frontend/src/main.tsx new file mode 100644 index 0000000..cc14d83 --- /dev/null +++ b/apps/frontend/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import './index.css'; +import App from './App'; + +createRoot(document.getElementById('root')!).render( + + + , +); diff --git a/apps/frontend/src/vite-env.d.ts b/apps/frontend/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/apps/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/apps/frontend/tsconfig.app.json b/apps/frontend/tsconfig.app.json new file mode 100644 index 0000000..d96f791 --- /dev/null +++ b/apps/frontend/tsconfig.app.json @@ -0,0 +1,35 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2019", + "useDefineForClassFields": true, + "lib": ["ES2019", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + + + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + } + }, + "include": ["src"] +} diff --git a/apps/frontend/tsconfig.json b/apps/frontend/tsconfig.json new file mode 100644 index 0000000..2b78387 --- /dev/null +++ b/apps/frontend/tsconfig.json @@ -0,0 +1,10 @@ +{ + "files": [], + "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }], + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/apps/frontend/tsconfig.node.json b/apps/frontend/tsconfig.node.json new file mode 100644 index 0000000..f85a399 --- /dev/null +++ b/apps/frontend/tsconfig.node.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/apps/frontend/vite.config.ts b/apps/frontend/vite.config.ts new file mode 100644 index 0000000..0e624d1 --- /dev/null +++ b/apps/frontend/vite.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import path from 'path'; +import tailwindcss from '@tailwindcss/vite'; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], + resolve: { + alias: { + '@': path.resolve(__dirname, 'src'), + }, + }, +}); diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..2b6c906 --- /dev/null +++ b/compose.yml @@ -0,0 +1,44 @@ +services: + db: + image: postgres:14-alpine + restart: always + environment: + POSTGRES_USER: user + POSTGRES_PASSWORD: password + POSTGRES_DB: acme_db + volumes: + - postgres_data:/var/lib/postgresql/data + ports: + - "5432:5432" + + backend: + build: + context: ./apps/backend + dockerfile: Dockerfile + command: npm run start:dev + ports: + - "3000:3000" + volumes: + - ./apps/backend:/app + - /app/node_modules + env_file: + - .env + depends_on: + - db + + frontend: + build: + context: ./apps/frontend + dockerfile: Dockerfile + command: npm run dev + ports: + - "5173:5173" + volumes: + - ./apps/frontend:/app + - /app/node_modules + environment: + VITE_BACKEND_URL: http://localhost:3000 + VITE_WS_URL: ws://localhost:3000/graphql + +volumes: + postgres_data: diff --git a/docs/DEVELOPMENT_WORKFLOW.md b/docs/DEVELOPMENT_WORKFLOW.md new file mode 100644 index 0000000..9472019 --- /dev/null +++ b/docs/DEVELOPMENT_WORKFLOW.md @@ -0,0 +1,178 @@ +# Development Workflow + +This document outlines the development workflow and best practices for working with the Turborepo monorepo. + +## Getting Started + +1. **Install Dependencies** + + ```bash + npm install + ``` + +2. **Start Development** + + ```bash + npm run dev + ``` + + This will start all applications in development mode with hot reloading. + +## Available Scripts + +### Root Level Scripts + +| Script | Description | +| -------- | ------------------------------------------ | +| `dev` | Start all applications in development mode | +| `build` | Build all packages and applications | +| `test` | Run tests across all packages | +| `lint` | Run linting across all packages | +| `format` | Format all files with Prettier | +| `clean` | Clean all build artifacts | + +### Package Level Scripts + +Each package in `apps/` and `packages/` can have its own scripts. Common ones include: + +| Script | Description | +| ------- | ------------------------ | +| `dev` | Start development server | +| `build` | Build the package | +| `test` | Run tests | +| `lint` | Run linting | + +## Development Process + +### 1. Creating a New Feature + +1. Create a new branch from `main` + + ```bash + git checkout -b feature/your-feature-name + ``` + +2. Make your changes in the relevant packages +3. Run tests and linting + + ```bash + npm run test + npm run lint + ``` + +4. Create a changeset for versioning + + ```bash + npm run changeset + ``` + +5. Commit your changes + + ```bash + git add . + git commit -m "feat: your feature description" + ``` + +### 2. Working with Dependencies + +- **Adding a new dependency to a package** + + ```bash + cd packages/your-package + npm run add package-name + ``` + +- **Adding a workspace dependency** + + ```bash + cd packages/your-package + npm run add @your-scope/package-name --workspace + ``` + +### 3. Testing Changes + +- Run tests for all packages + + ```bash + npm run test + ``` + +- Run tests for a specific package + + ```bash + npm run test --filter=package-name + ``` + +- Run tests in watch mode + + ```bash + npm run test --watch + ``` + +### 4. Building Packages + +- Build all packages + + ```bash + npm run build + ``` + +- Build a specific package + + ```bash + npm run build --filter=package-name + ``` + +## Best Practices + +1. **Package Organization** + - Keep related code together + - Use clear package names + - Document package dependencies + +2. **Versioning** + - Use changesets for versioning + - Follow semantic versioning + - Keep changelogs up to date + +3. **Testing** + - Write tests for new features + - Maintain test coverage + - Run tests before committing + +4. **Code Quality** + - Follow the established code style + - Run linters before committing + - Keep dependencies up to date + +5. **Documentation** + - Document new features + - Update README files + - Keep API documentation current + +## Troubleshooting + +### Common Issues + +1. **Build Failures** + - Check for circular dependencies + - Verify all dependencies are installed + - Check TypeScript configurations + +2. **Test Failures** + - Check for environment variables + - Verify test setup + - Check for timing issues + +3. **Dependency Issues** + - Clear node_modules: `npm run clean` + - Reinstall dependencies: `npm install` + - Check for version conflicts + +### Getting Help + +If you encounter issues: + +1. Check the [Turborepo documentation](https://turbo.build/repo/docs) +2. Search existing issues +3. Ask in the [Turborepo Discord](https://turbo.build/discord) diff --git a/docs/PROJECT_STRUCTURE.md b/docs/PROJECT_STRUCTURE.md new file mode 100644 index 0000000..e866e32 --- /dev/null +++ b/docs/PROJECT_STRUCTURE.md @@ -0,0 +1,52 @@ +# Project Structure + +This document outlines the structure of the Turborepo monorepo template. + +## Directory Structure + +```txt +root/ +β”œβ”€β”€ apps/ # Application packages +β”‚ β”œβ”€β”€ web/ # Web application +β”‚ └── docs/ # Documentation site +β”œβ”€β”€ package.json # Root package.json +β”œβ”€β”€ turbo.json # Turborepo configuration +└── pnpm-workspace.yaml # PNPM workspace configuration +``` + +## Key Directories + +### `apps/` + +Contains all the applications in the monorepo. Each application is a separate package that can be developed and deployed independently. + +- `web/`: The main web application +- `docs/`: Documentation site (if applicable) + +### Configuration Files + +- `turbo.json`: Defines the pipeline and dependencies between packages +- `pnpm-workspace.yaml`: Configures the PNPM workspace +- `.changeset/`: Configuration for versioning and changelog generation + +## Package Management + +### Adding a New Package + +1. Create a new directory in `apps/` +2. Initialize the package with `package.json` +3. Add the package to the workspace in `pnpm-workspace.yaml` +4. Update `turbo.json` if necessary + +## Development Workflow + +1. Install dependencies: `pnpm install` +2. Start development: `pnpm dev` +3. Build packages: `pnpm build` +4. Run tests: `pnpm test` + +## Best Practices + +1. Use TypeScript for all packages +2. Follow the established directory structure +3. Keep package dependencies up to date diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..4d08e1d --- /dev/null +++ b/docs/README.md @@ -0,0 +1,27 @@ +# Turborepo Documentation + +This folder contains detailed documentation for the Turborepo Starter template. Each document focuses on a specific aspect of the monorepo setup: + +## Core Documentation + +- [Project Structure](./PROJECT_STRUCTURE.md) - Overview of the monorepo architecture and package organization +- [Development Workflow](./DEVELOPMENT_WORKFLOW.md) - Best practices for development in a monorepo + +## Monorepo Resources + +- [Turborepo Documentation](https://turbo.build/repo/docs) +- [PNPM Workspace Documentation](https://pnpm.io/workspaces) + +## Development Tools + +- [TypeScript Documentation](https://www.typescriptlang.org/docs/) +- [ESLint Documentation](https://eslint.org/docs/latest/) +- [Prettier Documentation](https://prettier.io/docs/en/) + +## Getting Help + +If you need additional help or have questions: + +1. Check the [Turborepo GitHub Discussions](https://github.com/vercel/turbo/discussions) +2. Join the [Turborepo Discord](https://turbo.build/discord) +3. Open an issue in this repository diff --git a/package.json b/package.json new file mode 100644 index 0000000..09fb908 --- /dev/null +++ b/package.json @@ -0,0 +1,21 @@ +{ + "name": "test", + "scripts": { + "build": "turbo run build", + "format": "prettier --ignore-path .gitignore -u --write .", + "lint": "turbo run lint", + "lint:fix": "turbo run lint:fix", + "test": "turbo run test", + "type-check": "turbo run type-check" + }, + "version": "0.1.0", + "private": true, + "engines": { + "node": ">=16.16.0" + }, + "workspaces": [ + "packages/*", + "apps/*" + ], + "packageManager": "pnpm@10.13.1" +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..eedc936 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,8542 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: {} + + apps/backend: + dependencies: + '@nestjs/common': + specifier: ^11.0.1 + version: 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': + specifier: ^11.0.1 + version: 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/platform-express': + specifier: ^11.0.1 + version: 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + reflect-metadata: + specifier: ^0.2.2 + version: 0.2.2 + rxjs: + specifier: ^7.8.1 + version: 7.8.2 + devDependencies: + '@eslint/eslintrc': + specifier: ^3.2.0 + version: 3.3.1 + '@eslint/js': + specifier: ^9.33.0 + version: 9.35.0 + '@nestjs/cli': + specifier: ^11.0.0 + version: 11.0.10(@types/node@22.18.1) + '@nestjs/schematics': + specifier: ^11.0.0 + version: 11.0.7(chokidar@4.0.3)(typescript@5.8.3) + '@nestjs/testing': + specifier: ^11.0.1 + version: 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-express@11.1.6) + '@types/express': + specifier: ^5.0.0 + version: 5.0.3 + '@types/jest': + specifier: ^30.0.0 + version: 30.0.0 + '@types/node': + specifier: ^22.10.7 + version: 22.18.1 + '@types/supertest': + specifier: ^6.0.2 + version: 6.0.3 + '@typescript-eslint/eslint-plugin': + specifier: ^8.42.0 + version: 8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/parser': + specifier: ^8.42.0 + version: 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + eslint: + specifier: ^9.18.0 + version: 9.35.0(jiti@2.5.1) + eslint-config-prettier: + specifier: ^10.0.1 + version: 10.1.8(eslint@9.35.0(jiti@2.5.1)) + eslint-plugin-prettier: + specifier: ^5.2.2 + version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1))(prettier@3.6.2) + globals: + specifier: ^16.0.0 + version: 16.3.0 + jest: + specifier: ^30.0.0 + version: 30.1.3(@types/node@22.18.1)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)) + prettier: + specifier: ^3.4.2 + version: 3.6.2 + source-map-support: + specifier: ^0.5.21 + version: 0.5.21 + supertest: + specifier: ^7.0.0 + version: 7.1.4 + ts-jest: + specifier: ^29.2.5 + version: 29.4.1(@babel/core@7.28.4)(@jest/transform@30.1.2)(@jest/types@30.0.5)(babel-jest@30.1.2(@babel/core@7.28.4))(jest-util@30.0.5)(jest@30.1.3(@types/node@22.18.1)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)))(typescript@5.8.3) + ts-loader: + specifier: ^9.5.2 + version: 9.5.4(typescript@5.8.3)(webpack@5.100.2) + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@22.18.1)(typescript@5.8.3) + tsconfig-paths: + specifier: ^4.2.0 + version: 4.2.0 + typescript: + specifier: ^5.7.3 + version: 5.8.3 + typescript-eslint: + specifier: ^8.39.1 + version: 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + + apps/frontend: + dependencies: + '@tailwindcss/vite': + specifier: ^4.1.13 + version: 4.1.13(vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)) + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + lucide: + specifier: ^0.542.0 + version: 0.542.0 + lucide-react: + specifier: ^0.542.0 + version: 0.542.0(react@19.1.1) + react: + specifier: ^19.1.1 + version: 19.1.1 + react-dom: + specifier: ^19.1.1 + version: 19.1.1(react@19.1.1) + tailwind-merge: + specifier: ^3.3.1 + version: 3.3.1 + tailwindcss: + specifier: ^4.1.13 + version: 4.1.13 + devDependencies: + '@eslint/js': + specifier: ^9.33.0 + version: 9.35.0 + '@types/node': + specifier: ^22.18.1 + version: 22.18.1 + '@types/react': + specifier: ^19.1.10 + version: 19.1.12 + '@types/react-dom': + specifier: ^19.1.7 + version: 19.1.9(@types/react@19.1.12) + '@vitejs/plugin-react': + specifier: ^5.0.0 + version: 5.0.2(vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)) + eslint: + specifier: ^9.33.0 + version: 9.35.0(jiti@2.5.1) + eslint-plugin-jsx-a11y: + specifier: ^6.10.2 + version: 6.10.2(eslint@9.35.0(jiti@2.5.1)) + eslint-plugin-prettier: + specifier: ^5.5.4 + version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1))(prettier@3.6.2) + eslint-plugin-react-dom: + specifier: ^1.53.0 + version: 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + eslint-plugin-react-hooks: + specifier: ^5.2.0 + version: 5.2.0(eslint@9.35.0(jiti@2.5.1)) + eslint-plugin-react-refresh: + specifier: ^0.4.20 + version: 0.4.20(eslint@9.35.0(jiti@2.5.1)) + eslint-plugin-react-x: + specifier: ^1.53.0 + version: 1.53.0(eslint@9.35.0(jiti@2.5.1))(ts-api-utils@2.1.0(typescript@5.8.3))(typescript@5.8.3) + globals: + specifier: ^16.3.0 + version: 16.3.0 + tw-animate-css: + specifier: ^1.3.8 + version: 1.3.8 + typescript: + specifier: ~5.8.3 + version: 5.8.3 + typescript-eslint: + specifier: ^8.39.1 + version: 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + vite: + specifier: ^7.1.2 + version: 7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0) + +packages: + + '@angular-devkit/core@19.2.15': + resolution: {integrity: sha512-pU2RZYX6vhd7uLSdLwPnuBcr0mXJSjp3EgOXKsrlQFQZevc+Qs+2JdXgIElnOT/aDqtRtriDmLlSbtdE8n3ZbA==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + chokidar: ^4.0.0 + peerDependenciesMeta: + chokidar: + optional: true + + '@angular-devkit/schematics-cli@19.2.15': + resolution: {integrity: sha512-1ESFmFGMpGQmalDB3t2EtmWDGv6gOFYBMxmHO2f1KI/UDl8UmZnCGL4mD3EWo8Hv0YIsZ9wOH9Q7ZHNYjeSpzg==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + hasBin: true + + '@angular-devkit/schematics@19.2.15': + resolution: {integrity: sha512-kNOJ+3vekJJCQKWihNmxBkarJzNW09kP5a9E1SRNiQVNOUEeSwcRR0qYotM65nx821gNzjjhJXnAZ8OazWldrg==} + engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.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'} + + '@babel/compat-data@7.28.4': + resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.4': + resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.3': + resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.4': + resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.4': + resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.27.1': + resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.27.1': + resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.27.1': + resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.4': + resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.4': + resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@borewit/text-codec@0.1.1': + resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} + + '@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'} + + '@emnapi/core@1.5.0': + resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} + + '@emnapi/runtime@1.5.0': + resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} + + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + + '@esbuild/aix-ppc64@0.25.9': + resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.9': + resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.9': + resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.9': + resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.9': + resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.9': + resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.9': + resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.9': + resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.9': + resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.9': + resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.9': + resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.9': + resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.9': + resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.9': + resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.9': + resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.9': + resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.9': + resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.9': + resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.9': + resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.9': + resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.9': + resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.9': + resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.9': + resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.9': + resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.9': + resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.9': + resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.8.0': + resolution: {integrity: sha512-MJQFqrZgcW0UNYLGOuQpey/oTN59vyWwplvCGZztn1cKz9agZPPYpJB7h2OMmuu7VLqkvEjN8feFZJmxNF9D+Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint-react/ast@1.53.0': + resolution: {integrity: sha512-TyJURQF4IEOLWUQvmCukc6GQsaqzW2ALwY97gy1AaCTR+9CXz12qF84JQydxVmph2LOndPJk1KCrnNkLAvxzIw==} + engines: {node: '>=18.18.0'} + + '@eslint-react/core@1.53.0': + resolution: {integrity: sha512-LP53OVMymLnEqJtmHeCyYMtFjK9Mw4F7lui5VO9YlbELopynPrpeiMPyVScxydLzW/toE7ZpDLTaB8B7Nrfdpw==} + engines: {node: '>=18.18.0'} + + '@eslint-react/eff@1.53.0': + resolution: {integrity: sha512-jlGTpgrLD+txK1ApUg7hX1/Oje2D9Bv/uHtnzdgBT6cI8vpt8EEXXclAxz9NN4insfEu+g5GZB8sQSvtsQCzwQ==} + engines: {node: '>=18.18.0'} + + '@eslint-react/kit@1.53.0': + resolution: {integrity: sha512-1OqcBpLtqsQSTgSBS8lxpoRojj7RLdZ0vBsnHlmWmARJhBV9+dlyu3scPduiohai3zjUdFLfLKvUqZpNeNbZig==} + engines: {node: '>=18.18.0'} + + '@eslint-react/shared@1.53.0': + resolution: {integrity: sha512-8cKjzAJZOmpwoH8KsbyAUpLd3N2Lw6N4TSVZ+W8OnsspOfLhmN9VEyuS442fiHwZ33+mXulVewfpKahFOb9XAA==} + engines: {node: '>=18.18.0'} + + '@eslint-react/var@1.53.0': + resolution: {integrity: sha512-9IKGvSUyVABV07A9IJDa3QMGvpXwlJzb6UegJMW5OxUA5fkKcAqPZPp7fgoLkhqCpN/8l/rwbhdq1PcHxgmFsQ==} + engines: {node: '>=18.18.0'} + + '@eslint/config-array@0.21.0': + resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.3.1': + resolution: {integrity: sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.15.2': + resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.35.0': + resolution: {integrity: sha512-30iXE9whjlILfWobBkNerJo+TXYsgVM5ERQwMcMKCHckHflCmf7wXDAHlARoWnh0s1U72WqlbeyE7iAcCzuCPw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.3.5': + resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@inquirer/checkbox@4.2.2': + resolution: {integrity: sha512-E+KExNurKcUJJdxmjglTl141EwxWyAHplvsYJQgSwXf8qiNWkTxTuCCqmhFEmbIXd4zLaGMfQFJ6WrZ7fSeV3g==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/confirm@5.1.16': + resolution: {integrity: sha512-j1a5VstaK5KQy8Mu8cHmuQvN1Zc62TbLhjJxwHvKPPKEoowSF6h/0UdOpA9DNdWZ+9Inq73+puRq1df6OJ8Sag==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/core@10.2.0': + resolution: {integrity: sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/editor@4.2.18': + resolution: {integrity: sha512-yeQN3AXjCm7+Hmq5L6Dm2wEDeBRdAZuyZ4I7tWSSanbxDzqM0KqzoDbKM7p4ebllAYdoQuPJS6N71/3L281i6w==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/expand@4.0.18': + resolution: {integrity: sha512-xUjteYtavH7HwDMzq4Cn2X4Qsh5NozoDHCJTdoXg9HfZ4w3R6mxV1B9tL7DGJX2eq/zqtsFjhm0/RJIMGlh3ag==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/external-editor@1.0.1': + resolution: {integrity: sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/figures@1.0.13': + resolution: {integrity: sha512-lGPVU3yO9ZNqA7vTYz26jny41lE7yoQansmqdMLBEfqaGsmdg7V3W9mK9Pvb5IL4EVZ9GnSDGMO/cJXud5dMaw==} + engines: {node: '>=18'} + + '@inquirer/input@4.2.2': + resolution: {integrity: sha512-hqOvBZj/MhQCpHUuD3MVq18SSoDNHy7wEnQ8mtvs71K8OPZVXJinOzcvQna33dNYLYE4LkA9BlhAhK6MJcsVbw==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/number@3.0.18': + resolution: {integrity: sha512-7exgBm52WXZRczsydCVftozFTrrwbG5ySE0GqUd2zLNSBXyIucs2Wnm7ZKLe/aUu6NUg9dg7Q80QIHCdZJiY4A==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/password@4.0.18': + resolution: {integrity: sha512-zXvzAGxPQTNk/SbT3carAD4Iqi6A2JS2qtcqQjsL22uvD+JfQzUrDEtPjLL7PLn8zlSNyPdY02IiQjzoL9TStA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/prompts@7.3.2': + resolution: {integrity: sha512-G1ytyOoHh5BphmEBxSwALin3n1KGNYB6yImbICcRQdzXfOGbuJ9Jske/Of5Sebk339NSGGNfUshnzK8YWkTPsQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/prompts@7.8.0': + resolution: {integrity: sha512-JHwGbQ6wjf1dxxnalDYpZwZxUEosT+6CPGD9Zh4sm9WXdtUp9XODCQD3NjSTmu+0OAyxWXNOqf0spjIymJa2Tw==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/rawlist@4.1.6': + resolution: {integrity: sha512-KOZqa3QNr3f0pMnufzL7K+nweFFCCBs6LCXZzXDrVGTyssjLeudn5ySktZYv1XiSqobyHRYYK0c6QsOxJEhXKA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/search@3.1.1': + resolution: {integrity: sha512-TkMUY+A2p2EYVY3GCTItYGvqT6LiLzHBnqsU1rJbrpXUijFfM6zvUx0R4civofVwFCmJZcKqOVwwWAjplKkhxA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/select@4.3.2': + resolution: {integrity: sha512-nwous24r31M+WyDEHV+qckXkepvihxhnyIaod2MG7eCE6G0Zm/HUF6jgN8GXgf4U7AU6SLseKdanY195cwvU6w==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/type@3.0.8': + resolution: {integrity: sha512-lg9Whz8onIHRthWaN1Q9EGLa/0LFJjyM8mEUbL1eTi6yMGvBf8gvyDLtxSXztQsxMvhxxNpJYrwa1YHdq+w4Jw==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@30.1.2': + resolution: {integrity: sha512-BGMAxj8VRmoD0MoA/jo9alMXSRoqW8KPeqOfEo1ncxnRLatTBCpRoOwlwlEMdudp68Q6WSGwYrrLtTGOh8fLzw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/core@30.1.3': + resolution: {integrity: sha512-LIQz7NEDDO1+eyOA2ZmkiAyYvZuo6s1UxD/e2IHldR6D7UYogVq3arTmli07MkENLq6/3JEQjp0mA8rrHHJ8KQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/diff-sequences@30.0.1': + resolution: {integrity: sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/environment@30.1.2': + resolution: {integrity: sha512-N8t1Ytw4/mr9uN28OnVf0SYE2dGhaIxOVYcwsf9IInBKjvofAjbFRvedvBBlyTYk2knbJTiEjEJ2PyyDIBnd9w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/expect-utils@30.1.2': + resolution: {integrity: sha512-HXy1qT/bfdjCv7iC336ExbqqYtZvljrV8odNdso7dWK9bSeHtLlvwWWC3YSybSPL03Gg5rug6WLCZAZFH72m0A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/expect@30.1.2': + resolution: {integrity: sha512-tyaIExOwQRCxPCGNC05lIjWJztDwk2gPDNSDGg1zitXJJ8dC3++G/CRjE5mb2wQsf89+lsgAgqxxNpDLiCViTA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/fake-timers@30.1.2': + resolution: {integrity: sha512-Beljfv9AYkr9K+ETX9tvV61rJTY706BhBUtiaepQHeEGfe0DbpvUA5Z3fomwc5Xkhns6NWrcFDZn+72fLieUnA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/get-type@30.1.0': + resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/globals@30.1.2': + resolution: {integrity: sha512-teNTPZ8yZe3ahbYnvnVRDeOjr+3pu2uiAtNtrEsiMjVPPj+cXd5E/fr8BL7v/T7F31vYdEHrI5cC/2OoO/vM9A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/pattern@30.0.1': + resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/reporters@30.1.3': + resolution: {integrity: sha512-VWEQmJWfXMOrzdFEOyGjUEOuVXllgZsoPtEHZzfdNz18RmzJ5nlR6kp8hDdY8dDS1yGOXAY7DHT+AOHIPSBV0w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@30.0.5': + resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/snapshot-utils@30.1.2': + resolution: {integrity: sha512-vHoMTpimcPSR7OxS2S0V1Cpg8eKDRxucHjoWl5u4RQcnxqQrV3avETiFpl8etn4dqxEGarBeHbIBety/f8mLXw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/source-map@30.0.1': + resolution: {integrity: sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/test-result@30.1.3': + resolution: {integrity: sha512-P9IV8T24D43cNRANPPokn7tZh0FAFnYS2HIfi5vK18CjRkTDR9Y3e1BoEcAJnl4ghZZF4Ecda4M/k41QkvurEQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/test-sequencer@30.1.3': + resolution: {integrity: sha512-82J+hzC0qeQIiiZDThh+YUadvshdBswi5nuyXlEmXzrhw5ZQSRHeQ5LpVMD/xc8B3wPePvs6VMzHnntxL+4E3w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/transform@30.1.2': + resolution: {integrity: sha512-UYYFGifSgfjujf1Cbd3iU/IQoSd6uwsj8XHj5DSDf5ERDcWMdJOPTkHWXj4U+Z/uMagyOQZ6Vne8C4nRIrCxqA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/types@30.0.5': + resolution: {integrity: sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + 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==} + + '@jridgewell/trace-mapping@0.3.30': + resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@lukeed/csprng@1.1.0': + resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} + engines: {node: '>=8'} + + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@nestjs/cli@11.0.10': + resolution: {integrity: sha512-4waDT0yGWANg0pKz4E47+nUrqIJv/UqrZ5wLPkCqc7oMGRMWKAaw1NDZ9rKsaqhqvxb2LfI5+uXOWr4yi94DOQ==} + engines: {node: '>= 20.11'} + hasBin: true + peerDependencies: + '@swc/cli': ^0.1.62 || ^0.3.0 || ^0.4.0 || ^0.5.0 || ^0.6.0 || ^0.7.0 + '@swc/core': ^1.3.62 + peerDependenciesMeta: + '@swc/cli': + optional: true + '@swc/core': + optional: true + + '@nestjs/common@11.1.6': + resolution: {integrity: sha512-krKwLLcFmeuKDqngG2N/RuZHCs2ycsKcxWIDgcm7i1lf3sQ0iG03ci+DsP/r3FcT/eJDFsIHnKtNta2LIi7PzQ==} + peerDependencies: + class-transformer: '>=0.4.1' + class-validator: '>=0.13.2' + reflect-metadata: ^0.1.12 || ^0.2.0 + rxjs: ^7.1.0 + peerDependenciesMeta: + class-transformer: + optional: true + class-validator: + optional: true + + '@nestjs/core@11.1.6': + resolution: {integrity: sha512-siWX7UDgErisW18VTeJA+x+/tpNZrJewjTBsRPF3JVxuWRuAB1kRoiJcxHgln8Lb5UY9NdvklITR84DUEXD0Cg==} + engines: {node: '>= 20'} + peerDependencies: + '@nestjs/common': ^11.0.0 + '@nestjs/microservices': ^11.0.0 + '@nestjs/platform-express': ^11.0.0 + '@nestjs/websockets': ^11.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/platform-express@11.1.6': + resolution: {integrity: sha512-HErwPmKnk+loTq8qzu1up+k7FC6Kqa8x6lJ4cDw77KnTxLzsCaPt+jBvOq6UfICmfqcqCCf3dKXg+aObQp+kIQ==} + peerDependencies: + '@nestjs/common': ^11.0.0 + '@nestjs/core': ^11.0.0 + + '@nestjs/schematics@11.0.7': + resolution: {integrity: sha512-t8dNYYMwEeEsrlwc2jbkfwCfXczq4AeNEgx1KVQuJ6wYibXk0ZbXbPdfp8scnEAaQv1grpncNV5gWgzi7ZwbvQ==} + peerDependencies: + typescript: '>=4.8.2' + + '@nestjs/testing@11.1.6': + resolution: {integrity: sha512-srYzzDNxGvVCe1j0SpTS9/ix75PKt6Sn6iMaH1rpJ6nj2g8vwNrhK0CoJJXvpCYgrnI+2WES2pprYnq8rAMYHA==} + peerDependencies: + '@nestjs/common': ^11.0.0 + '@nestjs/core': ^11.0.0 + '@nestjs/microservices': ^11.0.0 + '@nestjs/platform-express': ^11.0.0 + peerDependenciesMeta: + '@nestjs/microservices': + optional: true + '@nestjs/platform-express': + optional: true + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@nuxt/opencollective@0.4.1': + resolution: {integrity: sha512-GXD3wy50qYbxCJ652bDrDzgMr3NFEkIS374+IgFQKkCvk9yiYcLvX2XDYr7UyQxf4wK0e+yqDYRubZ0DtOxnmQ==} + engines: {node: ^14.18.0 || >=16.10.0, npm: '>=5.10.0'} + hasBin: true + + '@paralleldrive/cuid2@2.2.2': + resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@pkgr/core@0.2.9': + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@rolldown/pluginutils@1.0.0-beta.34': + resolution: {integrity: sha512-LyAREkZHP5pMom7c24meKmJCdhf2hEyvam2q0unr3or9ydwDL+DJ8chTF6Av/RFPb3rH8UFBdMzO5MxTZW97oA==} + + '@rollup/rollup-android-arm-eabi@4.50.1': + resolution: {integrity: sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.50.1': + resolution: {integrity: sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.50.1': + resolution: {integrity: sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.50.1': + resolution: {integrity: sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.50.1': + resolution: {integrity: sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.50.1': + resolution: {integrity: sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.50.1': + resolution: {integrity: sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.50.1': + resolution: {integrity: sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.50.1': + resolution: {integrity: sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.50.1': + resolution: {integrity: sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.50.1': + resolution: {integrity: sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.50.1': + resolution: {integrity: sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.50.1': + resolution: {integrity: sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.50.1': + resolution: {integrity: sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.50.1': + resolution: {integrity: sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.50.1': + resolution: {integrity: sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.50.1': + resolution: {integrity: sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.50.1': + resolution: {integrity: sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.50.1': + resolution: {integrity: sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.50.1': + resolution: {integrity: sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.50.1': + resolution: {integrity: sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==} + cpu: [x64] + os: [win32] + + '@sinclair/typebox@0.34.41': + resolution: {integrity: sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@13.0.5': + resolution: {integrity: sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==} + + '@tailwindcss/node@4.1.13': + resolution: {integrity: sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==} + + '@tailwindcss/oxide-android-arm64@4.1.13': + resolution: {integrity: sha512-BrpTrVYyejbgGo57yc8ieE+D6VT9GOgnNdmh5Sac6+t0m+v+sKQevpFVpwX3pBrM2qKrQwJ0c5eDbtjouY/+ew==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.13': + resolution: {integrity: sha512-YP+Jksc4U0KHcu76UhRDHq9bx4qtBftp9ShK/7UGfq0wpaP96YVnnjFnj3ZFrUAjc5iECzODl/Ts0AN7ZPOANQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.13': + resolution: {integrity: sha512-aAJ3bbwrn/PQHDxCto9sxwQfT30PzyYJFG0u/BWZGeVXi5Hx6uuUOQEI2Fa43qvmUjTRQNZnGqe9t0Zntexeuw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.13': + resolution: {integrity: sha512-Wt8KvASHwSXhKE/dJLCCWcTSVmBj3xhVhp/aF3RpAhGeZ3sVo7+NTfgiN8Vey/Fi8prRClDs6/f0KXPDTZE6nQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13': + resolution: {integrity: sha512-mbVbcAsW3Gkm2MGwA93eLtWrwajz91aXZCNSkGTx/R5eb6KpKD5q8Ueckkh9YNboU8RH7jiv+ol/I7ZyQ9H7Bw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.13': + resolution: {integrity: sha512-wdtfkmpXiwej/yoAkrCP2DNzRXCALq9NVLgLELgLim1QpSfhQM5+ZxQQF8fkOiEpuNoKLp4nKZ6RC4kmeFH0HQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.13': + resolution: {integrity: sha512-hZQrmtLdhyqzXHB7mkXfq0IYbxegaqTmfa1p9MBj72WPoDD3oNOh1Lnxf6xZLY9C3OV6qiCYkO1i/LrzEdW2mg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.13': + resolution: {integrity: sha512-uaZTYWxSXyMWDJZNY1Ul7XkJTCBRFZ5Fo6wtjrgBKzZLoJNrG+WderJwAjPzuNZOnmdrVg260DKwXCFtJ/hWRQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.13': + resolution: {integrity: sha512-oXiPj5mi4Hdn50v5RdnuuIms0PVPI/EG4fxAfFiIKQh5TgQgX7oSuDWntHW7WNIi/yVLAiS+CRGW4RkoGSSgVQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.13': + resolution: {integrity: sha512-+LC2nNtPovtrDwBc/nqnIKYh/W2+R69FA0hgoeOn64BdCX522u19ryLh3Vf3F8W49XBcMIxSe665kwy21FkhvA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.13': + resolution: {integrity: sha512-dziTNeQXtoQ2KBXmrjCxsuPk3F3CQ/yb7ZNZNA+UkNTeiTGgfeh+gH5Pi7mRncVgcPD2xgHvkFCh/MhZWSgyQg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.13': + resolution: {integrity: sha512-3+LKesjXydTkHk5zXX01b5KMzLV1xl2mcktBJkje7rhFUpUlYJy7IMOLqjIRQncLTa1WZZiFY/foAeB5nmaiTw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.13': + resolution: {integrity: sha512-CPgsM1IpGRa880sMbYmG1s4xhAy3xEt1QULgTJGQmZUeNgXFR7s1YxYygmJyBGtou4SyEosGAGEeYqY7R53bIA==} + engines: {node: '>= 10'} + + '@tailwindcss/vite@4.1.13': + resolution: {integrity: sha512-0PmqLQ010N58SbMTJ7BVJ4I2xopiQn/5i6nlb4JmxzQf8zcS5+m2Cv6tqh+sfDwtIdjoEnOvwsGQ1hkUi8QEHQ==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 + + '@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==} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@tybys/wasm-util@0.10.0': + resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/body-parser@1.19.6': + resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/cookiejar@2.1.5': + resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} + + '@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==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/express-serve-static-core@5.0.7': + resolution: {integrity: sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==} + + '@types/express@5.0.3': + resolution: {integrity: sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==} + + '@types/http-errors@2.0.5': + resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@30.0.0': + resolution: {integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/methods@1.1.4': + resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} + + '@types/mime@1.3.5': + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + + '@types/node@22.18.1': + resolution: {integrity: sha512-rzSDyhn4cYznVG+PCzGe1lwuMYJrcBS1fc3JqSa2PvtABwWo+dZ1ij5OVok3tqfpEBCBoaR4d7upFJk73HRJDw==} + + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + + '@types/react-dom@19.1.9': + resolution: {integrity: sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==} + peerDependencies: + '@types/react': ^19.0.0 + + '@types/react@19.1.12': + resolution: {integrity: sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==} + + '@types/send@0.17.5': + resolution: {integrity: sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==} + + '@types/serve-static@1.15.8': + resolution: {integrity: sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/superagent@8.1.9': + resolution: {integrity: sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==} + + '@types/supertest@6.0.3': + resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + + '@typescript-eslint/eslint-plugin@8.42.0': + resolution: {integrity: sha512-Aq2dPqsQkxHOLfb2OPv43RnIvfj05nw8v/6n3B2NABIPpHnjQnaLo9QGMTvml+tv4korl/Cjfrb/BYhoL8UUTQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.42.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@8.42.0': + resolution: {integrity: sha512-r1XG74QgShUgXph1BYseJ+KZd17bKQib/yF3SR+demvytiRXrwd12Blnz5eYGm8tXaeRdd4x88MlfwldHoudGg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.42.0': + resolution: {integrity: sha512-vfVpLHAhbPjilrabtOSNcUDmBboQNrJUiNAGoImkZKnMjs2TIcWG33s4Ds0wY3/50aZmTMqJa6PiwkwezaAklg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/scope-manager@8.42.0': + resolution: {integrity: sha512-51+x9o78NBAVgQzOPd17DkNTnIzJ8T/O2dmMBLoK9qbY0Gm52XJcdJcCl18ExBMiHo6jPMErUQWUv5RLE51zJw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.42.0': + resolution: {integrity: sha512-kHeFUOdwAJfUmYKjR3CLgZSglGHjbNTi1H8sTYRYV2xX6eNz4RyJ2LIgsDLKf8Yi0/GL1WZAC/DgZBeBft8QAQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@8.42.0': + resolution: {integrity: sha512-9KChw92sbPTYVFw3JLRH1ockhyR3zqqn9lQXol3/YbI6jVxzWoGcT3AsAW0mu1MY0gYtsXnUGV/AKpkAj5tVlQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@8.42.0': + resolution: {integrity: sha512-LdtAWMiFmbRLNP7JNeY0SqEtJvGMYSzfiWBSmx+VSZ1CH+1zyl8Mmw1TT39OrtsRvIYShjJWzTDMPWZJCpwBlw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.42.0': + resolution: {integrity: sha512-ku/uYtT4QXY8sl9EDJETD27o3Ewdi72hcXg1ah/kkUgBvAYHLwj2ofswFFNXS+FL5G+AGkxBtvGt8pFBHKlHsQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@8.42.0': + resolution: {integrity: sha512-JnIzu7H3RH5BrKC4NoZqRfmjqCIS1u3hGZltDYJgkVdqAezl4L9d1ZLw+36huCujtSBSAirGINF/S4UxOcR+/g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@8.42.0': + resolution: {integrity: sha512-3WbiuzoEowaEn8RSnhJBrxSwX8ULYE9CXaPepS2C2W3NSA5NNIvBaslpBSBElPq0UGr0xVJlXFWOAKIkyylydQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + + '@vitejs/plugin-react@5.0.2': + resolution: {integrity: sha512-tmyFgixPZCx2+e6VO9TNITWcCQl8+Nl/E8YbAyPVv85QCc7/A3JrdfG2A8gIzvVhWuzMOVrFW1aReaNxrI6tbw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + + '@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==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + acorn-import-phases@1.0.4: + resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} + engines: {node: '>=10.13.0'} + peerDependencies: + acorn: ^8.14.0 + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + 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.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-colors@4.1.3: + 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@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.0: + resolution: {integrity: sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + ansis@4.1.0: + resolution: {integrity: sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==} + engines: {node: '>=14'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + append-field@1.0.0: + resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + 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.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axe-core@4.10.3: + resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==} + engines: {node: '>=4'} + + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} + engines: {node: '>= 0.4'} + + babel-jest@30.1.2: + resolution: {integrity: sha512-IQCus1rt9kaSh7PQxLYRY5NmkNrNlU2TpabzwV7T2jljnpdHOcmnYYv8QmE04Li4S3a2Lj8/yXyET5pBarPr6g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 + + babel-plugin-istanbul@7.0.1: + resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==} + engines: {node: '>=12'} + + babel-plugin-jest-hoist@30.0.1: + resolution: {integrity: sha512-zTPME3pI50NsFW8ZBaVIOeAxzEY7XHlmWeXXu9srI+9kNfzCUTy8MFan46xOGZY8NZThMqq+e3qZUKsvXbasnQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + babel-preset-current-node-syntax@1.2.0: + resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} + peerDependencies: + '@babel/core': ^7.0.0 || ^8.0.0-0 + + babel-preset-jest@30.0.1: + resolution: {integrity: sha512-+YHejD5iTWI46cZmcc/YtX4gaKBtdqCHCVfuVinizVpbmyjO3zYmeuyFdfA8duRqQZfgCAMlsfmkVbJ+e2MAJw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + birecord@0.1.1: + resolution: {integrity: sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + body-parser@2.2.0: + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + engines: {node: '>=18'} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.25.4: + resolution: {integrity: sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + 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'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001741: + resolution: {integrity: sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + chardet@2.1.0: + resolution: {integrity: sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + + ci-info@4.3.0: + resolution: {integrity: sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==} + engines: {node: '>=8'} + + cjs-module-lexer@2.1.0: + resolution: {integrity: sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + + cli-spinners@2.9.2: + 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@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'} + + clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + 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'} + + comment-json@4.2.5: + resolution: {integrity: sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==} + engines: {node: '>= 6'} + + compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + + component-emitter@1.3.1: + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} + + 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} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + content-disposition@1.0.0: + resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cookiejar@2.1.4: + resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} + + 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@8.3.6: + resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + dedent@1.7.0: + resolution: {integrity: sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + detect-libc@2.0.4: + resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + engines: {node: '>=8'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + dezalgo@1.0.4: + resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.214: + resolution: {integrity: sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==} + + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + esbuild@0.25.9: + resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-prettier@10.1.8: + resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-plugin-jsx-a11y@6.10.2: + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-prettier@5.5.4: + resolution: {integrity: sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-plugin-react-dom@1.53.0: + resolution: {integrity: sha512-JfjDWxFLCuAo+Vm2S6uVGxHMteN37r193PORuCfERpi3LCh97xq0FI3j05SKHvyQmV87jUuBbKLvOBTylTSRvw==} + engines: {node: '>=18.18.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: ^4.9.5 || ^5.3.3 + peerDependenciesMeta: + typescript: + optional: true + + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react-refresh@0.4.20: + resolution: {integrity: sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==} + peerDependencies: + eslint: '>=8.40' + + eslint-plugin-react-x@1.53.0: + resolution: {integrity: sha512-5a1CpHtBXQQUPB6dbxvcqg97QJ+APWNbZJQEBKNCiVjnx1DpCOzhAwZ2jMOZe+HS96Cf3TqqlRf4HBUm4KYYxg==} + engines: {node: '>=18.18.0'} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + ts-api-utils: ^2.1.0 + typescript: ^4.9.5 || ^5.3.3 + peerDependenciesMeta: + ts-api-utils: + optional: true + typescript: + optional: true + + 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} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.35.0: + resolution: {integrity: sha512-QePbBFMJFjgmlE+cXAlbHZbHpdFVS2E/6vzCy7aKlebddvl1vadiC4JFV5u/wqTkNUwEV8WrQi257jf5f06hrg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + 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'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exit-x@0.2.2: + resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} + engines: {node: '>= 0.8.0'} + + expect@30.1.2: + resolution: {integrity: sha512-xvHszRavo28ejws8FpemjhwswGj4w/BetHIL8cU49u4sGyXDw2+p3YbeDbj6xzlxi6kWTjIRSTJ+9sNXPnF0Zg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + express@5.1.0: + resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} + engines: {node: '>= 18'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + 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==} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fflate@0.8.2: + resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + file-type@21.0.0: + resolution: {integrity: sha512-ek5xNX2YBYlXhiUXui3D/BXa3LdqPmoLJ7rqEx2bKJ7EAUEfmXgW0Das7Dc6Nr9MvqaOnIqiPV0mZk/r/UpNAg==} + engines: {node: '>=20'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@2.1.0: + resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} + engines: {node: '>= 0.8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + fork-ts-checker-webpack-plugin@9.1.0: + resolution: {integrity: sha512-mpafl89VFPJmhnJ1ssH+8wmM2b50n+Rew5x42NeI2U78aRWgtkEtGmctp7iT16UjquJTjorEmIfESj3DxdW84Q==} + engines: {node: '>=14.21.3'} + peerDependencies: + typescript: '>3.6.0' + webpack: ^5.11.0 + + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + engines: {node: '>= 6'} + + formidable@3.5.4: + resolution: {integrity: sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==} + engines: {node: '>=14.0.0'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + 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==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + 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==} + hasBin: true + + glob@11.0.3: + resolution: {integrity: sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==} + engines: {node: 20 || >=22} + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.3.0: + resolution: {integrity: sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + handlebars@4.7.8: + resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} + engines: {node: '>=0.4.7'} + hasBin: true + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@4.0.0: + 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==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.7.0: + resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-generator-function@1.1.0: + resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + engines: {node: '>= 0.4'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-immutable-type@5.0.1: + resolution: {integrity: sha512-LkHEOGVZZXxGl8vDs+10k3DvP++SEoYEAJLRk6buTFi6kD7QekThV7xHS0j6gpnUCQ0zpud/gMDGiV4dQneLTg==} + peerDependencies: + eslint: '*' + typescript: '>=4.7.4' + + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + + iterare@1.2.1: + resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} + engines: {node: '>=6'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jackspeak@4.1.1: + resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} + engines: {node: 20 || >=22} + + jest-changed-files@30.0.5: + resolution: {integrity: sha512-bGl2Ntdx0eAwXuGpdLdVYVr5YQHnSZlQ0y9HVDu565lCUAe9sj6JOtBbMmBBikGIegne9piDDIOeiLVoqTkz4A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-circus@30.1.3: + resolution: {integrity: sha512-Yf3dnhRON2GJT4RYzM89t/EXIWNxKTpWTL9BfF3+geFetWP4XSvJjiU1vrWplOiUkmq8cHLiwuhz+XuUp9DscA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-cli@30.1.3: + resolution: {integrity: sha512-G8E2Ol3OKch1DEeIBl41NP7OiC6LBhfg25Btv+idcusmoUSpqUkbrneMqbW9lVpI/rCKb/uETidb7DNteheuAQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@30.1.3: + resolution: {integrity: sha512-M/f7gqdQEPgZNA181Myz+GXCe8jXcJsGjCMXUzRj22FIXsZOyHNte84e0exntOvdPaeh9tA0w+B8qlP2fAezfw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@types/node': '*' + esbuild-register: '>=3.4.0' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + esbuild-register: + optional: true + ts-node: + optional: true + + jest-diff@30.1.2: + resolution: {integrity: sha512-4+prq+9J61mOVXCa4Qp8ZjavdxzrWQXrI80GNxP8f4tkI2syPuPrJgdRPZRrfUTRvIoUwcmNLbqEJy9W800+NQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-docblock@30.0.1: + resolution: {integrity: sha512-/vF78qn3DYphAaIc3jy4gA7XSAz167n9Bm/wn/1XhTLW7tTBIzXtCJpb/vcmc73NIIeeohCbdL94JasyXUZsGA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-each@30.1.0: + resolution: {integrity: sha512-A+9FKzxPluqogNahpCv04UJvcZ9B3HamqpDNWNKDjtxVRYB8xbZLFuCr8JAJFpNp83CA0anGQFlpQna9Me+/tQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-environment-node@30.1.2: + resolution: {integrity: sha512-w8qBiXtqGWJ9xpJIA98M0EIoq079GOQRQUyse5qg1plShUCQ0Ek1VTTcczqKrn3f24TFAgFtT+4q3aOXvjbsuA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-haste-map@30.1.0: + resolution: {integrity: sha512-JLeM84kNjpRkggcGpQLsV7B8W4LNUWz7oDNVnY1Vjj22b5/fAb3kk3htiD+4Na8bmJmjJR7rBtS2Rmq/NEcADg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-leak-detector@30.1.0: + resolution: {integrity: sha512-AoFvJzwxK+4KohH60vRuHaqXfWmeBATFZpzpmzNmYTtmRMiyGPVhkXpBqxUQunw+dQB48bDf4NpUs6ivVbRv1g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-matcher-utils@30.1.2: + resolution: {integrity: sha512-7ai16hy4rSbDjvPTuUhuV8nyPBd6EX34HkBsBcBX2lENCuAQ0qKCPb/+lt8OSWUa9WWmGYLy41PrEzkwRwoGZQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-message-util@30.1.0: + resolution: {integrity: sha512-HizKDGG98cYkWmaLUHChq4iN+oCENohQLb7Z5guBPumYs+/etonmNFlg1Ps6yN9LTPyZn+M+b/9BbnHx3WTMDg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-mock@30.0.5: + resolution: {integrity: sha512-Od7TyasAAQX/6S+QCbN6vZoWOMwlTtzzGuxJku1GhGanAjz9y+QsQkpScDmETvdc9aSXyJ/Op4rhpMYBWW91wQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@30.0.1: + resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-resolve-dependencies@30.1.3: + resolution: {integrity: sha512-DNfq3WGmuRyHRHfEet+Zm3QOmVFtIarUOQHHryKPc0YL9ROfgWZxl4+aZq/VAzok2SS3gZdniP+dO4zgo59hBg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-resolve@30.1.3: + resolution: {integrity: sha512-DI4PtTqzw9GwELFS41sdMK32Ajp3XZQ8iygeDMWkxlRhm7uUTOFSZFVZABFuxr0jvspn8MAYy54NxZCsuCTSOw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-runner@30.1.3: + resolution: {integrity: sha512-dd1ORcxQraW44Uz029TtXj85W11yvLpDuIzNOlofrC8GN+SgDlgY4BvyxJiVeuabA1t6idjNbX59jLd2oplOGQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-runtime@30.1.3: + resolution: {integrity: sha512-WS8xgjuNSphdIGnleQcJ3AKE4tBKOVP+tKhCD0u+Tb2sBmsU8DxfbBpZX7//+XOz81zVs4eFpJQwBNji2Y07DA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-snapshot@30.1.2: + resolution: {integrity: sha512-4q4+6+1c8B6Cy5pGgFvjDy/Pa6VYRiGu0yQafKkJ9u6wQx4G5PqI2QR6nxTl43yy7IWsINwz6oT4o6tD12a8Dg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-util@30.0.5: + resolution: {integrity: sha512-pvyPWssDZR0FlfMxCBoc0tvM8iUEskaRFALUtGQYzVEAqisAztmy+R8LnU14KT4XA0H/a5HMVTXat1jLne010g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-validate@30.1.0: + resolution: {integrity: sha512-7P3ZlCFW/vhfQ8pE7zW6Oi4EzvuB4sgR72Q1INfW9m0FGo0GADYlPwIkf4CyPq7wq85g+kPMtPOHNAdWHeBOaA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-watcher@30.1.3: + resolution: {integrity: sha512-6jQUZCP1BTL2gvG9E4YF06Ytq4yMb4If6YoQGRR6PpjtqOXSP3sKe2kqwB6SQ+H9DezOfZaSLnmka1NtGm3fCQ==} + 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'} + + jest-worker@30.1.0: + resolution: {integrity: sha512-uvWcSjlwAAgIu133Tt77A05H7RIk3Ho8tZL50bQM2AkvLdluw9NG48lRCl3Dt+MOH719n/0nnb5YxUwcuJiKRA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest@30.1.3: + resolution: {integrity: sha512-Ry+p2+NLk6u8Agh5yVqELfUJvRfV51hhVBRIB5yZPY7mU0DGBmOuFG5GebZbMbm86cdQNK0fhJuDX8/1YorISQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jiti@2.5.1: + resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} + + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lightningcss-darwin-arm64@1.30.1: + resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.1: + resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.1: + resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.1: + resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.1: + resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.1: + resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.1: + resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.1: + resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.1: + resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.1: + resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.1: + resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} + engines: {node: '>= 12.0.0'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + load-esm@1.0.2: + resolution: {integrity: sha512-nVAvWk/jeyrWyXEAs84mpQCYccxRqgKY4OznLuJhJCa0XsPSfdOIr2zvBZEj3IHEHbX97jjscKRRV539bW0Gpw==} + engines: {node: '>=13.2.0'} + + loader-runner@4.3.0: + resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + engines: {node: '>=6.11.5'} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@11.2.1: + resolution: {integrity: sha512-r8LA6i4LP4EeWOhqBaZZjDWwehd1xUJPCJd9Sv300H0ZmcUER4+JPh7bqqZeqs1o5pgtgvXm+d9UGrB5zZGDiQ==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@0.542.0: + resolution: {integrity: sha512-w3hD8/SQB7+lzU2r4VdFyzzOzKnUjTZIF/MQJGSSvni7Llewni4vuViRppfRAa2guOsY5k4jZyxw/i9DQHv+dw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + lucide@0.542.0: + resolution: {integrity: sha512-+EtDSHjqg/nONgCfnjHCNd84OzbDjxR8ShnOf+oImlU+A8gqlptZ6pGrMCnhEDw8pVNQv3zu/L0eDvMzcc7nWA==} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + magic-string@0.30.18: + resolution: {integrity: sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + 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'} + + 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@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.0.2: + resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==} + engines: {node: '>= 18'} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + + 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@2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-postinstall@0.3.3: + resolution: {integrity: sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + node-abort-controller@3.1.1: + resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + + node-emoji@1.11.0: + resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.20: + resolution: {integrity: sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.0: + resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} + engines: {node: 20 || >=22} + + path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} + hasBin: true + + pretty-format@30.0.5: + resolution: {integrity: sha512-D1tKtYvByrBkFLe2wHJl2bwMJIiT8rW+XA+TiataH79/FszLQMrpGEvzUVkzPau7OCO0Qnrhpe87PqtOAIB8Yw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + pure-rand@7.0.1: + resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.1: + resolution: {integrity: sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==} + engines: {node: '>= 0.10'} + + react-dom@19.1.1: + resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} + peerDependencies: + react: ^19.1.1 + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react@19.1.1: + resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} + engines: {node: '>=0.10.0'} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + 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'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rollup@4.50.1: + resolution: {integrity: sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + 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'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + + schema-utils@3.3.0: + resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} + engines: {node: '>= 10.13.0'} + + schema-utils@4.3.2: + resolution: {integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==} + engines: {node: '>= 10.13.0'} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} + + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + serve-static@2.2.0: + resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + engines: {node: '>= 18'} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-ts@2.2.1: + resolution: {integrity: sha512-Q2u0gko67PLLhbte5HmPfdOjNvUKbKQM+mCNQae6jE91DmoFHY6HH9GcdqCeNx87DZ2KKjiFxmA0R/42OneGWw==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strtok3@10.3.4: + resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} + engines: {node: '>=18'} + + superagent@10.2.3: + resolution: {integrity: sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==} + engines: {node: '>=14.18.0'} + + supertest@7.1.4: + resolution: {integrity: sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==} + engines: {node: '>=14.18.0'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + 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} + + tailwind-merge@3.3.1: + resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==} + + tailwindcss@4.1.13: + resolution: {integrity: sha512-i+zidfmTqtwquj4hMEwdjshYYgMbOrPzb9a0M3ZgNa0JMoZeFC6bxZvO8yr8ozS6ix2SDz0+mvryPeBs2TFE+w==} + + tapable@2.2.3: + resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==} + engines: {node: '>=6'} + + tar@7.4.3: + resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + engines: {node: '>=18'} + + terser-webpack-plugin@5.3.14: + resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} + 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.44.0: + resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==} + engines: {node: '>=10'} + hasBin: true + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + token-types@6.1.1: + resolution: {integrity: sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ==} + engines: {node: '>=14.16'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + ts-declaration-location@1.0.7: + resolution: {integrity: sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==} + peerDependencies: + typescript: '>=4.0.0' + + ts-jest@29.4.1: + resolution: {integrity: sha512-SaeUtjfpg9Uqu8IbeDKtdaS0g8lS6FT6OzM3ezrDfErPJPHNDo/Ey+VFGP1bQIDfagYDLyRpd7O15XpG1Es2Uw==} + engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/transform': ^29.0.0 || ^30.0.0 + '@jest/types': ^29.0.0 || ^30.0.0 + babel-jest: ^29.0.0 || ^30.0.0 + esbuild: '*' + jest: ^29.0.0 || ^30.0.0 + jest-util: ^29.0.0 || ^30.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/transform': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + jest-util: + optional: true + + ts-loader@9.5.4: + resolution: {integrity: sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==} + engines: {node: '>=12.0.0'} + peerDependencies: + typescript: '*' + webpack: ^5.0.0 + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + ts-pattern@5.8.0: + resolution: {integrity: sha512-kIjN2qmWiHnhgr5DAkAafF9fwb0T5OhMVSWrm8XEdTFnX6+wfXwYOFjeF86UZ54vduqiR7BfqScFmXSzSaH8oA==} + + 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'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tw-animate-css@1.3.8: + resolution: {integrity: sha512-Qrk3PZ7l7wUcGYhwZloqfkWCmaXZAoqjkdbIDvzfGshwGtexa/DAs9koXxIkrpEasyevandomzCBAV1Yyop5rw==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + 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'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + 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.42.0: + resolution: {integrity: sha512-ozR/rQn+aQXQxh1YgbCzQWDFrsi9mcg+1PM3l/z5o1+20P7suOIaNg515bpr/OYt6FObz/NHcBstydDLHWeEKg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + engines: {node: '>=14.17'} + hasBin: true + + uglify-js@3.19.3: + resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} + engines: {node: '>=0.8.0'} + 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'} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + 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'} + + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vite@7.1.4: + resolution: {integrity: sha512-X5QFK4SGynAeeIt+A7ZWnApdUyHYm+pzv/8/A57LqSGcI88U6R6ipOs3uCesdc6yl7nl+zNO0t8LmqAdXcQihw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + watchpack@2.4.4: + resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} + engines: {node: '>=10.13.0'} + + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + + webpack-node-externals@3.0.0: + resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==} + engines: {node: '>=6'} + + webpack-sources@3.3.3: + resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} + engines: {node: '>=10.13.0'} + + webpack@5.100.2: + resolution: {integrity: sha512-QaNKAvGCDRh3wW1dsDjeMdDXwZm2vqq3zn6Pvq4rHOEOGSaUMgOOjG2Y9ZbIGzpfkJk9ZYTHpDqgDfeBDcnLaw==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + + 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'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yoctocolors-cjs@2.1.3: + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} + engines: {node: '>=18'} + + zod@4.1.5: + resolution: {integrity: sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg==} + +snapshots: + + '@angular-devkit/core@19.2.15(chokidar@4.0.3)': + dependencies: + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + jsonc-parser: 3.3.1 + picomatch: 4.0.2 + rxjs: 7.8.1 + source-map: 0.7.4 + optionalDependencies: + chokidar: 4.0.3 + + '@angular-devkit/schematics-cli@19.2.15(@types/node@22.18.1)(chokidar@4.0.3)': + dependencies: + '@angular-devkit/core': 19.2.15(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.15(chokidar@4.0.3) + '@inquirer/prompts': 7.3.2(@types/node@22.18.1) + ansi-colors: 4.1.3 + symbol-observable: 4.0.0 + yargs-parser: 21.1.1 + transitivePeerDependencies: + - '@types/node' + - chokidar + + '@angular-devkit/schematics@19.2.15(chokidar@4.0.3)': + dependencies: + '@angular-devkit/core': 19.2.15(chokidar@4.0.3) + jsonc-parser: 3.3.1 + magic-string: 0.30.17 + ora: 5.4.1 + rxjs: 7.8.1 + transitivePeerDependencies: + - chokidar + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.4': {} + + '@babel/core@7.28.4': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.4 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.3': + dependencies: + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.4 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.25.4 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.4 + '@babel/types': 7.28.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.4 + + '@babel/parser@7.28.4': + dependencies: + '@babel/types': 7.28.4 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + + '@babel/traverse@7.28.4': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.4 + '@babel/template': 7.27.2 + '@babel/types': 7.28.4 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.4': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + + '@bcoe/v8-coverage@0.2.3': {} + + '@borewit/text-codec@0.1.1': {} + + '@colors/colors@1.5.0': + optional: true + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@emnapi/core@1.5.0': + dependencies: + '@emnapi/wasi-threads': 1.1.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.5.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.1.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.25.9': + optional: true + + '@esbuild/android-arm64@0.25.9': + optional: true + + '@esbuild/android-arm@0.25.9': + optional: true + + '@esbuild/android-x64@0.25.9': + optional: true + + '@esbuild/darwin-arm64@0.25.9': + optional: true + + '@esbuild/darwin-x64@0.25.9': + optional: true + + '@esbuild/freebsd-arm64@0.25.9': + optional: true + + '@esbuild/freebsd-x64@0.25.9': + optional: true + + '@esbuild/linux-arm64@0.25.9': + optional: true + + '@esbuild/linux-arm@0.25.9': + optional: true + + '@esbuild/linux-ia32@0.25.9': + optional: true + + '@esbuild/linux-loong64@0.25.9': + optional: true + + '@esbuild/linux-mips64el@0.25.9': + optional: true + + '@esbuild/linux-ppc64@0.25.9': + optional: true + + '@esbuild/linux-riscv64@0.25.9': + optional: true + + '@esbuild/linux-s390x@0.25.9': + optional: true + + '@esbuild/linux-x64@0.25.9': + optional: true + + '@esbuild/netbsd-arm64@0.25.9': + optional: true + + '@esbuild/netbsd-x64@0.25.9': + optional: true + + '@esbuild/openbsd-arm64@0.25.9': + optional: true + + '@esbuild/openbsd-x64@0.25.9': + optional: true + + '@esbuild/openharmony-arm64@0.25.9': + optional: true + + '@esbuild/sunos-x64@0.25.9': + optional: true + + '@esbuild/win32-arm64@0.25.9': + optional: true + + '@esbuild/win32-ia32@0.25.9': + optional: true + + '@esbuild/win32-x64@0.25.9': + optional: true + + '@eslint-community/eslint-utils@4.8.0(eslint@9.35.0(jiti@2.5.1))': + dependencies: + eslint: 9.35.0(jiti@2.5.1) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint-react/ast@1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@eslint-react/eff': 1.53.0 + '@typescript-eslint/types': 8.42.0 + '@typescript-eslint/typescript-estree': 8.42.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + string-ts: 2.2.1 + ts-pattern: 5.8.0 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@eslint-react/core@1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@eslint-react/ast': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@eslint-react/eff': 1.53.0 + '@eslint-react/kit': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@eslint-react/shared': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@eslint-react/var': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.42.0 + '@typescript-eslint/type-utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/types': 8.42.0 + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + birecord: 0.1.1 + ts-pattern: 5.8.0 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@eslint-react/eff@1.53.0': {} + + '@eslint-react/kit@1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@eslint-react/eff': 1.53.0 + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + ts-pattern: 5.8.0 + zod: 4.1.5 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@eslint-react/shared@1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@eslint-react/eff': 1.53.0 + '@eslint-react/kit': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + ts-pattern: 5.8.0 + zod: 4.1.5 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@eslint-react/var@1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@eslint-react/ast': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@eslint-react/eff': 1.53.0 + '@typescript-eslint/scope-manager': 8.42.0 + '@typescript-eslint/types': 8.42.0 + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + string-ts: 2.2.1 + ts-pattern: 5.8.0 + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + '@eslint/config-array@0.21.0': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.1 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.3.1': {} + + '@eslint/core@0.15.2': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.1 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.35.0': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.3.5': + dependencies: + '@eslint/core': 0.15.2 + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@inquirer/checkbox@4.2.2(@types/node@22.18.1)': + dependencies: + '@inquirer/core': 10.2.0(@types/node@22.18.1) + '@inquirer/figures': 1.0.13 + '@inquirer/type': 3.0.8(@types/node@22.18.1) + ansi-escapes: 4.3.2 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/confirm@5.1.16(@types/node@22.18.1)': + dependencies: + '@inquirer/core': 10.2.0(@types/node@22.18.1) + '@inquirer/type': 3.0.8(@types/node@22.18.1) + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/core@10.2.0(@types/node@22.18.1)': + dependencies: + '@inquirer/figures': 1.0.13 + '@inquirer/type': 3.0.8(@types/node@22.18.1) + ansi-escapes: 4.3.2 + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/editor@4.2.18(@types/node@22.18.1)': + dependencies: + '@inquirer/core': 10.2.0(@types/node@22.18.1) + '@inquirer/external-editor': 1.0.1(@types/node@22.18.1) + '@inquirer/type': 3.0.8(@types/node@22.18.1) + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/expand@4.0.18(@types/node@22.18.1)': + dependencies: + '@inquirer/core': 10.2.0(@types/node@22.18.1) + '@inquirer/type': 3.0.8(@types/node@22.18.1) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/external-editor@1.0.1(@types/node@22.18.1)': + dependencies: + chardet: 2.1.0 + iconv-lite: 0.6.3 + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/figures@1.0.13': {} + + '@inquirer/input@4.2.2(@types/node@22.18.1)': + dependencies: + '@inquirer/core': 10.2.0(@types/node@22.18.1) + '@inquirer/type': 3.0.8(@types/node@22.18.1) + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/number@3.0.18(@types/node@22.18.1)': + dependencies: + '@inquirer/core': 10.2.0(@types/node@22.18.1) + '@inquirer/type': 3.0.8(@types/node@22.18.1) + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/password@4.0.18(@types/node@22.18.1)': + dependencies: + '@inquirer/core': 10.2.0(@types/node@22.18.1) + '@inquirer/type': 3.0.8(@types/node@22.18.1) + ansi-escapes: 4.3.2 + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/prompts@7.3.2(@types/node@22.18.1)': + dependencies: + '@inquirer/checkbox': 4.2.2(@types/node@22.18.1) + '@inquirer/confirm': 5.1.16(@types/node@22.18.1) + '@inquirer/editor': 4.2.18(@types/node@22.18.1) + '@inquirer/expand': 4.0.18(@types/node@22.18.1) + '@inquirer/input': 4.2.2(@types/node@22.18.1) + '@inquirer/number': 3.0.18(@types/node@22.18.1) + '@inquirer/password': 4.0.18(@types/node@22.18.1) + '@inquirer/rawlist': 4.1.6(@types/node@22.18.1) + '@inquirer/search': 3.1.1(@types/node@22.18.1) + '@inquirer/select': 4.3.2(@types/node@22.18.1) + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/prompts@7.8.0(@types/node@22.18.1)': + dependencies: + '@inquirer/checkbox': 4.2.2(@types/node@22.18.1) + '@inquirer/confirm': 5.1.16(@types/node@22.18.1) + '@inquirer/editor': 4.2.18(@types/node@22.18.1) + '@inquirer/expand': 4.0.18(@types/node@22.18.1) + '@inquirer/input': 4.2.2(@types/node@22.18.1) + '@inquirer/number': 3.0.18(@types/node@22.18.1) + '@inquirer/password': 4.0.18(@types/node@22.18.1) + '@inquirer/rawlist': 4.1.6(@types/node@22.18.1) + '@inquirer/search': 3.1.1(@types/node@22.18.1) + '@inquirer/select': 4.3.2(@types/node@22.18.1) + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/rawlist@4.1.6(@types/node@22.18.1)': + dependencies: + '@inquirer/core': 10.2.0(@types/node@22.18.1) + '@inquirer/type': 3.0.8(@types/node@22.18.1) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/search@3.1.1(@types/node@22.18.1)': + dependencies: + '@inquirer/core': 10.2.0(@types/node@22.18.1) + '@inquirer/figures': 1.0.13 + '@inquirer/type': 3.0.8(@types/node@22.18.1) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/select@4.3.2(@types/node@22.18.1)': + dependencies: + '@inquirer/core': 10.2.0(@types/node@22.18.1) + '@inquirer/figures': 1.0.13 + '@inquirer/type': 3.0.8(@types/node@22.18.1) + ansi-escapes: 4.3.2 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.18.1 + + '@inquirer/type@3.0.8(@types/node@22.18.1)': + optionalDependencies: + '@types/node': 22.18.1 + + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.2 + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/console@30.1.2': + dependencies: + '@jest/types': 30.0.5 + '@types/node': 22.18.1 + chalk: 4.1.2 + jest-message-util: 30.1.0 + jest-util: 30.0.5 + slash: 3.0.0 + + '@jest/core@30.1.3(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3))': + dependencies: + '@jest/console': 30.1.2 + '@jest/pattern': 30.0.1 + '@jest/reporters': 30.1.3 + '@jest/test-result': 30.1.3 + '@jest/transform': 30.1.2 + '@jest/types': 30.0.5 + '@types/node': 22.18.1 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 4.3.0 + exit-x: 0.2.2 + graceful-fs: 4.2.11 + jest-changed-files: 30.0.5 + jest-config: 30.1.3(@types/node@22.18.1)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)) + jest-haste-map: 30.1.0 + jest-message-util: 30.1.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.1.3 + jest-resolve-dependencies: 30.1.3 + jest-runner: 30.1.3 + jest-runtime: 30.1.3 + jest-snapshot: 30.1.2 + jest-util: 30.0.5 + jest-validate: 30.1.0 + jest-watcher: 30.1.3 + micromatch: 4.0.8 + pretty-format: 30.0.5 + slash: 3.0.0 + transitivePeerDependencies: + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + + '@jest/diff-sequences@30.0.1': {} + + '@jest/environment@30.1.2': + dependencies: + '@jest/fake-timers': 30.1.2 + '@jest/types': 30.0.5 + '@types/node': 22.18.1 + jest-mock: 30.0.5 + + '@jest/expect-utils@30.1.2': + dependencies: + '@jest/get-type': 30.1.0 + + '@jest/expect@30.1.2': + dependencies: + expect: 30.1.2 + jest-snapshot: 30.1.2 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@30.1.2': + dependencies: + '@jest/types': 30.0.5 + '@sinonjs/fake-timers': 13.0.5 + '@types/node': 22.18.1 + jest-message-util: 30.1.0 + jest-mock: 30.0.5 + jest-util: 30.0.5 + + '@jest/get-type@30.1.0': {} + + '@jest/globals@30.1.2': + dependencies: + '@jest/environment': 30.1.2 + '@jest/expect': 30.1.2 + '@jest/types': 30.0.5 + jest-mock: 30.0.5 + transitivePeerDependencies: + - supports-color + + '@jest/pattern@30.0.1': + dependencies: + '@types/node': 22.18.1 + jest-regex-util: 30.0.1 + + '@jest/reporters@30.1.3': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 30.1.2 + '@jest/test-result': 30.1.3 + '@jest/transform': 30.1.2 + '@jest/types': 30.0.5 + '@jridgewell/trace-mapping': 0.3.30 + '@types/node': 22.18.1 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit-x: 0.2.2 + glob: 10.4.5 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + jest-message-util: 30.1.0 + jest-util: 30.0.5 + jest-worker: 30.1.0 + slash: 3.0.0 + string-length: 4.0.2 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@30.0.5': + dependencies: + '@sinclair/typebox': 0.34.41 + + '@jest/snapshot-utils@30.1.2': + dependencies: + '@jest/types': 30.0.5 + chalk: 4.1.2 + graceful-fs: 4.2.11 + natural-compare: 1.4.0 + + '@jest/source-map@30.0.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.30 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@30.1.3': + dependencies: + '@jest/console': 30.1.2 + '@jest/types': 30.0.5 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + + '@jest/test-sequencer@30.1.3': + dependencies: + '@jest/test-result': 30.1.3 + graceful-fs: 4.2.11 + jest-haste-map: 30.1.0 + slash: 3.0.0 + + '@jest/transform@30.1.2': + dependencies: + '@babel/core': 7.28.4 + '@jest/types': 30.0.5 + '@jridgewell/trace-mapping': 0.3.30 + babel-plugin-istanbul: 7.0.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.1.0 + jest-regex-util: 30.0.1 + jest-util: 30.0.5 + micromatch: 4.0.8 + pirates: 4.0.7 + slash: 3.0.0 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color + + '@jest/types@30.0.5': + dependencies: + '@jest/pattern': 30.0.1 + '@jest/schemas': 30.0.5 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.18.1 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.30 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.30': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@lukeed/csprng@1.1.0': {} + + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.5.0 + '@emnapi/runtime': 1.5.0 + '@tybys/wasm-util': 0.10.0 + optional: true + + '@nestjs/cli@11.0.10(@types/node@22.18.1)': + dependencies: + '@angular-devkit/core': 19.2.15(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.15(chokidar@4.0.3) + '@angular-devkit/schematics-cli': 19.2.15(@types/node@22.18.1)(chokidar@4.0.3) + '@inquirer/prompts': 7.8.0(@types/node@22.18.1) + '@nestjs/schematics': 11.0.7(chokidar@4.0.3)(typescript@5.8.3) + ansis: 4.1.0 + chokidar: 4.0.3 + cli-table3: 0.6.5 + commander: 4.1.1 + fork-ts-checker-webpack-plugin: 9.1.0(typescript@5.8.3)(webpack@5.100.2) + glob: 11.0.3 + 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.8.3 + webpack: 5.100.2 + webpack-node-externals: 3.0.0 + transitivePeerDependencies: + - '@types/node' + - esbuild + - uglify-js + - webpack-cli + + '@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + file-type: 21.0.0 + iterare: 1.2.1 + load-esm: 1.0.2 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + transitivePeerDependencies: + - supports-color + + '@nestjs/core@11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + dependencies: + '@nestjs/common': 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nuxt/opencollective': 0.4.1 + fast-safe-stringify: 2.1.1 + iterare: 1.2.1 + path-to-regexp: 8.2.0 + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + tslib: 2.8.1 + uid: 2.0.2 + optionalDependencies: + '@nestjs/platform-express': 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + + '@nestjs/platform-express@11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)': + dependencies: + '@nestjs/common': 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + cors: 2.8.5 + express: 5.1.0 + multer: 2.0.2 + path-to-regexp: 8.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@nestjs/schematics@11.0.7(chokidar@4.0.3)(typescript@5.8.3)': + dependencies: + '@angular-devkit/core': 19.2.15(chokidar@4.0.3) + '@angular-devkit/schematics': 19.2.15(chokidar@4.0.3) + comment-json: 4.2.5 + jsonc-parser: 3.3.1 + pluralize: 8.0.0 + typescript: 5.8.3 + transitivePeerDependencies: + - chokidar + + '@nestjs/testing@11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-express@11.1.6)': + dependencies: + '@nestjs/common': 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + tslib: 2.8.1 + optionalDependencies: + '@nestjs/platform-express': 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + + '@noble/hashes@1.8.0': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@nuxt/opencollective@0.4.1': + dependencies: + consola: 3.4.2 + + '@paralleldrive/cuid2@2.2.2': + dependencies: + '@noble/hashes': 1.8.0 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.2.9': {} + + '@rolldown/pluginutils@1.0.0-beta.34': {} + + '@rollup/rollup-android-arm-eabi@4.50.1': + optional: true + + '@rollup/rollup-android-arm64@4.50.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.50.1': + optional: true + + '@rollup/rollup-darwin-x64@4.50.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.50.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.50.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.50.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.50.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.50.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.50.1': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.50.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.50.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.50.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.50.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.50.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.50.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.50.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.50.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.50.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.50.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.50.1': + optional: true + + '@sinclair/typebox@0.34.41': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@13.0.5': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@tailwindcss/node@4.1.13': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.5.1 + lightningcss: 1.30.1 + magic-string: 0.30.18 + source-map-js: 1.2.1 + tailwindcss: 4.1.13 + + '@tailwindcss/oxide-android-arm64@4.1.13': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.13': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.13': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.13': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.13': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.13': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.13': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.13': + optional: true + + '@tailwindcss/oxide@4.1.13': + dependencies: + detect-libc: 2.0.4 + tar: 7.4.3 + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.13 + '@tailwindcss/oxide-darwin-arm64': 4.1.13 + '@tailwindcss/oxide-darwin-x64': 4.1.13 + '@tailwindcss/oxide-freebsd-x64': 4.1.13 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.13 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.13 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.13 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.13 + '@tailwindcss/oxide-linux-x64-musl': 4.1.13 + '@tailwindcss/oxide-wasm32-wasi': 4.1.13 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.13 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.13 + + '@tailwindcss/vite@4.1.13(vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0))': + dependencies: + '@tailwindcss/node': 4.1.13 + '@tailwindcss/oxide': 4.1.13 + tailwindcss: 4.1.13 + vite: 7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0) + + '@tokenizer/inflate@0.2.7': + dependencies: + debug: 4.4.1 + fflate: 0.8.2 + token-types: 6.1.1 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@tybys/wasm-util@0.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.4 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.4 + '@babel/types': 7.28.4 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.4 + + '@types/body-parser@1.19.6': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 22.18.1 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 22.18.1 + + '@types/cookiejar@2.1.5': {} + + '@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 + '@types/json-schema': 7.0.15 + + '@types/estree@1.0.8': {} + + '@types/express-serve-static-core@5.0.7': + dependencies: + '@types/node': 22.18.1 + '@types/qs': 6.14.0 + '@types/range-parser': 1.2.7 + '@types/send': 0.17.5 + + '@types/express@5.0.3': + dependencies: + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 5.0.7 + '@types/serve-static': 1.15.8 + + '@types/http-errors@2.0.5': {} + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jest@30.0.0': + dependencies: + expect: 30.1.2 + pretty-format: 30.0.5 + + '@types/json-schema@7.0.15': {} + + '@types/methods@1.1.4': {} + + '@types/mime@1.3.5': {} + + '@types/node@22.18.1': + dependencies: + undici-types: 6.21.0 + + '@types/qs@6.14.0': {} + + '@types/range-parser@1.2.7': {} + + '@types/react-dom@19.1.9(@types/react@19.1.12)': + dependencies: + '@types/react': 19.1.12 + + '@types/react@19.1.12': + dependencies: + csstype: 3.1.3 + + '@types/send@0.17.5': + dependencies: + '@types/mime': 1.3.5 + '@types/node': 22.18.1 + + '@types/serve-static@1.15.8': + dependencies: + '@types/http-errors': 2.0.5 + '@types/node': 22.18.1 + '@types/send': 0.17.5 + + '@types/stack-utils@2.0.3': {} + + '@types/superagent@8.1.9': + dependencies: + '@types/cookiejar': 2.1.5 + '@types/methods': 1.1.4 + '@types/node': 22.18.1 + form-data: 4.0.4 + + '@types/supertest@6.0.3': + dependencies: + '@types/methods': 1.1.4 + '@types/superagent': 8.1.9 + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.33': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.42.0 + '@typescript-eslint/type-utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.42.0 + eslint: 9.35.0(jiti@2.5.1) + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.42.0 + '@typescript-eslint/types': 8.42.0 + '@typescript-eslint/typescript-estree': 8.42.0(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.42.0 + debug: 4.4.1 + eslint: 9.35.0(jiti@2.5.1) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.42.0(typescript@5.8.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.42.0(typescript@5.8.3) + '@typescript-eslint/types': 8.42.0 + debug: 4.4.1 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.42.0': + dependencies: + '@typescript-eslint/types': 8.42.0 + '@typescript-eslint/visitor-keys': 8.42.0 + + '@typescript-eslint/tsconfig-utils@8.42.0(typescript@5.8.3)': + dependencies: + typescript: 5.8.3 + + '@typescript-eslint/type-utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@typescript-eslint/types': 8.42.0 + '@typescript-eslint/typescript-estree': 8.42.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + debug: 4.4.1 + eslint: 9.35.0(jiti@2.5.1) + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.42.0': {} + + '@typescript-eslint/typescript-estree@8.42.0(typescript@5.8.3)': + dependencies: + '@typescript-eslint/project-service': 8.42.0(typescript@5.8.3) + '@typescript-eslint/tsconfig-utils': 8.42.0(typescript@5.8.3) + '@typescript-eslint/types': 8.42.0 + '@typescript-eslint/visitor-keys': 8.42.0 + debug: 4.4.1 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.2 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3)': + dependencies: + '@eslint-community/eslint-utils': 4.8.0(eslint@9.35.0(jiti@2.5.1)) + '@typescript-eslint/scope-manager': 8.42.0 + '@typescript-eslint/types': 8.42.0 + '@typescript-eslint/typescript-estree': 8.42.0(typescript@5.8.3) + eslint: 9.35.0(jiti@2.5.1) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.42.0': + dependencies: + '@typescript-eslint/types': 8.42.0 + eslint-visitor-keys: 4.2.1 + + '@ungap/structured-clone@1.3.0': {} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + '@vitejs/plugin-react@5.0.2(vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0))': + dependencies: + '@babel/core': 7.28.4 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4) + '@rolldown/pluginutils': 1.0.0-beta.34 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0) + transitivePeerDependencies: + - supports-color + + '@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': {} + + accepts@2.0.0: + dependencies: + mime-types: 3.0.1 + negotiator: 1.0.0 + + acorn-import-phases@1.0.4(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn-walk@8.3.4: + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + ajv-formats@2.1.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + + ajv-formats@3.0.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 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-colors@4.1.3: {} + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansi-styles@6.2.1: {} + + ansis@4.1.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + append-field@1.0.0: {} + + arg@4.1.3: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array-timsort@1.0.3: {} + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + asap@2.0.6: {} + + ast-types-flow@0.0.8: {} + + async-function@1.0.0: {} + + asynckit@0.4.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axe-core@4.10.3: {} + + axobject-query@4.1.0: {} + + babel-jest@30.1.2(@babel/core@7.28.4): + dependencies: + '@babel/core': 7.28.4 + '@jest/transform': 30.1.2 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 7.0.1 + babel-preset-jest: 30.0.1(@babel/core@7.28.4) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@7.0.1: + dependencies: + '@babel/helper-plugin-utils': 7.27.1 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 6.0.3 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@30.0.1: + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.4 + '@types/babel__core': 7.20.5 + + babel-preset-current-node-syntax@1.2.0(@babel/core@7.28.4): + dependencies: + '@babel/core': 7.28.4 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.28.4) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.28.4) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.28.4) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.28.4) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.28.4) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.28.4) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.28.4) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.28.4) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.28.4) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.28.4) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.28.4) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.28.4) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.4) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.4) + + babel-preset-jest@30.0.1(@babel/core@7.28.4): + dependencies: + '@babel/core': 7.28.4 + babel-plugin-jest-hoist: 30.0.1 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.4) + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + birecord@0.1.1: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + body-parser@2.2.0: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.1 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 3.0.1 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.25.4: + dependencies: + caniuse-lite: 1.0.30001741 + electron-to-chromium: 1.5.214 + node-releases: 2.0.20 + update-browserslist-db: 1.1.3(browserslist@4.25.4) + + bs-logger@0.2.6: + dependencies: + fast-json-stable-stringify: 2.1.0 + + bser@2.1.1: + dependencies: + node-int64: 0.4.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: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001741: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + char-regex@1.0.2: {} + + chardet@2.1.0: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chownr@3.0.0: {} + + chrome-trace-event@1.0.4: {} + + ci-info@4.3.0: {} + + cjs-module-lexer@2.1.0: {} + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-spinners@2.9.2: {} + + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + + cli-width@4.1.0: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone@1.0.4: {} + + clsx@2.1.1: {} + + co@4.6.0: {} + + collect-v8-coverage@1.0.2: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@2.20.3: {} + + commander@4.1.1: {} + + 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 + + compare-versions@6.1.1: {} + + component-emitter@1.3.1: {} + + 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 + + consola@3.4.2: {} + + content-disposition@1.0.0: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + + convert-source-map@2.0.0: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cookiejar@2.1.4: {} + + core-util-is@1.0.3: {} + + cors@2.8.5: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + cosmiconfig@8.3.6(typescript@5.8.3): + dependencies: + import-fresh: 3.3.1 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + optionalDependencies: + typescript: 5.8.3 + + create-require@1.1.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.1.3: {} + + damerau-levenshtein@1.0.8: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + dedent@1.7.0: {} + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + defaults@1.0.4: + dependencies: + clone: 1.0.4 + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + delayed-stream@1.0.0: {} + + depd@2.0.0: {} + + detect-libc@2.0.4: {} + + detect-newline@3.1.0: {} + + dezalgo@1.0.4: + dependencies: + asap: 2.0.6 + wrappy: 1.0.2 + + diff@4.0.2: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + ee-first@1.1.1: {} + + electron-to-chromium@1.5.214: {} + + emittery@0.13.1: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@2.0.0: {} + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.3 + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.24.0: + dependencies: + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + data-view-buffer: 1.0.2 + data-view-byte-length: 1.0.2 + data-view-byte-offset: 1.0.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-set-tostringtag: 2.1.0 + es-to-primitive: 1.3.0 + function.prototype.name: 1.1.8 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + get-symbol-description: 1.1.0 + globalthis: 1.0.4 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 + is-callable: 1.2.7 + is-data-view: 1.0.2 + is-negative-zero: 2.0.3 + is-regex: 1.2.1 + is-set: 2.0.3 + is-shared-array-buffer: 1.0.4 + is-string: 1.1.1 + is-typed-array: 1.1.15 + is-weakref: 1.1.1 + math-intrinsics: 1.1.0 + object-inspect: 1.13.4 + object-keys: 1.1.1 + object.assign: 4.1.7 + own-keys: 1.0.1 + regexp.prototype.flags: 1.5.4 + safe-array-concat: 1.1.3 + safe-push-apply: 1.0.0 + safe-regex-test: 1.1.0 + set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.3 + typed-array-byte-length: 1.0.3 + typed-array-byte-offset: 1.0.4 + typed-array-length: 1.0.7 + unbox-primitive: 1.1.0 + which-typed-array: 1.1.19 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + esbuild@0.25.9: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.9 + '@esbuild/android-arm': 0.25.9 + '@esbuild/android-arm64': 0.25.9 + '@esbuild/android-x64': 0.25.9 + '@esbuild/darwin-arm64': 0.25.9 + '@esbuild/darwin-x64': 0.25.9 + '@esbuild/freebsd-arm64': 0.25.9 + '@esbuild/freebsd-x64': 0.25.9 + '@esbuild/linux-arm': 0.25.9 + '@esbuild/linux-arm64': 0.25.9 + '@esbuild/linux-ia32': 0.25.9 + '@esbuild/linux-loong64': 0.25.9 + '@esbuild/linux-mips64el': 0.25.9 + '@esbuild/linux-ppc64': 0.25.9 + '@esbuild/linux-riscv64': 0.25.9 + '@esbuild/linux-s390x': 0.25.9 + '@esbuild/linux-x64': 0.25.9 + '@esbuild/netbsd-arm64': 0.25.9 + '@esbuild/netbsd-x64': 0.25.9 + '@esbuild/openbsd-arm64': 0.25.9 + '@esbuild/openbsd-x64': 0.25.9 + '@esbuild/openharmony-arm64': 0.25.9 + '@esbuild/sunos-x64': 0.25.9 + '@esbuild/win32-arm64': 0.25.9 + '@esbuild/win32-ia32': 0.25.9 + '@esbuild/win32-x64': 0.25.9 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@2.0.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-prettier@10.1.8(eslint@9.35.0(jiti@2.5.1)): + dependencies: + eslint: 9.35.0(jiti@2.5.1) + + eslint-plugin-jsx-a11y@6.10.2(eslint@9.35.0(jiti@2.5.1)): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + ast-types-flow: 0.0.8 + axe-core: 4.10.3 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + eslint: 9.35.0(jiti@2.5.1) + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + safe-regex-test: 1.1.0 + string.prototype.includes: 2.0.1 + + eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.35.0(jiti@2.5.1)))(eslint@9.35.0(jiti@2.5.1))(prettier@3.6.2): + dependencies: + eslint: 9.35.0(jiti@2.5.1) + prettier: 3.6.2 + prettier-linter-helpers: 1.0.0 + synckit: 0.11.11 + optionalDependencies: + '@types/eslint': 9.6.1 + eslint-config-prettier: 10.1.8(eslint@9.35.0(jiti@2.5.1)) + + eslint-plugin-react-dom@1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3): + dependencies: + '@eslint-react/ast': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@eslint-react/core': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@eslint-react/eff': 1.53.0 + '@eslint-react/kit': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@eslint-react/shared': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@eslint-react/var': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.42.0 + '@typescript-eslint/types': 8.42.0 + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + compare-versions: 6.1.1 + eslint: 9.35.0(jiti@2.5.1) + string-ts: 2.2.1 + ts-pattern: 5.8.0 + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-hooks@5.2.0(eslint@9.35.0(jiti@2.5.1)): + dependencies: + eslint: 9.35.0(jiti@2.5.1) + + eslint-plugin-react-refresh@0.4.20(eslint@9.35.0(jiti@2.5.1)): + dependencies: + eslint: 9.35.0(jiti@2.5.1) + + eslint-plugin-react-x@1.53.0(eslint@9.35.0(jiti@2.5.1))(ts-api-utils@2.1.0(typescript@5.8.3))(typescript@5.8.3): + dependencies: + '@eslint-react/ast': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@eslint-react/core': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@eslint-react/eff': 1.53.0 + '@eslint-react/kit': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@eslint-react/shared': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@eslint-react/var': 1.53.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.42.0 + '@typescript-eslint/type-utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/types': 8.42.0 + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + compare-versions: 6.1.1 + eslint: 9.35.0(jiti@2.5.1) + is-immutable-type: 5.0.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + string-ts: 2.2.1 + ts-pattern: 5.8.0 + optionalDependencies: + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.35.0(jiti@2.5.1): + dependencies: + '@eslint-community/eslint-utils': 4.8.0(eslint@9.35.0(jiti@2.5.1)) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.21.0 + '@eslint/config-helpers': 0.3.1 + '@eslint/core': 0.15.2 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.35.0 + '@eslint/plugin-kit': 0.3.5 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.1 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.5.1 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esprima@4.0.1: {} + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + etag@1.8.1: {} + + events@3.3.0: {} + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exit-x@0.2.2: {} + + expect@30.1.2: + dependencies: + '@jest/expect-utils': 30.1.2 + '@jest/get-type': 30.1.0 + jest-matcher-utils: 30.1.2 + jest-message-util: 30.1.0 + jest-mock: 30.0.5 + jest-util: 30.0.5 + + express@5.1.0: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.0 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.0 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + mime-types: 3.0.1 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.0 + serve-static: 2.2.0 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-safe-stringify@2.1.1: {} + + fast-uri@3.1.0: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fflate@0.8.2: {} + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + file-type@21.0.0: + dependencies: + '@tokenizer/inflate': 0.2.7 + strtok3: 10.3.4 + token-types: 6.1.1 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + finalhandler@2.1.0: + dependencies: + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fork-ts-checker-webpack-plugin@9.1.0(typescript@5.8.3)(webpack@5.100.2): + dependencies: + '@babel/code-frame': 7.27.1 + chalk: 4.1.2 + chokidar: 4.0.3 + cosmiconfig: 8.3.6(typescript@5.8.3) + 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.2 + tapable: 2.2.3 + typescript: 5.8.3 + webpack: 5.100.2 + + form-data@4.0.4: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + formidable@3.5.4: + dependencies: + '@paralleldrive/cuid2': 2.2.2 + dezalgo: 1.0.4 + once: 1.4.0 + + forwarded@0.2.0: {} + + fresh@2.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.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 + + functions-have-names@1.2.3: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-package-type@0.1.0: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@6.0.1: {} + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + 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@11.0.3: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.1.1 + minimatch: 10.0.3 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.0 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globals@14.0.0: {} + + globals@16.3.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + handlebars@4.7.8: + dependencies: + minimist: 1.2.8 + neo-async: 2.6.2 + source-map: 0.6.1 + wordwrap: 1.0.0 + optionalDependencies: + uglify-js: 3.19.3 + + has-bigints@1.1.0: {} + + has-flag@4.0.0: {} + + has-own-prop@2.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + html-escaper@2.0.2: {} + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + human-signals@2.1.0: {} + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.7.0: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-local@3.2.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + ipaddr.js@1.9.1: {} + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-arrayish@0.2.1: {} + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-callable@1.2.7: {} + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-fullwidth-code-point@3.0.0: {} + + is-generator-fn@2.1.0: {} + + is-generator-function@1.1.0: + dependencies: + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-immutable-type@5.0.1(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3): + dependencies: + '@typescript-eslint/type-utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + eslint: 9.35.0(jiti@2.5.1) + ts-api-utils: 2.1.0(typescript@5.8.3) + ts-declaration-location: 1.0.7(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + is-interactive@1.0.0: {} + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-promise@4.0.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-stream@2.0.1: {} + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + + is-unicode-supported@0.1.0: {} + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@6.0.3: + dependencies: + '@babel/core': 7.28.4 + '@babel/parser': 7.28.4 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.7.2 + transitivePeerDependencies: + - supports-color + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.30 + debug: 4.4.1 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + iterare@1.2.1: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jackspeak@4.1.1: + dependencies: + '@isaacs/cliui': 8.0.2 + + jest-changed-files@30.0.5: + dependencies: + execa: 5.1.1 + jest-util: 30.0.5 + p-limit: 3.1.0 + + jest-circus@30.1.3: + dependencies: + '@jest/environment': 30.1.2 + '@jest/expect': 30.1.2 + '@jest/test-result': 30.1.3 + '@jest/types': 30.0.5 + '@types/node': 22.18.1 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.7.0 + is-generator-fn: 2.1.0 + jest-each: 30.1.0 + jest-matcher-utils: 30.1.2 + jest-message-util: 30.1.0 + jest-runtime: 30.1.3 + jest-snapshot: 30.1.2 + jest-util: 30.0.5 + p-limit: 3.1.0 + pretty-format: 30.0.5 + pure-rand: 7.0.1 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@30.1.3(@types/node@22.18.1)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)): + dependencies: + '@jest/core': 30.1.3(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)) + '@jest/test-result': 30.1.3 + '@jest/types': 30.0.5 + chalk: 4.1.2 + exit-x: 0.2.2 + import-local: 3.2.0 + jest-config: 30.1.3(@types/node@22.18.1)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)) + jest-util: 30.0.5 + jest-validate: 30.1.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + + jest-config@30.1.3(@types/node@22.18.1)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)): + dependencies: + '@babel/core': 7.28.4 + '@jest/get-type': 30.1.0 + '@jest/pattern': 30.0.1 + '@jest/test-sequencer': 30.1.3 + '@jest/types': 30.0.5 + babel-jest: 30.1.2(@babel/core@7.28.4) + chalk: 4.1.2 + ci-info: 4.3.0 + deepmerge: 4.3.1 + glob: 10.4.5 + graceful-fs: 4.2.11 + jest-circus: 30.1.3 + jest-docblock: 30.0.1 + jest-environment-node: 30.1.2 + jest-regex-util: 30.0.1 + jest-resolve: 30.1.3 + jest-runner: 30.1.3 + jest-util: 30.0.5 + jest-validate: 30.1.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 30.0.5 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.18.1 + ts-node: 10.9.2(@types/node@22.18.1)(typescript@5.8.3) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@30.1.2: + dependencies: + '@jest/diff-sequences': 30.0.1 + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + pretty-format: 30.0.5 + + jest-docblock@30.0.1: + dependencies: + detect-newline: 3.1.0 + + jest-each@30.1.0: + dependencies: + '@jest/get-type': 30.1.0 + '@jest/types': 30.0.5 + chalk: 4.1.2 + jest-util: 30.0.5 + pretty-format: 30.0.5 + + jest-environment-node@30.1.2: + dependencies: + '@jest/environment': 30.1.2 + '@jest/fake-timers': 30.1.2 + '@jest/types': 30.0.5 + '@types/node': 22.18.1 + jest-mock: 30.0.5 + jest-util: 30.0.5 + jest-validate: 30.1.0 + + jest-haste-map@30.1.0: + dependencies: + '@jest/types': 30.0.5 + '@types/node': 22.18.1 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 30.0.1 + jest-util: 30.0.5 + jest-worker: 30.1.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-leak-detector@30.1.0: + dependencies: + '@jest/get-type': 30.1.0 + pretty-format: 30.0.5 + + jest-matcher-utils@30.1.2: + dependencies: + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + jest-diff: 30.1.2 + pretty-format: 30.0.5 + + jest-message-util@30.1.0: + dependencies: + '@babel/code-frame': 7.27.1 + '@jest/types': 30.0.5 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 30.0.5 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@30.0.5: + dependencies: + '@jest/types': 30.0.5 + '@types/node': 22.18.1 + jest-util: 30.0.5 + + jest-pnp-resolver@1.2.3(jest-resolve@30.1.3): + optionalDependencies: + jest-resolve: 30.1.3 + + jest-regex-util@30.0.1: {} + + jest-resolve-dependencies@30.1.3: + dependencies: + jest-regex-util: 30.0.1 + jest-snapshot: 30.1.2 + transitivePeerDependencies: + - supports-color + + jest-resolve@30.1.3: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 30.1.0 + jest-pnp-resolver: 1.2.3(jest-resolve@30.1.3) + jest-util: 30.0.5 + jest-validate: 30.1.0 + slash: 3.0.0 + unrs-resolver: 1.11.1 + + jest-runner@30.1.3: + dependencies: + '@jest/console': 30.1.2 + '@jest/environment': 30.1.2 + '@jest/test-result': 30.1.3 + '@jest/transform': 30.1.2 + '@jest/types': 30.0.5 + '@types/node': 22.18.1 + chalk: 4.1.2 + emittery: 0.13.1 + exit-x: 0.2.2 + graceful-fs: 4.2.11 + jest-docblock: 30.0.1 + jest-environment-node: 30.1.2 + jest-haste-map: 30.1.0 + jest-leak-detector: 30.1.0 + jest-message-util: 30.1.0 + jest-resolve: 30.1.3 + jest-runtime: 30.1.3 + jest-util: 30.0.5 + jest-watcher: 30.1.3 + jest-worker: 30.1.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@30.1.3: + dependencies: + '@jest/environment': 30.1.2 + '@jest/fake-timers': 30.1.2 + '@jest/globals': 30.1.2 + '@jest/source-map': 30.0.1 + '@jest/test-result': 30.1.3 + '@jest/transform': 30.1.2 + '@jest/types': 30.0.5 + '@types/node': 22.18.1 + chalk: 4.1.2 + cjs-module-lexer: 2.1.0 + collect-v8-coverage: 1.0.2 + glob: 10.4.5 + graceful-fs: 4.2.11 + jest-haste-map: 30.1.0 + jest-message-util: 30.1.0 + jest-mock: 30.0.5 + jest-regex-util: 30.0.1 + jest-resolve: 30.1.3 + jest-snapshot: 30.1.2 + jest-util: 30.0.5 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-snapshot@30.1.2: + dependencies: + '@babel/core': 7.28.4 + '@babel/generator': 7.28.3 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4) + '@babel/types': 7.28.4 + '@jest/expect-utils': 30.1.2 + '@jest/get-type': 30.1.0 + '@jest/snapshot-utils': 30.1.2 + '@jest/transform': 30.1.2 + '@jest/types': 30.0.5 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.4) + chalk: 4.1.2 + expect: 30.1.2 + graceful-fs: 4.2.11 + jest-diff: 30.1.2 + jest-matcher-utils: 30.1.2 + jest-message-util: 30.1.0 + jest-util: 30.0.5 + pretty-format: 30.0.5 + semver: 7.7.2 + synckit: 0.11.11 + transitivePeerDependencies: + - supports-color + + jest-util@30.0.5: + dependencies: + '@jest/types': 30.0.5 + '@types/node': 22.18.1 + chalk: 4.1.2 + ci-info: 4.3.0 + graceful-fs: 4.2.11 + picomatch: 4.0.3 + + jest-validate@30.1.0: + dependencies: + '@jest/get-type': 30.1.0 + '@jest/types': 30.0.5 + camelcase: 6.3.0 + chalk: 4.1.2 + leven: 3.1.0 + pretty-format: 30.0.5 + + jest-watcher@30.1.3: + dependencies: + '@jest/test-result': 30.1.3 + '@jest/types': 30.0.5 + '@types/node': 22.18.1 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 30.0.5 + string-length: 4.0.2 + + jest-worker@27.5.1: + dependencies: + '@types/node': 22.18.1 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest-worker@30.1.0: + dependencies: + '@types/node': 22.18.1 + '@ungap/structured-clone': 1.3.0 + jest-util: 30.0.5 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@30.1.3(@types/node@22.18.1)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)): + dependencies: + '@jest/core': 30.1.3(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)) + '@jest/types': 30.0.5 + import-local: 3.2.0 + jest-cli: 30.1.3(@types/node@22.18.1)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + + jiti@2.5.1: {} + + js-tokens@4.0.0: {} + + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + jsonc-parser@3.3.1: {} + + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + leven@3.1.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-darwin-arm64@1.30.1: + optional: true + + lightningcss-darwin-x64@1.30.1: + optional: true + + lightningcss-freebsd-x64@1.30.1: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.1: + optional: true + + lightningcss-linux-arm64-gnu@1.30.1: + optional: true + + lightningcss-linux-arm64-musl@1.30.1: + optional: true + + lightningcss-linux-x64-gnu@1.30.1: + optional: true + + lightningcss-linux-x64-musl@1.30.1: + optional: true + + lightningcss-win32-arm64-msvc@1.30.1: + optional: true + + lightningcss-win32-x64-msvc@1.30.1: + optional: true + + lightningcss@1.30.1: + dependencies: + detect-libc: 2.0.4 + optionalDependencies: + lightningcss-darwin-arm64: 1.30.1 + lightningcss-darwin-x64: 1.30.1 + lightningcss-freebsd-x64: 1.30.1 + lightningcss-linux-arm-gnueabihf: 1.30.1 + lightningcss-linux-arm64-gnu: 1.30.1 + lightningcss-linux-arm64-musl: 1.30.1 + lightningcss-linux-x64-gnu: 1.30.1 + lightningcss-linux-x64-musl: 1.30.1 + lightningcss-win32-arm64-msvc: 1.30.1 + lightningcss-win32-x64-msvc: 1.30.1 + + lines-and-columns@1.2.4: {} + + load-esm@1.0.2: {} + + loader-runner@4.3.0: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.memoize@4.1.2: {} + + lodash.merge@4.6.2: {} + + lodash@4.17.21: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + lru-cache@10.4.3: {} + + lru-cache@11.2.1: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.542.0(react@19.1.1): + dependencies: + react: 19.1.1 + + lucide@0.542.0: {} + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magic-string@0.30.18: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + make-dir@4.0.0: + dependencies: + semver: 7.7.2 + + make-error@1.3.6: {} + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + math-intrinsics@1.1.0: {} + + media-typer@0.3.0: {} + + media-typer@1.1.0: {} + + memfs@3.5.3: + dependencies: + fs-monkey: 1.1.0 + + merge-descriptors@2.0.0: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + methods@1.1.2: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-db@1.54.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime-types@3.0.1: + dependencies: + mime-db: 1.54.0 + + mime@2.6.0: {} + + mimic-fn@2.1.0: {} + + minimatch@10.0.3: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minimist@1.2.8: {} + + minipass@7.1.2: {} + + minizlib@3.0.2: + dependencies: + minipass: 7.1.2 + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mkdirp@3.0.1: {} + + 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@2.0.0: {} + + nanoid@3.3.11: {} + + napi-postinstall@0.3.3: {} + + natural-compare@1.4.0: {} + + negotiator@1.0.0: {} + + neo-async@2.6.2: {} + + node-abort-controller@3.1.1: {} + + node-emoji@1.11.0: + dependencies: + lodash: 4.17.21 + + node-int64@0.4.0: {} + + node-releases@2.0.20: {} + + normalize-path@3.0.0: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parseurl@1.3.3: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-scurry@2.0.0: + dependencies: + lru-cache: 11.2.1 + minipass: 7.1.2 + + path-to-regexp@8.2.0: {} + + path-type@4.0.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.2: {} + + picomatch@4.0.3: {} + + pirates@4.0.7: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + pluralize@8.0.0: {} + + possible-typed-array-names@1.1.0: {} + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@3.6.2: {} + + pretty-format@30.0.5: + dependencies: + '@jest/schemas': 30.0.5 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + punycode@2.3.1: {} + + pure-rand@7.0.1: {} + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + + queue-microtask@1.2.3: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + range-parser@1.2.1: {} + + raw-body@3.0.1: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.7.0 + unpipe: 1.0.0 + + react-dom@19.1.1(react@19.1.1): + dependencies: + react: 19.1.1 + scheduler: 0.26.0 + + react-is@18.3.1: {} + + react-refresh@0.17.0: {} + + react@19.1.1: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdirp@4.1.2: {} + + reflect-metadata@0.2.2: {} + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-errors: 1.3.0 + get-proto: 1.0.1 + gopd: 1.2.0 + set-function-name: 2.0.2 + + repeat-string@1.6.1: {} + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + reusify@1.1.0: {} + + rollup@4.50.1: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.50.1 + '@rollup/rollup-android-arm64': 4.50.1 + '@rollup/rollup-darwin-arm64': 4.50.1 + '@rollup/rollup-darwin-x64': 4.50.1 + '@rollup/rollup-freebsd-arm64': 4.50.1 + '@rollup/rollup-freebsd-x64': 4.50.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.50.1 + '@rollup/rollup-linux-arm-musleabihf': 4.50.1 + '@rollup/rollup-linux-arm64-gnu': 4.50.1 + '@rollup/rollup-linux-arm64-musl': 4.50.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.50.1 + '@rollup/rollup-linux-ppc64-gnu': 4.50.1 + '@rollup/rollup-linux-riscv64-gnu': 4.50.1 + '@rollup/rollup-linux-riscv64-musl': 4.50.1 + '@rollup/rollup-linux-s390x-gnu': 4.50.1 + '@rollup/rollup-linux-x64-gnu': 4.50.1 + '@rollup/rollup-linux-x64-musl': 4.50.1 + '@rollup/rollup-openharmony-arm64': 4.50.1 + '@rollup/rollup-win32-arm64-msvc': 4.50.1 + '@rollup/rollup-win32-ia32-msvc': 4.50.1 + '@rollup/rollup-win32-x64-msvc': 4.50.1 + fsevents: 2.3.3 + + router@2.2.0: + dependencies: + debug: 4.4.1 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.2.0 + transitivePeerDependencies: + - supports-color + + 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 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.2.1: {} + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safer-buffer@2.1.2: {} + + scheduler@0.26.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.2: + 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) + + semver@6.3.1: {} + + semver@7.7.2: {} + + send@1.2.0: + dependencies: + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.0 + mime-types: 3.0.1 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + serve-static@2.2.0: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.0 + transitivePeerDependencies: + - supports-color + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + slash@3.0.0: {} + + source-map-js@1.2.1: {} + + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + source-map@0.7.4: {} + + source-map@0.7.6: {} + + sprintf-js@1.0.3: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + statuses@2.0.1: {} + + statuses@2.0.2: {} + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + streamsearch@1.1.0: {} + + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + + string-ts@2.2.1: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.2.0 + + strip-bom@3.0.0: {} + + strip-bom@4.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-json-comments@3.1.1: {} + + strtok3@10.3.4: + dependencies: + '@tokenizer/token': 0.3.0 + + superagent@10.2.3: + dependencies: + component-emitter: 1.3.1 + cookiejar: 2.1.4 + debug: 4.4.1 + fast-safe-stringify: 2.1.1 + form-data: 4.0.4 + formidable: 3.5.4 + methods: 1.1.2 + mime: 2.6.0 + qs: 6.14.0 + transitivePeerDependencies: + - supports-color + + supertest@7.1.4: + dependencies: + methods: 1.1.2 + superagent: 10.2.3 + transitivePeerDependencies: + - supports-color + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + symbol-observable@4.0.0: {} + + synckit@0.11.11: + dependencies: + '@pkgr/core': 0.2.9 + + tailwind-merge@3.3.1: {} + + tailwindcss@4.1.13: {} + + tapable@2.2.3: {} + + tar@7.4.3: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.0.2 + mkdirp: 3.0.1 + yallist: 5.0.0 + + terser-webpack-plugin@5.3.14(webpack@5.100.2): + dependencies: + '@jridgewell/trace-mapping': 0.3.30 + jest-worker: 27.5.1 + schema-utils: 4.3.2 + serialize-javascript: 6.0.2 + terser: 5.44.0 + webpack: 5.100.2 + + terser@5.44.0: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tmpl@1.0.5: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + token-types@6.1.1: + dependencies: + '@borewit/text-codec': 0.1.1 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + + tree-kill@1.2.2: {} + + ts-api-utils@2.1.0(typescript@5.8.3): + dependencies: + typescript: 5.8.3 + + ts-declaration-location@1.0.7(typescript@5.8.3): + dependencies: + picomatch: 4.0.3 + typescript: 5.8.3 + + ts-jest@29.4.1(@babel/core@7.28.4)(@jest/transform@30.1.2)(@jest/types@30.0.5)(babel-jest@30.1.2(@babel/core@7.28.4))(jest-util@30.0.5)(jest@30.1.3(@types/node@22.18.1)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)))(typescript@5.8.3): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + handlebars: 4.7.8 + jest: 30.1.3(@types/node@22.18.1)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)) + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.2 + type-fest: 4.41.0 + typescript: 5.8.3 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.28.4 + '@jest/transform': 30.1.2 + '@jest/types': 30.0.5 + babel-jest: 30.1.2(@babel/core@7.28.4) + jest-util: 30.0.5 + + ts-loader@9.5.4(typescript@5.8.3)(webpack@5.100.2): + dependencies: + chalk: 4.1.2 + enhanced-resolve: 5.18.3 + micromatch: 4.0.8 + semver: 7.7.2 + source-map: 0.7.6 + typescript: 5.8.3 + webpack: 5.100.2 + + ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.18.1 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.8.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + ts-pattern@5.8.0: {} + + tsconfig-paths-webpack-plugin@4.2.0: + dependencies: + chalk: 4.1.2 + enhanced-resolve: 5.18.3 + tapable: 2.2.3 + tsconfig-paths: 4.2.0 + + tsconfig-paths@4.2.0: + dependencies: + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + tw-animate-css@1.3.8: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-detect@4.0.8: {} + + 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 + media-typer: 1.1.0 + mime-types: 3.0.1 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typedarray@0.0.6: {} + + typescript-eslint@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/parser': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.42.0(typescript@5.8.3) + '@typescript-eslint/utils': 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) + eslint: 9.35.0(jiti@2.5.1) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + typescript@5.8.3: {} + + uglify-js@3.19.3: + optional: true + + 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 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.21.0: {} + + universalify@2.0.1: {} + + unpipe@1.0.0: {} + + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.3 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + + update-browserslist-db@1.1.3(browserslist@4.25.4): + dependencies: + browserslist: 4.25.4 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + v8-compile-cache-lib@3.0.1: {} + + v8-to-istanbul@9.3.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.30 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + + vary@1.1.2: {} + + vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0): + dependencies: + esbuild: 0.25.9 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.50.1 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 22.18.1 + fsevents: 2.3.3 + jiti: 2.5.1 + lightningcss: 1.30.1 + terser: 5.44.0 + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + watchpack@2.4.4: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + + webpack-node-externals@3.0.0: {} + + webpack-sources@3.3.3: {} + + webpack@5.100.2: + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.15.0 + acorn-import-phases: 1.0.4(acorn@8.15.0) + browserslist: 4.25.4 + 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.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.3.2 + tapable: 2.2.3 + terser-webpack-plugin: 5.3.14(webpack@5.100.2) + watchpack: 2.4.4 + webpack-sources: 3.3.3 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.0 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wordwrap@1.0.0: {} + + 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 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + write-file-atomic@5.0.1: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + + xtend@4.0.2: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yallist@5.0.0: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} + + yoctocolors-cjs@2.1.3: {} + + zod@4.1.5: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..852bf6b --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - apps/* diff --git a/turbo.json b/turbo.json new file mode 100644 index 0000000..70e6c80 --- /dev/null +++ b/turbo.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://turborepo.org/schema.json", + "globalDependencies": ["**/.env.*local"], + "tasks": { + "build": { + "dependsOn": ["^build"], + "outputs": ["dist/**", ".next/**"] + }, + "lint": { + "outputs": [] + }, + "lint:fix": { + "outputs": [] + }, + "type-check": { + "outputs": [] + }, + "test": { + "cache": false + } + } +} From 41b635aaee98823d84349efe2e98ce984b809d3e Mon Sep 17 00:00:00 2001 From: Joaquin Date: Sun, 7 Sep 2025 16:35:53 -0300 Subject: [PATCH 02/17] Fix lint errors in apps/frontend --- apps/frontend/src/App.tsx | 8 +++++--- apps/frontend/src/lib/utils.ts | 6 +++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/frontend/src/App.tsx b/apps/frontend/src/App.tsx index 3d37e1b..4d6f9ed 100644 --- a/apps/frontend/src/App.tsx +++ b/apps/frontend/src/App.tsx @@ -9,16 +9,18 @@ function App() { return ( <>

Vite + React

- +

Edit src/App.tsx and save to test HMR

diff --git a/apps/frontend/src/lib/utils.ts b/apps/frontend/src/lib/utils.ts index bd0c391..2819a83 100644 --- a/apps/frontend/src/lib/utils.ts +++ b/apps/frontend/src/lib/utils.ts @@ -1,6 +1,6 @@ -import { clsx, type ClassValue } from "clsx" -import { twMerge } from "tailwind-merge" +import { clsx, type ClassValue } from 'clsx'; +import { twMerge } from 'tailwind-merge'; export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) + return twMerge(clsx(inputs)); } From 5b871d7b18dba86772c654a6329b5bacd153d4b2 Mon Sep 17 00:00:00 2001 From: Joaquin Date: Mon, 8 Sep 2025 01:07:41 -0300 Subject: [PATCH 03/17] feat(backend): restructure and implement campaigns and content management modules Removed unused `app.controller` and its test file Updated `app.module` to integrate new modules Added `campaigns` module: - `campaign.entity.ts` for Campaign entity definition - `campaigns.controller.ts` for Campaigns API endpoints - `campaigns.service.ts` for Campaigns business logic - `create-campaign.dto.ts` for Campaign creation validation Added `content-pieces` module: - `content-piece.entity.ts` for ContentPiece entity definition - `content-pieces.controller.ts` for ContentPieces API endpoints - `content-pieces.service.ts` for ContentPieces business logic - DTOs for create and update operations - `review-state.enum.ts` for review state management Added `content-piece-translations` module: - `content-piece-translation.entity.ts` for ContentPieceTranslation entity - `content-piece-translation.controller.ts` for API endpoints - `content-piece-translation.service.ts` for business logic - DTOs for create and update operations Updated `eslint.config.mjs` and `package.json` for new configurations - Add required dependencies like typeORM and class-validator - Config eslint to prevent unnecesary error messages Updated `main.ts` to reflect new application structure --- apps/backend/eslint.config.mjs | 8 +- apps/backend/package.json | 10 +- apps/backend/src/app.controller.spec.ts | 22 - apps/backend/src/app.controller.ts | 12 - apps/backend/src/app.module.ts | 27 +- apps/backend/src/campaigns/campaign.entity.ts | 23 + .../src/campaigns/campaigns.controller.ts | 40 + .../backend/src/campaigns/campaigns.module.ts | 13 + .../src/campaigns/campaigns.service.ts | 29 + .../src/campaigns/dto/create-campaign.dto.ts | 20 + .../content-piece-translation.controller.ts | 67 ++ .../content-piece-translation.entity.ts | 32 + .../content-piece-translation.module.ts | 17 + .../content-piece-translation.service.ts | 49 + .../create-content-piece-translation.dto.ts | 41 + .../update-content-piece-translation.dto.ts | 21 + .../content-pieces/content-piece.entity.ts | 43 + .../content-pieces.controller.ts | 55 + .../content-pieces/content-pieces.module.ts | 13 + .../content-pieces/content-pieces.service.ts | 54 + .../dto/create-content-piece.dto.ts | 20 + .../dto/update-content-piece.dto.ts | 17 + .../src/content-pieces/review-state.enum.ts | 7 + apps/backend/src/main.ts | 14 + pnpm-lock.yaml | 1018 ++++++++++++++++- 25 files changed, 1613 insertions(+), 59 deletions(-) delete mode 100644 apps/backend/src/app.controller.spec.ts delete mode 100644 apps/backend/src/app.controller.ts create mode 100644 apps/backend/src/campaigns/campaign.entity.ts create mode 100644 apps/backend/src/campaigns/campaigns.controller.ts create mode 100644 apps/backend/src/campaigns/campaigns.module.ts create mode 100644 apps/backend/src/campaigns/campaigns.service.ts create mode 100644 apps/backend/src/campaigns/dto/create-campaign.dto.ts create mode 100644 apps/backend/src/content-piece-translations/content-piece-translation.controller.ts create mode 100644 apps/backend/src/content-piece-translations/content-piece-translation.entity.ts create mode 100644 apps/backend/src/content-piece-translations/content-piece-translation.module.ts create mode 100644 apps/backend/src/content-piece-translations/content-piece-translation.service.ts create mode 100644 apps/backend/src/content-piece-translations/dto/create-content-piece-translation.dto.ts create mode 100644 apps/backend/src/content-piece-translations/dto/update-content-piece-translation.dto.ts create mode 100644 apps/backend/src/content-pieces/content-piece.entity.ts create mode 100644 apps/backend/src/content-pieces/content-pieces.controller.ts create mode 100644 apps/backend/src/content-pieces/content-pieces.module.ts create mode 100644 apps/backend/src/content-pieces/content-pieces.service.ts create mode 100644 apps/backend/src/content-pieces/dto/create-content-piece.dto.ts create mode 100644 apps/backend/src/content-pieces/dto/update-content-piece.dto.ts create mode 100644 apps/backend/src/content-pieces/review-state.enum.ts diff --git a/apps/backend/eslint.config.mjs b/apps/backend/eslint.config.mjs index 786418b..e83bac7 100644 --- a/apps/backend/eslint.config.mjs +++ b/apps/backend/eslint.config.mjs @@ -19,16 +19,16 @@ export default [ }, sourceType: 'commonjs', parserOptions: { - projectService: true, tsconfigRootDir: import.meta.dirname, }, }, }, { rules: { - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-floating-promises': 'warn', - '@typescript-eslint/no-unsafe-argument': 'warn', + '@typescript-eslint/no-unsafe-call': 'error', + '@typescript-eslint/no-unsafe-member-access': 'error', + '@typescript-eslint/no-unsafe-assignment': 'error', + '@typescript-eslint/no-unsafe-return': 'error', }, }, ]; diff --git a/apps/backend/package.json b/apps/backend/package.json index 372f890..5ff3bd5 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -21,10 +21,18 @@ }, "dependencies": { "@nestjs/common": "^11.0.1", + "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.0.1", + "@nestjs/mapped-types": "^2.1.0", "@nestjs/platform-express": "^11.0.1", + "@nestjs/swagger": "^11.2.0", + "@nestjs/typeorm": "^11.0.0", + "class-validator": "^0.14.2", + "pg": "^8.16.3", "reflect-metadata": "^0.2.2", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "swagger-ui-express": "^5.0.1", + "typeorm": "^0.3.26" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", diff --git a/apps/backend/src/app.controller.spec.ts b/apps/backend/src/app.controller.spec.ts deleted file mode 100644 index d22f389..0000000 --- a/apps/backend/src/app.controller.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { AppController } from './app.controller'; -import { AppService } from './app.service'; - -describe('AppController', () => { - let appController: AppController; - - beforeEach(async () => { - const app: TestingModule = await Test.createTestingModule({ - controllers: [AppController], - providers: [AppService], - }).compile(); - - appController = app.get(AppController); - }); - - describe('root', () => { - it('should return "Hello World!"', () => { - expect(appController.getHello()).toBe('Hello World!'); - }); - }); -}); diff --git a/apps/backend/src/app.controller.ts b/apps/backend/src/app.controller.ts deleted file mode 100644 index cce879e..0000000 --- a/apps/backend/src/app.controller.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Controller, Get } from '@nestjs/common'; -import { AppService } from './app.service'; - -@Controller() -export class AppController { - constructor(private readonly appService: AppService) {} - - @Get() - getHello(): string { - return this.appService.getHello(); - } -} diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts index 8662803..88778ac 100644 --- a/apps/backend/src/app.module.ts +++ b/apps/backend/src/app.module.ts @@ -1,10 +1,27 @@ import { Module } from '@nestjs/common'; -import { AppController } from './app.controller'; -import { AppService } from './app.service'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { ConfigModule } from '@nestjs/config'; +import { CampaignsModule } from './campaigns/campaigns.module'; +import { ContentPiecesModule } from './content-pieces/content-pieces.module'; +import { ContentPieceTranslationModule } from './content-piece-translations/content-piece-translation.module'; @Module({ - imports: [], - controllers: [AppController], - providers: [AppService], + imports: [ + ConfigModule.forRoot(), + + TypeOrmModule.forRoot({ + type: 'postgres', + url: process.env.DATABASE_URL, + autoLoadEntities: true, // Automatically load all entities + synchronize: true, // Auto-create database tables (for development only) + }), + + // Feature modules + CampaignsModule, + ContentPiecesModule, + ContentPieceTranslationModule, + ], + controllers: [], + providers: [], }) export class AppModule {} diff --git a/apps/backend/src/campaigns/campaign.entity.ts b/apps/backend/src/campaigns/campaign.entity.ts new file mode 100644 index 0000000..04fee53 --- /dev/null +++ b/apps/backend/src/campaigns/campaign.entity.ts @@ -0,0 +1,23 @@ +import { Entity, PrimaryGeneratedColumn, CreateDateColumn, Column, OneToMany, UpdateDateColumn } from 'typeorm'; +import { ContentPiece } from '../content-pieces/content-piece.entity'; + +@Entity() +export class Campaign { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column() + name: string; + + @Column() + description: string; + + @CreateDateColumn() + createdAt: Date; + + @UpdateDateColumn() + updatedAt: Date; + + @OneToMany(() => ContentPiece, (contentPiece) => contentPiece.campaign) + contentPieces: ContentPiece[]; +} diff --git a/apps/backend/src/campaigns/campaigns.controller.ts b/apps/backend/src/campaigns/campaigns.controller.ts new file mode 100644 index 0000000..28b803f --- /dev/null +++ b/apps/backend/src/campaigns/campaigns.controller.ts @@ -0,0 +1,40 @@ +import { Controller, Get, Post, Body, Param, NotFoundException } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiBody, ApiParam } from '@nestjs/swagger'; +import { CampaignsService } from './campaigns.service'; +import { CreateCampaignDto } from './dto/create-campaign.dto'; +import { Campaign } from './campaign.entity'; + +@ApiTags('campaigns') +@Controller('campaigns') +export class CampaignsController { + constructor(private readonly campaignsService: CampaignsService) {} + + @Post() + @ApiOperation({ summary: 'Create a new campaign' }) + async create(@Body() createCampaignDto: CreateCampaignDto): Promise { + return this.campaignsService.create(createCampaignDto); + } + + @Get() + @ApiOperation({ summary: 'Get all campaigns' }) + async findAll(): Promise { + // This endpoint returns a list of all campaigns. + return this.campaignsService.findAll(); + } + + @Get(':id') + @ApiOperation({ summary: 'Get a campaign by ID' }) + @ApiParam({ name: 'id', description: 'The ID of the campaign' }) + async findOne(@Param('id') id: string): Promise { + // This endpoint returns a single campaign by its ID. + try { + return await this.campaignsService.findOne(id); + } catch (error) { + // Handle the case where the campaign is not found. + if (error instanceof NotFoundException) { + throw new NotFoundException(error.message); + } + throw error; + } + } +} diff --git a/apps/backend/src/campaigns/campaigns.module.ts b/apps/backend/src/campaigns/campaigns.module.ts new file mode 100644 index 0000000..85dfc57 --- /dev/null +++ b/apps/backend/src/campaigns/campaigns.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Campaign } from './campaign.entity'; +import { CampaignsService } from './campaigns.service'; +import { CampaignsController } from './campaigns.controller'; + +@Module({ + imports: [TypeOrmModule.forFeature([Campaign])], + providers: [CampaignsService], + controllers: [CampaignsController], + exports: [CampaignsService], +}) +export class CampaignsModule {} diff --git a/apps/backend/src/campaigns/campaigns.service.ts b/apps/backend/src/campaigns/campaigns.service.ts new file mode 100644 index 0000000..63f7d4a --- /dev/null +++ b/apps/backend/src/campaigns/campaigns.service.ts @@ -0,0 +1,29 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { Campaign } from './campaign.entity'; + +@Injectable() +export class CampaignsService { + constructor( + @InjectRepository(Campaign) + private readonly campaignRepository: Repository, + ) {} + + async create(createCampaignDto: Partial): Promise { + const newCampaign = this.campaignRepository.create(createCampaignDto); + return this.campaignRepository.save(newCampaign); + } + + async findOne(id: string): Promise { + const campaign = await this.campaignRepository.findOne({ where: { id } }); + if (!campaign) { + throw new NotFoundException(`Campaign with ID ${id} not found`); + } + return campaign; + } + + async findAll(): Promise { + return this.campaignRepository.find(); + } +} diff --git a/apps/backend/src/campaigns/dto/create-campaign.dto.ts b/apps/backend/src/campaigns/dto/create-campaign.dto.ts new file mode 100644 index 0000000..245a322 --- /dev/null +++ b/apps/backend/src/campaigns/dto/create-campaign.dto.ts @@ -0,0 +1,20 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsString, IsNotEmpty } from 'class-validator'; + +export class CreateCampaignDto { + @ApiProperty({ + description: 'The name of the campaign', + example: 'Summer Socials 2025', + }) + @IsString() + @IsNotEmpty() + name: string; + + @ApiProperty({ + description: 'A brief description of the campaign', + example: 'Marketing content for the summer product line.', + }) + @IsString() + @IsNotEmpty() + description: string; +} diff --git a/apps/backend/src/content-piece-translations/content-piece-translation.controller.ts b/apps/backend/src/content-piece-translations/content-piece-translation.controller.ts new file mode 100644 index 0000000..87a0267 --- /dev/null +++ b/apps/backend/src/content-piece-translations/content-piece-translation.controller.ts @@ -0,0 +1,67 @@ +import { Controller, Get, Post, Body, Param, Patch, Delete, NotFoundException } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiParam } from '@nestjs/swagger'; +import { ContentPieceTranslationService } from './content-piece-translation.service'; +import { ContentPieceTranslation } from './content-piece-translation.entity'; +import { CreateContentPieceTranslationDto } from './dto/create-content-piece-translation.dto'; +import { UpdateContentPieceTranslationDto } from './dto/update-content-piece-translation.dto'; +import { ContentPiecesService } from 'src/content-pieces/content-pieces.service'; + +@ApiTags('content-piece-translations') +@Controller('content-piece-translations') +export class ContentPieceTranslationController { + constructor( + private readonly translationService: ContentPieceTranslationService, + private readonly contentPieceService: ContentPiecesService, + ) {} + + @Post() + @ApiOperation({ summary: 'Create a new content piece translation' }) + async create(@Body() createTranslationDto: CreateContentPieceTranslationDto): Promise { + return this.translationService.create(createTranslationDto); + } + + @Get() + @ApiOperation({ summary: 'Get all content piece translations' }) + async findAll(@Param('contentPieceId') contentPieceId: string | undefined): Promise { + if (contentPieceId) { + const contentPiece = await this.contentPieceService.findOne(contentPieceId); + if (!contentPiece) { + throw new NotFoundException(`Content piece with ID ${contentPieceId} not found`); + } + return this.translationService.findAll(contentPiece); + } + + return this.translationService.findAll(); + } + + @Get(':id') + @ApiOperation({ summary: 'Get a content piece translation by ID' }) + @ApiParam({ name: 'id', description: 'The ID of the translation' }) + async findOne(@Param('id') id: string): Promise { + try { + return await this.translationService.findOne(id); + } catch (error) { + if (error instanceof NotFoundException) { + throw new NotFoundException(error.message); + } + throw error; + } + } + + @Patch(':id') + @ApiOperation({ summary: 'Update a content piece translation by ID' }) + @ApiParam({ name: 'id', description: 'The ID of the translation to update' }) + async update( + @Param('id') id: string, + @Body() updateTranslationDto: UpdateContentPieceTranslationDto, + ): Promise { + return this.translationService.update(id, updateTranslationDto); + } + + @Delete(':id') + @ApiOperation({ summary: 'Delete a content piece translation by ID' }) + @ApiParam({ name: 'id', description: 'The ID of the translation to delete' }) + async remove(@Param('id') id: string): Promise { + return this.translationService.remove(id); + } +} diff --git a/apps/backend/src/content-piece-translations/content-piece-translation.entity.ts b/apps/backend/src/content-piece-translations/content-piece-translation.entity.ts new file mode 100644 index 0000000..5e1907c --- /dev/null +++ b/apps/backend/src/content-piece-translations/content-piece-translation.entity.ts @@ -0,0 +1,32 @@ +import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn, UpdateDateColumn } from 'typeorm'; +import { ContentPiece } from '../content-pieces/content-piece.entity'; + +@Entity() +export class ContentPieceTranslation { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column() + languageCode: string; + + @Column() + translatedTitle: string; + + @Column() + translatedDescription: string; + + @Column({ default: false }) + isAIGenerated: boolean; + + @Column({ default: false }) + isHumanEdited: boolean; + + @CreateDateColumn() + createdAt: Date; + + @UpdateDateColumn() + updatedAt: Date; + + @ManyToOne(() => ContentPiece, (contentPiece): ContentPieceTranslation[] => contentPiece.translations) + contentPiece: ContentPiece; +} diff --git a/apps/backend/src/content-piece-translations/content-piece-translation.module.ts b/apps/backend/src/content-piece-translations/content-piece-translation.module.ts new file mode 100644 index 0000000..898e54e --- /dev/null +++ b/apps/backend/src/content-piece-translations/content-piece-translation.module.ts @@ -0,0 +1,17 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { ContentPieceTranslation } from './content-piece-translation.entity'; +import { ContentPieceTranslationService } from './content-piece-translation.service'; +import { ContentPieceTranslationController } from './content-piece-translation.controller'; +import { ContentPiecesModule } from 'src/content-pieces/content-pieces.module'; + +@Module({ + imports: [ + TypeOrmModule.forFeature([ContentPieceTranslation]), + ContentPiecesModule, + ], + controllers: [ContentPieceTranslationController], + providers: [ContentPieceTranslationService], + exports: [ContentPieceTranslationService], +}) +export class ContentPieceTranslationModule {} diff --git a/apps/backend/src/content-piece-translations/content-piece-translation.service.ts b/apps/backend/src/content-piece-translations/content-piece-translation.service.ts new file mode 100644 index 0000000..54b9491 --- /dev/null +++ b/apps/backend/src/content-piece-translations/content-piece-translation.service.ts @@ -0,0 +1,49 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { ContentPieceTranslation } from './content-piece-translation.entity'; +import { CreateContentPieceTranslationDto } from './dto/create-content-piece-translation.dto'; +import { UpdateContentPieceTranslationDto } from './dto/update-content-piece-translation.dto'; +import { ContentPiece } from 'src/content-pieces/content-piece.entity'; + +@Injectable() +export class ContentPieceTranslationService { + constructor( + @InjectRepository(ContentPieceTranslation) + private readonly translationRepository: Repository, + ) {} + + async create(createTranslationDto: CreateContentPieceTranslationDto): Promise { + const newTranslation = this.translationRepository.create(createTranslationDto); + return this.translationRepository.save(newTranslation); + } + + async findAll(contentPiece: ContentPiece | undefined = undefined): Promise { + if (!contentPiece) { + return this.translationRepository.find({ relations: ['contentPiece'] }); + } + + return this.translationRepository.find({ where: { contentPiece }, relations: ['contentPiece'] }); + } + + async findOne(id: string): Promise { + const translation = await this.translationRepository.findOne({ where: { id }, relations: ['contentPiece'] }); + if (!translation) { + throw new NotFoundException(`Translation with ID ${id} not found`); + } + return translation; + } + + async update(id: string, updateTranslationDto: UpdateContentPieceTranslationDto): Promise { + const translation = await this.findOne(id); + this.translationRepository.merge(translation, updateTranslationDto); + return this.translationRepository.save(translation); + } + + async remove(id: string): Promise { + const result = await this.translationRepository.delete(id); + if (result.affected === 0) { + throw new NotFoundException(`Translation with ID ${id} not found`); + } + } +} diff --git a/apps/backend/src/content-piece-translations/dto/create-content-piece-translation.dto.ts b/apps/backend/src/content-piece-translations/dto/create-content-piece-translation.dto.ts new file mode 100644 index 0000000..ea24ce6 --- /dev/null +++ b/apps/backend/src/content-piece-translations/dto/create-content-piece-translation.dto.ts @@ -0,0 +1,41 @@ +import { IsString, IsNotEmpty, IsBoolean } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; + +export class CreateContentPieceTranslationDto { + @ApiProperty({ + description: 'The ID of the content piece this translation belongs to', + example: '1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d', + }) + @IsString() + @IsNotEmpty() + contentPieceId: string; + + @ApiProperty({ description: 'The language code for the translation', example: 'es' }) + @IsString() + @IsNotEmpty() + languageCode: string; + + @ApiProperty({ description: 'The translated title', example: 'Hola Mundo' }) + @IsString() + @IsNotEmpty() + translatedTitle: string; + + @ApiProperty({ description: 'The translated description', example: 'Una breve descripcion.' }) + @IsString() + @IsNotEmpty() + translatedDescription: string; + + @ApiProperty({ + description: 'A flag to indicate if the translation was AI-generated', + example: true, + }) + @IsBoolean() + isAIGenerated: boolean; + + @ApiProperty({ + description: 'A flag to indicate if a human has edited the translation', + example: false, + }) + @IsBoolean() + isHumanEdited: boolean; +} diff --git a/apps/backend/src/content-piece-translations/dto/update-content-piece-translation.dto.ts b/apps/backend/src/content-piece-translations/dto/update-content-piece-translation.dto.ts new file mode 100644 index 0000000..434cd95 --- /dev/null +++ b/apps/backend/src/content-piece-translations/dto/update-content-piece-translation.dto.ts @@ -0,0 +1,21 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateContentPieceTranslationDto } from './create-content-piece-translation.dto'; +import { ApiProperty } from '@nestjs/swagger'; +import { IsOptional, IsString, IsBoolean } from 'class-validator'; + +export class UpdateContentPieceTranslationDto extends PartialType(CreateContentPieceTranslationDto) { + @ApiProperty({ description: 'The translated title', required: false }) + @IsOptional() + @IsString() + translatedTitle?: string; + + @ApiProperty({ description: 'The translated description', required: false }) + @IsOptional() + @IsString() + translatedDescription?: string; + + @ApiProperty({ description: 'A flag to indicate if a human has edited the translation', required: false }) + @IsOptional() + @IsBoolean() + isHumanEdited?: boolean; +} diff --git a/apps/backend/src/content-pieces/content-piece.entity.ts b/apps/backend/src/content-pieces/content-piece.entity.ts new file mode 100644 index 0000000..15f06a4 --- /dev/null +++ b/apps/backend/src/content-pieces/content-piece.entity.ts @@ -0,0 +1,43 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + ManyToOne, + OneToMany, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm'; +import { Campaign } from '../campaigns/campaign.entity'; +import { ContentPieceTranslation } from '../content-piece-translations/content-piece-translation.entity'; +import { ReviewState } from './review-state.enum'; + +@Entity() +export class ContentPiece { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column({ + type: 'enum', + enum: ReviewState, + default: ReviewState.Draft, + }) + reviewState: ReviewState; + + @Column({ type: 'jsonb', nullable: true }) + aiGeneratedDraft: object; + + @Column() + sourceLanguage: string; + + @CreateDateColumn() + createdAt: Date; + + @UpdateDateColumn() + updatedAt: Date; + + @ManyToOne(() => Campaign, (campaign) => campaign.contentPieces) + campaign: Campaign; + + @OneToMany(() => ContentPieceTranslation, (translation) => translation.contentPiece) + translations: ContentPieceTranslation[]; +} diff --git a/apps/backend/src/content-pieces/content-pieces.controller.ts b/apps/backend/src/content-pieces/content-pieces.controller.ts new file mode 100644 index 0000000..5e9c954 --- /dev/null +++ b/apps/backend/src/content-pieces/content-pieces.controller.ts @@ -0,0 +1,55 @@ +import { Controller, Get, Post, Body, Param, Patch, Delete, NotFoundException } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiBody, ApiParam } from '@nestjs/swagger'; +import { ContentPiecesService } from './content-pieces.service'; +import { ContentPiece } from './content-piece.entity'; +import { CreateContentPieceDto } from './dto/create-content-piece.dto'; +import { UpdateContentPieceDto } from './dto/update-content-piece.dto'; + +@ApiTags('content-pieces') +@Controller('content-pieces') +export class ContentPiecesController { + constructor(private readonly contentPiecesService: ContentPiecesService) {} + + @Post() + @ApiOperation({ summary: 'Create a new content piece' }) + async create(@Body() createContentPieceDto: CreateContentPieceDto): Promise { + return this.contentPiecesService.create(createContentPieceDto); + } + + @Get() + @ApiOperation({ summary: 'Get all content pieces' }) + async findAll(@Param('campaignId') campaignId: string | undefined): Promise { + return this.contentPiecesService.findAll(campaignId); + } + + @Get(':id') + @ApiOperation({ summary: 'Get a content piece by ID' }) + @ApiParam({ name: 'id', description: 'The ID of the content piece' }) + async findOne(@Param('id') id: string): Promise { + try { + return await this.contentPiecesService.findOne(id); + } catch (error) { + if (error instanceof NotFoundException) { + throw new NotFoundException(error.message); + } + throw error; + } + } + + @Patch(':id') + @ApiOperation({ summary: 'Update a content piece by ID' }) + @ApiParam({ name: 'id', description: 'The ID of the content piece to update' }) + async update( + @Param('id') id: string, + @Body() updateContentPieceDto: UpdateContentPieceDto, + ): Promise { + return this.contentPiecesService.update(id, updateContentPieceDto); + } + + @Delete(':id') + @ApiOperation({ summary: 'Delete a content piece by ID' }) + @ApiParam({ name: 'id', description: 'The ID of the content piece to delete' }) + async remove(@Param('id') id: string): Promise { + return this.contentPiecesService.remove(id); + } +} diff --git a/apps/backend/src/content-pieces/content-pieces.module.ts b/apps/backend/src/content-pieces/content-pieces.module.ts new file mode 100644 index 0000000..23b4a21 --- /dev/null +++ b/apps/backend/src/content-pieces/content-pieces.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { ContentPiece } from './content-piece.entity'; +import { ContentPiecesService } from './content-pieces.service'; +import { ContentPiecesController } from './content-pieces.controller'; + +@Module({ + imports: [TypeOrmModule.forFeature([ContentPiece])], + controllers: [ContentPiecesController], + providers: [ContentPiecesService], + exports: [ContentPiecesService], +}) +export class ContentPiecesModule {} diff --git a/apps/backend/src/content-pieces/content-pieces.service.ts b/apps/backend/src/content-pieces/content-pieces.service.ts new file mode 100644 index 0000000..f62f8ed --- /dev/null +++ b/apps/backend/src/content-pieces/content-pieces.service.ts @@ -0,0 +1,54 @@ +import { Injectable, NotFoundException } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { ContentPiece } from './content-piece.entity'; +import { CreateContentPieceDto } from './dto/create-content-piece.dto'; +import { UpdateContentPieceDto } from './dto/update-content-piece.dto'; + +@Injectable() +export class ContentPiecesService { + constructor( + @InjectRepository(ContentPiece) + private readonly contentPieceRepository: Repository, + ) {} + + async create(createContentPieceDto: CreateContentPieceDto): Promise { + const newContentPiece = this.contentPieceRepository.create(createContentPieceDto); + return this.contentPieceRepository.save(newContentPiece); + } + + async findAll(campaignId: string | undefined = undefined): Promise { + if (campaignId) { + return this.contentPieceRepository.find({ + where: { campaign: { id: campaignId } }, + relations: ['campaign', 'translations'], + }); + } + + return this.contentPieceRepository.find({ relations: ['campaign', 'translations'] }); + } + + async findOne(id: string): Promise { + const contentPiece = await this.contentPieceRepository.findOne({ + where: { id }, + relations: ['campaign', 'translations'], + }); + if (!contentPiece) { + throw new NotFoundException(`ContentPiece with ID ${id} not found`); + } + return contentPiece; + } + + async update(id: string, updateContentPieceDto: UpdateContentPieceDto): Promise { + const contentPiece = await this.findOne(id); + this.contentPieceRepository.merge(contentPiece, updateContentPieceDto); + return this.contentPieceRepository.save(contentPiece); + } + + async remove(id: string): Promise { + const result = await this.contentPieceRepository.delete(id); + if (result.affected === 0) { + throw new NotFoundException(`ContentPiece with ID ${id} not found`); + } + } +} diff --git a/apps/backend/src/content-pieces/dto/create-content-piece.dto.ts b/apps/backend/src/content-pieces/dto/create-content-piece.dto.ts new file mode 100644 index 0000000..5c82c9b --- /dev/null +++ b/apps/backend/src/content-pieces/dto/create-content-piece.dto.ts @@ -0,0 +1,20 @@ +import { IsString, IsNotEmpty, IsOptional } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; + +export class CreateContentPieceDto { + @ApiProperty({ + description: 'The source language of the content piece', + example: 'en', + }) + @IsString() + @IsNotEmpty() + sourceLanguage: string; + + @ApiProperty({ + description: 'The ID of the campaign this content piece belongs to', + example: '1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d', + }) + @IsString() + @IsNotEmpty() + campaignId: string; +} diff --git a/apps/backend/src/content-pieces/dto/update-content-piece.dto.ts b/apps/backend/src/content-pieces/dto/update-content-piece.dto.ts new file mode 100644 index 0000000..648182b --- /dev/null +++ b/apps/backend/src/content-pieces/dto/update-content-piece.dto.ts @@ -0,0 +1,17 @@ +import { PartialType } from '@nestjs/mapped-types'; +import { CreateContentPieceDto } from './create-content-piece.dto'; +import { IsOptional, IsEnum } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; +import { ReviewState } from '../review-state.enum'; + +export class UpdateContentPieceDto extends PartialType(CreateContentPieceDto) { + @ApiProperty({ + description: 'The review state of the content piece', + example: 'Reviewed', + enum: ReviewState, + required: false, + }) + @IsOptional() + @IsEnum(ReviewState) + reviewState?: ReviewState; +} diff --git a/apps/backend/src/content-pieces/review-state.enum.ts b/apps/backend/src/content-pieces/review-state.enum.ts new file mode 100644 index 0000000..2cb4e23 --- /dev/null +++ b/apps/backend/src/content-pieces/review-state.enum.ts @@ -0,0 +1,7 @@ +export enum ReviewState { + Draft = 'Draft', + SuggestedByAI = 'Suggested by AI', + Reviewed = 'Reviewed', + Approved = 'Approved', + Rejected = 'Rejected', +} diff --git a/apps/backend/src/main.ts b/apps/backend/src/main.ts index 7d0328d..1e65eb4 100644 --- a/apps/backend/src/main.ts +++ b/apps/backend/src/main.ts @@ -1,8 +1,22 @@ import { NestFactory } from '@nestjs/core'; +import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); + + const config = new DocumentBuilder() + .setTitle('ACME GLOBAL MEDIA API') + .setDescription('API documentation for the AI content workflow application') + .setVersion('1.0') + .addTag('campaigns') + .addTag('content-pieces') + .addTag('translations') + .build(); + + const document = SwaggerModule.createDocument(app, config); + SwaggerModule.setup('api/docs', app, document); + await app.listen(process.env.PORT ?? 3000); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eedc936..29925f9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,19 +12,43 @@ importers: dependencies: '@nestjs/common': specifier: ^11.0.1 - version: 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/config': + specifier: ^4.0.2 + version: 4.0.2(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2) '@nestjs/core': specifier: ^11.0.1 - version: 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + version: 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/mapped-types': + specifier: ^2.1.0 + version: 2.1.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-validator@0.14.2)(reflect-metadata@0.2.2) '@nestjs/platform-express': specifier: ^11.0.1 - version: 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + version: 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + '@nestjs/swagger': + specifier: ^11.2.0 + version: 11.2.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(class-validator@0.14.2)(reflect-metadata@0.2.2) + '@nestjs/typeorm': + specifier: ^11.0.0 + version: 11.0.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.26(mysql2@3.14.4)(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3))) + class-validator: + specifier: ^0.14.2 + version: 0.14.2 + pg: + specifier: ^8.16.3 + version: 8.16.3 reflect-metadata: specifier: ^0.2.2 version: 0.2.2 rxjs: specifier: ^7.8.1 version: 7.8.2 + swagger-ui-express: + specifier: ^5.0.1 + version: 5.0.1(express@5.1.0) + typeorm: + specifier: ^0.3.26 + version: 0.3.26(mysql2@3.14.4)(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)) devDependencies: '@eslint/eslintrc': specifier: ^3.2.0 @@ -40,7 +64,7 @@ importers: version: 11.0.7(chokidar@4.0.3)(typescript@5.8.3) '@nestjs/testing': specifier: ^11.0.1 - version: 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-express@11.1.6) + version: 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-express@11.1.6) '@types/express': specifier: ^5.0.0 version: 5.0.3 @@ -104,6 +128,12 @@ importers: apps/frontend: dependencies: + '@radix-ui/react-slot': + specifier: ^1.2.3 + version: 1.2.3(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-tooltip': + specifier: ^1.2.8 + version: 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@tailwindcss/vite': specifier: ^4.1.13 version: 4.1.13(vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)) @@ -125,6 +155,9 @@ importers: react-dom: specifier: ^19.1.1 version: 19.1.1(react@19.1.1) + react-router-dom: + specifier: ^7.8.2 + version: 7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) tailwind-merge: specifier: ^3.3.1 version: 3.3.1 @@ -619,6 +652,21 @@ packages: resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -906,6 +954,9 @@ packages: resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} engines: {node: '>=8'} + '@microsoft/tsdoc@0.15.1': + resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -935,6 +986,12 @@ packages: class-validator: optional: true + '@nestjs/config@4.0.2': + resolution: {integrity: sha512-McMW6EXtpc8+CwTUwFdg6h7dYcBUpH5iUILCclAsa+MbCEvC9ZKu4dCHRlJqALuhjLw97pbQu62l4+wRwGeZqA==} + peerDependencies: + '@nestjs/common': ^10.0.0 || ^11.0.0 + rxjs: ^7.1.0 + '@nestjs/core@11.1.6': resolution: {integrity: sha512-siWX7UDgErisW18VTeJA+x+/tpNZrJewjTBsRPF3JVxuWRuAB1kRoiJcxHgln8Lb5UY9NdvklITR84DUEXD0Cg==} engines: {node: '>= 20'} @@ -953,6 +1010,19 @@ packages: '@nestjs/websockets': optional: true + '@nestjs/mapped-types@2.1.0': + resolution: {integrity: sha512-W+n+rM69XsFdwORF11UqJahn4J3xi4g/ZEOlJNL6KoW5ygWSmBB2p0S2BZ4FQeS/NDH72e6xIcu35SfJnE8bXw==} + peerDependencies: + '@nestjs/common': ^10.0.0 || ^11.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@11.1.6': resolution: {integrity: sha512-HErwPmKnk+loTq8qzu1up+k7FC6Kqa8x6lJ4cDw77KnTxLzsCaPt+jBvOq6UfICmfqcqCCf3dKXg+aObQp+kIQ==} peerDependencies: @@ -964,6 +1034,23 @@ packages: peerDependencies: typescript: '>=4.8.2' + '@nestjs/swagger@11.2.0': + resolution: {integrity: sha512-5wolt8GmpNcrQv34tIPUtPoV1EeFbCetm40Ij3+M0FNNnf2RJ3FyWfuQvI8SBlcJyfaounYVTKzKHreFXsUyOg==} + peerDependencies: + '@fastify/static': ^8.0.0 + '@nestjs/common': ^11.0.1 + '@nestjs/core': ^11.0.1 + 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 + '@nestjs/testing@11.1.6': resolution: {integrity: sha512-srYzzDNxGvVCe1j0SpTS9/ix75PKt6Sn6iMaH1rpJ6nj2g8vwNrhK0CoJJXvpCYgrnI+2WES2pprYnq8rAMYHA==} peerDependencies: @@ -977,6 +1064,15 @@ packages: '@nestjs/platform-express': optional: true + '@nestjs/typeorm@11.0.0': + resolution: {integrity: sha512-SOeUQl70Lb2OfhGkvnh4KXWlsd+zA08RuuQgT7kKbzivngxzSo1Oc7Usu5VxCxACQC9wc2l9esOHILSJeK7rJA==} + peerDependencies: + '@nestjs/common': ^10.0.0 || ^11.0.0 + '@nestjs/core': ^10.0.0 || ^11.0.0 + reflect-metadata: ^0.1.13 || ^0.2.0 + rxjs: ^7.2.0 + typeorm: ^0.3.0 + '@noble/hashes@1.8.0': resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} @@ -1009,6 +1105,215 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-tooltip@1.2.8': + resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.3': + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@rolldown/pluginutils@1.0.0-beta.34': resolution: {integrity: sha512-LyAREkZHP5pMom7c24meKmJCdhf2hEyvam2q0unr3or9ydwDL+DJ8chTF6Av/RFPb3rH8UFBdMzO5MxTZW97oA==} @@ -1117,6 +1422,9 @@ packages: cpu: [x64] os: [win32] + '@scarf/scarf@1.4.0': + resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} + '@sinclair/typebox@0.34.41': resolution: {integrity: sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==} @@ -1126,6 +1434,9 @@ packages: '@sinonjs/fake-timers@13.0.5': resolution: {integrity: sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==} + '@sqltools/formatter@1.2.5': + resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} + '@tailwindcss/node@4.1.13': resolution: {integrity: sha512-eq3ouolC1oEFOAvOMOBAmfCIqZBJuvWvvYWh5h5iOYfe1HFC6+GZ6EIL0JdM3/niGRJmnrOc+8gl9/HGUaaptw==} @@ -1330,6 +1641,9 @@ packages: '@types/supertest@6.0.3': resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==} + '@types/validator@13.15.3': + resolution: {integrity: sha512-7bcUmDyS6PN3EuD9SlGGOxM77F8WLVsrwkxyWxKnxzmXoequ6c7741QBrANq6htVRGOITJ7z72mTP6Z4XyuG+Q==} + '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -1634,6 +1948,10 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + ansis@3.17.0: + resolution: {integrity: sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg==} + engines: {node: '>=14'} + ansis@4.1.0: resolution: {integrity: sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==} engines: {node: '>=14'} @@ -1642,6 +1960,10 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + app-root-path@3.1.0: + resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==} + engines: {node: '>= 6.0.0'} + append-field@1.0.0: resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} @@ -1698,6 +2020,10 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + aws-ssl-profiles@1.1.2: + resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==} + engines: {node: '>= 6.0.0'} + axe-core@4.10.3: resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==} engines: {node: '>=4'} @@ -1775,6 +2101,9 @@ packages: buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + busboy@1.6.0: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} @@ -1840,6 +2169,9 @@ packages: cjs-module-lexer@2.1.0: resolution: {integrity: sha512-UX0OwmYRYQQetfrLEZeewIFFI+wSTofC+pMBLNuH3RUuu/xzG1oz84UCEDOSoQlN3fZ4+AzmV50ZYvGqkMh9yA==} + class-validator@0.14.2: + resolution: {integrity: sha512-3kMVRF2io8N8pY1IFIXlho9r8IPUUIfHe2hYVtiebvAzU2XeQFXTv+XI4WX+TnXmtwXMDcjngcpkiPM0O9PvLw==} + class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} @@ -1936,6 +2268,10 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} + cookie@1.0.2: + resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} + engines: {node: '>=18'} + cookiejar@2.1.4: resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} @@ -1980,6 +2316,9 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} + dayjs@1.11.18: + resolution: {integrity: sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==} + debug@4.4.1: resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} engines: {node: '>=6.0'} @@ -2019,6 +2358,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + denque@2.1.0: + resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==} + engines: {node: '>=0.10'} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -2038,6 +2381,18 @@ packages: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} + dotenv-expand@12.0.1: + resolution: {integrity: sha512-LaKRbou8gt0RNID/9RoI+J2rvXsBRPMV7p+ElHlPhcSARbCPDYcYG2s1TIzAfWv4YSgyY5taidWzzs31lNV3yQ==} + engines: {node: '>=12'} + + dotenv@16.4.7: + resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + engines: {node: '>=12'} + + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -2389,6 +2744,9 @@ packages: functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + generate-function@2.3.1: + resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -2641,6 +2999,9 @@ packages: is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-property@1.0.2: + resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==} + is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -2922,6 +3283,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + libphonenumber-js@1.12.15: + resolution: {integrity: sha512-TMDCtIhWUDHh91wRC+wFuGlIzKdPzaTUHHVrIZ3vPUEoNaXFLrsIQ1ZpAeZeXApIF6rvDksMTvjrIQlLKaYxqQ==} + lightningcss-darwin-arm64@1.30.1: resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} engines: {node: '>= 12.0.0'} @@ -3018,6 +3382,9 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -3028,6 +3395,14 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + + lru.min@1.1.2: + resolution: {integrity: sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==} + engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} + lucide-react@0.542.0: resolution: {integrity: sha512-w3hD8/SQB7+lzU2r4VdFyzzOzKnUjTZIF/MQJGSSvni7Llewni4vuViRppfRAa2guOsY5k4jZyxw/i9DQHv+dw==} peerDependencies: @@ -3154,6 +3529,14 @@ packages: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} + mysql2@3.14.4: + resolution: {integrity: sha512-Cs/jx3WZPNrYHVz+Iunp9ziahaG5uFMvD2R8Zlmc194AqXNxt9HBNu7ZsPYrUtmJsF0egETCWIdMIYAwOGjL1w==} + engines: {node: '>= 8.0'} + + named-placeholders@1.1.3: + resolution: {integrity: sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==} + engines: {node: '>=12.0.0'} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -3304,6 +3687,40 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pg-cloudflare@1.2.7: + resolution: {integrity: sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==} + + pg-connection-string@2.9.1: + resolution: {integrity: sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-pool@3.10.1: + resolution: {integrity: sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.10.3: + resolution: {integrity: sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg@8.16.3: + resolution: {integrity: sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==} + engines: {node: '>= 16.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -3339,6 +3756,22 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-bytea@1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -3397,6 +3830,23 @@ packages: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} + react-router-dom@7.8.2: + resolution: {integrity: sha512-Z4VM5mKDipal2jQ385H6UBhiiEDlnJPx6jyWsTYoZQdl5TrjxEV2a9yl3Fi60NBJxYzOTGTTHXPi0pdizvTwow==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.8.2: + resolution: {integrity: sha512-7M2fR1JbIZ/jFWqelpvSZx+7vd7UlBTfdZqf6OSdF9g6+sfdqJDAWcak6ervbHph200ePlu+7G8LdoiC3ReyAQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + react@19.1.1: resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} engines: {node: '>=0.10.0'} @@ -3512,6 +3962,9 @@ packages: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} + seq-queue@0.0.5: + resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==} + serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} @@ -3519,6 +3972,9 @@ packages: resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} engines: {node: '>= 18'} + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -3534,6 +3990,11 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + sha.js@2.4.12: + resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} + engines: {node: '>= 0.10'} + hasBin: true + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -3591,9 +4052,21 @@ packages: resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} engines: {node: '>= 12'} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + sql-highlight@6.1.0: + resolution: {integrity: sha512-ed7OK4e9ywpE7pgRMkMQmZDPKSVdm0oX5IEtZiKnFucSF0zu6c80GZBe38UqHuVhTWJ9xsKgSMjCG2bml86KvA==} + engines: {node: '>=14'} + + sqlstring@2.3.3: + resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} + engines: {node: '>= 0.6'} + stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} @@ -3692,6 +4165,18 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + swagger-ui-dist@5.21.0: + resolution: {integrity: sha512-E0K3AB6HvQd8yQNSMR7eE5bk+323AUxjtCz/4ZNKiahOlPhPJxqn3UPIGs00cyY/dhrTDJ61L7C/a8u6zhGrZg==} + + swagger-ui-dist@5.28.1: + resolution: {integrity: sha512-IvPrtNi8MvjiuDgoSmPYgg27Lvu38fnLD1OSd8Y103xXsPAqezVNnNeHnVCZ/d+CMXJblflGaIyHxAYIF3O71w==} + + swagger-ui-express@5.0.1: + resolution: {integrity: sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA==} + engines: {node: '>= v0.10.32'} + peerDependencies: + express: '>=4.0.0 || >=5.0.0-beta' + symbol-observable@4.0.0: resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} engines: {node: '>=0.10'} @@ -3746,6 +4231,10 @@ packages: tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + to-buffer@1.2.1: + resolution: {integrity: sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==} + engines: {node: '>= 0.4'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -3881,6 +4370,62 @@ packages: typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + typeorm@0.3.26: + resolution: {integrity: sha512-o2RrBNn3lczx1qv4j+JliVMmtkPSqEGpG0UuZkt9tCfWkoXKu8MZnjvp2GjWPll1SehwemQw6xrbVRhmOglj8Q==} + engines: {node: '>=16.13.0'} + hasBin: true + peerDependencies: + '@google-cloud/spanner': ^5.18.0 || ^6.0.0 || ^7.0.0 + '@sap/hana-client': ^2.14.22 + better-sqlite3: ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 + ioredis: ^5.0.4 + mongodb: ^5.8.0 || ^6.0.0 + mssql: ^9.1.1 || ^10.0.1 || ^11.0.1 + mysql2: ^2.2.5 || ^3.0.1 + oracledb: ^6.3.0 + pg: ^8.5.1 + pg-native: ^3.0.0 + pg-query-stream: ^4.0.0 + redis: ^3.1.1 || ^4.0.0 || ^5.0.14 + reflect-metadata: ^0.1.14 || ^0.2.0 + sql.js: ^1.4.0 + sqlite3: ^5.0.3 + ts-node: ^10.7.0 + typeorm-aurora-data-api-driver: ^2.0.0 || ^3.0.0 + peerDependenciesMeta: + '@google-cloud/spanner': + optional: true + '@sap/hana-client': + optional: true + better-sqlite3: + optional: true + ioredis: + optional: true + mongodb: + optional: true + mssql: + optional: true + mysql2: + optional: true + oracledb: + optional: true + pg: + optional: true + pg-native: + optional: true + pg-query-stream: + optional: true + redis: + optional: true + sql.js: + optional: true + sqlite3: + optional: true + ts-node: + optional: true + typeorm-aurora-data-api-driver: + optional: true + typescript-eslint@8.42.0: resolution: {integrity: sha512-ozR/rQn+aQXQxh1YgbCzQWDFrsi9mcg+1PM3l/z5o1+20P7suOIaNg515bpr/OYt6FObz/NHcBstydDLHWeEKg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -3936,6 +4481,10 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + uuid@11.1.0: + resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} + hasBin: true + v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -3943,6 +4492,10 @@ packages: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} + validator@13.15.15: + resolution: {integrity: sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==} + engines: {node: '>= 0.10'} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -4551,6 +5104,23 @@ snapshots: '@eslint/core': 0.15.2 levn: 0.4.1 + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + + '@floating-ui/utils@0.2.10': {} + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -4939,6 +5509,8 @@ snapshots: '@lukeed/csprng@1.1.0': {} + '@microsoft/tsdoc@0.15.1': {} + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.5.0 @@ -4973,7 +5545,7 @@ snapshots: - uglify-js - webpack-cli - '@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: file-type: 21.0.0 iterare: 1.2.1 @@ -4982,12 +5554,22 @@ snapshots: rxjs: 7.8.2 tslib: 2.8.1 uid: 2.0.2 + optionalDependencies: + class-validator: 0.14.2 transitivePeerDependencies: - supports-color - '@nestjs/core@11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)': + '@nestjs/config@4.0.2(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(rxjs@7.8.2)': + dependencies: + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + dotenv: 16.4.7 + dotenv-expand: 12.0.1 + lodash: 4.17.21 + rxjs: 7.8.2 + + '@nestjs/core@11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: - '@nestjs/common': 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nuxt/opencollective': 0.4.1 fast-safe-stringify: 2.1.1 iterare: 1.2.1 @@ -4997,12 +5579,19 @@ snapshots: tslib: 2.8.1 uid: 2.0.2 optionalDependencies: - '@nestjs/platform-express': 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + '@nestjs/platform-express': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) - '@nestjs/platform-express@11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)': + '@nestjs/mapped-types@2.1.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-validator@0.14.2)(reflect-metadata@0.2.2)': dependencies: - '@nestjs/common': 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + reflect-metadata: 0.2.2 + optionalDependencies: + class-validator: 0.14.2 + + '@nestjs/platform-express@11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)': + dependencies: + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) cors: 2.8.5 express: 5.1.0 multer: 2.0.2 @@ -5022,13 +5611,35 @@ snapshots: transitivePeerDependencies: - chokidar - '@nestjs/testing@11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-express@11.1.6)': + '@nestjs/swagger@11.2.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(class-validator@0.14.2)(reflect-metadata@0.2.2)': dependencies: - '@nestjs/common': 11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2) - '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@microsoft/tsdoc': 0.15.1 + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/mapped-types': 2.1.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-validator@0.14.2)(reflect-metadata@0.2.2) + js-yaml: 4.1.0 + lodash: 4.17.21 + path-to-regexp: 8.2.0 + reflect-metadata: 0.2.2 + swagger-ui-dist: 5.21.0 + optionalDependencies: + class-validator: 0.14.2 + + '@nestjs/testing@11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/platform-express@11.1.6)': + dependencies: + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) tslib: 2.8.1 optionalDependencies: - '@nestjs/platform-express': 11.1.6(@nestjs/common@11.1.6(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + '@nestjs/platform-express': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + + '@nestjs/typeorm@11.0.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.26(mysql2@3.14.4)(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)))': + dependencies: + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + reflect-metadata: 0.2.2 + rxjs: 7.8.2 + typeorm: 0.3.26(mysql2@3.14.4)(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)) '@noble/hashes@1.8.0': {} @@ -5057,6 +5668,182 @@ snapshots: '@pkgr/core@0.2.9': {} + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.12)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.12 + + '@radix-ui/react-context@1.1.2(@types/react@19.1.12)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.12 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.12)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + + '@radix-ui/react-id@1.1.1(@types/react@19.1.12)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.12 + + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/rect': 1.1.1 + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + + '@radix-ui/react-slot@1.2.3(@types/react@19.1.12)(react@19.1.1)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.12 + + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-context': 1.1.2(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-id': 1.1.1(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.12)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.12 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.12)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.12)(react@19.1.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.12 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.12)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.12 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.12)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.12)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.12 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.12)(react@19.1.1)': + dependencies: + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.12 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.1.12)(react@19.1.1)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.12 + + '@radix-ui/react-use-size@1.1.1(@types/react@19.1.12)(react@19.1.1)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.12)(react@19.1.1) + react: 19.1.1 + optionalDependencies: + '@types/react': 19.1.12 + + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + optionalDependencies: + '@types/react': 19.1.12 + '@types/react-dom': 19.1.9(@types/react@19.1.12) + + '@radix-ui/rect@1.1.1': {} + '@rolldown/pluginutils@1.0.0-beta.34': {} '@rollup/rollup-android-arm-eabi@4.50.1': @@ -5122,6 +5909,8 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.50.1': optional: true + '@scarf/scarf@1.4.0': {} + '@sinclair/typebox@0.34.41': {} '@sinonjs/commons@3.0.1': @@ -5132,6 +5921,8 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 + '@sqltools/formatter@1.2.5': {} + '@tailwindcss/node@4.1.13': dependencies: '@jridgewell/remapping': 2.3.5 @@ -5347,6 +6138,8 @@ snapshots: '@types/methods': 1.1.4 '@types/superagent': 8.1.9 + '@types/validator@13.15.3': {} + '@types/yargs-parser@21.0.3': {} '@types/yargs@17.0.33': @@ -5667,6 +6460,8 @@ snapshots: ansi-styles@6.2.1: {} + ansis@3.17.0: {} + ansis@4.1.0: {} anymatch@3.1.3: @@ -5674,6 +6469,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + app-root-path@3.1.0: {} + append-field@1.0.0: {} arg@4.1.3: {} @@ -5740,6 +6537,9 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 + aws-ssl-profiles@1.1.2: + optional: true + axe-core@4.10.3: {} axobject-query@4.1.0: {} @@ -5859,6 +6659,11 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + busboy@1.6.0: dependencies: streamsearch: 1.1.0 @@ -5911,6 +6716,12 @@ snapshots: cjs-module-lexer@2.1.0: {} + class-validator@0.14.2: + dependencies: + '@types/validator': 13.15.3 + libphonenumber-js: 1.12.15 + validator: 13.15.15 + class-variance-authority@0.7.1: dependencies: clsx: 2.1.1 @@ -5992,6 +6803,8 @@ snapshots: cookie@0.7.2: {} + cookie@1.0.2: {} + cookiejar@2.1.4: {} core-util-is@1.0.3: {} @@ -6040,6 +6853,8 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 + dayjs@1.11.18: {} + debug@4.4.1: dependencies: ms: 2.1.3 @@ -6068,6 +6883,9 @@ snapshots: delayed-stream@1.0.0: {} + denque@2.1.0: + optional: true + depd@2.0.0: {} detect-libc@2.0.4: {} @@ -6081,6 +6899,14 @@ snapshots: diff@4.0.2: {} + dotenv-expand@12.0.1: + dependencies: + dotenv: 16.6.1 + + dotenv@16.4.7: {} + + dotenv@16.6.1: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -6601,6 +7427,11 @@ snapshots: functions-have-names@1.2.3: {} + generate-function@2.3.1: + dependencies: + is-property: 1.0.2 + optional: true + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} @@ -6855,6 +7686,9 @@ snapshots: is-promise@4.0.0: {} + is-property@1.0.2: + optional: true + is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -7322,6 +8156,8 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + libphonenumber-js@1.12.15: {} + lightningcss-darwin-arm64@1.30.1: optional: true @@ -7392,6 +8228,9 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + long@5.3.2: + optional: true + lru-cache@10.4.3: {} lru-cache@11.2.1: {} @@ -7400,6 +8239,12 @@ snapshots: dependencies: yallist: 3.1.1 + lru-cache@7.18.3: + optional: true + + lru.min@1.1.2: + optional: true + lucide-react@0.542.0(react@19.1.1): dependencies: react: 19.1.1 @@ -7503,6 +8348,24 @@ snapshots: mute-stream@2.0.0: {} + mysql2@3.14.4: + dependencies: + aws-ssl-profiles: 1.1.2 + denque: 2.1.0 + generate-function: 2.3.1 + iconv-lite: 0.7.0 + long: 5.3.2 + lru.min: 1.1.2 + named-placeholders: 1.1.3 + seq-queue: 0.0.5 + sqlstring: 2.3.3 + optional: true + + named-placeholders@1.1.3: + dependencies: + lru-cache: 7.18.3 + optional: true + nanoid@3.3.11: {} napi-postinstall@0.3.3: {} @@ -7650,6 +8513,41 @@ snapshots: path-type@4.0.0: {} + pg-cloudflare@1.2.7: + optional: true + + pg-connection-string@2.9.1: {} + + pg-int8@1.0.1: {} + + pg-pool@3.10.1(pg@8.16.3): + dependencies: + pg: 8.16.3 + + pg-protocol@1.10.3: {} + + pg-types@2.2.0: + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.0 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + pg@8.16.3: + dependencies: + pg-connection-string: 2.9.1 + pg-pool: 3.10.1(pg@8.16.3) + pg-protocol: 1.10.3 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.2.7 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -7674,6 +8572,16 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postgres-array@2.0.0: {} + + postgres-bytea@1.0.0: {} + + postgres-date@1.0.7: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + prelude-ls@1.2.1: {} prettier-linter-helpers@1.0.0: @@ -7725,6 +8633,20 @@ snapshots: react-refresh@0.17.0: {} + react-router-dom@7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-router: 7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + + react-router@7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + cookie: 1.0.2 + react: 19.1.1 + set-cookie-parser: 2.7.1 + optionalDependencies: + react-dom: 19.1.1(react@19.1.1) + react@19.1.1: {} readable-stream@3.6.2: @@ -7885,6 +8807,9 @@ snapshots: transitivePeerDependencies: - supports-color + seq-queue@0.0.5: + optional: true + serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 @@ -7898,6 +8823,8 @@ snapshots: transitivePeerDependencies: - supports-color + set-cookie-parser@2.7.1: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -7922,6 +8849,12 @@ snapshots: setprototypeof@1.2.0: {} + sha.js@2.4.12: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + to-buffer: 1.2.1 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -7980,8 +8913,15 @@ snapshots: source-map@0.7.6: {} + split2@4.2.0: {} + sprintf-js@1.0.3: {} + sql-highlight@6.1.0: {} + + sqlstring@2.3.3: + optional: true + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 @@ -8098,6 +9038,19 @@ snapshots: dependencies: has-flag: 4.0.0 + swagger-ui-dist@5.21.0: + dependencies: + '@scarf/scarf': 1.4.0 + + swagger-ui-dist@5.28.1: + dependencies: + '@scarf/scarf': 1.4.0 + + swagger-ui-express@5.0.1(express@5.1.0): + dependencies: + express: 5.1.0 + swagger-ui-dist: 5.28.1 + symbol-observable@4.0.0: {} synckit@0.11.11: @@ -8148,6 +9101,12 @@ snapshots: tmpl@1.0.5: {} + to-buffer@1.2.1: + dependencies: + isarray: 2.0.5 + safe-buffer: 5.2.1 + typed-array-buffer: 1.0.3 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -8294,6 +9253,31 @@ snapshots: typedarray@0.0.6: {} + typeorm@0.3.26(mysql2@3.14.4)(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)): + dependencies: + '@sqltools/formatter': 1.2.5 + ansis: 3.17.0 + app-root-path: 3.1.0 + buffer: 6.0.3 + dayjs: 1.11.18 + debug: 4.4.1 + dedent: 1.7.0 + dotenv: 16.6.1 + glob: 10.4.5 + reflect-metadata: 0.2.2 + sha.js: 2.4.12 + sql-highlight: 6.1.0 + tslib: 2.8.1 + uuid: 11.1.0 + yargs: 17.7.2 + optionalDependencies: + mysql2: 3.14.4 + pg: 8.16.3 + ts-node: 10.9.2(@types/node@22.18.1)(typescript@5.8.3) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + typescript-eslint@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3): dependencies: '@typescript-eslint/eslint-plugin': 8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3))(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) @@ -8365,6 +9349,8 @@ snapshots: util-deprecate@1.0.2: {} + uuid@11.1.0: {} + v8-compile-cache-lib@3.0.1: {} v8-to-istanbul@9.3.0: @@ -8373,6 +9359,8 @@ snapshots: '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 + validator@13.15.15: {} + vary@1.1.2: {} vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0): From aa82b57dab8e94e095b6c87bccf9b522b51bc462 Mon Sep 17 00:00:00 2001 From: Joaquin Date: Mon, 8 Sep 2025 04:23:48 -0300 Subject: [PATCH 04/17] feat(backend): implement GraphQL API with real-time subscriptions GraphQL API: Added GraphQL resolvers for Campaigns, ContentPieces, and ContentPieceTranslations to enable real-time updates. Subscriptions: Configured PubSub for GraphQL subscriptions to support live updates in the frontend. Modules and Services: - Refactored CampaignsService to include pubSub.publish for event-driven updates. - Added new modules and resolvers for ContentPieceTranslations and ContentPieces. Entity Updates: - Updated Campaign, ContentPiece, and ContentPieceTranslation entities to align with the new GraphQL schema. File Renames: Renamed files in ContentPieceTranslations for consistency with naming conventions. Dependencies: Added required dependencies for GraphQL subscriptions (graphql-subscriptions, @nestjs/graphql, etc.). Configuration: - Updated eslint.config.mjs for TypeScript linting. - Updated main.ts to enable WebSocket support for subscriptions. - Removed: Deleted unused ContentPieceTranslationModule. Why: These changes enable the backend to support a GraphQL API with real-time subscriptions, allowing the frontend to receive live updates for campaigns and content pieces. --- apps/backend/eslint.config.mjs | 3 + apps/backend/package.json | 10 +++ apps/backend/src/app.module.ts | 38 +++++++++--- apps/backend/src/campaigns/campaign.entity.ts | 8 +++ .../src/campaigns/campaigns.controller.ts | 2 +- .../backend/src/campaigns/campaigns.module.ts | 11 +++- .../src/campaigns/campaigns.resolver.ts | 51 ++++++++++++++++ .../src/campaigns/campaigns.service.ts | 25 +++++++- .../content-piece-translation.module.ts | 17 ------ ... content-piece-translations.controller.ts} | 8 +-- ...s => content-piece-translations.entity.ts} | 11 ++++ .../content-piece-translations.module.ts | 23 +++++++ .../content-piece-translations.resolver.ts | 20 ++++++ ... => content-piece-translations.service.ts} | 45 +++++++++++--- ... create-content-piece-translations.dto.ts} | 0 ... update-content-piece-translations.dto.ts} | 2 +- .../content-pieces/content-piece.entity.ts | 14 ++++- .../content-pieces.controller.ts | 7 +-- .../content-pieces/content-pieces.module.ts | 11 +++- .../content-pieces/content-pieces.resolver.ts | 20 ++++++ .../content-pieces/content-pieces.service.ts | 36 +++++++++-- .../dto/create-content-piece.dto.ts | 4 +- .../src/content-pieces/review-state.enum.ts | 7 +++ .../backend/src/langchain/langchain.module.ts | 8 +++ .../src/langchain/langchain.service.ts | 61 +++++++++++++++++++ apps/backend/src/main.ts | 7 +++ 26 files changed, 390 insertions(+), 59 deletions(-) create mode 100644 apps/backend/src/campaigns/campaigns.resolver.ts delete mode 100644 apps/backend/src/content-piece-translations/content-piece-translation.module.ts rename apps/backend/src/content-piece-translations/{content-piece-translation.controller.ts => content-piece-translations.controller.ts} (96%) rename apps/backend/src/content-piece-translations/{content-piece-translation.entity.ts => content-piece-translations.entity.ts} (79%) create mode 100644 apps/backend/src/content-piece-translations/content-piece-translations.module.ts create mode 100644 apps/backend/src/content-piece-translations/content-piece-translations.resolver.ts rename apps/backend/src/content-piece-translations/{content-piece-translation.service.ts => content-piece-translations.service.ts} (54%) rename apps/backend/src/content-piece-translations/dto/{create-content-piece-translation.dto.ts => create-content-piece-translations.dto.ts} (100%) rename apps/backend/src/content-piece-translations/dto/{update-content-piece-translation.dto.ts => update-content-piece-translations.dto.ts} (96%) create mode 100644 apps/backend/src/content-pieces/content-pieces.resolver.ts create mode 100644 apps/backend/src/langchain/langchain.module.ts create mode 100644 apps/backend/src/langchain/langchain.service.ts diff --git a/apps/backend/eslint.config.mjs b/apps/backend/eslint.config.mjs index e83bac7..366de4d 100644 --- a/apps/backend/eslint.config.mjs +++ b/apps/backend/eslint.config.mjs @@ -3,6 +3,7 @@ import eslint from '@eslint/js'; import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'; import globals from 'globals'; import tseslint from 'typescript-eslint'; +import parser from '@typescript-eslint/parser'; export default [ { @@ -19,6 +20,8 @@ export default [ }, sourceType: 'commonjs', parserOptions: { + parser, + project: ['./tsconfig.json'], tsconfigRootDir: import.meta.dirname, }, }, diff --git a/apps/backend/package.json b/apps/backend/package.json index 5ff3bd5..d33427c 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -20,14 +20,24 @@ "test:e2e": "jest --config ./test/jest-e2e.json" }, "dependencies": { + "@apollo/server": "^4.12.2", + "@langchain/anthropic": "^0.3.27", + "@langchain/core": "^0.3.75", + "@langchain/openai": "^0.6.11", + "@nestjs/apollo": "^13.1.0", "@nestjs/common": "^11.0.1", "@nestjs/config": "^4.0.2", "@nestjs/core": "^11.0.1", + "@nestjs/graphql": "^13.1.0", "@nestjs/mapped-types": "^2.1.0", "@nestjs/platform-express": "^11.0.1", "@nestjs/swagger": "^11.2.0", "@nestjs/typeorm": "^11.0.0", + "apollo-server-express": "^3.13.0", "class-validator": "^0.14.2", + "graphql": "^16.11.0", + "graphql-subscriptions": "^3.0.0", + "langchain": "^0.3.33", "pg": "^8.16.3", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts index 88778ac..3d567a0 100644 --- a/apps/backend/src/app.module.ts +++ b/apps/backend/src/app.module.ts @@ -1,25 +1,43 @@ +import { join } from 'path'; import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; -import { ConfigModule } from '@nestjs/config'; +import { GraphQLModule } from '@nestjs/graphql'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { ApolloDriver, ApolloDriverConfig } from '@nestjs/apollo'; import { CampaignsModule } from './campaigns/campaigns.module'; import { ContentPiecesModule } from './content-pieces/content-pieces.module'; -import { ContentPieceTranslationModule } from './content-piece-translations/content-piece-translation.module'; +import { ContentPieceTranslationsModule } from './content-piece-translations/content-piece-translations.module'; +import { LangChainModule } from './langchain/langchain.module'; @Module({ imports: [ - ConfigModule.forRoot(), - - TypeOrmModule.forRoot({ - type: 'postgres', - url: process.env.DATABASE_URL, - autoLoadEntities: true, // Automatically load all entities - synchronize: true, // Auto-create database tables (for development only) + ConfigModule.forRoot({ + isGlobal: true, + }), + TypeOrmModule.forRootAsync({ + imports: [ConfigModule], + useFactory: (configService: ConfigService) => ({ + type: 'postgres', + url: configService.get('DATABASE_URL'), + autoLoadEntities: true, + synchronize: true, // In production, use migrations + }), + inject: [ConfigService], + }), + GraphQLModule.forRoot({ + driver: ApolloDriver, + autoSchemaFile: join(process.cwd(), 'src/schema.gql'), + sortSchema: true, + subscriptions: { + 'graphql-ws': true, + }, }), // Feature modules CampaignsModule, ContentPiecesModule, - ContentPieceTranslationModule, + ContentPieceTranslationsModule, + LangChainModule, ], controllers: [], providers: [], diff --git a/apps/backend/src/campaigns/campaign.entity.ts b/apps/backend/src/campaigns/campaign.entity.ts index 04fee53..0389d92 100644 --- a/apps/backend/src/campaigns/campaign.entity.ts +++ b/apps/backend/src/campaigns/campaign.entity.ts @@ -1,23 +1,31 @@ import { Entity, PrimaryGeneratedColumn, CreateDateColumn, Column, OneToMany, UpdateDateColumn } from 'typeorm'; +import { Field, ID, ObjectType } from '@nestjs/graphql'; import { ContentPiece } from '../content-pieces/content-piece.entity'; +@ObjectType() @Entity() export class Campaign { + @Field(() => ID) @PrimaryGeneratedColumn('uuid') id: string; + @Field() @Column() name: string; + @Field() @Column() description: string; + @Field() @CreateDateColumn() createdAt: Date; + @Field() @UpdateDateColumn() updatedAt: Date; + @Field(() => [ContentPiece], { defaultValue: [] }) @OneToMany(() => ContentPiece, (contentPiece) => contentPiece.campaign) contentPieces: ContentPiece[]; } diff --git a/apps/backend/src/campaigns/campaigns.controller.ts b/apps/backend/src/campaigns/campaigns.controller.ts index 28b803f..b0e1fd8 100644 --- a/apps/backend/src/campaigns/campaigns.controller.ts +++ b/apps/backend/src/campaigns/campaigns.controller.ts @@ -1,5 +1,5 @@ import { Controller, Get, Post, Body, Param, NotFoundException } from '@nestjs/common'; -import { ApiTags, ApiOperation, ApiBody, ApiParam } from '@nestjs/swagger'; +import { ApiTags, ApiOperation, ApiParam } from '@nestjs/swagger'; import { CampaignsService } from './campaigns.service'; import { CreateCampaignDto } from './dto/create-campaign.dto'; import { Campaign } from './campaign.entity'; diff --git a/apps/backend/src/campaigns/campaigns.module.ts b/apps/backend/src/campaigns/campaigns.module.ts index 85dfc57..1ba296d 100644 --- a/apps/backend/src/campaigns/campaigns.module.ts +++ b/apps/backend/src/campaigns/campaigns.module.ts @@ -3,10 +3,19 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { Campaign } from './campaign.entity'; import { CampaignsService } from './campaigns.service'; import { CampaignsController } from './campaigns.controller'; +import { CampaignResolver } from './campaigns.resolver'; +import { PubSub } from 'graphql-subscriptions'; @Module({ imports: [TypeOrmModule.forFeature([Campaign])], - providers: [CampaignsService], + providers: [ + CampaignsService, + CampaignResolver, + { + provide: PubSub, + useValue: new PubSub(), + }, + ], controllers: [CampaignsController], exports: [CampaignsService], }) diff --git a/apps/backend/src/campaigns/campaigns.resolver.ts b/apps/backend/src/campaigns/campaigns.resolver.ts new file mode 100644 index 0000000..4589616 --- /dev/null +++ b/apps/backend/src/campaigns/campaigns.resolver.ts @@ -0,0 +1,51 @@ +import { Resolver, Query, Mutation, Args, ID, Subscription } from '@nestjs/graphql'; +import { PubSub } from 'graphql-subscriptions'; +import { CampaignsService } from './campaigns.service'; +import { Campaign } from './campaign.entity'; + +@Resolver(() => Campaign) +export class CampaignResolver { + constructor( + private readonly campaignsService: CampaignsService, + private readonly pubSub: PubSub, + ) {} + + @Query(() => [Campaign]) + async campaigns(): Promise { + return this.campaignsService.findAll(); + } + + @Query(() => Campaign) + async campaign(@Args('id', { type: () => ID }) id: string): Promise { + return this.campaignsService.findOne(id); + } + + @Subscription(() => Campaign, { + name: 'onCampaignUpdated', + }) + onCampaignUpdated() { + return this.pubSub.asyncIterableIterator('onCampaignUpdated'); + } + + @Mutation(() => Campaign) + async createCampaign(@Args('name') name: string, @Args('description') description: string): Promise { + const campaign = await this.campaignsService.create({ name, description }); + return campaign; + } + + @Mutation(() => Campaign) + async updateCampaign( + @Args('id', { type: () => ID }) id: string, + @Args('name') name?: string, + @Args('description') description?: string, + ): Promise { + const campaign = await this.campaignsService.update(id, { name, description }); + return campaign; + } + + @Mutation(() => ID) + async removeCampaign(@Args('id', { type: () => ID }) id: string): Promise { + await this.campaignsService.remove(id); + return id; + } +} diff --git a/apps/backend/src/campaigns/campaigns.service.ts b/apps/backend/src/campaigns/campaigns.service.ts index 63f7d4a..c291233 100644 --- a/apps/backend/src/campaigns/campaigns.service.ts +++ b/apps/backend/src/campaigns/campaigns.service.ts @@ -2,17 +2,22 @@ import { Injectable, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Campaign } from './campaign.entity'; +import { PubSub } from 'graphql-subscriptions'; @Injectable() export class CampaignsService { constructor( @InjectRepository(Campaign) private readonly campaignRepository: Repository, + private readonly pubSub: PubSub, ) {} async create(createCampaignDto: Partial): Promise { - const newCampaign = this.campaignRepository.create(createCampaignDto); - return this.campaignRepository.save(newCampaign); + const entity = this.campaignRepository.create(createCampaignDto); + const newCampaign = await this.campaignRepository.save(entity); + + await this.pubSub.publish('onCampaignUpdated', { onCampaignUpdated: newCampaign }); + return newCampaign; } async findOne(id: string): Promise { @@ -26,4 +31,20 @@ export class CampaignsService { async findAll(): Promise { return this.campaignRepository.find(); } + + async update(id: string, updateCampaignDto: Partial): Promise { + const entity = await this.findOne(id); + Object.assign(entity, updateCampaignDto); + const campaign = await this.campaignRepository.save(entity); + + await this.pubSub.publish('onCampaignUpdated', { onCampaignUpdated: campaign }); + return campaign; + } + + async remove(id: string): Promise { + const entity = await this.findOne(id); + await this.campaignRepository.remove(entity); + + await this.pubSub.publish('onCampaignUpdated', { onCampaignUpdated: { id } }); + } } diff --git a/apps/backend/src/content-piece-translations/content-piece-translation.module.ts b/apps/backend/src/content-piece-translations/content-piece-translation.module.ts deleted file mode 100644 index 898e54e..0000000 --- a/apps/backend/src/content-piece-translations/content-piece-translation.module.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; -import { ContentPieceTranslation } from './content-piece-translation.entity'; -import { ContentPieceTranslationService } from './content-piece-translation.service'; -import { ContentPieceTranslationController } from './content-piece-translation.controller'; -import { ContentPiecesModule } from 'src/content-pieces/content-pieces.module'; - -@Module({ - imports: [ - TypeOrmModule.forFeature([ContentPieceTranslation]), - ContentPiecesModule, - ], - controllers: [ContentPieceTranslationController], - providers: [ContentPieceTranslationService], - exports: [ContentPieceTranslationService], -}) -export class ContentPieceTranslationModule {} diff --git a/apps/backend/src/content-piece-translations/content-piece-translation.controller.ts b/apps/backend/src/content-piece-translations/content-piece-translations.controller.ts similarity index 96% rename from apps/backend/src/content-piece-translations/content-piece-translation.controller.ts rename to apps/backend/src/content-piece-translations/content-piece-translations.controller.ts index 87a0267..031ef2c 100644 --- a/apps/backend/src/content-piece-translations/content-piece-translation.controller.ts +++ b/apps/backend/src/content-piece-translations/content-piece-translations.controller.ts @@ -1,9 +1,9 @@ import { Controller, Get, Post, Body, Param, Patch, Delete, NotFoundException } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiParam } from '@nestjs/swagger'; -import { ContentPieceTranslationService } from './content-piece-translation.service'; -import { ContentPieceTranslation } from './content-piece-translation.entity'; -import { CreateContentPieceTranslationDto } from './dto/create-content-piece-translation.dto'; -import { UpdateContentPieceTranslationDto } from './dto/update-content-piece-translation.dto'; +import { ContentPieceTranslationService } from './content-piece-translations.service'; +import { ContentPieceTranslation } from './content-piece-translations.entity'; +import { CreateContentPieceTranslationDto } from './dto/create-content-piece-translations.dto'; +import { UpdateContentPieceTranslationDto } from './dto/update-content-piece-translations.dto'; import { ContentPiecesService } from 'src/content-pieces/content-pieces.service'; @ApiTags('content-piece-translations') diff --git a/apps/backend/src/content-piece-translations/content-piece-translation.entity.ts b/apps/backend/src/content-piece-translations/content-piece-translations.entity.ts similarity index 79% rename from apps/backend/src/content-piece-translations/content-piece-translation.entity.ts rename to apps/backend/src/content-piece-translations/content-piece-translations.entity.ts index 5e1907c..53fab0a 100644 --- a/apps/backend/src/content-piece-translations/content-piece-translation.entity.ts +++ b/apps/backend/src/content-piece-translations/content-piece-translations.entity.ts @@ -1,32 +1,43 @@ import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn, UpdateDateColumn } from 'typeorm'; +import { Field, ID, ObjectType } from '@nestjs/graphql'; import { ContentPiece } from '../content-pieces/content-piece.entity'; +@ObjectType() @Entity() export class ContentPieceTranslation { + @Field(() => ID) @PrimaryGeneratedColumn('uuid') id: string; + @Field() @Column() languageCode: string; + @Field() @Column() translatedTitle: string; + @Field() @Column() translatedDescription: string; + @Field() @Column({ default: false }) isAIGenerated: boolean; + @Field() @Column({ default: false }) isHumanEdited: boolean; + @Field() @CreateDateColumn() createdAt: Date; + @Field() @UpdateDateColumn() updatedAt: Date; + @Field(() => ContentPiece) @ManyToOne(() => ContentPiece, (contentPiece): ContentPieceTranslation[] => contentPiece.translations) contentPiece: ContentPiece; } diff --git a/apps/backend/src/content-piece-translations/content-piece-translations.module.ts b/apps/backend/src/content-piece-translations/content-piece-translations.module.ts new file mode 100644 index 0000000..b3248c2 --- /dev/null +++ b/apps/backend/src/content-piece-translations/content-piece-translations.module.ts @@ -0,0 +1,23 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { ContentPieceTranslation } from './content-piece-translations.entity'; +import { ContentPieceTranslationService } from './content-piece-translations.service'; +import { ContentPieceTranslationResolver } from './content-piece-translations.resolver'; +import { ContentPieceTranslationController } from './content-piece-translations.controller'; +import { ContentPiecesModule } from 'src/content-pieces/content-pieces.module'; +import { PubSub } from 'graphql-subscriptions'; + +@Module({ + imports: [TypeOrmModule.forFeature([ContentPieceTranslation]), ContentPiecesModule], + controllers: [ContentPieceTranslationController], + providers: [ + ContentPieceTranslationService, + ContentPieceTranslationResolver, + { + provide: PubSub, + useValue: new PubSub(), + }, + ], + exports: [ContentPieceTranslationService], +}) +export class ContentPieceTranslationsModule {} diff --git a/apps/backend/src/content-piece-translations/content-piece-translations.resolver.ts b/apps/backend/src/content-piece-translations/content-piece-translations.resolver.ts new file mode 100644 index 0000000..c3c8d1d --- /dev/null +++ b/apps/backend/src/content-piece-translations/content-piece-translations.resolver.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@nestjs/common'; +import { ContentPieceTranslationService } from './content-piece-translations.service'; +import { PubSub } from 'graphql-subscriptions'; +import { Subscription } from '@nestjs/graphql'; +import { ContentPieceTranslation } from './content-piece-translations.entity'; + +@Injectable() +export class ContentPieceTranslationResolver { + constructor( + private readonly contentPieceTranslationService: ContentPieceTranslationService, + private readonly pubSub: PubSub, + ) {} + + @Subscription(() => ContentPieceTranslation, { + name: 'onContentPieceTranslationUpdated', + }) + onContentPieceTranslationUpdated() { + return this.pubSub.asyncIterableIterator('onContentPieceTranslationUpdated'); + } +} diff --git a/apps/backend/src/content-piece-translations/content-piece-translation.service.ts b/apps/backend/src/content-piece-translations/content-piece-translations.service.ts similarity index 54% rename from apps/backend/src/content-piece-translations/content-piece-translation.service.ts rename to apps/backend/src/content-piece-translations/content-piece-translations.service.ts index 54b9491..b6b7a19 100644 --- a/apps/backend/src/content-piece-translations/content-piece-translation.service.ts +++ b/apps/backend/src/content-piece-translations/content-piece-translations.service.ts @@ -1,21 +1,32 @@ import { Injectable, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { ContentPieceTranslation } from './content-piece-translation.entity'; -import { CreateContentPieceTranslationDto } from './dto/create-content-piece-translation.dto'; -import { UpdateContentPieceTranslationDto } from './dto/update-content-piece-translation.dto'; +import { ContentPieceTranslation } from './content-piece-translations.entity'; +import { CreateContentPieceTranslationDto } from './dto/create-content-piece-translations.dto'; +import { UpdateContentPieceTranslationDto } from './dto/update-content-piece-translations.dto'; import { ContentPiece } from 'src/content-pieces/content-piece.entity'; +import { PubSub } from 'graphql-subscriptions'; @Injectable() export class ContentPieceTranslationService { constructor( @InjectRepository(ContentPieceTranslation) private readonly translationRepository: Repository, + private readonly pubSub: PubSub, ) {} async create(createTranslationDto: CreateContentPieceTranslationDto): Promise { - const newTranslation = this.translationRepository.create(createTranslationDto); - return this.translationRepository.save(newTranslation); + const translation = this.translationRepository.create(createTranslationDto); + const newTranslation = await this.translationRepository.save(translation); + + await this.pubSub.publish('onContentPieceTranslationUpdated', { + onContentPieceTranslationUpdated: { + newTranslation, + campaignId: newTranslation.contentPiece.campaign.id, + contentPieceId: newTranslation.contentPiece.id, + }, + }); + return newTranslation; } async findAll(contentPiece: ContentPiece | undefined = undefined): Promise { @@ -37,13 +48,31 @@ export class ContentPieceTranslationService { async update(id: string, updateTranslationDto: UpdateContentPieceTranslationDto): Promise { const translation = await this.findOne(id); this.translationRepository.merge(translation, updateTranslationDto); - return this.translationRepository.save(translation); + const updatedTranslation = await this.translationRepository.save(translation); + + await this.pubSub.publish('onContentPieceTranslationUpdated', { + onContentPieceTranslationUpdated: { + updatedTranslation, + campaignId: updatedTranslation.contentPiece.campaign.id, + contentPieceId: updatedTranslation.contentPiece.id, + }, + }); + return updatedTranslation; } async remove(id: string): Promise { - const result = await this.translationRepository.delete(id); - if (result.affected === 0) { + const translation = await this.translationRepository.findOne({ where: { id } }); + if (!translation) { throw new NotFoundException(`Translation with ID ${id} not found`); } + await this.translationRepository.remove(translation); + + await this.pubSub.publish('onContentPieceTranslationUpdated', { + onContentPieceTranslationUpdated: { + id: translation.id, + campaignId: translation.contentPiece.campaign.id, + contentPieceId: translation.contentPiece.id, + }, + }); } } diff --git a/apps/backend/src/content-piece-translations/dto/create-content-piece-translation.dto.ts b/apps/backend/src/content-piece-translations/dto/create-content-piece-translations.dto.ts similarity index 100% rename from apps/backend/src/content-piece-translations/dto/create-content-piece-translation.dto.ts rename to apps/backend/src/content-piece-translations/dto/create-content-piece-translations.dto.ts diff --git a/apps/backend/src/content-piece-translations/dto/update-content-piece-translation.dto.ts b/apps/backend/src/content-piece-translations/dto/update-content-piece-translations.dto.ts similarity index 96% rename from apps/backend/src/content-piece-translations/dto/update-content-piece-translation.dto.ts rename to apps/backend/src/content-piece-translations/dto/update-content-piece-translations.dto.ts index 434cd95..47adcc3 100644 --- a/apps/backend/src/content-piece-translations/dto/update-content-piece-translation.dto.ts +++ b/apps/backend/src/content-piece-translations/dto/update-content-piece-translations.dto.ts @@ -1,5 +1,5 @@ import { PartialType } from '@nestjs/mapped-types'; -import { CreateContentPieceTranslationDto } from './create-content-piece-translation.dto'; +import { CreateContentPieceTranslationDto } from './create-content-piece-translations.dto'; import { ApiProperty } from '@nestjs/swagger'; import { IsOptional, IsString, IsBoolean } from 'class-validator'; diff --git a/apps/backend/src/content-pieces/content-piece.entity.ts b/apps/backend/src/content-pieces/content-piece.entity.ts index 15f06a4..3c20969 100644 --- a/apps/backend/src/content-pieces/content-piece.entity.ts +++ b/apps/backend/src/content-pieces/content-piece.entity.ts @@ -7,15 +7,19 @@ import { CreateDateColumn, UpdateDateColumn, } from 'typeorm'; +import { Field, ID, ObjectType } from '@nestjs/graphql'; import { Campaign } from '../campaigns/campaign.entity'; -import { ContentPieceTranslation } from '../content-piece-translations/content-piece-translation.entity'; +import { ContentPieceTranslation } from '../content-piece-translations/content-piece-translations.entity'; import { ReviewState } from './review-state.enum'; +@ObjectType() @Entity() export class ContentPiece { + @Field(() => ID) @PrimaryGeneratedColumn('uuid') id: string; + @Field(() => ReviewState) @Column({ type: 'enum', enum: ReviewState, @@ -23,21 +27,27 @@ export class ContentPiece { }) reviewState: ReviewState; + @Field(() => String, { nullable: true }) @Column({ type: 'jsonb', nullable: true }) aiGeneratedDraft: object; + @Field() @Column() sourceLanguage: string; + @Field() @CreateDateColumn() createdAt: Date; + @Field() @UpdateDateColumn() updatedAt: Date; + @Field(() => Campaign) @ManyToOne(() => Campaign, (campaign) => campaign.contentPieces) campaign: Campaign; - @OneToMany(() => ContentPieceTranslation, (translation) => translation.contentPiece) + @Field(() => [ContentPieceTranslation], { nullable: false }) + @OneToMany(() => ContentPieceTranslation, (translation): ContentPiece => translation.contentPiece) translations: ContentPieceTranslation[]; } diff --git a/apps/backend/src/content-pieces/content-pieces.controller.ts b/apps/backend/src/content-pieces/content-pieces.controller.ts index 5e9c954..0ddc20d 100644 --- a/apps/backend/src/content-pieces/content-pieces.controller.ts +++ b/apps/backend/src/content-pieces/content-pieces.controller.ts @@ -1,5 +1,5 @@ import { Controller, Get, Post, Body, Param, Patch, Delete, NotFoundException } from '@nestjs/common'; -import { ApiTags, ApiOperation, ApiBody, ApiParam } from '@nestjs/swagger'; +import { ApiTags, ApiOperation, ApiParam } from '@nestjs/swagger'; import { ContentPiecesService } from './content-pieces.service'; import { ContentPiece } from './content-piece.entity'; import { CreateContentPieceDto } from './dto/create-content-piece.dto'; @@ -39,10 +39,7 @@ export class ContentPiecesController { @Patch(':id') @ApiOperation({ summary: 'Update a content piece by ID' }) @ApiParam({ name: 'id', description: 'The ID of the content piece to update' }) - async update( - @Param('id') id: string, - @Body() updateContentPieceDto: UpdateContentPieceDto, - ): Promise { + async update(@Param('id') id: string, @Body() updateContentPieceDto: UpdateContentPieceDto): Promise { return this.contentPiecesService.update(id, updateContentPieceDto); } diff --git a/apps/backend/src/content-pieces/content-pieces.module.ts b/apps/backend/src/content-pieces/content-pieces.module.ts index 23b4a21..ebced9c 100644 --- a/apps/backend/src/content-pieces/content-pieces.module.ts +++ b/apps/backend/src/content-pieces/content-pieces.module.ts @@ -2,12 +2,21 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { ContentPiece } from './content-piece.entity'; import { ContentPiecesService } from './content-pieces.service'; +import { ContentPiecesResolver } from './content-pieces.resolver'; import { ContentPiecesController } from './content-pieces.controller'; +import { PubSub } from 'graphql-subscriptions'; @Module({ imports: [TypeOrmModule.forFeature([ContentPiece])], controllers: [ContentPiecesController], - providers: [ContentPiecesService], + providers: [ + ContentPiecesService, + ContentPiecesResolver, + { + provide: PubSub, + useValue: new PubSub(), + }, + ], exports: [ContentPiecesService], }) export class ContentPiecesModule {} diff --git a/apps/backend/src/content-pieces/content-pieces.resolver.ts b/apps/backend/src/content-pieces/content-pieces.resolver.ts new file mode 100644 index 0000000..97d7a7e --- /dev/null +++ b/apps/backend/src/content-pieces/content-pieces.resolver.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@nestjs/common'; +import { PubSub } from 'graphql-subscriptions'; +import { ContentPiecesService } from './content-pieces.service'; +import { Subscription } from '@nestjs/graphql'; +import { ContentPiece } from './content-piece.entity'; + +@Injectable() +export class ContentPiecesResolver { + constructor( + private readonly contentPieceService: ContentPiecesService, + private readonly pubSub: PubSub, + ) {} + + @Subscription(() => ContentPiece, { + name: 'onContentPieceUpdated', + }) + onContentPieceUpdated() { + return this.pubSub.asyncIterableIterator('onContentPieceUpdated'); + } +} diff --git a/apps/backend/src/content-pieces/content-pieces.service.ts b/apps/backend/src/content-pieces/content-pieces.service.ts index f62f8ed..3cefcc9 100644 --- a/apps/backend/src/content-pieces/content-pieces.service.ts +++ b/apps/backend/src/content-pieces/content-pieces.service.ts @@ -4,17 +4,27 @@ import { Repository } from 'typeorm'; import { ContentPiece } from './content-piece.entity'; import { CreateContentPieceDto } from './dto/create-content-piece.dto'; import { UpdateContentPieceDto } from './dto/update-content-piece.dto'; +import { PubSub } from 'graphql-subscriptions'; @Injectable() export class ContentPiecesService { constructor( @InjectRepository(ContentPiece) private readonly contentPieceRepository: Repository, + private readonly pubSub: PubSub, ) {} async create(createContentPieceDto: CreateContentPieceDto): Promise { - const newContentPiece = this.contentPieceRepository.create(createContentPieceDto); - return this.contentPieceRepository.save(newContentPiece); + const entity = this.contentPieceRepository.create(createContentPieceDto); + const newContent = await this.contentPieceRepository.save(entity); + + await this.pubSub.publish('onContentPieceUpdated', { + onContentPieceUpdated: { + ...newContent, + campaignId: newContent.campaign.id, + }, + }); + return newContent; } async findAll(campaignId: string | undefined = undefined): Promise { @@ -42,13 +52,29 @@ export class ContentPiecesService { async update(id: string, updateContentPieceDto: UpdateContentPieceDto): Promise { const contentPiece = await this.findOne(id); this.contentPieceRepository.merge(contentPiece, updateContentPieceDto); - return this.contentPieceRepository.save(contentPiece); + const updatedContentPiece = await this.contentPieceRepository.save(contentPiece); + + await this.pubSub.publish('onContentPieceUpdated', { + onContentPieceUpdated: { + ...updatedContentPiece, + campaignId: updatedContentPiece.campaign.id, + }, + }); + return updatedContentPiece; } async remove(id: string): Promise { - const result = await this.contentPieceRepository.delete(id); - if (result.affected === 0) { + const contentPiece = await this.findOne(id); + if (!contentPiece) { throw new NotFoundException(`ContentPiece with ID ${id} not found`); } + await this.contentPieceRepository.delete(id); + + await this.pubSub.publish('onContentPieceUpdated', { + onContentPieceUpdated: { + id, + campaignId: contentPiece.campaign.id, + }, + }); } } diff --git a/apps/backend/src/content-pieces/dto/create-content-piece.dto.ts b/apps/backend/src/content-pieces/dto/create-content-piece.dto.ts index 5c82c9b..a4bd994 100644 --- a/apps/backend/src/content-pieces/dto/create-content-piece.dto.ts +++ b/apps/backend/src/content-pieces/dto/create-content-piece.dto.ts @@ -1,4 +1,4 @@ -import { IsString, IsNotEmpty, IsOptional } from 'class-validator'; +import { IsString, IsNotEmpty } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; export class CreateContentPieceDto { @@ -9,7 +9,7 @@ export class CreateContentPieceDto { @IsString() @IsNotEmpty() sourceLanguage: string; - + @ApiProperty({ description: 'The ID of the campaign this content piece belongs to', example: '1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d', diff --git a/apps/backend/src/content-pieces/review-state.enum.ts b/apps/backend/src/content-pieces/review-state.enum.ts index 2cb4e23..ed2ecac 100644 --- a/apps/backend/src/content-pieces/review-state.enum.ts +++ b/apps/backend/src/content-pieces/review-state.enum.ts @@ -1,3 +1,5 @@ +import { registerEnumType } from '@nestjs/graphql'; + export enum ReviewState { Draft = 'Draft', SuggestedByAI = 'Suggested by AI', @@ -5,3 +7,8 @@ export enum ReviewState { Approved = 'Approved', Rejected = 'Rejected', } + +registerEnumType(ReviewState, { + name: 'ReviewState', + description: 'The review state of a content piece.', +}); diff --git a/apps/backend/src/langchain/langchain.module.ts b/apps/backend/src/langchain/langchain.module.ts new file mode 100644 index 0000000..8fa54c1 --- /dev/null +++ b/apps/backend/src/langchain/langchain.module.ts @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { LangChainService } from './langchain.service'; + +@Module({ + providers: [LangChainService], + exports: [LangChainService], +}) +export class LangChainModule {} diff --git a/apps/backend/src/langchain/langchain.service.ts b/apps/backend/src/langchain/langchain.service.ts new file mode 100644 index 0000000..35fecad --- /dev/null +++ b/apps/backend/src/langchain/langchain.service.ts @@ -0,0 +1,61 @@ +import { Injectable, BadRequestException } from '@nestjs/common'; +import { OpenAI } from '@langchain/openai'; +import { ChatAnthropic } from '@langchain/anthropic'; +import { PromptTemplate } from '@langchain/core/prompts'; +import { BaseLanguageModel } from '@langchain/core/language_models/base'; +import { StringOutputParser } from '@langchain/core/output_parsers'; + +export enum ModelProvider { + OpenAI = 'openai', + Anthropic = 'anthropic', +} + +@Injectable() +export class LangChainService { + private readonly openAILLM: OpenAI; + private readonly anthropicLLM: ChatAnthropic; + + constructor() { + this.openAILLM = new OpenAI({ + openAIApiKey: process.env.OPENAI_API_KEY, + }); + this.anthropicLLM = new ChatAnthropic({ + anthropicApiKey: process.env.ANTHROPIC_API_KEY, + }); + } + + private getModel(provider: ModelProvider): BaseLanguageModel { + switch (provider) { + case ModelProvider.OpenAI: + return this.openAILLM; + case ModelProvider.Anthropic: + return this.anthropicLLM; + default: + throw new BadRequestException('Invalid AI model provider'); + } + } + + async generateDraft(sourceLanguage: string, topic: string, modelProvider: ModelProvider) { + const llm = this.getModel(modelProvider); + + const promptTemplate = PromptTemplate.fromTemplate( + 'Generate a short, engaging marketing headline and description about {topic} in {sourceLanguage}.', + ); + + // Use LCEL: Pipe the prompt into the LLM and then into an output parser + const chain = promptTemplate.pipe(llm).pipe(new StringOutputParser()); + + return chain.invoke({ topic, sourceLanguage }); + } + + async translateContent(text: string, targetLanguage: string, modelProvider: ModelProvider) { + const llm = this.getModel(modelProvider); + + const translatePrompt = PromptTemplate.fromTemplate('Translate the following text into {targetLanguage}: {text}'); + + // Use LCEL again + const translateChain = translatePrompt.pipe(llm).pipe(new StringOutputParser()); + + return translateChain.invoke({ text, targetLanguage }); + } +} diff --git a/apps/backend/src/main.ts b/apps/backend/src/main.ts index 1e65eb4..d1a669c 100644 --- a/apps/backend/src/main.ts +++ b/apps/backend/src/main.ts @@ -17,6 +17,13 @@ async function bootstrap() { const document = SwaggerModule.createDocument(app, config); SwaggerModule.setup('api/docs', app, document); + app.enableCors({ + origin: '*', + methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS', + preflightContinue: false, + optionsSuccessStatus: 204, + }); + await app.listen(process.env.PORT ?? 3000); } From a10f0c02bbe25aba4a48cc148b8e849af3eb1581 Mon Sep 17 00:00:00 2001 From: Joaquin Date: Mon, 8 Sep 2025 04:27:47 -0300 Subject: [PATCH 05/17] feat(frontend): add basic UI, components, and GraphQL subscriptions UI Components: - Added CampaignTable and CampaignRow components for displaying campaign data. - Added ContentTable and ContentRow components for displaying content pieces. - Introduced reusable UI components: table and tooltip. GraphQL Integration: - Implemented CampaignContext to manage campaign data and handle real-time updates via GraphQL subscriptions. - Added apolloClient setup for GraphQL queries and subscriptions. Pages: - Created CampaignIndex and CampaignEdit pages for campaign management. - Added ContentIndex page for managing content pieces. - Added NotFound page for handling invalid routes. Types and Validation: - Defined TypeScript types in lib/types.ts for campaigns, content pieces, and translations. - Added validators.ts for input validation. Styling: - Updated index.css for basic styling. - Removed unused App.css and react.svg. Configuration: - Updated tsconfig.app.json to include new paths and configurations. - Updated index.html for the new app structure. Why: These changes introduce a basic UI and integrate GraphQL subscriptions to enable real-time updates for campaigns and content pieces. This lays the foundation for further development and testing. --- apps/frontend/index.html | 4 +- apps/frontend/package.json | 9 +- apps/frontend/src/App.css | 42 - apps/frontend/src/App.tsx | 53 +- apps/frontend/src/assets/react.svg | 1 - .../components/CampaignTable/CampaignRow.tsx | 41 + .../CampaignTable/CampaignTable.tsx | 30 + .../components/ContentTable/ContentRow.tsx | 35 + .../components/ContentTable/ContentTable.tsx | 31 + apps/frontend/src/components/ui/table.tsx | 73 + apps/frontend/src/components/ui/tooltip.tsx | 46 + apps/frontend/src/context/CampaignContext.tsx | 262 +++ apps/frontend/src/index.css | 12 +- apps/frontend/src/lib/apolloClient.ts | 32 + apps/frontend/src/lib/types.ts | 42 + apps/frontend/src/lib/validators.ts | 5 + apps/frontend/src/pages/CampaignEdit.tsx | 26 + apps/frontend/src/pages/CampaignIndex.tsx | 15 + apps/frontend/src/pages/ContentIndex.tsx | 43 + apps/frontend/src/pages/NotFound.tsx | 15 + apps/frontend/tsconfig.app.json | 5 +- pnpm-lock.yaml | 1805 ++++++++++++++++- 22 files changed, 2535 insertions(+), 92 deletions(-) delete mode 100644 apps/frontend/src/App.css delete mode 100644 apps/frontend/src/assets/react.svg create mode 100644 apps/frontend/src/components/CampaignTable/CampaignRow.tsx create mode 100644 apps/frontend/src/components/CampaignTable/CampaignTable.tsx create mode 100644 apps/frontend/src/components/ContentTable/ContentRow.tsx create mode 100644 apps/frontend/src/components/ContentTable/ContentTable.tsx create mode 100644 apps/frontend/src/components/ui/table.tsx create mode 100644 apps/frontend/src/components/ui/tooltip.tsx create mode 100644 apps/frontend/src/context/CampaignContext.tsx create mode 100644 apps/frontend/src/lib/apolloClient.ts create mode 100644 apps/frontend/src/lib/types.ts create mode 100644 apps/frontend/src/lib/validators.ts create mode 100644 apps/frontend/src/pages/CampaignEdit.tsx create mode 100644 apps/frontend/src/pages/CampaignIndex.tsx create mode 100644 apps/frontend/src/pages/ContentIndex.tsx create mode 100644 apps/frontend/src/pages/NotFound.tsx diff --git a/apps/frontend/index.html b/apps/frontend/index.html index e4b78ea..dd3edc9 100644 --- a/apps/frontend/index.html +++ b/apps/frontend/index.html @@ -1,12 +1,12 @@ - + Vite + React + TS - +
diff --git a/apps/frontend/package.json b/apps/frontend/package.json index a2c8183..d766ef1 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -10,13 +10,20 @@ "preview": "vite preview" }, "dependencies": { + "@apollo/client": "^4.0.4", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-tooltip": "^1.2.8", "@tailwindcss/vite": "^4.1.13", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "graphql": "^16.11.0", + "graphql-ws": "^6.0.6", "lucide": "^0.542.0", "lucide-react": "^0.542.0", "react": "^19.1.1", "react-dom": "^19.1.1", + "react-router-dom": "^7.8.2", + "subscriptions-transport-ws": "^0.11.0", "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.13" }, @@ -29,9 +36,9 @@ "eslint": "^9.33.0", "eslint-plugin-jsx-a11y": "^6.10.2", "eslint-plugin-prettier": "^5.5.4", + "eslint-plugin-react-dom": "^1.53.0", "eslint-plugin-react-hooks": "^5.2.0", "eslint-plugin-react-refresh": "^0.4.20", - "eslint-plugin-react-dom": "^1.53.0", "eslint-plugin-react-x": "^1.53.0", "globals": "^16.3.0", "tw-animate-css": "^1.3.8", diff --git a/apps/frontend/src/App.css b/apps/frontend/src/App.css deleted file mode 100644 index b9d355d..0000000 --- a/apps/frontend/src/App.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/apps/frontend/src/App.tsx b/apps/frontend/src/App.tsx index 4d6f9ed..fbd4c99 100644 --- a/apps/frontend/src/App.tsx +++ b/apps/frontend/src/App.tsx @@ -1,32 +1,33 @@ -import { useState } from 'react'; -import reactLogo from './assets/react.svg'; -import viteLogo from '/vite.svg'; -import './App.css'; +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; +import { CampaignProvider } from '@/context/CampaignContext'; +import CampaignIndex from '@/pages/CampaignIndex'; +import ContentIndex from '@/pages/ContentIndex'; +import NotFound from '@/pages/NotFound'; +import CampaignEdit from './pages/CampaignEdit'; function App() { - const [count, setCount] = useState(0); - return ( - <> - -

Vite + React

-
- -

- Edit src/App.tsx and save to test HMR -

-
-

Click on the Vite and React logos to learn more

- + + +
+ + {/* Campaign Index Page */} + } /> + } /> + + {/* Campaign Edit Page */} + } /> + + {/* Content Index Page for a specific campaign */} + } /> + + {/* 404 Page */} + } /> + } /> + +
+
+
); } diff --git a/apps/frontend/src/assets/react.svg b/apps/frontend/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/apps/frontend/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/apps/frontend/src/components/CampaignTable/CampaignRow.tsx b/apps/frontend/src/components/CampaignTable/CampaignRow.tsx new file mode 100644 index 0000000..eecaeb3 --- /dev/null +++ b/apps/frontend/src/components/CampaignTable/CampaignRow.tsx @@ -0,0 +1,41 @@ +import { TableRow, TableCell } from '@/components/ui/table'; +import { Plus, Table2 } from 'lucide-react'; +import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'; +import type { Campaign } from '@/lib/types'; +import { Link } from 'react-router-dom'; + +const CampaignRow = ({ campaign }: { campaign: Campaign }) => { + return ( + + {campaign.id} + {campaign.name} + {campaign.createdAt} + {campaign.updatedAt} + + + + + + + + View Contents + + + + + + + + + Edit campaign + + + + ); +}; + +export default CampaignRow; diff --git a/apps/frontend/src/components/CampaignTable/CampaignTable.tsx b/apps/frontend/src/components/CampaignTable/CampaignTable.tsx new file mode 100644 index 0000000..ba9ce39 --- /dev/null +++ b/apps/frontend/src/components/CampaignTable/CampaignTable.tsx @@ -0,0 +1,30 @@ +import CampaignRow from './CampaignRow'; +import { Table, TableBody, TableCaption, TableHead, TableHeader, TableRow } from '@/components/ui/table'; + +import { useCampaigns } from '../../context/CampaignContext'; + +const CampaignTable = () => { + const { campaigns } = useCampaigns(); + + return ( + + A list of your campaigns. + + + ID + Name + Created At + Updated At + Actions + + + + {campaigns.map((campaign) => ( + + ))} + +
+ ); +}; + +export default CampaignTable; diff --git a/apps/frontend/src/components/ContentTable/ContentRow.tsx b/apps/frontend/src/components/ContentTable/ContentRow.tsx new file mode 100644 index 0000000..17cd12e --- /dev/null +++ b/apps/frontend/src/components/ContentTable/ContentRow.tsx @@ -0,0 +1,35 @@ +import { TableRow, TableCell } from '@/components/ui/table'; +import { Plus } from 'lucide-react'; +import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'; +import type { Campaign, Content } from '@/lib/types'; +import { Link } from 'react-router-dom'; + +interface ContentRowProps { + campaign: Campaign; + content: Content; +} + +const ContentRow = ({ campaign, content }: ContentRowProps) => { + return ( + + {content.id} + {content.updatedAt} + {content.translations[0]?.languageCode} + {content.reviewState} + + + + + + + + Review + + + + ); +}; + +export default ContentRow; diff --git a/apps/frontend/src/components/ContentTable/ContentTable.tsx b/apps/frontend/src/components/ContentTable/ContentTable.tsx new file mode 100644 index 0000000..3996b4d --- /dev/null +++ b/apps/frontend/src/components/ContentTable/ContentTable.tsx @@ -0,0 +1,31 @@ +import { Table, TableBody, TableCaption, TableHead, TableHeader, TableRow } from '@/components/ui/table'; + +import { useCampaigns } from '../../context/CampaignContext'; +import ContentRow from './ContentRow'; + +const ContentTable = ({ campaignId }: { campaignId: string }) => { + const { campaigns } = useCampaigns(); + const campaign = campaigns.find((c) => c.id === campaignId); + + return ( + + A list of contents for campaign {campaign?.name}. + + + ID + Name + Created At + Updated At + Actions + + + + {campaign?.contentPieces.map((content) => ( + + ))} + +
+ ); +}; + +export default ContentTable; diff --git a/apps/frontend/src/components/ui/table.tsx b/apps/frontend/src/components/ui/table.tsx new file mode 100644 index 0000000..84dec5c --- /dev/null +++ b/apps/frontend/src/components/ui/table.tsx @@ -0,0 +1,73 @@ +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +function Table({ className, ...props }: React.ComponentProps<'table'>) { + return ( +
+ + + ); +} + +function TableHeader({ className, ...props }: React.ComponentProps<'thead'>) { + return ; +} + +function TableBody({ className, ...props }: React.ComponentProps<'tbody'>) { + return ; +} + +function TableFooter({ className, ...props }: React.ComponentProps<'tfoot'>) { + return ( + tr]:last:border-b-0', className)} + {...props} + /> + ); +} + +function TableRow({ className, ...props }: React.ComponentProps<'tr'>) { + return ( + + ); +} + +function TableHead({ className, ...props }: React.ComponentProps<'th'>) { + return ( +
[role=checkbox]]:translate-y-[2px]', + className, + )} + {...props} + /> + ); +} + +function TableCell({ className, ...props }: React.ComponentProps<'td'>) { + return ( + [role=checkbox]]:translate-y-[2px]', + className, + )} + {...props} + /> + ); +} + +function TableCaption({ className, ...props }: React.ComponentProps<'caption'>) { + return ( +
+ ); +} + +export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption }; diff --git a/apps/frontend/src/components/ui/tooltip.tsx b/apps/frontend/src/components/ui/tooltip.tsx new file mode 100644 index 0000000..7aa5589 --- /dev/null +++ b/apps/frontend/src/components/ui/tooltip.tsx @@ -0,0 +1,46 @@ +import * as React from 'react'; +import * as TooltipPrimitive from '@radix-ui/react-tooltip'; + +import { cn } from '@/lib/utils'; + +function TooltipProvider({ delayDuration = 0, ...props }: React.ComponentProps) { + return ; +} + +function Tooltip({ ...props }: React.ComponentProps) { + return ( + + + + ); +} + +function TooltipTrigger({ ...props }: React.ComponentProps) { + return ; +} + +function TooltipContent({ + className, + sideOffset = 0, + children, + ...props +}: React.ComponentProps) { + return ( + + + {children} + + + + ); +} + +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; diff --git a/apps/frontend/src/context/CampaignContext.tsx b/apps/frontend/src/context/CampaignContext.tsx new file mode 100644 index 0000000..d008e4a --- /dev/null +++ b/apps/frontend/src/context/CampaignContext.tsx @@ -0,0 +1,262 @@ +import type { Campaign, Content, ContentTranslation } from '@/lib/types'; +import React, { createContext, use, useState, useMemo, type ReactNode, useEffect } from 'react'; +import { gql } from '@apollo/client'; +import { client } from '@/lib/apolloClient'; + +// Define the context value type +type CampaignContextType = { + campaigns: Campaign[]; + setCampaigns: React.Dispatch>; +}; + +// Create the context +const CampaignContext = createContext(undefined); + +// Define the subscription query +const CAMPAIGN_GET_ALL_QUERY = gql` + query GetCampaigns { + campaigns { + id + name + description + createdAt + updatedAt + contentPieces { + id + reviewState + aiGeneratedDraft + sourceLanguage + createdAt + updatedAt + translations { + id + languageCode + translatedTitle + translatedDescription + isAIGenerated + isHumanEdited + createdAt + updatedAt + } + } + } + } +`; + +const CAMPAIGN_UPDATED_SUBSCRIPTION = gql` + subscription OnCampaignUpdated { + campaignUpdated { + id + name + description + createdAt + updatedAt + contentPieces { + id + reviewState + aiGeneratedDraft + sourceLanguage + createdAt + updatedAt + translations { + id + languageCode + translatedTitle + translatedDescription + isAIGenerated + isHumanEdited + createdAt + updatedAt + } + } + } + } +`; + +const CONTENT_PIECE_UPDATED_SUBSCRIPTION = gql` + subscription onContentPieceUpdated { + contentPieceUpdated { + id + campaignId + reviewState + aiGeneratedDraft + sourceLanguage + createdAt + updatedAt + translations { + id + languageCode + translatedTitle + translatedDescription + isAIGenerated + isHumanEdited + createdAt + updatedAt + } + } + } +`; + +const CONTENT_PIECE_TRANSLATION_UPDATED_SUBSCRIPTION = gql` + subscription onContentPieceTranslationUpdated { + contentPieceTranslationUpdated { + id + campaignId + contentPieceId + languageCode + translatedTitle + translatedDescription + isAIGenerated + isHumanEdited + createdAt + updatedAt + } + } +`; + +// Create the provider component +export const CampaignProvider = ({ children }: { children: ReactNode }) => { + const [campaigns, setCampaigns] = useState([]); + + // query for initial campaigns + useEffect(() => { + client + .query<{ campaigns: Campaign[] }>({ + query: CAMPAIGN_GET_ALL_QUERY, + fetchPolicy: 'network-only', // Always fetch from network to get the latest data + }) + .then((result) => { + if (result.data && result.data.campaigns) { + setCampaigns(result.data.campaigns); + } + }) + .catch((error) => { + console.error('Error fetching campaigns:', error); + }); + }, []); + + // Subscribe to campaign updates + useEffect(() => { + const campaignObservable = client.subscribe<{ campaignUpdated: Campaign }>({ + query: CAMPAIGN_UPDATED_SUBSCRIPTION, + }); + const campaignSubscription = campaignObservable.subscribe({ + next: (result) => { + if (!result.data) return; + + const updatedCampaign = result.data.campaignUpdated; + setCampaigns((prevCampaigns) => { + const index = prevCampaigns.findIndex((c) => c.id === updatedCampaign.id); + if (index === -1) { + // Add new campaign + return [...prevCampaigns, updatedCampaign]; + } + const updatedCampaigns = [...prevCampaigns]; + if (updatedCampaigns[index].name === undefined) { + // Remove campaign if name is undefined (indicating deletion) + updatedCampaigns.splice(index, 1); + return updatedCampaigns; + } + // Update existing campaign + updatedCampaigns[index] = updatedCampaign; + return updatedCampaigns; + }); + }, + }); + + // Subscribe to content piece updates + const contentPieceObservable = client.subscribe<{ + contentPieceUpdated: Content & { campaignId: string }; + }>({ + query: CONTENT_PIECE_UPDATED_SUBSCRIPTION, + }); + const contentPieceSubscription = contentPieceObservable.subscribe({ + next: (result) => { + if (!result.data) return; + + const updatedContentPiece = result.data.contentPieceUpdated; + setCampaigns((prevCampaigns) => { + const campaignIndex = prevCampaigns.findIndex((c) => c.id === updatedContentPiece.campaignId); + if (campaignIndex === -1) return prevCampaigns; // Campaign not found + + const updatedCampaigns = [...prevCampaigns]; + const contentPieces = updatedCampaigns[campaignIndex].contentPieces; + const contentIndex = contentPieces.findIndex((cp) => cp.id === updatedContentPiece.id); + + if (contentIndex === -1) { + // Add new content piece + contentPieces.push(updatedContentPiece); + } else { + if (updatedContentPiece.reviewState === undefined) { + // Remove content piece if reviewState is undefined (indicating deletion) + contentPieces.splice(contentIndex, 1); + } else { + // Update existing content piece + contentPieces[contentIndex] = updatedContentPiece; + } + } + return updatedCampaigns; + }); + }, + }); + + // Subscribe to content piece translation updates + const contentPieceTranslationObservable = client.subscribe<{ + contentPieceTranslationUpdated: ContentTranslation & { campaignId: string; contentPieceId: string }; + }>({ + query: CONTENT_PIECE_TRANSLATION_UPDATED_SUBSCRIPTION, + }); + const contentPieceTranslationSubscription = contentPieceTranslationObservable.subscribe({ + next: (result) => { + if (!result.data) return; + + const updatedTranslation = result.data.contentPieceTranslationUpdated; + setCampaigns((prevCampaigns) => { + const campaignIndex = prevCampaigns.findIndex((c) => c.id === updatedTranslation.campaignId); + if (campaignIndex === -1) return prevCampaigns; // Campaign not found + + const updatedCampaigns = [...prevCampaigns]; + const contentPieces = updatedCampaigns[campaignIndex].contentPieces; + const contentIndex = contentPieces.findIndex((cp) => cp.id === updatedTranslation.contentPieceId); + if (contentIndex === -1) return prevCampaigns; // Content piece not found + + const translations = contentPieces[contentIndex].translations; + const translationIndex = translations.findIndex((t) => t.id === updatedTranslation.id); + + if (translationIndex === -1) { + // Add new translation + translations.push(updatedTranslation); + } else { + if (updatedTranslation.translatedTitle === undefined) { + // Remove translation if translatedTitle is undefined (indicating deletion) + translations.splice(translationIndex, 1); + } else { + // Update existing translation + translations[translationIndex] = updatedTranslation; + } + } + return updatedCampaigns; + }); + }, + }); + + // Cleanup subscriptions on unmount + return () => { + campaignSubscription.unsubscribe(); + contentPieceSubscription.unsubscribe(); + contentPieceTranslationSubscription.unsubscribe(); + }; + }, []); + + const value = useMemo(() => ({ campaigns, setCampaigns }), [campaigns]); + return {children}; +}; + +// Custom hook to use the CampaignContext +export const useCampaigns = () => { + const context = use(CampaignContext); + if (!context) { + throw new Error('useCampaigns must be used within a CampaignProvider'); + } + return context; +}; diff --git a/apps/frontend/src/index.css b/apps/frontend/src/index.css index b5a5386..2ed8446 100644 --- a/apps/frontend/src/index.css +++ b/apps/frontend/src/index.css @@ -1,5 +1,5 @@ -@import "tailwindcss"; -@import "tw-animate-css"; +@import 'tailwindcss'; +@import 'tw-animate-css'; @custom-variant dark (&:is(.dark *)); @@ -17,7 +17,7 @@ -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; --radius: 0.625rem; - --background: oklch(1 0 0); + --background: oklch(14.5% 0 0); --foreground: oklch(0.145 0 0); --card: oklch(1 0 0); --card-foreground: oklch(0.145 0 0); @@ -52,17 +52,17 @@ a { font-weight: 500; - color: #646cff; + color: #878ac9; text-decoration: inherit; } a:hover { - color: #535bf2; + color: #ce26f8; } body { margin: 0; display: flex; - place-items: center; + justify-content: center; min-width: 320px; min-height: 100vh; } diff --git a/apps/frontend/src/lib/apolloClient.ts b/apps/frontend/src/lib/apolloClient.ts new file mode 100644 index 0000000..b795d04 --- /dev/null +++ b/apps/frontend/src/lib/apolloClient.ts @@ -0,0 +1,32 @@ +import { ApolloClient, InMemoryCache, HttpLink, ApolloLink } from '@apollo/client'; +import { GraphQLWsLink } from '@apollo/client/link/subscriptions'; +import { createClient } from 'graphql-ws'; +import { getMainDefinition } from '@apollo/client/utilities'; + +// HTTP link for queries and mutations +const httpLink = new HttpLink({ + uri: 'http://localhost:3000/graphql', // Replace with your GraphQL endpoint +}); + +// WebSocket link for subscriptions +const wsLink = new GraphQLWsLink( + createClient({ + url: 'ws://localhost:3000/graphql', // Replace with your GraphQL WebSocket endpoint + }), +); + +// Split links based on operation type +const splitLink = ApolloLink.split( + ({ query }) => { + const definition = getMainDefinition(query); + return definition.kind === 'OperationDefinition' && definition.operation === 'subscription'; + }, + wsLink, + httpLink, +); + +// Apollo Client instance +export const client = new ApolloClient({ + link: splitLink, + cache: new InMemoryCache(), +}); diff --git a/apps/frontend/src/lib/types.ts b/apps/frontend/src/lib/types.ts new file mode 100644 index 0000000..d48e112 --- /dev/null +++ b/apps/frontend/src/lib/types.ts @@ -0,0 +1,42 @@ +export type Campaign = { + id: string; + name: string; + description: string; + createdAt: string; + updatedAt: string; + + contentPieces: Content[]; +}; + +export const ReviewState = { + draft: 'draft', + suggested_by_ai: 'suggested_by_ai', + reviewed: 'reviewed', + approved: 'approved', + rejected: 'rejected', +} as const; +export type ReviewStateType = (typeof ReviewState)[keyof typeof ReviewState]; + +export type Content = { + id: string; + reviewState: ReviewStateType; + aiGeneratedDraft?: object; + sourceLanguage: string; + + createdAt: string; + updatedAt: string; + + translations: ContentTranslation[]; +}; + +export type ContentTranslation = { + id: string; + languageCode: string; + translatedTitle: string; + translatedDescription: string; + isAIGenerated: boolean; + isHumanEdited: boolean; + + createdAt: string; + updatedAt: string; +}; diff --git a/apps/frontend/src/lib/validators.ts b/apps/frontend/src/lib/validators.ts new file mode 100644 index 0000000..39eb51d --- /dev/null +++ b/apps/frontend/src/lib/validators.ts @@ -0,0 +1,5 @@ +export const isValidUUID = (id: string | undefined): boolean => { + if (!id) return false; + const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; + return uuidRegex.test(id); +}; diff --git a/apps/frontend/src/pages/CampaignEdit.tsx b/apps/frontend/src/pages/CampaignEdit.tsx new file mode 100644 index 0000000..5c362a2 --- /dev/null +++ b/apps/frontend/src/pages/CampaignEdit.tsx @@ -0,0 +1,26 @@ +import { useCampaigns } from '@/context/CampaignContext'; +import { isValidUUID } from '@/lib/validators'; +import { useNavigate, useParams } from 'react-router-dom'; + +function CampaignEdit() { + const navigate = useNavigate(); + const campaigns = useCampaigns().campaigns; + + const { campaignId } = useParams(); + const campaign = campaigns.find((c) => c.id === campaignId); + + if (campaignId === undefined || !isValidUUID(campaignId) || !campaign) { + navigate('/404', { replace: true }); + return null; + } + + return ( + <> +

Edit Campaign

+ +
Hola
+ + ); +} + +export default CampaignEdit; diff --git a/apps/frontend/src/pages/CampaignIndex.tsx b/apps/frontend/src/pages/CampaignIndex.tsx new file mode 100644 index 0000000..7c96aa4 --- /dev/null +++ b/apps/frontend/src/pages/CampaignIndex.tsx @@ -0,0 +1,15 @@ +import CampaignTable from '@/components/CampaignTable/CampaignTable'; + +function CampaignIndex() { + return ( + <> +

Campaigns

+ +
+ +
+ + ); +} + +export default CampaignIndex; diff --git a/apps/frontend/src/pages/ContentIndex.tsx b/apps/frontend/src/pages/ContentIndex.tsx new file mode 100644 index 0000000..175412d --- /dev/null +++ b/apps/frontend/src/pages/ContentIndex.tsx @@ -0,0 +1,43 @@ +import ContentTable from '@/components/ContentTable/ContentTable'; +import { useCampaigns } from '@/context/CampaignContext'; +import { isValidUUID } from '@/lib/validators'; +import { useParams, useNavigate, Link } from 'react-router-dom'; + +const ContentIndex = () => { + const { campaignId } = useParams(); + const navigate = useNavigate(); + + if (!isValidUUID(campaignId)) { + navigate('/404', { replace: true }); + return null; + } + + if (campaignId === undefined) { + navigate('/404', { replace: true }); + return null; + } + + const campaign = useCampaigns().campaigns.find((c) => c.id === campaignId); + + return ( + <> +
+

{campaign?.name}'s contents

+ +
+ + Back to Campaigns + +
+
+ +
+

Content for Campaign: {campaign?.name}

+ + +
+ + ); +}; + +export default ContentIndex; diff --git a/apps/frontend/src/pages/NotFound.tsx b/apps/frontend/src/pages/NotFound.tsx new file mode 100644 index 0000000..4120444 --- /dev/null +++ b/apps/frontend/src/pages/NotFound.tsx @@ -0,0 +1,15 @@ +import { Link } from 'react-router-dom'; + +const NotFound = () => { + return ( +
+

404 - Page Not Found

+

The page you are looking for does not exist.

+ + Go back to home + +
+ ); +}; + +export default NotFound; diff --git a/apps/frontend/tsconfig.app.json b/apps/frontend/tsconfig.app.json index d96f791..80fce45 100644 --- a/apps/frontend/tsconfig.app.json +++ b/apps/frontend/tsconfig.app.json @@ -23,12 +23,9 @@ "noFallthroughCasesInSwitch": true, "noUncheckedSideEffectImports": true, - "baseUrl": ".", "paths": { - "@/*": [ - "./src/*" - ] + "@/*": ["./src/*"] } }, "include": ["src"] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 29925f9..f403ccc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,6 +10,21 @@ importers: apps/backend: dependencies: + '@apollo/server': + specifier: ^4.12.2 + version: 4.12.2(graphql@16.11.0) + '@langchain/anthropic': + specifier: ^0.3.27 + version: 0.3.27(@langchain/core@0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76))) + '@langchain/core': + specifier: ^0.3.75 + version: 0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76)) + '@langchain/openai': + specifier: ^0.6.11 + version: 0.6.11(@langchain/core@0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76)))(ws@8.18.1) + '@nestjs/apollo': + specifier: ^13.1.0 + version: 13.1.0(@apollo/server@4.12.2(graphql@16.11.0))(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/graphql@13.1.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(class-validator@0.14.2)(graphql@16.11.0)(reflect-metadata@0.2.2))(graphql@16.11.0) '@nestjs/common': specifier: ^11.0.1 version: 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -19,6 +34,9 @@ importers: '@nestjs/core': specifier: ^11.0.1 version: 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/graphql': + specifier: ^13.1.0 + version: 13.1.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(class-validator@0.14.2)(graphql@16.11.0)(reflect-metadata@0.2.2) '@nestjs/mapped-types': specifier: ^2.1.0 version: 2.1.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-validator@0.14.2)(reflect-metadata@0.2.2) @@ -31,9 +49,21 @@ importers: '@nestjs/typeorm': specifier: ^11.0.0 version: 11.0.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2)(typeorm@0.3.26(mysql2@3.14.4)(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3))) + apollo-server-express: + specifier: ^3.13.0 + version: 3.13.0(express@5.1.0)(graphql@16.11.0) class-validator: specifier: ^0.14.2 version: 0.14.2 + graphql: + specifier: ^16.11.0 + version: 16.11.0 + graphql-subscriptions: + specifier: ^3.0.0 + version: 3.0.0(graphql@16.11.0) + langchain: + specifier: ^0.3.33 + version: 0.3.33(@langchain/anthropic@0.3.27(@langchain/core@0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76))))(@langchain/core@0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76)))(handlebars@4.7.8)(openai@5.12.2(ws@8.18.1)(zod@3.25.76))(typeorm@0.3.26(mysql2@3.14.4)(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)))(ws@8.18.1) pg: specifier: ^8.16.3 version: 8.16.3 @@ -128,6 +158,9 @@ importers: apps/frontend: dependencies: + '@apollo/client': + specifier: ^4.0.4 + version: 4.0.4(graphql-ws@6.0.6(graphql@16.11.0)(ws@8.18.1))(graphql@16.11.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rxjs@7.8.2)(subscriptions-transport-ws@0.11.0(graphql@16.11.0)) '@radix-ui/react-slot': specifier: ^1.2.3 version: 1.2.3(@types/react@19.1.12)(react@19.1.1) @@ -136,13 +169,19 @@ importers: version: 1.2.8(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1) '@tailwindcss/vite': specifier: ^4.1.13 - version: 4.1.13(vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)) + version: 4.1.13(vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 clsx: specifier: ^2.1.1 version: 2.1.1 + graphql: + specifier: ^16.11.0 + version: 16.11.0 + graphql-ws: + specifier: ^6.0.6 + version: 6.0.6(graphql@16.11.0)(ws@8.18.1) lucide: specifier: ^0.542.0 version: 0.542.0 @@ -158,6 +197,9 @@ importers: react-router-dom: specifier: ^7.8.2 version: 7.8.2(react-dom@19.1.1(react@19.1.1))(react@19.1.1) + subscriptions-transport-ws: + specifier: ^0.11.0 + version: 0.11.0(graphql@16.11.0) tailwind-merge: specifier: ^3.3.1 version: 3.3.1 @@ -179,7 +221,7 @@ importers: version: 19.1.9(@types/react@19.1.12) '@vitejs/plugin-react': specifier: ^5.0.0 - version: 5.0.2(vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)) + version: 5.0.2(vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1)) eslint: specifier: ^9.33.0 version: 9.35.0(jiti@2.5.1) @@ -215,7 +257,7 @@ importers: version: 8.42.0(eslint@9.35.0(jiti@2.5.1))(typescript@5.8.3) vite: specifier: ^7.1.2 - version: 7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0) + version: 7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1) packages: @@ -237,6 +279,176 @@ packages: resolution: {integrity: sha512-kNOJ+3vekJJCQKWihNmxBkarJzNW09kP5a9E1SRNiQVNOUEeSwcRR0qYotM65nx821gNzjjhJXnAZ8OazWldrg==} engines: {node: ^18.19.1 || ^20.11.1 || >=22.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + '@anthropic-ai/sdk@0.56.0': + resolution: {integrity: sha512-SLCB8M8+VMg1cpCucnA1XWHGWqVSZtIWzmOdDOEu3eTFZMB+A0sGZ1ESO5MHDnqrNTXz3safMrWx9x4rMZSOqA==} + hasBin: true + + '@apollo/cache-control-types@1.0.3': + resolution: {integrity: sha512-F17/vCp7QVwom9eG7ToauIKdAxpSoadsJnqIfyryLFSkLSOEqu+eC5Z3N8OXcUVStuOMcNHlyraRsA6rRICu4g==} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/client@4.0.4': + resolution: {integrity: sha512-3+fTQUA3AdC08urPF7si0ptLiAaVOH5R/3drwXzic8yqzTL4W3ME6klLj/EpgMND0FbWD7sM8TCkEDoe4OckMw==} + peerDependencies: + graphql: ^16.0.0 + graphql-ws: ^5.5.5 || ^6.0.3 + react: ^17.0.0 || ^18.0.0 || >=19.0.0-rc + react-dom: ^17.0.0 || ^18.0.0 || >=19.0.0-rc + rxjs: ^7.3.0 + subscriptions-transport-ws: ^0.9.0 || ^0.11.0 + peerDependenciesMeta: + graphql-ws: + optional: true + react: + optional: true + react-dom: + optional: true + subscriptions-transport-ws: + optional: true + + '@apollo/protobufjs@1.2.6': + resolution: {integrity: sha512-Wqo1oSHNUj/jxmsVp4iR3I480p6qdqHikn38lKrFhfzcDJ7lwd7Ck7cHRl4JE81tWNArl77xhnG/OkZhxKBYOw==} + hasBin: true + + '@apollo/protobufjs@1.2.7': + resolution: {integrity: sha512-Lahx5zntHPZia35myYDBRuF58tlwPskwHc5CWBZC/4bMKB6siTBWwtMrkqXcsNwQiFSzSx5hKdRPUmemrEp3Gg==} + hasBin: true + + '@apollo/server-gateway-interface@1.1.1': + resolution: {integrity: sha512-pGwCl/po6+rxRmDMFgozKQo2pbsSwE91TpsDBAOgf74CRDPXHHtM88wbwjab0wMMZh95QfR45GGyDIdhY24bkQ==} + deprecated: '@apollo/server-gateway-interface v1 is part of Apollo Server v4, which is deprecated and will transition to end-of-life on January 26, 2026. As long as you are already using a non-EOL version of Node.js, upgrading to v2 should take only a few minutes. See https://www.apollographql.com/docs/apollo-server/previous-versions for details.' + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/server-plugin-landing-page-graphql-playground@4.0.1': + resolution: {integrity: sha512-tWhQzD7DtiTO/wfbGvasryz7eJSuEh9XJHgRTMZI7+Wu/omylG5gH6K6ksg1Vccg8/Xuglfi2f1M5Nm/IlBBGw==} + engines: {node: '>=14.0'} + deprecated: The use of GraphQL Playground in Apollo Server was supported in previous versions, but this is no longer the case as of December 31, 2022. This package exists for v4 migration purposes only. We do not intend to resolve security issues or other bugs with this package if they arise, so please migrate away from this to [Apollo Server's default Explorer](https://www.apollographql.com/docs/apollo-server/api/plugin/landing-pages) as soon as possible. + peerDependencies: + '@apollo/server': ^4.0.0 + + '@apollo/server@4.12.2': + resolution: {integrity: sha512-jKRlf+sBMMdKYrjMoiWKne42Eb6paBfDOr08KJnUaeaiyWFj+/040FjVPQI7YGLfdwnYIsl1NUUqS2UdgezJDg==} + engines: {node: '>=14.16.0'} + deprecated: Apollo Server v4 is deprecated and will transition to end-of-life on January 26, 2026. As long as you are already using a non-EOL version of Node.js, upgrading to v5 should take only a few minutes. See https://www.apollographql.com/docs/apollo-server/previous-versions for details. + peerDependencies: + graphql: ^16.6.0 + + '@apollo/usage-reporting-protobuf@4.1.1': + resolution: {integrity: sha512-u40dIUePHaSKVshcedO7Wp+mPiZsaU6xjv9J+VyxpoU/zL6Jle+9zWeG98tr/+SZ0nZ4OXhrbb8SNr0rAPpIDA==} + + '@apollo/utils.createhash@2.0.2': + resolution: {integrity: sha512-UkS3xqnVFLZ3JFpEmU/2cM2iKJotQXMoSTgxXsfQgXLC5gR1WaepoXagmYnPSA7Q/2cmnyTYK5OgAgoC4RULPg==} + engines: {node: '>=14'} + + '@apollo/utils.dropunuseddefinitions@1.1.0': + resolution: {integrity: sha512-jU1XjMr6ec9pPoL+BFWzEPW7VHHulVdGKMkPAMiCigpVIT11VmCbnij0bWob8uS3ODJ65tZLYKAh/55vLw2rbg==} + engines: {node: '>=12.13.0'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.dropunuseddefinitions@2.0.1': + resolution: {integrity: sha512-EsPIBqsSt2BwDsv8Wu76LK5R1KtsVkNoO4b0M5aK0hx+dGg9xJXuqlr7Fo34Dl+y83jmzn+UvEW+t1/GP2melA==} + engines: {node: '>=14'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.fetcher@2.0.1': + resolution: {integrity: sha512-jvvon885hEyWXd4H6zpWeN3tl88QcWnHp5gWF5OPF34uhvoR+DFqcNxs9vrRaBBSY3qda3Qe0bdud7tz2zGx1A==} + engines: {node: '>=14'} + + '@apollo/utils.isnodelike@2.0.1': + resolution: {integrity: sha512-w41XyepR+jBEuVpoRM715N2ZD0xMD413UiJx8w5xnAZD2ZkSJnMJBoIzauK83kJpSgNuR6ywbV29jG9NmxjK0Q==} + engines: {node: '>=14'} + + '@apollo/utils.keyvaluecache@1.0.2': + resolution: {integrity: sha512-p7PVdLPMnPzmXSQVEsy27cYEjVON+SH/Wb7COyW3rQN8+wJgT1nv9jZouYtztWW8ZgTkii5T6tC9qfoDREd4mg==} + + '@apollo/utils.keyvaluecache@2.1.1': + resolution: {integrity: sha512-qVo5PvUUMD8oB9oYvq4ViCjYAMWnZ5zZwEjNF37L2m1u528x5mueMlU+Cr1UinupCgdB78g+egA1G98rbJ03Vw==} + engines: {node: '>=14'} + + '@apollo/utils.logger@1.0.1': + resolution: {integrity: sha512-XdlzoY7fYNK4OIcvMD2G94RoFZbzTQaNP0jozmqqMudmaGo2I/2Jx71xlDJ801mWA/mbYRihyaw6KJii7k5RVA==} + + '@apollo/utils.logger@2.0.1': + resolution: {integrity: sha512-YuplwLHaHf1oviidB7MxnCXAdHp3IqYV8n0momZ3JfLniae92eYqMIx+j5qJFX6WKJPs6q7bczmV4lXIsTu5Pg==} + engines: {node: '>=14'} + + '@apollo/utils.printwithreducedwhitespace@1.1.0': + resolution: {integrity: sha512-GfFSkAv3n1toDZ4V6u2d7L4xMwLA+lv+6hqXicMN9KELSJ9yy9RzuEXaX73c/Ry+GzRsBy/fdSUGayGqdHfT2Q==} + engines: {node: '>=12.13.0'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.printwithreducedwhitespace@2.0.1': + resolution: {integrity: sha512-9M4LUXV/fQBh8vZWlLvb/HyyhjJ77/I5ZKu+NBWV/BmYGyRmoEP9EVAy7LCVoY3t8BDcyCAGfxJaLFCSuQkPUg==} + engines: {node: '>=14'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.removealiases@1.0.0': + resolution: {integrity: sha512-6cM8sEOJW2LaGjL/0vHV0GtRaSekrPQR4DiywaApQlL9EdROASZU5PsQibe2MWeZCOhNrPRuHh4wDMwPsWTn8A==} + engines: {node: '>=12.13.0'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.removealiases@2.0.1': + resolution: {integrity: sha512-0joRc2HBO4u594Op1nev+mUF6yRnxoUH64xw8x3bX7n8QBDYdeYgY4tF0vJReTy+zdn2xv6fMsquATSgC722FA==} + engines: {node: '>=14'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.sortast@1.1.0': + resolution: {integrity: sha512-VPlTsmUnOwzPK5yGZENN069y6uUHgeiSlpEhRnLFYwYNoJHsuJq2vXVwIaSmts015WTPa2fpz1inkLYByeuRQA==} + engines: {node: '>=12.13.0'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.sortast@2.0.1': + resolution: {integrity: sha512-eciIavsWpJ09za1pn37wpsCGrQNXUhM0TktnZmHwO+Zy9O4fu/WdB4+5BvVhFiZYOXvfjzJUcc+hsIV8RUOtMw==} + engines: {node: '>=14'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.stripsensitiveliterals@1.2.0': + resolution: {integrity: sha512-E41rDUzkz/cdikM5147d8nfCFVKovXxKBcjvLEQ7bjZm/cg9zEcXvS6vFY8ugTubI3fn6zoqo0CyU8zT+BGP9w==} + engines: {node: '>=12.13.0'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.stripsensitiveliterals@2.0.1': + resolution: {integrity: sha512-QJs7HtzXS/JIPMKWimFnUMK7VjkGQTzqD9bKD1h3iuPAqLsxd0mUNVbkYOPTsDhUKgcvUOfOqOJWYohAKMvcSA==} + engines: {node: '>=14'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.usagereporting@1.0.1': + resolution: {integrity: sha512-6dk+0hZlnDbahDBB2mP/PZ5ybrtCJdLMbeNJD+TJpKyZmSY6bA3SjI8Cr2EM9QA+AdziywuWg+SgbWUF3/zQqQ==} + engines: {node: '>=12.13.0'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.usagereporting@2.1.0': + resolution: {integrity: sha512-LPSlBrn+S17oBy5eWkrRSGb98sWmnEzo3DPTZgp8IQc8sJe0prDgDuppGq4NeQlpoqEHz0hQeYHAOA0Z3aQsxQ==} + engines: {node: '>=14'} + peerDependencies: + graphql: 14.x || 15.x || 16.x + + '@apollo/utils.withrequired@2.0.1': + resolution: {integrity: sha512-YBDiuAX9i1lLc6GeTy1m7DGLFn/gMnvXqlalOIMjM7DeOgIacEjjfwPqb0M1CQ2v11HhR15d1NmxJoRCfrNqcA==} + engines: {node: '>=14'} + + '@apollographql/apollo-tools@0.5.4': + resolution: {integrity: sha512-shM3q7rUbNyXVVRkQJQseXv6bnYM3BUma/eZhwXR4xsuM+bqWnJKvW7SAfRjP7LuSCocrexa5AXhjjawNHrIlw==} + engines: {node: '>=8', npm: '>=6'} + peerDependencies: + graphql: ^14.2.1 || ^15.0.0 || ^16.0.0 + + '@apollographql/graphql-playground-html@1.6.29': + resolution: {integrity: sha512-xCcXpoz52rI4ksJSdOCxeOCn2DLocxwHf9dVT/Q90Pte1LX+LY+91SFtJF3KXVHH8kEin+g1KKCQPKBjZJfWNA==} + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} @@ -417,6 +629,9 @@ packages: '@borewit/text-codec@0.1.1': resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} + '@cfworker/json-schema@4.1.1': + resolution: {integrity: sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==} + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} @@ -667,6 +882,64 @@ packages: '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@graphql-tools/merge@8.3.1': + resolution: {integrity: sha512-BMm99mqdNZbEYeTPK3it9r9S6rsZsQKtlqJsSBknAclXq2pGEfOxjcIZi+kBSkHZKPKCRrYDd5vY0+rUmIHVLg==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/merge@8.4.2': + resolution: {integrity: sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/merge@9.0.24': + resolution: {integrity: sha512-NzWx/Afl/1qHT3Nm1bghGG2l4jub28AdvtG11PoUlmjcIjnFBJMv4vqL0qnxWe8A82peWo4/TkVdjJRLXwgGEw==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/mock@8.7.20': + resolution: {integrity: sha512-ljcHSJWjC/ZyzpXd5cfNhPI7YljRVvabKHPzKjEs5ElxWu2cdlLGvyNYepApXDsM/OJG/2xuhGM+9GWu5gEAPQ==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/schema@10.0.23': + resolution: {integrity: sha512-aEGVpd1PCuGEwqTXCStpEkmheTHNdMayiIKH1xDWqYp9i8yKv9FRDgkGrY4RD8TNxnf7iII+6KOBGaJ3ygH95A==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/schema@8.5.1': + resolution: {integrity: sha512-0Esilsh0P/qYcB5DKQpiKeQs/jevzIadNTaT0jeWklPMwNbT7yMX4EqZany7mbeRRlSRwMzNzL5olyFdffHBZg==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/schema@9.0.19': + resolution: {integrity: sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/utils@10.8.6': + resolution: {integrity: sha512-Alc9Vyg0oOsGhRapfL3xvqh1zV8nKoFUdtLhXX7Ki4nClaIJXckrA86j+uxEuG3ic6j4jlM1nvcWXRn/71AVLQ==} + engines: {node: '>=16.0.0'} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/utils@8.9.0': + resolution: {integrity: sha512-pjJIWH0XOVnYGXCqej8g/u/tsfV4LvLlj0eATKQu5zwnxd/TiTHq7Cg313qUPTFFHZ3PP5wJ15chYVtLDwaymg==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-tools/utils@9.2.1': + resolution: {integrity: sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==} + peerDependencies: + graphql: ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@graphql-typed-document-node/core@3.2.0': + resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -928,6 +1201,9 @@ packages: resolution: {integrity: sha512-aREYa3aku9SSnea4aX6bhKn4bgv3AXkgijoQgbYV3yvbiGt6z+MQ85+6mIhx9DsKW2BuB/cLR/A+tcMThx+KLQ==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + '@josephg/resolvable@1.0.1': + resolution: {integrity: sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -950,6 +1226,28 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@langchain/anthropic@0.3.27': + resolution: {integrity: sha512-d4YUwZRjUGAMHTrv7U1jKqsvDrmns9/Ua2I/8BUPbCEBTswowGZUb0Om1KcjXG7MqehrJ03Gd78plckQ8Q7qfw==} + engines: {node: '>=18'} + peerDependencies: + '@langchain/core': '>=0.3.58 <0.4.0' + + '@langchain/core@0.3.75': + resolution: {integrity: sha512-kTyBS0DTeD0JYa9YH5lg6UdDbHmvplk3t9PCjP5jDQZCK5kPe2aDFToqdiCaLzZg8RzzM+clXLVyJtPTE8bZ2Q==} + engines: {node: '>=18'} + + '@langchain/openai@0.6.11': + resolution: {integrity: sha512-BkaudQTLsmdt9mF6tn6CrsK2TEFKk4EhAWYkouGTy/ljJIH/p2Nz9awIOGdrQiQt6AJ5mvKGupyVqy3W/jim2Q==} + engines: {node: '>=18'} + peerDependencies: + '@langchain/core': '>=0.3.68 <0.4.0' + + '@langchain/textsplitters@0.1.0': + resolution: {integrity: sha512-djI4uw9rlkAb5iMhtLED+xJebDdAG935AdP4eRTB02R7OB/act55Bj9wsskhZsvuyQRpO4O1wQOp85s6T6GWmw==} + engines: {node: '>=18'} + peerDependencies: + '@langchain/core': '>=0.2.21 <0.4.0' + '@lukeed/csprng@1.1.0': resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} engines: {node: '>=8'} @@ -960,6 +1258,25 @@ packages: '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + '@nestjs/apollo@13.1.0': + resolution: {integrity: sha512-/FRg195AxpZ58Kjd7geeksaRs3blmlGMDUak7WGbrl7ZWX7J9VuulhTjVHP6Z+dhH4Tn+AsyjkkJ2euC8psv3A==} + peerDependencies: + '@apollo/gateway': ^2.0.0 + '@apollo/server': ^4.11.3 + '@apollo/subgraph': ^2.0.0 + '@as-integrations/fastify': ^2.1.1 + '@nestjs/common': ^11.0.1 + '@nestjs/core': ^11.0.1 + '@nestjs/graphql': ^13.0.0 + graphql: ^16.10.0 + peerDependenciesMeta: + '@apollo/gateway': + optional: true + '@apollo/subgraph': + optional: true + '@as-integrations/fastify': + optional: true + '@nestjs/cli@11.0.10': resolution: {integrity: sha512-4waDT0yGWANg0pKz4E47+nUrqIJv/UqrZ5wLPkCqc7oMGRMWKAaw1NDZ9rKsaqhqvxb2LfI5+uXOWr4yi94DOQ==} engines: {node: '>= 20.11'} @@ -1010,6 +1327,27 @@ packages: '@nestjs/websockets': optional: true + '@nestjs/graphql@13.1.0': + resolution: {integrity: sha512-frjUJOPJNEZVqiFynhDs/+rEor3ySAj4pITTa/szAWRfdPhAxIJzOtZnn+eCLubr4lymlK/q71azFwTFyeVShg==} + peerDependencies: + '@apollo/subgraph': ^2.9.3 + '@nestjs/common': ^11.0.1 + '@nestjs/core': ^11.0.1 + class-transformer: '*' + class-validator: '*' + graphql: ^16.10.0 + reflect-metadata: ^0.1.13 || ^0.2.0 + ts-morph: ^20.0.0 || ^21.0.0 || ^24.0.0 || ^25.0.0 + peerDependenciesMeta: + '@apollo/subgraph': + optional: true + class-transformer: + optional: true + class-validator: + optional: true + ts-morph: + optional: true + '@nestjs/mapped-types@2.1.0': resolution: {integrity: sha512-W+n+rM69XsFdwORF11UqJahn4J3xi4g/ZEOlJNL6KoW5ygWSmBB2p0S2BZ4FQeS/NDH72e6xIcu35SfJnE8bXw==} peerDependencies: @@ -1105,6 +1443,36 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + '@radix-ui/primitive@1.1.3': resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} @@ -1549,6 +1917,9 @@ packages: '@tybys/wasm-util@0.10.0': resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + '@types/accepts@1.3.7': + resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==} + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -1561,6 +1932,9 @@ packages: '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/body-parser@1.19.2': + resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} + '@types/body-parser@1.19.6': resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} @@ -1570,6 +1944,9 @@ packages: '@types/cookiejar@2.1.5': resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} + '@types/cors@2.8.12': + resolution: {integrity: sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==} + '@types/eslint-scope@3.7.7': resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} @@ -1579,9 +1956,21 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/express-serve-static-core@4.17.31': + resolution: {integrity: sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==} + + '@types/express-serve-static-core@4.19.6': + resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} + '@types/express-serve-static-core@5.0.7': resolution: {integrity: sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==} + '@types/express@4.17.14': + resolution: {integrity: sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==} + + '@types/express@4.17.23': + resolution: {integrity: sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==} + '@types/express@5.0.3': resolution: {integrity: sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==} @@ -1603,12 +1992,21 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/long@4.0.2': + resolution: {integrity: sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==} + '@types/methods@1.1.4': resolution: {integrity: sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==} '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + '@types/node-fetch@2.6.13': + resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} + + '@types/node@10.17.60': + resolution: {integrity: sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==} + '@types/node@22.18.1': resolution: {integrity: sha512-rzSDyhn4cYznVG+PCzGe1lwuMYJrcBS1fc3JqSa2PvtABwWo+dZ1ij5OVok3tqfpEBCBoaR4d7upFJk73HRJDw==} @@ -1626,6 +2024,9 @@ packages: '@types/react@19.1.12': resolution: {integrity: sha512-cMoR+FoAf/Jyq6+Df2/Z41jISvGZZ2eTlnsaJRptmZ76Caldwy1odD4xTr/gNV9VLj0AWgg/nmkevIyUfIIq5w==} + '@types/retry@0.12.0': + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + '@types/send@0.17.5': resolution: {integrity: sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==} @@ -1641,6 +2042,9 @@ packages: '@types/supertest@6.0.3': resolution: {integrity: sha512-8WzXq62EXFhJ7QsH3Ocb/iKQ/Ty9ZVWnVzoTKc9tyyFRRF3a74Tk2+TLFgaFFw364Ere+npzHKEJ6ga2LzIL7w==} + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + '@types/validator@13.15.3': resolution: {integrity: sha512-7bcUmDyS6PN3EuD9SlGGOxM77F8WLVsrwkxyWxKnxzmXoequ6c7741QBrANq6htVRGOITJ7z72mTP6Z4XyuG+Q==} @@ -1858,12 +2262,36 @@ packages: '@webassemblyjs/wast-printer@1.14.1': resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + '@whatwg-node/promise-helpers@1.3.2': + resolution: {integrity: sha512-Nst5JdK47VIl9UcGwtv2Rcgyn5lWtZ0/mhRQ4G8NN2isxpq2TO30iqHzmwoJycjWuyUfg3GFXqP/gFHXeV57IA==} + engines: {node: '>=16.0.0'} + + '@wry/caches@1.0.1': + resolution: {integrity: sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==} + engines: {node: '>=8'} + + '@wry/context@0.7.4': + resolution: {integrity: sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==} + engines: {node: '>=8'} + + '@wry/equality@0.5.7': + resolution: {integrity: sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==} + engines: {node: '>=8'} + + '@wry/trie@0.5.0': + resolution: {integrity: sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==} + engines: {node: '>=8'} + '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} '@xtuc/long@4.2.2': resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + 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'} @@ -1960,6 +2388,56 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + apollo-datasource@3.3.2: + resolution: {integrity: sha512-L5TiS8E2Hn/Yz7SSnWIVbZw0ZfEIXZCa5VUiVxD9P53JvSrf4aStvsFDlGWPvpIdCR+aly2CfoB79B9/JjKFqg==} + engines: {node: '>=12.0'} + deprecated: The `apollo-datasource` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details. + + apollo-reporting-protobuf@3.4.0: + resolution: {integrity: sha512-h0u3EbC/9RpihWOmcSsvTW2O6RXVaD/mPEjfrPkxRPTEPWqncsgOoRJw+wih4OqfH3PvTJvoEIf4LwKrUaqWog==} + deprecated: The `apollo-reporting-protobuf` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/usage-reporting-protobuf` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details. + + apollo-server-core@3.13.0: + resolution: {integrity: sha512-v/g6DR6KuHn9DYSdtQijz8dLOkP78I5JSVJzPkARhDbhpH74QNwrQ2PP2URAPPEDJ2EeZNQDX8PvbYkAKqg+kg==} + engines: {node: '>=12.0'} + deprecated: The `apollo-server-core` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details. + peerDependencies: + graphql: ^15.3.0 || ^16.0.0 + + apollo-server-env@4.2.1: + resolution: {integrity: sha512-vm/7c7ld+zFMxibzqZ7SSa5tBENc4B0uye9LTfjJwGoQFY5xsUPH5FpO5j0bMUDZ8YYNbrF9SNtzc5Cngcr90g==} + engines: {node: '>=12.0'} + deprecated: The `apollo-server-env` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/utils.fetcher` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details. + + apollo-server-errors@3.3.1: + resolution: {integrity: sha512-xnZJ5QWs6FixHICXHxUfm+ZWqqxrNuPlQ+kj5m6RtEgIpekOPssH/SD9gf2B4HuWV0QozorrygwZnux8POvyPA==} + engines: {node: '>=12.0'} + deprecated: The `apollo-server-errors` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details. + peerDependencies: + graphql: ^15.3.0 || ^16.0.0 + + apollo-server-express@3.13.0: + resolution: {integrity: sha512-iSxICNbDUyebOuM8EKb3xOrpIwOQgKxGbR2diSr4HP3IW8T3njKFOoMce50vr+moOCe1ev8BnLcw9SNbuUtf7g==} + engines: {node: '>=12.0'} + deprecated: The `apollo-server-express` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details. + peerDependencies: + express: ^4.17.1 + graphql: ^15.3.0 || ^16.0.0 + + apollo-server-plugin-base@3.7.2: + resolution: {integrity: sha512-wE8dwGDvBOGehSsPTRZ8P/33Jan6/PmL0y0aN/1Z5a5GcbFhDaaJCjK5cav6npbbGL2DPKK0r6MPXi3k3N45aw==} + engines: {node: '>=12.0'} + deprecated: The `apollo-server-plugin-base` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details. + peerDependencies: + graphql: ^15.3.0 || ^16.0.0 + + apollo-server-types@3.8.0: + resolution: {integrity: sha512-ZI/8rTE4ww8BHktsVpb91Sdq7Cb71rdSkXELSwdSR0eXu600/sY+1UXhTWdiJvk+Eq5ljqoHLwLbY2+Clq2b9A==} + engines: {node: '>=12.0'} + deprecated: The `apollo-server-types` package is part of Apollo Server v2 and v3, which are now end-of-life (as of October 22nd 2023 and October 22nd 2024, respectively). This package's functionality is now found in the `@apollo/server` package. See https://www.apollographql.com/docs/apollo-server/previous-versions/ for more details. + peerDependencies: + graphql: ^15.3.0 || ^16.0.0 + app-root-path@3.1.0: resolution: {integrity: sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==} engines: {node: '>= 6.0.0'} @@ -1984,6 +2462,9 @@ packages: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} + 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'} @@ -2013,6 +2494,9 @@ packages: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} engines: {node: '>= 0.4'} + async-retry@1.3.3: + resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -2057,6 +2541,9 @@ packages: peerDependencies: '@babel/core': ^7.11.0 + backo2@1.0.2: + resolution: {integrity: sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -2069,6 +2556,10 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@2.2.0: resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} engines: {node: '>=18'} @@ -2249,6 +2740,13 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} + console-table-printer@2.14.6: + resolution: {integrity: sha512-MCBl5HNVaFuuHW6FGbL/4fB7N/ormCy+tQ+sxTrF6QtSbSNETvPuOVbkJBhzDgYhvjWGrTma4eYJa37ZuoQsPw==} + + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + content-disposition@1.0.0: resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} engines: {node: '>= 0.6'} @@ -2260,10 +2758,17 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-signature@1.0.6: + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} engines: {node: '>=6.6.0'} + cookie@0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + engines: {node: '>= 0.6'} + cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} @@ -2294,10 +2799,17 @@ packages: create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + cross-inspect@1.0.1: + resolution: {integrity: sha512-Pcw1JTvZLSJH83iiGWt6fRcT+BjZlCDRVwYLbUcHzv/CRpB7r0MlSrGbIyQvVSNyGnbt7G4AXuyCiDR3POvZ1A==} + engines: {node: '>=16.0.0'} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + cssfilter@0.0.10: + resolution: {integrity: sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -2319,6 +2831,14 @@ packages: dayjs@1.11.18: resolution: {integrity: sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==} + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.1: resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} engines: {node: '>=6.0'} @@ -2328,6 +2848,10 @@ packages: supports-color: optional: true + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dedent@1.7.0: resolution: {integrity: sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==} peerDependencies: @@ -2366,6 +2890,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + detect-libc@2.0.4: resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} @@ -2393,6 +2921,10 @@ packages: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} + dset@3.1.4: + resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==} + engines: {node: '>=4'} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -2416,6 +2948,10 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -2597,6 +3133,12 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + eventemitter3@3.1.2: + resolution: {integrity: sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==} + + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} @@ -2613,6 +3155,10 @@ packages: resolution: {integrity: sha512-xvHszRavo28ejws8FpemjhwswGj4w/BetHIL8cU49u4sGyXDw2+p3YbeDbj6xzlxi6kWTjIRSTJ+9sNXPnF0Zg==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + express@4.21.2: + resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} + engines: {node: '>= 0.10.0'} + express@5.1.0: resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} engines: {node: '>= 18'} @@ -2639,6 +3185,10 @@ packages: fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-xml-parser@4.5.3: + resolution: {integrity: sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==} + hasBin: true + fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} @@ -2669,6 +3219,10 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + engines: {node: '>= 0.8'} + finalhandler@2.1.0: resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} engines: {node: '>= 0.8'} @@ -2715,6 +3269,10 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} + 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'} @@ -2821,6 +3379,56 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + graphql-subscriptions@3.0.0: + resolution: {integrity: sha512-kZCdevgmzDjGAOqH7GlDmQXYAkuHoKpMlJrqF40HMPhUhM5ZWSFSxCwD/nSi6AkaijmMfsFhoJRGJ27UseCvRA==} + peerDependencies: + graphql: ^15.7.2 || ^16.0.0 + + graphql-tag@2.12.6: + resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} + engines: {node: '>=10'} + peerDependencies: + graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + + graphql-ws@6.0.4: + resolution: {integrity: sha512-8b4OZtNOvv8+NZva8HXamrc0y1jluYC0+13gdh7198FKjVzXyTvVc95DCwGzaKEfn3YuWZxUqjJlHe3qKM/F2g==} + engines: {node: '>=20'} + peerDependencies: + '@fastify/websocket': ^10 || ^11 + graphql: ^15.10.1 || ^16 + uWebSockets.js: ^20 + ws: ^8 + peerDependenciesMeta: + '@fastify/websocket': + optional: true + uWebSockets.js: + optional: true + ws: + optional: true + + graphql-ws@6.0.6: + resolution: {integrity: sha512-zgfER9s+ftkGKUZgc0xbx8T7/HMO4AV5/YuYiFc+AtgcO5T0v8AxYYNQ+ltzuzDZgNkYJaFspm5MMYLjQzrkmw==} + engines: {node: '>=20'} + peerDependencies: + '@fastify/websocket': ^10 || ^11 + crossws: ~0.3 + graphql: ^15.10.1 || ^16 + uWebSockets.js: ^20 + ws: ^8 + peerDependenciesMeta: + '@fastify/websocket': + optional: true + crossws: + optional: true + uWebSockets.js: + optional: true + ws: + optional: true + + graphql@16.11.0: + resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + handlebars@4.7.8: resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} engines: {node: '>=0.4.7'} @@ -2868,6 +3476,10 @@ packages: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} @@ -3072,6 +3684,9 @@ packages: resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} + iterall@1.3.0: + resolution: {integrity: sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg==} + iterare@1.2.1: resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} engines: {node: '>=6'} @@ -3219,6 +3834,9 @@ packages: resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} hasBin: true + js-tiktoken@1.0.21: + resolution: {integrity: sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -3261,6 +3879,10 @@ packages: jsonfile@6.2.0: resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jsonpointer@5.0.1: + resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} + engines: {node: '>=0.10.0'} + jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} @@ -3268,6 +3890,81 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + langchain@0.3.33: + resolution: {integrity: sha512-MgMfy/68/xUi02dSg4AZhXjo4jQ+WuVYrU/ryzn59nUb+LXaMRoP/C9eaqblin0OLqGp93jfT8FXDg5mcqSg5A==} + engines: {node: '>=18'} + peerDependencies: + '@langchain/anthropic': '*' + '@langchain/aws': '*' + '@langchain/cerebras': '*' + '@langchain/cohere': '*' + '@langchain/core': '>=0.3.58 <0.4.0' + '@langchain/deepseek': '*' + '@langchain/google-genai': '*' + '@langchain/google-vertexai': '*' + '@langchain/google-vertexai-web': '*' + '@langchain/groq': '*' + '@langchain/mistralai': '*' + '@langchain/ollama': '*' + '@langchain/xai': '*' + axios: '*' + cheerio: '*' + handlebars: ^4.7.8 + peggy: ^3.0.2 + typeorm: '*' + peerDependenciesMeta: + '@langchain/anthropic': + optional: true + '@langchain/aws': + optional: true + '@langchain/cerebras': + optional: true + '@langchain/cohere': + optional: true + '@langchain/deepseek': + optional: true + '@langchain/google-genai': + optional: true + '@langchain/google-vertexai': + optional: true + '@langchain/google-vertexai-web': + optional: true + '@langchain/groq': + optional: true + '@langchain/mistralai': + optional: true + '@langchain/ollama': + optional: true + '@langchain/xai': + optional: true + axios: + optional: true + cheerio: + optional: true + handlebars: + optional: true + peggy: + optional: true + typeorm: + optional: true + + langsmith@0.3.67: + resolution: {integrity: sha512-l4y3RmJ9yWF5a29fLg3eWZQxn6Q6dxTOgLGgQHzPGZHF3NUynn+A+airYIe/Yt4rwjGbuVrABAPsXBkVu/Hi7g==} + peerDependencies: + '@opentelemetry/api': '*' + '@opentelemetry/exporter-trace-otlp-proto': '*' + '@opentelemetry/sdk-trace-base': '*' + openai: '*' + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@opentelemetry/exporter-trace-otlp-proto': + optional: true + '@opentelemetry/sdk-trace-base': + optional: true + openai: + optional: true + language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -3375,6 +4072,13 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.omit@4.5.0: + resolution: {integrity: sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==} + deprecated: This package is deprecated. Use destructuring assignment syntax instead. + + lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -3382,6 +4086,13 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + loglevel@1.9.2: + resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} + engines: {node: '>= 0.6.0'} + + long@4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + long@5.3.2: resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} @@ -3395,6 +4106,14 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + lru-cache@7.13.1: + resolution: {integrity: sha512-CHqbAq7NFlW3RSnoWXLJBxCWaZVBrfa9UEHId2M3AW8iEBurbqduNexEUCGc3SHc6iCYXNJCDi903LajSVAEPQ==} + engines: {node: '>=12'} + lru-cache@7.18.3: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} @@ -3443,6 +4162,9 @@ packages: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} + 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'} @@ -3478,6 +4200,11 @@ packages: resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} engines: {node: '>= 0.6'} + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + mime@2.6.0: resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} engines: {node: '>=4.0.0'} @@ -3518,6 +4245,9 @@ packages: engines: {node: '>=10'} hasBin: true + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -3525,6 +4255,10 @@ packages: resolution: {integrity: sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==} engines: {node: '>= 10.16.0'} + mustache@4.2.0: + resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} + hasBin: true + mute-stream@2.0.0: resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} engines: {node: ^18.17.0 || >=20.5.0} @@ -3550,6 +4284,14 @@ 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'} + negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} @@ -3563,6 +4305,15 @@ packages: 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-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -3612,6 +4363,24 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + openai@5.12.2: + resolution: {integrity: sha512-xqzHHQch5Tws5PcKR2xsZGX9xtch+JQFz5zb14dGqlshmmDAFBFEWmeIpf7wVqWV+w7Emj7jRgkNJakyKE0tYQ==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.23.8 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + openapi-types@12.1.3: + resolution: {integrity: sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==} + + optimism@0.18.1: + resolution: {integrity: sha512-mLXNwWPa9dgFyDqkNi54sjDyNJ9/fTI6WGBLgnXku1vdKY/jovHfZT5r+aiVeFFLOz+foPNOm5YJ4mqgld2GBQ==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -3624,6 +4393,10 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} + p-finally@1.0.0: + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} + p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -3640,6 +4413,18 @@ packages: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-queue@6.6.2: + resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} + engines: {node: '>=8'} + + p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + + p-timeout@3.2.0: + resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} + engines: {node: '>=8'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -3679,6 +4464,9 @@ packages: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} + path-to-regexp@0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + path-to-regexp@8.2.0: resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} engines: {node: '>=16'} @@ -3800,6 +4588,10 @@ packages: pure-rand@7.0.1: resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + qs@6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} @@ -3814,6 +4606,10 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} + raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + raw-body@3.0.1: resolution: {integrity: sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==} engines: {node: '>= 0.10'} @@ -3898,6 +4694,10 @@ packages: resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} engines: {node: '>=8'} + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -3958,6 +4758,10 @@ packages: engines: {node: '>=10'} hasBin: true + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + engines: {node: '>= 0.8.0'} + send@1.2.0: resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} engines: {node: '>= 18'} @@ -3968,6 +4772,10 @@ packages: serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + engines: {node: '>= 0.8.0'} + serve-static@2.2.0: resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} engines: {node: '>= 18'} @@ -4026,6 +4834,9 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + simple-wcswidth@1.1.2: + resolution: {integrity: sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -4145,10 +4956,19 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strnum@1.1.2: + resolution: {integrity: sha512-vrN+B7DBIoTTZjnPNewwhx6cBA/H+IS7rfW68n7XxC1y7uoiGQBxaKzqucGUgavX15dJgiGztLJ8vxuEzwqBdA==} + strtok3@10.3.4: resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} engines: {node: '>=18'} + subscriptions-transport-ws@0.11.0: + resolution: {integrity: sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ==} + deprecated: The `subscriptions-transport-ws` package is no longer maintained. We recommend you use `graphql-ws` instead. For help migrating Apollo software to `graphql-ws`, see https://www.apollographql.com/docs/apollo-server/data/subscriptions/#switching-from-subscriptions-transport-ws For general help using `graphql-ws`, see https://github.com/enisdenjo/graphql-ws/blob/master/README.md + peerDependencies: + graphql: ^15.7.2 || ^16.0.0 + superagent@10.2.3: resolution: {integrity: sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==} engines: {node: '>=14.18.0'} @@ -4177,6 +4997,10 @@ packages: peerDependencies: express: '>=4.0.0 || >=5.0.0-beta' + symbol-observable@1.2.0: + resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==} + engines: {node: '>=0.10.0'} + symbol-observable@4.0.0: resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} engines: {node: '>=0.10'} @@ -4247,6 +5071,9 @@ packages: resolution: {integrity: sha512-kh9LVIWH5CnL63Ipf0jhlBIy0UsrMj/NJDfpsy1SqOXlLKEVyXXYrnFxFT1yOOYVGBSApeVnjPw/sBz5BfEjAQ==} engines: {node: '>=14.16'} + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -4481,10 +5308,22 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + uuid@10.0.0: + resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} + hasBin: true + uuid@11.1.0: resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} hasBin: true + uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -4496,6 +5335,14 @@ packages: resolution: {integrity: sha512-BgWVbCI72aIQy937xbawcs+hrVaN/CZ2UwutgaJ36hGqRrLNM+f5LUT/YPRbo8IV/ASeFzXszezV+y2+rq3l8A==} engines: {node: '>= 0.10'} + value-or-promise@1.0.11: + resolution: {integrity: sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg==} + engines: {node: '>=12'} + + value-or-promise@1.0.12: + resolution: {integrity: sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==} + engines: {node: '>=12'} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -4550,6 +5397,9 @@ packages: 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'} @@ -4568,6 +5418,13 @@ packages: webpack-cli: optional: true + whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} @@ -4615,6 +5472,35 @@ packages: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.18.1: + resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xss@1.0.15: + resolution: {integrity: sha512-FVdlVVC67WOIPvfOwhoMETV72f6GbW7aOabBC3WxN/oUdoEMDyLz4OgRv5/gck2ZeNqEQu+Tb0kloovXOfpYVg==} + engines: {node: '>= 0.10.0'} + hasBin: true + xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} @@ -4626,10 +5512,18 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yallist@5.0.0: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} + yaml@2.8.1: + resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -4650,6 +5544,14 @@ packages: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} + zod-to-json-schema@3.24.6: + resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} + peerDependencies: + zod: ^3.24.1 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zod@4.1.5: resolution: {integrity: sha512-rcUUZqlLJgBC33IT3PNMgsCq6TzLQEG/Ei/KTCU0PedSWRMAXoOUN+4t/0H+Q8bdnLPdqUYnvboJT0bn/229qg==} @@ -4688,6 +5590,203 @@ snapshots: transitivePeerDependencies: - chokidar + '@anthropic-ai/sdk@0.56.0': {} + + '@apollo/cache-control-types@1.0.3(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + + '@apollo/client@4.0.4(graphql-ws@6.0.6(graphql@16.11.0)(ws@8.18.1))(graphql@16.11.0)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)(rxjs@7.8.2)(subscriptions-transport-ws@0.11.0(graphql@16.11.0))': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.11.0) + '@wry/caches': 1.0.1 + '@wry/equality': 0.5.7 + '@wry/trie': 0.5.0 + graphql: 16.11.0 + graphql-tag: 2.12.6(graphql@16.11.0) + optimism: 0.18.1 + rxjs: 7.8.2 + tslib: 2.8.1 + optionalDependencies: + graphql-ws: 6.0.6(graphql@16.11.0)(ws@8.18.1) + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + subscriptions-transport-ws: 0.11.0(graphql@16.11.0) + + '@apollo/protobufjs@1.2.6': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/long': 4.0.2 + '@types/node': 10.17.60 + long: 4.0.0 + + '@apollo/protobufjs@1.2.7': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/long': 4.0.2 + long: 4.0.0 + + '@apollo/server-gateway-interface@1.1.1(graphql@16.11.0)': + dependencies: + '@apollo/usage-reporting-protobuf': 4.1.1 + '@apollo/utils.fetcher': 2.0.1 + '@apollo/utils.keyvaluecache': 2.1.1 + '@apollo/utils.logger': 2.0.1 + graphql: 16.11.0 + + '@apollo/server-plugin-landing-page-graphql-playground@4.0.1(@apollo/server@4.12.2(graphql@16.11.0))': + dependencies: + '@apollo/server': 4.12.2(graphql@16.11.0) + '@apollographql/graphql-playground-html': 1.6.29 + + '@apollo/server@4.12.2(graphql@16.11.0)': + dependencies: + '@apollo/cache-control-types': 1.0.3(graphql@16.11.0) + '@apollo/server-gateway-interface': 1.1.1(graphql@16.11.0) + '@apollo/usage-reporting-protobuf': 4.1.1 + '@apollo/utils.createhash': 2.0.2 + '@apollo/utils.fetcher': 2.0.1 + '@apollo/utils.isnodelike': 2.0.1 + '@apollo/utils.keyvaluecache': 2.1.1 + '@apollo/utils.logger': 2.0.1 + '@apollo/utils.usagereporting': 2.1.0(graphql@16.11.0) + '@apollo/utils.withrequired': 2.0.1 + '@graphql-tools/schema': 9.0.19(graphql@16.11.0) + '@types/express': 4.17.23 + '@types/express-serve-static-core': 4.19.6 + '@types/node-fetch': 2.6.13 + async-retry: 1.3.3 + cors: 2.8.5 + express: 4.21.2 + graphql: 16.11.0 + loglevel: 1.9.2 + lru-cache: 7.18.3 + negotiator: 0.6.4 + node-abort-controller: 3.1.1 + node-fetch: 2.7.0 + uuid: 9.0.1 + whatwg-mimetype: 3.0.0 + transitivePeerDependencies: + - encoding + - supports-color + + '@apollo/usage-reporting-protobuf@4.1.1': + dependencies: + '@apollo/protobufjs': 1.2.7 + + '@apollo/utils.createhash@2.0.2': + dependencies: + '@apollo/utils.isnodelike': 2.0.1 + sha.js: 2.4.12 + + '@apollo/utils.dropunuseddefinitions@1.1.0(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + + '@apollo/utils.dropunuseddefinitions@2.0.1(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + + '@apollo/utils.fetcher@2.0.1': {} + + '@apollo/utils.isnodelike@2.0.1': {} + + '@apollo/utils.keyvaluecache@1.0.2': + dependencies: + '@apollo/utils.logger': 1.0.1 + lru-cache: 7.13.1 + + '@apollo/utils.keyvaluecache@2.1.1': + dependencies: + '@apollo/utils.logger': 2.0.1 + lru-cache: 7.18.3 + + '@apollo/utils.logger@1.0.1': {} + + '@apollo/utils.logger@2.0.1': {} + + '@apollo/utils.printwithreducedwhitespace@1.1.0(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + + '@apollo/utils.printwithreducedwhitespace@2.0.1(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + + '@apollo/utils.removealiases@1.0.0(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + + '@apollo/utils.removealiases@2.0.1(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + + '@apollo/utils.sortast@1.1.0(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + lodash.sortby: 4.7.0 + + '@apollo/utils.sortast@2.0.1(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + lodash.sortby: 4.7.0 + + '@apollo/utils.stripsensitiveliterals@1.2.0(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + + '@apollo/utils.stripsensitiveliterals@2.0.1(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + + '@apollo/utils.usagereporting@1.0.1(graphql@16.11.0)': + dependencies: + '@apollo/usage-reporting-protobuf': 4.1.1 + '@apollo/utils.dropunuseddefinitions': 1.1.0(graphql@16.11.0) + '@apollo/utils.printwithreducedwhitespace': 1.1.0(graphql@16.11.0) + '@apollo/utils.removealiases': 1.0.0(graphql@16.11.0) + '@apollo/utils.sortast': 1.1.0(graphql@16.11.0) + '@apollo/utils.stripsensitiveliterals': 1.2.0(graphql@16.11.0) + graphql: 16.11.0 + + '@apollo/utils.usagereporting@2.1.0(graphql@16.11.0)': + dependencies: + '@apollo/usage-reporting-protobuf': 4.1.1 + '@apollo/utils.dropunuseddefinitions': 2.0.1(graphql@16.11.0) + '@apollo/utils.printwithreducedwhitespace': 2.0.1(graphql@16.11.0) + '@apollo/utils.removealiases': 2.0.1(graphql@16.11.0) + '@apollo/utils.sortast': 2.0.1(graphql@16.11.0) + '@apollo/utils.stripsensitiveliterals': 2.0.1(graphql@16.11.0) + graphql: 16.11.0 + + '@apollo/utils.withrequired@2.0.1': {} + + '@apollographql/apollo-tools@0.5.4(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + + '@apollographql/graphql-playground-html@1.6.29': + dependencies: + xss: 1.0.15 + '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 @@ -4889,6 +5988,8 @@ snapshots: '@borewit/text-codec@0.1.1': {} + '@cfworker/json-schema@4.1.1': {} + '@colors/colors@1.5.0': optional: true @@ -5121,6 +6222,79 @@ snapshots: '@floating-ui/utils@0.2.10': {} + '@graphql-tools/merge@8.3.1(graphql@16.11.0)': + dependencies: + '@graphql-tools/utils': 8.9.0(graphql@16.11.0) + graphql: 16.11.0 + tslib: 2.8.1 + + '@graphql-tools/merge@8.4.2(graphql@16.11.0)': + dependencies: + '@graphql-tools/utils': 9.2.1(graphql@16.11.0) + graphql: 16.11.0 + tslib: 2.8.1 + + '@graphql-tools/merge@9.0.24(graphql@16.11.0)': + dependencies: + '@graphql-tools/utils': 10.8.6(graphql@16.11.0) + graphql: 16.11.0 + tslib: 2.8.1 + + '@graphql-tools/mock@8.7.20(graphql@16.11.0)': + dependencies: + '@graphql-tools/schema': 9.0.19(graphql@16.11.0) + '@graphql-tools/utils': 9.2.1(graphql@16.11.0) + fast-json-stable-stringify: 2.1.0 + graphql: 16.11.0 + tslib: 2.8.1 + + '@graphql-tools/schema@10.0.23(graphql@16.11.0)': + dependencies: + '@graphql-tools/merge': 9.0.24(graphql@16.11.0) + '@graphql-tools/utils': 10.8.6(graphql@16.11.0) + graphql: 16.11.0 + tslib: 2.8.1 + + '@graphql-tools/schema@8.5.1(graphql@16.11.0)': + dependencies: + '@graphql-tools/merge': 8.3.1(graphql@16.11.0) + '@graphql-tools/utils': 8.9.0(graphql@16.11.0) + graphql: 16.11.0 + tslib: 2.8.1 + value-or-promise: 1.0.11 + + '@graphql-tools/schema@9.0.19(graphql@16.11.0)': + dependencies: + '@graphql-tools/merge': 8.4.2(graphql@16.11.0) + '@graphql-tools/utils': 9.2.1(graphql@16.11.0) + graphql: 16.11.0 + tslib: 2.8.1 + value-or-promise: 1.0.12 + + '@graphql-tools/utils@10.8.6(graphql@16.11.0)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.11.0) + '@whatwg-node/promise-helpers': 1.3.2 + cross-inspect: 1.0.1 + dset: 3.1.4 + graphql: 16.11.0 + tslib: 2.8.1 + + '@graphql-tools/utils@8.9.0(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + tslib: 2.8.1 + + '@graphql-tools/utils@9.2.1(graphql@16.11.0)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.11.0) + graphql: 16.11.0 + tslib: 2.8.1 + + '@graphql-typed-document-node/core@3.2.0(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -5478,6 +6652,8 @@ snapshots: '@types/yargs': 17.0.33 chalk: 4.1.2 + '@josephg/resolvable@1.0.1': {} + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -5507,6 +6683,46 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@langchain/anthropic@0.3.27(@langchain/core@0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76)))': + dependencies: + '@anthropic-ai/sdk': 0.56.0 + '@langchain/core': 0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76)) + fast-xml-parser: 4.5.3 + + '@langchain/core@0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76))': + dependencies: + '@cfworker/json-schema': 4.1.1 + ansi-styles: 5.2.0 + camelcase: 6.3.0 + decamelize: 1.2.0 + js-tiktoken: 1.0.21 + langsmith: 0.3.67(openai@5.12.2(ws@8.18.1)(zod@3.25.76)) + mustache: 4.2.0 + p-queue: 6.6.2 + p-retry: 4.6.2 + uuid: 10.0.0 + zod: 3.25.76 + zod-to-json-schema: 3.24.6(zod@3.25.76) + transitivePeerDependencies: + - '@opentelemetry/api' + - '@opentelemetry/exporter-trace-otlp-proto' + - '@opentelemetry/sdk-trace-base' + - openai + + '@langchain/openai@0.6.11(@langchain/core@0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76)))(ws@8.18.1)': + dependencies: + '@langchain/core': 0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76)) + js-tiktoken: 1.0.21 + openai: 5.12.2(ws@8.18.1)(zod@3.25.76) + zod: 3.25.76 + transitivePeerDependencies: + - ws + + '@langchain/textsplitters@0.1.0(@langchain/core@0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76)))': + dependencies: + '@langchain/core': 0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76)) + js-tiktoken: 1.0.21 + '@lukeed/csprng@1.1.0': {} '@microsoft/tsdoc@0.15.1': {} @@ -5518,6 +6734,18 @@ snapshots: '@tybys/wasm-util': 0.10.0 optional: true + '@nestjs/apollo@13.1.0(@apollo/server@4.12.2(graphql@16.11.0))(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(@nestjs/graphql@13.1.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(class-validator@0.14.2)(graphql@16.11.0)(reflect-metadata@0.2.2))(graphql@16.11.0)': + dependencies: + '@apollo/server': 4.12.2(graphql@16.11.0) + '@apollo/server-plugin-landing-page-graphql-playground': 4.0.1(@apollo/server@4.12.2(graphql@16.11.0)) + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/graphql': 13.1.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(class-validator@0.14.2)(graphql@16.11.0)(reflect-metadata@0.2.2) + graphql: 16.11.0 + iterall: 1.3.0 + lodash.omit: 4.5.0 + tslib: 2.8.1 + '@nestjs/cli@11.0.10(@types/node@22.18.1)': dependencies: '@angular-devkit/core': 19.2.15(chokidar@4.0.3) @@ -5581,6 +6809,33 @@ snapshots: optionalDependencies: '@nestjs/platform-express': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6) + '@nestjs/graphql@13.1.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.6)(class-validator@0.14.2)(graphql@16.11.0)(reflect-metadata@0.2.2)': + dependencies: + '@graphql-tools/merge': 9.0.24(graphql@16.11.0) + '@graphql-tools/schema': 10.0.23(graphql@16.11.0) + '@graphql-tools/utils': 10.8.6(graphql@16.11.0) + '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/core': 11.1.6(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.6)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/mapped-types': 2.1.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-validator@0.14.2)(reflect-metadata@0.2.2) + chokidar: 4.0.3 + fast-glob: 3.3.3 + graphql: 16.11.0 + graphql-tag: 2.12.6(graphql@16.11.0) + graphql-ws: 6.0.4(graphql@16.11.0)(ws@8.18.1) + lodash: 4.17.21 + normalize-path: 3.0.0 + reflect-metadata: 0.2.2 + subscriptions-transport-ws: 0.11.0(graphql@16.11.0) + tslib: 2.8.1 + ws: 8.18.1 + optionalDependencies: + class-validator: 0.14.2 + transitivePeerDependencies: + - '@fastify/websocket' + - bufferutil + - uWebSockets.js + - utf-8-validate + '@nestjs/mapped-types@2.1.0(@nestjs/common@11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-validator@0.14.2)(reflect-metadata@0.2.2)': dependencies: '@nestjs/common': 11.1.6(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -5668,6 +6923,29 @@ snapshots: '@pkgr/core@0.2.9': {} + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + '@radix-ui/primitive@1.1.3': {} '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.9(@types/react@19.1.12))(@types/react@19.1.12)(react-dom@19.1.1(react@19.1.1))(react@19.1.1)': @@ -5987,12 +7265,12 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.13 '@tailwindcss/oxide-win32-x64-msvc': 4.1.13 - '@tailwindcss/vite@4.1.13(vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0))': + '@tailwindcss/vite@4.1.13(vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))': dependencies: '@tailwindcss/node': 4.1.13 '@tailwindcss/oxide': 4.1.13 tailwindcss: 4.1.13 - vite: 7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0) + vite: 7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1) '@tokenizer/inflate@0.2.7': dependencies: @@ -6017,6 +7295,10 @@ snapshots: tslib: 2.8.1 optional: true + '@types/accepts@1.3.7': + dependencies: + '@types/node': 22.18.1 + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.28.4 @@ -6038,6 +7320,11 @@ snapshots: dependencies: '@babel/types': 7.28.4 + '@types/body-parser@1.19.2': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 22.18.1 + '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 @@ -6049,6 +7336,8 @@ snapshots: '@types/cookiejar@2.1.5': {} + '@types/cors@2.8.12': {} + '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 9.6.1 @@ -6061,6 +7350,19 @@ snapshots: '@types/estree@1.0.8': {} + '@types/express-serve-static-core@4.17.31': + dependencies: + '@types/node': 22.18.1 + '@types/qs': 6.14.0 + '@types/range-parser': 1.2.7 + + '@types/express-serve-static-core@4.19.6': + dependencies: + '@types/node': 22.18.1 + '@types/qs': 6.14.0 + '@types/range-parser': 1.2.7 + '@types/send': 0.17.5 + '@types/express-serve-static-core@5.0.7': dependencies: '@types/node': 22.18.1 @@ -6068,6 +7370,20 @@ snapshots: '@types/range-parser': 1.2.7 '@types/send': 0.17.5 + '@types/express@4.17.14': + dependencies: + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 4.17.31 + '@types/qs': 6.14.0 + '@types/serve-static': 1.15.8 + + '@types/express@4.17.23': + dependencies: + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 4.19.6 + '@types/qs': 6.14.0 + '@types/serve-static': 1.15.8 + '@types/express@5.0.3': dependencies: '@types/body-parser': 1.19.6 @@ -6093,10 +7409,19 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/long@4.0.2': {} + '@types/methods@1.1.4': {} '@types/mime@1.3.5': {} + '@types/node-fetch@2.6.13': + dependencies: + '@types/node': 22.18.1 + form-data: 4.0.4 + + '@types/node@10.17.60': {} + '@types/node@22.18.1': dependencies: undici-types: 6.21.0 @@ -6113,6 +7438,8 @@ snapshots: dependencies: csstype: 3.1.3 + '@types/retry@0.12.0': {} + '@types/send@0.17.5': dependencies: '@types/mime': 1.3.5 @@ -6138,6 +7465,8 @@ snapshots: '@types/methods': 1.1.4 '@types/superagent': 8.1.9 + '@types/uuid@10.0.0': {} + '@types/validator@13.15.3': {} '@types/yargs-parser@21.0.3': {} @@ -6300,7 +7629,7 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-react@5.0.2(vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0))': + '@vitejs/plugin-react@5.0.2(vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))': dependencies: '@babel/core': 7.28.4 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) @@ -6308,7 +7637,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.34 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0) + vite: 7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color @@ -6388,10 +7717,35 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 + '@whatwg-node/promise-helpers@1.3.2': + dependencies: + tslib: 2.8.1 + + '@wry/caches@1.0.1': + dependencies: + tslib: 2.8.1 + + '@wry/context@0.7.4': + dependencies: + tslib: 2.8.1 + + '@wry/equality@0.5.7': + dependencies: + tslib: 2.8.1 + + '@wry/trie@0.5.0': + dependencies: + tslib: 2.8.1 + '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + accepts@2.0.0: dependencies: mime-types: 3.0.1 @@ -6469,6 +7823,92 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + apollo-datasource@3.3.2: + dependencies: + '@apollo/utils.keyvaluecache': 1.0.2 + apollo-server-env: 4.2.1 + transitivePeerDependencies: + - encoding + + apollo-reporting-protobuf@3.4.0: + dependencies: + '@apollo/protobufjs': 1.2.6 + + apollo-server-core@3.13.0(graphql@16.11.0): + dependencies: + '@apollo/utils.keyvaluecache': 1.0.2 + '@apollo/utils.logger': 1.0.1 + '@apollo/utils.usagereporting': 1.0.1(graphql@16.11.0) + '@apollographql/apollo-tools': 0.5.4(graphql@16.11.0) + '@apollographql/graphql-playground-html': 1.6.29 + '@graphql-tools/mock': 8.7.20(graphql@16.11.0) + '@graphql-tools/schema': 8.5.1(graphql@16.11.0) + '@josephg/resolvable': 1.0.1 + apollo-datasource: 3.3.2 + apollo-reporting-protobuf: 3.4.0 + apollo-server-env: 4.2.1 + apollo-server-errors: 3.3.1(graphql@16.11.0) + apollo-server-plugin-base: 3.7.2(graphql@16.11.0) + apollo-server-types: 3.8.0(graphql@16.11.0) + async-retry: 1.3.3 + fast-json-stable-stringify: 2.1.0 + graphql: 16.11.0 + graphql-tag: 2.12.6(graphql@16.11.0) + loglevel: 1.9.2 + lru-cache: 6.0.0 + node-abort-controller: 3.1.1 + sha.js: 2.4.12 + uuid: 9.0.1 + whatwg-mimetype: 3.0.0 + transitivePeerDependencies: + - encoding + + apollo-server-env@4.2.1: + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + apollo-server-errors@3.3.1(graphql@16.11.0): + dependencies: + graphql: 16.11.0 + + apollo-server-express@3.13.0(express@5.1.0)(graphql@16.11.0): + dependencies: + '@types/accepts': 1.3.7 + '@types/body-parser': 1.19.2 + '@types/cors': 2.8.12 + '@types/express': 4.17.14 + '@types/express-serve-static-core': 4.17.31 + accepts: 1.3.8 + apollo-server-core: 3.13.0(graphql@16.11.0) + apollo-server-types: 3.8.0(graphql@16.11.0) + body-parser: 1.20.3 + cors: 2.8.5 + express: 5.1.0 + graphql: 16.11.0 + parseurl: 1.3.3 + transitivePeerDependencies: + - encoding + - supports-color + + apollo-server-plugin-base@3.7.2(graphql@16.11.0): + dependencies: + apollo-server-types: 3.8.0(graphql@16.11.0) + graphql: 16.11.0 + transitivePeerDependencies: + - encoding + + apollo-server-types@3.8.0(graphql@16.11.0): + dependencies: + '@apollo/utils.keyvaluecache': 1.0.2 + '@apollo/utils.logger': 1.0.1 + apollo-reporting-protobuf: 3.4.0 + apollo-server-env: 4.2.1 + graphql: 16.11.0 + transitivePeerDependencies: + - encoding + app-root-path@3.1.0: {} append-field@1.0.0: {} @@ -6488,6 +7928,8 @@ snapshots: call-bound: 1.0.4 is-array-buffer: 3.0.5 + array-flatten@1.1.1: {} + array-includes@3.1.9: dependencies: call-bind: 1.0.8 @@ -6531,6 +7973,10 @@ snapshots: async-function@1.0.0: {} + async-retry@1.3.3: + dependencies: + retry: 0.13.1 + asynckit@0.4.0: {} available-typed-arrays@1.0.7: @@ -6598,6 +8044,8 @@ snapshots: babel-plugin-jest-hoist: 30.0.1 babel-preset-current-node-syntax: 1.2.0(@babel/core@7.28.4) + backo2@1.0.2: {} + balanced-match@1.0.2: {} base64-js@1.5.1: {} @@ -6610,6 +8058,23 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + body-parser@1.20.3: + 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.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.13.0 + raw-body: 2.5.2 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + body-parser@2.2.0: dependencies: bytes: 3.1.2 @@ -6791,6 +8256,14 @@ snapshots: consola@3.4.2: {} + console-table-printer@2.14.6: + dependencies: + simple-wcswidth: 1.1.2 + + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + content-disposition@1.0.0: dependencies: safe-buffer: 5.2.1 @@ -6799,8 +8272,12 @@ snapshots: convert-source-map@2.0.0: {} + cookie-signature@1.0.6: {} + cookie-signature@1.2.2: {} + cookie@0.7.1: {} + cookie@0.7.2: {} cookie@1.0.2: {} @@ -6825,12 +8302,18 @@ snapshots: create-require@1.1.1: {} + cross-inspect@1.0.1: + dependencies: + tslib: 2.8.1 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 + cssfilter@0.0.10: {} + csstype@3.1.3: {} damerau-levenshtein@1.0.8: {} @@ -6855,10 +8338,16 @@ snapshots: dayjs@1.11.18: {} + debug@2.6.9: + dependencies: + ms: 2.0.0 + debug@4.4.1: dependencies: ms: 2.1.3 + decamelize@1.2.0: {} + dedent@1.7.0: {} deep-is@0.1.4: {} @@ -6888,6 +8377,8 @@ snapshots: depd@2.0.0: {} + destroy@1.2.0: {} + detect-libc@2.0.4: {} detect-newline@3.1.0: {} @@ -6907,6 +8398,8 @@ snapshots: dotenv@16.6.1: {} + dset@3.1.4: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -6925,6 +8418,8 @@ snapshots: emoji-regex@9.2.2: {} + encodeurl@1.0.2: {} + encodeurl@2.0.0: {} enhanced-resolve@5.18.3: @@ -7221,6 +8716,10 @@ snapshots: etag@1.8.1: {} + eventemitter3@3.1.2: {} + + eventemitter3@4.0.7: {} + events@3.3.0: {} execa@5.1.1: @@ -7246,6 +8745,42 @@ snapshots: jest-mock: 30.0.5 jest-util: 30.0.5 + express@4.21.2: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.3 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.1 + 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.1 + fresh: 0.5.2 + http-errors: 2.0.0 + 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.13.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.0 + serve-static: 1.16.2 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + express@5.1.0: dependencies: accepts: 2.0.0 @@ -7298,6 +8833,10 @@ snapshots: fast-uri@3.1.0: {} + fast-xml-parser@4.5.3: + dependencies: + strnum: 1.1.2 + fastq@1.19.1: dependencies: reusify: 1.1.0 @@ -7329,6 +8868,18 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@1.3.1: + 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.1 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + finalhandler@2.1.0: dependencies: debug: 4.4.1 @@ -7399,6 +8950,8 @@ snapshots: forwarded@0.2.0: {} + fresh@0.5.2: {} + fresh@2.0.0: {} fs-extra@10.1.0: @@ -7516,6 +9069,29 @@ snapshots: graphemer@1.4.0: {} + graphql-subscriptions@3.0.0(graphql@16.11.0): + dependencies: + graphql: 16.11.0 + + graphql-tag@2.12.6(graphql@16.11.0): + dependencies: + graphql: 16.11.0 + tslib: 2.8.1 + + graphql-ws@6.0.4(graphql@16.11.0)(ws@8.18.1): + dependencies: + graphql: 16.11.0 + optionalDependencies: + ws: 8.18.1 + + graphql-ws@6.0.6(graphql@16.11.0)(ws@8.18.1): + dependencies: + graphql: 16.11.0 + optionalDependencies: + ws: 8.18.1 + + graphql@16.11.0: {} + handlebars@4.7.8: dependencies: minimist: 1.2.8 @@ -7561,6 +9137,10 @@ snapshots: human-signals@2.1.0: {} + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 @@ -7767,6 +9347,8 @@ snapshots: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 + iterall@1.3.0: {} + iterare@1.2.1: {} jackspeak@3.4.3: @@ -8099,6 +9681,10 @@ snapshots: jiti@2.5.1: {} + js-tiktoken@1.0.21: + dependencies: + base64-js: 1.5.1 + js-tokens@4.0.0: {} js-yaml@3.14.1: @@ -8132,6 +9718,8 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 + jsonpointer@5.0.1: {} + jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.9 @@ -8143,6 +9731,43 @@ snapshots: dependencies: json-buffer: 3.0.1 + langchain@0.3.33(@langchain/anthropic@0.3.27(@langchain/core@0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76))))(@langchain/core@0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76)))(handlebars@4.7.8)(openai@5.12.2(ws@8.18.1)(zod@3.25.76))(typeorm@0.3.26(mysql2@3.14.4)(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)))(ws@8.18.1): + dependencies: + '@langchain/core': 0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76)) + '@langchain/openai': 0.6.11(@langchain/core@0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76)))(ws@8.18.1) + '@langchain/textsplitters': 0.1.0(@langchain/core@0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76))) + js-tiktoken: 1.0.21 + js-yaml: 4.1.0 + jsonpointer: 5.0.1 + langsmith: 0.3.67(openai@5.12.2(ws@8.18.1)(zod@3.25.76)) + openapi-types: 12.1.3 + p-retry: 4.6.2 + uuid: 10.0.0 + yaml: 2.8.1 + zod: 3.25.76 + optionalDependencies: + '@langchain/anthropic': 0.3.27(@langchain/core@0.3.75(openai@5.12.2(ws@8.18.1)(zod@3.25.76))) + handlebars: 4.7.8 + typeorm: 0.3.26(mysql2@3.14.4)(pg@8.16.3)(reflect-metadata@0.2.2)(ts-node@10.9.2(@types/node@22.18.1)(typescript@5.8.3)) + transitivePeerDependencies: + - '@opentelemetry/api' + - '@opentelemetry/exporter-trace-otlp-proto' + - '@opentelemetry/sdk-trace-base' + - openai + - ws + + langsmith@0.3.67(openai@5.12.2(ws@8.18.1)(zod@3.25.76)): + dependencies: + '@types/uuid': 10.0.0 + chalk: 4.1.2 + console-table-printer: 2.14.6 + p-queue: 6.6.2 + p-retry: 4.6.2 + semver: 7.7.2 + uuid: 10.0.0 + optionalDependencies: + openai: 5.12.2(ws@8.18.1)(zod@3.25.76) + language-subtag-registry@0.3.23: {} language-tags@1.0.9: @@ -8221,6 +9846,10 @@ snapshots: lodash.merge@4.6.2: {} + lodash.omit@4.5.0: {} + + lodash.sortby@4.7.0: {} + lodash@4.17.21: {} log-symbols@4.1.0: @@ -8228,6 +9857,10 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + loglevel@1.9.2: {} + + long@4.0.0: {} + long@5.3.2: optional: true @@ -8239,8 +9872,13 @@ snapshots: dependencies: yallist: 3.1.1 - lru-cache@7.18.3: - optional: true + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + lru-cache@7.13.1: {} + + lru-cache@7.18.3: {} lru.min@1.1.2: optional: true @@ -8279,6 +9917,8 @@ snapshots: dependencies: fs-monkey: 1.1.0 + merge-descriptors@1.0.3: {} + merge-descriptors@2.0.0: {} merge-stream@2.0.0: {} @@ -8304,6 +9944,8 @@ snapshots: dependencies: mime-db: 1.54.0 + mime@1.6.0: {} + mime@2.6.0: {} mimic-fn@2.1.0: {} @@ -8334,6 +9976,8 @@ snapshots: mkdirp@3.0.1: {} + ms@2.0.0: {} + ms@2.1.3: {} multer@2.0.2: @@ -8346,6 +9990,8 @@ snapshots: type-is: 1.6.18 xtend: 4.0.2 + mustache@4.2.0: {} + mute-stream@2.0.0: {} mysql2@3.14.4: @@ -8372,6 +10018,10 @@ snapshots: natural-compare@1.4.0: {} + negotiator@0.6.3: {} + + negotiator@0.6.4: {} + negotiator@1.0.0: {} neo-async@2.6.2: {} @@ -8382,6 +10032,10 @@ snapshots: dependencies: lodash: 4.17.21 + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + node-int64@0.4.0: {} node-releases@2.0.20: {} @@ -8433,6 +10087,20 @@ snapshots: dependencies: mimic-fn: 2.1.0 + openai@5.12.2(ws@8.18.1)(zod@3.25.76): + optionalDependencies: + ws: 8.18.1 + zod: 3.25.76 + + openapi-types@12.1.3: {} + + optimism@0.18.1: + dependencies: + '@wry/caches': 1.0.1 + '@wry/context': 0.7.4 + '@wry/trie': 0.5.0 + tslib: 2.8.1 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -8460,6 +10128,8 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 + p-finally@1.0.0: {} + p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -8476,6 +10146,20 @@ snapshots: dependencies: p-limit: 3.1.0 + p-queue@6.6.2: + dependencies: + eventemitter3: 4.0.7 + p-timeout: 3.2.0 + + p-retry@4.6.2: + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + + p-timeout@3.2.0: + dependencies: + p-finally: 1.0.0 + p-try@2.2.0: {} package-json-from-dist@1.0.1: {} @@ -8509,6 +10193,8 @@ snapshots: lru-cache: 11.2.1 minipass: 7.1.2 + path-to-regexp@0.1.12: {} + path-to-regexp@8.2.0: {} path-type@4.0.0: {} @@ -8605,6 +10291,10 @@ snapshots: pure-rand@7.0.1: {} + qs@6.13.0: + dependencies: + side-channel: 1.1.0 + qs@6.14.0: dependencies: side-channel: 1.1.0 @@ -8617,6 +10307,13 @@ snapshots: range-parser@1.2.1: {} + raw-body@2.5.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + raw-body@3.0.1: dependencies: bytes: 3.1.2 @@ -8698,6 +10395,8 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 + retry@0.13.1: {} + reusify@1.1.0: {} rollup@4.50.1: @@ -8791,6 +10490,24 @@ snapshots: semver@7.7.2: {} + send@0.19.0: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + send@1.2.0: dependencies: debug: 4.4.1 @@ -8814,6 +10531,15 @@ snapshots: dependencies: randombytes: 2.1.0 + serve-static@1.16.2: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.0 + transitivePeerDependencies: + - supports-color + serve-static@2.2.0: dependencies: encodeurl: 2.0.0 @@ -8893,6 +10619,8 @@ snapshots: signal-exit@4.1.0: {} + simple-wcswidth@1.1.2: {} + slash@3.0.0: {} source-map-js@1.2.1: {} @@ -9005,10 +10733,24 @@ snapshots: strip-json-comments@3.1.1: {} + strnum@1.1.2: {} + strtok3@10.3.4: dependencies: '@tokenizer/token': 0.3.0 + subscriptions-transport-ws@0.11.0(graphql@16.11.0): + dependencies: + backo2: 1.0.2 + eventemitter3: 3.1.2 + graphql: 16.11.0 + iterall: 1.3.0 + symbol-observable: 1.2.0 + ws: 7.5.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + superagent@10.2.3: dependencies: component-emitter: 1.3.1 @@ -9051,6 +10793,8 @@ snapshots: express: 5.1.0 swagger-ui-dist: 5.28.1 + symbol-observable@1.2.0: {} + symbol-observable@4.0.0: {} synckit@0.11.11: @@ -9119,6 +10863,8 @@ snapshots: '@tokenizer/token': 0.3.0 ieee754: 1.2.1 + tr46@0.0.3: {} + tree-kill@1.2.2: {} ts-api-utils@2.1.0(typescript@5.8.3): @@ -9349,8 +11095,14 @@ snapshots: util-deprecate@1.0.2: {} + utils-merge@1.0.1: {} + + uuid@10.0.0: {} + uuid@11.1.0: {} + uuid@9.0.1: {} + v8-compile-cache-lib@3.0.1: {} v8-to-istanbul@9.3.0: @@ -9361,9 +11113,13 @@ snapshots: validator@13.15.15: {} + value-or-promise@1.0.11: {} + + value-or-promise@1.0.12: {} + vary@1.1.2: {} - vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0): + vite@7.1.4(@types/node@22.18.1)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1): dependencies: esbuild: 0.25.9 fdir: 6.5.0(picomatch@4.0.3) @@ -9377,6 +11133,7 @@ snapshots: jiti: 2.5.1 lightningcss: 1.30.1 terser: 5.44.0 + yaml: 2.8.1 walker@1.0.8: dependencies: @@ -9391,6 +11148,8 @@ snapshots: dependencies: defaults: 1.0.4 + webidl-conversions@3.0.1: {} + webpack-node-externals@3.0.0: {} webpack-sources@3.3.3: {} @@ -9427,6 +11186,13 @@ snapshots: - esbuild - uglify-js + whatwg-mimetype@3.0.0: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 @@ -9501,14 +11267,27 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.1.0 + ws@7.5.10: {} + + ws@8.18.1: {} + + xss@1.0.15: + dependencies: + commander: 2.20.3 + cssfilter: 0.0.10 + xtend@4.0.2: {} y18n@5.0.8: {} yallist@3.1.1: {} + yallist@4.0.0: {} + yallist@5.0.0: {} + yaml@2.8.1: {} + yargs-parser@21.1.1: {} yargs@17.7.2: @@ -9527,4 +11306,10 @@ snapshots: yoctocolors-cjs@2.1.3: {} + zod-to-json-schema@3.24.6(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.76: {} + zod@4.1.5: {} From c78e1c8695bcec16212965a0a130620324947308 Mon Sep 17 00:00:00 2001 From: Joaquin Date: Mon, 8 Sep 2025 23:46:43 -0300 Subject: [PATCH 06/17] feat: implement AI-powered content generation and translation workflow This commit introduces significant updates to the backend to support AI-powered content generation and translation workflows. The changes include: Campaigns Module: Updated the campaign.entity.ts to include relationships with content pieces. Enhanced the campaigns.controller.ts and campaigns.resolver.ts to support querying campaigns with their content and translations. Updated the campaigns.service.ts to handle campaign-related logic more effectively. Content Pieces: Modified the content-piece.entity.ts to establish relationships with translations. Added a new generate-content.dto.ts to handle AI generation requests. Updated the content-pieces.controller.ts and content-pieces.service.ts to include endpoints and logic for generating AI-powered drafts and translations. Integrated LangChain for AI model selection (OpenAI/Anthropic) in langchain.service.ts. Content Piece Translations: Updated the content-piece-translations.entity.ts to support localized translations. Enhanced the content-piece-translations.controller.ts and content-piece-translations.service.ts to manage translation entities. Added validation and DTOs for creating and updating translations. LangChain Integration: Introduced langchain.enum.ts to define supported AI models (OpenAI, Anthropic). Updated langchain.service.ts to handle AI-powered content generation and localization. These changes enable the backend to: Generate AI-powered drafts for content pieces. Provide translation/localization suggestions via AI. Manage relationships between campaigns, content pieces, and translations. Support multi-model AI workflows using LangChain. --- apps/backend/src/campaigns/campaign.entity.ts | 4 + .../src/campaigns/campaigns.controller.ts | 20 ++- .../backend/src/campaigns/campaigns.module.ts | 3 +- .../src/campaigns/campaigns.resolver.ts | 17 ++- .../src/campaigns/campaigns.service.ts | 22 +++- .../content-piece-translations.controller.ts | 33 ++--- .../content-piece-translations.entity.ts | 15 +++ .../content-piece-translations.module.ts | 3 +- .../content-piece-translations.resolver.ts | 17 +-- .../content-piece-translations.service.ts | 55 +++++--- .../create-content-piece-translations.dto.ts | 17 +++ .../content-pieces/content-piece.entity.ts | 7 + .../content-pieces.controller.ts | 83 +++++++++++- .../content-pieces/content-pieces.module.ts | 5 +- .../content-pieces/content-pieces.resolver.ts | 21 +-- .../content-pieces/content-pieces.service.ts | 121 ++++++++++++++++-- .../dto/generate-content.dto.ts | 31 +++++ apps/backend/src/langchain/langchain.enum.ts | 11 ++ .../src/langchain/langchain.service.ts | 93 +++++++++++--- 19 files changed, 476 insertions(+), 102 deletions(-) create mode 100644 apps/backend/src/content-pieces/dto/generate-content.dto.ts create mode 100644 apps/backend/src/langchain/langchain.enum.ts diff --git a/apps/backend/src/campaigns/campaign.entity.ts b/apps/backend/src/campaigns/campaign.entity.ts index 0389d92..3bee30f 100644 --- a/apps/backend/src/campaigns/campaign.entity.ts +++ b/apps/backend/src/campaigns/campaign.entity.ts @@ -28,4 +28,8 @@ export class Campaign { @Field(() => [ContentPiece], { defaultValue: [] }) @OneToMany(() => ContentPiece, (contentPiece) => contentPiece.campaign) contentPieces: ContentPiece[]; + + // For subscription purposes + @Field() + _type: string; } diff --git a/apps/backend/src/campaigns/campaigns.controller.ts b/apps/backend/src/campaigns/campaigns.controller.ts index b0e1fd8..02b5361 100644 --- a/apps/backend/src/campaigns/campaigns.controller.ts +++ b/apps/backend/src/campaigns/campaigns.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Post, Body, Param, NotFoundException } from '@nestjs/common'; +import { Controller, Get, Post, Body, Param, NotFoundException, Delete, ParseUUIDPipe } from '@nestjs/common'; import { ApiTags, ApiOperation, ApiParam } from '@nestjs/swagger'; import { CampaignsService } from './campaigns.service'; import { CreateCampaignDto } from './dto/create-campaign.dto'; @@ -25,7 +25,7 @@ export class CampaignsController { @Get(':id') @ApiOperation({ summary: 'Get a campaign by ID' }) @ApiParam({ name: 'id', description: 'The ID of the campaign' }) - async findOne(@Param('id') id: string): Promise { + async findOne(@Param('id', new ParseUUIDPipe()) id: string): Promise { // This endpoint returns a single campaign by its ID. try { return await this.campaignsService.findOne(id); @@ -37,4 +37,20 @@ export class CampaignsController { throw error; } } + + @Delete(':id') + @ApiOperation({ summary: 'Delete a campaign by ID' }) + @ApiParam({ name: 'id', description: 'The ID of the campaign' }) + async remove(@Param('id', new ParseUUIDPipe()) id: string): Promise { + // This endpoint deletes a campaign by its ID. + try { + return await this.campaignsService.remove(id); + } catch (error) { + // Handle the case where the campaign is not found. + if (error instanceof NotFoundException) { + throw new NotFoundException(error.message); + } + throw error; + } + } } diff --git a/apps/backend/src/campaigns/campaigns.module.ts b/apps/backend/src/campaigns/campaigns.module.ts index 1ba296d..6711401 100644 --- a/apps/backend/src/campaigns/campaigns.module.ts +++ b/apps/backend/src/campaigns/campaigns.module.ts @@ -5,9 +5,10 @@ import { CampaignsService } from './campaigns.service'; import { CampaignsController } from './campaigns.controller'; import { CampaignResolver } from './campaigns.resolver'; import { PubSub } from 'graphql-subscriptions'; +import { ContentPiecesModule } from 'src/content-pieces/content-pieces.module'; @Module({ - imports: [TypeOrmModule.forFeature([Campaign])], + imports: [TypeOrmModule.forFeature([Campaign]), ContentPiecesModule], providers: [ CampaignsService, CampaignResolver, diff --git a/apps/backend/src/campaigns/campaigns.resolver.ts b/apps/backend/src/campaigns/campaigns.resolver.ts index 4589616..9de1d69 100644 --- a/apps/backend/src/campaigns/campaigns.resolver.ts +++ b/apps/backend/src/campaigns/campaigns.resolver.ts @@ -1,12 +1,15 @@ -import { Resolver, Query, Mutation, Args, ID, Subscription } from '@nestjs/graphql'; +import { Resolver, Query, Mutation, Args, ID, Subscription, ResolveField, Parent } from '@nestjs/graphql'; import { PubSub } from 'graphql-subscriptions'; import { CampaignsService } from './campaigns.service'; import { Campaign } from './campaign.entity'; +import { ContentPiece } from 'src/content-pieces/content-piece.entity'; +import { ContentPiecesService } from 'src/content-pieces/content-pieces.service'; @Resolver(() => Campaign) export class CampaignResolver { constructor( private readonly campaignsService: CampaignsService, + private readonly contentPiecesService: ContentPiecesService, private readonly pubSub: PubSub, ) {} @@ -21,10 +24,16 @@ export class CampaignResolver { } @Subscription(() => Campaign, { - name: 'onCampaignUpdated', + name: 'campaignUpdated', }) - onCampaignUpdated() { - return this.pubSub.asyncIterableIterator('onCampaignUpdated'); + campaignUpdated() { + return this.pubSub.asyncIterableIterator('campaignUpdated'); + } + + @ResolveField(() => [ContentPiece]) + async contentPieces(@Parent() campaign: Campaign): Promise { + const data = await this.contentPiecesService.findAll(campaign.id); + return data; } @Mutation(() => Campaign) diff --git a/apps/backend/src/campaigns/campaigns.service.ts b/apps/backend/src/campaigns/campaigns.service.ts index c291233..751da9b 100644 --- a/apps/backend/src/campaigns/campaigns.service.ts +++ b/apps/backend/src/campaigns/campaigns.service.ts @@ -16,12 +16,16 @@ export class CampaignsService { const entity = this.campaignRepository.create(createCampaignDto); const newCampaign = await this.campaignRepository.save(entity); - await this.pubSub.publish('onCampaignUpdated', { onCampaignUpdated: newCampaign }); + await this.pubSub.publish('campaignUpdated', { campaignUpdated: { ...newCampaign, _type: 'create' } }); return newCampaign; } async findOne(id: string): Promise { - const campaign = await this.campaignRepository.findOne({ where: { id } }); + const campaign = await this.campaignRepository.findOne({ + where: { id }, + order: { updatedAt: 'DESC' }, + relations: ['contentPieces'], + }); if (!campaign) { throw new NotFoundException(`Campaign with ID ${id} not found`); } @@ -29,7 +33,10 @@ export class CampaignsService { } async findAll(): Promise { - return this.campaignRepository.find(); + return this.campaignRepository.find({ + relations: ['contentPieces'], + order: { updatedAt: 'ASC', createdAt: 'DESC' }, + }); } async update(id: string, updateCampaignDto: Partial): Promise { @@ -37,14 +44,15 @@ export class CampaignsService { Object.assign(entity, updateCampaignDto); const campaign = await this.campaignRepository.save(entity); - await this.pubSub.publish('onCampaignUpdated', { onCampaignUpdated: campaign }); + await this.pubSub.publish('campaignUpdated', { campaignUpdated: { ...campaign, _type: 'update' } }); return campaign; } - async remove(id: string): Promise { + async remove(id: string): Promise { const entity = await this.findOne(id); - await this.campaignRepository.remove(entity); + const result = await this.campaignRepository.remove(entity); - await this.pubSub.publish('onCampaignUpdated', { onCampaignUpdated: { id } }); + await this.pubSub.publish('campaignUpdated', { campaignUpdated: { ...result, id: id, _type: 'remove' } }); + return result; } } diff --git a/apps/backend/src/content-piece-translations/content-piece-translations.controller.ts b/apps/backend/src/content-piece-translations/content-piece-translations.controller.ts index 031ef2c..8ec23eb 100644 --- a/apps/backend/src/content-piece-translations/content-piece-translations.controller.ts +++ b/apps/backend/src/content-piece-translations/content-piece-translations.controller.ts @@ -1,18 +1,25 @@ -import { Controller, Get, Post, Body, Param, Patch, Delete, NotFoundException } from '@nestjs/common'; +import { + Controller, + Get, + Post, + Body, + Param, + Patch, + Delete, + NotFoundException, + ParseUUIDPipe, + Query, +} from '@nestjs/common'; import { ApiTags, ApiOperation, ApiParam } from '@nestjs/swagger'; import { ContentPieceTranslationService } from './content-piece-translations.service'; import { ContentPieceTranslation } from './content-piece-translations.entity'; import { CreateContentPieceTranslationDto } from './dto/create-content-piece-translations.dto'; import { UpdateContentPieceTranslationDto } from './dto/update-content-piece-translations.dto'; -import { ContentPiecesService } from 'src/content-pieces/content-pieces.service'; @ApiTags('content-piece-translations') @Controller('content-piece-translations') export class ContentPieceTranslationController { - constructor( - private readonly translationService: ContentPieceTranslationService, - private readonly contentPieceService: ContentPiecesService, - ) {} + constructor(private readonly translationService: ContentPieceTranslationService) {} @Post() @ApiOperation({ summary: 'Create a new content piece translation' }) @@ -22,13 +29,9 @@ export class ContentPieceTranslationController { @Get() @ApiOperation({ summary: 'Get all content piece translations' }) - async findAll(@Param('contentPieceId') contentPieceId: string | undefined): Promise { + async findAll(@Query('contentPieceId') contentPieceId: string | undefined): Promise { if (contentPieceId) { - const contentPiece = await this.contentPieceService.findOne(contentPieceId); - if (!contentPiece) { - throw new NotFoundException(`Content piece with ID ${contentPieceId} not found`); - } - return this.translationService.findAll(contentPiece); + return this.translationService.findAll(contentPieceId); } return this.translationService.findAll(); @@ -37,7 +40,7 @@ export class ContentPieceTranslationController { @Get(':id') @ApiOperation({ summary: 'Get a content piece translation by ID' }) @ApiParam({ name: 'id', description: 'The ID of the translation' }) - async findOne(@Param('id') id: string): Promise { + async findOne(@Param('id', new ParseUUIDPipe()) id: string): Promise { try { return await this.translationService.findOne(id); } catch (error) { @@ -52,7 +55,7 @@ export class ContentPieceTranslationController { @ApiOperation({ summary: 'Update a content piece translation by ID' }) @ApiParam({ name: 'id', description: 'The ID of the translation to update' }) async update( - @Param('id') id: string, + @Param('id', new ParseUUIDPipe()) id: string, @Body() updateTranslationDto: UpdateContentPieceTranslationDto, ): Promise { return this.translationService.update(id, updateTranslationDto); @@ -61,7 +64,7 @@ export class ContentPieceTranslationController { @Delete(':id') @ApiOperation({ summary: 'Delete a content piece translation by ID' }) @ApiParam({ name: 'id', description: 'The ID of the translation to delete' }) - async remove(@Param('id') id: string): Promise { + async remove(@Param('id', new ParseUUIDPipe()) id: string): Promise { return this.translationService.remove(id); } } diff --git a/apps/backend/src/content-piece-translations/content-piece-translations.entity.ts b/apps/backend/src/content-piece-translations/content-piece-translations.entity.ts index 53fab0a..8b84c0f 100644 --- a/apps/backend/src/content-piece-translations/content-piece-translations.entity.ts +++ b/apps/backend/src/content-piece-translations/content-piece-translations.entity.ts @@ -1,6 +1,7 @@ import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, CreateDateColumn, UpdateDateColumn } from 'typeorm'; import { Field, ID, ObjectType } from '@nestjs/graphql'; import { ContentPiece } from '../content-pieces/content-piece.entity'; +import { ModelProvider } from 'src/langchain/langchain.enum'; @ObjectType() @Entity() @@ -9,6 +10,10 @@ export class ContentPieceTranslation { @PrimaryGeneratedColumn('uuid') id: string; + @Field(() => ModelProvider, { nullable: true }) + @Column({ type: 'enum', enum: ModelProvider, nullable: true }) + modelProvider: ModelProvider; + @Field() @Column() languageCode: string; @@ -40,4 +45,14 @@ export class ContentPieceTranslation { @Field(() => ContentPiece) @ManyToOne(() => ContentPiece, (contentPiece): ContentPieceTranslation[] => contentPiece.translations) contentPiece: ContentPiece; + + // For subscription purposes + @Field() + _type: string; + + @Field() + campaignId: string; + + @Field() + contentPieceId: string; } diff --git a/apps/backend/src/content-piece-translations/content-piece-translations.module.ts b/apps/backend/src/content-piece-translations/content-piece-translations.module.ts index b3248c2..223efb1 100644 --- a/apps/backend/src/content-piece-translations/content-piece-translations.module.ts +++ b/apps/backend/src/content-piece-translations/content-piece-translations.module.ts @@ -4,11 +4,10 @@ import { ContentPieceTranslation } from './content-piece-translations.entity'; import { ContentPieceTranslationService } from './content-piece-translations.service'; import { ContentPieceTranslationResolver } from './content-piece-translations.resolver'; import { ContentPieceTranslationController } from './content-piece-translations.controller'; -import { ContentPiecesModule } from 'src/content-pieces/content-pieces.module'; import { PubSub } from 'graphql-subscriptions'; @Module({ - imports: [TypeOrmModule.forFeature([ContentPieceTranslation]), ContentPiecesModule], + imports: [TypeOrmModule.forFeature([ContentPieceTranslation])], controllers: [ContentPieceTranslationController], providers: [ ContentPieceTranslationService, diff --git a/apps/backend/src/content-piece-translations/content-piece-translations.resolver.ts b/apps/backend/src/content-piece-translations/content-piece-translations.resolver.ts index c3c8d1d..d7f8bfc 100644 --- a/apps/backend/src/content-piece-translations/content-piece-translations.resolver.ts +++ b/apps/backend/src/content-piece-translations/content-piece-translations.resolver.ts @@ -1,20 +1,15 @@ -import { Injectable } from '@nestjs/common'; -import { ContentPieceTranslationService } from './content-piece-translations.service'; import { PubSub } from 'graphql-subscriptions'; -import { Subscription } from '@nestjs/graphql'; +import { Resolver, Subscription } from '@nestjs/graphql'; import { ContentPieceTranslation } from './content-piece-translations.entity'; -@Injectable() +@Resolver(() => ContentPieceTranslation) export class ContentPieceTranslationResolver { - constructor( - private readonly contentPieceTranslationService: ContentPieceTranslationService, - private readonly pubSub: PubSub, - ) {} + constructor(private readonly pubSub: PubSub) {} @Subscription(() => ContentPieceTranslation, { - name: 'onContentPieceTranslationUpdated', + name: 'contentPieceTranslationUpdated', }) - onContentPieceTranslationUpdated() { - return this.pubSub.asyncIterableIterator('onContentPieceTranslationUpdated'); + contentPieceTranslationUpdated() { + return this.pubSub.asyncIterableIterator('contentPieceTranslationUpdated'); } } diff --git a/apps/backend/src/content-piece-translations/content-piece-translations.service.ts b/apps/backend/src/content-piece-translations/content-piece-translations.service.ts index b6b7a19..367966e 100644 --- a/apps/backend/src/content-piece-translations/content-piece-translations.service.ts +++ b/apps/backend/src/content-piece-translations/content-piece-translations.service.ts @@ -4,7 +4,6 @@ import { Repository } from 'typeorm'; import { ContentPieceTranslation } from './content-piece-translations.entity'; import { CreateContentPieceTranslationDto } from './dto/create-content-piece-translations.dto'; import { UpdateContentPieceTranslationDto } from './dto/update-content-piece-translations.dto'; -import { ContentPiece } from 'src/content-pieces/content-piece.entity'; import { PubSub } from 'graphql-subscriptions'; @Injectable() @@ -16,29 +15,43 @@ export class ContentPieceTranslationService { ) {} async create(createTranslationDto: CreateContentPieceTranslationDto): Promise { - const translation = this.translationRepository.create(createTranslationDto); + const translation = this.translationRepository.create({ + ...createTranslationDto, + contentPiece: { id: createTranslationDto.contentPieceId }, + }); const newTranslation = await this.translationRepository.save(translation); - await this.pubSub.publish('onContentPieceTranslationUpdated', { - onContentPieceTranslationUpdated: { - newTranslation, - campaignId: newTranslation.contentPiece.campaign.id, + await this.pubSub.publish('contentPieceTranslationUpdated', { + contentPieceTranslationUpdated: { + ...newTranslation, + campaignId: createTranslationDto.campaignId, contentPieceId: newTranslation.contentPiece.id, + _type: 'create', }, }); return newTranslation; } - async findAll(contentPiece: ContentPiece | undefined = undefined): Promise { - if (!contentPiece) { + async findAll(contentPieceId: string | undefined = undefined): Promise { + if (!contentPieceId) { return this.translationRepository.find({ relations: ['contentPiece'] }); } - return this.translationRepository.find({ where: { contentPiece }, relations: ['contentPiece'] }); + return this.translationRepository.find({ + where: { + contentPiece: { + id: contentPieceId, + }, + }, + relations: ['contentPiece'], + }); } async findOne(id: string): Promise { - const translation = await this.translationRepository.findOne({ where: { id }, relations: ['contentPiece'] }); + const translation = await this.translationRepository.findOne({ + where: { id }, + relations: ['contentPiece', 'contentPiece.campaign'], + }); if (!translation) { throw new NotFoundException(`Translation with ID ${id} not found`); } @@ -50,29 +63,33 @@ export class ContentPieceTranslationService { this.translationRepository.merge(translation, updateTranslationDto); const updatedTranslation = await this.translationRepository.save(translation); - await this.pubSub.publish('onContentPieceTranslationUpdated', { - onContentPieceTranslationUpdated: { - updatedTranslation, - campaignId: updatedTranslation.contentPiece.campaign.id, - contentPieceId: updatedTranslation.contentPiece.id, + await this.pubSub.publish('contentPieceTranslationUpdated', { + contentPieceTranslationUpdated: { + ...updatedTranslation, + campaignId: translation.contentPiece.campaign.id, + contentPieceId: translation.contentPiece.id, + _type: 'update', }, }); return updatedTranslation; } - async remove(id: string): Promise { + async remove(id: string): Promise { const translation = await this.translationRepository.findOne({ where: { id } }); if (!translation) { throw new NotFoundException(`Translation with ID ${id} not found`); } await this.translationRepository.remove(translation); - await this.pubSub.publish('onContentPieceTranslationUpdated', { - onContentPieceTranslationUpdated: { - id: translation.id, + await this.pubSub.publish('contentPieceTranslationUpdated', { + contentPieceTranslationUpdated: { + ...translation, + id, campaignId: translation.contentPiece.campaign.id, contentPieceId: translation.contentPiece.id, + _type: 'remove', }, }); + return translation; } } diff --git a/apps/backend/src/content-piece-translations/dto/create-content-piece-translations.dto.ts b/apps/backend/src/content-piece-translations/dto/create-content-piece-translations.dto.ts index ea24ce6..0ee0bd2 100644 --- a/apps/backend/src/content-piece-translations/dto/create-content-piece-translations.dto.ts +++ b/apps/backend/src/content-piece-translations/dto/create-content-piece-translations.dto.ts @@ -1,7 +1,16 @@ import { IsString, IsNotEmpty, IsBoolean } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; +import { ModelProvider } from 'src/langchain/langchain.enum'; export class CreateContentPieceTranslationDto { + @ApiProperty({ + description: 'The ID of the campaign this translation belongs to', + example: '1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d', + }) + @IsString() + @IsNotEmpty() + campaignId: string; + @ApiProperty({ description: 'The ID of the content piece this translation belongs to', example: '1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d', @@ -10,6 +19,14 @@ export class CreateContentPieceTranslationDto { @IsNotEmpty() contentPieceId: string; + @ApiProperty({ + description: 'The model provider used for the translation', + example: ModelProvider.OpenAI, + }) + @IsString() + @IsNotEmpty() + modelProvider: ModelProvider; + @ApiProperty({ description: 'The language code for the translation', example: 'es' }) @IsString() @IsNotEmpty() diff --git a/apps/backend/src/content-pieces/content-piece.entity.ts b/apps/backend/src/content-pieces/content-piece.entity.ts index 3c20969..25086b5 100644 --- a/apps/backend/src/content-pieces/content-piece.entity.ts +++ b/apps/backend/src/content-pieces/content-piece.entity.ts @@ -50,4 +50,11 @@ export class ContentPiece { @Field(() => [ContentPieceTranslation], { nullable: false }) @OneToMany(() => ContentPieceTranslation, (translation): ContentPiece => translation.contentPiece) translations: ContentPieceTranslation[]; + + // For subscription purposes + @Field() + _type: string; + + @Field() + campaignId: string; } diff --git a/apps/backend/src/content-pieces/content-pieces.controller.ts b/apps/backend/src/content-pieces/content-pieces.controller.ts index 0ddc20d..6a1e2d0 100644 --- a/apps/backend/src/content-pieces/content-pieces.controller.ts +++ b/apps/backend/src/content-pieces/content-pieces.controller.ts @@ -1,9 +1,24 @@ -import { Controller, Get, Post, Body, Param, Patch, Delete, NotFoundException } from '@nestjs/common'; +import { + Controller, + Get, + Post, + Body, + Param, + Patch, + Delete, + NotFoundException, + ParseUUIDPipe, + BadRequestException, + Query, +} from '@nestjs/common'; import { ApiTags, ApiOperation, ApiParam } from '@nestjs/swagger'; import { ContentPiecesService } from './content-pieces.service'; import { ContentPiece } from './content-piece.entity'; import { CreateContentPieceDto } from './dto/create-content-piece.dto'; import { UpdateContentPieceDto } from './dto/update-content-piece.dto'; +import { GenerateContentDto } from './dto/generate-content.dto'; +import { ModelProvider } from 'src/langchain/langchain.enum'; +import { ReviewState } from './review-state.enum'; @ApiTags('content-pieces') @Controller('content-pieces') @@ -18,14 +33,14 @@ export class ContentPiecesController { @Get() @ApiOperation({ summary: 'Get all content pieces' }) - async findAll(@Param('campaignId') campaignId: string | undefined): Promise { + async findAll(@Query('campaignId') campaignId: string): Promise { return this.contentPiecesService.findAll(campaignId); } @Get(':id') @ApiOperation({ summary: 'Get a content piece by ID' }) @ApiParam({ name: 'id', description: 'The ID of the content piece' }) - async findOne(@Param('id') id: string): Promise { + async findOne(@Param('id', new ParseUUIDPipe()) id: string): Promise { try { return await this.contentPiecesService.findOne(id); } catch (error) { @@ -39,14 +54,72 @@ export class ContentPiecesController { @Patch(':id') @ApiOperation({ summary: 'Update a content piece by ID' }) @ApiParam({ name: 'id', description: 'The ID of the content piece to update' }) - async update(@Param('id') id: string, @Body() updateContentPieceDto: UpdateContentPieceDto): Promise { + async update( + @Param('id', new ParseUUIDPipe()) id: string, + @Body() updateContentPieceDto: UpdateContentPieceDto, + ): Promise { return this.contentPiecesService.update(id, updateContentPieceDto); } @Delete(':id') @ApiOperation({ summary: 'Delete a content piece by ID' }) @ApiParam({ name: 'id', description: 'The ID of the content piece to delete' }) - async remove(@Param('id') id: string): Promise { + async remove(@Param('id', new ParseUUIDPipe()) id: string): Promise { return this.contentPiecesService.remove(id); } + + @Post('generate') + @ApiOperation({ summary: 'Generate content for a content piece' }) + async generateContent(@Body() generateContentDto: GenerateContentDto): Promise { + const { id, campaignId, locale, modelProvider } = generateContentDto; + let provider: ModelProvider; + + if (!['openai', 'anthropic'].includes(modelProvider)) { + throw new BadRequestException('modelProvider must be either "openai" or "anthropic"'); + } else { + provider = modelProvider as ModelProvider; + } + + try { + if (id) { + return await this.contentPiecesService.generateForExistingContent(id, locale, provider); + } else { + if (!campaignId) throw new BadRequestException('campaignId is required when id is not provided'); + + return await this.contentPiecesService.generateForNewContent(campaignId, locale, provider); + } + } catch (error) { + console.error('Error generating content:', error); + throw new BadRequestException(error || 'Error generating content'); + } + } + + // Approve or Reject content endpoints + @Post(':id/approve') + @ApiOperation({ summary: 'Approve a content piece by ID' }) + @ApiParam({ name: 'id', description: 'The ID of the content piece to approve' }) + async approveContent(@Param('id', new ParseUUIDPipe()) id: string): Promise { + return await this.contentPiecesService.update(id, { + reviewState: ReviewState.Approved, + }); + } + + @Post(':id/reject') + @ApiOperation({ summary: 'Reject a content piece by ID' }) + @ApiParam({ name: 'id', description: 'The ID of the content piece to reject' }) + async rejectContent(@Param('id', new ParseUUIDPipe()) id: string): Promise { + return await this.contentPiecesService.update(id, { + reviewState: ReviewState.Rejected, + }); + } + + // Update to 'Reviewed' state + @Post(':id/reviewed') + @ApiOperation({ summary: "Mark a content piece as 'Reviewed' by ID" }) + @ApiParam({ name: 'id', description: 'The ID of the content piece to mark as reviewed' }) + async markAsReviewed(@Param('id', new ParseUUIDPipe()) id: string): Promise { + return await this.contentPiecesService.update(id, { + reviewState: ReviewState.Reviewed, + }); + } } diff --git a/apps/backend/src/content-pieces/content-pieces.module.ts b/apps/backend/src/content-pieces/content-pieces.module.ts index ebced9c..534ec97 100644 --- a/apps/backend/src/content-pieces/content-pieces.module.ts +++ b/apps/backend/src/content-pieces/content-pieces.module.ts @@ -5,13 +5,16 @@ import { ContentPiecesService } from './content-pieces.service'; import { ContentPiecesResolver } from './content-pieces.resolver'; import { ContentPiecesController } from './content-pieces.controller'; import { PubSub } from 'graphql-subscriptions'; +import { LangChainService } from 'src/langchain/langchain.service'; +import { ContentPieceTranslationsModule } from 'src/content-piece-translations/content-piece-translations.module'; @Module({ - imports: [TypeOrmModule.forFeature([ContentPiece])], + imports: [TypeOrmModule.forFeature([ContentPiece]), ContentPieceTranslationsModule], controllers: [ContentPiecesController], providers: [ ContentPiecesService, ContentPiecesResolver, + LangChainService, { provide: PubSub, useValue: new PubSub(), diff --git a/apps/backend/src/content-pieces/content-pieces.resolver.ts b/apps/backend/src/content-pieces/content-pieces.resolver.ts index 97d7a7e..0e964c7 100644 --- a/apps/backend/src/content-pieces/content-pieces.resolver.ts +++ b/apps/backend/src/content-pieces/content-pieces.resolver.ts @@ -1,20 +1,25 @@ -import { Injectable } from '@nestjs/common'; import { PubSub } from 'graphql-subscriptions'; -import { ContentPiecesService } from './content-pieces.service'; -import { Subscription } from '@nestjs/graphql'; +import { Parent, ResolveField, Resolver, Subscription } from '@nestjs/graphql'; import { ContentPiece } from './content-piece.entity'; +import { ContentPieceTranslation } from 'src/content-piece-translations/content-piece-translations.entity'; +import { ContentPieceTranslationService } from 'src/content-piece-translations/content-piece-translations.service'; -@Injectable() +@Resolver(() => ContentPiece) export class ContentPiecesResolver { constructor( - private readonly contentPieceService: ContentPiecesService, + private readonly contentPieceTranslationsService: ContentPieceTranslationService, private readonly pubSub: PubSub, ) {} @Subscription(() => ContentPiece, { - name: 'onContentPieceUpdated', + name: 'contentPieceUpdated', }) - onContentPieceUpdated() { - return this.pubSub.asyncIterableIterator('onContentPieceUpdated'); + contentPieceUpdated() { + return this.pubSub.asyncIterableIterator('contentPieceUpdated'); + } + + @ResolveField(() => [ContentPieceTranslation]) + async translations(@Parent() contentPiece: ContentPiece): Promise { + return await this.contentPieceTranslationsService.findAll(contentPiece.id); } } diff --git a/apps/backend/src/content-pieces/content-pieces.service.ts b/apps/backend/src/content-pieces/content-pieces.service.ts index 3cefcc9..ab02876 100644 --- a/apps/backend/src/content-pieces/content-pieces.service.ts +++ b/apps/backend/src/content-pieces/content-pieces.service.ts @@ -5,23 +5,33 @@ import { ContentPiece } from './content-piece.entity'; import { CreateContentPieceDto } from './dto/create-content-piece.dto'; import { UpdateContentPieceDto } from './dto/update-content-piece.dto'; import { PubSub } from 'graphql-subscriptions'; +import { LangChainService } from 'src/langchain/langchain.service'; +import { ReviewState } from './review-state.enum'; +import { ContentPieceTranslationService } from 'src/content-piece-translations/content-piece-translations.service'; +import { ModelProvider } from 'src/langchain/langchain.enum'; @Injectable() export class ContentPiecesService { constructor( @InjectRepository(ContentPiece) private readonly contentPieceRepository: Repository, + private readonly translationsService: ContentPieceTranslationService, + private readonly langChainService: LangChainService, private readonly pubSub: PubSub, ) {} async create(createContentPieceDto: CreateContentPieceDto): Promise { - const entity = this.contentPieceRepository.create(createContentPieceDto); + const entity = this.contentPieceRepository.create({ + sourceLanguage: createContentPieceDto.sourceLanguage, + campaign: { id: createContentPieceDto.campaignId }, + }); const newContent = await this.contentPieceRepository.save(entity); - await this.pubSub.publish('onContentPieceUpdated', { - onContentPieceUpdated: { + await this.pubSub.publish('contentPieceUpdated', { + contentPieceUpdated: { ...newContent, campaignId: newContent.campaign.id, + _type: 'create', }, }); return newContent; @@ -29,13 +39,15 @@ export class ContentPiecesService { async findAll(campaignId: string | undefined = undefined): Promise { if (campaignId) { - return this.contentPieceRepository.find({ + return await this.contentPieceRepository.find({ where: { campaign: { id: campaignId } }, relations: ['campaign', 'translations'], }); } - return this.contentPieceRepository.find({ relations: ['campaign', 'translations'] }); + return await this.contentPieceRepository.find({ + relations: ['campaign', 'translations'], + }); } async findOne(id: string): Promise { @@ -54,27 +66,116 @@ export class ContentPiecesService { this.contentPieceRepository.merge(contentPiece, updateContentPieceDto); const updatedContentPiece = await this.contentPieceRepository.save(contentPiece); - await this.pubSub.publish('onContentPieceUpdated', { - onContentPieceUpdated: { + await this.pubSub.publish('contentPieceUpdated', { + contentPieceUpdated: { ...updatedContentPiece, campaignId: updatedContentPiece.campaign.id, + _type: 'update', }, }); return updatedContentPiece; } - async remove(id: string): Promise { + async remove(id: string): Promise { const contentPiece = await this.findOne(id); if (!contentPiece) { throw new NotFoundException(`ContentPiece with ID ${id} not found`); } await this.contentPieceRepository.delete(id); - await this.pubSub.publish('onContentPieceUpdated', { - onContentPieceUpdated: { + await this.pubSub.publish('contentPieceUpdated', { + contentPieceUpdated: { + ...contentPiece, id, campaignId: contentPiece.campaign.id, + _type: 'remove', }, }); + return contentPiece; + } + + // generation info + async generateForExistingContent(id: string, locale: string, modelProvider: ModelProvider): Promise { + const contentPiece = await this.findOne(id); + + if (!contentPiece) { + throw new NotFoundException(`Content piece with ID ${id} not found`); + } + + const existingTranslationIndex = contentPiece.translations.findIndex((t) => t.languageCode === locale); + const existingTranslation = contentPiece.translations[existingTranslationIndex]; + + if (existingTranslation) { + // Update existing translation + const generatedData = await this.langChainService.generateDraft(locale, 'random', modelProvider); + existingTranslation.translatedTitle = generatedData.title; + existingTranslation.translatedDescription = generatedData.description; + existingTranslation.isAIGenerated = true; + existingTranslation.isHumanEdited = false; + + contentPiece.translations[existingTranslationIndex] = await this.translationsService.update( + existingTranslation.id, + existingTranslation, + ); + } else { + // Create new translation + if (!contentPiece.translations || contentPiece.translations.length === 0) { + contentPiece.translations = []; + + const generatedData = await this.langChainService.generateDraft(locale, 'random', modelProvider); + contentPiece.translations.push( + await this.translationsService.create({ + modelProvider, + campaignId: contentPiece.campaign.id, + contentPieceId: contentPiece.id, + languageCode: locale, + translatedDescription: generatedData.description, + translatedTitle: generatedData.title, + isAIGenerated: true, + isHumanEdited: false, + }), + ); + } else { + // at this point we know there are existing translations, so we can use the first one as a base for translation + const baseTranslation = contentPiece.translations[0]; + const generatedData = await this.langChainService.translateContent( + locale, + baseTranslation.translatedTitle, + baseTranslation.translatedDescription, + modelProvider, + ); + contentPiece.translations.push( + await this.translationsService.create({ + modelProvider, + languageCode: locale, + translatedTitle: generatedData.title, + translatedDescription: generatedData.description, + contentPieceId: contentPiece.id, + campaignId: contentPiece.campaign.id, + isAIGenerated: true, + isHumanEdited: false, + }), + ); + } + } + contentPiece.reviewState = ReviewState.SuggestedByAI; + return this.update(id, contentPiece); + } + + /** + * Method to create from scratch a new content piece and generate content for it + * + * create new content piece with the campaignId and use generateForExistingContent to generate content + * @param campaignId + * @param locale + * @param modelProvider + * @returns + */ + async generateForNewContent(campaignId: string, locale: string, modelProvider: ModelProvider): Promise { + const newContentPiece = await this.create({ + sourceLanguage: locale, + campaignId, + }); + return await this.generateForExistingContent(newContentPiece.id, locale, modelProvider); } } diff --git a/apps/backend/src/content-pieces/dto/generate-content.dto.ts b/apps/backend/src/content-pieces/dto/generate-content.dto.ts new file mode 100644 index 0000000..ebe84ae --- /dev/null +++ b/apps/backend/src/content-pieces/dto/generate-content.dto.ts @@ -0,0 +1,31 @@ +import { IsOptional, IsString, IsIn } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; + +export class GenerateContentDto { + @ApiProperty({ + description: 'The ID of the content piece to update. If not provided, a new content piece will be created.', + required: false, + }) + @IsOptional() + @IsString() + id?: string; + + @ApiProperty({ + description: 'The ID of the campaign to associate with the new content piece. Required if id is not provided.', + required: false, + }) + @IsOptional() + @IsString() + campaignId?: string; + + @ApiProperty({ description: 'The locale for the content piece', example: 'en-EN' }) + @IsString() + locale: string; + + @ApiProperty({ description: 'The model provider to use', example: 'openai', enum: ['openai', 'anthropic'] }) + @IsString() + @IsIn(['openai', 'anthropic'], { + message: 'modelProvider must be either "openai" or "anthropic"', + }) + modelProvider: 'openai' | 'anthropic'; +} diff --git a/apps/backend/src/langchain/langchain.enum.ts b/apps/backend/src/langchain/langchain.enum.ts new file mode 100644 index 0000000..0f27355 --- /dev/null +++ b/apps/backend/src/langchain/langchain.enum.ts @@ -0,0 +1,11 @@ +import { registerEnumType } from '@nestjs/graphql'; + +export enum ModelProvider { + OpenAI = 'openai', + Anthropic = 'anthropic', +} + +registerEnumType(ModelProvider, { + name: 'ModelProvider', + description: 'The model provider for AI content generation.', +}); diff --git a/apps/backend/src/langchain/langchain.service.ts b/apps/backend/src/langchain/langchain.service.ts index 35fecad..f858d30 100644 --- a/apps/backend/src/langchain/langchain.service.ts +++ b/apps/backend/src/langchain/langchain.service.ts @@ -1,26 +1,30 @@ import { Injectable, BadRequestException } from '@nestjs/common'; -import { OpenAI } from '@langchain/openai'; +import { ChatOpenAI } from '@langchain/openai'; import { ChatAnthropic } from '@langchain/anthropic'; import { PromptTemplate } from '@langchain/core/prompts'; import { BaseLanguageModel } from '@langchain/core/language_models/base'; -import { StringOutputParser } from '@langchain/core/output_parsers'; - -export enum ModelProvider { - OpenAI = 'openai', - Anthropic = 'anthropic', -} +import { JsonOutputParser } from '@langchain/core/output_parsers'; +import { ModelProvider } from './langchain.enum'; @Injectable() export class LangChainService { - private readonly openAILLM: OpenAI; + private readonly openAILLM: ChatOpenAI; private readonly anthropicLLM: ChatAnthropic; constructor() { - this.openAILLM = new OpenAI({ + this.openAILLM = new ChatOpenAI({ openAIApiKey: process.env.OPENAI_API_KEY, + temperature: 0.9, + modelName: 'gpt-4o-mini', + maxRetries: 1, + maxTokens: 500, }); this.anthropicLLM = new ChatAnthropic({ anthropicApiKey: process.env.ANTHROPIC_API_KEY, + temperature: 0.7, + modelName: 'claude-sonnet-4-20250514', + maxRetries: 1, + maxTokens: 500, }); } @@ -35,27 +39,82 @@ export class LangChainService { } } + /** + * Generate a draft for a specific topic and language. The draft includes a title and description. + * + * @param sourceLanguage The language to generate content in. + * @param topic The topic to generate content about. + * @param modelProvider The model provider to use for generation. + * @return The generated content. + */ async generateDraft(sourceLanguage: string, topic: string, modelProvider: ModelProvider) { const llm = this.getModel(modelProvider); const promptTemplate = PromptTemplate.fromTemplate( - 'Generate a short, engaging marketing headline and description about {topic} in {sourceLanguage}.', + `Generate a short, engaging marketing headline and description. You can be inspired by {topic} in {sourceLanguage}. + Return the result as a JSON object with "title" and "description" keys. + `, ); - // Use LCEL: Pipe the prompt into the LLM and then into an output parser - const chain = promptTemplate.pipe(llm).pipe(new StringOutputParser()); + const chain = promptTemplate.pipe(llm).pipe(new JsonOutputParser()); + + const result = await chain.invoke({ + topic, + sourceLanguage, + json_example: JSON.stringify({ title: 'Exciting Title', description: 'Engaging description text.' }), + }); + + try { + const _parsed = result; + if (!_parsed || typeof _parsed !== 'object') { + throw new Error('Invalid response format'); + } + const parsed = _parsed as { title: string; description: string }; - return chain.invoke({ topic, sourceLanguage }); + if (typeof parsed.title === 'string' && typeof parsed.description === 'string') { + return parsed; + } + throw new Error('Invalid response format'); + } catch { + throw new BadRequestException('Failed to parse AI response as JSON'); + } } - async translateContent(text: string, targetLanguage: string, modelProvider: ModelProvider) { + // has to receive locale, baseTranslation.translatedTitle, baseTranslation.translatedDescription, modelProvider, + // and return { title: string; description: string } + async translateContent(locale: string, title: string, description: string, modelProvider: ModelProvider) { const llm = this.getModel(modelProvider); - const translatePrompt = PromptTemplate.fromTemplate('Translate the following text into {targetLanguage}: {text}'); + const translatePrompt = PromptTemplate.fromTemplate(`Translate the following text into {locale}. + title: "{title}". description: "{description}". + Return the result as a JSON object with "title" and "description" keys. + + response example: '{json_example} + `); // Use LCEL again - const translateChain = translatePrompt.pipe(llm).pipe(new StringOutputParser()); + const translateChain = translatePrompt.pipe(llm).pipe(new JsonOutputParser()); + + const result = await translateChain.invoke({ + title, + description, + locale, + json_example: JSON.stringify({ title: 'Exciting Title', description: 'Engaging description text.' }), + }); - return translateChain.invoke({ text, targetLanguage }); + try { + const _parsed = result; + if (!_parsed || typeof _parsed !== 'object') { + throw new Error('Invalid response format'); + } + const parsed = _parsed as { title: string; description: string }; + + if (typeof parsed.title === 'string' && typeof parsed.description === 'string') { + return parsed; + } + throw new Error('Invalid response format'); + } catch { + throw new BadRequestException('Failed to parse AI response as JSON'); + } } } From 230e9b1e872ef683612ff8edb327901f84b4a58a Mon Sep 17 00:00:00 2001 From: Joaquin Date: Mon, 8 Sep 2025 23:50:21 -0300 Subject: [PATCH 07/17] feat: implement AI-powered content generation and review workflow in frontend This commit introduces significant updates to the frontend to support the AI-powered content generation and review workflow. The changes include: Core Pages: Updated ContentIndex.tsx to display campaign-specific content pieces and integrate the AI-powered draft generation feature. Updated CampaignIndex.tsx to improve the campaign listing and navigation experience. Added CampaignCreate.tsx for creating new campaigns. Removed CampaignEdit.tsx as its functionality was merged into other components. UI Enhancements: Added reusable UI components: badge.tsx, dialog.tsx, input.tsx, label.tsx, select.tsx, sonner.tsx, and spinner.tsx for consistent and modular UI elements. Updated tooltip.tsx for better user guidance. Added Header.tsx for a consistent page header across the app. Content Management: Enhanced ContentTable and ContentRow components to display content pieces with their review states and AI generation status. Added ReviewDialogForms.tsx to handle review actions (approve/reject) for content pieces. Campaign Management: Improved CampaignTable and CampaignRow components for better campaign visualization and interaction. Context and State Management: Updated CampaignContext.tsx to handle real-time updates for campaigns and content pieces. Added GenerationConfigContext.tsx to manage AI generation configurations (locale, model provider). API Integration: Added API utilities: campaign.ts, contentPiece.ts, contentPieceTranslation.ts, and util.ts for interacting with the backend. Centralized configuration in config.ts and error handling in errors.ts. Styling and Assets: Updated index.css for consistent styling across the app. Added a new favicon (favicon.png) for branding. Miscellaneous: Updated index.html and package.json to reflect the new dependencies and configurations. --- apps/frontend/index.html | 4 +- apps/frontend/package.json | 5 + apps/frontend/public/favicon.png | Bin 0 -> 14517 bytes apps/frontend/src/App.tsx | 43 +++-- .../components/CampaignTable/CampaignRow.tsx | 24 +-- .../CampaignTable/CampaignTable.tsx | 13 +- .../components/ContentTable/ContentRow.tsx | 148 +++++++++++++--- .../components/ContentTable/ContentTable.tsx | 11 +- .../ContentTable/ReviewDialogForms.tsx | 165 ++++++++++++++++++ .../frontend/src/components/layout/Header.tsx | 68 ++++++++ apps/frontend/src/components/ui/badge.tsx | 44 +++++ apps/frontend/src/components/ui/dialog.tsx | 121 +++++++++++++ apps/frontend/src/components/ui/input.tsx | 21 +++ apps/frontend/src/components/ui/label.tsx | 19 ++ apps/frontend/src/components/ui/select.tsx | 158 +++++++++++++++++ apps/frontend/src/components/ui/sonner.tsx | 23 +++ apps/frontend/src/components/ui/spinner.tsx | 11 ++ apps/frontend/src/components/ui/tooltip.tsx | 5 +- apps/frontend/src/context/CampaignContext.tsx | 63 +++++-- .../src/context/GenerationConfigContext.tsx | 39 +++++ apps/frontend/src/index.css | 6 +- apps/frontend/src/lib/api/campaign.ts | 49 ++++++ apps/frontend/src/lib/api/contentPiece.ts | 127 ++++++++++++++ .../src/lib/api/contentPieceTranslation.ts | 56 ++++++ apps/frontend/src/lib/api/util.ts | 37 ++++ apps/frontend/src/lib/config.ts | 2 + apps/frontend/src/lib/errors.ts | 9 + apps/frontend/src/lib/types.ts | 19 +- apps/frontend/src/pages/CampaignCreate.tsx | 85 +++++++++ apps/frontend/src/pages/CampaignEdit.tsx | 26 --- apps/frontend/src/pages/CampaignIndex.tsx | 12 +- apps/frontend/src/pages/ContentIndex.tsx | 66 ++++++- 32 files changed, 1342 insertions(+), 137 deletions(-) create mode 100644 apps/frontend/public/favicon.png create mode 100644 apps/frontend/src/components/ContentTable/ReviewDialogForms.tsx create mode 100644 apps/frontend/src/components/layout/Header.tsx create mode 100644 apps/frontend/src/components/ui/badge.tsx create mode 100644 apps/frontend/src/components/ui/dialog.tsx create mode 100644 apps/frontend/src/components/ui/input.tsx create mode 100644 apps/frontend/src/components/ui/label.tsx create mode 100644 apps/frontend/src/components/ui/select.tsx create mode 100644 apps/frontend/src/components/ui/sonner.tsx create mode 100644 apps/frontend/src/components/ui/spinner.tsx create mode 100644 apps/frontend/src/context/GenerationConfigContext.tsx create mode 100644 apps/frontend/src/lib/api/campaign.ts create mode 100644 apps/frontend/src/lib/api/contentPiece.ts create mode 100644 apps/frontend/src/lib/api/contentPieceTranslation.ts create mode 100644 apps/frontend/src/lib/api/util.ts create mode 100644 apps/frontend/src/lib/config.ts create mode 100644 apps/frontend/src/lib/errors.ts create mode 100644 apps/frontend/src/pages/CampaignCreate.tsx delete mode 100644 apps/frontend/src/pages/CampaignEdit.tsx diff --git a/apps/frontend/index.html b/apps/frontend/index.html index dd3edc9..ea42e94 100644 --- a/apps/frontend/index.html +++ b/apps/frontend/index.html @@ -2,9 +2,9 @@ - + - Vite + React + TS + AI Content Workflow
diff --git a/apps/frontend/package.json b/apps/frontend/package.json index d766ef1..6c77dea 100644 --- a/apps/frontend/package.json +++ b/apps/frontend/package.json @@ -11,6 +11,9 @@ }, "dependencies": { "@apollo/client": "^4.0.4", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-label": "^2.1.7", + "@radix-ui/react-select": "^2.2.6", "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-tooltip": "^1.2.8", "@tailwindcss/vite": "^4.1.13", @@ -20,9 +23,11 @@ "graphql-ws": "^6.0.6", "lucide": "^0.542.0", "lucide-react": "^0.542.0", + "next-themes": "^0.4.6", "react": "^19.1.1", "react-dom": "^19.1.1", "react-router-dom": "^7.8.2", + "sonner": "^2.0.7", "subscriptions-transport-ws": "^0.11.0", "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.13" diff --git a/apps/frontend/public/favicon.png b/apps/frontend/public/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..e8776549edf1eafdf842f8944a7f89943091f6f4 GIT binary patch literal 14517 zcmaL8c~p#F{5XDRX`?-9Zz3wfluD7BK`NB8@0x@PiAbpCnUo4`-j>QX5ke?JDm6n< zA(f@O?OqrB*L!J9GoA(j&{*T`u@L|~ z{KNxQW%$p;=^qjRTw>OEtk`@SH}pOZjsZrF{IS7f#j5|`Ka4h4Ewb}-+qxEJgY}X1 z<>H>Ma^yB`sQ6s+{|Zw`}V(r^;H^v`W1wxp#oq{?!5JR3PMi{LjLs z^}NBO2RIR}AAc>9WH+3cQx^xpsVSs9++2YD%FGL<$n48n4dzMa{V+_%dBcf@JLS86 zxAdYt^*2xOrNhskrG$s~48G0_r>4f8rK`ggDbHH{T%PF040m*F6P{X9J`@qjx4y^J z`rlc7U0K_%kw^8YIN-J3d*Qj?1v||s^eu~DW;#4sFsH!P>>dsRIsH74-&x;$@G$96 zoqU9EK%RQsjOK2UR?w91^6heZ0w-;rl=9J0nYJB(!uD`i zu6Yg7LiX_>re&>c2oGj=q8sz&i?c!Mm|6M5UfI1Q9UUcm95sd8IK^q-TcqEO*?e#~8g-T`*;iqJ>4+yhDnKS*;xAnqj`s;{dimYs>T@H{2|*sa}%& z=00Ue5o5IFWr`rwi8(3w(Ny1>N6@A>4IvjlXBoq-#?p-+IL-rOq@F;Mj^mwgUgI3G z&pz-;59H)h)(1I&M0XIc)*7w!f$15m75gqqN5SYnE+Hu?lXu-fQ~4IcsmxXdbC@WG}LukL^a<`;y^ zPdRq7{@fMyOz0=SD;N81wu38`ld-Qh=P9?YTsmtI;6*k!ti|KMj1=0LQ%jTxb08%akfvS?En$InV-L z*@3@Az#9q|lX+7S6ga$g)ldug0f+G*WHjHEoAFt`YiiNM^JaP(W~p8WFRXvQ58@p% zYMUUwEp7Ts_o32rkT$1w!9?2LSD9;4_alQiF2V%h#o%lhrenb7%mlm&jM7PCfoZ9_)UR z`y2HI??6l54&dQa`5WZ5G%I1 z?8?J5oDBduwc-5{lsNZ8179RO(`84srca}YtbO$fb~^!M3vy)(HfG5%GJj&YU6)WD zIZ3v%2e|~`@}$^=mV_K?4)>ZxnHs}RXE7F%{hTnPH1G)`V%Hwb8!gUFpq!UIooJ}( z+J4K7mM-^gQbf07$NZk3kpHAJ=IGe%nR0$AtF*^;?6q$g2>40^P#0PUwT?EEhw{-O z?;*YK8c26AekdQ=@E&e$_!C|~s+CYhOsJ3;D72rUiRrh!l5Pm_FxI05$cq(Ht@Irq zT*fV|AFL)43nc~r_%iO0Aen))>f$*)Y-T;8fg=ELDStzfTsn&x)^xX#R8Mbw%-Z22^I+^InEM^9WTS zJ4d2aBB_^*zOc5)mKGmxZeHl+IDg_n3IIg64knyUzae|+KH)Ic56Igvhs|)yr+Yp1 zM_9|`MT%ja6|Ak8+9rkPS&J^Q1Il{->;cx<11&nKy0P<=09aF~H5YjUh5}ch&rlQP zARjoUI(4_lPcNsIIHOQva3Wm7X-W&Z%9{=t#dGFjp2=L+nfh}pmKzZkv=bNX&E6^R z$jZTI0MO+T@x9Ti)jCF^fnU27+ndGkC7b*w3W(g&p_6JHivy#n{$8@He_0;2q&Y*j zt8oSh!+(7~)>84jH`z0_0sxT*Nh;qjK4Iv8+$tyfcI;$02@9GI)3r*WoSw%2Yx5_z z;EgldR*e}FhzzRt4S9QtD6ZZLYOy#|^Y|n(9I4^8nJB>nf1BDEBuR%d`kOdZKKr$# zcvGau5gcHt9 zwO1Yx>)WKGzj_vV8qlT{F+F9=JNUu(x?be&nWb*Uo+&=;hgqs=1H8qL%9tf1t$nq0 z%1KSLbU&t>0eR9TvbSZia<(tSZOplNf^rt><9e z(x+$v64ariU+cY>2rL?|$g=ptr#;MMg!1A;Y?#We)55|38km0;3lj%}O*dTbL1BW5 zJ0;0)t1pt%{m&q+)ziLo)pbfs?wT-QzUI=Od~r^_wF<}(`CaML%7q+Spf#zsU_3@* z_J!9UwMb9fUrfOkLi-*HnC>ehbvCb%xy>D1l^9skw<+9fEV}q6h!(RcQkrkAyNmy7^I`(r>Iy=cbwiaPaq3C0(Ga01+CynY8%wz)WE*`p>_)oj&jzuP-b{Y6Gw zAN!;tr}Sv`Xx{?pj4x_`M80&c_HfJ?2WhAL^2yXXx+LJ4zY>MEI~a1qai|GJCOwA#gy=jeHNpHBFZhb980aJPy-f@ z0_!Hygp}D)>cvdj?aLrFvOI7EU@fulwWbEUPE4L@Lu>ZM^oVLj+tz&VD&Z_QB2mul z#A5%V|1qD3xy~l-7$M=n=S66WI4-mo>uS^!L}(esX>?qFHroeI_si1(h`WF+?p4V_ zwTeU(%q3FtHKN`j?w^xk+q1%?nieq)!mq5)(jDf}2ANN798DFTQX4rayGuLyb`!+` zYag#4^GDda^_$*9mF=@Yr+9680&e3b!F#>D?n>+WDpm})MIZ=}AKWqFCfO_h8W-fp zTdLjvhn6P2mJ=LvpPAd84BeM@mdK%-g>@ZQs~|3)J9Kd3*4d-wo-0v*>Y_G5^b0Mxf0ju@;P)$t*m5ne?6?JJdoS zH@Y>L&}`%#k6jhXr>G_&H&w(sb_Z+iKcU-T(NKPWoS-T*GP(j?a}BAA^Yz2!E1?3d zPefiP9G>UvrAR2MIEWx~yK?HtWj6EjzX-<-@PAI>rmNXJn&AKCDd;jz#&|+mpVpm= zNJVREco=EBuKZ?2(jCV4OcdtM07NJWile0Kw8wR2pQcs`%6<-AAd3#UPL~+TpWd+~ z>uF0)GTbedV%*0mlmElS*l!3gmwxGYkziXC=|Tb4_}t@b9j^pRZ{%*es`4$p974`T z$*rGI!d-e!RoHoT*B-9}vgW#Hy2HC0P7FFFn$4VXPZZuR581%nRB#S~3+*8FE}c=^ zXFn;I+Oo>_%y!eA*m<@ta1Rpl;=St>$p@jUqEOuuh}>|Lk>2dM;USn=IS0}eLz^b3&zm6sdCed1XmsN3Y@Jp}nh2`ya8OhrJyJ__ zAcnLu3ek*~KkQ@#`b@t{pHGeRm;5S}R6~n?#pJO zQ_ZZk!=8eA4v}Y^x&?TmYYnBB{)wYPQamKiEVriebu5v#(4`8|&RC--;J1mxcNpC) zl~2#oEc}(5l-a;`5$)DCAC_7HjH^XqDu?#@sD?_uS3b#m)jlmjbU zj(k??x=O*eVNfNqJZ0OK57+DRZC5O`eAr4W556_l#~&a;CD*UwY)6Zuod-{9#s4bnbht;C?~(_>tPwBZGjU(K5?@eQpYSU0 zu>V%eU;f{X9e(mnPwo&MRZo(qHsRZZ5{l^HZEUbr# z8l0L>3t5UOA4*e&EJ%?WRgnk`T;VN#0N7JagxbIpIVV$;0fFYiVK%c0;E2m_zrcm@ z=$~pp1N+V0q&`tww<|aSQA~=8RF+q!Z^99QPeIGAH&bCnSYw}^g(hL~61n}90RwXPv&%(FHSUCIp*v-&khBu{ z3`=y{_r}$-@dqb(2~|gyOM$u+Tgl(Emt_z}n#-K`357^j$*y<#An~Hi!@AVnSni$& z2FUM9hA^Q0K83LGpVPR3ZsZoYb-cX5dZ06!UzUEg6Y$K3G#Kx#A(@3o3<<|hi&k2Od#>wt;H1!YZ&#F;h5 z`aWBOxyl%W=sU`1p~?zZUlm4ke{uZo0=V}zG?@H*LG(~rCCvWck;Ul8JiL`goblu7 zXNSmZu<3c-%qj)gYUym0d$~G2yUIR$n(E6z$_oC5NA|4HWsd0I1CV(i8r8gHkMVQV z;&gYCKL)h)Rt_L79|FrnCw_!q(13?mUJ^Z+maznPHyL>;(Sl%e>Cog8nXWLYso7nkqDYksQyyIn5BbvRxmsJHdaVIXBvJ02k+GQF|nD~`=I$%{l zOV&-lH<)$O!|n)F6Q^_Z&&B%3dN!ZMes!AU=!p{BNI8AqPdpS#QhA+|<_XJ2G7o;z ziG%*}UC$;8^WQ_`~!=gQhr}oc`m8Z~`^pB91l?MNg&f)s?bD%<8W=3q*yL@yG_jhDf$%)GL z)6E)(JHFXCPD=8R?%Y<+b1=y>y_|ma2q&QNsVb(Mr__4@zcG;-Eu7y?K94SRe(!gI zHL{d(oU*B(WCt>y_5|zR4R_r~+OY+(*gBaLFb44xg`2IH`&wYaj(2DYQ&3Yk1MS{ zZY0c|NXIeylqkaHSb_ez=Y!TEyJI+sPb@#1{FUiV=si^PenVKfQs`&}i6arHS2|O2 zvoE#oQ(k**oKhT_zCzZorW&`up3=1gSqmM^jj2QAy?-m8+-!+lR1zCoH{9Z_#`p|#ncr9jT2^B1>m0Oe+Nq)tA)X}(j&!gH)R;%Xy;oRrs z=dm_Atd1$OQC^YnPl_^Q%-uG2)p*Wf(<6IMV=>J-2WGWx8d^L^p}%-v+lGT_#*@Q~ zCQDG|Cm~A87LI?I=I9-F&#wPm54sxA|NIH{`k^A(^GXMKf`hd=K^t3kR_8w)?R5ZY z1<>;BnwlKG_C|Te(E5Q-c|vI;fU^Lgbh;kPHrH$_o4a+N@^eb~S;H(lp#^z#P? zS496H7omo6-1C&t9H!$Yo>#U8z_~dYOD%sKm?<6CYGsR%uyvB2ET>AN`& zW?~NWCN0qv*|k>K7Yi3zCvx_GSmDMgIa?Nx-FJrk2KHQ0ZL;tWfmOf2~N zD`>4^=~Z!TpPMjz|1T|{CW16P1qIl_J;nfeGIZwkz zwx1FKb$n?2geK(yw)oaa-VQ0W%Qe(hRN=<$binod22~}N{*9YA5pXdLJ8x+nuY+Ax zYba06JZ*_;I6m?wFhngj!c7wLnraqt<36Ls-9dP5Y>5L`D|eTn$moR9paffd8=x9^J;xS4P-xjU05RGb4U-mNLH{N_Auv8w6# zF4`y7!JZ_yf#Oy-6C_f2StKD18@Km))j#O_aYE~i$Fbz4kOp6bdWC7dl6=|M1DYPI z#-uJTCGKnO6A59j31b)1p!uL1;mxAV?=Cocv~IBIUf<8d>aGhyyzv)BCq9r;E{*yv zZFj#QU(GyYQ!#o;OKLf!e3E3qDc-P4d#};C;!cObuqMv)^OZZgW0S1zwU@ER$~wHJ z#0`i0osv$l5XgU)dB@5~x)-knJPd1D5@eq?k^t1C^e zQgj`?as-Jk!SqZFE=qRuUMIa=m?OORZWk_@MOlNepOD_yM}MI<$6dY|r-h6Mk}+_! zt?Ut{$C4~xcY0VVJ9tu~bmklUr%ketuPDoKJwlTmkxk2nlY&FORjP-W%;9Ha{`=_7 zV)uj*G-gVoQI1=cHPddrk_CEFMleI$8V_wsD%I<~3XoO^rS7HVBQu1?kwM8DF^Dj8z3L^pjH&tK%s z2i*ELRD11>fTD?eT4xJhyJ`RW%0iPnwqYn=Y;qPq?GfGr-7j0Eno7UD{IgUwBJdG& zpM~XUKmW-5$gkn0vqX~){ju+;c3o)XqxYf z_icXDJ!ILFNg3Va3kRA$EXda0xJ zYvgIOd$bgH?~aC%>s<8AnRf+o|2MrZ7-DVvT?vHGg->5`VZSJDWfgM=qWZF@K!2a8 zHfHomLD-n^bO3>H{k=vILQhrFJdHh=f%smSF?nXS?7h&1<3b49+M87Nb6E9$e?5JG zxp8u(xO`ym7-g=uAowRKW}(=5@i3p`=6vvjR=A{dCKD!gfs|Yh7Jh^><1>G&Q1=)K zaJ3A9RE>UNw1`Ey6BAbXP4~PUrpm(SPSNMYzX$f7Tc_k9!x3opV|g#MIsoxfhmrCJ27~(n;F*rSE`0Q1QwMj@-`OWi1@I!GTyc1D`P5j zzA!I=l=J3b85T%UR;1|5j9a$}wmnc4sHjud$~tUE1eRyJI0FGi9VM!((SBq_9)31z zM3vpGImkMCz1N*_^QXjqsyI}bE2&I_iMIvnf9Rq%*1wlq@KpF9fz)-at`0XWH3$cG zAekaY{i#LFKAbz1mmbJbr276AKR%gBwUN;~8!jT1(we;%6V-)$MGEgN+cI~h?5_HZ zV_AN0zR?-=^&=Ap{_Ua4;&GlG{eJNzQK`gvNa~@Lq@!`| zBiBQH8zMJvr7fFui1f0(dx`f_;>?$txSW#w@;=8<#d8-RRiv?*$Texv$as{V{n7g# zZpO2&)E@per==m{q;^l^SQ_bw293kC=>qo{I+#V=?rNFDMi^!4>$Onlmzr0Py>UtA3T?jGEbROOhVb`owDx&ps6nN=!{zAo)ZE6p9a*4mM;)RgAwlE@$+Lw!O-~)ZXavV_lJ?<#CvDoXx@itst=9gXYTbunm_e zf(iz1`((>ulSLm48u{V*w8StxYa2H1Dm0jnUiV}djJR)16I!1R4m4ofSF~%-LNC@K>mBMJyPo ze5{l6Tam(J0t2a*dFCUdjkxOhazCEimxWy_P^m!A+V8dvvnI(omnnp4uZ=dV7sy7Y zzRO1<>*6~LI&HtpwGo?g9Ai#!&gy{x{|&6fFc9r{3^cN)#wc9QDW7GtfjV_*3N@)2 zx!{GW54nx5yU@Xo+1I^t2VGdYwW)lde0EpxY60_@2QUP0l()-GJkc0GB_CtF(?)}# zR;HU=OQ2#?|MB~R?b9OuEQ5_0`KWNJRu#mZtK zy1D>$=I>D5AhTo?YJd*>aL>V-ljRfE` zeYa$?PEfyOcp7E6-d!i-n^K{l$_&nMcs49h_L+}g(NXu21)DaCaE9Os&UYWOZi}Rt zsT)$GW*E3VV{g9j7EAtva!|JPn={T1q^O@-IuRVYdBpe93hn==Sm{5_`LGT%9>3X9 z3Z=pZ30@Hm{x`dr2KOkEkD2K3E}Yl;2UGRK<+x>W;aPIr*+p)_hYC0;BYXHb2h>A) z-AEl2&OO#rYW9aTaiwW9`$bdV+2s4NJ9A#h{bkToEymm@9VBh{%aB$@bp0x_L}T%W zAcdOR$l_{AYX7`q`&hAQs;{C77NZ+^obTtDnWCHPrJLG=Xmhb8Tn?Fmvv9~6Y~zvk zV4gG6Ze4XrBb09YB=Z(JK)FirrKl6uIGL_iV*#6{PC5u1uo?CrK02#ZbgS%AlNr7I z--6+)E;5)!!cpL+8-$KO&RE+zY=YSOf-i3BXZoM;fVC-sp%x))Sow?cb0UZj~t6QMV;61dM7v5ski@evO_m?=WOC`>2Tv5EVQ?5`95DKiyf0q{q?jsBgM%Q+#`MAA3{T=n6cg}?`(cBixUJ9JE9bVF&min z@nSlFHld#*#*Xij6V9Me;b^whaqKBdh+mFro>92TP8xn^nmuKZsY6LUtZaq)ddeV( zhIshi$6b)>{O-YB88RDL%3|uU?4j{8M6T^=qMIyXU-v7C%Iw&GL(}brdB}#|W{MrR zRPl^dN zV4*GWy9u^pS7rTUP{*mF{{b>jtTzP1GK2P!L&MLoh;Q9E);FY}j5r4k)nlK5>udk5 zx8a7{;dG5XT5c}D)aN2;d?hx#T!mxHmTC$nXMdpt)iT=@8!b>}J?f~R;7D7U;m%rC z_}cn~z5O@4{Wlie_~3rWZ<>^ESddOl&RbzjdCrP44yEphs--{9 z8+YddeAS?lPuDZxl-=!423_Yzt*AYhML~G=yY9<2F3l-HA8eIhpAY^}A>{82GQ2J5 zns9$6;Yiy`t|oVs^o*2Tx5P78@d|`?uD%2hE=OTiMR%{O$LrxvF{XhGLIw*0Y#qeV zp)}Dm;n%f~PW=6^BiID8>kiy^hoX|>dPq=BEF8c_ok`bS(i1)}yiYI&^8r<#t-$%a z%qKVY)S`;;pgNuRo(%5*kl;hDq`)mUl>zzm8?vFzM`H^i`t!B>r!%zS9cZWRR^h^* zSz!H$bRufWj+?TfUxn8%Q^6a^o!D%6m0b3Y9QTQ6*Pa)FnT(vai#lHHOu#n~RSWN_ zxtxqNe}MQfZpc=uO>Bt5__2XOnzN4{RUTS)@3=}%9|gSY{{F?46}@As8Io&7i4Tmhot5W1m=r$Qj3cJS3yIgZN4F5k}q*PlNrz|#dIbVqChkzY!zL4@RUoT~}<>!%f zvRu;ppei7Q`I{fca1917O!tLXKfXlgeL{lh=+@sktA zxY_dBtnn?LeG|+R@Y5xe1(n2Y;T)S0xO_mD0~$yVr5r?rLike#h+VIg|+ub zeF_)v`C!W}Q?^5EL^`(?;Udw(k@* zcO{MHH5}^r62^cXJF`X?yxl`*%~Md!3GHoIdD5wme9?+0MV!QCBe7;GN0#0@j$_zU zJ>>_7pjLY8%Fgu4`Xd2EDT}jLK811Hucpc=^8~PE69GP=hvyy07#aa#@ zJ;bicW}V)AN?1$WY})98^Z#%uv2Qiblla;Xd~#YyiZIq(||u+DS(@lj|6n zzwBMRlRv33B6iz&Pgt8axowju>t$TU2zEGSf$$eG%@^V}c zPSfKuhWedN_joNovLCNY(7vZ;my8IksJCUtf6AshYCGwS%}2+rj0$^`V{nXxV6Du| zYxzlcjL#L7Vaw>JDp}gcI&bl+~|B&w5~)0hF&(XkZp;+z*2#C@q(g3 ztL|WP%uC=9jG~v`_KmkFhvC0-!x!U{>7WCcPFMFIRieIZFK}IU=II1eeiJdGbcm}% z-)nJ*tsg1d^m5!{3p|)%4Cvu<@Sx<1o=yWUIeBh7p#zx1Wm@R@YYP0X_)L4Hfv+ur{5=Q5{9J4iH{1bg z8@ZkM>ifB)cKFDu3TJXj;6i1#Eg-OWBeyIMiPl}PwX&FtuD-!|6ZFAC;;4EsCt_V- zDg(Ym+7Dz6vSMstFF`OUu!l&Lhca7x+~m4ip&}N{n2$QDw9isL-2;>v39OSfT0zLt8;pJ- zwjt)@VNQrH%y()6WW#lFVJ|@qV94G>a*fkYZ(d$@bR&N0%wG}Gb=@uRCfx*sodU!o zrrCrulQs0D#k*#h%Zcx~UvV@sgSp!TRkzAnJ(KO7^^YG@a#s{;EK>hR$%xQc2>(N%6jtQuPzj8)g4LSOuuL!~sv z#!d_yWPL<-*ZwBbfR#3Z4Ya4a^*^g=-!RNbzV77c-Rmi|)MLQRVfi}3&}?G&w3O%; zdi!7gYlD+04Hj+|M#x1_Cho zos{>1EV!_*JGT439Q~7Lgjfgmv?X>8FVEB=ZRdxSplNsct2Hgp88YUtw0jQn5o|*c zEmVWCSnGO8vFc)n-FggMmWS#meHx$Q>|$p#559Abuvnu$v=4*;qT!5{$aZ;OVuYq0 zC<&yv0z!ia@sp8ZSqZWg%UvZ_{_-oJS||HGaWm}s1H3xkOWsS!$A+u`&n$d5%#m-LMAMhZf{hNX(qHLA)g!P`3UwwA70yVlzxETD%9G^3f+DZtYxhH$ z%MlpLtj!{&MxbP4?>LyT^GChgdW&Blos{;0R!pU94!iFmzSI%>t0(V>KXr6vvRYQ} z0x*Tmay0~BslOW^$|!cr3Li0}Z>@MbeMqItk)39V=P4;Og3d9Wi3>I5_RiRYY>!7L z_$oXaIQzYeZweFX!+h%89pyjAp3De2<<973ar-cPoIbp!!JsTmYrcRGB{T2w06{kb zD<~rkHq1`Xm@pLCF=3WYcPq!d4!Mej73#A^%oa$+Gsdrn%0D~|j=(LyF%P96pvX^Y zKt1%_gQH;cX1-mXhGS{S2&(cBzvvy}9!{|PlME~9j0^YG?7m(8bv^*MYQVvedn*3h zf`)M&G$=7Qo(z4+Ura!>10HI9?*>|~#@*$xUrEAee=;?Er3?G_m&X((K}ItoPywOm z7hPU5NArddtwr-@HJB58#3Vq_<_!d#yOlKBH+8msz4!cSwvDS3E~ve!2Afbt^Wv?< zZ~DtwDPDE4Ppn#PHK%^C5=xyRgLw%$cn^^l1kU(|xg^Cb^tYK zF~Jace{MORqaG;WB8me zLy$F$F(lk^$=jY3Z1HXMmXwr;%bGV#1a%19`58O)>Vw~O1a>$~WqQ+-?X@jlGszVGJkEzCB_}^OZ8!h{4fC^@qV^kQ? z;co(5|CLbLYo-cVHe*&CODpQeo=urZq<*K+cBeNvhB(p$iS_b?8UzIhBB4I{aT ztYh>V)aT#|NB*7SB2#e@CGBVLF6o(?taJod(rPpzHDaWziz%ojCSRg8`wpt2^UT?R z`ZCEZ-moYhvBM2>35@M>Xni4I{}knPmNG20w9XVs6pa|LGkIwpl7PQ<2;)>JM!-t< z(q@YGv{z41wp|r`rR@V30sG*|`ZjRjCf3(La%JGCGTY>(`N${SB_DLQ{f0N9U5CvkOXepQ`Qy zhf311-%Gy?`~y|vZTXtNx9ZJmw-B8wuvun=byra!5apcapk}v^ag+n+PT-)e+!;q< zm@)+MqfEc$vrA9Pn^d#H#mr_XV5l@-3+vsVh`5hm=&VquerX!RURmN*H55<=A88eS zetzOdfv`a}gp3uN=}>KG(0=!LRc>&Sy}#orD^I$D8~%%3w8YmC;11eD?Z#q<3!+S5 zh1-nwv6(OMc3=+fl$md}PnwixR>cWUCTI7(EjhMsgIQopOi)(h`5e;d zBN>LZm!*%tiL(H?^W)|g5`SN#Zp+c#er~NlL2~QFw~EJvzFY7YRc*=7rDV!!qgUga z1vn+H%3FslaVtp`;Ouyg0YfKGIou#UUC{cr>lUjCy$?b%y98L=3yL=A>3&dk{e9de zl6V8VWEka4VH$Ww3U=Dw|0X4)m4v4a4vo7TU@EuusUSm(@uG}AO_|*|8+VK!%iM;& z`KyWI@az_ltzY>!(5RvJT8kzc2WXl)$C}SG4@_e;3i6gH23F*zg!MgXl7DptKl$&9 z1X@IJB85?_^(E<3MK^y9NHMUJB0n%YRX~fI_LQ(b3BC+bIS1d6QJ2Yrdnv~7!7jLQ zrT*QJHBfv?U~xFfBN2iB3UI#;F_(KO*0Rfm@GD;N_48w9qq+RwCy#e!)w@v@#kM!m zDX7`ld5Q&m*jw0v@R8*I{XQNv(8y|DM)y?AWX!})*M%!-0|s!}DH_4zn6?ltF`;Y4 z`;U~c;O({b$_ilLU9rKoDHS}>23O|s(Zfb!0uK1|Mv#3ykh){ZGu}$WQ)O`g9NIxx zF8__S*6Tuin~b|;zp*V8FKs~eUB?)U!t^Msv;q5%IwN0PhK!>YfMMebzW+uZD82!% z0gdd#`h)dH#40%OR-|=yNX99c=)>WG9lrHe%*@a>Emhdmq?Sqxq7&&t6+eqL~C`9dk0Va7?tT>nv zl8$**GarHw*>bqZei51<+DrL)j|6{IQufMlIQU!$KqCMBCqr%c)C_(R0kDAo{C`Z1 Z>ToY#pGQ>T55YBH&Fb|Y&sWmU{T~HIXQ}`I literal 0 HcmV?d00001 diff --git a/apps/frontend/src/App.tsx b/apps/frontend/src/App.tsx index fbd4c99..b0d34b9 100644 --- a/apps/frontend/src/App.tsx +++ b/apps/frontend/src/App.tsx @@ -1,33 +1,38 @@ +import { Toaster } from '@/components/ui/sonner'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import { CampaignProvider } from '@/context/CampaignContext'; +import { GenerationConfigProvider } from './context/GenerationConfigContext'; import CampaignIndex from '@/pages/CampaignIndex'; import ContentIndex from '@/pages/ContentIndex'; import NotFound from '@/pages/NotFound'; -import CampaignEdit from './pages/CampaignEdit'; +import CampaignCreate from './pages/CampaignCreate'; function App() { return ( - - -
- - {/* Campaign Index Page */} - } /> - } /> + + + +
+ + {/* Campaign Index Page */} + } /> + } /> - {/* Campaign Edit Page */} - } /> + {/* Campaign Create Page */} + } /> - {/* Content Index Page for a specific campaign */} - } /> + {/* Content Index Page for a specific campaign */} + } /> - {/* 404 Page */} - } /> - } /> - -
-
-
+ {/* 404 Page */} + } /> + } /> +
+ +
+
+
+ ); } diff --git a/apps/frontend/src/components/CampaignTable/CampaignRow.tsx b/apps/frontend/src/components/CampaignTable/CampaignRow.tsx index eecaeb3..a59b2a0 100644 --- a/apps/frontend/src/components/CampaignTable/CampaignRow.tsx +++ b/apps/frontend/src/components/CampaignTable/CampaignRow.tsx @@ -1,5 +1,5 @@ import { TableRow, TableCell } from '@/components/ui/table'; -import { Plus, Table2 } from 'lucide-react'; +import { Table2 } from 'lucide-react'; import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'; import type { Campaign } from '@/lib/types'; import { Link } from 'react-router-dom'; @@ -7,31 +7,19 @@ import { Link } from 'react-router-dom'; const CampaignRow = ({ campaign }: { campaign: Campaign }) => { return ( - {campaign.id} {campaign.name} - {campaign.createdAt} - {campaign.updatedAt} - + {new Date(Date.parse(campaign.createdAt)).toLocaleString()} + {new Date(Date.parse(campaign.updatedAt)).toLocaleString()} + - - View Contents - - - - - - - - - Edit campaign + View contents diff --git a/apps/frontend/src/components/CampaignTable/CampaignTable.tsx b/apps/frontend/src/components/CampaignTable/CampaignTable.tsx index ba9ce39..7f4776f 100644 --- a/apps/frontend/src/components/CampaignTable/CampaignTable.tsx +++ b/apps/frontend/src/components/CampaignTable/CampaignTable.tsx @@ -8,17 +8,16 @@ const CampaignTable = () => { return ( - A list of your campaigns. + A list of your campaigns. - ID - Name - Created At - Updated At - Actions + Name + Created At + Updated At + Actions - + {campaigns.map((campaign) => ( ))} diff --git a/apps/frontend/src/components/ContentTable/ContentRow.tsx b/apps/frontend/src/components/ContentTable/ContentRow.tsx index 17cd12e..99f218f 100644 --- a/apps/frontend/src/components/ContentTable/ContentRow.tsx +++ b/apps/frontend/src/components/ContentTable/ContentRow.tsx @@ -1,34 +1,138 @@ import { TableRow, TableCell } from '@/components/ui/table'; -import { Plus } from 'lucide-react'; +import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'; +import { Eye } from 'lucide-react'; import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'; -import type { Campaign, Content } from '@/lib/types'; -import { Link } from 'react-router-dom'; +import { ReviewState, type Campaign, type ContentPiece } from '@/lib/types'; +import { useCallback, useState } from 'react'; +import ReviewDialogForm from './ReviewDialogForms'; +import { Badge } from '../ui/badge'; interface ContentRowProps { - campaign: Campaign; - content: Content; + campaign?: Campaign; + content: ContentPiece; } const ContentRow = ({ campaign, content }: ContentRowProps) => { + const [showDialog, setShowDialog] = useState(false); + + const onShowReview = () => { + setShowDialog(true); + }; + const onCloseDialog = () => { + setShowDialog(false); + }; + + const contentReviewBadgeVariant = useCallback(() => { + switch (content.reviewState) { + case ReviewState.approved: + return 'green'; + case ReviewState.rejected: + return 'red'; + case ReviewState.draft: + return 'blue'; + case ReviewState.reviewed: + return 'brown'; + case ReviewState.suggested_by_ai: + return 'yellow'; + default: + return 'gray'; + } + }, [content.reviewState]); + return ( - - {content.id} - {content.updatedAt} - {content.translations[0]?.languageCode} - {content.reviewState} - - - - - - - - Review - - - + + Review + + + + + + + + Review Content Information + + Review a content. You can aprove or reject it in the next steps. + + + {content !== null && ( +
+
+
+

Data

+

+ ID: + {content.id} +

+

+ Created At: + {content.createdAt} +

+

+ Updated At: + {content.updatedAt} +

+

+ Source Language: + {content.sourceLanguage} +

+

+ Review: + {content.reviewState} +

+
+ + {campaign && } +
+
+

Translations

+ {[...content.translations].map((translation) => ( +
+

+ ID: + {translation.id} +

+

+ Model Provider: + {translation.modelProvider || 'N/A'} +

+

+ Language: + {translation.languageCode} +

+

+ Title: + {translation.translatedTitle} +

+

+ Description: + {translation.translatedDescription} +

+

+ Generation Type: + {translation.isAIGenerated ? 'AI Generated' : 'Human Generated'} +

+
+ ))} +
+
+ )} +
+
+ ); }; diff --git a/apps/frontend/src/components/ContentTable/ContentTable.tsx b/apps/frontend/src/components/ContentTable/ContentTable.tsx index 3996b4d..e2be7a3 100644 --- a/apps/frontend/src/components/ContentTable/ContentTable.tsx +++ b/apps/frontend/src/components/ContentTable/ContentTable.tsx @@ -1,5 +1,4 @@ import { Table, TableBody, TableCaption, TableHead, TableHeader, TableRow } from '@/components/ui/table'; - import { useCampaigns } from '../../context/CampaignContext'; import ContentRow from './ContentRow'; @@ -13,15 +12,15 @@ const ContentTable = ({ campaignId }: { campaignId: string }) => { ID - Name - Created At - Updated At - Actions + Updated at + Language + Review + Actions {campaign?.contentPieces.map((content) => ( - + ))}
diff --git a/apps/frontend/src/components/ContentTable/ReviewDialogForms.tsx b/apps/frontend/src/components/ContentTable/ReviewDialogForms.tsx new file mode 100644 index 0000000..087c54a --- /dev/null +++ b/apps/frontend/src/components/ContentTable/ReviewDialogForms.tsx @@ -0,0 +1,165 @@ +import { + LocaleOptions, + ModelProviderOptions, + useGenerationConfig, + type Locale, + type ModelProvider, +} from '@/context/GenerationConfigContext'; +import { Label } from '../ui/label'; +import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from '../ui/select'; + +import { ReviewState, type Campaign, type ContentPiece } from '@/lib/types'; +import { useEffect, useMemo, useState } from 'react'; +import Spinner from '../ui/spinner'; +import { cn } from '@/lib/utils'; +import * as contentPieceAPI from '@/lib/api/contentPiece'; +import { CheckCheck, Trash2 } from 'lucide-react'; + +function ReviewDialogForm({ campaign, content }: { campaign: Campaign; content: ContentPiece }) { + const { locale: defaultLocal, modelProvider: defaultModelProvider } = useGenerationConfig(); + const [locale, setLocale] = useState(defaultLocal); + const [modelProvider, setModelProvider] = useState(defaultModelProvider); + + const [isAIGenerating, setIsAIGenerating] = useState(false); + + const onGenerationRequestSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsAIGenerating(true); + + await contentPieceAPI.generateDraft(campaign.id, locale, modelProvider, content.id); + + setIsAIGenerating(false); + }; + + const [isUpdatingState, setIsUpdatingState] = useState(false); + + const updateState = async (state: 'approved' | 'rejected') => { + setIsUpdatingState(true); + + if (state === 'approved') { + await contentPieceAPI.approve(content.id); + } else if (state === 'rejected') { + await contentPieceAPI.reject(content.id); + } + + setIsUpdatingState(false); + }; + + const canUpdateState = useMemo(() => { + return content.reviewState !== ReviewState.approved && content.reviewState !== ReviewState.rejected; + }, [content.reviewState]); + + useEffect(() => { + if (content.reviewState !== ReviewState.suggested_by_ai) return; + + contentPieceAPI.markAsReviewed(content.id); + }, [content.reviewState]); + + // if content is already approved or rejected, do not show the form + if (!canUpdateState) { + return null; + } + return ( +
+

Do you like the content? Feel free to generate more!

+ +

+ If you choose to generate content in a language that already has a draft, the existing draft will be + overwritten. +

+

+ If you choose to generate content in a language that does not exist yet, a new translation will be created. This + will be a translation of the original content, not a newly generated draft. +

+ +
+
+
+ + +
+ +
+ + +
+
+ + +
+ +
+ + +
+
+ ); +} + +export default ReviewDialogForm; diff --git a/apps/frontend/src/components/layout/Header.tsx b/apps/frontend/src/components/layout/Header.tsx new file mode 100644 index 0000000..e6fc42a --- /dev/null +++ b/apps/frontend/src/components/layout/Header.tsx @@ -0,0 +1,68 @@ +import { + useGenerationConfig, + LocaleOptions, + ModelProviderOptions, + type ModelProvider, + type Locale, +} from '@/context/GenerationConfigContext'; +import { Label } from '../ui/label'; +import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from '../ui/select'; + +function Header() { + const config = useGenerationConfig(); + + return ( +
+

ACME GLOBAL MEDIA

+ +
+
+ + +
+ +
+ + +
+
+
+ ); +} + +export default Header; diff --git a/apps/frontend/src/components/ui/badge.tsx b/apps/frontend/src/components/ui/badge.tsx new file mode 100644 index 0000000..12e7423 --- /dev/null +++ b/apps/frontend/src/components/ui/badge.tsx @@ -0,0 +1,44 @@ +import * as React from 'react'; +import { Slot } from '@radix-ui/react-slot'; +import { cva, type VariantProps } from 'class-variance-authority'; + +import { cn } from '@/lib/utils'; + +const badgeVariants = cva( + 'inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden', + { + variants: { + variant: { + default: 'border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90', + secondary: 'border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90', + destructive: + 'border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60', + outline: 'text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground', + + green: 'border-transparent bg-green-500 text-white [a&]:hover:bg-green-600', + red: 'border-transparent bg-red-500 text-white [a&]:hover:bg-red-600', + blue: 'border-transparent bg-blue-500 text-white [a&]:hover:bg-blue-600', + brown: 'border-transparent bg-yellow-900 text-white [a&]:hover:bg-yellow-950', + yellow: 'border-transparent bg-yellow-500 text-black [a&]:hover:bg-yellow-600', + purple: 'border-transparent bg-purple-500 text-white [a&]:hover:bg-purple-600', + gray: 'border-transparent bg-gray-500 text-white [a&]:hover:bg-gray-600', + }, + }, + defaultVariants: { + variant: 'default', + }, + }, +); + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<'span'> & VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : 'span'; + + return ; +} + +export { Badge, badgeVariants }; diff --git a/apps/frontend/src/components/ui/dialog.tsx b/apps/frontend/src/components/ui/dialog.tsx new file mode 100644 index 0000000..18a4d06 --- /dev/null +++ b/apps/frontend/src/components/ui/dialog.tsx @@ -0,0 +1,121 @@ +import * as React from 'react'; +import * as DialogPrimitive from '@radix-ui/react-dialog'; +import { XIcon } from 'lucide-react'; + +import { cn } from '@/lib/utils'; + +function Dialog({ ...props }: React.ComponentProps) { + return ; +} + +function DialogTrigger({ ...props }: React.ComponentProps) { + return ; +} + +function DialogPortal({ ...props }: React.ComponentProps) { + return ; +} + +function DialogClose({ ...props }: React.ComponentProps) { + return ; +} + +function DialogOverlay({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function DialogContent({ + className, + children, + showCloseButton = true, + ...props +}: React.ComponentProps & { + showCloseButton?: boolean; +}) { + return ( + + + + {children} + {showCloseButton && ( + + + Close + + )} + + + ); +} + +function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function DialogFooter({ className, ...props }: React.ComponentProps<'div'>) { + return ( +
+ ); +} + +function DialogTitle({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function DialogDescription({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogPortal, + DialogTitle, + DialogTrigger, +}; diff --git a/apps/frontend/src/components/ui/input.tsx b/apps/frontend/src/components/ui/input.tsx new file mode 100644 index 0000000..3c1cfca --- /dev/null +++ b/apps/frontend/src/components/ui/input.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; + +import { cn } from '@/lib/utils'; + +function Input({ className, type, ...props }: React.ComponentProps<'input'>) { + return ( + + ); +} + +export { Input }; diff --git a/apps/frontend/src/components/ui/label.tsx b/apps/frontend/src/components/ui/label.tsx new file mode 100644 index 0000000..1756eaf --- /dev/null +++ b/apps/frontend/src/components/ui/label.tsx @@ -0,0 +1,19 @@ +import * as React from 'react'; +import * as LabelPrimitive from '@radix-ui/react-label'; + +import { cn } from '@/lib/utils'; + +function Label({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +export { Label }; diff --git a/apps/frontend/src/components/ui/select.tsx b/apps/frontend/src/components/ui/select.tsx new file mode 100644 index 0000000..9a8469c --- /dev/null +++ b/apps/frontend/src/components/ui/select.tsx @@ -0,0 +1,158 @@ +import * as React from 'react'; +import * as SelectPrimitive from '@radix-ui/react-select'; +import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from 'lucide-react'; + +import { cn } from '@/lib/utils'; + +function Select({ ...props }: React.ComponentProps) { + return ; +} + +function SelectGroup({ ...props }: React.ComponentProps) { + return ; +} + +function SelectValue({ ...props }: React.ComponentProps) { + return ; +} + +function SelectTrigger({ + className, + size = 'default', + children, + ...props +}: React.ComponentProps & { + size?: 'sm' | 'default'; +}) { + return ( + + {children} + + + + + ); +} + +function SelectContent({ + className, + children, + position = 'popper', + ...props +}: React.ComponentProps) { + return ( + + + + + {children} + + + + + ); +} + +function SelectLabel({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function SelectItem({ className, children, ...props }: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function SelectSeparator({ className, ...props }: React.ComponentProps) { + return ( + + ); +} + +function SelectScrollUpButton({ className, ...props }: React.ComponentProps) { + return ( + + + + ); +} + +function SelectScrollDownButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +export { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectScrollDownButton, + SelectScrollUpButton, + SelectSeparator, + SelectTrigger, + SelectValue, +}; diff --git a/apps/frontend/src/components/ui/sonner.tsx b/apps/frontend/src/components/ui/sonner.tsx new file mode 100644 index 0000000..225d010 --- /dev/null +++ b/apps/frontend/src/components/ui/sonner.tsx @@ -0,0 +1,23 @@ +import { useTheme } from 'next-themes'; +import { Toaster as Sonner, type ToasterProps } from 'sonner'; + +const Toaster = ({ ...props }: ToasterProps) => { + const { theme = 'system' } = useTheme(); + + return ( + + ); +}; + +export { Toaster }; diff --git a/apps/frontend/src/components/ui/spinner.tsx b/apps/frontend/src/components/ui/spinner.tsx new file mode 100644 index 0000000..a52d211 --- /dev/null +++ b/apps/frontend/src/components/ui/spinner.tsx @@ -0,0 +1,11 @@ +import { LoaderCircle } from 'lucide-react'; + +function Spinner(props: { color: string; size: number }) { + return ( +
+ +
+ ); +} + +export default Spinner; diff --git a/apps/frontend/src/components/ui/tooltip.tsx b/apps/frontend/src/components/ui/tooltip.tsx index 7aa5589..6724a2a 100644 --- a/apps/frontend/src/components/ui/tooltip.tsx +++ b/apps/frontend/src/components/ui/tooltip.tsx @@ -1,10 +1,11 @@ import * as React from 'react'; import * as TooltipPrimitive from '@radix-ui/react-tooltip'; +import { Provider as TooltipPrimitiveProvider } from '@radix-ui/react-tooltip'; import { cn } from '@/lib/utils'; -function TooltipProvider({ delayDuration = 0, ...props }: React.ComponentProps) { - return ; +function TooltipProvider({ delayDuration = 0, ...props }: React.ComponentProps) { + return ; } function Tooltip({ ...props }: React.ComponentProps) { diff --git a/apps/frontend/src/context/CampaignContext.tsx b/apps/frontend/src/context/CampaignContext.tsx index d008e4a..1b9f878 100644 --- a/apps/frontend/src/context/CampaignContext.tsx +++ b/apps/frontend/src/context/CampaignContext.tsx @@ -1,4 +1,4 @@ -import type { Campaign, Content, ContentTranslation } from '@/lib/types'; +import type { Campaign, ContentPiece, ContentPieceTranslation } from '@/lib/types'; import React, { createContext, use, useState, useMemo, type ReactNode, useEffect } from 'react'; import { gql } from '@apollo/client'; import { client } from '@/lib/apolloClient'; @@ -12,6 +12,10 @@ type CampaignContextType = { // Create the context const CampaignContext = createContext(undefined); +type UpdateInfo = { + [K in keyof T]: T[K]; +} & { _type: 'create' | 'update' | 'remove' }; + // Define the subscription query const CAMPAIGN_GET_ALL_QUERY = gql` query GetCampaigns { @@ -30,6 +34,7 @@ const CAMPAIGN_GET_ALL_QUERY = gql` updatedAt translations { id + modelProvider languageCode translatedTitle translatedDescription @@ -44,13 +49,14 @@ const CAMPAIGN_GET_ALL_QUERY = gql` `; const CAMPAIGN_UPDATED_SUBSCRIPTION = gql` - subscription OnCampaignUpdated { + subscription campaignUpdated { campaignUpdated { id name description createdAt updatedAt + _type contentPieces { id reviewState @@ -60,6 +66,7 @@ const CAMPAIGN_UPDATED_SUBSCRIPTION = gql` updatedAt translations { id + modelProvider languageCode translatedTitle translatedDescription @@ -74,7 +81,7 @@ const CAMPAIGN_UPDATED_SUBSCRIPTION = gql` `; const CONTENT_PIECE_UPDATED_SUBSCRIPTION = gql` - subscription onContentPieceUpdated { + subscription contentPieceUpdated { contentPieceUpdated { id campaignId @@ -83,8 +90,10 @@ const CONTENT_PIECE_UPDATED_SUBSCRIPTION = gql` sourceLanguage createdAt updatedAt + _type translations { id + modelProvider languageCode translatedTitle translatedDescription @@ -98,11 +107,10 @@ const CONTENT_PIECE_UPDATED_SUBSCRIPTION = gql` `; const CONTENT_PIECE_TRANSLATION_UPDATED_SUBSCRIPTION = gql` - subscription onContentPieceTranslationUpdated { + subscription contentPieceTranslationUpdated { contentPieceTranslationUpdated { id - campaignId - contentPieceId + modelProvider languageCode translatedTitle translatedDescription @@ -110,6 +118,10 @@ const CONTENT_PIECE_TRANSLATION_UPDATED_SUBSCRIPTION = gql` isHumanEdited createdAt updatedAt + + _type + campaignId + contentPieceId } } `; @@ -137,7 +149,7 @@ export const CampaignProvider = ({ children }: { children: ReactNode }) => { // Subscribe to campaign updates useEffect(() => { - const campaignObservable = client.subscribe<{ campaignUpdated: Campaign }>({ + const campaignObservable = client.subscribe<{ campaignUpdated: UpdateInfo }>({ query: CAMPAIGN_UPDATED_SUBSCRIPTION, }); const campaignSubscription = campaignObservable.subscribe({ @@ -152,8 +164,7 @@ export const CampaignProvider = ({ children }: { children: ReactNode }) => { return [...prevCampaigns, updatedCampaign]; } const updatedCampaigns = [...prevCampaigns]; - if (updatedCampaigns[index].name === undefined) { - // Remove campaign if name is undefined (indicating deletion) + if (updatedCampaign._type === 'remove') { updatedCampaigns.splice(index, 1); return updatedCampaigns; } @@ -166,7 +177,7 @@ export const CampaignProvider = ({ children }: { children: ReactNode }) => { // Subscribe to content piece updates const contentPieceObservable = client.subscribe<{ - contentPieceUpdated: Content & { campaignId: string }; + contentPieceUpdated: UpdateInfo; }>({ query: CONTENT_PIECE_UPDATED_SUBSCRIPTION, }); @@ -180,21 +191,24 @@ export const CampaignProvider = ({ children }: { children: ReactNode }) => { if (campaignIndex === -1) return prevCampaigns; // Campaign not found const updatedCampaigns = [...prevCampaigns]; - const contentPieces = updatedCampaigns[campaignIndex].contentPieces; + const contentPieces = [...updatedCampaigns[campaignIndex].contentPieces]; const contentIndex = contentPieces.findIndex((cp) => cp.id === updatedContentPiece.id); if (contentIndex === -1) { // Add new content piece contentPieces.push(updatedContentPiece); } else { - if (updatedContentPiece.reviewState === undefined) { - // Remove content piece if reviewState is undefined (indicating deletion) + if (updatedContentPiece._type === 'remove') { contentPieces.splice(contentIndex, 1); } else { // Update existing content piece contentPieces[contentIndex] = updatedContentPiece; } } + updatedCampaigns[campaignIndex] = { + ...updatedCampaigns[campaignIndex], + contentPieces, + }; return updatedCampaigns; }); }, @@ -202,7 +216,9 @@ export const CampaignProvider = ({ children }: { children: ReactNode }) => { // Subscribe to content piece translation updates const contentPieceTranslationObservable = client.subscribe<{ - contentPieceTranslationUpdated: ContentTranslation & { campaignId: string; contentPieceId: string }; + contentPieceTranslationUpdated: UpdateInfo< + ContentPieceTranslation & { campaignId: string; contentPieceId: string } + >; }>({ query: CONTENT_PIECE_TRANSLATION_UPDATED_SUBSCRIPTION, }); @@ -218,23 +234,34 @@ export const CampaignProvider = ({ children }: { children: ReactNode }) => { const updatedCampaigns = [...prevCampaigns]; const contentPieces = updatedCampaigns[campaignIndex].contentPieces; const contentIndex = contentPieces.findIndex((cp) => cp.id === updatedTranslation.contentPieceId); - if (contentIndex === -1) return prevCampaigns; // Content piece not found + if (contentIndex === -1) return prevCampaigns; // ContentPiece piece not found - const translations = contentPieces[contentIndex].translations; + const translations = [...contentPieces[contentIndex].translations]; const translationIndex = translations.findIndex((t) => t.id === updatedTranslation.id); if (translationIndex === -1) { // Add new translation translations.push(updatedTranslation); } else { - if (updatedTranslation.translatedTitle === undefined) { - // Remove translation if translatedTitle is undefined (indicating deletion) + if (updatedTranslation._type === 'remove') { translations.splice(translationIndex, 1); } else { // Update existing translation translations[translationIndex] = updatedTranslation; } } + + updatedCampaigns[campaignIndex] = { + ...updatedCampaigns[campaignIndex], + contentPieces: [ + ...contentPieces.slice(0, contentIndex), + { + ...contentPieces[contentIndex], + translations, + }, + ...contentPieces.slice(contentIndex + 1), + ].sort((a, b) => a.createdAt.localeCompare(b.createdAt)), + }; return updatedCampaigns; }); }, diff --git a/apps/frontend/src/context/GenerationConfigContext.tsx b/apps/frontend/src/context/GenerationConfigContext.tsx new file mode 100644 index 0000000..2e6a957 --- /dev/null +++ b/apps/frontend/src/context/GenerationConfigContext.tsx @@ -0,0 +1,39 @@ +import { createContext, use, useMemo, useState, type ReactNode } from 'react'; + +export const ModelProviderOptions = { + openai: 'OpenAI', + anthropic: 'Anthropic', +}; +export type ModelProvider = keyof typeof ModelProviderOptions; + +export const LocaleOptions = { + 'en-EN': 'English', + 'es-ES': 'Spanish', + 'fr-FR': 'French', +}; +export type Locale = keyof typeof LocaleOptions; + +export interface GenerationConfigContextProps { + locale: Locale; + setLocale: (locale: Locale) => void; + modelProvider: ModelProvider; + setModelProvider: (provider: ModelProvider) => void; +} + +const GenerationConfigContext = createContext(undefined); + +export const GenerationConfigProvider = ({ children }: { children: ReactNode }) => { + const [locale, setLocale] = useState('en-EN'); + const [modelProvider, setModelProvider] = useState('openai'); + + const value = useMemo(() => ({ locale, setLocale, modelProvider, setModelProvider }), [locale, modelProvider]); + return {children}; +}; + +export const useGenerationConfig = () => { + const context = use(GenerationConfigContext); + if (!context) { + throw new Error('useGenerationConfig must be used within a GenerationConfigProvider'); + } + return context; +}; diff --git a/apps/frontend/src/index.css b/apps/frontend/src/index.css index 2ed8446..c6cae5b 100644 --- a/apps/frontend/src/index.css +++ b/apps/frontend/src/index.css @@ -21,8 +21,8 @@ --foreground: oklch(0.145 0 0); --card: oklch(1 0 0); --card-foreground: oklch(0.145 0 0); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); + --popover: oklch(27.503% 0.0185 294.29); + --popover-foreground: oklch(91.279% 0.0001 271.152); --primary: oklch(0.205 0 0); --primary-foreground: oklch(0.985 0 0); --secondary: oklch(0.97 0 0); @@ -32,7 +32,7 @@ --accent: oklch(0.97 0 0); --accent-foreground: oklch(0.205 0 0); --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0 0); + --border: oklch(0.4 0 0); --input: oklch(0.922 0 0); --ring: oklch(0.708 0 0); --chart-1: oklch(0.646 0.222 41.116); diff --git a/apps/frontend/src/lib/api/campaign.ts b/apps/frontend/src/lib/api/campaign.ts new file mode 100644 index 0000000..f177a01 --- /dev/null +++ b/apps/frontend/src/lib/api/campaign.ts @@ -0,0 +1,49 @@ +import type { Campaign } from '../types'; +import { api } from './util'; +import { toast } from 'sonner'; + +export async function create(data: Partial) { + try { + const response = api.post>('/campaigns', data); + + toast.success('Campaign has been created', { + description: new Date().toLocaleString(), + }); + return response; + } catch (error) { + toast.error('Campaign has not been created', { + description: new Date().toLocaleString(), + }); + } +} + +export async function update(campaignId: string, data: Partial) { + try { + const response = api.put>(`/campaigns/${campaignId}`, data); + + toast.success('Campaign has been updated', { + description: new Date().toLocaleString(), + }); + return response; + } catch (error) { + toast.error('Campaign has not been updated', { + description: new Date().toLocaleString(), + }); + return null; + } +} + +export async function remove(campaignId: string) { + try { + const response = await api.delete(`/campaigns/${campaignId}`); + toast.success('Campaign has been deleted', { + description: new Date().toLocaleString(), + }); + return response; + } catch (error) { + toast.error('Campaign has not been deleted', { + description: new Date().toLocaleString(), + }); + return null; + } +} diff --git a/apps/frontend/src/lib/api/contentPiece.ts b/apps/frontend/src/lib/api/contentPiece.ts new file mode 100644 index 0000000..994434a --- /dev/null +++ b/apps/frontend/src/lib/api/contentPiece.ts @@ -0,0 +1,127 @@ +import type { ModelProvider } from '@/context/GenerationConfigContext'; +import type { ContentPiece } from '../types'; +import { api } from './util'; +import { toast } from 'sonner'; + +export async function create(data: ContentPiece) { + try { + const response = await api.post>('/content-pieces', data); + toast.success('Content piece has been created', { + description: new Date().toLocaleString(), + }); + return response; + } catch (error) { + toast.error('Content piece has NOT been created', { + description: new Date().toLocaleString(), + }); + return null; + } +} + +export async function update(contentPieceId: string, data: Partial) { + try { + const response = await api.put>(`/content-pieces/${contentPieceId}`, data); + toast.success('Content piece has been updated', { + description: new Date().toLocaleString(), + }); + return response; + } catch (error) { + toast.error('Content piece has NOT been updated', { + description: new Date().toLocaleString(), + }); + return null; + } +} + +export async function remove(contentPieceId: string) { + try { + const response = await api.delete(`/content-pieces/${contentPieceId}`); + toast.success('Content piece has been deleted', { + description: new Date().toLocaleString(), + }); + return response; + } catch (error) { + toast.error('Content piece has NOT been deleted', { + description: new Date().toLocaleString(), + }); + return null; + } +} + +export async function generateDraft( + campaignId: string, + locale: string, + modelProvider: ModelProvider, + contentId?: string, +) { + try { + const response = await api.post< + ContentPiece, + { + campaignId: string; + locale: string; + modelProvider: ModelProvider; + id?: string; + } + >(`/content-pieces/generate`, { + campaignId, + locale, + modelProvider, + id: contentId, + }); + + toast.success('Content piece draft generated', { + description: new Date().toLocaleString(), + }); + return response; + } catch (error) { + toast.error('Content piece draft generation failed', { + description: new Date().toLocaleString(), + }); + return null; + } +} + +// approve or reject a content piece +export async function approve(contentPieceId: string) { + try { + const response = await api.post(`/content-pieces/${contentPieceId}/approve`, undefined); + toast.success('Content piece has been approved', { + description: new Date().toLocaleString(), + }); + return response; + } catch (error) { + toast.error('Content piece has NOT been approved', { + description: new Date().toLocaleString(), + }); + return null; + } +} + +export async function reject(contentPieceId: string) { + try { + const response = await api.post(`/content-pieces/${contentPieceId}/reject`, undefined); + toast.success('Content piece has been rejected', { + description: new Date().toLocaleString(), + }); + return response; + } catch (error) { + toast.error('Content piece has NOT been rejected', { + description: new Date().toLocaleString(), + }); + return null; + } +} + +// update to reviewed +export async function markAsReviewed(contentPieceId: string) { + try { + const response = await api.post(`/content-pieces/${contentPieceId}/reviewed`, undefined); + return response; + } catch (error) { + toast.error("Content piece has NOT been marked as 'Reviewed'", { + description: new Date().toLocaleString(), + }); + return null; + } +} diff --git a/apps/frontend/src/lib/api/contentPieceTranslation.ts b/apps/frontend/src/lib/api/contentPieceTranslation.ts new file mode 100644 index 0000000..516325d --- /dev/null +++ b/apps/frontend/src/lib/api/contentPieceTranslation.ts @@ -0,0 +1,56 @@ +import type { ContentPieceTranslation } from '../types'; +import { api } from './util'; +import { toast } from 'sonner'; + +export async function create(contentPieceTranslation: ContentPieceTranslation) { + try { + const response = await api.post>( + '/content-piece-translations', + contentPieceTranslation, + ); + toast.success('Content piece translation has been created', { + description: new Date().toLocaleString(), + }); + return response; + } catch (error) { + toast.error('Content piece translation has not been created', { + description: new Date().toLocaleString(), + }); + return null; + } +} + +export async function update(contentPieceTranslationId: string, data: Partial) { + try { + const response = await api.put>( + `/content-piece-translations/${contentPieceTranslationId}`, + data, + ); + toast.success('Content piece translation has been updated', { + description: new Date().toLocaleString(), + }); + return response; + } catch (error) { + toast.error('Content piece translation has not been updated', { + description: new Date().toLocaleString(), + }); + return null; + } +} + +export async function remove(contentPieceTranslationId: string) { + try { + const response = await api.delete( + `/content-piece-translations/${contentPieceTranslationId}`, + ); + toast.success('Content piece translation has been deleted', { + description: new Date().toLocaleString(), + }); + return response; + } catch (error) { + toast.error('Content piece translation has not been deleted', { + description: new Date().toLocaleString(), + }); + return null; + } +} diff --git a/apps/frontend/src/lib/api/util.ts b/apps/frontend/src/lib/api/util.ts new file mode 100644 index 0000000..f636855 --- /dev/null +++ b/apps/frontend/src/lib/api/util.ts @@ -0,0 +1,37 @@ +import { API_BASE_URL } from '@/lib/config'; +import { HttpError } from '@/lib/errors'; + +async function fetchFromAPI(endpoint: string, options: RequestInit = {}): Promise { + const url = `${API_BASE_URL}${endpoint}`; + + const response = await fetch(url, { + ...options, + headers: { + 'Content-Type': 'application/json', + ...(options.headers || {}), + }, + }); + + if (!response.ok) { + const errorBody = await response.json(); + throw new HttpError(response.status, errorBody.message || 'API Error'); + } + + return response.json(); +} + +// Define API methods +export const api = { + get: (endpoint: string) => fetchFromAPI(endpoint, { method: 'GET' }), + post: (endpoint: string, body: U) => + fetchFromAPI(endpoint, { + method: 'POST', + body: JSON.stringify(body), + }), + put: (endpoint: string, body: U) => + fetchFromAPI(endpoint, { + method: 'PUT', + body: JSON.stringify(body), + }), + delete: (endpoint: string) => fetchFromAPI(endpoint, { method: 'DELETE' }), +}; diff --git a/apps/frontend/src/lib/config.ts b/apps/frontend/src/lib/config.ts new file mode 100644 index 0000000..96459fe --- /dev/null +++ b/apps/frontend/src/lib/config.ts @@ -0,0 +1,2 @@ +export const API_BASE_URL: string = import.meta.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3000'; +export const GRAPHQL_BASE_URL: string = import.meta.env.NEXT_PUBLIC_GRAPHQL_BASE_URL || 'ws://localhost:3000/graphql'; diff --git a/apps/frontend/src/lib/errors.ts b/apps/frontend/src/lib/errors.ts new file mode 100644 index 0000000..8e6da3e --- /dev/null +++ b/apps/frontend/src/lib/errors.ts @@ -0,0 +1,9 @@ +export class HttpError extends Error { + public status: number; + + constructor(status: number, message: string) { + super(message); + this.status = status; + this.name = 'HttpError'; + } +} diff --git a/apps/frontend/src/lib/types.ts b/apps/frontend/src/lib/types.ts index d48e112..2637f81 100644 --- a/apps/frontend/src/lib/types.ts +++ b/apps/frontend/src/lib/types.ts @@ -5,19 +5,19 @@ export type Campaign = { createdAt: string; updatedAt: string; - contentPieces: Content[]; + contentPieces: ContentPiece[]; }; export const ReviewState = { - draft: 'draft', - suggested_by_ai: 'suggested_by_ai', - reviewed: 'reviewed', - approved: 'approved', - rejected: 'rejected', + draft: 'Draft', + suggested_by_ai: 'SuggestedByAI', + reviewed: 'Reviewed', + approved: 'Approved', + rejected: 'Rejected', } as const; export type ReviewStateType = (typeof ReviewState)[keyof typeof ReviewState]; -export type Content = { +export type ContentPiece = { id: string; reviewState: ReviewStateType; aiGeneratedDraft?: object; @@ -26,16 +26,17 @@ export type Content = { createdAt: string; updatedAt: string; - translations: ContentTranslation[]; + translations: ContentPieceTranslation[]; }; -export type ContentTranslation = { +export type ContentPieceTranslation = { id: string; languageCode: string; translatedTitle: string; translatedDescription: string; isAIGenerated: boolean; isHumanEdited: boolean; + modelProvider?: string; createdAt: string; updatedAt: string; diff --git a/apps/frontend/src/pages/CampaignCreate.tsx b/apps/frontend/src/pages/CampaignCreate.tsx new file mode 100644 index 0000000..f12dd0c --- /dev/null +++ b/apps/frontend/src/pages/CampaignCreate.tsx @@ -0,0 +1,85 @@ +import Spinner from '@/components/ui/spinner'; +import { ArrowBigLeftDash } from 'lucide-react'; +import { useState } from 'react'; +import { Link, useNavigate } from 'react-router-dom'; +import * as campaignAPI from '@/lib/api/campaign'; +import Header from '@/components/layout/Header'; + +function CampaignCreate() { + const [newCampaignName, setNewCampaignName] = useState(''); + const [newCampaignDescription, setNewCampaignDescription] = useState(''); + const [isLoading, setIsLoading] = useState(false); + + const navigator = useNavigate(); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setIsLoading(true); + + await campaignAPI.create({ + name: newCampaignName, + description: newCampaignDescription, + }); + navigator('/campaigns'); + + setIsLoading(false); + }; + + return ( + <> +
+
+

Create a Campaign

+ +
+ + Back to Campaigns + +
+
+ +
+
+ + setNewCampaignName(e.target.value)} + required + /> +
+ +
+ +