mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-12 15:52:56 +10:00
fix(i18n): delete local translations
This commit is contained in:
@ -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=
|
||||
|
||||
14
.github/workflows/update-translations.yml
vendored
14
.github/workflows/update-translations.yml
vendored
@ -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
2
.gitignore
vendored
@ -48,4 +48,4 @@ libs/prisma
|
||||
|
||||
# Lingui Compiled Messages
|
||||
apps/client/src/locales/_build/
|
||||
apps/client/src/locales/**/*.js
|
||||
apps/client/src/locales
|
||||
@ -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
@ -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({
|
||||
|
||||
23
apps/server/src/cache/cache.module.ts
vendored
23
apps/server/src/cache/cache.module.ts
vendored
@ -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 {}
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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) {
|
||||
|
||||
35
apps/server/src/translation/translation.controller.ts
Normal file
35
apps/server/src/translation/translation.controller.ts
Normal 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
|
||||
);
|
||||
}
|
||||
}
|
||||
10
apps/server/src/translation/translation.module.ts
Normal file
10
apps/server/src/translation/translation.module.ts
Normal 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 {}
|
||||
@ -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 } });
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
179
pnpm-lock.yaml
generated
@ -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==}
|
||||
|
||||
|
||||
@ -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"]
|
||||
|
||||
Reference in New Issue
Block a user