fix(i18n): delete local translations

This commit is contained in:
Amruth Pillai
2023-11-10 13:14:44 +01:00
parent d8c605d047
commit 48727be809
65 changed files with 143 additions and 70442 deletions

View File

@ -57,6 +57,10 @@ REDIS_URL=redis://default:password@localhost:6379
# Sentry (for error reporting, Optional)
# SENTRY_DSN=
# Crowdin (Optional)
CROWDIN_DISTRIBUTION_HASH=
CROWDIN_PERSONAL_TOKEN=
# GitHub (OAuth, Optional)
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=

View File

@ -10,20 +10,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Checkout Repository
uses: actions/checkout@v4.1.1
- name: crowdin action
- name: Sync Sources with Crowdin
uses: crowdin/github-action@v1
with:
upload_sources: true
create_pull_request: true
create_pull_request: false
upload_translations: false
download_translations: true
localization_branch_name: l10n
pull_request_base_branch_name: "v4"
pull_request_title: "New Translations"
pull_request_body: "There have been new translations added to the project. Please review and merge the changes made on Crowdin to help keep them in sync."
download_translations: false
env:
GITHUB_TOKEN: ${{ github.token }}

2
.gitignore vendored
View File

@ -48,4 +48,4 @@ libs/prisma
# Lingui Compiled Messages
apps/client/src/locales/_build/
apps/client/src/locales/**/*.js
apps/client/src/locales

View File

@ -1,6 +1,8 @@
import { i18n } from "@lingui/core";
import { t } from "@lingui/macro";
import { axios } from "./axios";
type Locale = "en-US" | "de-DE" | "zu-ZA";
export const defaultLocale = "en-US";
@ -20,7 +22,8 @@ export const getLocales = () => {
};
export async function dynamicActivate(locale: string) {
const { messages } = await import(`../locales/${locale}/messages.po`);
const response = await axios(`translation/${locale}`);
const messages = await response.data;
i18n.load(locale, messages);
i18n.activate(locale);

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

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

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

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

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

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

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

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

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

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

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

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

@ -14,6 +14,7 @@ import { MailModule } from "./mail/mail.module";
import { PrinterModule } from "./printer/printer.module";
import { ResumeModule } from "./resume/resume.module";
import { StorageModule } from "./storage/storage.module";
import { TranslationModule } from "./translation/translation.module";
import { UserModule } from "./user/user.module";
import { UtilsModule } from "./utils/utils.module";
@ -34,6 +35,7 @@ import { UtilsModule } from "./utils/utils.module";
ResumeModule,
StorageModule,
PrinterModule,
TranslationModule,
// Static Assets
ServeStaticModule.forRoot({

View File

@ -1,8 +1,6 @@
import { CacheModule as NestCacheModule } from "@nestjs/cache-manager";
import { Logger, Module } from "@nestjs/common";
import { Module } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { RedisModule } from "@songkeys/nestjs-redis";
import { redisStore } from "cache-manager-redis-yet";
import { Config } from "../config/schema";
@ -14,25 +12,6 @@ import { Config } from "../config/schema";
config: { url: configService.getOrThrow("REDIS_URL") },
}),
}),
NestCacheModule.registerAsync({
isGlobal: true,
inject: [ConfigService],
useFactory: async (configService: ConfigService<Config>) => {
const url = configService.get("REDIS_URL");
if (!url) {
Logger.warn(
"`REDIS_URL` was not set, using in-memory cache instead. This is not suitable for production.",
"CacheModule",
);
return {};
}
return { store: await redisStore({ url }) };
},
}),
],
})
export class CacheModule {}

View File

@ -42,6 +42,9 @@ export const configSchema = z.object({
// Sentry
SENTRY_DSN: z.string().url().startsWith("https://").optional(),
// Crowdin (Optional)
CROWDIN_DISTRIBUTION_HASH: z.string().optional(),
// GitHub (OAuth)
GITHUB_CLIENT_ID: z.string().optional(),
GITHUB_CLIENT_SECRET: z.string().optional(),

View File

@ -1,11 +1,11 @@
import { CacheInterceptor, CacheKey, CacheTTL } from "@nestjs/cache-manager";
import { Controller, Get, NotFoundException, UseInterceptors } from "@nestjs/common";
import { Controller, Get, NotFoundException } from "@nestjs/common";
import { ApiTags } from "@nestjs/swagger";
import { HealthCheck, HealthCheckService } from "@nestjs/terminus";
import { RedisService } from "@songkeys/nestjs-redis";
import { RedisHealthIndicator } from "@songkeys/nestjs-redis-health";
import { configSchema } from "../config/schema";
import { UtilsService } from "../utils/utils.service";
import { BrowserHealthIndicator } from "./browser.health";
import { DatabaseHealthIndicator } from "./database.health";
import { StorageHealthIndicator } from "./storage.health";
@ -20,14 +20,10 @@ export class HealthController {
private readonly storage: StorageHealthIndicator,
private readonly redisService: RedisService,
private readonly redis: RedisHealthIndicator,
private readonly utils: UtilsService,
) {}
@Get()
@HealthCheck()
@UseInterceptors(CacheInterceptor)
@CacheKey("health:check")
@CacheTTL(30000) // 30 seconds
check() {
private run() {
return this.health.check([
() => this.database.isHealthy(),
() => this.storage.isHealthy(),
@ -42,6 +38,12 @@ export class HealthController {
]);
}
@Get()
@HealthCheck()
check() {
return this.utils.getCachedOrSet(`health:check`, () => this.run(), 1000 * 30); // 30 seconds
}
@Get("environment")
environment() {
if (process.env.NODE_ENV === "production") throw new NotFoundException();

View File

@ -1,4 +1,3 @@
import { CacheInterceptor, CacheKey } from "@nestjs/cache-manager";
import {
BadRequestException,
Body,
@ -11,7 +10,6 @@ import {
Patch,
Post,
UseGuards,
UseInterceptors,
} from "@nestjs/common";
import { ApiTags } from "@nestjs/swagger";
import { User as UserEntity } from "@prisma/client";
@ -25,6 +23,7 @@ import { User } from "@/server/user/decorators/user.decorator";
import { OptionalGuard } from "../auth/guards/optional.guard";
import { TwoFactorGuard } from "../auth/guards/two-factor.guard";
import { ErrorMessage } from "../constants/error-message";
import { UtilsService } from "../utils/utils.service";
import { Resume } from "./decorators/resume.decorator";
import { ResumeGuard } from "./guards/resume.guard";
import { ResumeService } from "./resume.service";
@ -32,13 +31,18 @@ import { ResumeService } from "./resume.service";
@ApiTags("Resume")
@Controller("resume")
export class ResumeController {
constructor(private readonly resumeService: ResumeService) {}
constructor(
private readonly resumeService: ResumeService,
private readonly utils: UtilsService,
) {}
@Get("schema")
@UseInterceptors(CacheInterceptor)
@CacheKey("resume:schema")
async getSchema() {
return zodToJsonSchema(resumeDataSchema);
getSchema() {
return this.utils.getCachedOrSet(
`resume:schema`,
() => zodToJsonSchema(resumeDataSchema),
1000 * 60 * 60 * 24, // 24 hours
);
}
@Post()

View File

@ -1,12 +1,10 @@
import { CACHE_MANAGER } from "@nestjs/cache-manager";
import { BadRequestException, Inject, Injectable, Logger } from "@nestjs/common";
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
import { Prisma } from "@prisma/client";
import { CreateResumeDto, ImportResumeDto, ResumeDto, UpdateResumeDto } from "@reactive-resume/dto";
import { defaultResumeData, ResumeData } from "@reactive-resume/schema";
import type { DeepPartial } from "@reactive-resume/utils";
import { generateRandomName, kebabCase } from "@reactive-resume/utils";
import { RedisService } from "@songkeys/nestjs-redis";
import { Cache } from "cache-manager";
import deepmerge from "deepmerge";
import Redis from "ioredis";
import { PrismaService } from "nestjs-prisma";
@ -28,7 +26,6 @@ export class ResumeService {
private readonly storageService: StorageService,
private readonly redisService: RedisService,
private readonly utils: UtilsService,
@Inject(CACHE_MANAGER) private readonly cache: Cache,
) {
this.redis = this.redisService.getClient();
}
@ -54,8 +51,8 @@ export class ResumeService {
});
await Promise.all([
this.cache.del(`user:${userId}:resumes`),
this.cache.set(`user:${userId}:resume:${resume.id}`, resume),
this.redis.del(`user:${userId}:resumes`),
this.redis.set(`user:${userId}:resume:${resume.id}`, JSON.stringify(resume)),
]);
return resume;
@ -75,8 +72,8 @@ export class ResumeService {
});
await Promise.all([
this.cache.del(`user:${userId}:resumes`),
this.cache.set(`user:${userId}:resume:${resume.id}`, resume),
this.redis.del(`user:${userId}:resumes`),
this.redis.set(`user:${userId}:resume:${resume.id}`, JSON.stringify(resume)),
]);
return resume;
@ -142,10 +139,10 @@ export class ResumeService {
});
await Promise.all([
this.cache.set(`user:${userId}:resume:${id}`, resume),
this.cache.del(`user:${userId}:resumes`),
this.cache.del(`user:${userId}:storage:resumes:${id}`),
this.cache.del(`user:${userId}:storage:previews:${id}`),
this.redis.set(`user:${userId}:resume:${id}`, JSON.stringify(resume)),
this.redis.del(`user:${userId}:resumes`),
this.redis.del(`user:${userId}:storage:resumes:${id}`),
this.redis.del(`user:${userId}:storage:previews:${id}`),
]);
return resume;
@ -163,8 +160,8 @@ export class ResumeService {
});
await Promise.all([
this.cache.set(`user:${userId}:resume:${id}`, resume),
this.cache.del(`user:${userId}:resumes`),
this.redis.set(`user:${userId}:resume:${id}`, JSON.stringify(resume)),
this.redis.del(`user:${userId}:resumes`),
]);
return resume;
@ -173,8 +170,8 @@ export class ResumeService {
async remove(userId: string, id: string) {
await Promise.all([
// Remove cached keys
this.cache.del(`user:${userId}:resumes`),
this.cache.del(`user:${userId}:resume:${id}`),
this.redis.del(`user:${userId}:resumes`),
this.redis.del(`user:${userId}:resume:${id}`),
// Remove files in storage, and their cached keys
this.storageService.deleteObject(userId, "resumes", id),

View File

@ -1,14 +1,8 @@
import { CACHE_MANAGER } from "@nestjs/cache-manager";
import {
Inject,
Injectable,
InternalServerErrorException,
Logger,
OnModuleInit,
} from "@nestjs/common";
import { Injectable, InternalServerErrorException, Logger, OnModuleInit } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { createId } from "@paralleldrive/cuid2";
import { Cache } from "cache-manager";
import { RedisService } from "@songkeys/nestjs-redis";
import { Redis } from "ioredis";
import { Client } from "minio";
import { MinioService } from "nestjs-minio-client";
import sharp from "sharp";
@ -44,6 +38,7 @@ const PUBLIC_ACCESS_POLICY = {
@Injectable()
export class StorageService implements OnModuleInit {
private readonly redis: Redis;
private readonly logger = new Logger(StorageService.name);
private client: Client;
@ -52,8 +47,10 @@ export class StorageService implements OnModuleInit {
constructor(
private readonly configService: ConfigService<Config>,
private readonly minioService: MinioService,
@Inject(CACHE_MANAGER) private readonly cache: Cache,
) {}
private readonly redisService: RedisService,
) {
this.redis = this.redisService.getClient();
}
async onModuleInit() {
this.client = this.minioService.client;
@ -125,7 +122,7 @@ export class StorageService implements OnModuleInit {
await Promise.all([
this.client.putObject(this.bucketName, filepath, buffer, metadata),
this.cache.set(`user:${userId}:storage:${type}:${filename}`, url),
this.redis.set(`user:${userId}:storage:${type}:${filename}`, url),
]);
return url;
@ -140,7 +137,7 @@ export class StorageService implements OnModuleInit {
try {
return Promise.all([
this.cache.del(`user:${userId}:storage:${type}:${filename}`),
this.redis.del(`user:${userId}:storage:${type}:${filename}`),
this.client.removeObject(this.bucketName, path),
]);
} catch (error) {

View File

@ -0,0 +1,35 @@
import { HttpService } from "@nestjs/axios";
import { Controller, Get, Header, Param } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { Config } from "../config/schema";
import { UtilsService } from "../utils/utils.service";
@Controller("translation")
export class TranslationController {
constructor(
private readonly httpService: HttpService,
private readonly configService: ConfigService<Config>,
private readonly utils: UtilsService,
) {}
private async fetchTranslations(locale: string) {
const distributionHash = this.configService.get("CROWDIN_DISTRIBUTION_HASH");
const response = await this.httpService.axiosRef.get(
`https://distributions.crowdin.net/${distributionHash}/content/${locale}/messages.json`,
);
return response.data;
}
@Get("/:locale")
@Header("Content-Type", "application/octet-stream")
@Header("Content-Disposition", 'attachment; filename="messages.po"')
async getTranslation(@Param("locale") locale: string) {
return this.utils.getCachedOrSet(
`translation:${locale}`,
async () => this.fetchTranslations(locale),
1000 * 60 * 60 * 24, // 24 hours
);
}
}

View File

@ -0,0 +1,10 @@
import { HttpModule } from "@nestjs/axios";
import { Module } from "@nestjs/common";
import { TranslationController } from "./translation.controller";
@Module({
imports: [HttpModule],
controllers: [TranslationController],
})
export class TranslationModule {}

View File

@ -1,7 +1,7 @@
import { CACHE_MANAGER } from "@nestjs/cache-manager";
import { Inject, Injectable, InternalServerErrorException } from "@nestjs/common";
import { Injectable, InternalServerErrorException } from "@nestjs/common";
import { Prisma } from "@prisma/client";
import { Cache } from "cache-manager";
import { RedisService } from "@songkeys/nestjs-redis";
import Redis from "ioredis";
import { PrismaService } from "nestjs-prisma";
import { ErrorMessage } from "../constants/error-message";
@ -9,11 +9,15 @@ import { StorageService } from "../storage/storage.service";
@Injectable()
export class UserService {
private readonly redis: Redis;
constructor(
private readonly prisma: PrismaService,
private readonly storageService: StorageService,
@Inject(CACHE_MANAGER) private readonly cache: Cache,
) {}
private readonly redisService: RedisService,
) {
this.redis = this.redisService.getClient();
}
async findOneById(id: string) {
const user = await this.prisma.user.findUniqueOrThrow({
@ -67,10 +71,7 @@ export class UserService {
}
async deleteOneById(id: string) {
await Promise.all([
...(await this.cache.store.keys(`user:${id}:*`)).map((key) => this.cache.del(key)),
this.storageService.deleteFolder(id),
]);
await Promise.all([this.redis.del(`user:${id}:*`), this.storageService.deleteFolder(id)]);
return this.prisma.user.delete({ where: { id } });
}

View File

@ -1,18 +1,21 @@
import { CACHE_MANAGER } from "@nestjs/cache-manager";
import { Inject, Injectable, InternalServerErrorException, Logger } from "@nestjs/common";
import { Injectable, InternalServerErrorException, Logger } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { Cache } from "cache-manager";
import { RedisService } from "@songkeys/nestjs-redis";
import Redis from "ioredis";
import { Config } from "../config/schema";
@Injectable()
export class UtilsService {
private readonly redis: Redis;
logger = new Logger(UtilsService.name);
constructor(
private readonly redisService: RedisService,
private readonly configService: ConfigService<Config>,
@Inject(CACHE_MANAGER) private readonly cache: Cache,
) {}
) {
this.redis = this.redisService.getClient();
}
getUrl(): string {
const url =
@ -27,28 +30,34 @@ export class UtilsService {
return url;
}
async getCachedOrSet<T>(key: string, callback: () => Promise<T>, ttl?: number): Promise<T> {
async getCachedOrSet<T>(
key: string,
callback: () => Promise<T> | T,
ttl: number = 1000 * 60 * 60 * 24, // 24 hours
type: "json" | "string" = "json",
): Promise<T> {
// Try to get the value from the cache
const start = performance.now();
const cachedValue = await this.cache.get<T>(key);
const cachedValue = await this.redis.get(key);
const duration = Number(performance.now() - start).toFixed(0);
if (cachedValue === undefined) {
if (!cachedValue) {
this.logger.debug(`Cache Key "${key}": miss`);
} else {
this.logger.debug(`Cache Key "${key}": hit - ${duration}ms`);
}
// If the value is in the cache, return it
if (cachedValue !== undefined) {
return cachedValue;
if (cachedValue) {
return (type === "string" ? cachedValue : JSON.parse(cachedValue)) as T;
}
// If the value is not in the cache, run the callback
const value = await callback();
const valueToCache = (type === "string" ? value : JSON.stringify(value)) as string;
// Store the value in the cache
await this.cache.set(key, value, ttl);
await this.redis.set(key, valueToCache, "PX", ttl);
// Return the value
return value;

View File

@ -131,7 +131,6 @@
"@lingui/react": "^4.5.0",
"@nestjs-modules/mailer": "^1.9.1",
"@nestjs/axios": "^3.0.1",
"@nestjs/cache-manager": "^2.1.1",
"@nestjs/common": "^10.2.8",
"@nestjs/config": "^3.1.1",
"@nestjs/core": "^10.2.8",
@ -186,8 +185,6 @@
"axios": "^1.6.1",
"axios-auth-refresh": "^3.3.6",
"bcryptjs": "^2.4.3",
"cache-manager": "^5.2.4",
"cache-manager-redis-yet": "^4.1.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"cmdk": "^0.2.0",

179
pnpm-lock.yaml generated
View File

@ -41,9 +41,6 @@ dependencies:
'@nestjs/axios':
specifier: ^3.0.1
version: 3.0.1(@nestjs/common@10.2.8)(axios@1.6.1)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/cache-manager':
specifier: ^2.1.1
version: 2.1.1(@nestjs/common@10.2.8)(@nestjs/core@10.2.8)(cache-manager@5.2.4)(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/common':
specifier: ^10.2.8
version: 10.2.8(reflect-metadata@0.1.13)(rxjs@7.8.1)
@ -206,12 +203,6 @@ dependencies:
bcryptjs:
specifier: ^2.4.3
version: 2.4.3
cache-manager:
specifier: ^5.2.4
version: 5.2.4
cache-manager-redis-yet:
specifier: ^4.1.2
version: 4.1.2
class-variance-authority:
specifier: ^0.7.0
version: 0.7.0
@ -2164,16 +2155,6 @@ packages:
conventional-changelog-conventionalcommits: 7.0.2
dev: true
/@commitlint/config-validator@18.1.0:
resolution: {integrity: sha512-kbHkIuItXn93o2NmTdwi5Mk1ujyuSIysRE/XHtrcps/27GuUKEIqBJp6TdJ4Sq+ze59RlzYSHMKuDKZbfg9+uQ==}
engines: {node: '>=v18'}
requiresBuild: true
dependencies:
'@commitlint/types': 18.1.0
ajv: 8.12.0
dev: true
optional: true
/@commitlint/config-validator@18.4.0:
resolution: {integrity: sha512-1y6qHMU3o4cYQSK+Y9EnmH6H1GRiwQGjnLIUOIKlekrmfc8MrMk1ByNmb8od4vK3qHJAaL/77/5n+1uyyIF5dA==}
engines: {node: '>=v18'}
@ -2194,13 +2175,6 @@ packages:
lodash.upperfirst: 4.3.1
dev: true
/@commitlint/execute-rule@18.1.0:
resolution: {integrity: sha512-w3Vt4K+O7+nSr9/gFSEfZ1exKUOPSlJaRpnk7Y+XowEhvwT7AIk1HNANH+gETf0zGZ020+hfiMW/Ome+SNCUsg==}
engines: {node: '>=v18'}
requiresBuild: true
dev: true
optional: true
/@commitlint/execute-rule@18.4.0:
resolution: {integrity: sha512-g013SWki6ZWhURBLOSXTaVQGWHdA0QlPJGiW4a+YpThezmJOemvc4LiKVpn13AjSKQ40QnmBqpBrxujOaSo+3A==}
engines: {node: '>=v18'}
@ -2232,28 +2206,6 @@ packages:
'@commitlint/types': 18.4.0
dev: true
/@commitlint/load@18.2.0(typescript@5.2.2):
resolution: {integrity: sha512-xjX3d3CRlOALwImhOsmLYZh14/+gW/KxsY7+bPKrzmGuFailf9K7ckhB071oYZVJdACnpY4hDYiosFyOC+MpAA==}
engines: {node: '>=v18'}
requiresBuild: true
dependencies:
'@commitlint/config-validator': 18.1.0
'@commitlint/execute-rule': 18.1.0
'@commitlint/resolve-extends': 18.1.0
'@commitlint/types': 18.1.0
'@types/node': 18.18.8
chalk: 4.1.2
cosmiconfig: 8.3.6(typescript@5.2.2)
cosmiconfig-typescript-loader: 5.0.0(@types/node@18.18.8)(cosmiconfig@8.3.6)(typescript@5.2.2)
lodash.isplainobject: 4.0.6
lodash.merge: 4.6.2
lodash.uniq: 4.5.0
resolve-from: 5.0.0
transitivePeerDependencies:
- typescript
dev: true
optional: true
/@commitlint/load@18.4.0(typescript@5.2.2):
resolution: {integrity: sha512-7unGl1HGRNMgWrUPmj8OFkJyuNUMb6xA1i53/OAFKd9l+U3C4WTfoJe3t/TUz8vKZLCaDcWWR/b2cw5HveBBFg==}
engines: {node: '>=v18'}
@ -2299,20 +2251,6 @@ packages:
minimist: 1.2.8
dev: true
/@commitlint/resolve-extends@18.1.0:
resolution: {integrity: sha512-3mZpzOEJkELt7BbaZp6+bofJyxViyObebagFn0A7IHaLARhPkWTivXdjvZHS12nAORftv88Yhbh8eCPKfSvB7g==}
engines: {node: '>=v18'}
requiresBuild: true
dependencies:
'@commitlint/config-validator': 18.1.0
'@commitlint/types': 18.1.0
import-fresh: 3.3.0
lodash.mergewith: 4.6.2
resolve-from: 5.0.0
resolve-global: 1.0.0
dev: true
optional: true
/@commitlint/resolve-extends@18.4.0:
resolution: {integrity: sha512-qhgU6ach+S6sJMD9NjCYiEycOObGhxzWQLQzqlScJCv9zkPs15Bg0ffLXTQ3z7ipXv46XEKYMnSJzjLRw2Tlkg==}
engines: {node: '>=v18'}
@ -2348,15 +2286,6 @@ packages:
find-up: 5.0.0
dev: true
/@commitlint/types@18.1.0:
resolution: {integrity: sha512-65vGxZmbs+2OVwEItxhp3Ul7X2m2LyLfifYI/NdPwRqblmuES2w2aIRhIjb7cwUIBHHSTT8WXj4ixVHQibmvLQ==}
engines: {node: '>=v18'}
requiresBuild: true
dependencies:
chalk: 4.1.2
dev: true
optional: true
/@commitlint/types@18.4.0:
resolution: {integrity: sha512-MKeaFxt0I9fhqUb2E+YIzX/gZtmkuodJET/XKiZIMvXUff8Ee4Ih86eLg+yAm2jf1pwGBmU02uNOp0y094w2Uw==}
engines: {node: '>=v18'}
@ -3564,22 +3493,6 @@ packages:
rxjs: 7.8.1
dev: false
/@nestjs/cache-manager@2.1.1(@nestjs/common@10.2.8)(@nestjs/core@10.2.8)(cache-manager@5.2.4)(reflect-metadata@0.1.13)(rxjs@7.8.1):
resolution: {integrity: sha512-oYfRys4Ng0zp2HTUPNjH7gizf4vvG3PQZZ+3yGemb3xrF+p3JxDSK0cDq9NTjHzD5UmhjiyAftB9GkuL+t3r9g==}
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.2.8(reflect-metadata@0.1.13)(rxjs@7.8.1)
'@nestjs/core': 10.2.8(@nestjs/common@10.2.8)(@nestjs/platform-express@10.2.8)(reflect-metadata@0.1.13)(rxjs@7.8.1)
cache-manager: 5.2.4
reflect-metadata: 0.1.13
rxjs: 7.8.1
dev: false
/@nestjs/common@10.2.8(reflect-metadata@0.1.13)(rxjs@7.8.1):
resolution: {integrity: sha512-rmpwcdvq2IWMmsUVP8rsdKub6uDWk7dwCYo0aif50JTwcvcxzaP3iKVFKoSgvp0RKYu8h15+/AEOfaInmPpl0Q==}
peerDependencies:
@ -6131,55 +6044,6 @@ packages:
'@babel/runtime': 7.23.2
dev: false
/@redis/bloom@1.2.0(@redis/client@1.5.11):
resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==}
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': 1.5.11
dev: false
/@redis/client@1.5.11:
resolution: {integrity: sha512-cV7yHcOAtNQ5x/yQl7Yw1xf53kO0FNDTdDU6bFIMbW6ljB7U7ns0YRM+QIkpoqTAt6zK5k9Fq0QWlUbLcq9AvA==}
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.11):
resolution: {integrity: sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==}
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': 1.5.11
dev: false
/@redis/json@1.0.6(@redis/client@1.5.11):
resolution: {integrity: sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw==}
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': 1.5.11
dev: false
/@redis/search@1.1.5(@redis/client@1.5.11):
resolution: {integrity: sha512-hPP8w7GfGsbtYEJdn4n7nXa6xt6hVZnnDktKW4ArMaFQ/m/aR7eFvsLQmG/mn1Upq99btPJk+F27IQ2dYpCoUg==}
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': 1.5.11
dev: false
/@redis/time-series@1.0.5(@redis/client@1.5.11):
resolution: {integrity: sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==}
peerDependencies:
'@redis/client': ^1.0.0
dependencies:
'@redis/client': 1.5.11
dev: false
/@remirror/core-constants@2.0.2:
resolution: {integrity: sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ==}
dev: false
@ -9064,27 +8928,6 @@ packages:
engines: {node: '>=8'}
dev: true
/cache-manager-redis-yet@4.1.2:
resolution: {integrity: sha512-pM2K1ZlOv8gQpE1Z5mcDrfLj5CsNKVRiYua/SZ12j7LEDgfDeFVntI6JSgIw0siFSR/9P/FpG30scI3frHwibA==}
engines: {node: '>= 16.17.0'}
dependencies:
'@redis/bloom': 1.2.0(@redis/client@1.5.11)
'@redis/client': 1.5.11
'@redis/graph': 1.1.0(@redis/client@1.5.11)
'@redis/json': 1.0.6(@redis/client@1.5.11)
'@redis/search': 1.1.5(@redis/client@1.5.11)
'@redis/time-series': 1.0.5(@redis/client@1.5.11)
cache-manager: 5.2.4
redis: 4.6.10
dev: false
/cache-manager@5.2.4:
resolution: {integrity: sha512-gkuCjug16NdGvKm/sydxGVx17uffrSWcEe2xraBtwRCgdYcFxwJAla4OYpASAZT2yhSoxgDiWL9XH6IAChcZJA==}
dependencies:
lodash.clonedeep: 4.5.0
lru-cache: 10.0.1
dev: false
/cacheable-lookup@5.0.4:
resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==}
engines: {node: '>=10.6.0'}
@ -10151,7 +9994,7 @@ packages:
longest: 2.0.1
word-wrap: 1.2.5
optionalDependencies:
'@commitlint/load': 18.2.0(typescript@5.2.2)
'@commitlint/load': 18.4.0(typescript@5.2.2)
transitivePeerDependencies:
- typescript
dev: true
@ -12069,11 +11912,6 @@ packages:
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
dev: true
/generic-pool@3.9.0:
resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==}
engines: {node: '>= 4'}
dev: false
/gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
@ -14359,10 +14197,6 @@ packages:
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
dev: true
/lodash.clonedeep@4.5.0:
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
dev: false
/lodash.debounce@4.0.8:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
@ -17670,17 +17504,6 @@ packages:
redis-errors: 1.2.0
dev: false
/redis@4.6.10:
resolution: {integrity: sha512-mmbyhuKgDiJ5TWUhiKhBssz+mjsuSI/lSZNPI9QvZOYzWvYGejtb+W3RlDDf8LD6Bdl5/mZeG8O1feUGhXTxEg==}
dependencies:
'@redis/bloom': 1.2.0(@redis/client@1.5.11)
'@redis/client': 1.5.11
'@redis/graph': 1.1.0(@redis/client@1.5.11)
'@redis/json': 1.0.6(@redis/client@1.5.11)
'@redis/search': 1.1.5(@redis/client@1.5.11)
'@redis/time-series': 1.0.5(@redis/client@1.5.11)
dev: false
/reflect-metadata@0.1.13:
resolution: {integrity: sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==}

View File

@ -18,12 +18,12 @@
"@/client/*": ["apps/client/src/*"],
"@/server/*": ["apps/server/src/*"],
"@/artboard/*": ["apps/artboard/src/*"],
"@reactive-resume/ui": ["libs/ui/src/index.ts"],
"@reactive-resume/dto": ["libs/dto/src/index.ts"],
"@reactive-resume/utils": ["libs/utils/src/index.ts"],
"@reactive-resume/hooks": ["libs/hooks/src/index.ts"],
"@reactive-resume/parser": ["libs/parser/src/index.ts"],
"@reactive-resume/schema": ["libs/schema/src/index.ts"],
"@reactive-resume/ui": ["libs/ui/src/index.ts"],
"@reactive-resume/utils": ["libs/utils/src/index.ts"]
"@reactive-resume/schema": ["libs/schema/src/index.ts"]
}
},
"exclude": ["node_modules", "dist", "tmp", ".nx"]