server side asset rendering example, totp challenge start

This commit is contained in:
Evert Prants 2023-08-14 21:56:11 +03:00
parent ae51916e06
commit 048775899b
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
21 changed files with 767 additions and 89 deletions

View File

@ -3,19 +3,35 @@ import { AuthService } from './services/auth.service';
import { MessagePattern } from '@nestjs/microservices'; import { MessagePattern } from '@nestjs/microservices';
import { LoginRequest } from './interfaces/auth.interface'; import { LoginRequest } from './interfaces/auth.interface';
import { UserInfo } from '@freeblox/shared'; import { UserInfo } from '@freeblox/shared';
import { AuthChallenge } from './enums/challenge.enum';
@Controller() @Controller()
export class AuthController { export class AuthController {
constructor(private readonly authService: AuthService) {} constructor(private readonly authService: AuthService) {}
@MessagePattern('auth.login') @MessagePattern('auth.login')
login({ body }: { body: LoginRequest }) { login({ body, ip }: { body: LoginRequest; ip: string }) {
return this.authService.login(body); return this.authService.login(body, ip);
} }
@MessagePattern('auth.loginByRefreshToken') @MessagePattern('auth.loginByRefreshToken')
loginByRefreshToken({ token }: { token: string }) { loginByRefreshToken({ token, ip }: { token: string; ip: string }) {
return this.authService.loginByRefreshToken(token); return this.authService.loginByRefreshToken(token, ip);
}
@MessagePattern('auth.loginByChallenge')
loginByChallenge({
challenge,
secret,
body,
ip,
}: {
challenge: AuthChallenge;
secret: string;
body: Record<string, string>;
ip: string;
}) {
return this.authService.loginByChallenge(challenge, secret, body, ip);
} }
@MessagePattern('auth.verify') @MessagePattern('auth.verify')

View File

@ -2,7 +2,13 @@ import { Module, OnModuleInit } from '@nestjs/common';
import { AuthController } from './auth.controller'; import { AuthController } from './auth.controller';
import { AuthService } from './services/auth.service'; import { AuthService } from './services/auth.service';
import { ClientsModule } from '@nestjs/microservices'; import { ClientsModule } from '@nestjs/microservices';
import { makeKnex, makeTypeOrm, natsClient } from '@freeblox/shared'; import {
getCacheManager,
getTypeOrm,
makeKnex,
makeTypeOrm,
natsClient,
} from '@freeblox/shared';
import { ConfigModule, ConfigService } from '@nestjs/config'; import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm'; import { TypeOrmModule } from '@nestjs/typeorm';
import knex from 'knex'; import knex from 'knex';
@ -33,14 +39,8 @@ const entities = [
ignoreEnvFile: process.env.NODE_ENV === 'development', ignoreEnvFile: process.env.NODE_ENV === 'development',
load: [makeKnex('auth', __dirname), makeTypeOrm('auth'), security], load: [makeKnex('auth', __dirname), makeTypeOrm('auth'), security],
}), }),
TypeOrmModule.forRootAsync({ getTypeOrm(entities),
imports: [ConfigModule], getCacheManager(),
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
...config.get('typeorm'),
entities,
}),
}),
TypeOrmModule.forFeature(entities), TypeOrmModule.forFeature(entities),
ClientsModule.register([natsClient('auth')]), ClientsModule.register([natsClient('auth')]),
], ],

View File

@ -0,0 +1,3 @@
export enum AuthChallenge {
OTP = 'OTP',
}

View File

@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common'; import { Inject, Injectable } from '@nestjs/common';
import { LoginRequest } from '../interfaces/auth.interface'; import { LoginRequest } from '../interfaces/auth.interface';
import { JWTService } from './jwt.service'; import { JWTService } from './jwt.service';
import { ILike, Repository } from 'typeorm'; import { ILike, Repository } from 'typeorm';
@ -11,12 +11,15 @@ import { BanService } from './ban.service';
import { import {
BadRequestRpcException, BadRequestRpcException,
ForbiddenRpcException, ForbiddenRpcException,
PreconditionFailedRpcException,
UserInfo, UserInfo,
generateString,
} from '@freeblox/shared'; } from '@freeblox/shared';
import { RoleService } from './role.service'; import { RoleService } from './role.service';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { RefreshService } from './refresh.service'; import { RefreshService } from './refresh.service';
import { AuthChallenge } from '../enums/challenge.enum';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
@Injectable() @Injectable()
export class AuthService { export class AuthService {
@ -29,6 +32,7 @@ export class AuthService {
@InjectRepository(UserEntity) @InjectRepository(UserEntity)
private readonly userRepository: Repository<UserEntity>, private readonly userRepository: Repository<UserEntity>,
private readonly config: ConfigService, private readonly config: ConfigService,
@Inject(CACHE_MANAGER) private cache: Cache,
) {} ) {}
/** /**
@ -36,7 +40,7 @@ export class AuthService {
* @param body Username/email and password * @param body Username/email and password
* @returns JWT token * @returns JWT token
*/ */
async login(body: LoginRequest) { async login(body: LoginRequest, ip: string) {
if (!body.email || !body.password) { if (!body.email || !body.password) {
throw new BadRequestRpcException('Invalid username or password'); throw new BadRequestRpcException('Invalid username or password');
} }
@ -68,20 +72,9 @@ export class AuthService {
} }
// Check TOTP // Check TOTP
const userOTPToken = await this.otpService.getUserTOTP(userEntity); const userOTPToken = await this.otpService.userHasTOTP(userEntity);
if (userOTPToken) { if (userOTPToken) {
if (!body.totpToken) { return this.createOTPChallenge(userEntity);
throw new PreconditionFailedRpcException('TOTP Token required');
}
const validate = this.otpService.validateTOTP(
userOTPToken.token,
body.totpToken,
);
if (!validate) {
throw new ForbiddenRpcException('Invalid TOTP Token');
}
} }
// Issue access token // Issue access token
@ -100,13 +93,104 @@ export class AuthService {
); );
return { return {
token: issuedToken, challenge: null,
refresh: refreshToken, challengeSecret: null,
expires_in: exp, authResult: {
token: issuedToken,
refresh: refreshToken,
expires_in: exp,
},
}; };
} }
async loginByRefreshToken(token: string) { /**
* Login by challenge.
* @param challenge Challenge type
* @param token Challenge secret
* @param response Challenge response from user
* @returns Authentication result or another challenge
*/
async loginByChallenge(
challenge: AuthChallenge,
token: string,
response: Record<string, string>,
ip: string,
) {
const decrypted = await this.jwtService.decrypt(token);
const tokenKey = `chlg:${challenge}:${decrypted.token}`;
const challengeSubject = await this.cache.get<string>(tokenKey);
// Invalid token
if (!challengeSubject) {
throw new ForbiddenRpcException('Invalid challenge response');
}
// Wrong subject, somehow..
if (challengeSubject !== decrypted.sub) {
await this.cache.del(tokenKey);
throw new ForbiddenRpcException('Invalid challenge response');
}
const loginUser = await this.userRepository.findOneByOrFail({
id: challengeSubject,
});
// TOTP verification login
if (challenge === AuthChallenge.OTP) {
// If no code is provided, assume request is incorrect
// and delete the challenge from cache.
if (!response.code) {
await this.cache.del(tokenKey);
throw new ForbiddenRpcException('Invalid challenge response');
}
const userOTPToken = await this.otpService.getUserTOTP(loginUser);
// User does not actually have TOTP?
if (!userOTPToken) {
await this.cache.del(tokenKey);
throw new ForbiddenRpcException('Invalid challenge response');
}
const validate = this.otpService.validateTOTP(
userOTPToken.token,
response.code,
);
// Here we do not delete from the cache, let the user retry.
if (!validate) {
throw new ForbiddenRpcException('Invalid challenge response');
}
} else {
await this.cache.del(tokenKey);
throw new ForbiddenRpcException('Invalid challenge');
}
await this.cache.del(tokenKey);
// Issue access and refresh token
const exp = this.config.get('security.jwtTokenExpiry');
const issuedToken = await this.issueAccessToken(loginUser);
const refreshToken = await this.refreshService.issueRefreshToken(loginUser);
// Set login time to now
await this.userRepository.update(
{ id: loginUser.id },
{ loginAt: new Date() },
);
return {
challenge: null,
challengeSecret: null,
authResult: {
token: issuedToken,
refresh: refreshToken,
expires_in: exp,
},
};
}
async loginByRefreshToken(token: string, ip: string) {
const refreshToken = await this.refreshService.useRefreshToken(token); const refreshToken = await this.refreshService.useRefreshToken(token);
const userEntity = refreshToken.user; const userEntity = refreshToken.user;
@ -121,9 +205,13 @@ export class AuthService {
); );
return { return {
token: issuedToken, challenge: null,
refresh: refreshToken.token, challengeSecret: null,
expires_in: exp, authResult: {
token: issuedToken,
refresh: refreshToken.token,
expires_in: exp,
},
}; };
} }
@ -193,21 +281,51 @@ export class AuthService {
(privileges, ban) => [...privileges, ...(ban.privileges || [])], (privileges, ban) => [...privileges, ...(ban.privileges || [])],
[], [],
); );
const privileges = await this.roleService.getUserPrivileges(
const userPrivileges = await this.roleService.getUserPrivileges(
user, user,
bannedPrivileges, bannedPrivileges,
); );
// If we only have privilege bans, only restrict those privileges.
// If we have a system ban, only return the web privilege.
const privileges =
!banned || bans.every((ban) => ban.privilegeBan)
? userPrivileges
: ['web'];
// Issue new token // Issue new token
return this.jwtService.sign({ return this.jwtService.sign({
sub: user.id, sub: user.id,
username: user.username, username: user.username,
display_name: user.displayName, display_name: user.displayName,
language: user.language, language: user.language,
banned: banned, banned,
privileges: banned privileges,
? []
: privileges.map((privilege) => privilege.privilege),
}); });
} }
/**
* Create OTP challenge for user's login.
* @private
* @param userEntity User
* @returns Challenge response
*/
async createOTPChallenge(userEntity: UserEntity) {
// Create challenge for auth.
const challengeToken = generateString(256);
const tokenKey = `chlg:${AuthChallenge.OTP}:${challengeToken}`;
const encryptedToken = await this.jwtService.encrypt({
token: challengeToken,
sub: userEntity.id,
});
// Challenge is only valid for 5 minutes.
await this.cache.set(tokenKey, userEntity.id, 300000);
return {
challenge: AuthChallenge.OTP,
challengeSecret: encryptedToken,
authResult: null,
};
}
} }

View File

@ -7,10 +7,15 @@ import { AuthModule } from './services/auth/auth.module';
import { CatalogModule } from './services/catalog/catalog.module'; import { CatalogModule } from './services/catalog/catalog.module';
import { UserMiddleware } from './middleware/user.middleware'; import { UserMiddleware } from './middleware/user.middleware';
import { AssetsModule } from './services/assets/assets.module'; import { AssetsModule } from './services/assets/assets.module';
import { ThrottlerModule } from '@nestjs/throttler';
@Module({ @Module({
imports: [ imports: [
ClientsModule.register([natsClient('auth')]), ClientsModule.register([natsClient('auth')]),
ThrottlerModule.forRoot({
ttl: 60,
limit: 10,
}),
AuthModule, AuthModule,
CatalogModule, CatalogModule,
AssetsModule, AssetsModule,

View File

@ -4,6 +4,7 @@ import {
Controller, Controller,
Get, Get,
Inject, Inject,
Ip,
Post, Post,
UseGuards, UseGuards,
UseInterceptors, UseInterceptors,
@ -21,8 +22,10 @@ import { UserInfo } from '@freeblox/shared';
import { lastValueFrom } from 'rxjs'; import { lastValueFrom } from 'rxjs';
import { AuthGuard } from '../../guards/auth.guard'; import { AuthGuard } from '../../guards/auth.guard';
import { UserDto } from './dtos/user.dto'; import { UserDto } from './dtos/user.dto';
import { LoginResponseDto } from './dtos/login-response.dto'; import { ChallengeResponseDto } from './dtos/challenge-response.dto';
import { LoginByRefreshTokenDto } from './dtos/login-refresh-token.dto'; import { LoginByRefreshTokenDto } from './dtos/login-refresh-token.dto';
import { ChallengeRequestDto } from './dtos/challenge-request.dto';
import { Throttle } from '@nestjs/throttler';
@Controller({ @Controller({
version: '1', version: '1',
@ -35,17 +38,35 @@ export class AuthController {
constructor(@Inject('auth') private auth: ClientProxy) {} constructor(@Inject('auth') private auth: ClientProxy) {}
@Post('login') @Post('login')
@Throttle(3, 60)
@ApiOperation({ summary: 'Login by username or email and password' }) @ApiOperation({ summary: 'Login by username or email and password' })
@ApiOkResponse({ type: LoginResponseDto }) @ApiOkResponse({ type: ChallengeResponseDto })
async login(@Body() body: LoginDto) { async login(@Body() body: LoginDto, @Ip() ip: string) {
return this.auth.send('auth.login', { body }); return this.auth.send('auth.login', { body, ip });
}
@Post('challenge')
@Throttle(3, 60)
@ApiOperation({ summary: 'Login by challenge' })
@ApiOkResponse({ type: ChallengeResponseDto })
async challenge(@Body() body: ChallengeRequestDto, @Ip() ip: string) {
return this.auth.send('auth.loginByChallenge', {
challenge: body.challenge,
secret: body.secret,
body: body.body,
ip,
});
} }
@Post('refresh') @Post('refresh')
@Throttle(3, 60)
@ApiOperation({ summary: 'Login by refresh token' }) @ApiOperation({ summary: 'Login by refresh token' })
@ApiOkResponse({ type: LoginResponseDto }) @ApiOkResponse({ type: ChallengeResponseDto })
async refresh(@Body() body: LoginByRefreshTokenDto) { async refresh(@Body() body: LoginByRefreshTokenDto, @Ip() ip: string) {
return this.auth.send('auth.loginByRefreshToken', { token: body.token }); return this.auth.send('auth.loginByRefreshToken', {
token: body.token,
ip,
});
} }
@Get('me') @Get('me')

View File

@ -0,0 +1,13 @@
import { ApiProperty } from '@nestjs/swagger';
import { AuthChallenge } from 'apps/auth/src/enums/challenge.enum';
export class ChallengeRequestDto {
@ApiProperty({ type: String, enum: AuthChallenge })
challenge: AuthChallenge;
@ApiProperty()
secret: string;
@ApiProperty()
body: Record<string, string>;
}

View File

@ -0,0 +1,24 @@
import { ApiProperty } from '@nestjs/swagger';
import { AuthChallenge } from '../../../../../auth/src/enums/challenge.enum';
export class AuthResultResponse {
@ApiProperty()
token: string;
@ApiProperty()
refresh: string;
@ApiProperty()
expires_in: number;
}
export class ChallengeResponseDto {
@ApiProperty({ type: String, enum: AuthChallenge, nullable: true })
challenge: AuthChallenge;
@ApiProperty({ nullable: true })
challengeSecret: string;
@ApiProperty({ type: AuthResultResponse, nullable: true })
authResult: AuthResultResponse;
}

View File

@ -1,12 +0,0 @@
import { ApiProperty } from '@nestjs/swagger';
export class LoginResponseDto {
@ApiProperty()
token: string;
@ApiProperty()
refresh: string;
@ApiProperty()
expires_in: number;
}

View File

@ -24,6 +24,7 @@ import { lastValueFrom } from 'rxjs';
import { CategoryResponseDto } from './dtos/category-response.dto'; import { CategoryResponseDto } from './dtos/category-response.dto';
import { ContentAssetDto } from './dtos/content-asset.dto'; import { ContentAssetDto } from './dtos/content-asset.dto';
import { RequirePrivileges } from '../../decorators/require-privileges.decorator'; import { RequirePrivileges } from '../../decorators/require-privileges.decorator';
import { Throttle } from '@nestjs/throttler';
@Controller({ @Controller({
version: '1', version: '1',
@ -42,6 +43,7 @@ export class CatalogController {
} }
@Post('content') @Post('content')
@Throttle(3, 60)
@ApiOperation({ summary: 'Create new content' }) @ApiOperation({ summary: 'Create new content' })
@ApiOkResponse({ type: ContentResponseDto }) @ApiOkResponse({ type: ContentResponseDto })
@RequirePrivileges('create:*', 'contentedit') @RequirePrivileges('create:*', 'contentedit')
@ -83,6 +85,7 @@ export class CatalogController {
} }
@Patch('content/:id') @Patch('content/:id')
@Throttle(3, 60)
@ApiOperation({ summary: 'Update content details' }) @ApiOperation({ summary: 'Update content details' })
@ApiOkResponse({ type: ContentResponseDto }) @ApiOkResponse({ type: ContentResponseDto })
@RequirePrivileges('create:*', 'contentedit') @RequirePrivileges('create:*', 'contentedit')
@ -95,6 +98,7 @@ export class CatalogController {
} }
@Post('content/:id/revision') @Post('content/:id/revision')
@Throttle(3, 60)
@ApiOperation({ @ApiOperation({
summary: 'Create a new revision (upload new content for item)', summary: 'Create a new revision (upload new content for item)',
}) })
@ -115,6 +119,7 @@ export class CatalogController {
} }
@Patch('content/:id/publish') @Patch('content/:id/publish')
@Throttle(3, 60)
@ApiOkResponse({ type: ContentResponseDto }) @ApiOkResponse({ type: ContentResponseDto })
@ApiOperation({ @ApiOperation({
summary: 'Publish content', summary: 'Publish content',
@ -129,4 +134,9 @@ export class CatalogController {
user, user,
}); });
} }
@Post('test')
async test() {
return this.catalog.send('render.assetid', {});
}
} }

View File

@ -1,7 +1,13 @@
import { Controller } from '@nestjs/common'; import { Controller } from '@nestjs/common';
import { RenderService } from './services/render.service'; import { RenderService } from './services/render.service';
import { MessagePattern } from '@nestjs/microservices';
@Controller() @Controller()
export class RenderController { export class RenderController {
constructor(private readonly renderService: RenderService) {} constructor(private readonly renderService: RenderService) {}
@MessagePattern('render.assetid')
async renderAsset({ id }: { id: string }) {
return this.renderService.render();
}
} }

View File

@ -0,0 +1,48 @@
import {
Engine,
EngineEvents,
EnvironmentComponent,
EventEmitter,
LevelComponent,
ViewportComponent,
WebGLRenderer,
instanceCharacterObject,
} from '@freeblox/engine';
import { Vector2, Vector3 } from 'three';
export class BarebonesRenderer extends Engine {
public events = new EventEmitter<EngineEvents>();
override mount(element: HTMLElement): void {
this.element = element;
this.render = new WebGLRenderer(element, new Vector2(800, 800), {
alpha: true,
});
this.render.renderer.autoClear = false;
this.use(ViewportComponent);
this.use(EnvironmentComponent);
this.use(LevelComponent);
this.getComponent(ViewportComponent).setSize(800, 800);
}
}
(async function () {
const engine = new BarebonesRenderer();
const div = document.createElement('div');
document.body.appendChild(div);
document.body.style.margin = '0';
document.body.style.padding = '0';
engine.mount(div);
const level = engine.getComponent(LevelComponent);
const viewport = engine.getComponent(ViewportComponent);
const char = await instanceCharacterObject('test');
level.world.add(char);
viewport.camera.position.set(2, 6, 5);
viewport.camera.lookAt(new Vector3(0, 3.5, 0));
engine.render.renderer.setClearColor(0x000000, 0);
engine.render.render();
engine.stop();
})();

View File

@ -1,4 +1,53 @@
import { Injectable } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common';
import { readFileSync } from 'fs';
import { join } from 'path';
import puppeteer from 'puppeteer';
@Injectable() @Injectable()
export class RenderService {} export class RenderService {
private logger = new Logger(RenderService.name);
async render() {
const file = readFileSync(join(__dirname, 'renderer.js'), 'utf-8');
const browser = await puppeteer.launch({
headless: true,
args: [
'--use-gl=swiftshader',
'--no-sandbox',
'--enable-surface-synchronization',
],
});
const page = await browser.newPage();
await page.setViewport({ width: 800, height: 800 });
page
.on('console', (message) =>
this.logger.log(`${message.type().toUpperCase()} ${message.text()}`),
)
.on('pageerror', ({ message }) => this.logger.log(message))
.on('response', (response) =>
this.logger.log(`${response.status()} ${response.url()}`),
)
.on('requestfailed', (request) =>
this.logger.log(`${request.failure().errorText} ${request.url()}`),
);
await page.setContent(
`<html><body><script type="application/javascript">${file}</script></body></html>`,
{
waitUntil: ['load', 'networkidle0'],
},
);
const picture = await page.screenshot({
encoding: 'base64',
omitBackground: true,
});
await browser.close();
return picture;
}
}

View File

@ -21,6 +21,13 @@ services:
- ./docker/postgres:/docker-entrypoint-initdb.d - ./docker/postgres:/docker-entrypoint-initdb.d
networks: networks:
- fblx - fblx
redis:
container_name: fblx-redis
image: redis:7-alpine
volumes:
- fblx-redis:/data
networks:
- fblx
auth: auth:
container_name: fblx-auth container_name: fblx-auth
build: build:
@ -28,6 +35,10 @@ services:
dockerfile: Dockerfile.dev dockerfile: Dockerfile.dev
args: args:
- SERVICE=auth - SERVICE=auth
depends_on:
- nats
- postgres
- redis
networks: networks:
- fblx - fblx
environment: environment:
@ -49,6 +60,10 @@ services:
dockerfile: Dockerfile.dev dockerfile: Dockerfile.dev
args: args:
- SERVICE=catalog - SERVICE=catalog
depends_on:
- nats
- postgres
- redis
networks: networks:
- fblx - fblx
environment: environment:
@ -66,6 +81,10 @@ services:
dockerfile: Dockerfile.dev dockerfile: Dockerfile.dev
args: args:
- SERVICE=game - SERVICE=game
depends_on:
- nats
- postgres
- redis
networks: networks:
- fblx - fblx
environment: environment:
@ -83,6 +102,10 @@ services:
dockerfile: Dockerfile.dev dockerfile: Dockerfile.dev
args: args:
- SERVICE=player - SERVICE=player
depends_on:
- nats
- postgres
- redis
networks: networks:
- fblx - fblx
environment: environment:
@ -100,6 +123,10 @@ services:
dockerfile: Dockerfile.dev dockerfile: Dockerfile.dev
args: args:
- SERVICE=server - SERVICE=server
depends_on:
- nats
- postgres
- redis
networks: networks:
- fblx - fblx
environment: environment:
@ -117,6 +144,10 @@ services:
dockerfile: Dockerfile.dev dockerfile: Dockerfile.dev
args: args:
- SERVICE=session - SERVICE=session
depends_on:
- nats
- postgres
- redis
networks: networks:
- fblx - fblx
environment: environment:
@ -134,6 +165,10 @@ services:
dockerfile: Dockerfile.dev dockerfile: Dockerfile.dev
args: args:
- SERVICE=bank - SERVICE=bank
depends_on:
- nats
- postgres
- redis
networks: networks:
- fblx - fblx
environment: environment:
@ -151,6 +186,10 @@ services:
dockerfile: Dockerfile.dev dockerfile: Dockerfile.dev
args: args:
- SERVICE=assets - SERVICE=assets
depends_on:
- nats
- postgres
- redis
networks: networks:
- fblx - fblx
environment: environment:
@ -171,6 +210,9 @@ services:
build: build:
context: . context: .
dockerfile: Dockerfile.render.dev dockerfile: Dockerfile.render.dev
depends_on:
- nats
- redis
networks: networks:
- fblx - fblx
environment: environment:
@ -185,6 +227,8 @@ services:
dockerfile: Dockerfile.dev dockerfile: Dockerfile.dev
args: args:
- SERVICE=freeblox-web-service - SERVICE=freeblox-web-service
depends_on:
- nats
networks: networks:
- fblx - fblx
ports: ports:
@ -224,3 +268,4 @@ networks:
fblx: fblx:
volumes: volumes:
fblx-pgadmin: fblx-pgadmin:
fblx-redis:

14
libs/shared/src/cache/cache-manager.ts vendored Normal file
View File

@ -0,0 +1,14 @@
import { CacheModule } from '@nestjs/cache-manager';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { redisConfig } from './redis.provider';
import * as redisStore from 'cache-manager-redis-store';
export const getCacheManager = () =>
CacheModule.registerAsync({
imports: [ConfigModule, ConfigModule.forFeature(redisConfig)],
useFactory: (config) => ({
store: redisStore,
...config.get('redis'),
}),
inject: [ConfigService],
});

View File

@ -0,0 +1,6 @@
import { registerAs } from '@nestjs/config';
export const redisConfig = registerAs('redis', () => ({
host: String(process.env.REDIS_HOST || 'redis'),
port: Number(process.env.REDIS_PORT) || 6379,
}));

View File

@ -1,5 +1,5 @@
import { registerAs } from '@nestjs/config'; import { ConfigModule, ConfigService, registerAs } from '@nestjs/config';
import { TypeOrmModuleOptions } from '@nestjs/typeorm'; import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
export const makeTypeOrm = (database: string) => export const makeTypeOrm = (database: string) =>
registerAs( registerAs(
@ -14,3 +14,13 @@ export const makeTypeOrm = (database: string) =>
database, database,
} as TypeOrmModuleOptions), } as TypeOrmModuleOptions),
); );
export const getTypeOrm = (entities?: any[]) =>
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
...config.get('typeorm'),
entities,
}),
});

View File

@ -12,3 +12,5 @@ export * from './types/userinfo';
export * from './types/page-query.interface'; export * from './types/page-query.interface';
export * from './exception/rpc.exception'; export * from './exception/rpc.exception';
export * from './filters/rpc-exception.filter'; export * from './filters/rpc-exception.filter';
export * from './cache/redis.provider';
export * from './cache/cache-manager';

View File

@ -28,16 +28,22 @@
"@aws-sdk/s3-request-presigner": "^3.375.0", "@aws-sdk/s3-request-presigner": "^3.375.0",
"@aws-sdk/url-parser": "^3.374.0", "@aws-sdk/url-parser": "^3.374.0",
"@aws-sdk/util-format-url": "^3.370.0", "@aws-sdk/util-format-url": "^3.370.0",
"@freeblox/engine": "^0.0.4",
"@nestjs/axios": "^3.0.0", "@nestjs/axios": "^3.0.0",
"@nestjs/cache-manager": "^2.1.0",
"@nestjs/common": "^10.0.3", "@nestjs/common": "^10.0.3",
"@nestjs/config": "^3.0.0", "@nestjs/config": "^3.0.0",
"@nestjs/core": "^10.0.3", "@nestjs/core": "^10.0.3",
"@nestjs/microservices": "^10.0.3", "@nestjs/microservices": "^10.0.3",
"@nestjs/platform-express": "^10.0.3", "@nestjs/platform-express": "^10.0.3",
"@nestjs/schedule": "^3.0.1",
"@nestjs/swagger": "^7.0.11", "@nestjs/swagger": "^7.0.11",
"@nestjs/throttler": "^4.2.1",
"@nestjs/typeorm": "^10.0.0", "@nestjs/typeorm": "^10.0.0",
"axios": "^1.4.0", "axios": "^1.4.0",
"bcrypt": "^5.1.0", "bcrypt": "^5.1.0",
"cache-manager": "^5.2.3",
"cache-manager-redis-store": "^3.0.1",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.0", "class-validator": "^0.14.0",
"jose": "^4.14.4", "jose": "^4.14.4",
@ -53,13 +59,15 @@
"rxjs": "^7.8.1", "rxjs": "^7.8.1",
"three": "^0.154.0", "three": "^0.154.0",
"typeorm": "^0.3.17", "typeorm": "^0.3.17",
"uuid": "^9.0.0" "uuid": "^9.0.0",
"webpack-merge": "^5.9.0"
}, },
"devDependencies": { "devDependencies": {
"@nestjs/cli": "^10.0.5", "@nestjs/cli": "^10.0.5",
"@nestjs/schematics": "^10.0.1", "@nestjs/schematics": "^10.0.1",
"@nestjs/testing": "^10.0.3", "@nestjs/testing": "^10.0.3",
"@types/bcrypt": "^5.0.0", "@types/bcrypt": "^5.0.0",
"@types/cron": "^2.0.1",
"@types/express": "^4.17.17", "@types/express": "^4.17.17",
"@types/jest": "29.5.2", "@types/jest": "29.5.2",
"@types/multer": "^1.4.7", "@types/multer": "^1.4.7",
@ -106,4 +114,4 @@
"^@freeblox/shared(|/.*)$": "<rootDir>/libs/shared/src/$1" "^@freeblox/shared(|/.*)$": "<rootDir>/libs/shared/src/$1"
} }
} }
} }

View File

@ -26,9 +26,15 @@ dependencies:
'@aws-sdk/util-format-url': '@aws-sdk/util-format-url':
specifier: ^3.370.0 specifier: ^3.370.0
version: 3.370.0 version: 3.370.0
'@freeblox/engine':
specifier: ^0.0.4
version: 0.0.4
'@nestjs/axios': '@nestjs/axios':
specifier: ^3.0.0 specifier: ^3.0.0
version: 3.0.0(@nestjs/common@10.0.3)(axios@1.4.0)(reflect-metadata@0.1.13)(rxjs@7.8.1) version: 3.0.0(@nestjs/common@10.0.3)(axios@1.4.0)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/cache-manager':
specifier: ^2.1.0
version: 2.1.0(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(cache-manager@5.2.3)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/common': '@nestjs/common':
specifier: ^10.0.3 specifier: ^10.0.3
version: 10.0.3(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1) version: 10.0.3(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1)
@ -40,13 +46,19 @@ dependencies:
version: 10.0.3(@nestjs/common@10.0.3)(@nestjs/microservices@10.0.3)(@nestjs/platform-express@10.0.3)(reflect-metadata@0.1.13)(rxjs@7.8.1) version: 10.0.3(@nestjs/common@10.0.3)(@nestjs/microservices@10.0.3)(@nestjs/platform-express@10.0.3)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/microservices': '@nestjs/microservices':
specifier: ^10.0.3 specifier: ^10.0.3
version: 10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(nats@2.15.1)(reflect-metadata@0.1.13)(rxjs@7.8.1) version: 10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(cache-manager@5.2.3)(nats@2.15.1)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/platform-express': '@nestjs/platform-express':
specifier: ^10.0.3 specifier: ^10.0.3
version: 10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3) version: 10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)
'@nestjs/schedule':
specifier: ^3.0.1
version: 3.0.1(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(reflect-metadata@0.1.13)
'@nestjs/swagger': '@nestjs/swagger':
specifier: ^7.0.11 specifier: ^7.0.11
version: 7.0.11(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13) version: 7.0.11(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)
'@nestjs/throttler':
specifier: ^4.2.1
version: 4.2.1(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(reflect-metadata@0.1.13)
'@nestjs/typeorm': '@nestjs/typeorm':
specifier: ^10.0.0 specifier: ^10.0.0
version: 10.0.0(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(reflect-metadata@0.1.13)(rxjs@7.8.1)(typeorm@0.3.17) version: 10.0.0(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(reflect-metadata@0.1.13)(rxjs@7.8.1)(typeorm@0.3.17)
@ -56,6 +68,12 @@ dependencies:
bcrypt: bcrypt:
specifier: ^5.1.0 specifier: ^5.1.0
version: 5.1.0 version: 5.1.0
cache-manager:
specifier: ^5.2.3
version: 5.2.3
cache-manager-redis-store:
specifier: ^3.0.1
version: 3.0.1
class-transformer: class-transformer:
specifier: ^0.5.1 specifier: ^0.5.1
version: 0.5.1 version: 0.5.1
@ -104,6 +122,9 @@ dependencies:
uuid: uuid:
specifier: ^9.0.0 specifier: ^9.0.0
version: 9.0.0 version: 9.0.0
webpack-merge:
specifier: ^5.9.0
version: 5.9.0
devDependencies: devDependencies:
'@nestjs/cli': '@nestjs/cli':
@ -118,6 +139,9 @@ devDependencies:
'@types/bcrypt': '@types/bcrypt':
specifier: ^5.0.0 specifier: ^5.0.0
version: 5.0.0 version: 5.0.0
'@types/cron':
specifier: ^2.0.1
version: 2.0.1
'@types/express': '@types/express':
specifier: ^4.17.17 specifier: ^4.17.17
version: 4.17.17 version: 4.17.17
@ -1300,6 +1324,10 @@ packages:
dependencies: dependencies:
'@jridgewell/trace-mapping': 0.3.9 '@jridgewell/trace-mapping': 0.3.9
/@dimforge/rapier3d@0.11.2:
resolution: {integrity: sha512-B+AKkPmtJxED3goMTGU8v0ju8hUAUQGLgghzCos4G4OeN9X+mJ5lfN2xtNA0n8tJRJk2YfsMk9BOj/6AN89Acg==}
dev: false
/@eslint-community/eslint-utils@4.4.0(eslint@8.43.0): /@eslint-community/eslint-utils@4.4.0(eslint@8.43.0):
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -1337,6 +1365,17 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true dev: true
/@freeblox/engine@0.0.4:
resolution: {integrity: sha512-faxtovSxW6hHNgpOdPeRTYuZk01LiHt8hZA8Vp6cBkdbBMP8jmXBXX/ADFTLv/v9GBXK2DBLbmeZhZ0R46imwg==, tarball: https://git.icynet.eu/api/packages/freeblox/npm/%40freeblox%2Fengine/-/0.0.4/engine-0.0.4.tgz}
dependencies:
'@dimforge/rapier3d': 0.11.2
buffer: 6.0.3
reflect-metadata: 0.1.13
smart-buffer: 4.2.0
three: 0.153.0
uuid: 9.0.0
dev: false
/@humanwhocodes/config-array@0.11.10: /@humanwhocodes/config-array@0.11.10:
resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==} resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==}
engines: {node: '>=10.10.0'} engines: {node: '>=10.10.0'}
@ -1683,6 +1722,22 @@ packages:
rxjs: 7.8.1 rxjs: 7.8.1
dev: false dev: false
/@nestjs/cache-manager@2.1.0(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(cache-manager@5.2.3)(reflect-metadata@0.1.13)(rxjs@7.8.1):
resolution: {integrity: sha512-9kep3a8Mq5cMuXN/anGhSYc0P48CRBXk5wyJJRBFxhNkCH8AIzZF4CASGVDIEMmm3OjVcEUHojjyJwCODS17Qw==}
peerDependencies:
'@nestjs/common': ^9.0.0 || ^10.0.0
'@nestjs/core': ^9.0.0 || ^10.0.0
cache-manager: <=5
reflect-metadata: ^0.1.12
rxjs: ^7.0.0
dependencies:
'@nestjs/common': 10.0.3(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/core': 10.0.3(@nestjs/common@10.0.3)(@nestjs/microservices@10.0.3)(@nestjs/platform-express@10.0.3)(reflect-metadata@0.1.13)(rxjs@7.8.1)
cache-manager: 5.2.3
reflect-metadata: 0.1.13
rxjs: 7.8.1
dev: false
/@nestjs/cli@10.0.5: /@nestjs/cli@10.0.5:
resolution: {integrity: sha512-Btc1lzAkm4j+af9YA0Kv+6N2x7vDneEhsozzEp87kHZrONYNS8zg/SBFTRx5b/e6g0MJshv6vP56PVrdNZy3kA==} resolution: {integrity: sha512-Btc1lzAkm4j+af9YA0Kv+6N2x7vDneEhsozzEp87kHZrONYNS8zg/SBFTRx5b/e6g0MJshv6vP56PVrdNZy3kA==}
engines: {node: '>= 16'} engines: {node: '>= 16'}
@ -1778,7 +1833,7 @@ packages:
optional: true optional: true
dependencies: dependencies:
'@nestjs/common': 10.0.3(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nestjs/common': 10.0.3(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/microservices': 10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(nats@2.15.1)(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nestjs/microservices': 10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(cache-manager@5.2.3)(nats@2.15.1)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/platform-express': 10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3) '@nestjs/platform-express': 10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)
'@nuxtjs/opencollective': 0.3.2 '@nuxtjs/opencollective': 0.3.2
fast-safe-stringify: 2.1.1 fast-safe-stringify: 2.1.1
@ -1810,7 +1865,7 @@ packages:
reflect-metadata: 0.1.13 reflect-metadata: 0.1.13
dev: false dev: false
/@nestjs/microservices@10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(nats@2.15.1)(reflect-metadata@0.1.13)(rxjs@7.8.1): /@nestjs/microservices@10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(cache-manager@5.2.3)(nats@2.15.1)(reflect-metadata@0.1.13)(rxjs@7.8.1):
resolution: {integrity: sha512-ySAdASLA2FLD0ScEmAHObNsg/IdnG4pYXWxQKLO3co3CAAwHCjF0D4kI2SeegBx89KU0D1wPLvLYzRI0pXh4jQ==} resolution: {integrity: sha512-ySAdASLA2FLD0ScEmAHObNsg/IdnG4pYXWxQKLO3co3CAAwHCjF0D4kI2SeegBx89KU0D1wPLvLYzRI0pXh4jQ==}
peerDependencies: peerDependencies:
'@grpc/grpc-js': '*' '@grpc/grpc-js': '*'
@ -1848,6 +1903,7 @@ packages:
dependencies: dependencies:
'@nestjs/common': 10.0.3(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nestjs/common': 10.0.3(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/core': 10.0.3(@nestjs/common@10.0.3)(@nestjs/microservices@10.0.3)(@nestjs/platform-express@10.0.3)(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nestjs/core': 10.0.3(@nestjs/common@10.0.3)(@nestjs/microservices@10.0.3)(@nestjs/platform-express@10.0.3)(reflect-metadata@0.1.13)(rxjs@7.8.1)
cache-manager: 5.2.3
iterare: 1.2.1 iterare: 1.2.1
nats: 2.15.1 nats: 2.15.1
reflect-metadata: 0.1.13 reflect-metadata: 0.1.13
@ -1870,6 +1926,20 @@ packages:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
/@nestjs/schedule@3.0.1(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(reflect-metadata@0.1.13):
resolution: {integrity: sha512-4CAFu4rE/QPYnz/icRg3GiuLmY1bXopG8bWTJ9d7bXzaHBaPKIjGvZ20wsK8P+MncrVCkmK0iYhQrNj0cwX9+A==}
peerDependencies:
'@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0
'@nestjs/core': ^8.0.0 || ^9.0.0 || ^10.0.0
reflect-metadata: ^0.1.12
dependencies:
'@nestjs/common': 10.0.3(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/core': 10.0.3(@nestjs/common@10.0.3)(@nestjs/microservices@10.0.3)(@nestjs/platform-express@10.0.3)(reflect-metadata@0.1.13)(rxjs@7.8.1)
cron: 2.3.1
reflect-metadata: 0.1.13
uuid: 9.0.0
dev: false
/@nestjs/schematics@10.0.1(chokidar@3.5.3)(typescript@5.1.3): /@nestjs/schematics@10.0.1(chokidar@3.5.3)(typescript@5.1.3):
resolution: {integrity: sha512-buxpYtSwOmWyf0nUJWJCkCkYITwbOfIEKHTnGS7sDbcfaajrOFXb5pPAGD2E1CUb3C1+NkQIURPKzs0IouZTQg==} resolution: {integrity: sha512-buxpYtSwOmWyf0nUJWJCkCkYITwbOfIEKHTnGS7sDbcfaajrOFXb5pPAGD2E1CUb3C1+NkQIURPKzs0IouZTQg==}
peerDependencies: peerDependencies:
@ -1929,11 +1999,24 @@ packages:
dependencies: dependencies:
'@nestjs/common': 10.0.3(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nestjs/common': 10.0.3(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/core': 10.0.3(@nestjs/common@10.0.3)(@nestjs/microservices@10.0.3)(@nestjs/platform-express@10.0.3)(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nestjs/core': 10.0.3(@nestjs/common@10.0.3)(@nestjs/microservices@10.0.3)(@nestjs/platform-express@10.0.3)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/microservices': 10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(nats@2.15.1)(reflect-metadata@0.1.13)(rxjs@7.8.1) '@nestjs/microservices': 10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(cache-manager@5.2.3)(nats@2.15.1)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/platform-express': 10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3) '@nestjs/platform-express': 10.0.3(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)
tslib: 2.5.3 tslib: 2.5.3
dev: true dev: true
/@nestjs/throttler@4.2.1(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(reflect-metadata@0.1.13):
resolution: {integrity: sha512-wVPMuIyr0KdrK1RVVQceWVNesogCm9IgYC1V5EkaTZ+usIE4qxEyzdwU5IqQLgOO/Loiq98MLwReDxazX7i9Uw==}
peerDependencies:
'@nestjs/common': ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0
'@nestjs/core': ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0
reflect-metadata: ^0.1.13
dependencies:
'@nestjs/common': 10.0.3(class-transformer@0.5.1)(class-validator@0.14.0)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/core': 10.0.3(@nestjs/common@10.0.3)(@nestjs/microservices@10.0.3)(@nestjs/platform-express@10.0.3)(reflect-metadata@0.1.13)(rxjs@7.8.1)
md5: 2.3.0
reflect-metadata: 0.1.13
dev: false
/@nestjs/typeorm@10.0.0(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(reflect-metadata@0.1.13)(rxjs@7.8.1)(typeorm@0.3.17): /@nestjs/typeorm@10.0.0(@nestjs/common@10.0.3)(@nestjs/core@10.0.3)(reflect-metadata@0.1.13)(rxjs@7.8.1)(typeorm@0.3.17):
resolution: {integrity: sha512-WQU4HCDTz4UavsFzvGUKDHqi0MO5K47yFoPXdmh+Z/hCNO7SHCMmV9jLiLukM8n5nKUqJ3jDqiljkWBcZPdCtA==} resolution: {integrity: sha512-WQU4HCDTz4UavsFzvGUKDHqi0MO5K47yFoPXdmh+Z/hCNO7SHCMmV9jLiLukM8n5nKUqJ3jDqiljkWBcZPdCtA==}
peerDependencies: peerDependencies:
@ -2044,6 +2127,55 @@ packages:
- supports-color - supports-color
dev: false dev: false
/@redis/bloom@1.2.0(@redis/client@1.5.8):
resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==}
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': 1.5.8
dev: false
/@redis/client@1.5.8:
resolution: {integrity: sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw==}
engines: {node: '>=14'}
dependencies:
cluster-key-slot: 1.1.2
generic-pool: 3.9.0
yallist: 4.0.0
dev: false
/@redis/graph@1.1.0(@redis/client@1.5.8):
resolution: {integrity: sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==}
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': 1.5.8
dev: false
/@redis/json@1.0.4(@redis/client@1.5.8):
resolution: {integrity: sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==}
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': 1.5.8
dev: false
/@redis/search@1.1.3(@redis/client@1.5.8):
resolution: {integrity: sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng==}
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': 1.5.8
dev: false
/@redis/time-series@1.0.4(@redis/client@1.5.8):
resolution: {integrity: sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==}
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': 1.5.8
dev: false
/@sinclair/typebox@0.25.24: /@sinclair/typebox@0.25.24:
resolution: {integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==} resolution: {integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==}
dev: true dev: true
@ -2554,6 +2686,13 @@ packages:
resolution: {integrity: sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==} resolution: {integrity: sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==}
dev: true dev: true
/@types/cron@2.0.1:
resolution: {integrity: sha512-WHa/1rtNtD2Q/H0+YTTZoty+/5rcE66iAFX2IY+JuUoOACsevYyFkSYu/2vdw+G5LrmO7Lxowrqm0av4k3qWNQ==}
dependencies:
'@types/luxon': 3.3.1
'@types/node': 20.3.2
dev: true
/@types/eslint-scope@3.7.4: /@types/eslint-scope@3.7.4:
resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==} resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==}
dependencies: dependencies:
@ -2627,6 +2766,10 @@ packages:
resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==} resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
dev: true dev: true
/@types/luxon@3.3.1:
resolution: {integrity: sha512-XOS5nBcgEeP2PpcqJHjCWhUCAzGfXIU8ILOSLpx2FhxqMW9KdxgCGXNOEKGVBfveKtIpztHzKK5vSRVLyW/NqA==}
dev: true
/@types/mime@1.3.2: /@types/mime@1.3.2:
resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==} resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==}
dev: true dev: true
@ -3427,6 +3570,19 @@ packages:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
/cache-manager-redis-store@3.0.1:
resolution: {integrity: sha512-o560kw+dFqusC9lQJhcm6L2F2fMKobJ5af+FoR2PdnMVdpQ3f3Bz6qzvObTGyvoazQJxjQNWgMQeChP4vRTuXQ==}
engines: {node: '>= 16.18.0'}
dependencies:
redis: 4.6.7
dev: false
/cache-manager@5.2.3:
resolution: {integrity: sha512-9OErI8fksFkxAMJ8Mco0aiZSdphyd90HcKiOMJQncSlU1yq/9lHHxrT8PDayxrmr9IIIZPOAEfXuGSD7g29uog==}
dependencies:
lodash.clonedeep: 4.5.0
lru-cache: 9.1.2
/call-bind@1.0.2: /call-bind@1.0.2:
resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
dependencies: dependencies:
@ -3475,6 +3631,10 @@ packages:
resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==}
dev: true dev: true
/charenc@0.0.2:
resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
dev: false
/chokidar@3.5.3: /chokidar@3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'} engines: {node: '>= 8.10.0'}
@ -3583,11 +3743,25 @@ packages:
strip-ansi: 6.0.1 strip-ansi: 6.0.1
wrap-ansi: 7.0.0 wrap-ansi: 7.0.0
/clone-deep@4.0.1:
resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==}
engines: {node: '>=6'}
dependencies:
is-plain-object: 2.0.4
kind-of: 6.0.3
shallow-clone: 3.0.1
dev: false
/clone@1.0.4: /clone@1.0.4:
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
engines: {node: '>=0.8'} engines: {node: '>=0.8'}
dev: true dev: true
/cluster-key-slot@1.1.2:
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
engines: {node: '>=0.10.0'}
dev: false
/co@4.6.0: /co@4.6.0:
resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
@ -3740,6 +3914,12 @@ 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@2.3.1:
resolution: {integrity: sha512-1eRRlIT0UfIqauwbG9pkg3J6CX9A6My2ytJWqAXoK0T9oJnUZTzGBNPxao0zjodIbPgf8UQWjE62BMb9eVllSQ==}
dependencies:
luxon: 3.3.0
dev: false
/cross-fetch@4.0.0: /cross-fetch@4.0.0:
resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==} resolution: {integrity: sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==}
dependencies: dependencies:
@ -3756,6 +3936,10 @@ packages:
shebang-command: 2.0.0 shebang-command: 2.0.0
which: 2.0.2 which: 2.0.2
/crypt@0.0.2:
resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
dev: false
/data-uri-to-buffer@5.0.1: /data-uri-to-buffer@5.0.1:
resolution: {integrity: sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==} resolution: {integrity: sha512-a9l6T1qqDogvvnw0nKlfZzqsyikEBZBClF39V3TFoKhDtGBqHu2HkuomJc02j5zft8zrUaXEuoicLeW54RkzPg==}
engines: {node: '>= 14'} engines: {node: '>= 14'}
@ -4484,6 +4668,11 @@ packages:
wide-align: 1.1.5 wide-align: 1.1.5
dev: false dev: false
/generic-pool@3.9.0:
resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==}
engines: {node: '>= 4'}
dev: false
/gensync@1.0.0-beta.2: /gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
@ -4839,6 +5028,10 @@ packages:
binary-extensions: 2.2.0 binary-extensions: 2.2.0
dev: true dev: true
/is-buffer@1.1.6:
resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
dev: false
/is-core-module@2.12.1: /is-core-module@2.12.1:
resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==} resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==}
dependencies: dependencies:
@ -4880,6 +5073,13 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/is-plain-object@2.0.4:
resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
engines: {node: '>=0.10.0'}
dependencies:
isobject: 3.0.1
dev: false
/is-stream@2.0.1: /is-stream@2.0.1:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -4896,6 +5096,11 @@ packages:
/isexe@2.0.0: /isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
/isobject@3.0.1:
resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==}
engines: {node: '>=0.10.0'}
dev: false
/istanbul-lib-coverage@3.2.0: /istanbul-lib-coverage@3.2.0:
resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -5464,6 +5669,11 @@ packages:
safe-buffer: 5.2.1 safe-buffer: 5.2.1
dev: false dev: false
/kind-of@6.0.3:
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
engines: {node: '>=0.10.0'}
dev: false
/kleur@3.0.3: /kleur@3.0.3:
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -5558,6 +5768,9 @@ packages:
p-locate: 5.0.0 p-locate: 5.0.0
dev: true dev: true
/lodash.clonedeep@4.5.0:
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
/lodash.memoize@4.1.2: /lodash.memoize@4.1.2:
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
dev: true dev: true
@ -5598,6 +5811,15 @@ packages:
engines: {node: '>=12'} engines: {node: '>=12'}
dev: false dev: false
/lru-cache@9.1.2:
resolution: {integrity: sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==}
engines: {node: 14 || >=16.14}
/luxon@3.3.0:
resolution: {integrity: sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==}
engines: {node: '>=12'}
dev: false
/macos-release@2.5.1: /macos-release@2.5.1:
resolution: {integrity: sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==} resolution: {integrity: sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -5625,6 +5847,14 @@ packages:
tmpl: 1.0.5 tmpl: 1.0.5
dev: true dev: true
/md5@2.3.0:
resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
dependencies:
charenc: 0.0.2
crypt: 0.0.2
is-buffer: 1.1.6
dev: false
/media-typer@0.3.0: /media-typer@0.3.0:
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@ -6464,6 +6694,17 @@ packages:
resolve: 1.22.2 resolve: 1.22.2
dev: false dev: false
/redis@4.6.7:
resolution: {integrity: sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==}
dependencies:
'@redis/bloom': 1.2.0(@redis/client@1.5.8)
'@redis/client': 1.5.8
'@redis/graph': 1.1.0(@redis/client@1.5.8)
'@redis/json': 1.0.4(@redis/client@1.5.8)
'@redis/search': 1.1.3(@redis/client@1.5.8)
'@redis/time-series': 1.0.4(@redis/client@1.5.8)
dev: false
/reflect-metadata@0.1.13: /reflect-metadata@0.1.13:
resolution: {integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==} resolution: {integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==}
@ -6645,6 +6886,13 @@ packages:
safe-buffer: 5.2.1 safe-buffer: 5.2.1
dev: false dev: false
/shallow-clone@3.0.1:
resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==}
engines: {node: '>=8'}
dependencies:
kind-of: 6.0.3
dev: false
/shebang-command@2.0.0: /shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -7024,6 +7272,10 @@ packages:
engines: {node: '>=0.2.6'} engines: {node: '>=0.2.6'}
dev: false dev: false
/three@0.153.0:
resolution: {integrity: sha512-OCP2/uQR6GcDpSLnJt/3a4mdS0kNWcbfUXIwLoEMgLzEUIVIYsSDwskpmOii/AkDM+BBwrl6+CKgrjX9+E2aWg==}
dev: false
/three@0.154.0: /three@0.154.0:
resolution: {integrity: sha512-Uzz8C/5GesJzv8i+Y2prEMYUwodwZySPcNhuJUdsVMH2Yn4Nm8qlbQe6qRN5fOhg55XB0WiLfTPBxVHxpE60ug==} resolution: {integrity: sha512-Uzz8C/5GesJzv8i+Y2prEMYUwodwZySPcNhuJUdsVMH2Yn4Nm8qlbQe6qRN5fOhg55XB0WiLfTPBxVHxpE60ug==}
dev: false dev: false
@ -7416,6 +7668,14 @@ packages:
/webidl-conversions@3.0.1: /webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
/webpack-merge@5.9.0:
resolution: {integrity: sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg==}
engines: {node: '>=10.0.0'}
dependencies:
clone-deep: 4.0.1
wildcard: 2.0.1
dev: false
/webpack-node-externals@3.0.0: /webpack-node-externals@3.0.0:
resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==} resolution: {integrity: sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -7525,6 +7785,10 @@ packages:
string-width: 4.2.3 string-width: 4.2.3
dev: false dev: false
/wildcard@2.0.1:
resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==}
dev: false
/windows-release@4.0.0: /windows-release@4.0.0:
resolution: {integrity: sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg==} resolution: {integrity: sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg==}
engines: {node: '>=10'} engines: {node: '>=10'}

View File

@ -12,23 +12,51 @@ const writeGlobEntry = (pattern, to) => {
); );
}; };
module.exports = function (config) { const appName = process.argv[process.argv.length - 1];
const appName = process.argv[process.argv.length - 1];
config.entry = { const configs = [
main: path.join(__dirname, 'apps', appName, 'src', 'main.ts'), function (config) {
...writeGlobEntry( config.entry = {
path.resolve('apps', appName, 'src', 'database', 'migrations', '*.ts'), main: path.join(__dirname, 'apps', appName, 'src', 'main.ts'),
'database/migrations', ...writeGlobEntry(
), path.resolve('apps', appName, 'src', 'database', 'migrations', '*.ts'),
...writeGlobEntry( 'database/migrations',
path.resolve('apps', appName, 'src', 'database', 'seeds', '*.ts'), ),
'database/seeds', ...writeGlobEntry(
), path.resolve('apps', appName, 'src', 'database', 'seeds', '*.ts'),
'database/seeds',
),
};
config.output = {
path: `${__dirname}/dist/apps/${appName}`,
filename: '[name].js',
libraryTarget: 'commonjs',
};
return config;
},
];
if (appName === 'render') {
const config2 = {
entry: {
renderer:
appName === 'render'
? path.resolve('apps', appName, 'src', 'renderer', 'index.ts')
: undefined,
},
target: 'web',
externalsPresets: {},
externals: {
'@dimforge/rapier3d': 'RAPIER',
},
output: {
path: `${__dirname}/dist/apps/${appName}`,
filename: '[name].js',
libraryTarget: '',
},
}; };
config.output = { configs.push(config2);
path: `${__dirname}/dist/apps/${appName}`, }
filename: '[name].js',
libraryTarget: 'commonjs', module.exports = configs;
};
return config;
};