@solidstarters/solid-core 1.2.4 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/{redis.options.d.ts → cache.options.d.ts} +1 -1
- package/dist/config/cache.options.d.ts.map +1 -0
- package/dist/config/cache.options.js +36 -0
- package/dist/config/cache.options.js.map +1 -0
- package/dist/config/common.config.d.ts +5 -4
- package/dist/config/common.config.d.ts.map +1 -1
- package/dist/config/common.config.js +0 -2
- package/dist/config/common.config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/services/file.service.d.ts +2 -0
- package/dist/services/file.service.d.ts.map +1 -1
- package/dist/services/file.service.js +14 -0
- package/dist/services/file.service.js.map +1 -1
- package/dist/services/rabbitmq-publisher.service.d.ts +3 -1
- package/dist/services/rabbitmq-publisher.service.d.ts.map +1 -1
- package/dist/services/rabbitmq-publisher.service.js +27 -26
- package/dist/services/rabbitmq-publisher.service.js.map +1 -1
- package/dist/services/rabbitmq-subscriber.service.d.ts +4 -2
- package/dist/services/rabbitmq-subscriber.service.d.ts.map +1 -1
- package/dist/services/rabbitmq-subscriber.service.js +20 -25
- package/dist/services/rabbitmq-subscriber.service.js.map +1 -1
- package/dist/solid-core-cli.module.js +2 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/config/cache.options.ts +36 -0
- package/src/config/common.config.ts +6 -2
- package/src/index.ts +1 -1
- package/src/services/file.service.ts +13 -4
- package/src/services/rabbitmq-publisher.service.ts +30 -9
- package/src/services/rabbitmq-subscriber.service.ts +23 -14
- package/src/solid-core-cli.module.ts +1 -1
- package/dist/config/redis.options.d.ts.map +0 -1
- package/dist/config/redis.options.js +0 -22
- package/dist/config/redis.options.js.map +0 -1
- package/src/config/redis.options.ts +0 -20
package/package.json
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { CacheModuleAsyncOptions } from '@nestjs/cache-manager';
|
|
2
|
+
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
3
|
+
import { redisStore } from 'cache-manager-redis-store';
|
|
4
|
+
import { isNumber } from 'class-validator';
|
|
5
|
+
|
|
6
|
+
export const RedisOptions: CacheModuleAsyncOptions = {
|
|
7
|
+
isGlobal: true,
|
|
8
|
+
imports: [ConfigModule],
|
|
9
|
+
useFactory: async (configService: ConfigService) => {
|
|
10
|
+
if (!isRedisConfigured(configService)) {
|
|
11
|
+
return {
|
|
12
|
+
ttl: 0
|
|
13
|
+
} // This defaults to in-memory cache
|
|
14
|
+
}
|
|
15
|
+
const store = await createRedisStore(configService);
|
|
16
|
+
return {
|
|
17
|
+
store: () => store,
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
inject: [ConfigService],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
async function createRedisStore(configService: ConfigService<Record<string, unknown>, false>) {
|
|
24
|
+
return await redisStore({
|
|
25
|
+
socket: {
|
|
26
|
+
host: configService.get<string>('REDIS_HOST'),
|
|
27
|
+
port: parseInt(configService.get<string>('REDIS_PORT')!),
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isRedisConfigured(configService: ConfigService): boolean {
|
|
33
|
+
const host = configService.get<string>('REDIS_HOST');
|
|
34
|
+
const port = configService.get<string>('REDIS_PORT');
|
|
35
|
+
return host && port && isNumber(parseInt(port));
|
|
36
|
+
}
|
|
@@ -36,9 +36,13 @@ export default registerAs('common', () => {
|
|
|
36
36
|
awsS3Credentials: {
|
|
37
37
|
S3_AWS_ACCESS_KEY: process.env.S3_AWS_ACCESS_KEY,
|
|
38
38
|
S3_AWS_SECRET_KEY: process.env.S3_AWS_SECRET_KEY,
|
|
39
|
-
S3_AWS_BUCKET_NAME: process.env.S3_AWS_BUCKET_NAME,
|
|
40
|
-
S3_AWS_REGION_HOST: process.env.S3_AWS_REGION_HOST,
|
|
41
39
|
S3_AWS_REGION_NAME: process.env.S3_AWS_REGION_NAME
|
|
42
40
|
}
|
|
43
41
|
};
|
|
44
42
|
});
|
|
43
|
+
|
|
44
|
+
export interface AwsS3Config {
|
|
45
|
+
S3_AWS_ACCESS_KEY: string;
|
|
46
|
+
S3_AWS_SECRET_KEY: string;
|
|
47
|
+
S3_AWS_REGION_NAME: string;
|
|
48
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ export * from './commands/seed.command'
|
|
|
8
8
|
export * from './config/app-builder.config'
|
|
9
9
|
export * from './config/common.config'
|
|
10
10
|
export * from './config/iam.config'
|
|
11
|
-
export * from './config/
|
|
11
|
+
export * from './config/cache.options'
|
|
12
12
|
|
|
13
13
|
export * from './decorators/active-user.decorator'
|
|
14
14
|
export * from './decorators/auth.decorator'
|
|
@@ -3,7 +3,7 @@ import * as fs from 'fs';
|
|
|
3
3
|
// import * as AWS from 'aws-sdk';
|
|
4
4
|
import { S3Client, PutObjectCommand, DeleteObjectCommand, ObjectCannedACL } from '@aws-sdk/client-s3';
|
|
5
5
|
import { ConfigType } from '@nestjs/config';
|
|
6
|
-
import commonConfig from '../config/common.config';
|
|
6
|
+
import commonConfig, { AwsS3Config } from '../config/common.config';
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
@@ -18,14 +18,13 @@ export class FileService {
|
|
|
18
18
|
private readonly commonConfiguration: ConfigType<typeof commonConfig>,
|
|
19
19
|
|
|
20
20
|
) {
|
|
21
|
+
if (!this.isValidS3Config(this.commonConfiguration.awsS3Credentials)) { return }
|
|
21
22
|
this.s3Client = new S3Client({
|
|
22
23
|
region: this.commonConfiguration.awsS3Credentials.S3_AWS_REGION_NAME,
|
|
23
24
|
credentials: {
|
|
24
25
|
accessKeyId: this.commonConfiguration.awsS3Credentials.S3_AWS_ACCESS_KEY,
|
|
25
26
|
secretAccessKey: this.commonConfiguration.awsS3Credentials.S3_AWS_SECRET_KEY,
|
|
26
27
|
},
|
|
27
|
-
// endpoint: `https://${process.env.S3_AWS_BUCKET_NAME}.s3.${process.env.S3_AWS_REGION_NAME}.amazonaws.com`, // Correct regional endpoint
|
|
28
|
-
|
|
29
28
|
});
|
|
30
29
|
}
|
|
31
30
|
|
|
@@ -84,6 +83,7 @@ export class FileService {
|
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
async copyToS3(filePath: string, ContentType: string, fileName: string, bucketName: string): Promise<string> {
|
|
86
|
+
this.checkIfS3ClientExists();
|
|
87
87
|
try {
|
|
88
88
|
// Read Image File TO Fetch Buffer
|
|
89
89
|
const data = await this.readImageFile(filePath);
|
|
@@ -109,7 +109,12 @@ export class FileService {
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
private checkIfS3ClientExists() {
|
|
113
|
+
if (!this.s3Client) { throw new Error('S3 Client not initialized. Please check the S3 configuration'); }
|
|
114
|
+
}
|
|
115
|
+
|
|
112
116
|
async copyToS3WithPublic(filePath: string, ContentType: string, fileName: string, bucketName: string): Promise<string> {
|
|
117
|
+
this.checkIfS3ClientExists();
|
|
113
118
|
try {
|
|
114
119
|
// Read Image File TO Fetch Buffer
|
|
115
120
|
const data = await this.readImageFile(filePath);
|
|
@@ -136,7 +141,7 @@ export class FileService {
|
|
|
136
141
|
}
|
|
137
142
|
|
|
138
143
|
async deleteFromS3(fileName: string, bucketName: string): Promise<string> {
|
|
139
|
-
|
|
144
|
+
this.checkIfS3ClientExists();
|
|
140
145
|
const params = {
|
|
141
146
|
Bucket: bucketName, // your S3 bucket name
|
|
142
147
|
Key: fileName // the name of the file you want to delete
|
|
@@ -146,4 +151,8 @@ export class FileService {
|
|
|
146
151
|
const response = await this.s3Client.send(command);
|
|
147
152
|
return fileName
|
|
148
153
|
}
|
|
154
|
+
|
|
155
|
+
private isValidS3Config(config: AwsS3Config): boolean {
|
|
156
|
+
return !!config.S3_AWS_ACCESS_KEY && !!config.S3_AWS_SECRET_KEY && !!config.S3_AWS_REGION_NAME;
|
|
157
|
+
}
|
|
149
158
|
}
|
|
@@ -1,30 +1,50 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Injectable, Logger } from '@nestjs/common';
|
|
1
|
+
import { Logger } from '@nestjs/common';
|
|
3
2
|
import * as amqp from 'amqplib';
|
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
4
|
+
import { QueuesModuleOptions } from "../interfaces";
|
|
4
5
|
import { QueueMessage, QueuePublisher } from '../interfaces/mq';
|
|
5
6
|
import { MqMessageQueueService } from './mq-message-queue.service';
|
|
6
7
|
import { MqMessageService } from './mq-message.service';
|
|
7
|
-
import { QueuesModuleOptions } from "../interfaces";
|
|
8
8
|
|
|
9
|
-
@Injectable()
|
|
10
9
|
export abstract class RabbitMqPublisher<T> implements QueuePublisher<T> { // TODO This can be made a generic type for better type visibility
|
|
11
10
|
private readonly logger = new Logger(RabbitMqPublisher.name);
|
|
11
|
+
private readonly url: string;
|
|
12
|
+
private readonly serviceRole: string;
|
|
12
13
|
|
|
13
14
|
constructor(
|
|
14
15
|
protected readonly mqMessageService: MqMessageService,
|
|
15
16
|
protected readonly mqMessageQueueService: MqMessageQueueService,
|
|
16
17
|
) {
|
|
17
|
-
|
|
18
|
-
this.
|
|
18
|
+
this.url = process.env.QUEUES_RABBIT_MQ_URL;
|
|
19
|
+
this.serviceRole = process.env.QUEUES_SERVICE_ROLE;
|
|
20
|
+
if (!this.url) {
|
|
21
|
+
this.logger.debug('RabbitMqPublisher url is not defined in the environment variables');
|
|
22
|
+
}
|
|
23
|
+
if (!this.serviceRole) {
|
|
24
|
+
this.logger.debug('Queue service Role is not defined in the environment variables');
|
|
25
|
+
}
|
|
26
|
+
this.logger.debug(`RabbitMqPublisher instance created with options: ${JSON.stringify(this.options())} and url: ${this.url}`);
|
|
19
27
|
}
|
|
20
28
|
|
|
21
29
|
abstract options(): QueuesModuleOptions;
|
|
22
30
|
|
|
23
31
|
async publish(message: QueueMessage<T>): Promise<string> {
|
|
24
|
-
|
|
25
|
-
|
|
32
|
+
if (!this.url) {
|
|
33
|
+
this.logger.error('RabbitMqPublisher url is not defined in the environment variables');
|
|
34
|
+
throw new Error('RabbitMqPublisher url is not defined in the environment variables');
|
|
35
|
+
}
|
|
36
|
+
if (!this.serviceRole) {
|
|
37
|
+
this.logger.error('Queue service Role is not defined in the environment variables');
|
|
38
|
+
throw new Error('Queue service Role is not defined in the environment variables');
|
|
39
|
+
}
|
|
40
|
+
if (this.serviceRole === 'subscriber') {
|
|
41
|
+
this.logger.error('Queue service Role is subscriber, cannot publish messages');
|
|
42
|
+
throw new Error('Queue service Role is subscriber, cannot publish messages');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
this.logger.debug(`RabbitMqPublisher publishing with options: ${JSON.stringify(this.options())} and url: ${this.url}`);
|
|
26
46
|
|
|
27
|
-
const connection = await amqp.connect(url);
|
|
47
|
+
const connection = await amqp.connect(this.url);
|
|
28
48
|
// this.logger.debug(`RabbitMqPublisher publisher connected options: ${JSON.stringify(this.options())} and url: ${url}`);
|
|
29
49
|
|
|
30
50
|
const channel = await connection.createChannel();
|
|
@@ -117,5 +137,6 @@ export abstract class RabbitMqPublisher<T> implements QueuePublisher<T> { // TOD
|
|
|
117
137
|
}
|
|
118
138
|
|
|
119
139
|
}
|
|
140
|
+
|
|
120
141
|
|
|
121
142
|
}
|
|
@@ -1,41 +1,50 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Logger, OnModuleInit } from '@nestjs/common';
|
|
2
2
|
import * as amqp from 'amqplib';
|
|
3
|
+
import { QueuesModuleOptions } from "../interfaces";
|
|
3
4
|
import { QueueMessage, QueueSubscriber } from '../interfaces/mq';
|
|
4
|
-
import { MqMessageService } from './mq-message.service';
|
|
5
5
|
import { MqMessageQueueService } from './mq-message-queue.service';
|
|
6
|
-
import {
|
|
6
|
+
import { MqMessageService } from './mq-message.service';
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
@Injectable()
|
|
10
9
|
export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscriber<T> { // TODO This can be made a generic type for better type visibility
|
|
11
10
|
private readonly logger = new Logger(RabbitMqSubscriber.name);
|
|
11
|
+
private readonly url: string;
|
|
12
|
+
private readonly serviceRole: string;
|
|
12
13
|
|
|
13
14
|
constructor(
|
|
14
15
|
protected readonly mqMessageService: MqMessageService,
|
|
15
16
|
protected readonly mqMessageQueueService: MqMessageQueueService,
|
|
16
17
|
) {
|
|
18
|
+
this.url = process.env.QUEUES_RABBIT_MQ_URL;
|
|
19
|
+
this.serviceRole = process.env.SERVICE_ROLE;
|
|
20
|
+
if (!this.url) {
|
|
21
|
+
this.logger.debug('RabbitMqPublisher url is not defined in the environment variables');
|
|
22
|
+
}
|
|
23
|
+
if (!this.serviceRole) {
|
|
24
|
+
this.logger.debug('Queue service Role is not defined in the environment variables');
|
|
25
|
+
}
|
|
26
|
+
this.logger.debug(`RabbitMqSubscriber instance created with options: ${JSON.stringify(this.options())} and url: ${this.url}`);
|
|
17
27
|
}
|
|
18
28
|
|
|
19
29
|
abstract subscribe(message: QueueMessage<T>);
|
|
20
30
|
|
|
21
31
|
abstract options(): QueuesModuleOptions;
|
|
22
32
|
|
|
23
|
-
// setReceiveHandler(receiveHandler: (message: any) => Promise<any>): void {
|
|
24
|
-
// this.options.receive = receiveHandler; // Overwrite the default receive handler
|
|
25
|
-
// }
|
|
26
|
-
|
|
27
33
|
async onModuleInit(): Promise<void> {
|
|
28
34
|
// we will start subscriber only if the current service role is subscriber.
|
|
29
|
-
if (['both', 'subscriber'].includes(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
if (['both', 'subscriber'].includes(this.serviceRole)) {
|
|
36
|
+
if (!this.url) {
|
|
37
|
+
this.logger.error('RabbitMqPublisher url is not defined in the environment variables');
|
|
38
|
+
throw new Error('RabbitMqPublisher url is not defined in the environment variables');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!this.url) {
|
|
33
42
|
this.logger.warn(`Unable to create RabbitMqSubscriber instance: ${JSON.stringify(this.options())} as rabbitmq url is not configured.`);
|
|
34
43
|
return;
|
|
35
44
|
}
|
|
36
45
|
|
|
37
46
|
// this.logger.debug(`RabbitMqSubscriber instance created with options: ${JSON.stringify(this.options())} and url: ${url}`);
|
|
38
|
-
const connection = await amqp.connect(url);
|
|
47
|
+
const connection = await amqp.connect(this.url);
|
|
39
48
|
// this.logger.debug(`RabbitMqSubscriber connection established: ${JSON.stringify(this.options())} and url: ${url}`);
|
|
40
49
|
|
|
41
50
|
const channel = await connection.createChannel();
|
|
@@ -104,7 +113,7 @@ export abstract class RabbitMqSubscriber<T> implements OnModuleInit, QueueSubscr
|
|
|
104
113
|
{},
|
|
105
114
|
);
|
|
106
115
|
|
|
107
|
-
this.logger.debug(`RabbitMqSubscriber ready to consume messages: ${JSON.stringify(this.options())} and url: ${url}`);
|
|
116
|
+
this.logger.debug(`RabbitMqSubscriber ready to consume messages: ${JSON.stringify(this.options())} and url: ${this.url}`);
|
|
108
117
|
}
|
|
109
118
|
|
|
110
119
|
}
|
|
@@ -5,7 +5,7 @@ import { WinstonLoggerConfig } from './winston.logger';
|
|
|
5
5
|
import { WinstonModule } from 'nest-winston';
|
|
6
6
|
import { CacheModule } from '@nestjs/cache-manager';
|
|
7
7
|
import { EventEmitterModule } from '@nestjs/event-emitter';
|
|
8
|
-
import { RedisOptions } from './config/
|
|
8
|
+
import { RedisOptions } from './config/cache.options';
|
|
9
9
|
import { ConfigModule } from '@nestjs/config';
|
|
10
10
|
import Joi from '@hapi/joi';
|
|
11
11
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"redis.options.d.ts","sourceRoot":"","sources":["../../src/config/redis.options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAIhE,eAAO,MAAM,YAAY,EAAE,uBAe1B,CAAC"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RedisOptions = void 0;
|
|
4
|
-
const config_1 = require("@nestjs/config");
|
|
5
|
-
const cache_manager_redis_store_1 = require("cache-manager-redis-store");
|
|
6
|
-
exports.RedisOptions = {
|
|
7
|
-
isGlobal: true,
|
|
8
|
-
imports: [config_1.ConfigModule],
|
|
9
|
-
useFactory: async (configService) => {
|
|
10
|
-
const store = await (0, cache_manager_redis_store_1.redisStore)({
|
|
11
|
-
socket: {
|
|
12
|
-
host: configService.get('REDIS_HOST'),
|
|
13
|
-
port: parseInt(configService.get('REDIS_PORT')),
|
|
14
|
-
},
|
|
15
|
-
});
|
|
16
|
-
return {
|
|
17
|
-
store: () => store,
|
|
18
|
-
};
|
|
19
|
-
},
|
|
20
|
-
inject: [config_1.ConfigService],
|
|
21
|
-
};
|
|
22
|
-
//# sourceMappingURL=redis.options.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"redis.options.js","sourceRoot":"","sources":["../../src/config/redis.options.ts"],"names":[],"mappings":";;;AACA,2CAA6D;AAC7D,yEAAuD;AAE1C,QAAA,YAAY,GAA4B;IACjD,QAAQ,EAAE,IAAI;IACd,OAAO,EAAE,CAAC,qBAAY,CAAC;IACvB,UAAU,EAAE,KAAK,EAAE,aAA4B,EAAE,EAAE;QAC/C,MAAM,KAAK,GAAG,MAAM,IAAA,sCAAU,EAAC;YAC3B,MAAM,EAAE;gBACJ,IAAI,EAAE,aAAa,CAAC,GAAG,CAAS,YAAY,CAAC;gBAC7C,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAS,YAAY,CAAE,CAAC;aAC3D;SACJ,CAAC,CAAC;QACH,OAAO;YACH,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK;SACrB,CAAC;IACN,CAAC;IACD,MAAM,EAAE,CAAC,sBAAa,CAAC;CAC1B,CAAC"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { CacheModuleAsyncOptions } from '@nestjs/cache-manager';
|
|
2
|
-
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
3
|
-
import { redisStore } from 'cache-manager-redis-store';
|
|
4
|
-
|
|
5
|
-
export const RedisOptions: CacheModuleAsyncOptions = {
|
|
6
|
-
isGlobal: true,
|
|
7
|
-
imports: [ConfigModule],
|
|
8
|
-
useFactory: async (configService: ConfigService) => {
|
|
9
|
-
const store = await redisStore({
|
|
10
|
-
socket: {
|
|
11
|
-
host: configService.get<string>('REDIS_HOST'),
|
|
12
|
-
port: parseInt(configService.get<string>('REDIS_PORT')!),
|
|
13
|
-
},
|
|
14
|
-
});
|
|
15
|
-
return {
|
|
16
|
-
store: () => store,
|
|
17
|
-
};
|
|
18
|
-
},
|
|
19
|
-
inject: [ConfigService],
|
|
20
|
-
};
|