chore(repo) init AppFileTransactions module
This commit is contained in:
parent
58de1b1652
commit
cc6fe98e20
@ -6,7 +6,7 @@ export class AppController {
|
||||
constructor(private readonly appService: AppService) {}
|
||||
|
||||
@Get()
|
||||
getData() {
|
||||
return this.appService.getData();
|
||||
async getData() {
|
||||
return await this.appService.getData();
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,19 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AppController } from './app.controller';
|
||||
import { AppService } from './app.service';
|
||||
|
||||
import { AppConfigModule } from './modules/config/config.module';
|
||||
import { AppDatabaseModule } from './modules/database/database.module';
|
||||
import { AppFileTransactionsModule } from './modules/file-transactions/file-transactions.module';
|
||||
import { AppLoggerModule } from './modules/logger/logger.module';
|
||||
|
||||
@Module({
|
||||
imports: [AppConfigModule, AppLoggerModule, AppDatabaseModule],
|
||||
imports: [
|
||||
AppConfigModule,
|
||||
AppLoggerModule,
|
||||
AppDatabaseModule,
|
||||
AppFileTransactionsModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
})
|
||||
|
@ -2,9 +2,9 @@ import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
logger = new Logger(AppService.name);
|
||||
private readonly logger = new Logger(AppService.name);
|
||||
|
||||
getData(): { message: string } {
|
||||
async getData() {
|
||||
return ({ message: 'Hello API' });
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { localConfig } from './local.config';
|
||||
import { loggerConfig } from '../logger/logger.config';
|
||||
import { databaseConfig } from '../database/database.config';
|
||||
import { keyvConfig } from '../keyv/keyv.config';
|
||||
import { loggerConfig } from '../logger/logger.config';
|
||||
import { localConfig } from './local.config';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
expandVariables: true,
|
||||
load: [localConfig, loggerConfig, databaseConfig],
|
||||
load: [localConfig, loggerConfig, databaseConfig, keyvConfig],
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
@ -0,0 +1,137 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
import fs from 'node:fs';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import path from 'node:path';
|
||||
import { FileTransactionsService } from './file-transactions.service';
|
||||
import {
|
||||
copyFilesToFolderOrFail,
|
||||
deleteFiles,
|
||||
renameFiles,
|
||||
renameFilesOrFail,
|
||||
} from './file-utils';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
export class FileTransaction {
|
||||
public static readonly TO_ADD_SUFFIX = 'toAdd';
|
||||
public static readonly TO_DELETE_SUFFIX = 'toDelete';
|
||||
|
||||
private readonly manager: FileTransactionsService;
|
||||
private readonly logger: Logger;
|
||||
|
||||
public readonly transactionId: string;
|
||||
private readonly ts: Date;
|
||||
public readonly filesToAdd: { src: string; dest: string }[];
|
||||
public readonly filesToDelete: string[];
|
||||
|
||||
constructor(
|
||||
manager: FileTransactionsService,
|
||||
opts: Partial<{
|
||||
transactionId: string;
|
||||
filesToAdd: { src: string; dest: string }[];
|
||||
filesToDelete: string[];
|
||||
logger: Logger;
|
||||
}>
|
||||
) {
|
||||
this.manager = manager;
|
||||
this.logger = opts.logger ?? new Logger(FileTransaction.name);
|
||||
this.filesToAdd = opts.filesToAdd ?? [];
|
||||
this.filesToDelete = opts.filesToDelete ?? [];
|
||||
this.transactionId = opts.transactionId ?? randomUUID().split('-').pop() as string;
|
||||
this.ts = new Date();
|
||||
}
|
||||
|
||||
async addFile(src: string, dest: string) {
|
||||
const destFolderName = path.dirname(dest);
|
||||
const destFileName = path.basename(dest);
|
||||
const destFileNameWithSuffix = `${destFileName}.${this.transactionId}.${FileTransaction.TO_ADD_SUFFIX}`;
|
||||
const destFilePathWithSuffix = path.join(
|
||||
destFolderName,
|
||||
destFileNameWithSuffix
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
`Adding file '${destFilePathWithSuffix}' in fileTransaction '${
|
||||
this.transactionId
|
||||
}' (started at ${dayjs(this.ts).format('YYYY-MM-DD HH:mm:ss')})`
|
||||
);
|
||||
this.filesToAdd.push({ src: src, dest: destFilePathWithSuffix });
|
||||
|
||||
if (fs.existsSync(dest)) {
|
||||
await this.deleteFile(dest);
|
||||
}
|
||||
|
||||
await copyFilesToFolderOrFail(this.logger, destFolderName, {
|
||||
srcpath: src,
|
||||
name: destFileNameWithSuffix,
|
||||
});
|
||||
await deleteFiles(this.logger, src);
|
||||
this.manager.persist(this);
|
||||
}
|
||||
|
||||
async deleteFile(src: string) {
|
||||
const destFolderName = path.dirname(src);
|
||||
const destFileName = path.basename(src);
|
||||
const destFileNameWithSuffix = `${destFileName}.${this.transactionId}.${FileTransaction.TO_DELETE_SUFFIX}`;
|
||||
const destFilePathWithSuffix = path.join(
|
||||
destFolderName,
|
||||
destFileNameWithSuffix
|
||||
);
|
||||
|
||||
this.logger.log(
|
||||
`Deleting file '${destFilePathWithSuffix}' in fileTransaction '${
|
||||
this.transactionId
|
||||
}' (started at ${dayjs(this.ts).format('YYYY-MM-DD HH:mm:ss')})`
|
||||
);
|
||||
this.filesToDelete.push(destFilePathWithSuffix);
|
||||
await renameFilesOrFail(this.logger, { src, dest: destFilePathWithSuffix });
|
||||
this.manager.persist(this);
|
||||
}
|
||||
|
||||
async commitTransaction() {
|
||||
this.logger.log(
|
||||
`Committing fileTransaction '${this.transactionId}' (started at ${dayjs(
|
||||
this.ts
|
||||
).format('YYYY-MM-DD HH:mm:ss')})`
|
||||
);
|
||||
await renameFiles(
|
||||
this.logger,
|
||||
...this.filesToAdd.map((fileToAdd) => ({
|
||||
src: fileToAdd.dest,
|
||||
dest: fileToAdd.dest.replace(
|
||||
`.${this.transactionId}.${FileTransaction.TO_ADD_SUFFIX}`,
|
||||
''
|
||||
),
|
||||
}))
|
||||
);
|
||||
await deleteFiles(this.logger, ...this.filesToDelete);
|
||||
this.manager.unregister(this);
|
||||
}
|
||||
|
||||
async rollbackTransaction() {
|
||||
this.logger.log(
|
||||
`Rollbacking fileTransaction '${this.transactionId}' (started at ${dayjs(
|
||||
this.ts
|
||||
).format('YYYY-MM-DD HH:mm:ss')})`
|
||||
);
|
||||
|
||||
await renameFiles(
|
||||
this.logger,
|
||||
...this.filesToAdd.map((fileToMove) => ({
|
||||
src: fileToMove.dest,
|
||||
dest: fileToMove.src,
|
||||
}))
|
||||
);
|
||||
|
||||
await renameFiles(
|
||||
this.logger,
|
||||
...this.filesToDelete.map((fileToRestore) => ({
|
||||
src: fileToRestore,
|
||||
dest: fileToRestore.replace(
|
||||
`.${this.transactionId}.${FileTransaction.TO_DELETE_SUFFIX}`,
|
||||
''
|
||||
),
|
||||
}))
|
||||
);
|
||||
this.manager.unregister(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { FileTransactionsService } from './file-transactions.service';
|
||||
import { KeyvModule } from '../keyv/keyv.module';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [KeyvModule],
|
||||
providers: [FileTransactionsService],
|
||||
exports: [FileTransactionsService],
|
||||
})
|
||||
export class AppFileTransactionsModule {}
|
@ -0,0 +1,54 @@
|
||||
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
|
||||
import { FileTransaction } from './file-transaction';
|
||||
import { createKeyv, Keyv } from '@keyv/redis';
|
||||
import { parse, stringify } from 'flatted';
|
||||
import { KeyvService } from '../keyv/keyv.service';
|
||||
|
||||
const FILE_TRANSACTIONS_KEY = `FILE_TRANSACTIONS_KEY`;
|
||||
|
||||
@Injectable()
|
||||
export class FileTransactionsService implements OnModuleInit {
|
||||
private readonly logger = new Logger(FileTransactionsService.name);
|
||||
private readonly map: Record<string, FileTransaction> = {};
|
||||
|
||||
private readonly keyv: Keyv;
|
||||
|
||||
constructor(readonly keyvService: KeyvService) {
|
||||
this.keyv = this.keyvService.create({
|
||||
namespace: FileTransactionsService.name,
|
||||
});
|
||||
}
|
||||
|
||||
register(logger?: Logger) {
|
||||
const tx = new FileTransaction(this, { logger });
|
||||
this.persist(tx);
|
||||
return tx;
|
||||
}
|
||||
|
||||
persist(tx: FileTransaction) {
|
||||
this.map[tx.transactionId] = tx;
|
||||
this.keyv.set(FILE_TRANSACTIONS_KEY, this.map);
|
||||
}
|
||||
|
||||
unregister(tx: FileTransaction) {
|
||||
delete this.map[tx.transactionId];
|
||||
this.keyv.set(FILE_TRANSACTIONS_KEY, this.map);
|
||||
}
|
||||
|
||||
async onModuleInit() {
|
||||
this.logger.log('Checking for dangling file transactions...');
|
||||
const dangling = await this.keyv.get<Set<FileTransaction>>(
|
||||
FILE_TRANSACTIONS_KEY
|
||||
);
|
||||
|
||||
if (dangling) {
|
||||
for (const danglingTx of Object.values(dangling)) {
|
||||
const tx = new FileTransaction(this, {
|
||||
...danglingTx,
|
||||
logger: this.logger,
|
||||
});
|
||||
await tx.rollbackTransaction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
106
apps/ebitemp-api/src/app/modules/file-transactions/file-utils.ts
Normal file
106
apps/ebitemp-api/src/app/modules/file-transactions/file-utils.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import { Logger } from '@nestjs/common';
|
||||
import { promises as fs } from 'node:fs';
|
||||
import path from 'path';
|
||||
|
||||
interface File {
|
||||
srcpath: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export const copyFilesToFolder = (logger: Logger, destFolder: string, ...files: File[]) =>
|
||||
_copyFilesToFolder(logger, destFolder, false, ...files);
|
||||
export const copyFilesToFolderOrFail = (logger: Logger, destFolder: string, ...files: File[]) =>
|
||||
_copyFilesToFolder(logger, destFolder, true, ...files);
|
||||
export const deleteFolder = (logger: Logger, folder: string) => _deleteFolder(logger, false, folder);
|
||||
export const deleteFolderOrFail = (logger: Logger, folder: string) => _deleteFolder(logger, true, folder);
|
||||
export const deleteFiles = (logger: Logger, ...files: string[]) => _deleteFiles(logger, false, ...files);
|
||||
export const deleteFilesOrFail = (logger: Logger, ...files: string[]) => _deleteFiles(logger, true, ...files);
|
||||
export const renameFiles = (logger: Logger, ...files: Array<{ src: string; dest: string }>) =>
|
||||
_renameFiles(logger, false, ...files);
|
||||
export const renameFilesOrFail = (logger: Logger, ...files: Array<{ src: string; dest: string }>) =>
|
||||
_renameFiles(logger, true, ...files);
|
||||
|
||||
export const normalizeWin32PathToPosix = (filepath: string): string =>
|
||||
path.win32.normalize(filepath).split(path.win32.sep).join(path.posix.sep);
|
||||
|
||||
const _copyFilesToFolder = async (
|
||||
logger: Logger,
|
||||
destFolder: string,
|
||||
throwsOnError = false,
|
||||
...files: File[]
|
||||
): Promise<void> => {
|
||||
await fs.mkdir(destFolder, { recursive: true });
|
||||
|
||||
for (const file of files) {
|
||||
try {
|
||||
const destpath = path.join(destFolder, file.name);
|
||||
await fs.copyFile(file.srcpath, destpath);
|
||||
logger.debug(`Copying file '${file.srcpath}' to '${destpath}'`);
|
||||
} catch (err: any) {
|
||||
const msg = `Could not copy '${file.srcpath}' to '${destFolder}'. Inner exception: ${err.message}`;
|
||||
if (throwsOnError) {
|
||||
logger.error(msg);
|
||||
err.message = msg;
|
||||
throw err;
|
||||
}
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const _deleteFolder = async (logger: Logger, throwsOnError = false, folder: string): Promise<void> => {
|
||||
try {
|
||||
await fs.rmdir(folder, { recursive: true });
|
||||
logger.debug(`Deleting folder '${folder}'`);
|
||||
} catch (err: any) {
|
||||
if (err.code === 'ENOENT') {
|
||||
return;
|
||||
}
|
||||
const msg = `Could not delete '${folder}'. Inner exception: ${err.message}`;
|
||||
if (throwsOnError) {
|
||||
logger.error(msg);
|
||||
throw err;
|
||||
}
|
||||
logger.warn(msg);
|
||||
}
|
||||
};
|
||||
|
||||
const _deleteFiles = async (logger: Logger, throwsOnError = false, ...files: string[]): Promise<void> => {
|
||||
for (const file of files) {
|
||||
try {
|
||||
await fs.unlink(file);
|
||||
logger.debug(`Deleting file '${file}'`);
|
||||
} catch (err: any) {
|
||||
if (err.code === 'ENOENT') {
|
||||
return;
|
||||
}
|
||||
const msg = `Could not delete '${file}'. Inner exception: ${err.message}`;
|
||||
if (throwsOnError) {
|
||||
logger.error(msg);
|
||||
throw err;
|
||||
}
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const _renameFiles = async (
|
||||
logger: Logger,
|
||||
throwsOnError = false,
|
||||
...files: Array<{ src: string; dest: string }>
|
||||
): Promise<void> => {
|
||||
for (const file of files) {
|
||||
try {
|
||||
await fs.rename(file.src, file.dest);
|
||||
logger.debug(`Renaming file '${file.src}' to '${file.dest}'`);
|
||||
} catch (err: any) {
|
||||
const msg = `Could not rename '${file.src}' to '${file.dest}'. Inner exception: ${err.message}`;
|
||||
if (throwsOnError) {
|
||||
logger.error(msg);
|
||||
err.message = msg;
|
||||
throw err;
|
||||
}
|
||||
logger.warn(msg);
|
||||
}
|
||||
}
|
||||
};
|
17
apps/ebitemp-api/src/app/modules/keyv/keyv.config.ts
Normal file
17
apps/ebitemp-api/src/app/modules/keyv/keyv.config.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import coerceRecordTypes from '../config/utils/coerce-record-types';
|
||||
import { registerAs } from '@nestjs/config';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const keyvSchema = z.object({
|
||||
redis: z.string(),
|
||||
});
|
||||
export type KeyvConfig = z.infer<typeof keyvSchema>;
|
||||
|
||||
export const keyvConfig = registerAs('keyv', () => {
|
||||
const env = coerceRecordTypes(process.env);
|
||||
|
||||
const config: KeyvConfig = keyvSchema.strict().parse({
|
||||
redis: env['REDIS_CONNECTION_STRING'],
|
||||
});
|
||||
return config;
|
||||
});
|
9
apps/ebitemp-api/src/app/modules/keyv/keyv.module.ts
Normal file
9
apps/ebitemp-api/src/app/modules/keyv/keyv.module.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { KeyvService } from './keyv.service';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
providers: [KeyvService],
|
||||
exports: [KeyvService],
|
||||
})
|
||||
export class KeyvModule {}
|
16
apps/ebitemp-api/src/app/modules/keyv/keyv.service.ts
Normal file
16
apps/ebitemp-api/src/app/modules/keyv/keyv.service.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { createKeyv, KeyvRedisOptions } from '@keyv/redis';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { parse, stringify } from 'flatted';
|
||||
import { keyvConfig, KeyvConfig } from './keyv.config';
|
||||
|
||||
@Injectable()
|
||||
export class KeyvService {
|
||||
constructor(@Inject(keyvConfig.KEY) private readonly config: KeyvConfig) {}
|
||||
|
||||
create(options?: KeyvRedisOptions) {
|
||||
const keyv = createKeyv(this.config.redis, options);
|
||||
keyv.serialize = stringify;
|
||||
keyv.deserialize = parse;
|
||||
return keyv;
|
||||
}
|
||||
}
|
@ -15,3 +15,14 @@ services:
|
||||
memory: 4096M
|
||||
reservations:
|
||||
memory: 2048M
|
||||
redis:
|
||||
image: redis:alpine
|
||||
ports:
|
||||
- '${REDIS_PORT}:6379'
|
||||
restart: unless-stopped
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
memory: 4096M
|
||||
reservations:
|
||||
memory: 2048M
|
||||
|
@ -12,6 +12,7 @@
|
||||
"dependencies": {
|
||||
"10": "^0.0.1",
|
||||
"@autotelic/pino-seq-transport": "^0.1.0",
|
||||
"@keyv/redis": "^4.2.0",
|
||||
"@nestjs/common": "^10.0.2",
|
||||
"@nestjs/config": "^4.0.0",
|
||||
"@nestjs/core": "^10.0.2",
|
||||
@ -19,7 +20,10 @@
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"@nx/devkit": "20.4.1",
|
||||
"axios": "^1.6.0",
|
||||
"cacheable": "^1.8.8",
|
||||
"connection-string": "^4.4.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"flatted": "^3.3.2",
|
||||
"lodash": "^4.17.21",
|
||||
"nestjs-pino": "^4.3.0",
|
||||
"patch-package": "^8.0.0",
|
||||
|
119
pnpm-lock.yaml
generated
119
pnpm-lock.yaml
generated
@ -11,6 +11,9 @@ dependencies:
|
||||
'@autotelic/pino-seq-transport':
|
||||
specifier: ^0.1.0
|
||||
version: 0.1.0
|
||||
'@keyv/redis':
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
'@nestjs/common':
|
||||
specifier: ^10.0.2
|
||||
version: 10.4.15(reflect-metadata@0.1.14)(rxjs@7.8.1)
|
||||
@ -32,9 +35,18 @@ dependencies:
|
||||
axios:
|
||||
specifier: ^1.6.0
|
||||
version: 1.7.9
|
||||
cacheable:
|
||||
specifier: ^1.8.8
|
||||
version: 1.8.8
|
||||
connection-string:
|
||||
specifier: ^4.4.0
|
||||
version: 4.4.0
|
||||
dayjs:
|
||||
specifier: ^1.11.13
|
||||
version: 1.11.13
|
||||
flatted:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2
|
||||
lodash:
|
||||
specifier: ^4.17.21
|
||||
version: 4.17.21
|
||||
@ -2124,6 +2136,21 @@ packages:
|
||||
tslib: 2.8.1
|
||||
dev: true
|
||||
|
||||
/@keyv/redis@4.2.0:
|
||||
resolution: {integrity: sha512-QszmBfZZ3wOKJ5z1hn0CTLf04WN/552ITrSDYC3Yg4jT6yVdlz2fJxi5CNrnZ8NIu/Qaj7OAkbSL+pyFUXp6oA==}
|
||||
engines: {node: '>= 18'}
|
||||
dependencies:
|
||||
cluster-key-slot: 1.1.2
|
||||
keyv: 5.2.3
|
||||
redis: 4.7.0
|
||||
dev: false
|
||||
|
||||
/@keyv/serialize@1.0.2:
|
||||
resolution: {integrity: sha512-+E/LyaAeuABniD/RvUezWVXKpeuvwLEA9//nE9952zBaOdBd2mQ3pPoM8cUe2X6IcMByfuSLzmYqnYshG60+HQ==}
|
||||
dependencies:
|
||||
buffer: 6.0.3
|
||||
dev: false
|
||||
|
||||
/@leichtgewicht/ip-codec@2.0.5:
|
||||
resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==}
|
||||
dev: true
|
||||
@ -3081,6 +3108,55 @@ packages:
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@redis/bloom@1.2.0(@redis/client@1.6.0):
|
||||
resolution: {integrity: sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==}
|
||||
peerDependencies:
|
||||
'@redis/client': ^1.0.0
|
||||
dependencies:
|
||||
'@redis/client': 1.6.0
|
||||
dev: false
|
||||
|
||||
/@redis/client@1.6.0:
|
||||
resolution: {integrity: sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg==}
|
||||
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.1(@redis/client@1.6.0):
|
||||
resolution: {integrity: sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==}
|
||||
peerDependencies:
|
||||
'@redis/client': ^1.0.0
|
||||
dependencies:
|
||||
'@redis/client': 1.6.0
|
||||
dev: false
|
||||
|
||||
/@redis/json@1.0.7(@redis/client@1.6.0):
|
||||
resolution: {integrity: sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ==}
|
||||
peerDependencies:
|
||||
'@redis/client': ^1.0.0
|
||||
dependencies:
|
||||
'@redis/client': 1.6.0
|
||||
dev: false
|
||||
|
||||
/@redis/search@1.2.0(@redis/client@1.6.0):
|
||||
resolution: {integrity: sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw==}
|
||||
peerDependencies:
|
||||
'@redis/client': ^1.0.0
|
||||
dependencies:
|
||||
'@redis/client': 1.6.0
|
||||
dev: false
|
||||
|
||||
/@redis/time-series@1.1.0(@redis/client@1.6.0):
|
||||
resolution: {integrity: sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g==}
|
||||
peerDependencies:
|
||||
'@redis/client': ^1.0.0
|
||||
dependencies:
|
||||
'@redis/client': 1.6.0
|
||||
dev: false
|
||||
|
||||
/@sinclair/typebox@0.27.8:
|
||||
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
|
||||
|
||||
@ -4455,6 +4531,13 @@ packages:
|
||||
responselike: 2.0.1
|
||||
dev: true
|
||||
|
||||
/cacheable@1.8.8:
|
||||
resolution: {integrity: sha512-OE1/jlarWxROUIpd0qGBSKFLkNsotY8pt4GeiVErUYh/NUeTNrT+SBksUgllQv4m6a0W/VZsLuiHb88maavqEw==}
|
||||
dependencies:
|
||||
hookified: 1.7.0
|
||||
keyv: 5.2.3
|
||||
dev: false
|
||||
|
||||
/call-bind-apply-helpers@1.0.1:
|
||||
resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -4660,6 +4743,11 @@ packages:
|
||||
semver: 5.7.2
|
||||
dev: false
|
||||
|
||||
/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:
|
||||
resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==}
|
||||
engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'}
|
||||
@ -5922,7 +6010,6 @@ packages:
|
||||
|
||||
/flatted@3.3.2:
|
||||
resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==}
|
||||
dev: true
|
||||
|
||||
/follow-redirects@1.15.9:
|
||||
resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==}
|
||||
@ -6031,6 +6118,11 @@ packages:
|
||||
/function-bind@1.1.2:
|
||||
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
|
||||
|
||||
/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'}
|
||||
@ -6244,6 +6336,10 @@ packages:
|
||||
/highlight.js@10.7.3:
|
||||
resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==}
|
||||
|
||||
/hookified@1.7.0:
|
||||
resolution: {integrity: sha512-XQdMjqC1AyeOzfs+17cnIk7Wdfu1hh2JtcyNfBf5u9jHrT3iZUlGHxLTntFBuk5lwkqJ6l3+daeQdHK5yByHVA==}
|
||||
dev: false
|
||||
|
||||
/hosted-git-info@7.0.2:
|
||||
resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==}
|
||||
engines: {node: ^16.14.0 || >=18.0.0}
|
||||
@ -7293,6 +7389,12 @@ packages:
|
||||
json-buffer: 3.0.1
|
||||
dev: true
|
||||
|
||||
/keyv@5.2.3:
|
||||
resolution: {integrity: sha512-AGKecUfzrowabUv0bH1RIR5Vf7w+l4S3xtQAypKaUpTdIR1EbrAcTxHCrpo9Q+IWeUlFE2palRtgIQcgm+PQJw==}
|
||||
dependencies:
|
||||
'@keyv/serialize': 1.0.2
|
||||
dev: false
|
||||
|
||||
/kind-of@6.0.3:
|
||||
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -8968,6 +9070,17 @@ packages:
|
||||
resolve: 1.22.10
|
||||
dev: true
|
||||
|
||||
/redis@4.7.0:
|
||||
resolution: {integrity: sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ==}
|
||||
dependencies:
|
||||
'@redis/bloom': 1.2.0(@redis/client@1.6.0)
|
||||
'@redis/client': 1.6.0
|
||||
'@redis/graph': 1.1.1(@redis/client@1.6.0)
|
||||
'@redis/json': 1.0.7(@redis/client@1.6.0)
|
||||
'@redis/search': 1.2.0(@redis/client@1.6.0)
|
||||
'@redis/time-series': 1.1.0(@redis/client@1.6.0)
|
||||
dev: false
|
||||
|
||||
/reflect-metadata@0.1.14:
|
||||
resolution: {integrity: sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==}
|
||||
|
||||
@ -10751,6 +10864,10 @@ packages:
|
||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||
dev: true
|
||||
|
||||
/yallist@4.0.0:
|
||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
||||
dev: false
|
||||
|
||||
/yaml@1.10.2:
|
||||
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
|
||||
engines: {node: '>= 6'}
|
||||
|
@ -2,5 +2,5 @@ import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class <%= className %>Service {
|
||||
protected readonly logger = new Logger(<%= className %>Service.name);
|
||||
private readonly logger = new Logger(<%= className %>Service.name);
|
||||
}
|
||||
|
Reference in New Issue
Block a user