@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.
Files changed (149) hide show
  1. package/lib/containers/containers.js +4 -1
  2. package/lib/containers/containers.js.map +1 -1
  3. package/lib/containers/context-services-from-container.d.ts +1 -1
  4. package/lib/containers/context-services-from-container.js +1 -1
  5. package/lib/containers/context-services-from-container.js.map +1 -1
  6. package/lib/graphql/resolvers/channel-member.d.ts +3 -2
  7. package/lib/graphql/resolvers/channel-member.js +30 -5
  8. package/lib/graphql/resolvers/channel-member.js.map +1 -1
  9. package/lib/graphql/resolvers/channel.d.ts +3 -2
  10. package/lib/graphql/resolvers/channel.js +279 -53
  11. package/lib/graphql/resolvers/channel.js.map +1 -1
  12. package/lib/graphql/resolvers/extended-token-account.d.ts +3 -2
  13. package/lib/graphql/resolvers/extended-token-account.js +90 -23
  14. package/lib/graphql/resolvers/extended-token-account.js.map +1 -1
  15. package/lib/graphql/resolvers/index.d.ts +1 -1
  16. package/lib/graphql/resolvers/post-thread.d.ts +1 -1
  17. package/lib/graphql/resolvers/post-thread.js +294 -132
  18. package/lib/graphql/resolvers/post-thread.js.map +1 -1
  19. package/lib/graphql/resolvers/post.d.ts +2 -3
  20. package/lib/graphql/resolvers/post.js +696 -234
  21. package/lib/graphql/resolvers/post.js.map +1 -1
  22. package/lib/graphql/resolvers/reaction.d.ts +3 -2
  23. package/lib/graphql/resolvers/reaction.js +96 -14
  24. package/lib/graphql/resolvers/reaction.js.map +1 -1
  25. package/lib/graphql/schema/channel-member.graphql +110 -21
  26. package/lib/graphql/schema/channel-member.graphql.js +1 -1
  27. package/lib/graphql/schema/channel.graphql +337 -38
  28. package/lib/graphql/schema/channel.graphql.js +1 -1
  29. package/lib/graphql/schema/post-thread.graphql +167 -21
  30. package/lib/graphql/schema/post-thread.graphql.js +1 -1
  31. package/lib/graphql/schema/post.graphql +284 -40
  32. package/lib/graphql/schema/post.graphql.js +1 -1
  33. package/lib/graphql/schema/reaction.graphql +71 -13
  34. package/lib/graphql/schema/reaction.graphql.js +1 -1
  35. package/lib/graphql/schema/services.graphql +2 -0
  36. package/lib/graphql/schema/users.graphql +76 -13
  37. package/lib/graphql/schema/users.graphql.js +1 -1
  38. package/lib/index.js +1 -1
  39. package/lib/index.js.map +1 -1
  40. package/lib/interfaces/index.d.ts +0 -1
  41. package/lib/interfaces/services.d.ts +1 -1
  42. package/lib/migrations/dbMigrations/AddPostsConfigurationsMigration.d.ts +17 -0
  43. package/lib/migrations/dbMigrations/AddPostsConfigurationsMigration.js +44 -0
  44. package/lib/migrations/dbMigrations/AddPostsConfigurationsMigration.js.map +1 -0
  45. package/lib/migrations/dbMigrations/index.d.ts +1 -0
  46. package/lib/migrations/index.d.ts +1 -0
  47. package/lib/migrations/mail-template-migration.js +1 -1
  48. package/lib/migrations/message-notification-template-migration.d.ts +1 -1
  49. package/lib/migrations/message-notification-template-migration.js +1 -1
  50. package/lib/plugins/channel-moleculer-service.d.ts +21 -1
  51. package/lib/plugins/channel-moleculer-service.js +417 -115
  52. package/lib/plugins/channel-moleculer-service.js.map +1 -1
  53. package/lib/plugins/extended-token-account-moleculer-service.d.ts +25 -1
  54. package/lib/plugins/extended-token-account-moleculer-service.js +348 -22
  55. package/lib/plugins/extended-token-account-moleculer-service.js.map +1 -1
  56. package/lib/plugins/messenger-notification-moleculer-service.d.ts +27 -3
  57. package/lib/plugins/messenger-notification-moleculer-service.js +404 -58
  58. package/lib/plugins/messenger-notification-moleculer-service.js.map +1 -1
  59. package/lib/plugins/post-moleculer-service.d.ts +85 -21
  60. package/lib/plugins/post-moleculer-service.js +986 -256
  61. package/lib/plugins/post-moleculer-service.js.map +1 -1
  62. package/lib/plugins/post-thread-moleculer-service.d.ts +33 -1
  63. package/lib/plugins/post-thread-moleculer-service.js +326 -8
  64. package/lib/plugins/post-thread-moleculer-service.js.map +1 -1
  65. package/lib/plugins/reaction-moleculer-service.js +1 -1
  66. package/lib/plugins/reaction-moleculer-service.js.map +1 -1
  67. package/lib/preferences/settings/post-settings.d.ts +2 -0
  68. package/lib/preferences/settings/post-settings.js +47 -9
  69. package/lib/preferences/settings/post-settings.js.map +1 -1
  70. package/lib/services/channel-service.d.ts +179 -33
  71. package/lib/services/channel-service.js +821 -274
  72. package/lib/services/channel-service.js.map +1 -1
  73. package/lib/services/extended-token-account-service.d.ts +130 -14
  74. package/lib/services/extended-token-account-service.js +462 -52
  75. package/lib/services/extended-token-account-service.js.map +1 -1
  76. package/lib/services/index.d.ts +1 -0
  77. package/lib/services/messenger-notification-service.d.ts +106 -13
  78. package/lib/services/messenger-notification-service.js +824 -442
  79. package/lib/services/messenger-notification-service.js.map +1 -1
  80. package/lib/services/post-service.d.ts +182 -16
  81. package/lib/services/post-service.js +731 -115
  82. package/lib/services/post-service.js.map +1 -1
  83. package/lib/services/post-thread-service.d.ts +114 -5
  84. package/lib/services/post-thread-service.js +400 -13
  85. package/lib/services/post-thread-service.js.map +1 -1
  86. package/lib/services/proxy-services/channel-microservice.d.ts +5 -3
  87. package/lib/services/proxy-services/channel-microservice.js +19 -10
  88. package/lib/services/proxy-services/channel-microservice.js.map +1 -1
  89. package/lib/services/proxy-services/messenger-notification-microservice.d.ts +128 -8
  90. package/lib/services/proxy-services/messenger-notification-microservice.js +324 -29
  91. package/lib/services/proxy-services/messenger-notification-microservice.js.map +1 -1
  92. package/lib/services/proxy-services/post-microservice.d.ts +186 -12
  93. package/lib/services/proxy-services/post-microservice.js +543 -54
  94. package/lib/services/proxy-services/post-microservice.js.map +1 -1
  95. package/lib/services/proxy-services/post-thread-microservice.d.ts +134 -3
  96. package/lib/services/proxy-services/post-thread-microservice.js +388 -6
  97. package/lib/services/proxy-services/post-thread-microservice.js.map +1 -1
  98. package/lib/services/proxy-services/reaction-microservice.d.ts +161 -3
  99. package/lib/services/proxy-services/reaction-microservice.js +474 -2
  100. package/lib/services/proxy-services/reaction-microservice.js.map +1 -1
  101. package/lib/services/reaction-service.d.ts +124 -4
  102. package/lib/services/reaction-service.js +415 -3
  103. package/lib/services/reaction-service.js.map +1 -1
  104. package/lib/services/redis-cache-manager.d.ts +18 -0
  105. package/lib/services/redis-cache-manager.js +83 -0
  106. package/lib/services/redis-cache-manager.js.map +1 -0
  107. package/lib/store/models/account-token-store.d.ts +1 -1
  108. package/lib/store/models/account-token-store.js.map +1 -1
  109. package/lib/store/models/channel.d.ts +2 -3
  110. package/lib/store/models/channel.js +181 -72
  111. package/lib/store/models/channel.js.map +1 -1
  112. package/lib/store/models/post-thread.d.ts +3 -3
  113. package/lib/store/models/post-thread.js +96 -14
  114. package/lib/store/models/post-thread.js.map +1 -1
  115. package/lib/store/models/post.d.ts +2 -3
  116. package/lib/store/models/post.js +143 -23
  117. package/lib/store/models/post.js.map +1 -1
  118. package/lib/store/models/reaction.d.ts +2 -3
  119. package/lib/store/models/reaction.js +67 -8
  120. package/lib/store/models/reaction.js.map +1 -1
  121. package/lib/store/repositories/__tests__/__fixtures__/team-repository.d.ts +3 -3
  122. package/lib/store/repositories/channel-repository.d.ts +6 -6
  123. package/lib/store/repositories/channel-repository.js +5 -2
  124. package/lib/store/repositories/channel-repository.js.map +1 -1
  125. package/lib/store/repositories/post-repository.d.ts +6 -6
  126. package/lib/store/repositories/post-repository.js +5 -2
  127. package/lib/store/repositories/post-repository.js.map +1 -1
  128. package/lib/store/repositories/post-thread-repository.d.ts +6 -6
  129. package/lib/store/repositories/post-thread-repository.js +5 -2
  130. package/lib/store/repositories/post-thread-repository.js.map +1 -1
  131. package/lib/store/repositories/reaction-repository.d.ts +6 -6
  132. package/lib/store/repositories/reaction-repository.js +5 -2
  133. package/lib/store/repositories/reaction-repository.js.map +1 -1
  134. package/lib/templates/constants/SERVER_TYPES.ts.template +0 -3
  135. package/lib/templates/repositories/ChannelRepository.ts.template +3 -3
  136. package/lib/templates/repositories/PostRepository.ts.template +3 -3
  137. package/lib/templates/repositories/PostThreadRepository.ts.template +3 -3
  138. package/lib/templates/repositories/ReactionRepository.ts.template +3 -4
  139. package/lib/templates/services/ChannelService.ts.template +280 -39
  140. package/lib/templates/services/ExtendedTokenAccountService.ts.template +104 -9
  141. package/lib/templates/services/MessengerNotificationService.ts.template +94 -19
  142. package/lib/templates/services/PostService.ts.template +184 -20
  143. package/lib/templates/services/PostThreadService.ts.template +151 -6
  144. package/lib/templates/services/ReactionService.ts.template +129 -3
  145. package/lib/templates/services/RedisCacheManager.ts.template +22 -0
  146. package/package.json +6 -5
  147. package/lib/interfaces/context.d.ts +0 -14
  148. package/lib/store/models/common-options.js +0 -20
  149. package/lib/store/models/common-options.js.map +0 -1
@@ -1,6 +1,126 @@
1
- import { IReaction, IReactionInput, IReactionRepository, IReactionService, IReactionServiceInput } from 'common';
2
- import { BaseService } from '@common-stack/store-mongo';
3
- export declare class ReactionService extends BaseService<IReaction, IReactionServiceInput, Partial<IReactionInput>> implements IReactionService {
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
- constructor(reactionRepository: IReactionRepository);
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 {BaseService}from'@common-stack/store-mongo';let ReactionService = class ReactionService extends BaseService {
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
- constructor(reactionRepository) {
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(), __param(0, inject(SERVER_TYPES.ReactionRepository)), __metadata("design:paramtypes", [Object])], ReactionService);export{ReactionService};//# sourceMappingURL=reaction-service.js.map
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":"kLAYO,IAAM,eAAe,GAArB,MAAM,eACT,SAAQ,WAAsE,CAAA;AAKjE,EAAA,kBAAA;AAFb,EAAA,WAAA,CAAA,kBAEoD,EAAA;SAE3C,CAAA,kBAA4B,CAAA;QAFxB,CAAkB,kBAAA,GAAA;;;AANtB,eAAe,GAAA,UAAA,CAAA,CAAA,UAAA,EAAA,EAAA,OAAA,CAAA,CAAA,EAAA,MAAA,CAAA,YAAA,CAAA,kBAAA,CAAA,CAAA,EAAA,UAAA,CAAA,mBAAA,EAAA,CAAA,MAAA,CAAA,CAAA,CAAA,EAAA,eAAA,CAAA"}
1
+ {"version":3,"file":"reaction-service.js","sources":["../../src/services/reaction-service.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
@@ -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