Compare commits

...

8 Commits

Author SHA1 Message Date
SauravDhakal
4686e0abbc feat: ws simple setup only 2026-04-12 21:50:46 +05:45
SauravDhakal
2f01adeade fix: Prisma issue fix + Auth done 2026-04-12 08:06:05 +05:45
SauravDhakal
aa8deadf1f feat: Change auth flow 2026-04-11 07:57:28 +05:45
SauravDhakal
ab8b2ef353 fix: auth otp flow + remove generated 2026-04-05 16:19:19 +05:45
SauravDhakal
4905c6f1d1 fix: Welcome mail send using worker 2026-04-05 12:43:35 +05:45
SauravDhakal
2f30be8c82 fix: Added bullmq 2026-04-04 22:38:09 +05:45
SauravDhakal
f21ee1d131 feat: Event architecture implemented 2026-04-04 20:53:07 +05:45
SauravDhakal
9d931e0d96 fix: Move mail to src/ 2026-04-04 08:27:34 +05:45
58 changed files with 1572 additions and 8642 deletions

5
.gitignore vendored
View File

@@ -55,4 +55,7 @@ pids
# Diagnostic reports (https://nodejs.org/api/report.html) # Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
/generated/prisma prisma/generated
dump.rdb

1
.woodpecker.yml Normal file
View File

@@ -0,0 +1 @@
service:

104
README.md
View File

@@ -1,98 +1,8 @@
<p align="center"> ## Folder Structure
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
</p>
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 /common
[circleci-url]: https://circleci.com/gh/nestjs/nest |-> Common stuff thats shared across
/core
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p> |-> Infra/Setup for core functionality thats also shared
<p align="center"> /src
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a> |-> Modules, that are service specific
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
</p>
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->
## 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 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).

View File

@@ -1,3 +1,141 @@
export const authOTP = (otp: number) => (
`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your Verification Code</title>
<style>
body{
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background:#f4f7fb;
margin:0;
padding:0;
color:#374151;
}
.container{
max-width:600px;
margin:40px auto;
background:#ffffff;
border-radius:10px;
padding:40px;
box-shadow:0 8px 25px rgba(0,0,0,0.05);
}
.logo{
text-align:center;
font-size:24px;
font-weight:700;
color:#2563eb;
margin-bottom:30px;
}
h1{
font-size:22px;
margin-bottom:10px;
color:#111827;
}
p{
font-size:15px;
color:#4b5563;
line-height:1.6;
}
.otp-box{
margin:35px 0;
text-align:center;
}
.otp{
display:inline-block;
font-size:32px;
letter-spacing:8px;
font-weight:700;
background:#f1f5ff;
color:#1d4ed8;
padding:18px 30px;
border-radius:8px;
}
.expiry{
margin-top:12px;
font-size:13px;
color:#6b7280;
}
.warning{
margin-top:20px;
font-size:13px;
color:#6b7280;
background:#f9fafb;
padding:12px;
border-radius:6px;
}
.footer{
text-align:center;
font-size:12px;
color:#9ca3af;
margin-top:35px;
}
.divider{
height:1px;
background:#e5e7eb;
margin:30px 0;
}
</style>
</head>
<body>
<div class="container">
<div class="logo">MultiTenant SaaS</div>
<h1>Your Verification Code</h1>
<p>Hello,</p>
<p>
Use the following One-Time Password (OTP) to continue signing in to your
<strong>MultiTenant SaaS</strong> account.
</p>
<div class="otp-box">
<div class="otp">${otp}</div>
<div class="expiry">This code is valid for <strong>5 minutes</strong> only.</div>
</div>
<p>
Enter this code in the verification screen to complete your login or signup.
</p>
<div class="warning">
For security reasons, never share this code with anyone. Our team will never ask you for your OTP.
</div>
<div class="divider"></div>
<p>
If you did not request this code, you can safely ignore this email.
</p>
<div class="footer">
© 2026 MultiTenant SaaS. All rights reserved.
</div>
</div>
</body>
</html>
`
)
export const welcomeToApp = export const welcomeToApp =
` `
<!DOCTYPE html> <!DOCTYPE html>

View File

@@ -1,7 +1,14 @@
import { welcomeToApp } from "./auth" import { welcomeToApp, authOTP } from "./auth"
const EmailTemplates = { const EmailTemplates = {
welcomeToApp, signup_otp: (otp: number) => ({
subject: "Your MultiTenant SaaS Verification Code",
body: authOTP(otp)
}),
signup_completed: {
subject: "Welcome to app",
body: welcomeToApp
},
} }
export default EmailTemplates export default EmailTemplates

View File

@@ -9,13 +9,14 @@ import { Request, Response } from 'express';
@Catch(HttpException) // What exception to catch @Catch(HttpException) // What exception to catch
export class HttpExceptionFilter implements ExceptionFilter<HttpException> { export class HttpExceptionFilter implements ExceptionFilter<HttpException> {
constructor(private readonly logger: Logger) {} constructor(private readonly logger: Logger) { }
catch(exception: HttpException, host: ArgumentsHost) { catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp(); const ctx = host.switchToHttp();
const request: Request = ctx.getRequest(); const request: Request = ctx.getRequest();
const response: Response = ctx.getResponse(); const response: Response = ctx.getResponse();
const status = exception.getStatus(); const status = exception.getStatus();
if (status >= 500) { if (status >= 500) {
this.logger.warn({ this.logger.warn({
method: request.method, method: request.method,
@@ -28,10 +29,11 @@ export class HttpExceptionFilter implements ExceptionFilter<HttpException> {
exception.message = `${exception.message} not found`; exception.message = `${exception.message} not found`;
} }
response.status(status).json({
success: false, // response.status(status).json({
message: exception.message, // success: false,
statusCode: status, // message: exception.message,
}); // statusCode: status,
// });
} }
} }

View File

@@ -0,0 +1,29 @@
import { Catch, ArgumentsHost } from '@nestjs/common';
import { BaseWsExceptionFilter, WsException } from '@nestjs/websockets';
@Catch()
export class WsValidationExceptionFilter extends BaseWsExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const client = host.switchToWs().getClient();
if (exception instanceof WsException) {
client.emit('exception', {
status: 'error',
message: exception.getError(),
});
return;
}
// Handle ValidationPipe errors (they come as plain objects, not WsException)
if (
Array.isArray((exception as any)?.response?.message)
) {
client.emit('exception', {
status: 'error',
message: (exception as any).response.message,
});
return;
}
super.catch(exception, host);
}
}

View File

@@ -3,3 +3,4 @@ export const ROLE_KEY = '__ROLE_KEY__';
export const ORG_ROLE_KEY = '__ORG_ROLE_KEY__' export const ORG_ROLE_KEY = '__ORG_ROLE_KEY__'
export const ORG_ROLES_ALL_KEY = '__ORG_ROLE_ALL_KEY__'; export const ORG_ROLES_ALL_KEY = '__ORG_ROLE_ALL_KEY__';
export const CAN_PERFORM_KEY = '__CAN_PERFORM_KEY__'; export const CAN_PERFORM_KEY = '__CAN_PERFORM_KEY__';
export const TEMP_TOKEN_KEY = '__TEMP_TOKEN_KEY__';

View File

@@ -1,8 +0,0 @@
import { Module } from "@nestjs/common";
import { MailService } from "./mail.service";
@Module({
providers: [MailService],
exports: [MailService]
})
export class MailModule { }

View File

@@ -10,6 +10,7 @@
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start", "start": "nest start",
"start:dev": "nest start --watch", "start:dev": "nest start --watch",
"dev": "nest start --watch",
"start:debug": "nest start --debug --watch", "start:debug": "nest start --debug --watch",
"start:prod": "node dist/main", "start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
@@ -25,15 +26,20 @@
}, },
"dependencies": { "dependencies": {
"@keyv/redis": "^5.1.6", "@keyv/redis": "^5.1.6",
"@nestjs/bullmq": "^11.0.4",
"@nestjs/cache-manager": "^3.1.0", "@nestjs/cache-manager": "^3.1.0",
"@nestjs/common": "^11.0.1", "@nestjs/common": "^11.0.1",
"@nestjs/core": "^11.0.1", "@nestjs/core": "^11.0.1",
"@nestjs/event-emitter": "^3.0.1",
"@nestjs/jwt": "^11.0.2", "@nestjs/jwt": "^11.0.2",
"@nestjs/platform-express": "^11.0.1", "@nestjs/platform-express": "^11.0.1",
"@nestjs/platform-socket.io": "^11.1.18",
"@nestjs/swagger": "^11.2.6", "@nestjs/swagger": "^11.2.6",
"@nestjs/websockets": "^11.1.18",
"@prisma/adapter-pg": "^7.3.0", "@prisma/adapter-pg": "^7.3.0",
"@prisma/client": "^7.3.0", "@prisma/client": "^7.3.0",
"bcrypt": "^6.0.0", "bcrypt": "^6.0.0",
"bullmq": "^5.73.0",
"cache-manager": "^7.2.8", "cache-manager": "^7.2.8",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.3", "class-validator": "^0.14.3",
@@ -43,6 +49,9 @@
"rxjs": "^7.8.1" "rxjs": "^7.8.1"
}, },
"devDependencies": { "devDependencies": {
"@bull-board/api": "^6.20.6",
"@bull-board/express": "^6.20.6",
"@bull-board/nestjs": "^6.20.6",
"@eslint/eslintrc": "^3.2.0", "@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.18.0", "@eslint/js": "^9.18.0",
"@nestjs/cli": "^11.0.0", "@nestjs/cli": "^11.0.0",

521
pnpm-lock.yaml generated
View File

@@ -11,6 +11,9 @@ importers:
'@keyv/redis': '@keyv/redis':
specifier: ^5.1.6 specifier: ^5.1.6
version: 5.1.6(keyv@5.6.0) version: 5.1.6(keyv@5.6.0)
'@nestjs/bullmq':
specifier: ^11.0.4
version: 11.0.4(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(bullmq@5.73.0)
'@nestjs/cache-manager': '@nestjs/cache-manager':
specifier: ^3.1.0 specifier: ^3.1.0
version: 3.1.0(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(cache-manager@7.2.8)(keyv@5.6.0)(rxjs@7.8.2) version: 3.1.0(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(cache-manager@7.2.8)(keyv@5.6.0)(rxjs@7.8.2)
@@ -19,16 +22,25 @@ importers:
version: 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2) version: 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': '@nestjs/core':
specifier: ^11.0.1 specifier: ^11.0.1
version: 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.2) version: 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(@nestjs/websockets@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/event-emitter':
specifier: ^3.0.1
version: 3.0.1(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)
'@nestjs/jwt': '@nestjs/jwt':
specifier: ^11.0.2 specifier: ^11.0.2
version: 11.0.2(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)) version: 11.0.2(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))
'@nestjs/platform-express': '@nestjs/platform-express':
specifier: ^11.0.1 specifier: ^11.0.1
version: 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13) version: 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)
'@nestjs/platform-socket.io':
specifier: ^11.1.18
version: 11.1.18(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.18)(rxjs@7.8.2)
'@nestjs/swagger': '@nestjs/swagger':
specifier: ^11.2.6 specifier: ^11.2.6
version: 11.2.6(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2) version: 11.2.6(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)
'@nestjs/websockets':
specifier: ^11.1.18
version: 11.1.18(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(@nestjs/platform-socket.io@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@prisma/adapter-pg': '@prisma/adapter-pg':
specifier: ^7.3.0 specifier: ^7.3.0
version: 7.3.0 version: 7.3.0
@@ -38,6 +50,9 @@ importers:
bcrypt: bcrypt:
specifier: ^6.0.0 specifier: ^6.0.0
version: 6.0.0 version: 6.0.0
bullmq:
specifier: ^5.73.0
version: 5.73.0
cache-manager: cache-manager:
specifier: ^7.2.8 specifier: ^7.2.8
version: 7.2.8 version: 7.2.8
@@ -60,6 +75,15 @@ importers:
specifier: ^7.8.1 specifier: ^7.8.1
version: 7.8.2 version: 7.8.2
devDependencies: devDependencies:
'@bull-board/api':
specifier: ^6.20.6
version: 6.20.6(@bull-board/ui@6.20.6)
'@bull-board/express':
specifier: ^6.20.6
version: 6.20.6
'@bull-board/nestjs':
specifier: ^6.20.6
version: 6.20.6(@bull-board/api@6.20.6(@bull-board/ui@6.20.6))(@nestjs/bull-shared@11.0.4(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13))(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@eslint/eslintrc': '@eslint/eslintrc':
specifier: ^3.2.0 specifier: ^3.2.0
version: 3.3.3 version: 3.3.3
@@ -352,6 +376,27 @@ packages:
'@borewit/text-codec@0.2.1': '@borewit/text-codec@0.2.1':
resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==} resolution: {integrity: sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw==}
'@bull-board/api@6.20.6':
resolution: {integrity: sha512-B/9OlKWJ/He421Lyuc7htMpKN4R8hcNu5uoIRiyh9y9J0kMOfxfs82GKXdfR9R0595LvAcCOSvjn8EtWHXesTA==}
peerDependencies:
'@bull-board/ui': 6.20.6
'@bull-board/express@6.20.6':
resolution: {integrity: sha512-QBOjhi3jR4qIJvLCo++DdL0CyG4umiFXBCPJYr74DmRN41m27rDS3NSf7ceHdbQr9Ol8mw3xbVqGLn50x3QdWQ==}
'@bull-board/nestjs@6.20.6':
resolution: {integrity: sha512-jWXvn4cbRwlLlp4/+PIXJniP/blK0Dt8EphmN3k7SPwWG1yQiDGxLVA2ZbynjfwGE/weN73+i4WVR+7IuvK7WA==}
peerDependencies:
'@bull-board/api': ^6.20.6
'@nestjs/bull-shared': ^10.0.0 || ^11.0.0
'@nestjs/common': ^9.0.0 || ^10.0.0 || ^11.0.0
'@nestjs/core': ^9.0.0 || ^10.0.0 || ^11.0.0
reflect-metadata: ^0.1.13 || ^0.2.0
rxjs: ^7.8.1
'@bull-board/ui@6.20.6':
resolution: {integrity: sha512-nEXRgMHHd48ssINgvDqT7b4p/+57XRf3CUcTGQ7UIJb4F7n/kRRj8+ZQvQmMFsYGdNmbNU2eNheQ05vXSYiqdQ==}
'@cacheable/utils@2.3.4': '@cacheable/utils@2.3.4':
resolution: {integrity: sha512-knwKUJEYgIfwShABS1BX6JyJJTglAFcEU7EXqzTdiGCXur4voqkiJkdgZIQtWNFhynzDWERcTYv/sETMu3uJWA==} resolution: {integrity: sha512-knwKUJEYgIfwShABS1BX6JyJJTglAFcEU7EXqzTdiGCXur4voqkiJkdgZIQtWNFhynzDWERcTYv/sETMu3uJWA==}
@@ -592,6 +637,9 @@ packages:
'@types/node': '@types/node':
optional: true optional: true
'@ioredis/commands@1.5.1':
resolution: {integrity: sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==}
'@isaacs/balanced-match@4.0.1': '@isaacs/balanced-match@4.0.1':
resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==}
engines: {node: 20 || >=22} engines: {node: 20 || >=22}
@@ -716,6 +764,36 @@ packages:
resolution: {integrity: sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw==} resolution: {integrity: sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw==}
engines: {node: '>=16'} engines: {node: '>=16'}
'@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==}
cpu: [arm64]
os: [darwin]
'@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3':
resolution: {integrity: sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==}
cpu: [x64]
os: [darwin]
'@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3':
resolution: {integrity: sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==}
cpu: [arm64]
os: [linux]
'@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3':
resolution: {integrity: sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==}
cpu: [arm]
os: [linux]
'@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3':
resolution: {integrity: sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==}
cpu: [x64]
os: [linux]
'@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
resolution: {integrity: sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==}
cpu: [x64]
os: [win32]
'@napi-rs/nice-android-arm-eabi@1.1.1': '@napi-rs/nice-android-arm-eabi@1.1.1':
resolution: {integrity: sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==} resolution: {integrity: sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
@@ -829,6 +907,19 @@ packages:
resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==} resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
'@nestjs/bull-shared@11.0.4':
resolution: {integrity: sha512-VBJcDHSAzxQnpcDfA0kt9MTGUD1XZzfByV70su0W0eDCQ9aqIEBlzWRW21tv9FG9dIut22ysgDidshdjlnczLw==}
peerDependencies:
'@nestjs/common': ^10.0.0 || ^11.0.0
'@nestjs/core': ^10.0.0 || ^11.0.0
'@nestjs/bullmq@11.0.4':
resolution: {integrity: sha512-wBzK9raAVG0/6NTMdvLGM4/FQ1lsB35/pYS8L6a0SDgkTiLpd7mAjQ8R692oMx5s7IjvgntaZOuTUrKYLNfIkA==}
peerDependencies:
'@nestjs/common': ^10.0.0 || ^11.0.0
'@nestjs/core': ^10.0.0 || ^11.0.0
bullmq: ^3.0.0 || ^4.0.0 || ^5.0.0
'@nestjs/cache-manager@3.1.0': '@nestjs/cache-manager@3.1.0':
resolution: {integrity: sha512-pEIqYZrBcE8UdkJmZRduurvoUfdU+3kRPeO1R2muiMbZnRuqlki5klFFNllO9LyYWzrx98bd1j0PSPKSJk1Wbw==} resolution: {integrity: sha512-pEIqYZrBcE8UdkJmZRduurvoUfdU+3kRPeO1R2muiMbZnRuqlki5klFFNllO9LyYWzrx98bd1j0PSPKSJk1Wbw==}
peerDependencies: peerDependencies:
@@ -888,6 +979,12 @@ packages:
'@nestjs/websockets': '@nestjs/websockets':
optional: true optional: true
'@nestjs/event-emitter@3.0.1':
resolution: {integrity: sha512-0Ln/x+7xkU6AJFOcQI9tIhUMXVF7D5itiaQGOyJbXtlAfAIt8gzDdJm+Im7cFzKoWkiW5nCXCPh6GSvdQd/3Dw==}
peerDependencies:
'@nestjs/common': ^10.0.0 || ^11.0.0
'@nestjs/core': ^10.0.0 || ^11.0.0
'@nestjs/jwt@11.0.2': '@nestjs/jwt@11.0.2':
resolution: {integrity: sha512-rK8aE/3/Ma45gAWfCksAXUNbOoSOUudU0Kn3rT39htPF7wsYXtKfjALKeKKJbFrIWbLjsbqfXX5bIJNvgBugGA==} resolution: {integrity: sha512-rK8aE/3/Ma45gAWfCksAXUNbOoSOUudU0Kn3rT39htPF7wsYXtKfjALKeKKJbFrIWbLjsbqfXX5bIJNvgBugGA==}
peerDependencies: peerDependencies:
@@ -912,6 +1009,13 @@ packages:
'@nestjs/common': ^11.0.0 '@nestjs/common': ^11.0.0
'@nestjs/core': ^11.0.0 '@nestjs/core': ^11.0.0
'@nestjs/platform-socket.io@11.1.18':
resolution: {integrity: sha512-DiFRpMIdFaHqZQFwqLqGHMdNurrKVkRkMHxIrecjooPHJNNIMgrbpYZ+oJW8hpwifUyZUL4r4uXXRy4+yFEMjA==}
peerDependencies:
'@nestjs/common': ^11.0.0
'@nestjs/websockets': ^11.0.0
rxjs: ^7.1.0
'@nestjs/schematics@11.0.9': '@nestjs/schematics@11.0.9':
resolution: {integrity: sha512-0NfPbPlEaGwIT8/TCThxLzrlz3yzDNkfRNpbL7FiplKq3w4qXpJg0JYwqgMEJnLQZm3L/L/5XjoyfJHUO3qX9g==} resolution: {integrity: sha512-0NfPbPlEaGwIT8/TCThxLzrlz3yzDNkfRNpbL7FiplKq3w4qXpJg0JYwqgMEJnLQZm3L/L/5XjoyfJHUO3qX9g==}
peerDependencies: peerDependencies:
@@ -947,6 +1051,18 @@ packages:
'@nestjs/platform-express': '@nestjs/platform-express':
optional: true optional: true
'@nestjs/websockets@11.1.18':
resolution: {integrity: sha512-HLO/QGlJoJaMMDphgjbcIwW7/8EA8nnFQjf+qPvA+wWLLfPKoiFPUezc5m9YgN2A7jmzwo6YmEAXeHyqO9tvTw==}
peerDependencies:
'@nestjs/common': ^11.0.0
'@nestjs/core': ^11.0.0
'@nestjs/platform-socket.io': ^11.0.0
reflect-metadata: ^0.1.12 || ^0.2.0
rxjs: ^7.1.0
peerDependenciesMeta:
'@nestjs/platform-socket.io':
optional: true
'@noble/hashes@1.8.0': '@noble/hashes@1.8.0':
resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==}
engines: {node: ^14.21.3 || >=16} engines: {node: ^14.21.3 || >=16}
@@ -1058,6 +1174,9 @@ packages:
'@sinonjs/fake-timers@10.3.0': '@sinonjs/fake-timers@10.3.0':
resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==}
'@socket.io/component-emitter@3.1.2':
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
'@standard-schema/spec@1.1.0': '@standard-schema/spec@1.1.0':
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
@@ -1202,6 +1321,9 @@ packages:
'@types/cookiejar@2.1.5': '@types/cookiejar@2.1.5':
resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==} resolution: {integrity: sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==}
'@types/cors@2.8.19':
resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==}
'@types/eslint-scope@3.7.7': '@types/eslint-scope@3.7.7':
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
@@ -1286,6 +1408,9 @@ packages:
'@types/validator@13.15.10': '@types/validator@13.15.10':
resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==} resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==}
'@types/ws@8.18.1':
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
'@types/yargs-parser@21.0.3': '@types/yargs-parser@21.0.3':
resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
@@ -1442,6 +1567,10 @@ packages:
'@xtuc/long@4.2.2': '@xtuc/long@4.2.2':
resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} 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: accepts@2.0.0:
resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@@ -1547,6 +1676,9 @@ packages:
asap@2.0.6: asap@2.0.6:
resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
async@3.2.6:
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
asynckit@0.4.0: asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
@@ -1601,6 +1733,10 @@ packages:
base64-js@1.5.1: base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
base64id@2.0.0:
resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==}
engines: {node: ^4.5.0 || >= 5.9}
baseline-browser-mapping@2.9.19: baseline-browser-mapping@2.9.19:
resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==}
hasBin: true hasBin: true
@@ -1658,6 +1794,9 @@ packages:
buffer@5.7.1: buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
bullmq@5.73.0:
resolution: {integrity: sha512-uX8RbQaBbzk0H9JYXKGrNxpDqFcDBQFFKCyKarMjtfYHuct5X48M2LUq3Q9FXt/P2kWzPrqYlNnNqsico7ty5A==}
busboy@1.6.0: busboy@1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'} engines: {node: '>=10.16.0'}
@@ -1881,6 +2020,10 @@ packages:
create-require@1.1.1: create-require@1.1.1:
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
cron-parser@4.9.0:
resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==}
engines: {node: '>=12.0.0'}
cross-spawn@7.0.6: cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@@ -1949,6 +2092,10 @@ packages:
destr@2.0.5: destr@2.0.5:
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
detect-newline@3.1.0: detect-newline@3.1.0:
resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -1989,6 +2136,11 @@ packages:
effect@3.18.4: effect@3.18.4:
resolution: {integrity: sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==} resolution: {integrity: sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==}
ejs@3.1.10:
resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==}
engines: {node: '>=0.10.0'}
hasBin: true
electron-to-chromium@1.5.286: electron-to-chromium@1.5.286:
resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==} resolution: {integrity: sha512-9tfDXhJ4RKFNerfjdCcZfufu49vg620741MNs26a9+bhLThdB+plgMeou98CAaHu/WATj2iHOOHTp1hWtABj2A==}
@@ -2007,6 +2159,14 @@ packages:
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
engine.io-parser@5.2.3:
resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==}
engines: {node: '>=10.0.0'}
engine.io@6.6.6:
resolution: {integrity: sha512-U2SN0w3OpjFRVlrc17E6TMDmH58Xl9rai1MblNjAdwWp07Kk+llmzX0hjDpQdrDGzwmvOtgM5yI+meYX6iZ2xA==}
engines: {node: '>=10.2.0'}
enhanced-resolve@5.19.0: enhanced-resolve@5.19.0:
resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
@@ -2127,6 +2287,9 @@ packages:
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
eventemitter2@6.4.9:
resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==}
events-universal@1.0.1: events-universal@1.0.1:
resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==}
@@ -2220,6 +2383,9 @@ packages:
resolution: {integrity: sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==} resolution: {integrity: sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==}
engines: {node: '>=20'} engines: {node: '>=20'}
filelist@1.0.6:
resolution: {integrity: sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==}
filename-reserved-regex@3.0.0: filename-reserved-regex@3.0.0:
resolution: {integrity: sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==} resolution: {integrity: sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -2473,6 +2639,10 @@ packages:
inspect-with-kind@1.0.5: inspect-with-kind@1.0.5:
resolution: {integrity: sha512-MAQUJuIo7Xqk8EVNP+6d3CKq9c80hi4tjIbIAT6lmGW9W6WzlHiu9PS8uSuUYU+Do+j1baiFp3H25XEVxDIG2g==} resolution: {integrity: sha512-MAQUJuIo7Xqk8EVNP+6d3CKq9c80hi4tjIbIAT6lmGW9W6WzlHiu9PS8uSuUYU+Do+j1baiFp3H25XEVxDIG2g==}
ioredis@5.10.1:
resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==}
engines: {node: '>=12.22.0'}
ipaddr.js@1.9.1: ipaddr.js@1.9.1:
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
@@ -2557,6 +2727,11 @@ packages:
resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==}
engines: {node: '>=6'} engines: {node: '>=6'}
jake@10.9.4:
resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==}
engines: {node: '>=10'}
hasBin: true
jest-changed-files@29.7.0: jest-changed-files@29.7.0:
resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -2794,9 +2969,15 @@ packages:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'} engines: {node: '>=10'}
lodash.defaults@4.2.0:
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
lodash.includes@4.3.0: lodash.includes@4.3.0:
resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
lodash.isarguments@3.1.0:
resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
lodash.isboolean@3.0.3: lodash.isboolean@3.0.3:
resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
@@ -2849,6 +3030,10 @@ packages:
resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==}
engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'}
luxon@3.7.2:
resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==}
engines: {node: '>=12'}
magic-string@0.30.17: magic-string@0.30.17:
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
@@ -2937,6 +3122,10 @@ packages:
minimatch@3.1.2: minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
minimatch@5.1.9:
resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==}
engines: {node: '>=10'}
minimatch@9.0.5: minimatch@9.0.5:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
@@ -2955,6 +3144,13 @@ packages:
ms@2.1.3: ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
msgpackr-extract@3.0.3:
resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==}
hasBin: true
msgpackr@1.11.5:
resolution: {integrity: sha512-UjkUHN0yqp9RWKy0Lplhh+wlpdt9oQBYgULZOiFhV3VclSF1JnSQWZ5r9gORQlNYaUKQoR8itv7g7z1xDDuACA==}
multer@2.0.2: multer@2.0.2:
resolution: {integrity: sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==} resolution: {integrity: sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==}
engines: {node: '>= 10.16.0'} engines: {node: '>= 10.16.0'}
@@ -2974,6 +3170,10 @@ packages:
natural-compare@1.4.0: natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
negotiator@0.6.3:
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
engines: {node: '>= 0.6'}
negotiator@1.0.0: negotiator@1.0.0:
resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@@ -2994,6 +3194,10 @@ packages:
node-fetch-native@1.6.7: node-fetch-native@1.6.7:
resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
node-gyp-build-optional-packages@5.2.2:
resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==}
hasBin: true
node-gyp-build@4.8.4: node-gyp-build@4.8.4:
resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
hasBin: true hasBin: true
@@ -3029,6 +3233,10 @@ packages:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
object-hash@3.0.0:
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
engines: {node: '>= 6'}
object-inspect@1.13.4: object-inspect@1.13.4:
resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@@ -3310,6 +3518,17 @@ packages:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'} engines: {node: '>= 14.18.0'}
redis-errors@1.2.0:
resolution: {integrity: sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==}
engines: {node: '>=4'}
redis-info@3.1.0:
resolution: {integrity: sha512-ER4L9Sh/vm63DkIE0bkSjxluQlioBiBgf5w1UuldaW/3vPcecdljVDisZhmnCMvsxHNiARTTDDHGg9cGwTfrKg==}
redis-parser@3.0.0:
resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==}
engines: {node: '>=4'}
reflect-metadata@0.2.2: reflect-metadata@0.2.2:
resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==}
@@ -3473,6 +3692,17 @@ packages:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'} engines: {node: '>=8'}
socket.io-adapter@2.5.6:
resolution: {integrity: sha512-DkkO/dz7MGln0dHn5bmN3pPy+JmywNICWrJqVWiVOyvXjWQFIv9c2h24JrQLLFJ2aQVQf/Cvl1vblnd4r2apLQ==}
socket.io-parser@4.2.6:
resolution: {integrity: sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==}
engines: {node: '>=10.0.0'}
socket.io@4.8.3:
resolution: {integrity: sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==}
engines: {node: '>=10.2.0'}
sort-keys-length@1.0.1: sort-keys-length@1.0.1:
resolution: {integrity: sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==} resolution: {integrity: sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -3514,6 +3744,9 @@ packages:
resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
engines: {node: '>=10'} engines: {node: '>=10'}
standard-as-callback@2.1.0:
resolution: {integrity: sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==}
statuses@2.0.2: statuses@2.0.2:
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@@ -3801,6 +4034,10 @@ packages:
util-deprecate@1.0.2: util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 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: v8-compile-cache-lib@3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
@@ -3879,6 +4116,18 @@ packages:
resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0}
ws@8.18.3:
resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==}
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
xtend@4.0.2: xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'} engines: {node: '>=0.4'}
@@ -4164,6 +4413,33 @@ snapshots:
'@borewit/text-codec@0.2.1': {} '@borewit/text-codec@0.2.1': {}
'@bull-board/api@6.20.6(@bull-board/ui@6.20.6)':
dependencies:
'@bull-board/ui': 6.20.6
redis-info: 3.1.0
'@bull-board/express@6.20.6':
dependencies:
'@bull-board/api': 6.20.6(@bull-board/ui@6.20.6)
'@bull-board/ui': 6.20.6
ejs: 3.1.10
express: 5.2.1
transitivePeerDependencies:
- supports-color
'@bull-board/nestjs@6.20.6(@bull-board/api@6.20.6(@bull-board/ui@6.20.6))(@nestjs/bull-shared@11.0.4(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13))(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.2)':
dependencies:
'@bull-board/api': 6.20.6(@bull-board/ui@6.20.6)
'@nestjs/bull-shared': 11.0.4(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)
'@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(@nestjs/websockets@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)
reflect-metadata: 0.2.2
rxjs: 7.8.2
'@bull-board/ui@6.20.6':
dependencies:
'@bull-board/api': 6.20.6(@bull-board/ui@6.20.6)
'@cacheable/utils@2.3.4': '@cacheable/utils@2.3.4':
dependencies: dependencies:
hashery: 1.5.0 hashery: 1.5.0
@@ -4402,6 +4678,8 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/node': 22.19.10 '@types/node': 22.19.10
'@ioredis/commands@1.5.1': {}
'@isaacs/balanced-match@4.0.1': {} '@isaacs/balanced-match@4.0.1': {}
'@isaacs/brace-expansion@5.0.1': '@isaacs/brace-expansion@5.0.1':
@@ -4629,6 +4907,24 @@ snapshots:
chevrotain: 10.5.0 chevrotain: 10.5.0
lilconfig: 2.1.0 lilconfig: 2.1.0
'@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
optional: true
'@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3':
optional: true
'@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3':
optional: true
'@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3':
optional: true
'@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3':
optional: true
'@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
optional: true
'@napi-rs/nice-android-arm-eabi@1.1.1': '@napi-rs/nice-android-arm-eabi@1.1.1':
optional: true optional: true
@@ -4701,10 +4997,24 @@ snapshots:
'@napi-rs/nice-win32-x64-msvc': 1.1.1 '@napi-rs/nice-win32-x64-msvc': 1.1.1
optional: true optional: true
'@nestjs/bull-shared@11.0.4(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)':
dependencies:
'@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(@nestjs/websockets@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)
tslib: 2.8.1
'@nestjs/bullmq@11.0.4(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(bullmq@5.73.0)':
dependencies:
'@nestjs/bull-shared': 11.0.4(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)
'@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(@nestjs/websockets@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)
bullmq: 5.73.0
tslib: 2.8.1
'@nestjs/cache-manager@3.1.0(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(cache-manager@7.2.8)(keyv@5.6.0)(rxjs@7.8.2)': '@nestjs/cache-manager@3.1.0(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(cache-manager@7.2.8)(keyv@5.6.0)(rxjs@7.8.2)':
dependencies: dependencies:
'@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(@nestjs/websockets@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)
cache-manager: 7.2.8 cache-manager: 7.2.8
keyv: 5.6.0 keyv: 5.6.0
rxjs: 7.8.2 rxjs: 7.8.2
@@ -4761,7 +5071,7 @@ snapshots:
lodash: 4.17.23 lodash: 4.17.23
rxjs: 7.8.2 rxjs: 7.8.2
'@nestjs/core@11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.2)': '@nestjs/core@11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(@nestjs/websockets@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)':
dependencies: dependencies:
'@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nuxt/opencollective': 0.4.1 '@nuxt/opencollective': 0.4.1
@@ -4774,6 +5084,13 @@ snapshots:
uid: 2.0.2 uid: 2.0.2
optionalDependencies: optionalDependencies:
'@nestjs/platform-express': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13) '@nestjs/platform-express': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)
'@nestjs/websockets': 11.1.18(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(@nestjs/platform-socket.io@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/event-emitter@3.0.1(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)':
dependencies:
'@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(@nestjs/websockets@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)
eventemitter2: 6.4.9
'@nestjs/jwt@11.0.2(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))': '@nestjs/jwt@11.0.2(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))':
dependencies: dependencies:
@@ -4792,7 +5109,7 @@ snapshots:
'@nestjs/platform-express@11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)': '@nestjs/platform-express@11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)':
dependencies: dependencies:
'@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(@nestjs/websockets@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)
cors: 2.8.6 cors: 2.8.6
express: 5.2.1 express: 5.2.1
multer: 2.0.2 multer: 2.0.2
@@ -4801,6 +5118,18 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@nestjs/platform-socket.io@11.1.18(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.18)(rxjs@7.8.2)':
dependencies:
'@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/websockets': 11.1.18(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(@nestjs/platform-socket.io@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)
rxjs: 7.8.2
socket.io: 4.8.3
tslib: 2.8.1
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
'@nestjs/schematics@11.0.9(chokidar@4.0.3)(typescript@5.9.3)': '@nestjs/schematics@11.0.9(chokidar@4.0.3)(typescript@5.9.3)':
dependencies: dependencies:
'@angular-devkit/core': 19.2.17(chokidar@4.0.3) '@angular-devkit/core': 19.2.17(chokidar@4.0.3)
@@ -4816,7 +5145,7 @@ snapshots:
dependencies: dependencies:
'@microsoft/tsdoc': 0.16.0 '@microsoft/tsdoc': 0.16.0
'@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(@nestjs/websockets@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/mapped-types': 2.1.0(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2) '@nestjs/mapped-types': 2.1.0(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)
js-yaml: 4.1.1 js-yaml: 4.1.1
lodash: 4.17.23 lodash: 4.17.23
@@ -4830,11 +5159,23 @@ snapshots:
'@nestjs/testing@11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(@nestjs/platform-express@11.1.13)': '@nestjs/testing@11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(@nestjs/platform-express@11.1.13)':
dependencies: dependencies:
'@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.2) '@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(@nestjs/websockets@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)
tslib: 2.8.1 tslib: 2.8.1
optionalDependencies: optionalDependencies:
'@nestjs/platform-express': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13) '@nestjs/platform-express': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)
'@nestjs/websockets@11.1.18(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.13)(@nestjs/platform-socket.io@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)':
dependencies:
'@nestjs/common': 11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2)
'@nestjs/core': 11.1.13(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.13)(@nestjs/websockets@11.1.18)(reflect-metadata@0.2.2)(rxjs@7.8.2)
iterare: 1.2.1
object-hash: 3.0.0
reflect-metadata: 0.2.2
rxjs: 7.8.2
tslib: 2.8.1
optionalDependencies:
'@nestjs/platform-socket.io': 11.1.18(@nestjs/common@11.1.13(class-transformer@0.5.1)(class-validator@0.14.3)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/websockets@11.1.18)(rxjs@7.8.2)
'@noble/hashes@1.8.0': {} '@noble/hashes@1.8.0': {}
'@nodelib/fs.scandir@2.1.5': '@nodelib/fs.scandir@2.1.5':
@@ -4964,6 +5305,8 @@ snapshots:
dependencies: dependencies:
'@sinonjs/commons': 3.0.1 '@sinonjs/commons': 3.0.1
'@socket.io/component-emitter@3.1.2': {}
'@standard-schema/spec@1.1.0': {} '@standard-schema/spec@1.1.0': {}
'@swc/cli@0.6.0(@swc/core@1.15.11)(chokidar@4.0.3)': '@swc/cli@0.6.0(@swc/core@1.15.11)(chokidar@4.0.3)':
@@ -5102,6 +5445,10 @@ snapshots:
'@types/cookiejar@2.1.5': {} '@types/cookiejar@2.1.5': {}
'@types/cors@2.8.19':
dependencies:
'@types/node': 22.19.10
'@types/eslint-scope@3.7.7': '@types/eslint-scope@3.7.7':
dependencies: dependencies:
'@types/eslint': 9.6.1 '@types/eslint': 9.6.1
@@ -5208,6 +5555,10 @@ snapshots:
'@types/validator@13.15.10': {} '@types/validator@13.15.10': {}
'@types/ws@8.18.1':
dependencies:
'@types/node': 22.19.10
'@types/yargs-parser@21.0.3': {} '@types/yargs-parser@21.0.3': {}
'@types/yargs@17.0.35': '@types/yargs@17.0.35':
@@ -5480,6 +5831,11 @@ snapshots:
'@xtuc/long@4.2.2': {} '@xtuc/long@4.2.2': {}
accepts@1.3.8:
dependencies:
mime-types: 2.1.35
negotiator: 0.6.3
accepts@2.0.0: accepts@2.0.0:
dependencies: dependencies:
mime-types: 3.0.2 mime-types: 3.0.2
@@ -5567,6 +5923,8 @@ snapshots:
asap@2.0.6: {} asap@2.0.6: {}
async@3.2.6: {}
asynckit@0.4.0: {} asynckit@0.4.0: {}
aws-ssl-profiles@1.1.2: {} aws-ssl-profiles@1.1.2: {}
@@ -5634,6 +5992,8 @@ snapshots:
base64-js@1.5.1: {} base64-js@1.5.1: {}
base64id@2.0.0: {}
baseline-browser-mapping@2.9.19: {} baseline-browser-mapping@2.9.19: {}
bcrypt@6.0.0: bcrypt@6.0.0:
@@ -5712,6 +6072,18 @@ snapshots:
base64-js: 1.5.1 base64-js: 1.5.1
ieee754: 1.2.1 ieee754: 1.2.1
bullmq@5.73.0:
dependencies:
cron-parser: 4.9.0
ioredis: 5.10.1
msgpackr: 1.11.5
node-abort-controller: 3.1.1
semver: 7.7.4
tslib: 2.8.1
uuid: 11.1.0
transitivePeerDependencies:
- supports-color
busboy@1.6.0: busboy@1.6.0:
dependencies: dependencies:
streamsearch: 1.1.0 streamsearch: 1.1.0
@@ -5926,6 +6298,10 @@ snapshots:
create-require@1.1.1: {} create-require@1.1.1: {}
cron-parser@4.9.0:
dependencies:
luxon: 3.7.2
cross-spawn@7.0.6: cross-spawn@7.0.6:
dependencies: dependencies:
path-key: 3.1.1 path-key: 3.1.1
@@ -5968,6 +6344,9 @@ snapshots:
destr@2.0.5: {} destr@2.0.5: {}
detect-libc@2.1.2:
optional: true
detect-newline@3.1.0: {} detect-newline@3.1.0: {}
dezalgo@1.0.4: dezalgo@1.0.4:
@@ -6004,6 +6383,10 @@ snapshots:
'@standard-schema/spec': 1.1.0 '@standard-schema/spec': 1.1.0
fast-check: 3.23.2 fast-check: 3.23.2
ejs@3.1.10:
dependencies:
jake: 10.9.4
electron-to-chromium@1.5.286: {} electron-to-chromium@1.5.286: {}
emittery@0.13.1: {} emittery@0.13.1: {}
@@ -6014,6 +6397,25 @@ snapshots:
encodeurl@2.0.0: {} encodeurl@2.0.0: {}
engine.io-parser@5.2.3: {}
engine.io@6.6.6:
dependencies:
'@types/cors': 2.8.19
'@types/node': 22.19.10
'@types/ws': 8.18.1
accepts: 1.3.8
base64id: 2.0.0
cookie: 0.7.2
cors: 2.8.6
debug: 4.4.3
engine.io-parser: 5.2.3
ws: 8.18.3
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
enhanced-resolve@5.19.0: enhanced-resolve@5.19.0:
dependencies: dependencies:
graceful-fs: 4.2.11 graceful-fs: 4.2.11
@@ -6141,6 +6543,8 @@ snapshots:
etag@1.8.1: {} etag@1.8.1: {}
eventemitter2@6.4.9: {}
events-universal@1.0.1: events-universal@1.0.1:
dependencies: dependencies:
bare-events: 2.8.2 bare-events: 2.8.2
@@ -6277,6 +6681,10 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
filelist@1.0.6:
dependencies:
minimatch: 5.1.9
filename-reserved-regex@3.0.0: {} filename-reserved-regex@3.0.0: {}
filenamify@6.0.0: filenamify@6.0.0:
@@ -6551,6 +6959,20 @@ snapshots:
dependencies: dependencies:
kind-of: 6.0.3 kind-of: 6.0.3
ioredis@5.10.1:
dependencies:
'@ioredis/commands': 1.5.1
cluster-key-slot: 1.1.2
debug: 4.4.3
denque: 2.1.0
lodash.defaults: 4.2.0
lodash.isarguments: 3.1.0
redis-errors: 1.2.0
redis-parser: 3.0.0
standard-as-callback: 2.1.0
transitivePeerDependencies:
- supports-color
ipaddr.js@1.9.1: {} ipaddr.js@1.9.1: {}
is-arrayish@0.2.1: {} is-arrayish@0.2.1: {}
@@ -6628,6 +7050,12 @@ snapshots:
iterare@1.2.1: {} iterare@1.2.1: {}
jake@10.9.4:
dependencies:
async: 3.2.6
filelist: 1.0.6
picocolors: 1.1.1
jest-changed-files@29.7.0: jest-changed-files@29.7.0:
dependencies: dependencies:
execa: 5.1.1 execa: 5.1.1
@@ -7039,8 +7467,12 @@ snapshots:
dependencies: dependencies:
p-locate: 5.0.0 p-locate: 5.0.0
lodash.defaults@4.2.0: {}
lodash.includes@4.3.0: {} lodash.includes@4.3.0: {}
lodash.isarguments@3.1.0: {}
lodash.isboolean@3.0.3: {} lodash.isboolean@3.0.3: {}
lodash.isinteger@4.0.4: {} lodash.isinteger@4.0.4: {}
@@ -7078,6 +7510,8 @@ snapshots:
lru.min@1.1.4: {} lru.min@1.1.4: {}
luxon@3.7.2: {}
magic-string@0.30.17: magic-string@0.30.17:
dependencies: dependencies:
'@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/sourcemap-codec': 1.5.5
@@ -7143,6 +7577,10 @@ snapshots:
dependencies: dependencies:
brace-expansion: 1.1.12 brace-expansion: 1.1.12
minimatch@5.1.9:
dependencies:
brace-expansion: 2.0.2
minimatch@9.0.5: minimatch@9.0.5:
dependencies: dependencies:
brace-expansion: 2.0.2 brace-expansion: 2.0.2
@@ -7157,6 +7595,22 @@ snapshots:
ms@2.1.3: {} ms@2.1.3: {}
msgpackr-extract@3.0.3:
dependencies:
node-gyp-build-optional-packages: 5.2.2
optionalDependencies:
'@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.3
'@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.3
'@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.3
'@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.3
'@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.3
'@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3
optional: true
msgpackr@1.11.5:
optionalDependencies:
msgpackr-extract: 3.0.3
multer@2.0.2: multer@2.0.2:
dependencies: dependencies:
append-field: 1.0.0 append-field: 1.0.0
@@ -7187,6 +7641,8 @@ snapshots:
natural-compare@1.4.0: {} natural-compare@1.4.0: {}
negotiator@0.6.3: {}
negotiator@1.0.0: {} negotiator@1.0.0: {}
neo-async@2.6.2: {} neo-async@2.6.2: {}
@@ -7201,6 +7657,11 @@ snapshots:
node-fetch-native@1.6.7: {} node-fetch-native@1.6.7: {}
node-gyp-build-optional-packages@5.2.2:
dependencies:
detect-libc: 2.1.2
optional: true
node-gyp-build@4.8.4: {} node-gyp-build@4.8.4: {}
node-int64@0.4.0: {} node-int64@0.4.0: {}
@@ -7225,6 +7686,8 @@ snapshots:
object-assign@4.1.1: {} object-assign@4.1.1: {}
object-hash@3.0.0: {}
object-inspect@1.13.4: {} object-inspect@1.13.4: {}
ohash@2.0.11: {} ohash@2.0.11: {}
@@ -7486,6 +7949,16 @@ snapshots:
readdirp@4.1.2: {} readdirp@4.1.2: {}
redis-errors@1.2.0: {}
redis-info@3.1.0:
dependencies:
lodash: 4.17.23
redis-parser@3.0.0:
dependencies:
redis-errors: 1.2.0
reflect-metadata@0.2.2: {} reflect-metadata@0.2.2: {}
regexp-to-ast@0.5.0: {} regexp-to-ast@0.5.0: {}
@@ -7657,6 +8130,36 @@ snapshots:
slash@3.0.0: {} slash@3.0.0: {}
socket.io-adapter@2.5.6:
dependencies:
debug: 4.4.3
ws: 8.18.3
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
socket.io-parser@4.2.6:
dependencies:
'@socket.io/component-emitter': 3.1.2
debug: 4.4.3
transitivePeerDependencies:
- supports-color
socket.io@4.8.3:
dependencies:
accepts: 1.3.8
base64id: 2.0.0
cors: 2.8.6
debug: 4.4.3
engine.io: 6.6.6
socket.io-adapter: 2.5.6
socket.io-parser: 4.2.6
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
sort-keys-length@1.0.1: sort-keys-length@1.0.1:
dependencies: dependencies:
sort-keys: 1.1.2 sort-keys: 1.1.2
@@ -7691,6 +8194,8 @@ snapshots:
dependencies: dependencies:
escape-string-regexp: 2.0.0 escape-string-regexp: 2.0.0
standard-as-callback@2.1.0: {}
statuses@2.0.2: {} statuses@2.0.2: {}
std-env@3.10.0: {} std-env@3.10.0: {}
@@ -7985,6 +8490,8 @@ snapshots:
util-deprecate@1.0.2: {} util-deprecate@1.0.2: {}
uuid@11.1.0: {}
v8-compile-cache-lib@3.0.1: {} v8-compile-cache-lib@3.0.1: {}
v8-to-istanbul@9.3.0: v8-to-istanbul@9.3.0:
@@ -8077,6 +8584,8 @@ snapshots:
imurmurhash: 0.1.4 imurmurhash: 0.1.4
signal-exit: 3.0.7 signal-exit: 3.0.7
ws@8.18.3: {}
xtend@4.0.2: {} xtend@4.0.2: {}
y18n@5.0.8: {} y18n@5.0.8: {}

View File

@@ -1,39 +0,0 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
// @ts-nocheck
/*
* This file should be your main import to use Prisma-related types and utilities in a browser.
* Use it to get access to models, enums, and input types.
*
* This file does not contain a `PrismaClient` class, nor several other helpers that are intended as server-side only.
* See `client.ts` for the standard, server-side entry point.
*
* 🟢 You can import this file directly.
*/
import * as Prisma from './internal/prismaNamespaceBrowser'
export { Prisma }
export * as $Enums from './enums'
export * from './enums';
/**
* Model OrganizationJoinRequest
*
*/
export type OrganizationJoinRequest = Prisma.OrganizationJoinRequestModel
/**
* Model OrganizationUserJoinTable
*
*/
export type OrganizationUserJoinTable = Prisma.OrganizationUserJoinTableModel
/**
* Model Organization
*
*/
export type Organization = Prisma.OrganizationModel
/**
* Model User
*
*/
export type User = Prisma.UserModel

View File

@@ -1,59 +0,0 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
// @ts-nocheck
/*
* This file should be your main import to use Prisma. Through it you get access to all the models, enums, and input types.
* If you're looking for something you can import in the client-side of your application, please refer to the `browser.ts` file instead.
*
* 🟢 You can import this file directly.
*/
import * as process from 'node:process'
import * as path from 'node:path'
import * as runtime from "@prisma/client/runtime/client"
import * as $Enums from "./enums"
import * as $Class from "./internal/class"
import * as Prisma from "./internal/prismaNamespace"
export * as $Enums from './enums'
export * from "./enums"
/**
* ## Prisma Client
*
* Type-safe database client for TypeScript
* @example
* ```
* const prisma = new PrismaClient()
* // Fetch zero or more OrganizationJoinRequests
* const organizationJoinRequests = await prisma.organizationJoinRequest.findMany()
* ```
*
* Read more in our [docs](https://pris.ly/d/client).
*/
export const PrismaClient = $Class.getPrismaClientClass()
export type PrismaClient<LogOpts extends Prisma.LogLevel = never, OmitOpts extends Prisma.PrismaClientOptions["omit"] = Prisma.PrismaClientOptions["omit"], ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = $Class.PrismaClient<LogOpts, OmitOpts, ExtArgs>
export { Prisma }
/**
* Model OrganizationJoinRequest
*
*/
export type OrganizationJoinRequest = Prisma.OrganizationJoinRequestModel
/**
* Model OrganizationUserJoinTable
*
*/
export type OrganizationUserJoinTable = Prisma.OrganizationUserJoinTableModel
/**
* Model Organization
*
*/
export type Organization = Prisma.OrganizationModel
/**
* Model User
*
*/
export type User = Prisma.UserModel

View File

@@ -1,434 +0,0 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
// @ts-nocheck
/*
* This file exports various common sort, input & filter types that are not directly linked to a particular model.
*
* 🟢 You can import this file directly.
*/
import type * as runtime from "@prisma/client/runtime/client"
import * as $Enums from "./enums"
import type * as Prisma from "./internal/prismaNamespace"
export type StringFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
mode?: Prisma.QueryMode
not?: Prisma.NestedStringFilter<$PrismaModel> | string
}
export type EnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel = never> = {
equals?: $Enums.ORGANIZATION_JOIN_REQUEST | Prisma.EnumORGANIZATION_JOIN_REQUESTFieldRefInput<$PrismaModel>
in?: $Enums.ORGANIZATION_JOIN_REQUEST[] | Prisma.ListEnumORGANIZATION_JOIN_REQUESTFieldRefInput<$PrismaModel>
notIn?: $Enums.ORGANIZATION_JOIN_REQUEST[] | Prisma.ListEnumORGANIZATION_JOIN_REQUESTFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST
}
export type EnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel = never> = {
equals?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE | Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
in?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
notIn?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
}
export type DateTimeFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeFilter<$PrismaModel> | Date | string
}
export type EnumORG_ROLEFilter<$PrismaModel = never> = {
equals?: $Enums.ORG_ROLE | Prisma.EnumORG_ROLEFieldRefInput<$PrismaModel>
in?: $Enums.ORG_ROLE[] | Prisma.ListEnumORG_ROLEFieldRefInput<$PrismaModel>
notIn?: $Enums.ORG_ROLE[] | Prisma.ListEnumORG_ROLEFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumORG_ROLEFilter<$PrismaModel> | $Enums.ORG_ROLE
}
export type StringNullableFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
mode?: Prisma.QueryMode
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
}
export type SortOrderInput = {
sort: Prisma.SortOrder
nulls?: Prisma.NullsOrder
}
export type StringWithAggregatesFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
mode?: Prisma.QueryMode
not?: Prisma.NestedStringWithAggregatesFilter<$PrismaModel> | string
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedStringFilter<$PrismaModel>
_max?: Prisma.NestedStringFilter<$PrismaModel>
}
export type EnumORGANIZATION_JOIN_REQUESTWithAggregatesFilter<$PrismaModel = never> = {
equals?: $Enums.ORGANIZATION_JOIN_REQUEST | Prisma.EnumORGANIZATION_JOIN_REQUESTFieldRefInput<$PrismaModel>
in?: $Enums.ORGANIZATION_JOIN_REQUEST[] | Prisma.ListEnumORGANIZATION_JOIN_REQUESTFieldRefInput<$PrismaModel>
notIn?: $Enums.ORGANIZATION_JOIN_REQUEST[] | Prisma.ListEnumORGANIZATION_JOIN_REQUESTFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUESTWithAggregatesFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedEnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel>
_max?: Prisma.NestedEnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel>
}
export type EnumORGANIZATION_JOIN_REQUEST_TYPEWithAggregatesFilter<$PrismaModel = never> = {
equals?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE | Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
in?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
notIn?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEWithAggregatesFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel>
_max?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel>
}
export type DateTimeWithAggregatesFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedDateTimeFilter<$PrismaModel>
_max?: Prisma.NestedDateTimeFilter<$PrismaModel>
}
export type EnumORG_ROLEWithAggregatesFilter<$PrismaModel = never> = {
equals?: $Enums.ORG_ROLE | Prisma.EnumORG_ROLEFieldRefInput<$PrismaModel>
in?: $Enums.ORG_ROLE[] | Prisma.ListEnumORG_ROLEFieldRefInput<$PrismaModel>
notIn?: $Enums.ORG_ROLE[] | Prisma.ListEnumORG_ROLEFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumORG_ROLEWithAggregatesFilter<$PrismaModel> | $Enums.ORG_ROLE
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedEnumORG_ROLEFilter<$PrismaModel>
_max?: Prisma.NestedEnumORG_ROLEFilter<$PrismaModel>
}
export type StringNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
mode?: Prisma.QueryMode
not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedStringNullableFilter<$PrismaModel>
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
}
export type EnumUSER_ROLEFilter<$PrismaModel = never> = {
equals?: $Enums.USER_ROLE | Prisma.EnumUSER_ROLEFieldRefInput<$PrismaModel>
in?: $Enums.USER_ROLE[] | Prisma.ListEnumUSER_ROLEFieldRefInput<$PrismaModel>
notIn?: $Enums.USER_ROLE[] | Prisma.ListEnumUSER_ROLEFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumUSER_ROLEFilter<$PrismaModel> | $Enums.USER_ROLE
}
export type BoolNullableFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> | null
not?: Prisma.NestedBoolNullableFilter<$PrismaModel> | boolean | null
}
export type DateTimeNullableFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null
}
export type EnumUSER_ROLEWithAggregatesFilter<$PrismaModel = never> = {
equals?: $Enums.USER_ROLE | Prisma.EnumUSER_ROLEFieldRefInput<$PrismaModel>
in?: $Enums.USER_ROLE[] | Prisma.ListEnumUSER_ROLEFieldRefInput<$PrismaModel>
notIn?: $Enums.USER_ROLE[] | Prisma.ListEnumUSER_ROLEFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumUSER_ROLEWithAggregatesFilter<$PrismaModel> | $Enums.USER_ROLE
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedEnumUSER_ROLEFilter<$PrismaModel>
_max?: Prisma.NestedEnumUSER_ROLEFilter<$PrismaModel>
}
export type BoolNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> | null
not?: Prisma.NestedBoolNullableWithAggregatesFilter<$PrismaModel> | boolean | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedBoolNullableFilter<$PrismaModel>
_max?: Prisma.NestedBoolNullableFilter<$PrismaModel>
}
export type DateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
}
export type NestedStringFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
not?: Prisma.NestedStringFilter<$PrismaModel> | string
}
export type NestedEnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel = never> = {
equals?: $Enums.ORGANIZATION_JOIN_REQUEST | Prisma.EnumORGANIZATION_JOIN_REQUESTFieldRefInput<$PrismaModel>
in?: $Enums.ORGANIZATION_JOIN_REQUEST[] | Prisma.ListEnumORGANIZATION_JOIN_REQUESTFieldRefInput<$PrismaModel>
notIn?: $Enums.ORGANIZATION_JOIN_REQUEST[] | Prisma.ListEnumORGANIZATION_JOIN_REQUESTFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST
}
export type NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel = never> = {
equals?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE | Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
in?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
notIn?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
}
export type NestedDateTimeFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeFilter<$PrismaModel> | Date | string
}
export type NestedEnumORG_ROLEFilter<$PrismaModel = never> = {
equals?: $Enums.ORG_ROLE | Prisma.EnumORG_ROLEFieldRefInput<$PrismaModel>
in?: $Enums.ORG_ROLE[] | Prisma.ListEnumORG_ROLEFieldRefInput<$PrismaModel>
notIn?: $Enums.ORG_ROLE[] | Prisma.ListEnumORG_ROLEFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumORG_ROLEFilter<$PrismaModel> | $Enums.ORG_ROLE
}
export type NestedStringNullableFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
not?: Prisma.NestedStringNullableFilter<$PrismaModel> | string | null
}
export type NestedStringWithAggregatesFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
not?: Prisma.NestedStringWithAggregatesFilter<$PrismaModel> | string
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedStringFilter<$PrismaModel>
_max?: Prisma.NestedStringFilter<$PrismaModel>
}
export type NestedIntFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
not?: Prisma.NestedIntFilter<$PrismaModel> | number
}
export type NestedEnumORGANIZATION_JOIN_REQUESTWithAggregatesFilter<$PrismaModel = never> = {
equals?: $Enums.ORGANIZATION_JOIN_REQUEST | Prisma.EnumORGANIZATION_JOIN_REQUESTFieldRefInput<$PrismaModel>
in?: $Enums.ORGANIZATION_JOIN_REQUEST[] | Prisma.ListEnumORGANIZATION_JOIN_REQUESTFieldRefInput<$PrismaModel>
notIn?: $Enums.ORGANIZATION_JOIN_REQUEST[] | Prisma.ListEnumORGANIZATION_JOIN_REQUESTFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUESTWithAggregatesFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedEnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel>
_max?: Prisma.NestedEnumORGANIZATION_JOIN_REQUESTFilter<$PrismaModel>
}
export type NestedEnumORGANIZATION_JOIN_REQUEST_TYPEWithAggregatesFilter<$PrismaModel = never> = {
equals?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE | Prisma.EnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
in?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
notIn?: $Enums.ORGANIZATION_JOIN_REQUEST_TYPE[] | Prisma.ListEnumORGANIZATION_JOIN_REQUEST_TYPEFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEWithAggregatesFilter<$PrismaModel> | $Enums.ORGANIZATION_JOIN_REQUEST_TYPE
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel>
_max?: Prisma.NestedEnumORGANIZATION_JOIN_REQUEST_TYPEFilter<$PrismaModel>
}
export type NestedDateTimeWithAggregatesFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel>
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeWithAggregatesFilter<$PrismaModel> | Date | string
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedDateTimeFilter<$PrismaModel>
_max?: Prisma.NestedDateTimeFilter<$PrismaModel>
}
export type NestedEnumORG_ROLEWithAggregatesFilter<$PrismaModel = never> = {
equals?: $Enums.ORG_ROLE | Prisma.EnumORG_ROLEFieldRefInput<$PrismaModel>
in?: $Enums.ORG_ROLE[] | Prisma.ListEnumORG_ROLEFieldRefInput<$PrismaModel>
notIn?: $Enums.ORG_ROLE[] | Prisma.ListEnumORG_ROLEFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumORG_ROLEWithAggregatesFilter<$PrismaModel> | $Enums.ORG_ROLE
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedEnumORG_ROLEFilter<$PrismaModel>
_max?: Prisma.NestedEnumORG_ROLEFilter<$PrismaModel>
}
export type NestedStringNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: string | Prisma.StringFieldRefInput<$PrismaModel> | null
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel> | null
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
not?: Prisma.NestedStringNullableWithAggregatesFilter<$PrismaModel> | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedStringNullableFilter<$PrismaModel>
_max?: Prisma.NestedStringNullableFilter<$PrismaModel>
}
export type NestedIntNullableFilter<$PrismaModel = never> = {
equals?: number | Prisma.IntFieldRefInput<$PrismaModel> | null
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel> | null
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
not?: Prisma.NestedIntNullableFilter<$PrismaModel> | number | null
}
export type NestedEnumUSER_ROLEFilter<$PrismaModel = never> = {
equals?: $Enums.USER_ROLE | Prisma.EnumUSER_ROLEFieldRefInput<$PrismaModel>
in?: $Enums.USER_ROLE[] | Prisma.ListEnumUSER_ROLEFieldRefInput<$PrismaModel>
notIn?: $Enums.USER_ROLE[] | Prisma.ListEnumUSER_ROLEFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumUSER_ROLEFilter<$PrismaModel> | $Enums.USER_ROLE
}
export type NestedBoolNullableFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> | null
not?: Prisma.NestedBoolNullableFilter<$PrismaModel> | boolean | null
}
export type NestedDateTimeNullableFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeNullableFilter<$PrismaModel> | Date | string | null
}
export type NestedEnumUSER_ROLEWithAggregatesFilter<$PrismaModel = never> = {
equals?: $Enums.USER_ROLE | Prisma.EnumUSER_ROLEFieldRefInput<$PrismaModel>
in?: $Enums.USER_ROLE[] | Prisma.ListEnumUSER_ROLEFieldRefInput<$PrismaModel>
notIn?: $Enums.USER_ROLE[] | Prisma.ListEnumUSER_ROLEFieldRefInput<$PrismaModel>
not?: Prisma.NestedEnumUSER_ROLEWithAggregatesFilter<$PrismaModel> | $Enums.USER_ROLE
_count?: Prisma.NestedIntFilter<$PrismaModel>
_min?: Prisma.NestedEnumUSER_ROLEFilter<$PrismaModel>
_max?: Prisma.NestedEnumUSER_ROLEFilter<$PrismaModel>
}
export type NestedBoolNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel> | null
not?: Prisma.NestedBoolNullableWithAggregatesFilter<$PrismaModel> | boolean | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedBoolNullableFilter<$PrismaModel>
_max?: Prisma.NestedBoolNullableFilter<$PrismaModel>
}
export type NestedDateTimeNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel> | null
in?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
notIn?: Date[] | string[] | Prisma.ListDateTimeFieldRefInput<$PrismaModel> | null
lt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
lte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gt?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
gte?: Date | string | Prisma.DateTimeFieldRefInput<$PrismaModel>
not?: Prisma.NestedDateTimeNullableWithAggregatesFilter<$PrismaModel> | Date | string | null
_count?: Prisma.NestedIntNullableFilter<$PrismaModel>
_min?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
_max?: Prisma.NestedDateTimeNullableFilter<$PrismaModel>
}

View File

@@ -1,44 +0,0 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
// @ts-nocheck
/*
* This file exports all enum related types from the schema.
*
* 🟢 You can import this file directly.
*/
export const ORGANIZATION_JOIN_REQUEST = {
PENDING: 'PENDING',
ACCEPTED: 'ACCEPTED',
REJECTED: 'REJECTED',
CANCELLED: 'CANCELLED'
} as const
export type ORGANIZATION_JOIN_REQUEST = (typeof ORGANIZATION_JOIN_REQUEST)[keyof typeof ORGANIZATION_JOIN_REQUEST]
export const ORGANIZATION_JOIN_REQUEST_TYPE = {
INVITED: 'INVITED',
REQUESTED: 'REQUESTED'
} as const
export type ORGANIZATION_JOIN_REQUEST_TYPE = (typeof ORGANIZATION_JOIN_REQUEST_TYPE)[keyof typeof ORGANIZATION_JOIN_REQUEST_TYPE]
export const ORG_ROLE = {
owner: 'owner',
admin: 'admin',
member: 'member'
} as const
export type ORG_ROLE = (typeof ORG_ROLE)[keyof typeof ORG_ROLE]
export const USER_ROLE = {
superadmin: 'superadmin',
user: 'user'
} as const
export type USER_ROLE = (typeof USER_ROLE)[keyof typeof USER_ROLE]

View File

@@ -1,222 +0,0 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
// @ts-nocheck
/*
* WARNING: This is an internal file that is subject to change!
*
* 🛑 Under no circumstances should you import this file directly! 🛑
*
* Please import the `PrismaClient` class from the `client.ts` file instead.
*/
import * as runtime from "@prisma/client/runtime/client"
import type * as Prisma from "./prismaNamespace"
const config: runtime.GetPrismaClientConfig = {
"previewFeatures": [],
"clientVersion": "7.3.0",
"engineVersion": "9d6ad21cbbceab97458517b147a6a09ff43aa735",
"activeProvider": "postgresql",
"inlineSchema": "model OrganizationJoinRequest {\n id String @id @default(uuid())\n userId String\n orgId String\n status ORGANIZATION_JOIN_REQUEST @default(PENDING)\n requestType ORGANIZATION_JOIN_REQUEST_TYPE\n requestedOn DateTime @default(now())\n role ORG_ROLE @default(member)\n updatedAt DateTime @updatedAt\n rejectReason String?\n requestMessage String?\n\n organization Organization @relation(fields: [orgId], references: [id], onDelete: Cascade)\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n // @@unique([userId, orgId])\n @@index([userId, orgId])\n @@map(\"organization_join_request\")\n}\n\nenum ORGANIZATION_JOIN_REQUEST {\n PENDING\n ACCEPTED\n REJECTED\n CANCELLED\n}\n\nenum ORGANIZATION_JOIN_REQUEST_TYPE {\n INVITED\n REQUESTED\n}\n\nmodel OrganizationUserJoinTable {\n userId String\n orgId String\n role ORG_ROLE @default(member)\n joinedDate DateTime @default(now())\n\n organization Organization @relation(fields: [orgId], references: [id], onDelete: Restrict)\n user User @relation(fields: [userId], references: [id], onDelete: Cascade)\n\n @@unique([userId, orgId])\n @@map(\"organization_user_join\")\n}\n\nenum ORG_ROLE {\n owner\n admin\n member\n}\n\nmodel Organization {\n id String @id @default(uuid())\n name String\n description String?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n members OrganizationUserJoinTable[]\n requestingMembers OrganizationJoinRequest[]\n\n @@map(\"organization\")\n}\n\n// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n output = \"../generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nmodel User {\n id String @id @default(uuid())\n firstName String\n middleName String?\n lastName String\n email String @unique\n password String\n role USER_ROLE @default(user)\n isVerified Boolean? @default(false) // TODO: Email using queue\n refreshToken String?\n profilePicture String?\n isDeleted Boolean? @default(false)\n deletedAt DateTime?\n\n createdAt DateTime @default(now())\n updatedAt DateTime @updatedAt\n\n organizations OrganizationUserJoinTable[]\n organizationsRequested OrganizationJoinRequest[]\n\n @@map(\"user\")\n}\n\nenum USER_ROLE {\n superadmin\n user\n}\n",
"runtimeDataModel": {
"models": {},
"enums": {},
"types": {}
}
}
config.runtimeDataModel = JSON.parse("{\"models\":{\"OrganizationJoinRequest\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"orgId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"status\",\"kind\":\"enum\",\"type\":\"ORGANIZATION_JOIN_REQUEST\"},{\"name\":\"requestType\",\"kind\":\"enum\",\"type\":\"ORGANIZATION_JOIN_REQUEST_TYPE\"},{\"name\":\"requestedOn\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"role\",\"kind\":\"enum\",\"type\":\"ORG_ROLE\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"rejectReason\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"requestMessage\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"organization\",\"kind\":\"object\",\"type\":\"Organization\",\"relationName\":\"OrganizationToOrganizationJoinRequest\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"OrganizationJoinRequestToUser\"}],\"dbName\":\"organization_join_request\"},\"OrganizationUserJoinTable\":{\"fields\":[{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"orgId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"role\",\"kind\":\"enum\",\"type\":\"ORG_ROLE\"},{\"name\":\"joinedDate\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"organization\",\"kind\":\"object\",\"type\":\"Organization\",\"relationName\":\"OrganizationToOrganizationUserJoinTable\"},{\"name\":\"user\",\"kind\":\"object\",\"type\":\"User\",\"relationName\":\"OrganizationUserJoinTableToUser\"}],\"dbName\":\"organization_user_join\"},\"Organization\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"name\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"description\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"members\",\"kind\":\"object\",\"type\":\"OrganizationUserJoinTable\",\"relationName\":\"OrganizationToOrganizationUserJoinTable\"},{\"name\":\"requestingMembers\",\"kind\":\"object\",\"type\":\"OrganizationJoinRequest\",\"relationName\":\"OrganizationToOrganizationJoinRequest\"}],\"dbName\":\"organization\"},\"User\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"firstName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"middleName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"lastName\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"email\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"password\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"role\",\"kind\":\"enum\",\"type\":\"USER_ROLE\"},{\"name\":\"isVerified\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"refreshToken\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"profilePicture\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"isDeleted\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"deletedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"createdAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"updatedAt\",\"kind\":\"scalar\",\"type\":\"DateTime\"},{\"name\":\"organizations\",\"kind\":\"object\",\"type\":\"OrganizationUserJoinTable\",\"relationName\":\"OrganizationUserJoinTableToUser\"},{\"name\":\"organizationsRequested\",\"kind\":\"object\",\"type\":\"OrganizationJoinRequest\",\"relationName\":\"OrganizationJoinRequestToUser\"}],\"dbName\":\"user\"}},\"enums\":{},\"types\":{}}")
async function decodeBase64AsWasm(wasmBase64: string): Promise<WebAssembly.Module> {
const { Buffer } = await import('node:buffer')
const wasmArray = Buffer.from(wasmBase64, 'base64')
return new WebAssembly.Module(wasmArray)
}
config.compilerWasm = {
getRuntime: async () => await import("@prisma/client/runtime/query_compiler_fast_bg.postgresql.js"),
getQueryCompilerWasmModule: async () => {
const { wasm } = await import("@prisma/client/runtime/query_compiler_fast_bg.postgresql.wasm-base64.js")
return await decodeBase64AsWasm(wasm)
},
importName: "./query_compiler_fast_bg.js"
}
export type LogOptions<ClientOptions extends Prisma.PrismaClientOptions> =
'log' extends keyof ClientOptions ? ClientOptions['log'] extends Array<Prisma.LogLevel | Prisma.LogDefinition> ? Prisma.GetEvents<ClientOptions['log']> : never : never
export interface PrismaClientConstructor {
/**
* ## Prisma Client
*
* Type-safe database client for TypeScript
* @example
* ```
* const prisma = new PrismaClient()
* // Fetch zero or more OrganizationJoinRequests
* const organizationJoinRequests = await prisma.organizationJoinRequest.findMany()
* ```
*
* Read more in our [docs](https://pris.ly/d/client).
*/
new <
Options extends Prisma.PrismaClientOptions = Prisma.PrismaClientOptions,
LogOpts extends LogOptions<Options> = LogOptions<Options>,
OmitOpts extends Prisma.PrismaClientOptions['omit'] = Options extends { omit: infer U } ? U : Prisma.PrismaClientOptions['omit'],
ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs
>(options: Prisma.Subset<Options, Prisma.PrismaClientOptions> ): PrismaClient<LogOpts, OmitOpts, ExtArgs>
}
/**
* ## Prisma Client
*
* Type-safe database client for TypeScript
* @example
* ```
* const prisma = new PrismaClient()
* // Fetch zero or more OrganizationJoinRequests
* const organizationJoinRequests = await prisma.organizationJoinRequest.findMany()
* ```
*
* Read more in our [docs](https://pris.ly/d/client).
*/
export interface PrismaClient<
in LogOpts extends Prisma.LogLevel = never,
in out OmitOpts extends Prisma.PrismaClientOptions['omit'] = undefined,
in out ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs
> {
[K: symbol]: { types: Prisma.TypeMap<ExtArgs>['other'] }
$on<V extends LogOpts>(eventType: V, callback: (event: V extends 'query' ? Prisma.QueryEvent : Prisma.LogEvent) => void): PrismaClient;
/**
* Connect with the database
*/
$connect(): runtime.Types.Utils.JsPromise<void>;
/**
* Disconnect from the database
*/
$disconnect(): runtime.Types.Utils.JsPromise<void>;
/**
* Executes a prepared raw query and returns the number of affected rows.
* @example
* ```
* const result = await prisma.$executeRaw`UPDATE User SET cool = ${true} WHERE email = ${'user@email.com'};`
* ```
*
* Read more in our [docs](https://pris.ly/d/raw-queries).
*/
$executeRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise<number>;
/**
* Executes a raw query and returns the number of affected rows.
* Susceptible to SQL injections, see documentation.
* @example
* ```
* const result = await prisma.$executeRawUnsafe('UPDATE User SET cool = $1 WHERE email = $2 ;', true, 'user@email.com')
* ```
*
* Read more in our [docs](https://pris.ly/d/raw-queries).
*/
$executeRawUnsafe<T = unknown>(query: string, ...values: any[]): Prisma.PrismaPromise<number>;
/**
* Performs a prepared raw query and returns the `SELECT` data.
* @example
* ```
* const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${1} OR email = ${'user@email.com'};`
* ```
*
* Read more in our [docs](https://pris.ly/d/raw-queries).
*/
$queryRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise<T>;
/**
* Performs a raw query and returns the `SELECT` data.
* Susceptible to SQL injections, see documentation.
* @example
* ```
* const result = await prisma.$queryRawUnsafe('SELECT * FROM User WHERE id = $1 OR email = $2;', 1, 'user@email.com')
* ```
*
* Read more in our [docs](https://pris.ly/d/raw-queries).
*/
$queryRawUnsafe<T = unknown>(query: string, ...values: any[]): Prisma.PrismaPromise<T>;
/**
* Allows the running of a sequence of read/write operations that are guaranteed to either succeed or fail as a whole.
* @example
* ```
* const [george, bob, alice] = await prisma.$transaction([
* prisma.user.create({ data: { name: 'George' } }),
* prisma.user.create({ data: { name: 'Bob' } }),
* prisma.user.create({ data: { name: 'Alice' } }),
* ])
* ```
*
* Read more in our [docs](https://www.prisma.io/docs/concepts/components/prisma-client/transactions).
*/
$transaction<P extends Prisma.PrismaPromise<any>[]>(arg: [...P], options?: { isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise<runtime.Types.Utils.UnwrapTuple<P>>
$transaction<R>(fn: (prisma: Omit<PrismaClient, runtime.ITXClientDenyList>) => runtime.Types.Utils.JsPromise<R>, options?: { maxWait?: number, timeout?: number, isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise<R>
$extends: runtime.Types.Extensions.ExtendsHook<"extends", Prisma.TypeMapCb<OmitOpts>, ExtArgs, runtime.Types.Utils.Call<Prisma.TypeMapCb<OmitOpts>, {
extArgs: ExtArgs
}>>
/**
* `prisma.organizationJoinRequest`: Exposes CRUD operations for the **OrganizationJoinRequest** model.
* Example usage:
* ```ts
* // Fetch zero or more OrganizationJoinRequests
* const organizationJoinRequests = await prisma.organizationJoinRequest.findMany()
* ```
*/
get organizationJoinRequest(): Prisma.OrganizationJoinRequestDelegate<ExtArgs, { omit: OmitOpts }>;
/**
* `prisma.organizationUserJoinTable`: Exposes CRUD operations for the **OrganizationUserJoinTable** model.
* Example usage:
* ```ts
* // Fetch zero or more OrganizationUserJoinTables
* const organizationUserJoinTables = await prisma.organizationUserJoinTable.findMany()
* ```
*/
get organizationUserJoinTable(): Prisma.OrganizationUserJoinTableDelegate<ExtArgs, { omit: OmitOpts }>;
/**
* `prisma.organization`: Exposes CRUD operations for the **Organization** model.
* Example usage:
* ```ts
* // Fetch zero or more Organizations
* const organizations = await prisma.organization.findMany()
* ```
*/
get organization(): Prisma.OrganizationDelegate<ExtArgs, { omit: OmitOpts }>;
/**
* `prisma.user`: Exposes CRUD operations for the **User** model.
* Example usage:
* ```ts
* // Fetch zero or more Users
* const users = await prisma.user.findMany()
* ```
*/
get user(): Prisma.UserDelegate<ExtArgs, { omit: OmitOpts }>;
}
export function getPrismaClientClass(): PrismaClientConstructor {
return runtime.getPrismaClient(config) as unknown as PrismaClientConstructor
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,155 +0,0 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
// @ts-nocheck
/*
* WARNING: This is an internal file that is subject to change!
*
* 🛑 Under no circumstances should you import this file directly! 🛑
*
* All exports from this file are wrapped under a `Prisma` namespace object in the browser.ts file.
* While this enables partial backward compatibility, it is not part of the stable public API.
*
* If you are looking for your Models, Enums, and Input Types, please import them from the respective
* model files in the `model` directory!
*/
import * as runtime from "@prisma/client/runtime/index-browser"
export type * from '../models'
export type * from './prismaNamespace'
export const Decimal = runtime.Decimal
export const NullTypes = {
DbNull: runtime.NullTypes.DbNull as (new (secret: never) => typeof runtime.DbNull),
JsonNull: runtime.NullTypes.JsonNull as (new (secret: never) => typeof runtime.JsonNull),
AnyNull: runtime.NullTypes.AnyNull as (new (secret: never) => typeof runtime.AnyNull),
}
/**
* Helper for filtering JSON entries that have `null` on the database (empty on the db)
*
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
*/
export const DbNull = runtime.DbNull
/**
* Helper for filtering JSON entries that have JSON `null` values (not empty on the db)
*
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
*/
export const JsonNull = runtime.JsonNull
/**
* Helper for filtering JSON entries that are `Prisma.DbNull` or `Prisma.JsonNull`
*
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
*/
export const AnyNull = runtime.AnyNull
export const ModelName = {
OrganizationJoinRequest: 'OrganizationJoinRequest',
OrganizationUserJoinTable: 'OrganizationUserJoinTable',
Organization: 'Organization',
User: 'User'
} as const
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
/*
* Enums
*/
export const TransactionIsolationLevel = runtime.makeStrictEnum({
ReadUncommitted: 'ReadUncommitted',
ReadCommitted: 'ReadCommitted',
RepeatableRead: 'RepeatableRead',
Serializable: 'Serializable'
} as const)
export type TransactionIsolationLevel = (typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel]
export const OrganizationJoinRequestScalarFieldEnum = {
id: 'id',
userId: 'userId',
orgId: 'orgId',
status: 'status',
requestType: 'requestType',
requestedOn: 'requestedOn',
role: 'role',
updatedAt: 'updatedAt',
rejectReason: 'rejectReason',
requestMessage: 'requestMessage'
} as const
export type OrganizationJoinRequestScalarFieldEnum = (typeof OrganizationJoinRequestScalarFieldEnum)[keyof typeof OrganizationJoinRequestScalarFieldEnum]
export const OrganizationUserJoinTableScalarFieldEnum = {
userId: 'userId',
orgId: 'orgId',
role: 'role',
joinedDate: 'joinedDate'
} as const
export type OrganizationUserJoinTableScalarFieldEnum = (typeof OrganizationUserJoinTableScalarFieldEnum)[keyof typeof OrganizationUserJoinTableScalarFieldEnum]
export const OrganizationScalarFieldEnum = {
id: 'id',
name: 'name',
description: 'description',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type OrganizationScalarFieldEnum = (typeof OrganizationScalarFieldEnum)[keyof typeof OrganizationScalarFieldEnum]
export const UserScalarFieldEnum = {
id: 'id',
firstName: 'firstName',
middleName: 'middleName',
lastName: 'lastName',
email: 'email',
password: 'password',
role: 'role',
isVerified: 'isVerified',
refreshToken: 'refreshToken',
profilePicture: 'profilePicture',
isDeleted: 'isDeleted',
deletedAt: 'deletedAt',
createdAt: 'createdAt',
updatedAt: 'updatedAt'
} as const
export type UserScalarFieldEnum = (typeof UserScalarFieldEnum)[keyof typeof UserScalarFieldEnum]
export const SortOrder = {
asc: 'asc',
desc: 'desc'
} as const
export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder]
export const QueryMode = {
default: 'default',
insensitive: 'insensitive'
} as const
export type QueryMode = (typeof QueryMode)[keyof typeof QueryMode]
export const NullsOrder = {
first: 'first',
last: 'last'
} as const
export type NullsOrder = (typeof NullsOrder)[keyof typeof NullsOrder]

View File

@@ -1,15 +0,0 @@
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
/* eslint-disable */
// biome-ignore-all lint: generated file
// @ts-nocheck
/*
* This is a barrel export file for all models and their related types.
*
* 🟢 You can import this file directly.
*/
export type * from './models/OrganizationJoinRequest'
export type * from './models/OrganizationUserJoinTable'
export type * from './models/Organization'
export type * from './models/User'
export type * from './commonInputTypes'

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
-- CreateTable
CREATE TABLE "user_otp" (
"email" TEXT NOT NULL,
"otp" INTEGER NOT NULL,
"generatedOn" TIMESTAMP(3) NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "user_otp_email_key" ON "user_otp"("email");

View File

@@ -0,0 +1,35 @@
/*
Warnings:
- You are about to drop the column `firstName` on the `user` table. All the data in the column will be lost.
- You are about to drop the column `lastName` on the `user` table. All the data in the column will be lost.
- You are about to drop the column `middleName` on the `user` table. All the data in the column will be lost.
- You are about to drop the column `profilePicture` on the `user` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE "user" DROP COLUMN "firstName",
DROP COLUMN "lastName",
DROP COLUMN "middleName",
DROP COLUMN "profilePicture";
-- CreateTable
CREATE TABLE "UserAdditionalInformation" (
"id" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"firstName" TEXT NOT NULL,
"middleName" TEXT,
"lastName" TEXT NOT NULL,
"profilePicture" TEXT,
"address" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "UserAdditionalInformation_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "UserAdditionalInformation_userId_key" ON "UserAdditionalInformation"("userId");
-- AddForeignKey
ALTER TABLE "UserAdditionalInformation" ADD CONSTRAINT "UserAdditionalInformation_userId_fkey" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,20 @@
/*
Warnings:
- You are about to drop the column `isVerified` on the `user` table. All the data in the column will be lost.
- You are about to drop the column `generatedOn` on the `user_otp` table. All the data in the column will be lost.
- Added the required column `expiresAt` to the `user_otp` table without a default value. This is not possible if the table is not empty.
*/
-- CreateEnum
CREATE TYPE "USER_ACCOUNT_STATUS" AS ENUM ('pending', 'active', 'suspended', 'deleted');
-- AlterTable
ALTER TABLE "user" DROP COLUMN "isVerified",
ADD COLUMN "status" "USER_ACCOUNT_STATUS" NOT NULL DEFAULT 'pending',
ALTER COLUMN "password" DROP NOT NULL;
-- AlterTable
ALTER TABLE "user_otp" DROP COLUMN "generatedOn",
ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
ADD COLUMN "expiresAt" TIMESTAMP(3) NOT NULL;

View File

@@ -1,14 +1,10 @@
model User { model User {
id String @id @default(uuid()) id String @id @default(uuid())
firstName String
middleName String?
lastName String
email String @unique email String @unique
password String password String?
role USER_ROLE @default(user) role USER_ROLE @default(user)
isVerified Boolean? @default(false) // TODO: Email using queue
refreshToken String? refreshToken String?
profilePicture String? status USER_ACCOUNT_STATUS @default(pending)
isDeleted Boolean? @default(false) isDeleted Boolean? @default(false)
deletedAt DateTime? deletedAt DateTime?
@@ -17,11 +13,45 @@ model User {
organizations OrganizationUserJoinTable[] organizations OrganizationUserJoinTable[]
organizationsRequested OrganizationJoinRequest[] organizationsRequested OrganizationJoinRequest[]
userAdditionalInformation UserAdditionalInformation?
@@map("user") @@map("user")
} }
model UserAdditionalInformation {
id String @id @default(uuid())
userId String @unique
firstName String
middleName String?
lastName String
profilePicture String?
address String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
model UserOTP {
email String @unique
otp Int
// ExipresAt is also saved so its easier to check and also
// run cron job to remove expired OTPs
createdAt DateTime @default(now())
expiresAt DateTime
@@map("user_otp")
}
enum USER_ROLE { enum USER_ROLE {
superadmin superadmin
user user
} }
enum USER_ACCOUNT_STATUS {
pending
active
suspended
deleted
}

View File

@@ -11,8 +11,12 @@
Worker processes it: A separate background worker picks up the job, tries to send the email, and automatically handles retries if it fails. Worker processes it: A separate background worker picks up the job, tries to send the email, and automatically handles retries if it fails.
``` ```
``` ```
2. Also an API of my own
3. Production and testing env diff
4. Testing
# 🏗️ SaaS Architects Roadmap: NestJS & DevOps # 🏗️ SaaS Architects Roadmap: NestJS & DevOps

View File

@@ -1,26 +1,48 @@
import { Logger, MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; import { Logger, MiddlewareConsumer, Module, NestModule, ValidationPipe } from '@nestjs/common';
import { AppController } from './app.controller'; import { AppController } from './app.controller';
import { AppService } from './app.service'; import { AppService } from './app.service';
import { UserModule } from './user/user.module'; import { UserModule } from './user/user.module';
import { AuthModule } from './auth/auth.module'; import { AuthModule } from './auth/auth.module';
import { RequestContextMiddleware } from 'core/als/request-context.middleware'; import { RequestContextMiddleware } from 'core/als/request-context.middleware';
import { RequestContextModule } from 'core/als/request-context.module'; import { RequestContextModule } from 'core/als/request-context.module';
import { ConfigModule } from '@nestjs/config'; import { ConfigModule, ConfigService } from '@nestjs/config';
import { PrismaModule } from './prisma/prisma.module'; import { PrismaModule } from './prisma/prisma.module';
import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core'; import { APP_FILTER, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
import { ResponseInterceptor } from 'common/interceptors/response.interceptor'; import { ResponseInterceptor } from 'common/interceptors/response.interceptor';
import { HttpExceptionFilter } from 'common/exceptions/exception-filter'; import { HttpExceptionFilter } from 'common/exceptions/exception-filter';
import { OrganizationModule } from './organization/organization.module'; import { OrganizationModule } from './organization/organization.module';
import { OrganizationMembershipModule } from './organization-membership/organization-membership.module'; import { OrganizationMembershipModule } from './organization-membership/organization-membership.module';
import { AuthorizationModule } from './authorization/authorization.module'; import { AuthorizationModule } from './authorization/authorization.module';
import { CacheModule } from './cache/cache.module'; import { CacheModule } from './cache/cache.module';
import { MailModule } from 'core/mail/mail.module'; import { EventEmitterModule } from '@nestjs/event-emitter';
import { MailModule } from './mail/mail.module';
import { BullModule } from '@nestjs/bullmq';
import { BullBoardModule } from '@bull-board/nestjs';
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
import { ExpressAdapter } from '@bull-board/express';
import { NotificationModule } from './notification/notification.module';
@Module({ @Module({
imports: [ imports: [
ConfigModule.forRoot({ ConfigModule.forRoot({
isGlobal: true, isGlobal: true,
}), }),
EventEmitterModule.forRoot(),
BullModule.forRoot({
connection: {
host: 'localhost',
port: 6379,
},
}),
BullBoardModule.forRoot({
route: '/queues', // Dashboard URL
adapter: ExpressAdapter,
}),
BullBoardModule.forFeature({
name: 'mail', // Register each queue you want visible
adapter: BullMQAdapter,
}),
UserModule, UserModule,
AuthModule, AuthModule,
RequestContextModule, RequestContextModule,
@@ -29,7 +51,8 @@ import { MailModule } from 'core/mail/mail.module';
OrganizationMembershipModule, OrganizationMembershipModule,
AuthorizationModule, AuthorizationModule,
CacheModule, CacheModule,
MailModule MailModule,
NotificationModule,
], ],
controllers: [AppController], controllers: [AppController],
providers: [ providers: [
@@ -40,9 +63,13 @@ import { MailModule } from 'core/mail/mail.module';
useClass: ResponseInterceptor, useClass: ResponseInterceptor,
}, },
{ {
provide: APP_FILTER, provide: APP_PIPE,
useClass: HttpExceptionFilter, useClass: ValidationPipe,
}, },
// {
// provide: APP_FILTER,
// useClass: HttpExceptionFilter,
// },
// NOTE: Auto cache controller response // NOTE: Auto cache controller response
// { // {
// provide: APP_INTERCEPTOR, // provide: APP_INTERCEPTOR,
@@ -51,7 +78,26 @@ import { MailModule } from 'core/mail/mail.module';
], ],
}) })
export class AppModule implements NestModule { export class AppModule implements NestModule {
constructor(private readonly configService: ConfigService) { };
configure(consumer: MiddlewareConsumer) { configure(consumer: MiddlewareConsumer) {
consumer.apply(RequestContextMiddleware).forRoutes('*paths'); consumer.apply(RequestContextMiddleware).forRoutes('*paths');
} }
// Make sure all required env vars are present
onModuleInit() {
const requiredEnvVars = [
"TOKEN_SECRET",
"DATABASE_URL",
"BULL_MQ_REDIS_HOST",
"BULL_MQ_REDIS_PORT"
]
const missingEnvVars = requiredEnvVars.filter((envVar) => !(this.configService.get<string | number>(envVar)))
if (missingEnvVars.length > 0) {
Logger.error(`One or more env variables are missing. Add: ${missingEnvVars.join(', ')} to env file.`)
process.exit(1)
}
}
} }

View File

@@ -5,22 +5,26 @@ import {
HttpStatus, HttpStatus,
Post, Post,
Res, Res,
UseGuards,
} from '@nestjs/common'; } from '@nestjs/common';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
import { ApiOperation } from '@nestjs/swagger'; import { ApiBearerAuth, ApiOperation } from '@nestjs/swagger';
import { import {
CompleteProfileSetupRequestDTO,
LoginUserRequestDTO, LoginUserRequestDTO,
LoginUserResponseDTO, LoginUserResponseDTO,
RegisterUserRequestDTO, RegisterUserRequestDTO,
ValidateUserRegisterOTPRequestDTO,
} from './dto'; } from './dto';
import { Response } from 'express'; import { Response } from 'express';
import { DataResponse } from 'common/http'; import { DataResponse } from 'common/http';
import { Public } from './decorators'; import { IsTempToken, Public } from './decorators';
import { AuthGuard } from './guards/auth.guard';
@Controller('auth') @Controller('auth')
@Public() @Public()
export class AuthController { export class AuthController {
constructor(private readonly authService: AuthService) {} constructor(private readonly authService: AuthService) { }
@ApiOperation({ summary: 'User login' }) @ApiOperation({ summary: 'User login' })
@HttpCode(HttpStatus.OK) @HttpCode(HttpStatus.OK)
@@ -41,17 +45,53 @@ export class AuthController {
} }
@ApiOperation({ summary: 'User register' }) @ApiOperation({ summary: 'User register' })
@HttpCode(HttpStatus.CREATED)
@Post('/register') @Post('/register')
async register(@Body() body: RegisterUserRequestDTO): Promise<string> { async register(@Body() body: RegisterUserRequestDTO): Promise<string> {
await this.authService.register(body); await this.authService.register(body);
return 'Registered successfully. Login to continue.'; return 'Check your email for OTP';
} }
logout() {}
forgotPassword() {} // TODO: Assign Temp Token
@ApiOperation({ summary: 'Validate OTP' })
@Post('/validate-otp')
async validateOTP(@Body() body: ValidateUserRegisterOTPRequestDTO) {
const { accessToken, refreshToken } = await this.authService.validateOtp(body);
regenTokens() {} return {
message: 'Continue with the rest of profile setup',
data: {
accessToken,
refreshToken
}
}
}
// TODO: Assign Temp Token
@ApiOperation({ summary: 'Complete Profile' })
@ApiBearerAuth("access-token")
@Public(false)
@IsTempToken()
@UseGuards(AuthGuard)
@Post('/complete-profile')
async completeUserProfile(@Body() body: CompleteProfileSetupRequestDTO) {
const { accessToken, refreshToken, user } = await this.authService.completeProfileSetup(body);
return {
message: "Welcome to our app",
data: {
accessToken,
refreshToken,
user
}
}
}
logout() { }
forgotPassword() { }
regenTokens() { }
} }

View File

@@ -1,12 +1,14 @@
import { Global, Module } from '@nestjs/common'; import { Global, Module } from '@nestjs/common';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
import { AuthController } from './auth.controller'; import { AuthController } from './auth.controller';
import { APP_GUARD, Reflector } from '@nestjs/core'; import { APP_GUARD } from '@nestjs/core';
import { AuthGuard } from './guards/auth.guard'; import { AuthGuard } from './guards/auth.guard';
import { UserModule } from 'src/user/user.module'; import { UserModule } from 'src/user/user.module';
import { JwtModule } from '@nestjs/jwt';
import { RequestContextModule } from 'core/als/request-context.module'; import { RequestContextModule } from 'core/als/request-context.module';
import { MailModule } from 'core/mail/mail.module'; import { BullModule } from '@nestjs/bullmq';
import { PrismaModule } from 'src/prisma/prisma.module';
import { JwtModule } from '@nestjs/jwt';
import { ConfigModule, ConfigService } from '@nestjs/config';
@Global() @Global()
@Module({ @Module({
@@ -19,10 +21,21 @@ import { MailModule } from 'core/mail/mail.module';
], ],
controllers: [AuthController], controllers: [AuthController],
imports: [ imports: [
BullModule.registerQueue({
name: "mail"
}),
JwtModule.registerAsync({
global: true,
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
secret: config.get<string>("TOKEN_SECRET"),
signOptions: { expiresIn: '7d' }
})
}),
UserModule, UserModule,
JwtModule,
RequestContextModule, RequestContextModule,
MailModule PrismaModule
], ],
}) })
export class AuthModule { } export class AuthModule { }

View File

@@ -1,12 +1,25 @@
import { Injectable, UnauthorizedException } from '@nestjs/common'; import {
BadRequestException,
ConflictException,
Injectable,
InternalServerErrorException,
UnauthorizedException
} from '@nestjs/common';
import { Public } from './decorators'; import { Public } from './decorators';
import { LoginUserRequestDTO, RegisterUserRequestDTO } from './dto'; import {
CompleteProfileSetupRequestDTO,
LoginUserRequestDTO,
RegisterUserRequestDTO,
ValidateUserRegisterOTPRequestDTO
} from './dto';
import * as bcrypt from 'bcrypt'; import * as bcrypt from 'bcrypt';
import { UserService } from 'src/user/user.service'; import { UserService } from 'src/user/user.service';
import { TokenInputType } from './types'; import { OTPTokenInputType, TokenInputType } from './types';
import { JwtService } from '@nestjs/jwt'; import { JwtService } from '@nestjs/jwt';
import { MailService } from 'core/mail/mail.service'; import { Queue } from 'bullmq';
import EmailTemplates from 'common/emails'; import { InjectQueue } from '@nestjs/bullmq';
import { PrismaService } from 'src/prisma/prisma.service';
import { RequestContextService } from 'core/als/request-context.service';
@Injectable() @Injectable()
@Public() @Public()
@@ -14,27 +27,168 @@ export class AuthService {
constructor( constructor(
private readonly userService: UserService, private readonly userService: UserService,
private readonly jwtService: JwtService, private readonly jwtService: JwtService,
private readonly mailService: MailService, private readonly prismaService: PrismaService,
private readonly requestContext: RequestContextService,
@InjectQueue('mail') private readonly mailQueue: Queue
) { } ) { }
// Generate OTP
async register(dto: RegisterUserRequestDTO) { async register(dto: RegisterUserRequestDTO) {
const hashedPassword = await bcrypt.hash(dto.password, 10); const [userExists, otpExists] = await Promise.all([
await this.userService.createUserWithPassword({ this.userService.findByEmail(dto.email),
...dto, this.userService.findByEmailInOTP(dto.email),
password: hashedPassword, ])
});
this.mailService.sendMail({ if (userExists)
to: dto.email, throw new ConflictException("User with this email already exists");
subject: "Welcome onboard", else if (otpExists) {
body: EmailTemplates.welcomeToApp /* *
* If OTP was last generated more than 2 minutes ago, regen.
* Else, do nothing
* */
const now = Number(new Date()) / 1000;
const generatedPlusTwoMin = (Number(otpExists.createdAt) / 1000) + 60 * 2;
if (generatedPlusTwoMin > now) {
return;
}
}
const otp = this.genOtp()
await this.prismaService.$transaction(async (tx) => {
this.requestContext.tx = tx;
await this.userService.updateOTPByEmail(dto.email, otp);
}) })
this.mailQueue.add('send-register-otp-email', {
email: dto.email,
otp: otp
}, {
attempts: 3,
backoff: {
type: "exponential",
delay: 3000
},
removeOnComplete: true, // clean up Redis after success
removeOnFail: false,
})
return true; return true;
} }
// Validate OTP
async validateOtp(dto: ValidateUserRegisterOTPRequestDTO) {
const otpExists = await this.userService.findByEmailInOTP(dto.email)
const now = Number(new Date()) / 1000;
if (!otpExists)
throw new BadRequestException("No OTP request found")
else if (otpExists.otp !== dto.otp)
throw new BadRequestException("Invalid OTP")
else if ((Number(otpExists.expiresAt) / 1000 < now)) {
await this.userService.removeByEmailInOTP(dto.email);
throw new BadRequestException("OTP has expired")
}
const user = await this.prismaService.$transaction(async (tx) => {
this.requestContext.tx = tx;
await this.userService.removeByEmailInOTP(dto.email);
return await this.userService.initializeUserWithEmail(dto.email)
})
if (!user)
throw new InternalServerErrorException()
const token = {
userId: user.id,
email: user.email,
status: user.status
}
const tokens = this.genSignedTempToken(token)
return tokens;
}
// Complete rest of singup process
async completeProfileSetup(dto: CompleteProfileSetupRequestDTO) {
const user = this.requestContext.user;
if (!user)
throw new UnauthorizedException("User")
const hashedPassword = await bcrypt.hash(dto.password, 10);
const {
newUser,
userAdditionalInfo: _
} = await this.prismaService.$transaction(async (tx) => {
this.requestContext.tx = tx;
const newUser = await this.userService.createUserWithPassword(
user.email,
hashedPassword,
);
if (!newUser)
throw new UnauthorizedException()
const userAdditionalInfo = await this.userService.createUserAdditionalInformation(
newUser?.id,
dto
)
return {
newUser,
userAdditionalInfo,
}
})
this.mailQueue.add('send-welcome-email', {
email: user.email,
}, {
attempts: 3,
backoff: {
type: "exponential",
delay: 3000,
},
removeOnComplete: true, // clean up Redis after success
removeOnFail: false,
})
const token = {
userId: newUser.id,
email: newUser.email,
role: newUser.role,
status: newUser.status
};
const {
accessToken,
refreshToken
} = await this.genSignedTokens(token)
return {
accessToken,
refreshToken,
user: newUser
};
}
async login(dto: LoginUserRequestDTO) { async login(dto: LoginUserRequestDTO) {
const user = await this.userService.findUserForAuth(dto.email); const user = await this.userService.findUserForAuth(dto.email);
if (!user) throw new UnauthorizedException('Invalid credentials.'); if (!user) throw new UnauthorizedException('Invalid credentials.');
else if (!user.password) {
const token = {
userId: user.id,
email: user.email,
status: user.status
}
const { accessToken, refreshToken } = await this.genSignedTempToken(token)
return { accessToken, refreshToken, user };
}
const passwordMatch = await bcrypt.compare(dto.password, user.password); const passwordMatch = await bcrypt.compare(dto.password, user.password);
if (!passwordMatch) throw new UnauthorizedException('Invalid credentials.'); if (!passwordMatch) throw new UnauthorizedException('Invalid credentials.');
@@ -43,6 +197,7 @@ export class AuthService {
userId: user.id, userId: user.id,
email: user.email, email: user.email,
role: user.role, role: user.role,
status: user.status
}; };
// TODO: Store more info: orgId, orgRole, etc // TODO: Store more info: orgId, orgRole, etc
@@ -62,21 +217,36 @@ export class AuthService {
resetPassword() { } resetPassword() { }
// TODO: Use nest jwt // TODO: If remember me is there, sign for like 30d maybe
private async genSignedTokens(token: TokenInputType) { private async genSignedTokens(token: TokenInputType) {
const accessToken = await this.jwtService.signAsync(token, { const accessToken = await this.jwtService.signAsync(token);
secret: 'demo',
});
const refreshToken = await this.jwtService.signAsync( const refreshToken = await this.jwtService.signAsync(
{ {
userId: token.userId, userId: token.userId,
}, },
);
return { accessToken, refreshToken };
}
private async genSignedTempToken(token: OTPTokenInputType) {
const accessToken = await this.jwtService.signAsync(token);
const refreshToken = await this.jwtService.signAsync(
{ {
secret: 'demo', userId: token.userId,
}, },
); );
return { accessToken, refreshToken }; return { accessToken, refreshToken };
} }
genOtp(): number {
const array = new Uint32Array(1);
crypto.getRandomValues(array);
const otp = array[0] % 900000 + 100000;
return otp;
}
} }

View File

@@ -1,3 +1,4 @@
export * from './public.decorator'; export * from './public.decorator';
export * from './role.decorator'; export * from './role.decorator';
export * from './authorization.decorator'; export * from './authorization.decorator';
export * from './isTemp.decorator'

View File

@@ -0,0 +1,4 @@
import { SetMetadata } from "@nestjs/common";
import { TEMP_TOKEN_KEY } from "common/keys";
export const IsTempToken = () => SetMetadata(TEMP_TOKEN_KEY, true)

View File

@@ -0,0 +1,42 @@
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
import { IsNotEmpty, IsOptional, IsString, MinLength } from "class-validator";
export class CompleteProfileSetupRequestDTO {
@ApiProperty({
description: "User's firstName",
example: 'John',
type: 'string',
})
@IsString()
@IsNotEmpty()
firstName: string;
@ApiPropertyOptional({
description: "User's middleName",
example: 'Kumar',
type: 'string',
})
@IsString()
@IsOptional()
middleName?: string;
@ApiProperty({
description: "User's lastName",
example: 'Doe',
type: 'string',
})
@IsString()
@IsNotEmpty()
lastName: string;
@ApiProperty({
description: "User's password",
example: '123456',
type: 'string',
minLength: 6,
})
@IsString()
@IsNotEmpty()
@MinLength(6)
password: string;
}

View File

@@ -1,3 +1,5 @@
export * from './register-user.dto'; export * from './register-user.dto';
export * from './login-user.dto'; export * from './login-user.dto';
export * from './login-response.dto'; export * from './login-response.dto';
export * from "./validate-otp.dto";
export * from "./complete-setup.dto";

View File

@@ -2,39 +2,9 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { import {
IsEmail, IsEmail,
IsNotEmpty, IsNotEmpty,
IsOptional,
IsString,
MinLength,
} from 'class-validator'; } from 'class-validator';
export class RegisterUserRequestDTO { export class RegisterUserRequestDTO {
@ApiProperty({
description: "User's firstName",
example: 'John',
type: 'string',
})
@IsString()
@IsNotEmpty()
firstName: string;
@ApiPropertyOptional({
description: "User's middleName",
example: 'Kumar',
type: 'string',
})
@IsString()
@IsOptional()
middleName?: string;
@ApiProperty({
description: "User's lastName",
example: 'Doe',
type: 'string',
})
@IsString()
@IsNotEmpty()
lastName: string;
@ApiProperty({ @ApiProperty({
description: "User's email", description: "User's email",
example: 'user@example.com', example: 'user@example.com',
@@ -43,15 +13,4 @@ export class RegisterUserRequestDTO {
@IsEmail() @IsEmail()
@IsNotEmpty() @IsNotEmpty()
email: string; email: string;
@ApiProperty({
description: "User's password",
example: '123456',
type: 'string',
minLength: 6,
})
@IsString()
@IsNotEmpty()
@MinLength(6)
password: string;
} }

View File

@@ -0,0 +1,22 @@
import { ApiProperty } from "@nestjs/swagger";
import { IsEmail, IsNotEmpty, IsNumber } from "class-validator";
export class ValidateUserRegisterOTPRequestDTO {
@ApiProperty({
description: "Register OTP",
example: 123456,
type: 'number',
})
@IsNumber()
@IsNotEmpty()
otp: number
@ApiProperty({
description: "User's email",
example: 'user@example.com',
type: 'string',
})
@IsEmail()
@IsNotEmpty()
email: string;
}

View File

@@ -1,6 +1,7 @@
import { import {
CanActivate, CanActivate,
ExecutionContext, ExecutionContext,
ForbiddenException,
Injectable, Injectable,
UnauthorizedException, UnauthorizedException,
} from '@nestjs/common'; } from '@nestjs/common';
@@ -9,8 +10,10 @@ import { JwtService } from '@nestjs/jwt';
import { JwtPayload } from '../types'; import { JwtPayload } from '../types';
import { Request } from 'express'; import { Request } from 'express';
import { Reflector } from '@nestjs/core'; import { Reflector } from '@nestjs/core';
import { PUBLIC_KEY } from 'common/keys'; import { PUBLIC_KEY, TEMP_TOKEN_KEY } from 'common/keys';
import { UserService } from 'src/user/user.service'; import { UserService } from 'src/user/user.service';
import { USER_ACCOUNT_STATUS } from 'prisma/generated/prisma/enums';
import { ConfigService } from '@nestjs/config';
@Injectable() @Injectable()
export class AuthGuard implements CanActivate { export class AuthGuard implements CanActivate {
@@ -19,7 +22,8 @@ export class AuthGuard implements CanActivate {
private readonly jwtService: JwtService, private readonly jwtService: JwtService,
private readonly requestContext: RequestContextService, private readonly requestContext: RequestContextService,
private readonly userService: UserService, private readonly userService: UserService,
) {} private readonly configService: ConfigService,
) { }
async canActivate(context: ExecutionContext) { async canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest(); const request = context.switchToHttp().getRequest();
@@ -30,17 +34,33 @@ export class AuthGuard implements CanActivate {
); );
if (isPublicRoute) return true; if (isPublicRoute) return true;
const isTempToken = this.reflector.getAllAndOverride<boolean>(
TEMP_TOKEN_KEY,
[context.getHandler(), context.getClass()],
)
const token = this.extractTokenFromHeader(request); const token = this.extractTokenFromHeader(request);
if (!token) throw new UnauthorizedException(); if (!token) throw new UnauthorizedException();
try { try {
const payload: JwtPayload = await this.jwtService.verifyAsync(token, { const payload: JwtPayload = await this.jwtService.verifyAsync(token, {
secret: 'demo', secret: this.configService.get<string>("TOKEN_SECRET"),
}); });
if (isTempToken && payload.status !== USER_ACCOUNT_STATUS.pending)
throw new UnauthorizedException()
// TODO: Redis + Org too, blacklist token // TODO: Redis + Org too, blacklist token
const userExists = await this.userService.findById(payload.userId); const userExists = await this.userService.findById(payload.userId);
if (!userExists) throw new UnauthorizedException(); if (!userExists) throw new UnauthorizedException();
// NOTE: Add more checks here (other account status)
if (userExists.status !== USER_ACCOUNT_STATUS.active) {
if (userExists.status === USER_ACCOUNT_STATUS.pending && isTempToken === undefined)
throw new ForbiddenException()
}
this.requestContext.set('user', payload); this.requestContext.set('user', payload);
return true; return true;

View File

@@ -1,10 +1,11 @@
import { ORG_ROLE, USER_ROLE } from 'prisma/generated/prisma/enums'; import { ORG_ROLE, USER_ACCOUNT_STATUS, USER_ROLE } from 'prisma/generated/prisma/enums';
export interface JwtPayload { export interface JwtPayload {
iat?: number; iat?: number;
exp?: number; exp?: number;
orgId?: string; orgId?: string;
orgRole?: ORG_ROLE; orgRole?: ORG_ROLE;
status: USER_ACCOUNT_STATUS;
userId: string; userId: string;
email: string; email: string;
role: USER_ROLE; role: USER_ROLE;

View File

@@ -1,10 +1,19 @@
import { USER_ACCOUNT_STATUS } from "prisma/generated/prisma/enums";
export interface TokenInputType { export interface TokenInputType {
userId: string; userId: string;
email: string; email: string;
role: string; role: string;
status: USER_ACCOUNT_STATUS;
} }
export interface AccessTokenPayloadType extends TokenInputType {} export interface OTPTokenInputType {
userId: string;
email: string;
status: USER_ACCOUNT_STATUS
}
export interface AccessTokenPayloadType extends TokenInputType { }
export interface RefreshTokenPayloadType { export interface RefreshTokenPayloadType {
userId: string; userId: string;

View File

@@ -0,0 +1,4 @@
export const MAIL_JOBS_NAME = {
WELCOME: 'send-welcome-email',
REGISTER_OTP: 'send-register-otp-email'
}

44
src/mail/mail.consumer.ts Normal file
View File

@@ -0,0 +1,44 @@
import { Processor, WorkerHost } from "@nestjs/bullmq";
import { Job } from "bullmq";
import { MailService } from "./mail.service";
import { MAIL_JOBS_NAME } from "./mail-job-names";
import { RegisterOtpEmailJob, WelcomeEmailJob } from "./mail.interface";
@Processor('mail')
export class MailConsumer extends WorkerHost {
constructor(private readonly mailService: MailService) {
super()
}
// This runs, so we define handlers here
async process(job: Job) {
const handlers: Record<string, (job: Job) => Promise<void>> = {
[MAIL_JOBS_NAME.REGISTER_OTP]: (j: Job<RegisterOtpEmailJob>) =>
this.handleSendOTPMail(j),
[MAIL_JOBS_NAME.WELCOME]: (j: Job<WelcomeEmailJob>) =>
this.handleSendWelcomeMail(j),
}
const handler = handlers[job.name];
if (!handler) throw new Error(`No handler for job: ${job.name}`);
await handler(job);
}
/*
* These are seperated. Using switch-case is not scalable, couldn't define types
* when there were multiple types of emails to be sent
* */
async handleSendOTPMail(job: Job<RegisterOtpEmailJob>) {
await this.mailService.sendOTPMail({
to: job.data.email,
otp: job.data.otp
})
return
}
async handleSendWelcomeMail(job: Job<WelcomeEmailJob>) {
await this.mailService.sendWelcomeMail({ to: job.data.email })
return
}
}

View File

@@ -0,0 +1,8 @@
export interface WelcomeEmailJob {
email: string;
}
export interface RegisterOtpEmailJob {
email: string;
otp: number;
}

15
src/mail/mail.module.ts Normal file
View File

@@ -0,0 +1,15 @@
import { Module } from '@nestjs/common';
import { MailService } from './mail.service';
import { BullModule } from '@nestjs/bullmq';
import { MailConsumer } from './mail.consumer';
@Module({
imports: [
BullModule.registerQueue({
name: "mail"
}),
],
providers: [MailService, MailConsumer],
exports: [MailService]
})
export class MailModule { }

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { MailService } from './mail.service';
describe('MailService', () => {
let service: MailService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [MailService],
}).compile();
service = module.get<MailService>(MailService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -1,5 +1,6 @@
import { Injectable } from "@nestjs/common"; import { Injectable } from '@nestjs/common';
import { ConfigService } from "@nestjs/config"; import { ConfigService } from "@nestjs/config";
import EmailTemplates from 'common/emails';
import * as nodemailer from "nodemailer"; import * as nodemailer from "nodemailer";
@Injectable() @Injectable()
@@ -14,8 +15,6 @@ export class MailService {
if (!mailId || !mailPass) if (!mailId || !mailPass)
throw new Error("Make sure MAIL_ID and MAIL_PASS environment variables are set") throw new Error("Make sure MAIL_ID and MAIL_PASS environment variables are set")
// Use secure in prod
// TODO: A table for failed emails to retry later(actually bullmq)
this.transporter = nodemailer.createTransport({ this.transporter = nodemailer.createTransport({
host: "smtp.gmail.com", host: "smtp.gmail.com",
port: 587, port: 587,
@@ -30,6 +29,39 @@ export class MailService {
this.mailServiceAvailable = true; this.mailServiceAvailable = true;
} }
/*
* SIGN-UP
* */
async sendWelcomeMail({ to }: { to: string }) {
if (!this.mailServiceAvailable)
throw new Error("Mail service not available")
const email = EmailTemplates.signup_completed;
await this.transporter.sendMail(
{
to,
subject: email.subject,
html: email.body
}
)
}
async sendOTPMail({ to, otp }: { to: string, otp: number }) {
if (!this.mailServiceAvailable)
throw new Error("Mail service not available")
const email = EmailTemplates.signup_otp(otp);
await this.transporter.sendMail(
{
to,
subject: email.subject,
html: email.body
}
)
}
sendMail({ to, subject, body }: { to: string, subject: string, body: string }) { sendMail({ to, subject, body }: { to: string, subject: string, body: string }) {
if (!this.mailServiceAvailable) if (!this.mailServiceAvailable)
throw new Error("Mail service not available") throw new Error("Mail service not available")

View File

@@ -2,7 +2,7 @@ import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { Logger } from '@nestjs/common'; import { Logger, ValidationPipe } from '@nestjs/common';
async function bootstrap() { async function bootstrap() {
const app = await NestFactory.create(AppModule); const app = await NestFactory.create(AppModule);

View File

@@ -0,0 +1,19 @@
import {
IsNotEmpty,
IsOptional,
IsString
} from "class-validator"
export class NotificationDTO {
@IsString()
@IsNotEmpty()
name: string;
@IsString()
@IsNotEmpty()
email: string;
@IsString()
@IsOptional()
description?: string;
}

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { NotificationGateway } from './notification.gateway';
describe('NotificationGateway', () => {
let gateway: NotificationGateway;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [NotificationGateway],
}).compile();
gateway = module.get<NotificationGateway>(NotificationGateway);
});
it('should be defined', () => {
expect(gateway).toBeDefined();
});
});

View File

@@ -0,0 +1,29 @@
import {
ConnectedSocket,
MessageBody,
SubscribeMessage,
WebSocketGateway
} from "@nestjs/websockets";
import { Socket } from "net";
import { NotificationDTO } from "./notification.dto";
import { UseFilters, UsePipes, ValidationPipe } from "@nestjs/common";
import { WsValidationExceptionFilter } from "../../common/exceptions/websocket";
@WebSocketGateway()
@UsePipes(new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true,
transform: true,
}))
@UseFilters(new WsValidationExceptionFilter())
export class NotificationGateway {
@SubscribeMessage('hello')
handleHello(
@MessageBody() body: NotificationDTO,
@ConnectedSocket() client: Socket
) {
console.log(body);
client.emit("hello", "Hi")
}
}

View File

@@ -0,0 +1,8 @@
import { Module } from '@nestjs/common';
import { NotificationService } from './notification.service';
import { NotificationGateway } from './notification.gateway';
@Module({
providers: [NotificationService, NotificationGateway]
})
export class NotificationModule {}

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { NotificationService } from './notification.service';
describe('NotificationService', () => {
let service: NotificationService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [NotificationService],
}).compile();
service = module.get<NotificationService>(NotificationService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class NotificationService {}

View File

@@ -1,6 +1,5 @@
import { import {
BadRequestException, BadRequestException,
ForbiddenException,
Injectable, Injectable,
NotFoundException, NotFoundException,
} from '@nestjs/common'; } from '@nestjs/common';
@@ -12,8 +11,6 @@ import {
ORGANIZATION_JOIN_REQUEST, ORGANIZATION_JOIN_REQUEST,
ORGANIZATION_JOIN_REQUEST_TYPE, ORGANIZATION_JOIN_REQUEST_TYPE,
} from 'prisma/generated/prisma/enums'; } from 'prisma/generated/prisma/enums';
import { AuthorizationService } from 'src/authorization/authorization.service';
import { USER_ORGANIZATION_OPERATIONS } from 'src/authorization/operations';
import { Prisma } from 'prisma/generated/prisma/client'; import { Prisma } from 'prisma/generated/prisma/client';
import { JoinRequestToOrganizationRequestDTO } from './dto/join-request.dto'; import { JoinRequestToOrganizationRequestDTO } from './dto/join-request.dto';
import { USER_ORG_ACCEPT_REJECT_ACTION } from './constants'; import { USER_ORG_ACCEPT_REJECT_ACTION } from './constants';
@@ -24,7 +21,6 @@ export class OrganizationMembershipService {
private readonly userService: UserService, private readonly userService: UserService,
private readonly orgService: OrganizationService, private readonly orgService: OrganizationService,
private readonly prisma: PrismaService, private readonly prisma: PrismaService,
private readonly authorization: AuthorizationService,
) { } ) { }
/* * /* *
@@ -121,7 +117,12 @@ export class OrganizationMembershipService {
requestType: joinReqType, requestType: joinReqType,
status: ORGANIZATION_JOIN_REQUEST.PENDING status: ORGANIZATION_JOIN_REQUEST.PENDING
}, },
include: { user: { select: { firstName: true, email: true } } } include: {
user: {
include: { userAdditionalInformation: { select: { firstName: true } } },
select: { email: true }
},
}
}) })
} }
@@ -442,9 +443,9 @@ export class OrganizationMembershipService {
include: { include: {
user: { user: {
select: { select: {
firstName: true,
email: true email: true
} },
include: { userAdditionalInformation: { select: { firstName: true } } },
} }
}, },
} }

View File

@@ -4,18 +4,21 @@ import {
OnModuleDestroy, OnModuleDestroy,
OnModuleInit, OnModuleInit,
} from '@nestjs/common'; } from '@nestjs/common';
import { PrismaClient } from 'prisma/generated/prisma/client'; import { Prisma, PrismaClient } from 'prisma/generated/prisma/client';
import { Pool } from 'pg'; import { Pool } from 'pg';
import { PrismaPg } from '@prisma/adapter-pg'; import { PrismaPg } from '@prisma/adapter-pg';
import { RequestContextService } from 'core/als/request-context.service'; import { RequestContextService } from 'core/als/request-context.service';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { TransactionClient } from 'prisma/generated/prisma/internal/prismaNamespace';
@Global() @Global()
@Injectable() @Injectable()
export class PrismaService export class PrismaService
extends PrismaClient extends PrismaClient
implements OnModuleDestroy, OnModuleInit implements OnModuleDestroy, OnModuleInit {
{
private readonly db: PrismaClient;
constructor( constructor(
private readonly ctx: RequestContextService, private readonly ctx: RequestContextService,
private readonly configService: ConfigService, private readonly configService: ConfigService,
@@ -31,6 +34,8 @@ export class PrismaService
adapter: adapter, adapter: adapter,
log: ['info', 'warn'], log: ['info', 'warn'],
}); });
this.db = new PrismaClient({ adapter, log: ['warn', 'info', 'error'] })
} }
async onModuleInit() { async onModuleInit() {
try { try {
@@ -50,7 +55,7 @@ export class PrismaService
* For shared transaction across services. If present, return the transaction. * For shared transaction across services. If present, return the transaction.
* Else returns itself. * Else returns itself.
* */ * */
get client() { get client(): TransactionClient {
return this.ctx.get().tx ?? this; return this.ctx.tx ?? this.db;
} }
} }

View File

@@ -1,21 +1,15 @@
import { User } from 'prisma/generated/prisma/client'; import { User, USER_ACCOUNT_STATUS } from 'prisma/generated/prisma/client';
export class UserDTO { export class UserDTO {
readonly id: string; readonly id: string;
readonly email: string; readonly email: string;
readonly firstName: string;
readonly middleName: string | null;
readonly lastName: string;
readonly role: string; readonly role: string;
readonly profilePicture: string | null; readonly status: USER_ACCOUNT_STATUS;
constructor(user: User) { constructor(user: User) {
this.id = user.id; this.id = user.id;
this.email = user.email; this.email = user.email;
this.firstName = user.firstName;
this.lastName = user.lastName;
this.middleName = user.middleName;
this.role = user.role; this.role = user.role;
this.profilePicture = user.profilePicture; this.status = user.status
} }
} }

View File

@@ -1,16 +1,50 @@
import { ConflictException, Injectable } from '@nestjs/common'; import { ConflictException, Injectable } from '@nestjs/common';
import { Prisma } from 'prisma/generated/prisma/client'; import { Prisma, USER_ACCOUNT_STATUS } from 'prisma/generated/prisma/client';
import { RegisterUserRequestDTO } from 'src/auth/dto'; import { CompleteProfileSetupRequestDTO } from 'src/auth/dto';
import { PrismaService } from 'src/prisma/prisma.service'; import { PrismaService } from 'src/prisma/prisma.service';
@Injectable() @Injectable()
export class UserService { export class UserService {
constructor(private readonly prisma: PrismaService) {} constructor(
private readonly prisma: PrismaService,
) { }
async createUserWithPassword(dto: RegisterUserRequestDTO) { async initializeUserWithEmail(email: string) {
try { try {
return await this.prisma.user.create({ return await this.prisma.client.user.create({
data: dto, data: {
email,
},
});
} catch (err) {
if (err instanceof Prisma.PrismaClientKnownRequestError) {
if (err.code === 'P2002') {
throw new ConflictException('User already exists');
}
} else throw err;
}
}
async createUserWithPassword(email: string, password: string) {
return await this.prisma.client.user.update({
where: {
email,
},
data: {
password,
status: USER_ACCOUNT_STATUS.active
},
});
}
async createUserAdditionalInformation(userId: string, dto: CompleteProfileSetupRequestDTO) {
const { password, ...rest } = dto;
try {
return await this.prisma.client.userAdditionalInformation.create({
data: {
userId,
...rest
},
}); });
} catch (err) { } catch (err) {
if (err instanceof Prisma.PrismaClientKnownRequestError) { if (err instanceof Prisma.PrismaClientKnownRequestError) {
@@ -22,14 +56,14 @@ export class UserService {
} }
async findUserForAuth(email: string) { async findUserForAuth(email: string) {
return await this.prisma.user.findUnique({ return await this.prisma.client.user.findUnique({
where: { email }, where: { email },
omit: { password: false }, // Password is omitted by default, we are just reverting it omit: { password: false }, // Password is omitted by default, we are just reverting it
}); });
} }
async findById(id: string) { async findById(id: string) {
return await this.prisma.user.findUnique({ return await this.prisma.client.user.findUnique({
where: { where: {
id: id, id: id,
}, },
@@ -37,7 +71,7 @@ export class UserService {
} }
async findByEmail(email: string) { async findByEmail(email: string) {
return await this.prisma.user.findUnique({ return await this.prisma.client.user.findUnique({
where: { where: {
email: email, email: email,
}, },
@@ -45,9 +79,47 @@ export class UserService {
} }
async updateRefreshToken(id: string, refreshToken: string) { async updateRefreshToken(id: string, refreshToken: string) {
return await this.prisma.user.update({ return await this.prisma.client.user.update({
where: { id }, where: { id },
data: { refreshToken }, data: { refreshToken },
}); });
} }
/*
* USER OTP SERVICES
* */
async findByEmailInOTP(email: string) {
return await this.prisma.client.userOTP.findUnique({
where: {
email,
},
});
}
async removeByEmailInOTP(email: string) {
return await this.prisma.client.userOTP.delete({
where: {
email
}
})
}
async updateOTPByEmail(email: string, otp: number) {
return await this.prisma.client.userOTP.upsert({
where: {
email
},
create: {
email,
otp,
createdAt: new Date(),
expiresAt: new Date(Date.now() + 5 * 60 * 1000)
},
update: {
otp,
createdAt: new Date(),
expiresAt: new Date(Date.now() + 5 * 60 * 1000)
}
})
}
} }