@messenger-box/platform-server 10.0.3-alpha.7 → 10.0.3-alpha.72
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/lib/containers/containers.js +4 -1
- package/lib/containers/containers.js.map +1 -1
- package/lib/containers/context-services-from-container.d.ts +1 -1
- package/lib/containers/context-services-from-container.js +1 -1
- package/lib/containers/context-services-from-container.js.map +1 -1
- package/lib/graphql/resolvers/channel-member.d.ts +3 -2
- package/lib/graphql/resolvers/channel-member.js +30 -5
- package/lib/graphql/resolvers/channel-member.js.map +1 -1
- package/lib/graphql/resolvers/channel.d.ts +3 -2
- package/lib/graphql/resolvers/channel.js +279 -53
- package/lib/graphql/resolvers/channel.js.map +1 -1
- package/lib/graphql/resolvers/extended-token-account.d.ts +3 -2
- package/lib/graphql/resolvers/extended-token-account.js +90 -23
- package/lib/graphql/resolvers/extended-token-account.js.map +1 -1
- package/lib/graphql/resolvers/index.d.ts +1 -1
- package/lib/graphql/resolvers/post-thread.d.ts +1 -1
- package/lib/graphql/resolvers/post-thread.js +294 -132
- package/lib/graphql/resolvers/post-thread.js.map +1 -1
- package/lib/graphql/resolvers/post.d.ts +2 -3
- package/lib/graphql/resolvers/post.js +696 -234
- package/lib/graphql/resolvers/post.js.map +1 -1
- package/lib/graphql/resolvers/reaction.d.ts +3 -2
- package/lib/graphql/resolvers/reaction.js +96 -14
- package/lib/graphql/resolvers/reaction.js.map +1 -1
- package/lib/graphql/schema/channel-member.graphql +110 -21
- package/lib/graphql/schema/channel-member.graphql.js +1 -1
- package/lib/graphql/schema/channel.graphql +337 -38
- package/lib/graphql/schema/channel.graphql.js +1 -1
- package/lib/graphql/schema/post-thread.graphql +167 -21
- package/lib/graphql/schema/post-thread.graphql.js +1 -1
- package/lib/graphql/schema/post.graphql +284 -40
- package/lib/graphql/schema/post.graphql.js +1 -1
- package/lib/graphql/schema/reaction.graphql +71 -13
- package/lib/graphql/schema/reaction.graphql.js +1 -1
- package/lib/graphql/schema/services.graphql +2 -0
- package/lib/graphql/schema/users.graphql +76 -13
- package/lib/graphql/schema/users.graphql.js +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/interfaces/index.d.ts +0 -1
- package/lib/interfaces/services.d.ts +1 -1
- package/lib/migrations/dbMigrations/AddPostsConfigurationsMigration.d.ts +17 -0
- package/lib/migrations/dbMigrations/AddPostsConfigurationsMigration.js +44 -0
- package/lib/migrations/dbMigrations/AddPostsConfigurationsMigration.js.map +1 -0
- package/lib/migrations/dbMigrations/index.d.ts +1 -0
- package/lib/migrations/index.d.ts +1 -0
- package/lib/migrations/mail-template-migration.js +1 -1
- package/lib/migrations/message-notification-template-migration.d.ts +1 -1
- package/lib/migrations/message-notification-template-migration.js +1 -1
- package/lib/plugins/channel-moleculer-service.d.ts +21 -1
- package/lib/plugins/channel-moleculer-service.js +417 -115
- package/lib/plugins/channel-moleculer-service.js.map +1 -1
- package/lib/plugins/extended-token-account-moleculer-service.d.ts +25 -1
- package/lib/plugins/extended-token-account-moleculer-service.js +348 -22
- package/lib/plugins/extended-token-account-moleculer-service.js.map +1 -1
- package/lib/plugins/messenger-notification-moleculer-service.d.ts +27 -3
- package/lib/plugins/messenger-notification-moleculer-service.js +404 -58
- package/lib/plugins/messenger-notification-moleculer-service.js.map +1 -1
- package/lib/plugins/post-moleculer-service.d.ts +85 -21
- package/lib/plugins/post-moleculer-service.js +986 -256
- package/lib/plugins/post-moleculer-service.js.map +1 -1
- package/lib/plugins/post-thread-moleculer-service.d.ts +33 -1
- package/lib/plugins/post-thread-moleculer-service.js +326 -8
- package/lib/plugins/post-thread-moleculer-service.js.map +1 -1
- package/lib/plugins/reaction-moleculer-service.js +1 -1
- package/lib/plugins/reaction-moleculer-service.js.map +1 -1
- package/lib/preferences/settings/post-settings.d.ts +2 -0
- package/lib/preferences/settings/post-settings.js +47 -9
- package/lib/preferences/settings/post-settings.js.map +1 -1
- package/lib/services/channel-service.d.ts +179 -33
- package/lib/services/channel-service.js +821 -274
- package/lib/services/channel-service.js.map +1 -1
- package/lib/services/extended-token-account-service.d.ts +130 -14
- package/lib/services/extended-token-account-service.js +462 -52
- package/lib/services/extended-token-account-service.js.map +1 -1
- package/lib/services/index.d.ts +1 -0
- package/lib/services/messenger-notification-service.d.ts +106 -13
- package/lib/services/messenger-notification-service.js +824 -442
- package/lib/services/messenger-notification-service.js.map +1 -1
- package/lib/services/post-service.d.ts +182 -16
- package/lib/services/post-service.js +731 -115
- package/lib/services/post-service.js.map +1 -1
- package/lib/services/post-thread-service.d.ts +114 -5
- package/lib/services/post-thread-service.js +400 -13
- package/lib/services/post-thread-service.js.map +1 -1
- package/lib/services/proxy-services/channel-microservice.d.ts +5 -3
- package/lib/services/proxy-services/channel-microservice.js +19 -10
- package/lib/services/proxy-services/channel-microservice.js.map +1 -1
- package/lib/services/proxy-services/messenger-notification-microservice.d.ts +128 -8
- package/lib/services/proxy-services/messenger-notification-microservice.js +324 -29
- package/lib/services/proxy-services/messenger-notification-microservice.js.map +1 -1
- package/lib/services/proxy-services/post-microservice.d.ts +186 -12
- package/lib/services/proxy-services/post-microservice.js +543 -54
- package/lib/services/proxy-services/post-microservice.js.map +1 -1
- package/lib/services/proxy-services/post-thread-microservice.d.ts +134 -3
- package/lib/services/proxy-services/post-thread-microservice.js +388 -6
- package/lib/services/proxy-services/post-thread-microservice.js.map +1 -1
- package/lib/services/proxy-services/reaction-microservice.d.ts +161 -3
- package/lib/services/proxy-services/reaction-microservice.js +474 -2
- package/lib/services/proxy-services/reaction-microservice.js.map +1 -1
- package/lib/services/reaction-service.d.ts +124 -4
- package/lib/services/reaction-service.js +415 -3
- package/lib/services/reaction-service.js.map +1 -1
- package/lib/services/redis-cache-manager.d.ts +18 -0
- package/lib/services/redis-cache-manager.js +83 -0
- package/lib/services/redis-cache-manager.js.map +1 -0
- package/lib/store/models/account-token-store.d.ts +1 -1
- package/lib/store/models/account-token-store.js.map +1 -1
- package/lib/store/models/channel.d.ts +2 -3
- package/lib/store/models/channel.js +181 -72
- package/lib/store/models/channel.js.map +1 -1
- package/lib/store/models/post-thread.d.ts +3 -3
- package/lib/store/models/post-thread.js +96 -14
- package/lib/store/models/post-thread.js.map +1 -1
- package/lib/store/models/post.d.ts +2 -3
- package/lib/store/models/post.js +143 -23
- package/lib/store/models/post.js.map +1 -1
- package/lib/store/models/reaction.d.ts +2 -3
- package/lib/store/models/reaction.js +67 -8
- package/lib/store/models/reaction.js.map +1 -1
- package/lib/store/repositories/__tests__/__fixtures__/team-repository.d.ts +3 -3
- package/lib/store/repositories/channel-repository.d.ts +6 -6
- package/lib/store/repositories/channel-repository.js +5 -2
- package/lib/store/repositories/channel-repository.js.map +1 -1
- package/lib/store/repositories/post-repository.d.ts +6 -6
- package/lib/store/repositories/post-repository.js +5 -2
- package/lib/store/repositories/post-repository.js.map +1 -1
- package/lib/store/repositories/post-thread-repository.d.ts +6 -6
- package/lib/store/repositories/post-thread-repository.js +5 -2
- package/lib/store/repositories/post-thread-repository.js.map +1 -1
- package/lib/store/repositories/reaction-repository.d.ts +6 -6
- package/lib/store/repositories/reaction-repository.js +5 -2
- package/lib/store/repositories/reaction-repository.js.map +1 -1
- package/lib/templates/constants/SERVER_TYPES.ts.template +0 -3
- package/lib/templates/repositories/ChannelRepository.ts.template +3 -3
- package/lib/templates/repositories/PostRepository.ts.template +3 -3
- package/lib/templates/repositories/PostThreadRepository.ts.template +3 -3
- package/lib/templates/repositories/ReactionRepository.ts.template +3 -4
- package/lib/templates/services/ChannelService.ts.template +280 -39
- package/lib/templates/services/ExtendedTokenAccountService.ts.template +104 -9
- package/lib/templates/services/MessengerNotificationService.ts.template +94 -19
- package/lib/templates/services/PostService.ts.template +184 -20
- package/lib/templates/services/PostThreadService.ts.template +151 -6
- package/lib/templates/services/ReactionService.ts.template +129 -3
- package/lib/templates/services/RedisCacheManager.ts.template +22 -0
- package/package.json +6 -5
- package/lib/interfaces/context.d.ts +0 -14
- package/lib/store/models/common-options.js +0 -20
- package/lib/store/models/common-options.js.map +0 -1
|
@@ -1,6 +1,126 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { IReactionModel, IReactionInput, IReactionRepository, IReactionService, IReactionServiceInput, AsDomainType } from 'common/server';
|
|
2
|
+
import { BaseService2 } from '@common-stack/store-mongo';
|
|
3
|
+
import { CdmLogger } from '@cdm-logger/core';
|
|
4
|
+
import { Disposable, DisposableCollection } from '@adminide-stack/core';
|
|
5
|
+
/**
|
|
6
|
+
* Reaction Service Implementation
|
|
7
|
+
*
|
|
8
|
+
* This service handles reaction management within the messenger platform,
|
|
9
|
+
* providing comprehensive operations for handling emoji reactions, sentiment
|
|
10
|
+
* tracking, and user engagement features across posts, messages, and other
|
|
11
|
+
* interactive content.
|
|
12
|
+
*/
|
|
13
|
+
export declare class ReactionService extends BaseService2<IReactionModel> implements IReactionService, Disposable {
|
|
4
14
|
readonly reactionRepository: IReactionRepository;
|
|
5
|
-
|
|
15
|
+
protected readonly toDispose: DisposableCollection;
|
|
16
|
+
private logger;
|
|
17
|
+
constructor(reactionRepository: IReactionRepository, logger?: CdmLogger.ILogger);
|
|
18
|
+
/**
|
|
19
|
+
* Disposes of resources used by the service
|
|
20
|
+
*/
|
|
21
|
+
dispose(): void;
|
|
22
|
+
/**
|
|
23
|
+
* Adds a reaction to a post or message
|
|
24
|
+
*
|
|
25
|
+
* @description Creates a new reaction entry for a specific content item,
|
|
26
|
+
* handling duplicate detection and user validation.
|
|
27
|
+
*
|
|
28
|
+
* @param {IReactionServiceInput} data - Reaction creation data including user and reaction type
|
|
29
|
+
* @returns {Promise<AsDomainType<IReactionModel> | Error>} - Created reaction or error
|
|
30
|
+
*/
|
|
31
|
+
addReaction(data: IReactionServiceInput): Promise<AsDomainType<IReactionModel> | Error>;
|
|
32
|
+
/**
|
|
33
|
+
* Removes a reaction from a post or message
|
|
34
|
+
*
|
|
35
|
+
* @description Deletes an existing reaction entry, ensuring proper user
|
|
36
|
+
* authorization and content validation.
|
|
37
|
+
*
|
|
38
|
+
* @param {string} reactionId - The unique identifier of the reaction to remove
|
|
39
|
+
* @param {string} userId - The identifier of the user removing the reaction
|
|
40
|
+
* @returns {Promise<boolean | Error>} - Success status or error
|
|
41
|
+
*/
|
|
42
|
+
removeReaction(reactionId: string, userId: string): Promise<boolean | Error>;
|
|
43
|
+
/**
|
|
44
|
+
* Retrieves all reactions for a specific content item
|
|
45
|
+
*
|
|
46
|
+
* @description Fetches reaction data with aggregation and user information
|
|
47
|
+
* for display in the user interface.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} contentId - The identifier of the content (post, message, etc.)
|
|
50
|
+
* @param {string} contentType - The type of content being reacted to
|
|
51
|
+
* @returns {Promise<Array<AsDomainType<IReactionModel>> | Error>} - Array of reactions or error
|
|
52
|
+
*/
|
|
53
|
+
getReactionsByContent(contentId: string, contentType: string): Promise<Array<AsDomainType<IReactionModel>> | Error>;
|
|
54
|
+
/**
|
|
55
|
+
* Retrieves reaction statistics for content
|
|
56
|
+
*
|
|
57
|
+
* @description Provides aggregated reaction counts and statistics
|
|
58
|
+
* for analytics and display purposes.
|
|
59
|
+
*
|
|
60
|
+
* @param {string} contentId - The identifier of the content
|
|
61
|
+
* @param {string} contentType - The type of content
|
|
62
|
+
* @returns {Promise<any | Error>} - Reaction statistics or error
|
|
63
|
+
*/
|
|
64
|
+
getReactionStats(contentId: string, contentType: string): Promise<any | Error>;
|
|
65
|
+
/**
|
|
66
|
+
* Checks if a user has reacted to specific content
|
|
67
|
+
*
|
|
68
|
+
* @description Determines whether a user has already reacted to
|
|
69
|
+
* a piece of content, useful for UI state management.
|
|
70
|
+
*
|
|
71
|
+
* @param {string} contentId - The identifier of the content
|
|
72
|
+
* @param {string} userId - The identifier of the user
|
|
73
|
+
* @param {string} reactionType - The type of reaction to check
|
|
74
|
+
* @returns {Promise<boolean | Error>} - True if user has reacted, or error
|
|
75
|
+
*/
|
|
76
|
+
hasUserReacted(contentId: string, userId: string, reactionType: string): Promise<boolean | Error>;
|
|
77
|
+
/**
|
|
78
|
+
* Updates an existing reaction
|
|
79
|
+
*
|
|
80
|
+
* @description Modifies an existing reaction, typically changing
|
|
81
|
+
* the reaction type while maintaining the same user and content association.
|
|
82
|
+
*
|
|
83
|
+
* @param {string} reactionId - The unique identifier of the reaction
|
|
84
|
+
* @param {Partial<IReactionInput>} updates - The reaction updates to apply
|
|
85
|
+
* @returns {Promise<AsDomainType<IReactionModel> | Error>} - Updated reaction or error
|
|
86
|
+
*/
|
|
87
|
+
updateReaction(reactionId: string, updates: Partial<IReactionInput>): Promise<AsDomainType<IReactionModel> | Error>;
|
|
88
|
+
/**
|
|
89
|
+
* Removes all reactions from specific content
|
|
90
|
+
*
|
|
91
|
+
* @description Bulk removes all reactions from a content item,
|
|
92
|
+
* typically used during content deletion or moderation.
|
|
93
|
+
*
|
|
94
|
+
* @param {string} contentId - The identifier of the content
|
|
95
|
+
* @param {string} contentType - The type of content
|
|
96
|
+
* @returns {Promise<number | Error>} - Number of reactions removed or error
|
|
97
|
+
*/
|
|
98
|
+
removeAllReactionsByContent(contentId: string, contentType: string): Promise<number | Error>;
|
|
99
|
+
/**
|
|
100
|
+
* Retrieves reactions by user across all content
|
|
101
|
+
*
|
|
102
|
+
* @description Gets all reactions created by a specific user,
|
|
103
|
+
* useful for user activity tracking and analytics.
|
|
104
|
+
*
|
|
105
|
+
* @param {string} userId - The identifier of the user
|
|
106
|
+
* @param {number} limit - Maximum number of reactions to return
|
|
107
|
+
* @param {number} offset - Number of reactions to skip
|
|
108
|
+
* @returns {Promise<Array<AsDomainType<IReactionModel>> | Error>} - Array of user reactions or error
|
|
109
|
+
*/
|
|
110
|
+
getUserReactions(userId: string, limit?: number, offset?: number): Promise<Array<AsDomainType<IReactionModel>> | Error>;
|
|
111
|
+
/**
|
|
112
|
+
* Gets the most popular reactions across the platform
|
|
113
|
+
*
|
|
114
|
+
* @description Retrieves aggregated data about the most used reactions
|
|
115
|
+
* for analytics and trending features.
|
|
116
|
+
*
|
|
117
|
+
* @param {number} limit - Maximum number of popular reactions to return
|
|
118
|
+
* @param {Date} since - Optional date to filter reactions since
|
|
119
|
+
* @returns {Promise<Array<{ type: string; count: number; users: number }> | Error>} - Popular reactions or error
|
|
120
|
+
*/
|
|
121
|
+
getPopularReactions(limit?: number, since?: Date): Promise<Array<{
|
|
122
|
+
type: string;
|
|
123
|
+
count: number;
|
|
124
|
+
users: number;
|
|
125
|
+
}> | Error>;
|
|
6
126
|
}
|
|
@@ -1,8 +1,420 @@
|
|
|
1
|
-
import {__decorate,__param,__metadata}from'tslib';import {SERVER_TYPES}from'common';import {injectable,inject}from'inversify';import {
|
|
1
|
+
import {__decorate,__param,__metadata}from'tslib';import {SERVER_TYPES}from'common/server';import {injectable,inject}from'inversify';import {BaseService2}from'@common-stack/store-mongo';import'@cdm-logger/core';import {DisposableCollection}from'@adminide-stack/core';/**
|
|
2
|
+
* Reaction Service Implementation
|
|
3
|
+
*
|
|
4
|
+
* This service handles reaction management within the messenger platform,
|
|
5
|
+
* providing comprehensive operations for handling emoji reactions, sentiment
|
|
6
|
+
* tracking, and user engagement features across posts, messages, and other
|
|
7
|
+
* interactive content.
|
|
8
|
+
*/
|
|
9
|
+
let ReactionService = class ReactionService extends BaseService2 {
|
|
2
10
|
reactionRepository;
|
|
3
|
-
|
|
11
|
+
toDispose = new DisposableCollection();
|
|
12
|
+
logger;
|
|
13
|
+
constructor(reactionRepository, logger) {
|
|
4
14
|
super(reactionRepository);
|
|
5
15
|
this.reactionRepository = reactionRepository;
|
|
16
|
+
this.logger = logger?.child({
|
|
17
|
+
className: 'ReactionService'
|
|
18
|
+
}) || console;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Disposes of resources used by the service
|
|
22
|
+
*/
|
|
23
|
+
dispose() {
|
|
24
|
+
this.toDispose.dispose();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Adds a reaction to a post or message
|
|
28
|
+
*
|
|
29
|
+
* @description Creates a new reaction entry for a specific content item,
|
|
30
|
+
* handling duplicate detection and user validation.
|
|
31
|
+
*
|
|
32
|
+
* @param {IReactionServiceInput} data - Reaction creation data including user and reaction type
|
|
33
|
+
* @returns {Promise<AsDomainType<IReactionModel> | Error>} - Created reaction or error
|
|
34
|
+
*/
|
|
35
|
+
async addReaction(data) {
|
|
36
|
+
try {
|
|
37
|
+
if (!data.user) {
|
|
38
|
+
return new Error('User is required for reaction creation');
|
|
39
|
+
}
|
|
40
|
+
if (!data.post) {
|
|
41
|
+
return new Error('Post ID is required');
|
|
42
|
+
}
|
|
43
|
+
if (!data.reaction) {
|
|
44
|
+
return new Error('Reaction content is required');
|
|
45
|
+
}
|
|
46
|
+
// Check if user already reacted to this content with the same reaction type
|
|
47
|
+
const existingReaction = await this.hasUserReacted(data.post, data.user, data.reaction);
|
|
48
|
+
if (existingReaction === true) {
|
|
49
|
+
return new Error('User has already reacted with this reaction type');
|
|
50
|
+
}
|
|
51
|
+
// Create the reaction
|
|
52
|
+
const reactionData = {
|
|
53
|
+
...data,
|
|
54
|
+
createdAt: new Date(),
|
|
55
|
+
updatedAt: new Date()
|
|
56
|
+
}; // Type assertion to handle ObjectId conversion
|
|
57
|
+
const createdReaction = await this.reactionRepository.create(reactionData);
|
|
58
|
+
if (!createdReaction) {
|
|
59
|
+
return new Error('Failed to create reaction');
|
|
60
|
+
}
|
|
61
|
+
this.logger.debug('Reaction added successfully', {
|
|
62
|
+
reactionId: createdReaction.id,
|
|
63
|
+
user: data.user,
|
|
64
|
+
contentId: data.post
|
|
65
|
+
});
|
|
66
|
+
return createdReaction;
|
|
67
|
+
} catch (error) {
|
|
68
|
+
this.logger.error('Error adding reaction: %o', error);
|
|
69
|
+
return error instanceof Error ? error : new Error('Unknown error occurred while adding reaction');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Removes a reaction from a post or message
|
|
74
|
+
*
|
|
75
|
+
* @description Deletes an existing reaction entry, ensuring proper user
|
|
76
|
+
* authorization and content validation.
|
|
77
|
+
*
|
|
78
|
+
* @param {string} reactionId - The unique identifier of the reaction to remove
|
|
79
|
+
* @param {string} userId - The identifier of the user removing the reaction
|
|
80
|
+
* @returns {Promise<boolean | Error>} - Success status or error
|
|
81
|
+
*/
|
|
82
|
+
async removeReaction(reactionId, userId) {
|
|
83
|
+
try {
|
|
84
|
+
if (!reactionId) {
|
|
85
|
+
return new Error('Reaction ID is required');
|
|
86
|
+
}
|
|
87
|
+
if (!userId) {
|
|
88
|
+
return new Error('User ID is required');
|
|
89
|
+
}
|
|
90
|
+
// Get the reaction to verify ownership
|
|
91
|
+
const reaction = await this.get(reactionId);
|
|
92
|
+
if (!reaction) {
|
|
93
|
+
return new Error('Reaction not found');
|
|
94
|
+
}
|
|
95
|
+
// Verify user owns this reaction
|
|
96
|
+
if (reaction.user?.toString() !== userId) {
|
|
97
|
+
return new Error('User is not authorized to remove this reaction');
|
|
98
|
+
}
|
|
99
|
+
// Remove the reaction
|
|
100
|
+
const success = await this.reactionRepository.delete({
|
|
101
|
+
id: reactionId
|
|
102
|
+
});
|
|
103
|
+
if (success) {
|
|
104
|
+
this.logger.debug('Reaction removed successfully', {
|
|
105
|
+
reactionId,
|
|
106
|
+
userId
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return success;
|
|
110
|
+
} catch (error) {
|
|
111
|
+
this.logger.error('Error removing reaction: %o', error);
|
|
112
|
+
return error instanceof Error ? error : new Error('Unknown error occurred while removing reaction');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Retrieves all reactions for a specific content item
|
|
117
|
+
*
|
|
118
|
+
* @description Fetches reaction data with aggregation and user information
|
|
119
|
+
* for display in the user interface.
|
|
120
|
+
*
|
|
121
|
+
* @param {string} contentId - The identifier of the content (post, message, etc.)
|
|
122
|
+
* @param {string} contentType - The type of content being reacted to
|
|
123
|
+
* @returns {Promise<Array<AsDomainType<IReactionModel>> | Error>} - Array of reactions or error
|
|
124
|
+
*/
|
|
125
|
+
async getReactionsByContent(contentId, contentType) {
|
|
126
|
+
try {
|
|
127
|
+
if (!contentId) {
|
|
128
|
+
return new Error('Content ID is required');
|
|
129
|
+
}
|
|
130
|
+
if (!contentType) {
|
|
131
|
+
return new Error('Content type is required');
|
|
132
|
+
}
|
|
133
|
+
let criteria = {};
|
|
134
|
+
// Build criteria based on content type
|
|
135
|
+
switch (contentType.toLowerCase()) {
|
|
136
|
+
case 'post':
|
|
137
|
+
criteria.post = contentId;
|
|
138
|
+
break;
|
|
139
|
+
default:
|
|
140
|
+
return new Error(`Unsupported content type: ${contentType}`);
|
|
141
|
+
}
|
|
142
|
+
const reactions = await this.getAll({
|
|
143
|
+
criteria
|
|
144
|
+
});
|
|
145
|
+
this.logger.debug('Retrieved reactions for content', {
|
|
146
|
+
contentId,
|
|
147
|
+
contentType,
|
|
148
|
+
count: reactions.length
|
|
149
|
+
});
|
|
150
|
+
return reactions;
|
|
151
|
+
} catch (error) {
|
|
152
|
+
this.logger.error('Error getting reactions by content: %o', error);
|
|
153
|
+
return error instanceof Error ? error : new Error('Unknown error occurred while getting reactions');
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Retrieves reaction statistics for content
|
|
158
|
+
*
|
|
159
|
+
* @description Provides aggregated reaction counts and statistics
|
|
160
|
+
* for analytics and display purposes.
|
|
161
|
+
*
|
|
162
|
+
* @param {string} contentId - The identifier of the content
|
|
163
|
+
* @param {string} contentType - The type of content
|
|
164
|
+
* @returns {Promise<any | Error>} - Reaction statistics or error
|
|
165
|
+
*/
|
|
166
|
+
async getReactionStats(contentId, contentType) {
|
|
167
|
+
try {
|
|
168
|
+
const reactions = await this.getReactionsByContent(contentId, contentType);
|
|
169
|
+
if (reactions instanceof Error) {
|
|
170
|
+
return reactions;
|
|
171
|
+
}
|
|
172
|
+
// Aggregate reaction statistics
|
|
173
|
+
const stats = {
|
|
174
|
+
totalReactions: reactions.length,
|
|
175
|
+
uniqueUsers: new Set(reactions.map(r => r.user?.toString())).size,
|
|
176
|
+
reactionTypes: {},
|
|
177
|
+
topReactions: []
|
|
178
|
+
};
|
|
179
|
+
// Count reactions by type
|
|
180
|
+
const reactionCounts = {};
|
|
181
|
+
reactions.forEach(reaction => {
|
|
182
|
+
const key = reaction.reaction || 'unknown';
|
|
183
|
+
reactionCounts[key] = (reactionCounts[key] || 0) + 1;
|
|
184
|
+
});
|
|
185
|
+
// Sort reactions by count
|
|
186
|
+
const sortedReactions = Object.entries(reactionCounts).sort(([, a], [, b]) => b - a).map(([type, count]) => ({
|
|
187
|
+
type,
|
|
188
|
+
count
|
|
189
|
+
}));
|
|
190
|
+
stats.reactionTypes = reactionCounts;
|
|
191
|
+
stats.topReactions = sortedReactions.slice(0, 5); // Top 5 reactions
|
|
192
|
+
this.logger.debug('Generated reaction statistics', {
|
|
193
|
+
contentId,
|
|
194
|
+
contentType,
|
|
195
|
+
totalReactions: stats.totalReactions
|
|
196
|
+
});
|
|
197
|
+
return stats;
|
|
198
|
+
} catch (error) {
|
|
199
|
+
this.logger.error('Error getting reaction stats: %o', error);
|
|
200
|
+
return error instanceof Error ? error : new Error('Unknown error occurred while getting reaction stats');
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Checks if a user has reacted to specific content
|
|
205
|
+
*
|
|
206
|
+
* @description Determines whether a user has already reacted to
|
|
207
|
+
* a piece of content, useful for UI state management.
|
|
208
|
+
*
|
|
209
|
+
* @param {string} contentId - The identifier of the content
|
|
210
|
+
* @param {string} userId - The identifier of the user
|
|
211
|
+
* @param {string} reactionType - The type of reaction to check
|
|
212
|
+
* @returns {Promise<boolean | Error>} - True if user has reacted, or error
|
|
213
|
+
*/
|
|
214
|
+
async hasUserReacted(contentId, userId, reactionType) {
|
|
215
|
+
try {
|
|
216
|
+
if (!contentId || !userId || !reactionType) {
|
|
217
|
+
return new Error('Content ID, user ID, and reaction type are required');
|
|
218
|
+
}
|
|
219
|
+
const criteria = {
|
|
220
|
+
user: userId,
|
|
221
|
+
reaction: reactionType,
|
|
222
|
+
post: contentId
|
|
223
|
+
};
|
|
224
|
+
const existingReaction = await this.getAll({
|
|
225
|
+
criteria
|
|
226
|
+
});
|
|
227
|
+
return existingReaction.length > 0;
|
|
228
|
+
} catch (error) {
|
|
229
|
+
this.logger.error('Error checking if user has reacted: %o', error);
|
|
230
|
+
return error instanceof Error ? error : new Error('Unknown error occurred while checking user reaction');
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Updates an existing reaction
|
|
235
|
+
*
|
|
236
|
+
* @description Modifies an existing reaction, typically changing
|
|
237
|
+
* the reaction type while maintaining the same user and content association.
|
|
238
|
+
*
|
|
239
|
+
* @param {string} reactionId - The unique identifier of the reaction
|
|
240
|
+
* @param {Partial<IReactionInput>} updates - The reaction updates to apply
|
|
241
|
+
* @returns {Promise<AsDomainType<IReactionModel> | Error>} - Updated reaction or error
|
|
242
|
+
*/
|
|
243
|
+
async updateReaction(reactionId, updates) {
|
|
244
|
+
try {
|
|
245
|
+
if (!reactionId) {
|
|
246
|
+
return new Error('Reaction ID is required');
|
|
247
|
+
}
|
|
248
|
+
if (!updates || Object.keys(updates).length === 0) {
|
|
249
|
+
return new Error('Updates are required');
|
|
250
|
+
}
|
|
251
|
+
// Get existing reaction
|
|
252
|
+
const existingReaction = await this.get(reactionId);
|
|
253
|
+
if (!existingReaction) {
|
|
254
|
+
return new Error('Reaction not found');
|
|
255
|
+
}
|
|
256
|
+
// Prepare update data
|
|
257
|
+
const updateData = {
|
|
258
|
+
...updates,
|
|
259
|
+
updatedAt: new Date()
|
|
260
|
+
};
|
|
261
|
+
// Update the reaction
|
|
262
|
+
const updatedReaction = await this.update(reactionId, updateData);
|
|
263
|
+
if (!updatedReaction) {
|
|
264
|
+
return new Error('Failed to update reaction');
|
|
265
|
+
}
|
|
266
|
+
this.logger.debug('Reaction updated successfully', {
|
|
267
|
+
reactionId,
|
|
268
|
+
updates: Object.keys(updates)
|
|
269
|
+
});
|
|
270
|
+
return updatedReaction;
|
|
271
|
+
} catch (error) {
|
|
272
|
+
this.logger.error('Error updating reaction: %o', error);
|
|
273
|
+
return error instanceof Error ? error : new Error('Unknown error occurred while updating reaction');
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Removes all reactions from specific content
|
|
278
|
+
*
|
|
279
|
+
* @description Bulk removes all reactions from a content item,
|
|
280
|
+
* typically used during content deletion or moderation.
|
|
281
|
+
*
|
|
282
|
+
* @param {string} contentId - The identifier of the content
|
|
283
|
+
* @param {string} contentType - The type of content
|
|
284
|
+
* @returns {Promise<number | Error>} - Number of reactions removed or error
|
|
285
|
+
*/
|
|
286
|
+
async removeAllReactionsByContent(contentId, contentType) {
|
|
287
|
+
try {
|
|
288
|
+
if (!contentId) {
|
|
289
|
+
return new Error('Content ID is required');
|
|
290
|
+
}
|
|
291
|
+
if (!contentType) {
|
|
292
|
+
return new Error('Content type is required');
|
|
293
|
+
}
|
|
294
|
+
// Get all reactions for the content first to count them
|
|
295
|
+
const reactions = await this.getReactionsByContent(contentId, contentType);
|
|
296
|
+
if (reactions instanceof Error) {
|
|
297
|
+
return reactions;
|
|
298
|
+
}
|
|
299
|
+
let deletedCount = 0;
|
|
300
|
+
// Delete each reaction individually
|
|
301
|
+
for (const reaction of reactions) {
|
|
302
|
+
try {
|
|
303
|
+
const success = await this.reactionRepository.delete({
|
|
304
|
+
id: reaction.id
|
|
305
|
+
});
|
|
306
|
+
if (success) {
|
|
307
|
+
deletedCount++;
|
|
308
|
+
}
|
|
309
|
+
} catch (error) {
|
|
310
|
+
this.logger.warn('Failed to delete reaction', {
|
|
311
|
+
reactionId: reaction.id,
|
|
312
|
+
error: error.message
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
this.logger.debug('Bulk removed reactions from content', {
|
|
317
|
+
contentId,
|
|
318
|
+
contentType,
|
|
319
|
+
deletedCount
|
|
320
|
+
});
|
|
321
|
+
return deletedCount;
|
|
322
|
+
} catch (error) {
|
|
323
|
+
this.logger.error('Error removing all reactions by content: %o', error);
|
|
324
|
+
return error instanceof Error ? error : new Error('Unknown error occurred while removing reactions');
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Retrieves reactions by user across all content
|
|
329
|
+
*
|
|
330
|
+
* @description Gets all reactions created by a specific user,
|
|
331
|
+
* useful for user activity tracking and analytics.
|
|
332
|
+
*
|
|
333
|
+
* @param {string} userId - The identifier of the user
|
|
334
|
+
* @param {number} limit - Maximum number of reactions to return
|
|
335
|
+
* @param {number} offset - Number of reactions to skip
|
|
336
|
+
* @returns {Promise<Array<AsDomainType<IReactionModel>> | Error>} - Array of user reactions or error
|
|
337
|
+
*/
|
|
338
|
+
async getUserReactions(userId, limit = 50, offset = 0) {
|
|
339
|
+
try {
|
|
340
|
+
if (!userId) {
|
|
341
|
+
return new Error('User ID is required');
|
|
342
|
+
}
|
|
343
|
+
const reactions = await this.getAll({
|
|
344
|
+
criteria: {
|
|
345
|
+
user: userId
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
// Apply manual pagination since the base service doesn't support it
|
|
349
|
+
const paginatedReactions = reactions.slice(offset, offset + limit);
|
|
350
|
+
this.logger.debug('Retrieved user reactions', {
|
|
351
|
+
userId,
|
|
352
|
+
count: paginatedReactions.length,
|
|
353
|
+
limit,
|
|
354
|
+
offset
|
|
355
|
+
});
|
|
356
|
+
return paginatedReactions;
|
|
357
|
+
} catch (error) {
|
|
358
|
+
this.logger.error('Error getting user reactions: %o', error);
|
|
359
|
+
return error instanceof Error ? error : new Error('Unknown error occurred while getting user reactions');
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Gets the most popular reactions across the platform
|
|
364
|
+
*
|
|
365
|
+
* @description Retrieves aggregated data about the most used reactions
|
|
366
|
+
* for analytics and trending features.
|
|
367
|
+
*
|
|
368
|
+
* @param {number} limit - Maximum number of popular reactions to return
|
|
369
|
+
* @param {Date} since - Optional date to filter reactions since
|
|
370
|
+
* @returns {Promise<Array<{ type: string; count: number; users: number }> | Error>} - Popular reactions or error
|
|
371
|
+
*/
|
|
372
|
+
async getPopularReactions(limit = 10, since) {
|
|
373
|
+
try {
|
|
374
|
+
let criteria = {};
|
|
375
|
+
if (since) {
|
|
376
|
+
criteria.createdAt = {
|
|
377
|
+
$gte: since
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
const reactions = await this.getAll({
|
|
381
|
+
criteria
|
|
382
|
+
});
|
|
383
|
+
// Aggregate reactions by type
|
|
384
|
+
const reactionMap = new Map();
|
|
385
|
+
reactions.forEach(reaction => {
|
|
386
|
+
const type = reaction.reaction || 'unknown';
|
|
387
|
+
const userId = reaction.user?.toString() || '';
|
|
388
|
+
if (!reactionMap.has(type)) {
|
|
389
|
+
reactionMap.set(type, {
|
|
390
|
+
count: 0,
|
|
391
|
+
users: new Set()
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
const entry = reactionMap.get(type);
|
|
395
|
+
entry.count++;
|
|
396
|
+
if (userId) {
|
|
397
|
+
entry.users.add(userId);
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
// Convert to array and sort by count
|
|
401
|
+
const popularReactions = Array.from(reactionMap.entries()).map(([type, data]) => ({
|
|
402
|
+
type,
|
|
403
|
+
count: data.count,
|
|
404
|
+
users: data.users.size
|
|
405
|
+
})).sort((a, b) => b.count - a.count).slice(0, limit);
|
|
406
|
+
this.logger.debug('Generated popular reactions', {
|
|
407
|
+
totalTypes: reactionMap.size,
|
|
408
|
+
limit,
|
|
409
|
+
since: since?.toISOString()
|
|
410
|
+
});
|
|
411
|
+
return popularReactions;
|
|
412
|
+
} catch (error) {
|
|
413
|
+
this.logger.error('Error getting popular reactions: %o', error);
|
|
414
|
+
return error instanceof Error ? error : new Error('Unknown error occurred while getting popular reactions');
|
|
415
|
+
}
|
|
6
416
|
}
|
|
7
417
|
};
|
|
8
|
-
ReactionService = __decorate([injectable()
|
|
418
|
+
ReactionService = __decorate([injectable()
|
|
419
|
+
// @ts-ignore - Type compatibility issue between BaseService2 and IReactionService
|
|
420
|
+
, __param(0, inject(SERVER_TYPES.ReactionRepository)), __param(1, inject('Logger')), __metadata("design:paramtypes", [Object, Object])], ReactionService);export{ReactionService};//# sourceMappingURL=reaction-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reaction-service.js","sources":["../../src/services/reaction-service.ts"],"sourcesContent":[null],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reaction-service.js","sources":["../../src/services/reaction-service.ts"],"sourcesContent":[null],"names":[],"mappings":"2QAeA;;;;;;;AAOG;AAGI,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,YAA4B,CAAA;AAMhD,EAAA,kBAAA;AALM,EAAA,SAAA,GAAY,IAAA,oBAAwB,EAAA;AAC/C,EAAA,MAAA;aAIK,CAAA,kBAAA,EAAuC,MAEtB,EAAA;SAErB,CAAA,kBAAmB,CAAA;QAJf,CAAkB,kBAAA,GAAA;AAK3B,IAAA,IAAA,CAAA,MAAK,GAAA,MAAS,EAAA,KAAa,CAAA;MAC9B,SAAA,EAAA;AAED,KAAA,CAAA,IAAA,OAAA;;AAEG;;AAEC;SACH,GAAA;AAED,IAAA,IAAA,CAAA,SAAA,CAAA,OAAA,EAAA;;;;;;;;AAQG;;AAEC;AACI,EAAA,MAAA,WAAK,CAAA,IAAK,EAAI;AACV,IAAA,IAAA;eACH,CAAA,IAAA,EAAA;AAED,QAAA,OAAA,IAAK,KAAK,CAAA,wCAAO,CAAA;AACb;eACH,CAAA,IAAA,EAAA;AAED,QAAA,OAAA,IAAK,KAAK,CAAA,qBAAW,CAAA;AACjB;eACH,CAAA,QAAA,EAAA;eAE2E,IAAA,KAAA,CAAA,8BAAA,CAAA;AAC5E;AAEA;AACI,MAAA,MAAA,gBAAW,GAAA,MAAM,IAAA,CAAA,cAAA,CAAA,IAAA,CAAA,IAAA,EAAA,IAAA,CAAA,IAAA,EAAA,IAAkD,CAAC,QAAC,CAAA;0BACxE,KAAA,IAAA,EAAA;eAEqB,IAAA,KAAA,CAAA,kDAAA,CAAA;AACtB;AACI;wBACS,GAAE;;AAEP,QAAA,SAAiD,EAAA,IAAA,IAAA,EAAA;iBAEnD,EAAA,IAAA,IAAA;;AAGF,MAAA,MAAA,eAAW,GAAA,MAAM,IAAA,CAAA,kBAAA,CAA2B,MAAE,CAAA,YAAA,CAAA;0BACjD,EAAA;AAED,QAAA,OAAA,IAAW,KAAC,CAAK;;iBAET,CAAA,KAAM,CAAA,6BAAK,EAAA;kBACN,EAAA,eAAW,CAAA,EAAA;AACvB,QAAA,IAAA,EAAC,IAAC,CAAA,IAAA;AAEH,QAAA,SAAA,EAAO;QACX;aAAS,eAAQ;aACT;AACJ,MAAA,IAAA,CAAA,MAAA,CAAA,KAAY,CAAA,2BAA2B,EAAK,KAAA,CAAA;aAC/C,KAAA,YAAA,KAAA,GAAA,KAAA,GAAA,IAAA,KAAA,CAAA,8CAAA,CAAA;;AAGL;;;;;;;;;AASG;AACH;AACI,EAAA,MAAA,cAAK,CAAA,UAAA,EAAA,MAAA,EAAA;;AAEG,MAAA,IAAA,CAAA,UAAA,EAAO;eACV,IAAA,KAAA,CAAA,yBAAA,CAAA;;AAGG,MAAA,IAAA,CAAA,MAAA,EAAA;eACH,IAAA,KAAA,CAAA,qBAAA,CAAA;;;YAID,QAAa,GAAA,MAAG,IAAA,CAAA,GAAA,CAAA,UAAA,CAAA;AACZ,MAAA,IAAA,CAAA,QAAA,EAAA;eACH,IAAA,KAAA,CAAA,oBAAA,CAAA;;;AAIG,MAAA,IAAA,QAAA,CAAA,IAAO,EAAI,QAAM,EAAA,KAAA,MAAA,EAAA;eACpB,IAAA,KAAA,CAAA,gDAAA,CAAA;;AAGD;YAEA,OAAI,GAAA,MAAU,IAAA,CAAA,kBAAA,CAAA,MAAA,CAAA;AACV,QAAA,EAAA,EAAA;;;AAGC,QAAA,IAAA,CAAA,MAAE,CAAA,KAAA,CAAA,+BAAA,EAAA;oBACN;AAED,UAAA;SACH,CAAA;;aACO;AACJ,KAAA,CAAA,OAAA,KAAA,EAAY;UACf,CAAA,MAAA,CAAA,KAAA,CAAA,6BAAA,EAAA,KAAA,CAAA;MACJ,OAAA,KAAA,YAAA,KAAA,GAAA,KAAA,GAAA,IAAA,KAAA,CAAA,gDAAA,CAAA;AAED;;;;;;;;;AASG;AACH;AAII;6BACqB,CAAA,SAAA,EAAA,WAAA,EAAA;AACb,IAAA,IAAA;oBACH,EAAA;eAEG,IAAY,KAAA,CAAA,wBAAG,CAAA;AACf;sBACH,EAAA;eAEG,IAAA,KAAQ,CAAwB,0BAAG,CAAA;;AAGvC,MAAA,IAAA,QAAA,GAAmB,EAAA;AACf;AACI,MAAA,QAAA,WAAA,CAAA,WAAgB,EAAA;;AAEpB,UAAA,QAAA,CAAA,IAAA,GAAA,SAAA;AACI,UAAA;;iBAGF,IAAA,KAAA,CAAS,CAAG,0BAAoB,EAAA,WAAY,CAAA,CAAA,CAAA;AAElD;qBACa,GAAA,MAAA,IAAA,CAAA,MAAA,CAAA;;;AAGZ,MAAA,IAAA,CAAA,MAAE,CAAA,KAAA,CAAA,iCAAA,EAAA;AAEH,QAAA,SAAA;QACJ,WAAC;QAAC,KAAO,EAAA,SAAQ,CAAA;;AAEb,MAAA,OAAA,SAAY;aACf,KAAA,EAAA;MACJ,IAAA,CAAA,MAAA,CAAA,KAAA,CAAA,wCAAA,EAAA,KAAA,CAAA;AAED,MAAA,OAAA,KAAA,YAAA,KAAA,GAAA,KAAA,GAAA,IAAA,KAAA,CAAA,gDAAA,CAAA;;;;;;;;;AASG;AACH;AACI;;AAGI,EAAA,MAAA,gBAAa,CAAA,SAAA,EAAA,WAAoB,EAAA;AAC7B,IAAA,IAAA;YACJ,SAAC,GAAA,MAAA,IAAA,CAAA,qBAAA,CAAA,SAAA,EAAA,WAAA,CAAA;mBAE+B,YAAA,KAAA,EAAA;AAChC,QAAA,OAAA,SAAc;;;AAGV,MAAA,MAAA,KAAA,GAAA;AACA,QAAA,cAAA,EAAA,SAAgB,CAAA,MAAA;mBAClB,EAAA,IAAA,GAAA,CAAA,SAAA,CAAA,GAAA,CAAA,CAAA,IAAA,CAAA,CAAA,IAAA,EAAA,QAAA,EAAA,CAAA,CAAA,CAAA,IAAA;qBAEwB,EAAA,EAAA;oBACpB,EAAA;AACN,OAAA;AACI;AACA,MAAA,MAAA,cAAA,GAAA,EAAe;AACnB,MAAA,SAAG,CAAA,OAAA,CAAA,QAAA,IAAA;cAEuB,GAAA,GAAA,QAAA,CAAA,QAAA,IAAA,SAAA;AAC1B,QAAA,qCAAsC,CAAA,GAAA,CAAA;AACjC,OAAA,CAAA;AACA;AAEL,MAAA,MAAA,eAAM,GAAA,MAAgB,CAAA,OAAA,CAAA,cAAe,CAAA,CAAA,IAAA,CAAA,CAAA,GAAA,CAAA,CAAA,EAAA,GAAA,CAAA,CAAA,KAAA,CAAA,GAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,IAAA,EAAA,KAAA,CAAA,MAAA;AACrC,QAAA,IAAA;AAEA,QAAA;;yBAEe,GAAA,cAAA;wBACG,GAAA,eAAsB,CAAA,KAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA;AACvC,MAAA,IAAA,CAAA,MAAE,CAAA,KAAA,CAAA,+BAAA,EAAA;AAEH,QAAA,SAAA;QACJ,WAAC;QAAC,cAAc,EAAC,KAAA,CAAA;;AAEb,MAAA,OAAA,KAAA;aACH,KAAA,EAAA;MACJ,IAAA,CAAA,MAAA,CAAA,KAAA,CAAA,kCAAA,EAAA,KAAA,CAAA;AAED,MAAA,OAAA,KAAA,YAAA,KAAA,GAAA,KAAA,GAAA,IAAA,KAAA,CAAA,qDAAA,CAAA;;;;;;;;;;AAUG;AACH;AACI;;AAEQ,EAAA,MAAA,cAAA,CAAO,SAAS,EAAC,MAAA,EAAA,YAAA,EAAA;;AAGrB,MAAA,IAAA,CAAA,oBAAsC,IAAA,CAAA,YAAA,EAAA;AAClC,QAAA,OAAA,IAAA,KAAY,CAAA,qDAAA,CAAA;AACZ;AACA,MAAA,MAAA,QAAI,GAAW;cACjB,MAAA;AAEF,QAAA,QAAA,EAAM;;AAEL,OAAA;AAED,MAAA,MAAA,gBAAuB,GAAA,MAAO,IAAA,CAAA,MAAK,CAAA;QACvC;QAAE;aACM,gBAAa,CAAC,MAAwC,GAAA,CAAA;AAC1D,KAAA,CAAA,OAAA,KAAA,EAAY;UACf,CAAA,MAAA,CAAA,KAAA,CAAA,wCAAA,EAAA,KAAA,CAAA;MACJ,OAAA,KAAA,YAAA,KAAA,GAAA,KAAA,GAAA,IAAA,KAAA,CAAA,qDAAA,CAAA;AAED;;;;;;;;;AASG;AACH;AAII;sBACmB,CAAA,UAAG,EAAA,OAAA,EAAA;AACd,IAAA,IAAA;qBACH,EAAA;AAED,QAAA,OAAA,IAAK,KAAO,CAAI,yBAAqB,CAAA;AACjC;kBACH,IAAA,MAAA,CAAA,IAAA,CAAA,OAAA,CAAA,CAAA,MAAA,KAAA,CAAA,EAAA;eAEuB,IAAA,KAAA,CAAA,sBAAA,CAAA;;;AAGpB,MAAA,MAAA,gBAAW,GAAA,MAAM,IAAA,CAAA,GAAA,CAAA,UAAsB,CAAA;2BAC1C,EAAA;eAEqB,IAAA,KAAA,CAAA,oBAAA,CAAA;AACtB;AACI;sBACS,GAAA;kBACX;iBAEoB,EAAA,IAAA,IAAA;;;AAIlB,MAAA,MAAA,eAAW,GAAA,MAAM,IAAA,CAAA,MAAA,CAAA,UAAA,EAA2B,UAAE,CAAA;0BACjD,EAAA;AAED,QAAA,OAAA,IAAW,KAAC,CAAK;;AAEb,MAAA,IAAA,CAAA,MAAA,CAAA,KAAO,gCAAsB,EAAA;AAChC,QAAA,UAAE;AAEH,QAAA,OAAA,EAAA,mBAAuD;QAC3D;aAAS,eAAQ;aACT;AACJ,MAAA,IAAA,CAAA,MAAA,CAAA,KAAY,CAAA,6BAAgC,EAAA,KAAA,CAAK;aACpD,KAAA,YAAA,KAAA,GAAA,KAAA,GAAA,IAAA,KAAA,CAAA,gDAAA,CAAA;;AAGL;;;;;;;;;AASG;AACH;AACI,EAAA,MAAA,2BAAK,CAAA,SAAA,EAAA,WAAA,EAAA;;AAEG,MAAA,IAAA,CAAA,SAAA,EAAA;eACH,IAAA,KAAA,CAAA,wBAAA,CAAA;;AAGG,MAAA,IAAA,CAAA,WAAA,EAAW;eACd,IAAA,KAAA,CAAA,0BAAA,CAAA;;;AAKD,MAAA,MAAA,SAAa,GAAA,MAAA,IAAA,CAAA,qBAAoB,CAAA,SAAA,EAAA,WAAA,CAAA;AAC7B,MAAA,IAAA,SAAA,iBAAiB,EAAA;eACpB,SAAA;;sBAImC,GAAA,CAAA;AACpC;AACI,MAAA,KAAA,MAAA,QAAK,IAAA,SAAA,EAAA;AACD,QAAA,IAAA;uBACI,GAAA,UAAU,CAAA,kBAAA,CAAA,MAAA,CAAA;AACV,YAAA,EAAA,EAAA,QAAA,CAAA;;qBAEP,EAAA;wBAAQ,EAAA;AACL;wBACI;0BACK,CAAA,2BAAe,EAAA;AACvB,YAAA,UAAC,EAAC,QAAA,CAAA,EAAA;iBACN,EAAA,KAAA,CAAA;YACL;AAEA;;iBAEe,CAAA,KAAA,CAAA,qCAAA,EAAA;iBACC;AACf,QAAA,WAAE;AAEH,QAAA;QACJ;aAAS,YAAQ;aACT;AACJ,MAAA,IAAA,CAAA,MAAA,CAAA,KAAY,CAAA,6CAAsC,EAAA,KAAA,CAAA;aACrD,KAAA,YAAA,KAAA,GAAA,KAAA,GAAA,IAAA,KAAA,CAAA,iDAAA,CAAA;;AAGL;;;;;;;;;;AAUG;;AAMC,EAAA,MAAA,gBAAK,CAAA,MAAA,EAAA,KAAA,GAAA,EAAA,EAAA,MAAA,GAAA,CAAA,EAAA;;AAEG,MAAA,IAAA,CAAA,MAAA,EAAA;eACH,IAAA,KAAA,CAAA,qBAAA,CAAA;AAED;AACI,MAAA,MAAA,SAAA,GAAQ,MAAQ,IAAE,OAAQ,CAAA;AAC7B,QAAA,QAAE,EAAA;cAEiE,EAAA;AACpE;AAEA,OAAA,CAAA;;8BAE6B,GAAA,SAAC,CAAM,KAAA,CAAA,MAAA,EAAA,MAAA,GAAA,KAAA,CAAA;iBAC3B,CAAA,KAAA,CAAA,0BAAA,EAAA;;AAER,QAAA,KAAA,EAAE,kBAAA,CAAA,MAAA;AAEH,QAAA,KAAA;QACJ;QAAE;aACM,kBAAgD;AACpD,KAAA,CAAA,OAAA,KAAA,EAAY;UACf,CAAA,MAAA,CAAA,KAAA,CAAA,kCAAA,EAAA,KAAA,CAAA;MACJ,OAAA,KAAA,YAAA,KAAA,GAAA,KAAA,GAAA,IAAA,KAAA,CAAA,qDAAA,CAAA;AAED;;;;;;;;;AASG;AACH;AAII;2BACwC,CAAA,KAAG,GAAA,EAAA,EAAA,KAAA,EAAA;;kBAG3B,GAAA,EAAA;eACX,EAAA;gBAEK,CAAA,SAAA,GAAY;cAEY,EAAA;AAC9B,SAAA;AAEA;AACI,MAAA,MAAA,SAAA,SAAc,IAAA,CAAA,MAAyB,CAAA;;;AAInC;uBACH,GAAA,IAAA,GAAA,EAAA;gBAED,OAAM,CAAA,QAAmB,IAAA;kBACpB,GAAA,QAAQ,CAAC,QAAA,IAAA,SAAA;oBACV,GAAA,QAAS,CAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA;AACT,QAAA,IAAA,CAAA,WAAA,CAAK,GAAM,CAAA,OAAK;qBACnB,CAAA,GAAA,CAAA,IAAA,EAAA;AACL,YAAA,KAAG,EAAA,CAAA;YAEH,KAAqC,EAAA,IAAA,GAAA;YACrC;;mBAEY,GAAA,WAAA,CAAA,GAAA,CAAA,IAAA,CAAA;mBACC,EAAA;AACL,QAAA,IAAA,MAAA,EAAA;AACH,UAAA,KAAE,CAAA,KAAA,CAAA,GAAA,CAAA,MAAA,CAAA;AACF;AACA,OAAA,CAAA;AAEL;4BACgB,GAAW,KAAA,CAAA,IAAK,CAAA,WAAA,CAAA,OAAA,EAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,IAAA,EAAA,IAAA,CAAA,MAAA;;AAE5B,QAAA,KAAA,EAAA,IAAA,CAAA,KAAO;AACV,QAAA,KAAA,EAAE,IAAA,CAAA,KAAA,CAAA;AAEH,OAAA,CAAA,CAAA,CAAA,IAAA,CAAA,CAAA,CAAA,EAAO,gBAAgB,CAAC,CAAA,KAAA,CAAA,CAAA,KAAA,CAAA,CAAA,EAAA,KAAA,CAAA;UAC3B,CAAA,MAAA,CAAA,KAAA,CAAA,6BAAA,EAAA;QAAC,UAAO,EAAK,WAAG,CAAA,IAAA;aACT;AACJ,QAAA,KAAA,EAAA,KAAY,EAAA,WAAA;QAChB;MACH,OAAA,gBAAA;KACJ,CAAA,OAAA,KAAA,EAAA;AA9dY,MAAe,IAAA,CAAA,MAAA,CAAA,KAAA,CAAA,qCAAA,EAAA,KAAA,CAAA;AAF3B,MAAA,OAAA,KAAY,YAAA,KAAA,GAAA,KAAA,GAAA,IAAA,KAAA,CAAA,wDAAA,CAAA;;;AAOJ;AAEA,eAAA,GAAM,UAAS,CAAA,CAAA,UAAC;;AAPZ,EAAA,OAAA,CAAA,CAAA,EAAA,MA8dZ,CAAA,YAAA,CAAA,kBAAA,CAAA,CAAA,EAAA,OAAA,CAAA,CAAA,EAAA,MAAA,CAAA,QAAA,CAAA,CAAA,EAAA,UAAA,CAAA,mBAAA,EAAA,CAAA,MAAA,EAAA,MAAA,CAAA,CAAA,CAAA,EAAA,eAAA,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Redis } from 'ioredis';
|
|
2
|
+
import { CacheContext, IRedisCacheManager } from 'common/server';
|
|
3
|
+
import { CdmLogger } from '@cdm-logger/core';
|
|
4
|
+
import { DocumentNode } from '@apollo/client/index.js';
|
|
5
|
+
export declare class RedisCacheManager implements IRedisCacheManager {
|
|
6
|
+
protected readonly redisClient: Redis;
|
|
7
|
+
protected logger: CdmLogger.ILogger;
|
|
8
|
+
constructor(redisClient: Redis, logger: CdmLogger.ILogger);
|
|
9
|
+
del(query: string | DocumentNode, variables?: Record<string, unknown>, ctx?: CacheContext, shouldRemoveAll?: boolean): Promise<void>;
|
|
10
|
+
get<T>(query: string | DocumentNode, variables: Record<string, any>, ctx: CacheContext): Promise<T>;
|
|
11
|
+
set<T>(query: string | DocumentNode, variables: Record<string, any>, data: T, ctx: CacheContext, cachePolicy?: {
|
|
12
|
+
maxAge: number;
|
|
13
|
+
scope: string;
|
|
14
|
+
}): Promise<void>;
|
|
15
|
+
private getQueryName;
|
|
16
|
+
private getWildCardQueryKey;
|
|
17
|
+
private getCacheKey;
|
|
18
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import {__decorate,__param,__metadata}from'tslib';import {generateQueryCacheKey}from'@common-stack/server-core';import {print}from'graphql';import {injectable,inject}from'inversify';import {CommonType}from'@common-stack/core';import'@cdm-logger/core';import isEmpty from'lodash-es/isEmpty';import {config}from'../config/env-config.js';var RedisCacheManager_1;
|
|
2
|
+
let RedisCacheManager = RedisCacheManager_1 = class RedisCacheManager {
|
|
3
|
+
redisClient;
|
|
4
|
+
logger;
|
|
5
|
+
constructor(redisClient, logger) {
|
|
6
|
+
this.redisClient = redisClient;
|
|
7
|
+
this.logger = logger.child({
|
|
8
|
+
className: RedisCacheManager_1.name
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
async del(query, variables, ctx, shouldRemoveAll = false) {
|
|
12
|
+
let cacheKey = this.getCacheKey(query, variables ?? {}, ctx);
|
|
13
|
+
if (!isEmpty(variables)) {
|
|
14
|
+
this.logger.debug(`Deleting ${cacheKey} from redis`);
|
|
15
|
+
await this.redisClient.del(cacheKey);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const keysWithWildCard = shouldRemoveAll ? this.getWildCardQueryKey(query, ctx) : `${cacheKey.substring(0, cacheKey.lastIndexOf(':'))}:*`;
|
|
19
|
+
const cacheKeys = await this.redisClient.keys(keysWithWildCard);
|
|
20
|
+
this.logger.debug(`Found ${cacheKeys.length} ${JSON.stringify(cacheKeys)} against key ${keysWithWildCard}`);
|
|
21
|
+
if (cacheKeys.length) {
|
|
22
|
+
this.logger.debug(`Deleting ${cacheKeys.length} ${JSON.stringify(cacheKeys)} from redis`);
|
|
23
|
+
await this.redisClient.del(...cacheKeys);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async get(query, variables, ctx) {
|
|
27
|
+
const cacheKey = this.getCacheKey(query, variables, ctx);
|
|
28
|
+
const cacheResponse = await this.redisClient.get(cacheKey);
|
|
29
|
+
if (cacheResponse) {
|
|
30
|
+
const {
|
|
31
|
+
data
|
|
32
|
+
} = JSON.parse(JSON.parse(cacheResponse)?.value) ?? {};
|
|
33
|
+
const queryName = this.getQueryName(query);
|
|
34
|
+
this.logger.debug(`Found Cache for ${cacheKey}`);
|
|
35
|
+
return data?.[queryName];
|
|
36
|
+
}
|
|
37
|
+
this.logger.debug(`No Cache Found for key ${cacheKey}`);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
async set(query, variables, data, ctx, cachePolicy = {
|
|
41
|
+
maxAge: 86400,
|
|
42
|
+
scope: 'PUBLIC'
|
|
43
|
+
}) {
|
|
44
|
+
const cacheKey = this.getCacheKey(query, variables, ctx);
|
|
45
|
+
const cacheTime = Date.now();
|
|
46
|
+
this.logger.debug(`Set Cache Query for key ${cacheKey}`);
|
|
47
|
+
await this.redisClient.set(cacheKey, JSON.stringify({
|
|
48
|
+
value: JSON.stringify({
|
|
49
|
+
data: {
|
|
50
|
+
[this.getQueryName(query)]: data
|
|
51
|
+
},
|
|
52
|
+
cachePolicy,
|
|
53
|
+
cacheTime
|
|
54
|
+
}),
|
|
55
|
+
expires: cacheTime + cachePolicy.maxAge * 1000
|
|
56
|
+
}).trim(), 'EX', cachePolicy.maxAge);
|
|
57
|
+
}
|
|
58
|
+
getQueryName(query) {
|
|
59
|
+
const queryStr = typeof query === 'string' ? query : print(query);
|
|
60
|
+
const [, queryName] = queryStr?.match(/{\s*(\w+)/) ?? [];
|
|
61
|
+
return queryName;
|
|
62
|
+
}
|
|
63
|
+
getWildCardQueryKey(query, ctx) {
|
|
64
|
+
const queryStr = typeof query === 'string' ? query : print(query);
|
|
65
|
+
const [, queryName] = queryStr?.match(/{\s*(\w+)/) ?? [];
|
|
66
|
+
const {
|
|
67
|
+
tenantId,
|
|
68
|
+
userId
|
|
69
|
+
} = ctx;
|
|
70
|
+
const prefix = `${tenantId ? `:${tenantId}` : ''}${userId ? `:${userId}` : ''}`;
|
|
71
|
+
return `${config.APP_NAME}${prefix}:*${queryName}:*`;
|
|
72
|
+
}
|
|
73
|
+
getCacheKey(query, variables, ctx) {
|
|
74
|
+
const key = generateQueryCacheKey({
|
|
75
|
+
query,
|
|
76
|
+
variables,
|
|
77
|
+
logger: this.logger,
|
|
78
|
+
...ctx
|
|
79
|
+
});
|
|
80
|
+
return `${config.APP_NAME}:${key}`;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
RedisCacheManager = RedisCacheManager_1 = __decorate([injectable(), __param(0, inject(CommonType.REDIS_CLIENT)), __param(1, inject('Logger')), __metadata("design:paramtypes", [Function, Object])], RedisCacheManager);export{RedisCacheManager};//# sourceMappingURL=redis-cache-manager.js.map
|