@messenger-box/platform-server 10.0.3-alpha.50 → 10.0.3-alpha.54

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 (111) hide show
  1. package/lib/containers/containers.js.map +1 -1
  2. package/lib/graphql/resolvers/channel-member.d.ts +2 -1
  3. package/lib/graphql/resolvers/channel-member.js +13 -3
  4. package/lib/graphql/resolvers/channel-member.js.map +1 -1
  5. package/lib/graphql/resolvers/channel.d.ts +2 -1
  6. package/lib/graphql/resolvers/channel.js +260 -126
  7. package/lib/graphql/resolvers/channel.js.map +1 -1
  8. package/lib/graphql/resolvers/extended-token-account.d.ts +2 -1
  9. package/lib/graphql/resolvers/extended-token-account.js +90 -23
  10. package/lib/graphql/resolvers/extended-token-account.js.map +1 -1
  11. package/lib/graphql/resolvers/post-thread.js +285 -179
  12. package/lib/graphql/resolvers/post-thread.js.map +1 -1
  13. package/lib/graphql/resolvers/post.js +669 -242
  14. package/lib/graphql/resolvers/post.js.map +1 -1
  15. package/lib/graphql/resolvers/reaction.d.ts +2 -1
  16. package/lib/graphql/resolvers/reaction.js +96 -14
  17. package/lib/graphql/resolvers/reaction.js.map +1 -1
  18. package/lib/graphql/schema/channel.graphql +331 -39
  19. package/lib/graphql/schema/channel.graphql.js +1 -1
  20. package/lib/graphql/schema/post-thread.graphql +157 -21
  21. package/lib/graphql/schema/post-thread.graphql.js +1 -1
  22. package/lib/graphql/schema/post.graphql +265 -40
  23. package/lib/graphql/schema/post.graphql.js +1 -1
  24. package/lib/graphql/schema/reaction.graphql +71 -13
  25. package/lib/graphql/schema/reaction.graphql.js +1 -1
  26. package/lib/graphql/schema/users.graphql +76 -13
  27. package/lib/graphql/schema/users.graphql.js +1 -1
  28. package/lib/plugins/channel-moleculer-service.d.ts +21 -1
  29. package/lib/plugins/channel-moleculer-service.js +417 -115
  30. package/lib/plugins/channel-moleculer-service.js.map +1 -1
  31. package/lib/plugins/extended-token-account-moleculer-service.d.ts +25 -1
  32. package/lib/plugins/extended-token-account-moleculer-service.js +348 -22
  33. package/lib/plugins/extended-token-account-moleculer-service.js.map +1 -1
  34. package/lib/plugins/messenger-notification-moleculer-service.d.ts +26 -3
  35. package/lib/plugins/messenger-notification-moleculer-service.js +403 -57
  36. package/lib/plugins/messenger-notification-moleculer-service.js.map +1 -1
  37. package/lib/plugins/post-moleculer-service.d.ts +84 -20
  38. package/lib/plugins/post-moleculer-service.js +891 -259
  39. package/lib/plugins/post-moleculer-service.js.map +1 -1
  40. package/lib/plugins/post-thread-moleculer-service.d.ts +33 -1
  41. package/lib/plugins/post-thread-moleculer-service.js +320 -13
  42. package/lib/plugins/post-thread-moleculer-service.js.map +1 -1
  43. package/lib/services/channel-service.d.ts +185 -33
  44. package/lib/services/channel-service.js +767 -282
  45. package/lib/services/channel-service.js.map +1 -1
  46. package/lib/services/extended-token-account-service.d.ts +127 -14
  47. package/lib/services/extended-token-account-service.js +459 -52
  48. package/lib/services/extended-token-account-service.js.map +1 -1
  49. package/lib/services/messenger-notification-service.d.ts +106 -13
  50. package/lib/services/messenger-notification-service.js +824 -442
  51. package/lib/services/messenger-notification-service.js.map +1 -1
  52. package/lib/services/post-service.d.ts +176 -16
  53. package/lib/services/post-service.js +553 -119
  54. package/lib/services/post-service.js.map +1 -1
  55. package/lib/services/post-thread-service.d.ts +114 -6
  56. package/lib/services/post-thread-service.js +397 -18
  57. package/lib/services/post-thread-service.js.map +1 -1
  58. package/lib/services/proxy-services/channel-microservice.d.ts +4 -3
  59. package/lib/services/proxy-services/channel-microservice.js +12 -9
  60. package/lib/services/proxy-services/channel-microservice.js.map +1 -1
  61. package/lib/services/proxy-services/messenger-notification-microservice.d.ts +128 -8
  62. package/lib/services/proxy-services/messenger-notification-microservice.js +324 -29
  63. package/lib/services/proxy-services/messenger-notification-microservice.js.map +1 -1
  64. package/lib/services/proxy-services/post-microservice.d.ts +186 -13
  65. package/lib/services/proxy-services/post-microservice.js +543 -59
  66. package/lib/services/proxy-services/post-microservice.js.map +1 -1
  67. package/lib/services/proxy-services/post-thread-microservice.d.ts +134 -4
  68. package/lib/services/proxy-services/post-thread-microservice.js +387 -10
  69. package/lib/services/proxy-services/post-thread-microservice.js.map +1 -1
  70. package/lib/services/proxy-services/reaction-microservice.d.ts +161 -3
  71. package/lib/services/proxy-services/reaction-microservice.js +474 -2
  72. package/lib/services/proxy-services/reaction-microservice.js.map +1 -1
  73. package/lib/services/reaction-service.d.ts +124 -4
  74. package/lib/services/reaction-service.js +415 -3
  75. package/lib/services/reaction-service.js.map +1 -1
  76. package/lib/store/models/channel.d.ts +2 -3
  77. package/lib/store/models/channel.js +169 -71
  78. package/lib/store/models/channel.js.map +1 -1
  79. package/lib/store/models/post-thread.d.ts +3 -3
  80. package/lib/store/models/post-thread.js +96 -14
  81. package/lib/store/models/post-thread.js.map +1 -1
  82. package/lib/store/models/post.d.ts +2 -3
  83. package/lib/store/models/post.js +85 -18
  84. package/lib/store/models/post.js.map +1 -1
  85. package/lib/store/models/reaction.d.ts +2 -3
  86. package/lib/store/models/reaction.js +67 -8
  87. package/lib/store/models/reaction.js.map +1 -1
  88. package/lib/store/repositories/channel-repository.d.ts +6 -6
  89. package/lib/store/repositories/channel-repository.js +5 -2
  90. package/lib/store/repositories/channel-repository.js.map +1 -1
  91. package/lib/store/repositories/post-repository.d.ts +6 -6
  92. package/lib/store/repositories/post-repository.js +5 -2
  93. package/lib/store/repositories/post-repository.js.map +1 -1
  94. package/lib/store/repositories/post-thread-repository.d.ts +6 -6
  95. package/lib/store/repositories/post-thread-repository.js +5 -2
  96. package/lib/store/repositories/post-thread-repository.js.map +1 -1
  97. package/lib/store/repositories/reaction-repository.d.ts +6 -6
  98. package/lib/store/repositories/reaction-repository.js +5 -2
  99. package/lib/store/repositories/reaction-repository.js.map +1 -1
  100. package/lib/templates/repositories/ChannelRepository.ts.template +3 -3
  101. package/lib/templates/repositories/PostRepository.ts.template +3 -3
  102. package/lib/templates/repositories/PostThreadRepository.ts.template +3 -3
  103. package/lib/templates/repositories/ReactionRepository.ts.template +3 -4
  104. package/lib/templates/services/ChannelService.ts.template +277 -38
  105. package/lib/templates/services/ExtendedTokenAccountService.ts.template +93 -8
  106. package/lib/templates/services/PostService.ts.template +182 -20
  107. package/lib/templates/services/PostThreadService.ts.template +100 -5
  108. package/lib/templates/services/ReactionService.ts.template +129 -2
  109. package/package.json +3 -3
  110. package/lib/store/models/common-options.js +0 -20
  111. package/lib/store/models/common-options.js.map +0 -1
@@ -1,129 +1,338 @@
1
- import {Service}from'moleculer';import {MoleculerTopics,SERVER_TYPES}from'common/server';import {ApolloClientMixin}from'@adminide-stack/platform-server';import {BaseServiceMixin}from'@common-stack/store-mongo';import uniqBy from'lodash/uniqBy';import {config}from'../config/env-config.js';// import { TYPES } from '../constants';
2
- // import { IPostService, IPostServiceInput } from '../interfaces';
1
+ import {Service}from'moleculer';import {MoleculerTopics,SERVER_TYPES}from'common/server';import {ApolloClientMixin}from'@adminide-stack/platform-server';import uniqBy from'lodash/uniqBy';import {logger}from'@common-stack/server-core';import {config}from'../config/env-config.js';/**
2
+ * Post Moleculer Service
3
+ * ----------------------
4
+ *
5
+ * This Moleculer service provides comprehensive post management capabilities within
6
+ * the messenger platform ecosystem. It acts as a distributed service layer for
7
+ * handling post creation, file attachments, message threading, real-time notifications,
8
+ * and cross-service communication.
9
+ *
10
+ * Key capabilities:
11
+ * - Post lifecycle management with threading support
12
+ * - File attachment and upload link generation
13
+ * - Real-time message delivery and read receipts
14
+ * - Post thread creation and management
15
+ * - Channel integration and message counting
16
+ * - Event-driven architecture for real-time updates
17
+ * - Distributed service communication via Moleculer
18
+ * - Comprehensive error handling and logging
19
+ *
20
+ * The service integrates with multiple platform components including channels,
21
+ * notifications, file management, and real-time publishing systems to provide
22
+ * a cohesive messaging experience across the platform.
23
+ */
24
+ /**
25
+ * PostMoleculerService Class
26
+ *
27
+ * Comprehensive Moleculer service for distributed post management operations.
28
+ * Provides event-driven architecture, real-time communication, and seamless
29
+ * integration with other platform services.
30
+ */
3
31
  class PostMoleculerService extends Service {
4
32
  postService;
33
+ container;
5
34
  constructor(broker, {
6
- container
35
+ container,
36
+ settings
7
37
  }) {
8
38
  super(broker);
39
+ this.container = container;
9
40
  const topic = MoleculerTopics.PostService;
10
41
  this.postService = container.get(SERVER_TYPES.PostService);
11
42
  this.pubsub = container.get('PubSub');
43
+ logger.info(`Initializing PostMoleculerService with topic: ${topic}`);
12
44
  this.parseServiceSchema({
13
45
  name: topic,
14
- mixins: [ApolloClientMixin, BaseServiceMixin(this.postService)],
46
+ mixins: [ApolloClientMixin],
15
47
  settings: {
16
48
  apolloClient: {
17
49
  serverUri: config.GRAPHQL_URL
18
- }
50
+ },
51
+ ...settings
19
52
  },
20
53
  events: {
54
+ /**
55
+ * Handles post thread creation events
56
+ * Publishes real-time updates for thread creation
57
+ */
21
58
  onCreatePostThread: {
22
59
  handler: async ctx => {
23
- const {
24
- post,
25
- postThread
26
- } = ctx.params;
27
- const {
28
- channel: channelId,
29
- parentId: postParentId
30
- } = post;
31
- const triggerName = `THREAD_CREATED_UPDATED${channelId ? `_${channelId}` : ''}`;
32
- const triggerPostThreadName = postParentId ? `THREAD_POST_CREATED_${channelId}_${postParentId}` : `POST_CREATED.${channelId}`;
33
- await Promise.all([this.pubsub.publish(triggerName, {
34
- isCreated: true,
35
- isUpdated: false,
36
- lastMessage: post,
37
- data: postThread
38
- }), this.pubsub.publish(triggerPostThreadName, post), this.pubsub.publish(`THREAD_CREATED_UPDATED${channelId ? `_${channelId}` : ''}${postParentId ? `_${postParentId}` : ''}`, {
39
- isCreated: true,
40
- isUpdated: false,
41
- lastMessage: post,
42
- data: postThread
43
- })]);
60
+ try {
61
+ logger.debug('Processing post thread creation event', {
62
+ postId: ctx.params.post?.id,
63
+ threadId: ctx.params.postThread?.id,
64
+ channelId: ctx.params.post?.channel
65
+ });
66
+ const {
67
+ post,
68
+ postThread
69
+ } = ctx.params;
70
+ const {
71
+ channel: channelId,
72
+ parentId: postParentId
73
+ } = post;
74
+ const triggerName = `THREAD_CREATED_UPDATED${channelId ? `_${channelId}` : ''}`;
75
+ const triggerPostThreadName = postParentId ? `THREAD_POST_CREATED_${channelId}_${postParentId}` : `POST_CREATED.${channelId}`;
76
+ const publishPromises = [this.pubsub.publish(triggerName, {
77
+ isCreated: true,
78
+ isUpdated: false,
79
+ lastMessage: post,
80
+ data: postThread
81
+ }), this.pubsub.publish(triggerPostThreadName, post), this.pubsub.publish(`THREAD_CREATED_UPDATED${channelId ? `_${channelId}` : ''}${postParentId ? `_${postParentId}` : ''}`, {
82
+ isCreated: true,
83
+ isUpdated: false,
84
+ lastMessage: post,
85
+ data: postThread
86
+ })];
87
+ await Promise.all(publishPromises);
88
+ logger.debug('Post thread creation event processed successfully', {
89
+ postId: post?.id,
90
+ threadId: postThread?.id,
91
+ publishedEvents: publishPromises.length
92
+ });
93
+ } catch (error) {
94
+ logger.error('Error processing post thread creation event: %o', error);
95
+ throw error;
96
+ }
44
97
  }
45
98
  },
99
+ /**
100
+ * Handles post thread update events
101
+ * Updates thread participants and publishes real-time updates
102
+ */
46
103
  onUpdatePostThread: {
47
104
  handler: async ctx => {
48
- const {
49
- post,
50
- postThread,
51
- accountId,
52
- role,
53
- orgId
54
- } = ctx.params;
55
- const defaultResponder = [{
56
- user: accountId,
57
- roles: role,
58
- orgName: orgId
59
- }];
60
- const normalizedParticipants = [...postThread?.participants, ...defaultResponder].map(i => ({
61
- ...i,
62
- user: i.user.toString()
63
- }));
64
- const participants = uniqBy(normalizedParticipants, 'user');
65
- await this.broker.call(`${MoleculerTopics.PostThreadService}.update`, {
66
- id: postThread.id,
67
- data: {
68
- replyCount: postThread.replyCount + 1,
69
- lastReplyAt: post.createdAt,
70
- updatedAt: post.createdAt,
71
- participants
105
+ try {
106
+ logger.debug('Processing post thread update event', {
107
+ postId: ctx.params.post?.id,
108
+ threadId: ctx.params.postThread?.id,
109
+ accountId: ctx.params.accountId,
110
+ orgId: ctx.params.orgId
111
+ });
112
+ const {
113
+ post,
114
+ postThread,
115
+ accountId,
116
+ role,
117
+ orgId
118
+ } = ctx.params;
119
+ // Build participant list
120
+ const defaultResponder = [{
121
+ user: accountId,
122
+ roles: role,
123
+ orgName: orgId
124
+ }];
125
+ const normalizedParticipants = [...(postThread?.participants || []), ...defaultResponder].map(i => ({
126
+ ...i,
127
+ user: i.user.toString()
128
+ }));
129
+ const participants = uniqBy(normalizedParticipants, 'user');
130
+ // Update post thread
131
+ await this.broker.call(`${MoleculerTopics.PostThreadService}.update`, {
132
+ id: postThread.id,
133
+ data: {
134
+ replyCount: postThread.replyCount + 1,
135
+ lastReplyAt: post.createdAt,
136
+ updatedAt: post.createdAt,
137
+ participants
138
+ }
139
+ });
140
+ // Prepare trigger payload
141
+ const triggerPayload = {
142
+ isCreated: false,
143
+ isUpdated: true,
144
+ lastMessage: post,
145
+ data: postThread ? {
146
+ ...postThread,
147
+ replyCount: postThread.replyCount + 1,
148
+ lastReplyAt: post.createdAt,
149
+ updatedAt: post.createdAt,
150
+ participants
151
+ } : {}
152
+ };
153
+ const {
154
+ channel: channelId,
155
+ parentId: postParentId
156
+ } = post;
157
+ const triggerName = `THREAD_CREATED_UPDATED${channelId ? `_${channelId}` : ''}`;
158
+ const triggerPostThreadName = `THREAD_POST_CREATED_${channelId}_${postParentId}`;
159
+ // Publish updates
160
+ await Promise.all([this.pubsub.publish(triggerName, triggerPayload), this.pubsub.publish(triggerPostThreadName, post), this.pubsub.publish(`${triggerName}${postParentId ? `_${postParentId}` : ''}`, triggerPayload)]);
161
+ logger.debug('Post thread update event processed successfully', {
162
+ postId: post?.id,
163
+ threadId: postThread?.id,
164
+ participantCount: participants.length
165
+ });
166
+ } catch (error) {
167
+ logger.error('Error processing post thread update event: %o', error);
168
+ throw error;
169
+ }
170
+ }
171
+ },
172
+ /**
173
+ * Handles post creation events
174
+ * Triggers real-time notifications and channel updates
175
+ */
176
+ onPostCreated: {
177
+ handler: async ctx => {
178
+ try {
179
+ logger.debug('Processing post creation event', {
180
+ postId: ctx.params.post?.id,
181
+ channelId: ctx.params.post?.channel,
182
+ authorId: ctx.params.post?.author
183
+ });
184
+ const {
185
+ post,
186
+ userContext
187
+ } = ctx.params;
188
+ // Emit channel update event
189
+ await this.broker.emit('onChannelUpdated', {
190
+ channelId: post.channel,
191
+ lastPostId: post.id,
192
+ lastPostAt: post.createdAt,
193
+ userContext
194
+ });
195
+ logger.debug('Post creation event processed successfully', {
196
+ postId: post?.id,
197
+ channelId: post?.channel
198
+ });
199
+ } catch (error) {
200
+ logger.error('Error processing post creation event: %o', error);
201
+ // Don't throw to prevent breaking post creation
202
+ }
203
+ }
204
+ },
205
+ /**
206
+ * Handles bulk post processing events
207
+ * Processes multiple posts in batch operations
208
+ */
209
+ onBulkPostProcess: {
210
+ handler: async ctx => {
211
+ try {
212
+ logger.debug('Processing bulk post operation', {
213
+ postCount: ctx.params.posts?.length,
214
+ operation: ctx.params.operation
215
+ });
216
+ const {
217
+ posts,
218
+ operation,
219
+ userContext
220
+ } = ctx.params;
221
+ for (const post of posts) {
222
+ switch (operation) {
223
+ case 'delete':
224
+ // Use the base service delete method
225
+ await this.postService.delete({
226
+ id: post.id
227
+ });
228
+ break;
229
+ case 'archive':
230
+ // Implementation for archiving posts
231
+ break;
232
+ default:
233
+ logger.warn('Unknown bulk operation', {
234
+ operation
235
+ });
236
+ }
72
237
  }
73
- });
74
- const triggerPayload = {
75
- isCreated: false,
76
- isUpdated: true,
77
- lastMessage: post,
78
- data: postThread ? {
79
- ...postThread,
80
- replyCount: postThread.replyCount + 1,
81
- lastReplyAt: post.createdAt,
82
- updatedAt: post.createdAt,
83
- participants
84
- } : {}
85
- };
86
- const {
87
- channel: channelId,
88
- parentId: postParentId
89
- } = post;
90
- const triggerName = `THREAD_CREATED_UPDATED${channelId ? `_${channelId}` : ''}`;
91
- const triggerPostThreadName = `THREAD_POST_CREATED_${channelId}_${postParentId}`;
92
- await Promise.all([this.pubsub.publish(triggerName, triggerPayload), this.pubsub.publish(triggerPostThreadName, post), this.pubsub.publish(`${triggerName}${postParentId ? `_${postParentId}` : ''}`, triggerPayload)]);
238
+ logger.debug('Bulk post operation completed', {
239
+ postCount: posts.length,
240
+ operation
241
+ });
242
+ } catch (error) {
243
+ logger.error('Error processing bulk post operation: %o', error);
244
+ throw error;
245
+ }
93
246
  }
94
247
  }
95
248
  },
96
249
  actions: {
250
+ /**
251
+ * Attaches an uploaded file to a post
252
+ */
97
253
  attachUploadedFile: {
98
254
  params: {
99
255
  postId: 'string',
100
256
  createdBy: 'string',
101
257
  file: 'object'
102
258
  },
103
- handler(ctx) {
104
- const {
105
- postId,
106
- createdBy,
107
- file
108
- } = ctx.params;
109
- return this.postService.attachUploadedFile(postId, file, createdBy);
259
+ async handler(ctx) {
260
+ try {
261
+ logger.debug('Attaching uploaded file to post', {
262
+ postId: ctx.params.postId,
263
+ createdBy: ctx.params.createdBy,
264
+ fileName: ctx.params.file?.name
265
+ });
266
+ const {
267
+ postId,
268
+ createdBy,
269
+ file
270
+ } = ctx.params;
271
+ const result = await this.postService.attachUploadedFile(postId, file, createdBy);
272
+ if (result instanceof Error) {
273
+ logger.error('Failed to attach uploaded file', {
274
+ postId,
275
+ error: result.message
276
+ });
277
+ throw result;
278
+ }
279
+ logger.debug('File attached successfully', {
280
+ postId,
281
+ fileId: result?.id,
282
+ createdBy
283
+ });
284
+ return result;
285
+ } catch (error) {
286
+ logger.error('Error in attachUploadedFile action: %o', error);
287
+ throw error;
288
+ }
110
289
  }
111
290
  },
291
+ /**
292
+ * Creates a file upload link for a post
293
+ */
112
294
  createFileUploadLink: {
113
295
  params: {
114
296
  postId: 'string',
115
297
  filename: 'string',
116
298
  userId: 'string'
117
299
  },
118
- handler(ctx) {
119
- const {
120
- postId,
121
- filename,
122
- userId
123
- } = ctx.params;
124
- return this.postService.createFileUploadLink(postId, filename, userId);
300
+ async handler(ctx) {
301
+ try {
302
+ logger.debug('Creating file upload link', {
303
+ postId: ctx.params.postId,
304
+ filename: ctx.params.filename,
305
+ userId: ctx.params.userId
306
+ });
307
+ const {
308
+ postId,
309
+ filename,
310
+ userId
311
+ } = ctx.params;
312
+ const result = await this.postService.createFileUploadLink(postId, filename, userId);
313
+ if (result instanceof Error) {
314
+ logger.error('Failed to create file upload link', {
315
+ postId,
316
+ filename,
317
+ error: result.message
318
+ });
319
+ throw result;
320
+ }
321
+ logger.debug('File upload link created successfully', {
322
+ postId,
323
+ filename,
324
+ userId
325
+ });
326
+ return result;
327
+ } catch (error) {
328
+ logger.error('Error in createFileUploadLink action: %o', error);
329
+ throw error;
330
+ }
125
331
  }
126
332
  },
333
+ /**
334
+ * Attaches multiple uploaded files to a post
335
+ */
127
336
  attachUploadedFiles: {
128
337
  params: {
129
338
  postId: 'string',
@@ -133,15 +342,41 @@ class PostMoleculerService extends Service {
133
342
  items: 'object'
134
343
  }
135
344
  },
136
- handler(ctx) {
137
- const {
138
- postId,
139
- createdBy,
140
- files
141
- } = ctx.params;
142
- return this.postService.attachUploadedFiles(postId, files, createdBy);
345
+ async handler(ctx) {
346
+ try {
347
+ logger.debug('Attaching multiple uploaded files to post', {
348
+ postId: ctx.params.postId,
349
+ createdBy: ctx.params.createdBy,
350
+ fileCount: ctx.params.files?.length
351
+ });
352
+ const {
353
+ postId,
354
+ createdBy,
355
+ files
356
+ } = ctx.params;
357
+ const result = await this.postService.attachUploadedFiles(postId, files, createdBy);
358
+ if (result instanceof Error) {
359
+ logger.error('Failed to attach uploaded files', {
360
+ postId,
361
+ error: result.message
362
+ });
363
+ throw result;
364
+ }
365
+ logger.debug('Files attached successfully', {
366
+ postId,
367
+ fileCount: result?.length,
368
+ createdBy
369
+ });
370
+ return result;
371
+ } catch (error) {
372
+ logger.error('Error in attachUploadedFiles action: %o', error);
373
+ throw error;
374
+ }
143
375
  }
144
376
  },
377
+ /**
378
+ * Creates upload links for multiple files
379
+ */
145
380
  createFilesUploadLink: {
146
381
  params: {
147
382
  postId: 'string',
@@ -151,121 +386,423 @@ class PostMoleculerService extends Service {
151
386
  },
152
387
  userId: 'string'
153
388
  },
154
- handler(ctx) {
155
- const {
156
- postId,
157
- filenames,
158
- userId
159
- } = ctx.params;
160
- return this.postService.createFilesUploadLink(postId, filenames, userId);
389
+ async handler(ctx) {
390
+ try {
391
+ logger.debug('Creating multiple file upload links', {
392
+ postId: ctx.params.postId,
393
+ fileCount: ctx.params.filenames?.length,
394
+ userId: ctx.params.userId
395
+ });
396
+ const {
397
+ postId,
398
+ filenames,
399
+ userId
400
+ } = ctx.params;
401
+ const result = await this.postService.createFilesUploadLink(postId, filenames, userId);
402
+ if (result instanceof Error) {
403
+ logger.error('Failed to create file upload links', {
404
+ postId,
405
+ error: result.message
406
+ });
407
+ throw result;
408
+ }
409
+ logger.debug('File upload links created successfully', {
410
+ postId,
411
+ linkCount: result?.length,
412
+ userId
413
+ });
414
+ return result;
415
+ } catch (error) {
416
+ logger.error('Error in createFilesUploadLink action: %o', error);
417
+ throw error;
418
+ }
161
419
  }
162
420
  },
421
+ /**
422
+ * Deletes a file by URL
423
+ */
163
424
  deleteFile: {
164
425
  params: {
165
426
  url: 'string'
166
427
  },
167
- handler(ctx) {
168
- const {
169
- url
170
- } = ctx.params;
171
- return this.postService.deleteFile(url);
428
+ async handler(ctx) {
429
+ try {
430
+ logger.debug('Deleting file', {
431
+ url: ctx.params.url
432
+ });
433
+ const {
434
+ url
435
+ } = ctx.params;
436
+ const result = await this.postService.deleteFile(url);
437
+ if (result instanceof Error) {
438
+ logger.error('Failed to delete file', {
439
+ url,
440
+ error: result.message
441
+ });
442
+ throw result;
443
+ }
444
+ logger.debug('File deleted successfully', {
445
+ url,
446
+ success: result
447
+ });
448
+ return result;
449
+ } catch (error) {
450
+ logger.error('Error in deleteFile action: %o', error);
451
+ throw error;
452
+ }
172
453
  }
173
454
  },
455
+ /**
456
+ * Marks a message as read
457
+ */
174
458
  readMessage: {
175
459
  params: {
176
460
  channelId: 'string',
177
461
  messageId: 'string',
178
462
  user: 'string'
179
463
  },
180
- handler(ctx) {
181
- const {
182
- user,
183
- ...rest
184
- } = ctx.params;
185
- return this.postService.readMessage(rest, user);
464
+ async handler(ctx) {
465
+ try {
466
+ logger.debug('Marking message as read', {
467
+ channelId: ctx.params.channelId,
468
+ messageId: ctx.params.messageId,
469
+ userId: ctx.params.user
470
+ });
471
+ const {
472
+ user,
473
+ ...rest
474
+ } = ctx.params;
475
+ const result = await this.postService.readMessage(rest, user);
476
+ if (result instanceof Error) {
477
+ logger.error('Failed to mark message as read', {
478
+ messageId: rest.messageId,
479
+ error: result.message
480
+ });
481
+ throw result;
482
+ }
483
+ logger.debug('Message marked as read successfully', {
484
+ messageId: rest.messageId,
485
+ userId: user
486
+ });
487
+ return result;
488
+ } catch (error) {
489
+ logger.error('Error in readMessage action: %o', error);
490
+ throw error;
491
+ }
186
492
  }
187
493
  },
494
+ /**
495
+ * Marks a message as delivered
496
+ */
188
497
  deliverMessage: {
189
498
  params: {
190
499
  channelId: 'string',
191
500
  messageId: 'string',
192
501
  user: 'string'
193
502
  },
194
- handler(ctx) {
195
- const {
196
- user,
197
- ...rest
198
- } = ctx.params;
199
- return this.postService.deliverMessage(rest, user);
503
+ async handler(ctx) {
504
+ try {
505
+ logger.debug('Marking message as delivered', {
506
+ channelId: ctx.params.channelId,
507
+ messageId: ctx.params.messageId,
508
+ userId: ctx.params.user
509
+ });
510
+ const {
511
+ user,
512
+ ...rest
513
+ } = ctx.params;
514
+ const result = await this.postService.deliverMessage(rest, user);
515
+ if (result instanceof Error) {
516
+ logger.error('Failed to mark message as delivered', {
517
+ messageId: rest.messageId,
518
+ error: result.message
519
+ });
520
+ throw result;
521
+ }
522
+ logger.debug('Message marked as delivered successfully', {
523
+ messageId: rest.messageId,
524
+ userId: user
525
+ });
526
+ return result;
527
+ } catch (error) {
528
+ logger.error('Error in deliverMessage action: %o', error);
529
+ throw error;
530
+ }
200
531
  }
201
532
  },
533
+ /**
534
+ * Creates a post without subscription/real-time publishing
535
+ */
202
536
  createWithoutSubscription: {
203
537
  params: {
204
538
  data: 'object'
205
539
  },
206
540
  async handler(ctx) {
207
- const {
208
- data
209
- } = ctx.params;
210
- return this.postService.createWithoutSubscription(data);
541
+ try {
542
+ logger.debug('Creating post without subscription', {
543
+ channelId: ctx.params.data?.channel,
544
+ authorId: ctx.params.data?.author
545
+ });
546
+ const {
547
+ data
548
+ } = ctx.params;
549
+ const result = await this.postService.createWithoutSubscription(data);
550
+ if (result instanceof Error) {
551
+ logger.error('Failed to create post without subscription', {
552
+ error: result.message
553
+ });
554
+ throw result;
555
+ }
556
+ logger.debug('Post created successfully without subscription', {
557
+ postId: result?.id,
558
+ channelId: data?.channel
559
+ });
560
+ return result;
561
+ } catch (error) {
562
+ logger.error('Error in createWithoutSubscription action: %o', error);
563
+ throw error;
564
+ }
211
565
  }
212
566
  },
567
+ /**
568
+ * Creates a post with associated post thread
569
+ */
213
570
  createPostWithPostThread: {
214
571
  async handler(ctx) {
215
- const {
216
- threadMessageInput,
217
- channelId,
218
- responderId,
219
- accountId,
220
- postParentId,
221
- postId
222
- } = ctx.params;
223
- const {
224
- content,
225
- files,
226
- notificationParams
227
- } = threadMessageInput;
228
- const postPayload = {
229
- channel: channelId,
230
- message: content,
231
- editedBy: responderId || accountId,
232
- author: responderId || accountId,
233
- files,
234
- parentId: postParentId,
235
- props: notificationParams ? {
572
+ try {
573
+ logger.debug('Creating post with post thread', {
574
+ channelId: ctx.params.channelId,
575
+ accountId: ctx.params.accountId,
576
+ postParentId: ctx.params.postParentId
577
+ });
578
+ const {
579
+ threadMessageInput,
580
+ channelId,
581
+ responderId,
582
+ accountId,
583
+ postParentId,
584
+ postId
585
+ } = ctx.params;
586
+ const {
587
+ content,
588
+ files,
236
589
  notificationParams
237
- } : undefined
238
- };
239
- const post = await this.postService.createWithoutSubscription({
240
- ...(postId ? {
241
- _id: postId
242
- } : {}),
243
- ...postPayload
244
- });
245
- const postThread = await this.handlePostThreadCreate({
246
- ...ctx.params,
247
- post
248
- });
249
- return {
250
- post,
251
- postThread
252
- };
590
+ } = threadMessageInput;
591
+ const postPayload = {
592
+ channel: channelId,
593
+ message: content,
594
+ editedBy: responderId || accountId,
595
+ author: responderId || accountId,
596
+ files,
597
+ parentId: postParentId,
598
+ props: notificationParams ? {
599
+ notificationParams
600
+ } : undefined
601
+ };
602
+ const post = await this.postService.createWithoutSubscription({
603
+ ...(postId ? {
604
+ _id: postId
605
+ } : {}),
606
+ ...postPayload
607
+ });
608
+ if (post instanceof Error) {
609
+ logger.error('Failed to create post for post thread', {
610
+ error: post.message
611
+ });
612
+ throw post;
613
+ }
614
+ const postThread = await this.handlePostThreadCreate({
615
+ ...ctx.params,
616
+ post: post
617
+ });
618
+ logger.debug('Post with post thread created successfully', {
619
+ postId: post?.id,
620
+ threadId: postThread?.id
621
+ });
622
+ return {
623
+ post,
624
+ postThread
625
+ };
626
+ } catch (error) {
627
+ logger.error('Error in createPostWithPostThread action: %o', error);
628
+ throw error;
629
+ }
253
630
  }
254
631
  },
632
+ /**
633
+ * Gets the last message in a channel
634
+ */
255
635
  getLastMessage: {
256
636
  params: {
257
637
  channelId: 'string'
258
638
  },
259
- handler(ctx) {
260
- const {
261
- channelId
262
- } = ctx.params;
263
- return this.postService.getLastMessage(channelId);
639
+ async handler(ctx) {
640
+ try {
641
+ logger.debug('Getting last message', {
642
+ channelId: ctx.params.channelId
643
+ });
644
+ const {
645
+ channelId
646
+ } = ctx.params;
647
+ const result = await this.postService.getLastMessage(channelId);
648
+ if (result instanceof Error) {
649
+ logger.error('Failed to get last message', {
650
+ channelId,
651
+ error: result.message
652
+ });
653
+ throw result;
654
+ }
655
+ logger.debug('Last message retrieved successfully', {
656
+ channelId,
657
+ postId: result?.id
658
+ });
659
+ return result;
660
+ } catch (error) {
661
+ logger.error('Error in getLastMessage action: %o', error);
662
+ throw error;
663
+ }
664
+ }
665
+ },
666
+ /**
667
+ * Updates a post using base service method
668
+ */
669
+ updatePost: {
670
+ params: {
671
+ postId: 'string',
672
+ updates: 'object'
673
+ },
674
+ async handler(ctx) {
675
+ try {
676
+ logger.debug('Updating post', {
677
+ postId: ctx.params.postId,
678
+ updateKeys: Object.keys(ctx.params.updates || {})
679
+ });
680
+ const {
681
+ postId,
682
+ updates
683
+ } = ctx.params;
684
+ const result = await this.postService.update(postId, updates);
685
+ logger.debug('Post updated successfully', {
686
+ postId,
687
+ updatedPostId: result?.id
688
+ });
689
+ return result;
690
+ } catch (error) {
691
+ logger.error('Error in updatePost action: %o', error);
692
+ throw error;
693
+ }
694
+ }
695
+ },
696
+ /**
697
+ * Deletes a post using base service method
698
+ */
699
+ deletePost: {
700
+ params: {
701
+ postId: 'string'
702
+ },
703
+ async handler(ctx) {
704
+ try {
705
+ logger.debug('Deleting post', {
706
+ postId: ctx.params.postId
707
+ });
708
+ const {
709
+ postId
710
+ } = ctx.params;
711
+ const result = await this.postService.delete({
712
+ id: postId
713
+ });
714
+ logger.debug('Post deleted successfully', {
715
+ postId,
716
+ success: result
717
+ });
718
+ return result;
719
+ } catch (error) {
720
+ logger.error('Error in deletePost action: %o', error);
721
+ throw error;
722
+ }
723
+ }
724
+ },
725
+ /**
726
+ * Gets posts by channel using base service methods
727
+ */
728
+ getPostsByChannel: {
729
+ params: {
730
+ channelId: 'string',
731
+ limit: {
732
+ type: 'number',
733
+ optional: true,
734
+ default: 50
735
+ },
736
+ offset: {
737
+ type: 'number',
738
+ optional: true,
739
+ default: 0
740
+ }
741
+ },
742
+ async handler(ctx) {
743
+ try {
744
+ logger.debug('Getting posts by channel', {
745
+ channelId: ctx.params.channelId,
746
+ limit: ctx.params.limit,
747
+ offset: ctx.params.offset
748
+ });
749
+ const {
750
+ channelId,
751
+ limit,
752
+ offset
753
+ } = ctx.params;
754
+ // Use base service getAll with criteria
755
+ const result = await this.postService.getAll({
756
+ criteria: {
757
+ channel: channelId
758
+ },
759
+ pagination: {
760
+ limit,
761
+ offset
762
+ }
763
+ });
764
+ logger.debug('Posts retrieved successfully', {
765
+ channelId,
766
+ postCount: result?.length
767
+ });
768
+ return result;
769
+ } catch (error) {
770
+ logger.error('Error in getPostsByChannel action: %o', error);
771
+ throw error;
772
+ }
773
+ }
774
+ },
775
+ /**
776
+ * Health check endpoint
777
+ */
778
+ healthCheck: {
779
+ async handler(ctx) {
780
+ try {
781
+ logger.debug('Performing post service health check');
782
+ return {
783
+ status: 'healthy',
784
+ timestamp: new Date().toISOString(),
785
+ service: 'PostMoleculerService',
786
+ version: '1.0.0'
787
+ };
788
+ } catch (error) {
789
+ logger.error('Health check failed: %o', error);
790
+ throw error;
791
+ }
264
792
  }
265
793
  }
266
794
  }
267
795
  });
796
+ logger.info('PostMoleculerService initialized successfully');
268
797
  }
798
+ /**
799
+ * Handles post thread creation logic
800
+ *
801
+ * @description Creates or updates post threads with proper participant management
802
+ *
803
+ * @param {Object} params - Post thread creation parameters
804
+ * @returns {Promise<IPostThread>} - Created or updated post thread
805
+ */
269
806
  async handlePostThreadCreate({
270
807
  post,
271
808
  responderId,
@@ -274,58 +811,88 @@ class PostMoleculerService extends Service {
274
811
  orgId,
275
812
  postThreadId
276
813
  }) {
277
- const {
278
- role
279
- } = threadMessageInput;
280
- const channelId = post.channel?.toString();
281
- const postParentId = post.parentId?.toString();
282
- const postThread = await this.getPostThread({
283
- accountId,
284
- postThreadId,
285
- postParentId,
286
- channelId,
287
- role,
288
- orgId
289
- });
290
- const channel = await this.broker.call(`${MoleculerTopics.ChannelService}.get`, {
291
- id: channelId
292
- });
293
- const members = channel?.members?.map(m => ({
294
- user: m?.user,
295
- orgName: orgId,
296
- roles: role
297
- }));
298
- const defaultResponder = [{
299
- user: accountId,
300
- roles: role,
301
- orgName: orgId
302
- }];
303
- const responder = responderId ? [{
304
- user: responderId,
305
- roles: role,
306
- orgName: orgId
307
- }, ...defaultResponder] : defaultResponder;
308
- const normalizedParticipants = [...members, ...(postThread?.participants || []), ...responder].map(i => ({
309
- ...i,
310
- user: i.user.toString()
311
- }));
312
- const participants = uniqBy(normalizedParticipants, 'user');
313
- if (!postParentId && !postThread || postParentId && !postThread) {
314
- return this.createPostThread({
315
- post,
814
+ try {
815
+ logger.debug('Handling post thread creation', {
816
+ postId: post?.id,
817
+ accountId,
818
+ orgId,
819
+ hasExistingThread: !!postThreadId
820
+ });
821
+ const {
822
+ role
823
+ } = threadMessageInput;
824
+ const channelId = post.channel?.toString();
825
+ const postParentId = post.parentId?.toString();
826
+ const postThread = await this.getPostThread({
827
+ accountId,
828
+ postThreadId,
829
+ postParentId,
316
830
  channelId,
317
- participants,
318
- postParentId: postParentId ? postParentId : post.id
831
+ role,
832
+ orgId
319
833
  });
834
+ const channel = await this.broker.call(`${MoleculerTopics.ChannelService}.get`, {
835
+ id: channelId
836
+ });
837
+ const members = channel?.members?.map(m => ({
838
+ user: m?.user,
839
+ orgName: orgId,
840
+ roles: role
841
+ }));
842
+ const defaultResponder = [{
843
+ user: accountId,
844
+ roles: role,
845
+ orgName: orgId
846
+ }];
847
+ const responder = responderId ? [{
848
+ user: responderId,
849
+ roles: role,
850
+ orgName: orgId
851
+ }, ...defaultResponder] : defaultResponder;
852
+ const normalizedParticipants = [...(members || []), ...(postThread?.participants || []), ...responder].map(i => ({
853
+ ...i,
854
+ user: i.user.toString()
855
+ }));
856
+ const participants = uniqBy(normalizedParticipants, 'user');
857
+ if (!postParentId && !postThread || postParentId && !postThread) {
858
+ const result = await this.createPostThread({
859
+ post,
860
+ channelId,
861
+ participants,
862
+ postParentId: postParentId ? postParentId : post.id
863
+ });
864
+ logger.debug('New post thread created', {
865
+ postId: post?.id,
866
+ threadId: result?.id,
867
+ participantCount: participants.length
868
+ });
869
+ return result;
870
+ }
871
+ const result = await this.dispatchPostEventsWithParentId({
872
+ post,
873
+ postThread,
874
+ accountId,
875
+ orgId,
876
+ role
877
+ });
878
+ logger.debug('Existing post thread updated', {
879
+ postId: post?.id,
880
+ threadId: result?.id
881
+ });
882
+ return result;
883
+ } catch (error) {
884
+ logger.error('Error handling post thread creation: %o', error);
885
+ throw error;
320
886
  }
321
- return this.dispatchPostEventsWithParentId({
322
- post,
323
- postThread,
324
- accountId,
325
- orgId,
326
- role
327
- });
328
887
  }
888
+ /**
889
+ * Retrieves a post thread by criteria
890
+ *
891
+ * @description Finds existing post threads based on various criteria
892
+ *
893
+ * @param {Object} params - Search criteria
894
+ * @returns {Promise<IPostThread>} - Found post thread
895
+ */
329
896
  async getPostThread({
330
897
  postThreadId,
331
898
  channelId,
@@ -334,31 +901,55 @@ class PostMoleculerService extends Service {
334
901
  role,
335
902
  orgId
336
903
  }) {
337
- const criteria = {
338
- ...(postThreadId ? {
339
- _id: postThreadId
340
- } : {
341
- channel: channelId,
342
- post: postParentId,
343
- participants: {
344
- $elemMatch: {
345
- user: accountId,
346
- ...(role ? {
347
- roles: role
348
- } : {}),
349
- ...(orgId ? {
350
- orgName: orgId
351
- } : {})
904
+ try {
905
+ logger.debug('Getting post thread', {
906
+ postThreadId: postThreadId?.id,
907
+ channelId,
908
+ postParentId,
909
+ accountId,
910
+ orgId
911
+ });
912
+ const criteria = {
913
+ ...(postThreadId ? {
914
+ _id: postThreadId
915
+ } : {
916
+ channel: channelId,
917
+ post: postParentId,
918
+ participants: {
919
+ $elemMatch: {
920
+ user: accountId,
921
+ ...(role ? {
922
+ roles: role
923
+ } : {}),
924
+ ...(orgId ? {
925
+ orgName: orgId
926
+ } : {})
927
+ }
352
928
  }
353
- }
354
- })
355
- };
356
- const postThreads = await this.broker.call(`${MoleculerTopics.PostThreadService}.getAll`, {
357
- criteria
358
- });
359
- const [postThread] = postThreads ?? [];
360
- return postThread;
929
+ })
930
+ };
931
+ const postThreads = await this.broker.call(`${MoleculerTopics.PostThreadService}.getAll`, {
932
+ criteria
933
+ });
934
+ const [postThread] = postThreads ?? [];
935
+ logger.debug('Post thread retrieved', {
936
+ found: !!postThread,
937
+ threadId: postThread?.id
938
+ });
939
+ return postThread;
940
+ } catch (error) {
941
+ logger.error('Error getting post thread: %o', error);
942
+ throw error;
943
+ }
361
944
  }
945
+ /**
946
+ * Dispatches post events with parent ID for thread updates
947
+ *
948
+ * @description Handles event dispatching for post thread updates
949
+ *
950
+ * @param {Object} params - Event parameters
951
+ * @returns {Promise<IPostThread>} - Updated post thread
952
+ */
362
953
  async dispatchPostEventsWithParentId({
363
954
  post,
364
955
  postThread,
@@ -366,39 +957,80 @@ class PostMoleculerService extends Service {
366
957
  orgId,
367
958
  role
368
959
  }) {
369
- await this.broker.emit('onUpdatePostThread', {
370
- post,
371
- postThread,
372
- accountId,
373
- orgId,
374
- role
375
- });
376
- return {
377
- ...postThread,
378
- replyCount: postThread.replyCount + 1,
379
- lastReplyAt: post.createdAt
380
- };
960
+ try {
961
+ logger.debug('Dispatching post events with parent ID', {
962
+ postId: post?.id,
963
+ threadId: postThread?.id,
964
+ accountId,
965
+ orgId
966
+ });
967
+ await this.broker.emit('onUpdatePostThread', {
968
+ post,
969
+ postThread,
970
+ accountId,
971
+ orgId,
972
+ role
973
+ });
974
+ const updatedThread = {
975
+ ...postThread,
976
+ replyCount: postThread.replyCount + 1,
977
+ lastReplyAt: post.createdAt
978
+ };
979
+ logger.debug('Post events dispatched successfully', {
980
+ postId: post?.id,
981
+ threadId: updatedThread?.id,
982
+ newReplyCount: updatedThread.replyCount
983
+ });
984
+ return updatedThread;
985
+ } catch (error) {
986
+ logger.error('Error dispatching post events: %o', error);
987
+ throw error;
988
+ }
381
989
  }
990
+ /**
991
+ * Creates a new post thread
992
+ *
993
+ * @description Creates a new thread for organizing related posts
994
+ *
995
+ * @param {Object} params - Thread creation parameters
996
+ * @returns {Promise<IPostThread>} - Created post thread
997
+ */
382
998
  async createPostThread({
383
999
  channelId,
384
1000
  postParentId,
385
1001
  post,
386
1002
  participants
387
1003
  }) {
388
- const postThreadData = {
389
- post: postParentId,
390
- channel: channelId,
391
- replyCount: 0,
392
- lastReplyAt: post.createdAt,
393
- participants
394
- };
395
- const postThread = await this.broker.call(`${MoleculerTopics.PostThreadService}.create`, {
396
- data: postThreadData
397
- });
398
- await this.broker.emit('onCreatePostThread', {
399
- post,
400
- postThread
401
- });
402
- return postThread;
1004
+ try {
1005
+ logger.debug('Creating new post thread', {
1006
+ channelId,
1007
+ postParentId,
1008
+ postId: post?.id,
1009
+ participantCount: participants?.length
1010
+ });
1011
+ const postThreadData = {
1012
+ post: postParentId,
1013
+ channel: channelId,
1014
+ replyCount: 0,
1015
+ lastReplyAt: post.createdAt,
1016
+ participants
1017
+ };
1018
+ const postThread = await this.broker.call(`${MoleculerTopics.PostThreadService}.create`, {
1019
+ data: postThreadData
1020
+ });
1021
+ await this.broker.emit('onCreatePostThread', {
1022
+ post,
1023
+ postThread
1024
+ });
1025
+ logger.debug('Post thread created successfully', {
1026
+ threadId: postThread?.id,
1027
+ channelId,
1028
+ postParentId
1029
+ });
1030
+ return postThread;
1031
+ } catch (error) {
1032
+ logger.error('Error creating post thread: %o', error);
1033
+ throw error;
1034
+ }
403
1035
  }
404
1036
  }export{PostMoleculerService};//# sourceMappingURL=post-moleculer-service.js.map