@messenger-box/platform-server 10.0.3-alpha.7 → 10.0.3-alpha.74

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