@roadmanjs/chat 0.0.63 → 0.0.65

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 (59) hide show
  1. package/dist/chat/methods/ChatConvo.methods.js +5 -1
  2. package/dist/chat/methods/ChatConvo.methods.js.map +1 -1
  3. package/dist/chat/methods/ChatConvoResolver.methods.js +41 -4
  4. package/dist/chat/methods/ChatConvoResolver.methods.js.map +1 -1
  5. package/dist/chat/methods/ChatMessageResolver.methods.js +4 -3
  6. package/dist/chat/methods/ChatMessageResolver.methods.js.map +1 -1
  7. package/dist/chat/models/ChatAttachment.model.js.map +1 -1
  8. package/dist/chat/models/ChatConvo.model.d.ts +5 -0
  9. package/dist/chat/models/ChatConvo.model.js +21 -0
  10. package/dist/chat/models/ChatConvo.model.js.map +1 -1
  11. package/dist/chat/models/ChatMessage.model.js.map +1 -1
  12. package/dist/chat/models/ChatUser.model.js.map +1 -1
  13. package/dist/chat/resolvers/ChatConvo.public.resolver.js.map +1 -1
  14. package/dist/chat/resolvers/ChatConvo.resolver.js.map +1 -1
  15. package/dist/chat/resolvers/ChatMessage.resolver.js.map +1 -1
  16. package/dist/shared/ContextType.js.map +1 -1
  17. package/package.json +2 -1
  18. package/src/chat/fragments/README.md +1 -0
  19. package/src/chat/fragments/chatAttachment.fragment.ts +15 -0
  20. package/src/chat/fragments/chatConvo.fragment.ts +29 -0
  21. package/src/chat/fragments/chatMessage.fragment.ts +35 -0
  22. package/src/chat/fragments/chatUser.fragment.ts +23 -0
  23. package/src/chat/fragments/index.ts +5 -0
  24. package/src/chat/fragments/resType.ts +15 -0
  25. package/src/chat/index-client.ts +7 -0
  26. package/src/chat/index.ts +5 -0
  27. package/src/chat/methods/ChatConvo.methods.ts +340 -0
  28. package/src/chat/methods/ChatConvo.test.ts +122 -0
  29. package/src/chat/methods/ChatConvoResolver.methods.ts +281 -0
  30. package/src/chat/methods/ChatMessageResolver.methods.ts +218 -0
  31. package/src/chat/methods/index.ts +3 -0
  32. package/src/chat/models/ChatAttachment.model.ts +43 -0
  33. package/src/chat/models/ChatConvo.model.ts +127 -0
  34. package/src/chat/models/ChatMessage.model.ts +102 -0
  35. package/src/chat/models/ChatUser.model.ts +67 -0
  36. package/src/chat/models/chat.txt +17 -0
  37. package/src/chat/models/index.ts +3 -0
  38. package/src/chat/mutations/chatConvo.mutation.ts +20 -0
  39. package/src/chat/mutations/chatMessage.mutation.ts +11 -0
  40. package/src/chat/mutations/index.ts +2 -0
  41. package/src/chat/query/README.md +1 -0
  42. package/src/chat/query/chatConvo.query.ts +33 -0
  43. package/src/chat/query/chatMessage.query.ts +21 -0
  44. package/src/chat/query/index.ts +2 -0
  45. package/src/chat/resolvers/ChatConvo.public.resolver.ts +15 -0
  46. package/src/chat/resolvers/ChatConvo.resolver.ts +71 -0
  47. package/src/chat/resolvers/ChatMessage.resolver.ts +62 -0
  48. package/src/chat/resolvers/index.ts +2 -0
  49. package/src/chat/subscriptions/README.md +1 -0
  50. package/src/chat/subscriptions/chatConvo.subscription.ts +19 -0
  51. package/src/chat/subscriptions/chatMessage.subscription.ts +13 -0
  52. package/src/chat/subscriptions/index.ts +2 -0
  53. package/src/example.ts +16 -0
  54. package/src/index.ts +2 -0
  55. package/src/roadman.ts +25 -0
  56. package/src/scripts/copyClient.ts +64 -0
  57. package/src/scripts/createPackageJsonForClient.ts +32 -0
  58. package/src/shared/ContextType.ts +67 -0
  59. package/src/shared/pubsub.utils.ts +93 -0
@@ -0,0 +1,340 @@
1
+ import ChatConvoModel, {
2
+ ChatConvo,
3
+ ChatConvoModelName,
4
+ ChatConvoType,
5
+ chatConvoSelectors,
6
+ } from '../models/ChatConvo.model';
7
+ import {ChatMessage, ChatMessageModel} from '../models';
8
+ import {connectionOptions, createUpdate} from '@roadmanjs/couchset';
9
+ import {publishMessageToTopic, sendPushNotification} from '../../shared/pubsub.utils';
10
+
11
+ import {ContextType} from '../../shared/ContextType';
12
+ import {awaitTo} from '@stoqey/client-graphql';
13
+ import compact from 'lodash/compact';
14
+ import isEmpty from 'lodash/isEmpty';
15
+ import {log} from '@roadmanjs/logs';
16
+
17
+ export const createAConvoAndReturnIt = async (newConvo: ChatConvoType): Promise<ChatConvoType> => {
18
+ const {members = [], group = false, owner, ...others} = newConvo;
19
+
20
+ const [errorCreatingConvo, createdChatConvo = []] = await awaitTo(
21
+ createChatConvoType({
22
+ ...others,
23
+ members,
24
+ group,
25
+ owner,
26
+ })
27
+ );
28
+
29
+ if (errorCreatingConvo) {
30
+ throw errorCreatingConvo;
31
+ }
32
+
33
+ let convo = createdChatConvo[0];
34
+ if (owner) {
35
+ const selected = createdChatConvo.find((chat) => chat.owner === owner);
36
+ if (selected) {
37
+ convo = selected;
38
+ }
39
+ }
40
+
41
+ return convo;
42
+ };
43
+
44
+ export const createChatConvoType = async (
45
+ props: Partial<ChatConvoType>
46
+ ): Promise<ChatConvoType[]> => {
47
+ const {members = [], group = false, ...others} = props;
48
+
49
+ if (isEmpty(members)) {
50
+ throw new Error('members have to be more than one');
51
+ }
52
+
53
+ const defaultConvo: ChatConvoType = {
54
+ ...others,
55
+ members,
56
+ group,
57
+ owner: 'system',
58
+ };
59
+
60
+ const isPublicChat = defaultConvo.public;
61
+
62
+ if (isPublicChat) {
63
+ const existingPublicChat = await ChatConvoModel.pagination({
64
+ where: {convoId: defaultConvo.convoId},
65
+ });
66
+
67
+ if (existingPublicChat && existingPublicChat.length) {
68
+ return existingPublicChat;
69
+ }
70
+ }
71
+
72
+ const [errorSystemConvo, createdSystemConvo] = await awaitTo(
73
+ createUpdate<ChatConvoType>({
74
+ model: ChatConvoModel,
75
+ data: defaultConvo,
76
+ ...defaultConvo,
77
+ })
78
+ );
79
+
80
+ if (errorSystemConvo) {
81
+ throw errorSystemConvo;
82
+ }
83
+
84
+ if (isPublicChat) {
85
+ return [createdSystemConvo];
86
+ }
87
+
88
+ // create a convo for each member
89
+ const [errorConvos, convos] = await awaitTo(
90
+ Promise.all(
91
+ members.map((member) =>
92
+ createUpdate<ChatConvoType>({
93
+ model: ChatConvoModel,
94
+ data: {
95
+ ...defaultConvo,
96
+ owner: member,
97
+ convoId: createdSystemConvo?.id,
98
+ },
99
+ ...defaultConvo,
100
+ owner: member,
101
+ })
102
+ )
103
+ )
104
+ );
105
+
106
+ if (errorConvos) {
107
+ throw errorConvos;
108
+ }
109
+
110
+ return convos as ChatConvoType[];
111
+ };
112
+
113
+ export const getChatConvoById = async (id: string, owner: string): Promise<ChatConvo | null> => {
114
+ try {
115
+ const bucket = connectionOptions.bucketName;
116
+
117
+ const query = `
118
+ SELECT *
119
+ FROM \`${bucket}\` convo
120
+ JOIN \`${bucket}\` owner
121
+ ON KEYS convo.owner
122
+ NEST \`${bucket}\` members
123
+ ON KEYS convo.members
124
+ LEFT JOIN \`${bucket}\` lastMessage
125
+ ON KEYS convo.lastMessage
126
+ LEFT JOIN \`${bucket}\` source
127
+ ON KEYS convo.sourceId
128
+
129
+ WHERE convo._type = "${ChatConvoModelName}"
130
+ AND (convo.id = "${id}" OR convo.convoId = "${id}")
131
+ AND convo.owner = "${owner}"
132
+ LIMIT 1;
133
+ `;
134
+
135
+ const [errorFetching, data = []] = await awaitTo(
136
+ ChatConvoModel.customQuery<any>({
137
+ limit: 1,
138
+ query,
139
+ params: {limit: 1, id},
140
+ })
141
+ );
142
+
143
+ if (errorFetching) {
144
+ throw errorFetching;
145
+ }
146
+
147
+ const [rows = []] = data;
148
+
149
+ const dataToSend = rows.map((d) => {
150
+ const {convo, lastMessage = {}, members, owner} = d;
151
+ const source = d.source || {};
152
+ const lastMessageParsed = ChatMessageModel.parse(lastMessage);
153
+ const chatConvoItem = ChatConvoModel.parse({
154
+ ...convo,
155
+ source,
156
+ members,
157
+ owner,
158
+ });
159
+ chatConvoItem.lastMessage = lastMessageParsed;
160
+ return chatConvoItem;
161
+ });
162
+
163
+ return dataToSend[0];
164
+ } catch (error) {
165
+ log('error getting chat messages', error);
166
+ return null;
167
+ }
168
+ };
169
+
170
+ interface UpdateConvoLastMessage {
171
+ sender: string;
172
+ convoId: string;
173
+ lastMessageId: string;
174
+ }
175
+
176
+ export const updateConvoLastMessage = async (args: UpdateConvoLastMessage): Promise<boolean> => {
177
+ const {sender, convoId, lastMessageId} = args;
178
+ try {
179
+ // find all convo by convoId
180
+ // add update them all with the new lastMessageId
181
+
182
+ const convos: ChatConvoType[] = await ChatConvoModel.pagination({
183
+ select: chatConvoSelectors,
184
+ where: {convoId: {$eq: convoId}},
185
+ });
186
+
187
+ if (!isEmpty(convos)) {
188
+ // update convo objects
189
+ const [errorConvos, updatedConvos] = await awaitTo(
190
+ Promise.all(
191
+ convos.map((convo) => {
192
+ const update = {
193
+ ...convo,
194
+ lastMessage: lastMessageId,
195
+ };
196
+
197
+ if (convo.owner !== sender) {
198
+ // if this is not creator, update unread
199
+ update.unread = (convo.unread || 0) + 1;
200
+ }
201
+
202
+ return createUpdate<ChatConvoType>({
203
+ model: ChatConvoModel,
204
+ data: update,
205
+ ...convo,
206
+ });
207
+ })
208
+ )
209
+ );
210
+ if (errorConvos) {
211
+ throw errorConvos;
212
+ }
213
+
214
+ log(
215
+ `updated convos with lastMessage=${lastMessageId}`,
216
+ updatedConvos.map((uc) => uc.id)
217
+ );
218
+ }
219
+
220
+ return true;
221
+ } catch (error) {
222
+ return false;
223
+ }
224
+ };
225
+
226
+ interface UpdateConvoSubscriptions {
227
+ context: ContextType;
228
+ sender: string;
229
+ convoId: string;
230
+ data: any;
231
+ }
232
+
233
+ /**
234
+ * Send data to convo expect the sender
235
+ * @param args
236
+ * @returns
237
+ */
238
+ export const updateConvoSubscriptions = async (
239
+ args: UpdateConvoSubscriptions
240
+ ): Promise<boolean> => {
241
+ const {context, sender, convoId, data} = args;
242
+
243
+ const getSubscriptionData = () => {
244
+ if (data.id) {
245
+ // contains message payload
246
+ return {message: data.id};
247
+ }
248
+ return data;
249
+ };
250
+
251
+ const subscriptionData = getSubscriptionData();
252
+
253
+ const publishToMessageTopic = async () => {
254
+ return publishMessageToTopic(context, [ChatMessage.name], {
255
+ convoId,
256
+ owner: sender,
257
+ ...subscriptionData,
258
+ });
259
+ };
260
+
261
+ try {
262
+ // send to message topic
263
+ await publishToMessageTopic();
264
+
265
+ // send to convo topics
266
+ const membersConvos: ChatConvoType[] = await ChatConvoModel.pagination({
267
+ select: chatConvoSelectors,
268
+ where: {convoId: {$eq: convoId}, owner: {$neq: sender}},
269
+ });
270
+
271
+ if (!isEmpty(membersConvos)) {
272
+ const isPublicChat = compact(membersConvos.map((c) => c.public));
273
+
274
+ if (!isEmpty(isPublicChat)) {
275
+ log(`updated subscriptions isPublicChat`);
276
+ return;
277
+ }
278
+
279
+ // push notification here
280
+
281
+ // update sockets, no need for results
282
+ await awaitTo(
283
+ Promise.all(
284
+ membersConvos.map((convo) => {
285
+ const pushmessage = {
286
+ ...data,
287
+ convoId,
288
+ owner: convo.owner,
289
+ };
290
+
291
+ // unhandled promises
292
+ if (!subscriptionData.typing) {
293
+ sendPushNotification(sender, pushmessage);
294
+ }
295
+
296
+ // Send subscriptions to owners
297
+ return publishMessageToTopic(context, [ChatConvo.name], {
298
+ convoId,
299
+ owner: convo.owner,
300
+ ...subscriptionData,
301
+ }); // update sockets
302
+ })
303
+ )
304
+ );
305
+
306
+ log(
307
+ `updated subscriptions from=${sender} with data=${data}`,
308
+ membersConvos.map((uc) => uc.id)
309
+ );
310
+
311
+ // update sockets
312
+ }
313
+
314
+ return true;
315
+ } catch (error) {
316
+ return false;
317
+ }
318
+ };
319
+
320
+ export const removeUnreadCount = async (owner: string, convoId: string): Promise<any> => {
321
+ try {
322
+ const convos: ChatConvoType[] = await ChatConvoModel.pagination({
323
+ select: chatConvoSelectors,
324
+ where: {convoId: {$eq: convoId}, owner: {$eq: owner}},
325
+ });
326
+
327
+ if (!isEmpty(convos)) {
328
+ const convo = convos[0];
329
+ if (convo.unread > 0) {
330
+ convo.unread = 0; // remove the unread
331
+ await ChatConvoModel.updateById(convo.id, convo, {silent: true}); // do not updatedAt
332
+ }
333
+ }
334
+
335
+ return true;
336
+ } catch (err) {
337
+ log(err);
338
+ return false;
339
+ }
340
+ };
@@ -0,0 +1,122 @@
1
+ import 'reflect-metadata';
2
+ import 'mocha';
3
+
4
+ import {expect} from 'chai';
5
+ import { getChatConvoById } from './ChatConvo.methods';
6
+ import {startCouchbase} from '@roadmanjs/couchset';
7
+
8
+ before((done) => {
9
+ startCouchbase().then(() => done());
10
+ });
11
+
12
+ describe('ChatConvo', () => {
13
+ // it('it should send a push notification to a user', async () => {
14
+ // const senderId = '1c01d85f-b811-44b1-8a4f-bef8030bf265';
15
+ // const convoId = 'b613b7c5-5f73-4331-8703-3a1176728a31';
16
+
17
+ // const owner = '99bc43ba-02ab-4394-b48b-49a39a95443c';
18
+
19
+ // const sendMessage = await sendPushNotification(senderId, {
20
+ // owner,
21
+ // convoId,
22
+ // message: 'some message',
23
+ // });
24
+ // expect(sendMessage).to.not.be.empty;
25
+ // });
26
+ // it('it should create an new convo and return it', async () => {
27
+ // const newConvo: ChatConvoType = {
28
+ // owner: '1c01d85f-b811-44b1-8a4f-bef8030bf265',
29
+ // members: [
30
+ // '1c01d85f-b811-44b1-8a4f-bef8030bf265',
31
+ // '0ac710ce-4530-4ea9-8f70-9d19383c95d4',
32
+ // ],
33
+ // group: true,
34
+ // };
35
+
36
+ // const newConvoCreated = await startConvo(newConvo);
37
+
38
+ // console.log('new convo create', newConvoCreated);
39
+ // console.log('new convo create members', newConvoCreated.data.members);
40
+
41
+ // expect(newConvoCreated).to.be.not.empty;
42
+ // });
43
+
44
+ it("it should return chat convo with joins", async () => {
45
+ const convo = await getChatConvoById("d2bb6ba6-1bc5-480a-a3ae-c28bec3708bf", "1c01d85f-b811-44b1-8a4f-bef8030bf265");
46
+
47
+ console.log('convo with joins', convo);
48
+ expect(convo.members[0].id).to.be.not.empty;
49
+ })
50
+
51
+ // it("Create convo", async () => {
52
+ // const owner = "1c01d85f-b811-44b1-8a4f-bef8030bf265";
53
+ // const otherUser = "99bc43ba-02ab-4394-b48b-49a39a95443c";
54
+ // const members = [owner, otherUser];
55
+
56
+ // const chatConvo = {
57
+ // members,
58
+ // group: false,
59
+
60
+ // };
61
+
62
+ // const createdConvo = await createChatConvoType(chatConvo);
63
+
64
+ // console.log("Created", createdConvo);
65
+ // expect(createdConvo).to.not.be.empty;
66
+ // });
67
+
68
+ // it("Remove read count", async () => {
69
+ // const owner = "1c01d85f-b811-44b1-8a4f-bef8030bf265";
70
+ // const convoId = "b613b7c5-5f73-4331-8703-3a1176728a31";
71
+
72
+ // const hasUpdateCount = await removeUnreadCount(owner, convoId);
73
+
74
+ // console.log("Created", hasUpdateCount);
75
+ // expect(hasUpdateCount).to.be.true;
76
+ // });
77
+
78
+ // it('Start public ChatConvo', async () => {
79
+ // const id = 'rtv-1';
80
+
81
+ // const publicConvo = await startPublicConvo(id);
82
+
83
+ // console.log('Created', publicConvo);
84
+
85
+ // expect(publicConvo.public).to.be.true;
86
+ // });
87
+
88
+ // it('GetConvoOwnerNAuth public convo', async () => {
89
+ // const convoId = 'e8e15949-311e-4954-8701-3fe46cc21b98';
90
+ // const mockContext = {
91
+ // req: {
92
+ // headers: {
93
+ // authorization: '',
94
+ // },
95
+ // },
96
+ // };
97
+
98
+ // const publicMessages = await getConvoOwnerNAuth(convoId, mockContext);
99
+
100
+ // console.log('publicMessages', publicMessages);
101
+
102
+ // expect(publicMessages).not.to.be.empty;
103
+ // });
104
+
105
+ // it('GetConvoOwnerNAuth private convo', async () => {
106
+ // const convoId = 'e9992706-e854-4aef-bb5f-5e09d4224bf4';
107
+ // const mockContext = {
108
+ // req: {
109
+ // headers: {
110
+ // authorization:
111
+ // 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI5OWJjNDNiYS0wMmFiLTQzOTQtYjQ4Yi00OWEzOWE5NTQ0M2MiLCJpYXQiOjE2NjMyMTc2MjMsImV4cCI6MTY2MzQ3NjgyM30.zvCJo95goSCemwhvSEXF5nd3jIDhMZTfVrn9jUeo1OA',
112
+ // },
113
+ // },
114
+ // };
115
+
116
+ // const publicMessages = await getConvoOwnerNAuth(convoId, mockContext);
117
+
118
+ // console.log('publicMessages', publicMessages);
119
+
120
+ // expect(publicMessages).not.to.be.empty;
121
+ // });
122
+ });