@amityco/ts-sdk 0.0.1-beta.22 → 0.0.1-beta.23

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 (33) hide show
  1. package/dist/@types/domains/reaction.d.ts +1 -1
  2. package/dist/@types/domains/reaction.d.ts.map +1 -1
  3. package/dist/channel/api/queryChannelMembers.d.ts +2 -1
  4. package/dist/channel/api/queryChannelMembers.d.ts.map +1 -1
  5. package/dist/client/api/connectClient.d.ts +3 -1
  6. package/dist/client/api/connectClient.d.ts.map +1 -1
  7. package/dist/comment/api/queryComments.d.ts +1 -0
  8. package/dist/comment/api/queryComments.d.ts.map +1 -1
  9. package/dist/core/model/identifyModel.d.ts +1 -0
  10. package/dist/core/model/identifyModel.d.ts.map +1 -1
  11. package/dist/core/query/query.d.ts.map +1 -1
  12. package/dist/index.cjs.js +198 -65
  13. package/dist/index.esm.js +197 -65
  14. package/dist/index.umd.js +5 -5
  15. package/dist/message/api/createMessage.d.ts.map +1 -1
  16. package/dist/message/events/onMessageUpdated.d.ts.map +1 -1
  17. package/dist/reaction/events/onReactionAdded.d.ts.map +1 -1
  18. package/dist/reaction/utils/index.d.ts +1 -0
  19. package/dist/reaction/utils/index.d.ts.map +1 -1
  20. package/dist/reaction/utils/prepareMessagePayloadForCache.d.ts +3 -0
  21. package/dist/reaction/utils/prepareMessagePayloadForCache.d.ts.map +1 -0
  22. package/package.json +1 -1
  23. package/src/@types/domains/reaction.ts +1 -1
  24. package/src/channel/api/queryChannelMembers.ts +4 -4
  25. package/src/client/api/connectClient.ts +12 -7
  26. package/src/comment/api/queryComments.ts +6 -3
  27. package/src/core/model/identifyModel.ts +18 -0
  28. package/src/core/query/query.ts +19 -1
  29. package/src/message/api/createMessage.ts +19 -6
  30. package/src/message/events/onMessageUpdated.ts +9 -1
  31. package/src/reaction/events/onReactionAdded.ts +4 -0
  32. package/src/reaction/utils/index.ts +1 -0
  33. package/src/reaction/utils/prepareMessagePayloadForCache.ts +40 -0
@@ -1 +1 @@
1
- {"version":3,"file":"createMessage.d.ts","sourceRoot":"","sources":["../../../src/message/api/createMessage.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,aAAa;2JAKvB,QAAQ,MAAM,MAAM,CAAC,MAAM,OAAO,CAAC,CAAC;IAkBvC;;;;;;;;;;;;;;;OAeG;2BAEO,KACN,MAAM,OAAO,EACb,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,CAChF,GACA,MAAM,MAAM,CAAC,MAAM,OAAO,CAAC,GAAG,SAAS;CAvBzC,CAAC"}
1
+ {"version":3,"file":"createMessage.d.ts","sourceRoot":"","sources":["../../../src/message/api/createMessage.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,aAAa;2JAKvB,QAAQ,MAAM,MAAM,CAAC,MAAM,OAAO,CAAC,CAAC;IAmBvC;;;;;;;;;;;;;;;OAeG;2BAEO,KACN,MAAM,OAAO,EACb,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,CAChF,GACA,MAAM,MAAM,CAAC,MAAM,OAAO,CAAC,GAAG,SAAS;CAvBzC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"onMessageUpdated.d.ts","sourceRoot":"","sources":["../../../src/message/events/onMessageUpdated.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,aAAc,MAAM,QAAQ,CAAC,MAAM,OAAO,CAAC,KAAG,MAAM,YAShF,CAAC"}
1
+ {"version":3,"file":"onMessageUpdated.d.ts","sourceRoot":"","sources":["../../../src/message/events/onMessageUpdated.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,aAAc,MAAM,QAAQ,CAAC,MAAM,OAAO,CAAC,KAAG,MAAM,YAgBhF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"onReactionAdded.d.ts","sourceRoot":"","sources":["../../../src/reaction/events/onReactionAdded.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;KAgBK;AACL,eAAO,MAAM,eAAe,kBACX,MAAM,aAAa,eACrB,MAAM,QAAQ,CAAC,aAAa,CAAC,0FAEzC,MAAM,YAsCR,CAAC"}
1
+ {"version":3,"file":"onReactionAdded.d.ts","sourceRoot":"","sources":["../../../src/reaction/events/onReactionAdded.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;KAgBK;AACL,eAAO,MAAM,eAAe,kBACX,MAAM,aAAa,eACrB,MAAM,QAAQ,CAAC,aAAa,CAAC,0FAEzC,MAAM,YA0CR,CAAC"}
@@ -1,4 +1,5 @@
1
1
  export * from './dispatchReactable';
2
2
  export * from './fetchReference';
3
3
  export * from './preparePayloadForCache';
4
+ export * from './prepareMessagePayloadForCache';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/reaction/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/reaction/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,iCAAiC,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** @hidden */
2
+ export declare const prepareMessagePayloadForCache: (payload: Amity.Message) => void;
3
+ //# sourceMappingURL=prepareMessagePayloadForCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepareMessagePayloadForCache.d.ts","sourceRoot":"","sources":["../../../src/reaction/utils/prepareMessagePayloadForCache.ts"],"names":[],"mappings":"AAGA,cAAc;AAKd,eAAO,MAAM,6BAA6B,YAAa,MAAM,OAAO,SA+BnE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amityco/ts-sdk",
3
- "version": "0.0.1-beta.22",
3
+ "version": "0.0.1-beta.23",
4
4
  "license": "CC-BY-ND-4.0",
5
5
  "author": "amity.co <developers@amity.co> (https://amity.co)",
6
6
  "description": "Amity Social Cloud Typescript SDK",
@@ -18,7 +18,7 @@ declare global {
18
18
  myReactions?: string[];
19
19
 
20
20
  latestReaction?: Amity.Reaction & {
21
- eventName: 'added' | 'removed';
21
+ eventName: 'add' | 'remove';
22
22
  };
23
23
  };
24
24
 
@@ -19,22 +19,22 @@ import { ingestInCache } from '~/cache/api/ingestInCache';
19
19
  * */
20
20
  export const queryChannelMembers = async (query: {
21
21
  channelId: string;
22
- membership?: 'all' | 'muted' | 'banned' | 'member&banned';
22
+ memberships?: ('muted' | 'banned' | 'member')[];
23
23
  roles?: string[];
24
24
  sortBy?: 'firstCreated' | 'lastCreated';
25
+ search?: string;
25
26
  page?: Amity.Page;
26
27
  }): Promise<Amity.Cached<Amity.Paged<Amity.Membership<'channel'>>>> => {
27
28
  const client = getActiveClient();
28
29
  client.log('channel/queryChannelMembers', query);
29
30
 
30
- const { page, channelId, membership, ...params } = query ?? {};
31
+ const { page, channelId, ...params } = query ?? {};
31
32
 
32
33
  const { data } = await client.http.get<Amity.ChannelMembershipPayload & Amity.Pagination>(
33
- `/api/v3/channels/${encodeURIComponent(channelId)}/users`,
34
+ `/api/v4/channels/${encodeURIComponent(channelId)}/users`,
34
35
  {
35
36
  params: {
36
37
  ...params,
37
- filter: membership,
38
38
  options: {
39
39
  token: toToken(page, 'skiplimit'),
40
40
  },
@@ -32,12 +32,15 @@ import { onUserDeleted } from '~/user/events/onUserDeleted';
32
32
  * @category Client API
33
33
  * @async
34
34
  */
35
- export const connectClient = async (params: {
36
- userId: Amity.User['userId'];
37
- displayName?: Amity.User['displayName'];
38
- authToken?: string;
39
- deviceId?: Amity.Device['deviceId'];
40
- }): Promise<boolean> => {
35
+ export const connectClient = async (
36
+ params: {
37
+ userId: Amity.User['userId'];
38
+ displayName?: Amity.User['displayName'];
39
+ authToken?: string;
40
+ deviceId?: Amity.Device['deviceId'];
41
+ },
42
+ config?: { disableRTE: boolean },
43
+ ): Promise<boolean> => {
41
44
  const client = getActiveClient();
42
45
  client.log('client/api/connectClient', { apiKey: client.apiKey, ...params });
43
46
 
@@ -70,7 +73,9 @@ export const connectClient = async (params: {
70
73
 
71
74
  setActiveUser(users[0]);
72
75
 
73
- subscribeTopic(getNetworkTopic());
76
+ if (config?.disableRTE !== true) {
77
+ subscribeTopic(getNetworkTopic());
78
+ }
74
79
 
75
80
  const subscriptions = [
76
81
  onClientBanned(() => {
@@ -22,6 +22,7 @@ import { getResolver } from '~/core/model';
22
22
  export const queryComments = async (query: {
23
23
  referenceType: Amity.Comment['referenceType'];
24
24
  referenceId: Amity.Comment['referenceId'];
25
+ sortBy?: 'lastCreated' | 'firstCreated' | 'lastUpdated' | 'firstUpdated';
25
26
  parentId?: Amity.Comment['commentId'] | null;
26
27
  hasFlag?: boolean;
27
28
  isDeleted?: Amity.Comment['isDeleted'];
@@ -32,6 +33,10 @@ export const queryComments = async (query: {
32
33
 
33
34
  const { page = { limit: 10 }, ...params } = query;
34
35
 
36
+ const options = {
37
+ type: params.sortBy ? 'pagination' : undefined,
38
+ token: toToken(page, params.sortBy ? 'skiplimit' : 'afterbefore'),
39
+ };
35
40
  // const filterByParentId = query.parentId !== undefined
36
41
 
37
42
  // API-FIX: parameters should be querystring. (1)
@@ -43,9 +48,7 @@ export const queryComments = async (query: {
43
48
  params: {
44
49
  ...params,
45
50
  // filterByParentId, API-FIX: backend does not support this boolean LOL. what the hell seriously.
46
- options: {
47
- token: toToken(page, 'afterbefore'),
48
- },
51
+ options,
49
52
  },
50
53
  },
51
54
  );
@@ -57,3 +57,21 @@ export const identifyModel = (model: Record<string, unknown>) => {
57
57
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
58
58
  return criterias.find(([_, keys]) => hasKeys(model, keys))?.[0];
59
59
  };
60
+
61
+ /*
62
+ * Identify the modal key for a model
63
+ * Used to get args for optimistic updates
64
+ * Example: createMessage: get messageId on optimistic message creation
65
+ *
66
+ * @param model to be recognized
67
+ * @returns model key array if one if found or undefined
68
+ */
69
+ export const identifyModelKey = (model: Record<string, unknown>): string | undefined => {
70
+ const modalKey = identifyModel(model);
71
+
72
+ if (!modalKey) {
73
+ return undefined;
74
+ }
75
+
76
+ return CRITERIAS[modalKey]?.[0];
77
+ };
@@ -1,5 +1,6 @@
1
1
  /* eslint-disable no-use-before-define */
2
2
  import { isPaged } from './paging';
3
+ import { identifyModelKey } from '~/core/model';
3
4
 
4
5
  /**
5
6
  * Type guard to check and cast that a given async function is has the ".locally" property
@@ -201,7 +202,24 @@ export const runQuery = <Args extends any[], Returned extends any>(
201
202
  );
202
203
  }
203
204
 
204
- func(...args)
205
+ let optimisticArgs = args;
206
+ /* get args for optimistic method calls
207
+ *
208
+ * On optimistic updates, the modal key for the update needs to be passed to
209
+ * the server so as to avoid duplicate modal creation
210
+ *
211
+ * ex: on creating a new message pass the modalKey is messageId, pass this
212
+ * id onto the server so that a duplicate with seperate messageId is not
213
+ * created.
214
+ */
215
+ if (isMutator(func)) {
216
+ // @ts-ignore
217
+ const modelKey = local && local.data && identifyModelKey(local.data);
218
+ // @ts-ignore
219
+ optimisticArgs = modelKey ? [{ ...args[0], [modelKey]: local.data[modelKey] }] : args;
220
+ }
221
+
222
+ func(...optimisticArgs)
205
223
  .then(fresh => {
206
224
  // @ts-ignore i know.
207
225
  // isLocal(local) && syncInCache(local, fresh)
@@ -3,6 +3,7 @@ import { getActiveClient } from '~/client/api';
3
3
  import { upsertInCache, pullFromCache, pushToCache } from '~/cache/api';
4
4
  import { ingestInCache } from '~/cache/api/ingestInCache';
5
5
  import { fireEvent } from '~/core/events';
6
+ import { uuid } from '~/core/uuid';
6
7
 
7
8
  /**
8
9
  * ```js
@@ -28,6 +29,7 @@ export const createMessage = async <T extends Amity.MessageContentType>(
28
29
  >,
29
30
  ): Promise<Amity.Cached<Amity.Message>> => {
30
31
  const client = getActiveClient();
32
+
31
33
  client.log('user/createMessage', bundle);
32
34
 
33
35
  const { data } = await client.http.post<Amity.MessagePayload>('/api/v3/messages', bundle);
@@ -67,23 +69,34 @@ createMessage.optimistically = (
67
69
  >,
68
70
  ): Amity.Cached<Amity.Message> | undefined => {
69
71
  const client = getActiveClient();
70
- client.log('user/createMessage.locally', bundle);
71
72
 
72
73
  if (!client.cache) return;
73
74
 
74
- const channel = pullFromCache<Amity.Channel>(['channel', 'get', bundle.channelId]);
75
+ /*
76
+ * when creating messages optimistically a messageId needs to be added by the
77
+ * client, created a new variable so as to allow backward compatibility of API
78
+ */
79
+ const bundleWithMessageId = { ...bundle, messageId: uuid() };
80
+
81
+ // only log if cache is enabled
82
+ client.log('user/createMessage.locally', bundleWithMessageId);
75
83
 
76
- upsertInCache(['channel', 'get', bundle.channelId], {
84
+ const channel = pullFromCache<Amity.Channel>(['channel', 'get', bundleWithMessageId.channelId]);
85
+
86
+ upsertInCache(['channel', 'get', bundleWithMessageId.channelId], {
77
87
  ...channel?.data,
78
88
  messageCount: (channel?.data.messageCount ?? 0) + 1,
79
89
  });
80
90
 
91
+ // as reused to update created and updated time, which should be the same
92
+ const createdTime = new Date().toISOString();
93
+
81
94
  const message = {
82
- messageId: Math.random().toString(16),
83
95
  userId: client.userId,
84
96
  channelSegment: (channel?.data.messageCount ?? 0) + 1,
85
- createdAt: new Date().toISOString(),
86
- ...bundle,
97
+ createdAt: createdTime,
98
+ updatedAt: createdTime,
99
+ ...bundleWithMessageId,
87
100
  } as Amity.Message;
88
101
 
89
102
  pushToCache(['message', 'get', message.messageId], message, { cachedAt: -1 });
@@ -2,6 +2,7 @@ import { getActiveClient } from '~/client/api';
2
2
  import { createEventSubscriber } from '~/core/events';
3
3
 
4
4
  import { ingestInCache } from '~/cache/api/ingestInCache';
5
+ import { prepareMessagePayloadForCache } from '~/reaction/utils';
5
6
 
6
7
  /**
7
8
  * ```js
@@ -23,7 +24,14 @@ export const onMessageUpdated = (callback: Amity.Listener<Amity.Message>): Amity
23
24
 
24
25
  const filter = (payload: Amity.MessagePayload) => {
25
26
  ingestInCache(payload);
26
- callback(payload.messages[0]);
27
+ const message = payload.messages[0];
28
+
29
+ // if payload does not have myReactions
30
+ if (!message?.myReactions) {
31
+ prepareMessagePayloadForCache(message);
32
+ }
33
+
34
+ callback(message);
27
35
  };
28
36
 
29
37
  return createEventSubscriber(client, 'message/onMessageUpdated', 'v3.message.didUpdate', filter);
@@ -34,6 +34,10 @@ export const onReactionAdded = (
34
34
  }
35
35
  };
36
36
 
37
+ /*
38
+ * Important: Want to point out that reference type will never be 'message'
39
+ * for onReactionAdded
40
+ */
37
41
  if (referenceType === 'message') {
38
42
  const client = getActiveClient();
39
43
 
@@ -1,3 +1,4 @@
1
1
  export * from './dispatchReactable';
2
2
  export * from './fetchReference';
3
3
  export * from './preparePayloadForCache';
4
+ export * from './prepareMessagePayloadForCache';
@@ -0,0 +1,40 @@
1
+ import { pullFromCache } from '~/cache/api';
2
+ import { getActiveClient } from '~/client/api';
3
+
4
+ /** @hidden */
5
+ /*
6
+ * @param message payload from http request without myReactions
7
+ * add myReactions to http response if the event was a reaction event
8
+ */
9
+ export const prepareMessagePayloadForCache = (payload: Amity.Message) => {
10
+ const client = getActiveClient();
11
+
12
+ const cached = pullFromCache<Amity.Message>(['message', 'get', payload.messageId]);
13
+ // '[]' in cases where the new reaction is the first one
14
+ const myReactions = cached?.data.myReactions || [];
15
+
16
+ // add myReactions to the payload
17
+ Object.assign(payload, { myReactions });
18
+
19
+ // check if there are any updates to the reactions
20
+ const latestReaction = payload?.latestReaction;
21
+ const isLatestReactionMine = latestReaction && latestReaction.userId === client.userId;
22
+
23
+ if (!isLatestReactionMine) {
24
+ return;
25
+ }
26
+
27
+ // new reaction added
28
+ if (latestReaction.eventName === 'add' && !myReactions.includes(latestReaction.reactionName)) {
29
+ Object.assign(payload, {
30
+ myReactions: [...myReactions, latestReaction.reactionName],
31
+ });
32
+ }
33
+
34
+ // existing reaction removed
35
+ if (latestReaction.eventName === 'remove' && myReactions.includes(latestReaction.reactionName)) {
36
+ Object.assign(payload, {
37
+ myReactions: myReactions.filter(x => x !== latestReaction.reactionName),
38
+ });
39
+ }
40
+ };