@typexim/web-sdk 0.0.6 → 0.0.8-alpha.1

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 (45) hide show
  1. package/README.md +10 -3
  2. package/dist/types/enums/sdk.d.ts +0 -1
  3. package/dist/types/interfaces/business.d.ts +45 -1
  4. package/dist/types/interfaces/sdk/api.d.ts +41 -1
  5. package/dist/types/modules/ChatSDK.d.ts +24 -3
  6. package/dist/types/modules/TabSessionCoordinator.d.ts +5 -5
  7. package/dist/types/utils/misc.d.ts +10 -0
  8. package/dist/web-sdk.esm.js +1 -1
  9. package/dist/web-sdk.js +1 -1
  10. package/dist-test/enums/business.js +139 -0
  11. package/dist-test/enums/index.js +2 -0
  12. package/dist-test/enums/sdk.js +24 -0
  13. package/dist-test/events.js +50 -0
  14. package/dist-test/index.js +26 -0
  15. package/dist-test/interfaces/business.js +1 -0
  16. package/dist-test/interfaces/index.js +3 -0
  17. package/dist-test/interfaces/pushMessage.js +1 -0
  18. package/dist-test/interfaces/sdk/api.js +1 -0
  19. package/dist-test/interfaces/sdk/common.js +1 -0
  20. package/dist-test/interfaces/sdk/index.js +2 -0
  21. package/dist-test/modules/Base.js +70 -0
  22. package/dist-test/modules/BusinessWebsocket.js +68 -0
  23. package/dist-test/modules/ChatSDK.js +698 -0
  24. package/dist-test/modules/FeedCache.js +211 -0
  25. package/dist-test/modules/HttpClient.js +104 -0
  26. package/dist-test/modules/Logger.js +73 -0
  27. package/dist-test/modules/PushMessageProcessor.js +437 -0
  28. package/dist-test/modules/ReConnectWebsocket.js +223 -0
  29. package/dist-test/modules/Storage.js +27 -0
  30. package/dist-test/modules/TabSessionCoordinator.js +289 -0
  31. package/dist-test/modules/Version.js +20 -0
  32. package/dist-test/utils/date.js +4 -0
  33. package/dist-test/utils/http.js +13 -0
  34. package/dist-test/utils/makeSign.js +79 -0
  35. package/dist-test/utils/message.js +146 -0
  36. package/dist-test/utils/misc.js +13 -0
  37. package/dist-test/utils/promise.js +10 -0
  38. package/dist-test/utils/sleep.js +3 -0
  39. package/dist-test/utils/websocket.js +24 -0
  40. package/package.json +3 -2
  41. package/test/chat-sdk-independent-login.test.mjs +218 -0
  42. package/test/{chat-sdk-restore-login.test.mjs → chat-sdk-session-restore.test.mjs} +69 -29
  43. package/test/tab-session-coordinator.test.mjs +30 -64
  44. package/dist/types/modules/SingletonLock.d.ts +0 -12
  45. package/test/singleton-lock.test.mjs +0 -75
@@ -0,0 +1,437 @@
1
+ import { Bool, MessageKind, MessageOperation, PushMessageType } from '../enums/index.js';
2
+ import { CHAT_SDK_EVENT } from '../events.js';
3
+ export default class PushMessageProcessor {
4
+ constructor(config) {
5
+ Object.defineProperty(this, "context", {
6
+ enumerable: true,
7
+ configurable: true,
8
+ writable: true,
9
+ value: void 0
10
+ });
11
+ Object.defineProperty(this, "logger", {
12
+ enumerable: true,
13
+ configurable: true,
14
+ writable: true,
15
+ value: void 0
16
+ });
17
+ Object.defineProperty(this, "emitter", {
18
+ enumerable: true,
19
+ configurable: true,
20
+ writable: true,
21
+ value: void 0
22
+ });
23
+ Object.defineProperty(this, "feedCache", {
24
+ enumerable: true,
25
+ configurable: true,
26
+ writable: true,
27
+ value: void 0
28
+ });
29
+ Object.defineProperty(this, "handleKickoff", {
30
+ enumerable: true,
31
+ configurable: true,
32
+ writable: true,
33
+ value: void 0
34
+ });
35
+ this.context = config.context;
36
+ this.logger = config.logger;
37
+ this.emitter = config.emitter;
38
+ this.feedCache = config.feedCache;
39
+ this.handleKickoff = config.onKickoff;
40
+ }
41
+ emitFeedListUpdated() {
42
+ this.emitter.emit(CHAT_SDK_EVENT.FEED_LIST_UPDATED, {
43
+ list: this.feedCache.getAll(),
44
+ is_sync_completed: this.feedCache.isSyncCompleted(),
45
+ });
46
+ }
47
+ processCreateFeed(pushMessage) {
48
+ this.feedCache.unshift(pushMessage.content);
49
+ this.emitFeedListUpdated();
50
+ }
51
+ processUpdateFeed(pushMessage) {
52
+ const nFeed = pushMessage.content;
53
+ const feed = this.feedCache.getByChat(nFeed.chat_id, nFeed.thread_id);
54
+ if (feed === null) {
55
+ return;
56
+ }
57
+ const newFeed = { ...feed, ...nFeed };
58
+ this.feedCache.update(newFeed);
59
+ this.emitFeedListUpdated();
60
+ }
61
+ processDeleteFeed(pushMessage) {
62
+ const ok = this.feedCache.remove(pushMessage.content.id);
63
+ if (ok) {
64
+ this.emitFeedListUpdated();
65
+ }
66
+ }
67
+ processAddMessage(pushMessage) {
68
+ if (this.context.loginUser === null) {
69
+ return;
70
+ }
71
+ const loginUserId = this.context.loginUser.userId;
72
+ const message = pushMessage.content;
73
+ // 以下情况对消息不处理:
74
+ // 1. 消息对当前登录用户隐藏
75
+ // 2. 不更新feed的last_message_*
76
+ if (message.hide_ids.includes(loginUserId)) {
77
+ return;
78
+ }
79
+ // 找到message所属的feed
80
+ const feed = this.feedCache.getByChat(message.chat_id, message.thread_id);
81
+ if (feed === null) {
82
+ return;
83
+ }
84
+ if (message.no_last_msg !== Bool.yes) {
85
+ let needUpdateFeed = false;
86
+ let needUpdateFeedOrder = false;
87
+ const partialFeed = {};
88
+ // 更新未读消息数
89
+ if (message.message_kind_id !== MessageKind.system &&
90
+ message.sender_id !== loginUserId &&
91
+ message.no_read !== Bool.yes) {
92
+ needUpdateFeed = true;
93
+ const unreadMessageSet = new Set(feed.unread_message_ids);
94
+ unreadMessageSet.add(message.id);
95
+ partialFeed.unread_message_ids = [...unreadMessageSet];
96
+ partialFeed.badge = unreadMessageSet.size;
97
+ }
98
+ // 更新最后一条消息
99
+ if (feed.last_message_position < message.position) {
100
+ needUpdateFeed = true;
101
+ needUpdateFeedOrder = true;
102
+ partialFeed.last_message_id = message.id;
103
+ partialFeed.last_message_position = message.position;
104
+ partialFeed.last_message_sender_id = message.sender_id;
105
+ partialFeed.last_message_send_at = message.send_at;
106
+ partialFeed.last_message_kind_id = message.message_kind_id;
107
+ partialFeed.last_message_type_id = message.message_type_id;
108
+ partialFeed.last_message = message.content;
109
+ partialFeed.last_message_operation = message.operation;
110
+ partialFeed.last_message_operation_user_id = message.operation_user_id;
111
+ }
112
+ if (needUpdateFeed) {
113
+ const newFeed = { ...feed, ...partialFeed };
114
+ if (needUpdateFeedOrder) {
115
+ this.feedCache.unshift(newFeed);
116
+ }
117
+ else {
118
+ this.feedCache.update(newFeed);
119
+ }
120
+ this.emitFeedListUpdated();
121
+ }
122
+ }
123
+ this.emitter.emit(CHAT_SDK_EVENT.MESSAGE_RECEIVED, {
124
+ feed_id: feed.id,
125
+ message,
126
+ });
127
+ }
128
+ processUpdateMessage(pushMessage) {
129
+ const info = pushMessage.content;
130
+ const feed = this.feedCache.getByChat(info.chat_id, info.thread_id);
131
+ if (feed === null) {
132
+ return;
133
+ }
134
+ if (info.operation != null) {
135
+ let needUpdateFeed = false;
136
+ const partialFeed = {};
137
+ if (info.operation === MessageOperation.recall ||
138
+ info.operation === MessageOperation.destroy) {
139
+ // 更新未读消息数
140
+ if (feed.unread_message_ids != null &&
141
+ feed.unread_message_ids.includes(info.id)) {
142
+ needUpdateFeed = true;
143
+ const unreadMessageSet = new Set(feed.unread_message_ids);
144
+ unreadMessageSet.delete(info.id);
145
+ partialFeed.unread_message_ids = [...unreadMessageSet];
146
+ partialFeed.badge = partialFeed.unread_message_ids.length;
147
+ }
148
+ // 更新最后一条消息
149
+ if (feed.last_message_id === info.id) {
150
+ needUpdateFeed = true;
151
+ partialFeed.last_message = info.content ?? '{}';
152
+ partialFeed.last_message_operation = info.operation;
153
+ partialFeed.last_message_operation_user_id =
154
+ info.operation_user_id ?? '0';
155
+ }
156
+ }
157
+ else if (info.operation === MessageOperation.edit) {
158
+ if (feed.last_message_id === info.id) {
159
+ needUpdateFeed = true;
160
+ partialFeed.last_message_kind_id = info.message_kind_id;
161
+ partialFeed.last_message_type_id = info.message_type_id;
162
+ partialFeed.last_message = info.content;
163
+ partialFeed.last_message_operation = info.operation;
164
+ partialFeed.last_message_operation_user_id = info.operation_user_id;
165
+ }
166
+ }
167
+ if (needUpdateFeed) {
168
+ this.feedCache.update({
169
+ ...feed,
170
+ ...partialFeed,
171
+ });
172
+ this.emitFeedListUpdated();
173
+ }
174
+ if (info.operation === MessageOperation.recall) {
175
+ this.emitter.emit(CHAT_SDK_EVENT.MESSAGE_RECALLED, {
176
+ message_ids: [info.id],
177
+ });
178
+ }
179
+ else if (info.operation === MessageOperation.edit) {
180
+ if (info.content != null &&
181
+ info.edited_at != null &&
182
+ info.message_kind_id != null &&
183
+ info.message_type_id != null &&
184
+ info.operation_user_id != null) {
185
+ this.emitter.emit(CHAT_SDK_EVENT.MESSAGE_EDITED, {
186
+ chat_id: info.chat_id,
187
+ content: info.content,
188
+ edited_at: info.edited_at,
189
+ id: info.id,
190
+ message_kind_id: info.message_kind_id,
191
+ message_type_id: info.message_type_id,
192
+ operation: info.operation,
193
+ operation_user_id: info.operation_user_id,
194
+ thread_id: info.thread_id,
195
+ });
196
+ }
197
+ }
198
+ else if (info.operation === MessageOperation.destroy) {
199
+ this.emitter.emit(CHAT_SDK_EVENT.MESSAGE_DESTROYED, {
200
+ feed_id: feed.id,
201
+ message_ids: [info.id],
202
+ });
203
+ }
204
+ }
205
+ }
206
+ processDeleteMessage(pushMessage) {
207
+ const info = pushMessage.content;
208
+ const feed = this.feedCache.getByChat(info.chat_id, info.thread_id);
209
+ if (feed === null) {
210
+ return;
211
+ }
212
+ let needUpdateFeed = false;
213
+ const partialFeed = {};
214
+ // 更新最后一条消息
215
+ if (feed.last_message_id === info.id) {
216
+ needUpdateFeed = true;
217
+ partialFeed.last_message = info.content ?? '{}';
218
+ partialFeed.last_message_operation = info.operation;
219
+ partialFeed.last_message_operation_user_id =
220
+ info.operation_user_id ?? '0';
221
+ }
222
+ if (needUpdateFeed) {
223
+ this.feedCache.update({
224
+ ...feed,
225
+ ...partialFeed,
226
+ });
227
+ this.emitFeedListUpdated();
228
+ }
229
+ this.emitter.emit(CHAT_SDK_EVENT.MESSAGE_DESTROYED, {
230
+ feed_id: feed.id,
231
+ message_ids: [info.id],
232
+ });
233
+ }
234
+ processOpenClockMessage(pushMessage) {
235
+ const info = pushMessage.content;
236
+ const feed = this.feedCache.getByChat(info.chat_id, info.thread_id);
237
+ if (feed === null) {
238
+ return;
239
+ }
240
+ if (Array.isArray(info.msgs_open_clock)) {
241
+ const messageIds = info.msgs_open_clock.map((item) => item.message_id);
242
+ this.emitter.emit(CHAT_SDK_EVENT.MESSAGE_OPEN_CLOCK, {
243
+ feed_id: feed.id,
244
+ message_ids: messageIds,
245
+ });
246
+ }
247
+ }
248
+ processPushLiveMessage(pushMessage) {
249
+ this.emitter.emit(CHAT_SDK_EVENT.ROOM_MESSAGE_RECEIVED, {
250
+ room_id: pushMessage.content.room_id,
251
+ content: pushMessage.content.message,
252
+ });
253
+ }
254
+ processPushSystemNotice(pushMessage) {
255
+ this.emitter.emit(CHAT_SDK_EVENT.SYSTEM_NOTICE_RECEIVED, {
256
+ content: pushMessage.content,
257
+ });
258
+ }
259
+ processReadMessage(pushMessage) {
260
+ if (this.context.loginUser === null) {
261
+ return;
262
+ }
263
+ const loginUserId = this.context.loginUser.userId;
264
+ const info = pushMessage.content;
265
+ const feed = this.feedCache.getByChat(info.chat_id, info.thread_id);
266
+ if (feed === null) {
267
+ return;
268
+ }
269
+ let needUpdateFeed = false;
270
+ const partialFeed = {};
271
+ // 更新未读数
272
+ if (info.reader_ids.includes(loginUserId) && info.message_ids.length > 0) {
273
+ needUpdateFeed = true;
274
+ const unreadMessageSet = new Set(feed.unread_message_ids);
275
+ info.message_ids.forEach((id) => {
276
+ unreadMessageSet.delete(id);
277
+ });
278
+ partialFeed.unread_message_ids = [...unreadMessageSet];
279
+ partialFeed.badge = unreadMessageSet.size;
280
+ }
281
+ if (needUpdateFeed) {
282
+ this.feedCache.update({
283
+ ...feed,
284
+ ...partialFeed,
285
+ });
286
+ this.emitFeedListUpdated();
287
+ }
288
+ this.emitter.emit(CHAT_SDK_EVENT.MESSAGE_RECEIPT_RECEIVED, {
289
+ feed_id: feed.id,
290
+ message_ids: info.message_ids,
291
+ reader_user_ids: info.reader_ids,
292
+ });
293
+ }
294
+ processKickOutDevice() {
295
+ this.handleKickoff();
296
+ }
297
+ processGroupMember(pushMessage) {
298
+ const info = pushMessage.content;
299
+ const feed = this.feedCache.getByChat(info.chat_id, '0');
300
+ if (feed === null) {
301
+ return;
302
+ }
303
+ const chatterIdSet = new Set(feed.chat_member);
304
+ const isAdd = pushMessage.type === PushMessageType.ADD_GROUP_MEMBER;
305
+ const isDel = pushMessage.type === PushMessageType.DEL_GROUP_MEMBER;
306
+ info.chat_member.forEach((chatter) => {
307
+ if (isAdd) {
308
+ chatterIdSet.add(chatter.chat_id);
309
+ }
310
+ else if (isDel) {
311
+ chatterIdSet.delete(chatter.chat_id);
312
+ }
313
+ });
314
+ this.feedCache.update({
315
+ ...feed,
316
+ chat_member: [...chatterIdSet],
317
+ });
318
+ this.emitFeedListUpdated();
319
+ }
320
+ processUpdateGroup(pushMessage) {
321
+ const info = pushMessage.content;
322
+ const feed = this.feedCache.getByChat(info.chat_id, '0');
323
+ if (feed === null) {
324
+ return;
325
+ }
326
+ let needUpdateFeed = false;
327
+ const partialFeed = {};
328
+ if (info.avatar != null) {
329
+ needUpdateFeed = true;
330
+ partialFeed.avatar = info.avatar;
331
+ }
332
+ if (info.name != null) {
333
+ needUpdateFeed = true;
334
+ partialFeed.name = info.name;
335
+ }
336
+ if (needUpdateFeed) {
337
+ this.feedCache.update({
338
+ ...feed,
339
+ ...partialFeed,
340
+ });
341
+ this.emitFeedListUpdated();
342
+ }
343
+ }
344
+ processUpdateUserData(pushMessage) {
345
+ const info = pushMessage.content;
346
+ const feedList = this.feedCache.getByTargetId(info.id);
347
+ if (feedList.length > 0) {
348
+ const partialFeed = {};
349
+ if (info.avatar != null) {
350
+ partialFeed.avatar = info.avatar;
351
+ }
352
+ if (info.first_name != null || info.last_name != null) {
353
+ let name = info.first_name ?? '';
354
+ if (info.last_name != null) {
355
+ if (name.length > 0) {
356
+ name = `${name} ${info.last_name}`;
357
+ }
358
+ else {
359
+ name = info.last_name;
360
+ }
361
+ }
362
+ partialFeed.name = name;
363
+ }
364
+ for (const feed of feedList) {
365
+ this.feedCache.update({
366
+ ...feed,
367
+ ...partialFeed,
368
+ });
369
+ }
370
+ this.emitFeedListUpdated();
371
+ }
372
+ }
373
+ processUpdateMessageReaction(pushMessage) {
374
+ const info = pushMessage.content;
375
+ const feed = this.feedCache.getByChat(info.chat_id, info.thread_id);
376
+ if (feed === null) {
377
+ return;
378
+ }
379
+ this.emitter.emit(CHAT_SDK_EVENT.MESSAGE_REACTION_UPDATED, {
380
+ feed_id: feed.id,
381
+ message_id: info.message_id,
382
+ reactions: info.reactions,
383
+ });
384
+ }
385
+ process(pushMessage) {
386
+ this.logger.info('PushMessageProcessor process', pushMessage);
387
+ switch (pushMessage.type) {
388
+ case PushMessageType.CREATE_FEED:
389
+ this.processCreateFeed(pushMessage);
390
+ break;
391
+ case PushMessageType.UPDATE_FEED:
392
+ this.processUpdateFeed(pushMessage);
393
+ break;
394
+ case PushMessageType.DELETE_FEED:
395
+ this.processDeleteFeed(pushMessage);
396
+ break;
397
+ case PushMessageType.ADD_MESSAGE:
398
+ this.processAddMessage(pushMessage);
399
+ break;
400
+ case PushMessageType.UPDATE_MESSAGE:
401
+ this.processUpdateMessage(pushMessage);
402
+ break;
403
+ case PushMessageType.DELETE_MESSAGE:
404
+ this.processDeleteMessage(pushMessage);
405
+ break;
406
+ case PushMessageType.PUSH_LIVE_MESSAGE:
407
+ this.processPushLiveMessage(pushMessage);
408
+ break;
409
+ case PushMessageType.MSG_OPEN_CLOCK: {
410
+ this.processOpenClockMessage(pushMessage);
411
+ break;
412
+ }
413
+ case PushMessageType.PUSH_SYSTEM_NOTICE:
414
+ this.processPushSystemNotice(pushMessage);
415
+ break;
416
+ case PushMessageType.READ_MESSAGE:
417
+ this.processReadMessage(pushMessage);
418
+ break;
419
+ case PushMessageType.KICK_OUT_DEVICE:
420
+ this.processKickOutDevice();
421
+ break;
422
+ case PushMessageType.ADD_GROUP_MEMBER:
423
+ case PushMessageType.DEL_GROUP_MEMBER:
424
+ this.processGroupMember(pushMessage);
425
+ break;
426
+ case PushMessageType.UPDATE_GROUP:
427
+ this.processUpdateGroup(pushMessage);
428
+ break;
429
+ case PushMessageType.UPDATE_USER_DATA:
430
+ this.processUpdateUserData(pushMessage);
431
+ break;
432
+ case PushMessageType.UPDATE_MESSAGE_REACTION:
433
+ this.processUpdateMessageReaction(pushMessage);
434
+ break;
435
+ }
436
+ }
437
+ }
@@ -0,0 +1,223 @@
1
+ import { PushMessageType } from '../enums/index.js';
2
+ import { buildWebSocketAuthProtocols, buildWebSocketConnectUrl, } from '../utils/websocket.js';
3
+ import Base from './Base.js';
4
+ const PING_TIMEOUT_MS = 20000;
5
+ const PONG_TIMEOUT_MS = 10000;
6
+ const RE_CONNECT_TIMEOUT_MS = 5000;
7
+ export default class ReConnectWebsocket extends Base {
8
+ constructor(config) {
9
+ super();
10
+ Object.defineProperty(this, "url", {
11
+ enumerable: true,
12
+ configurable: true,
13
+ writable: true,
14
+ value: void 0
15
+ });
16
+ Object.defineProperty(this, "token", {
17
+ enumerable: true,
18
+ configurable: true,
19
+ writable: true,
20
+ value: void 0
21
+ });
22
+ Object.defineProperty(this, "wsRoute", {
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ value: void 0
27
+ });
28
+ Object.defineProperty(this, "logger", {
29
+ enumerable: true,
30
+ configurable: true,
31
+ writable: true,
32
+ value: void 0
33
+ });
34
+ Object.defineProperty(this, "ws", {
35
+ enumerable: true,
36
+ configurable: true,
37
+ writable: true,
38
+ value: void 0
39
+ });
40
+ Object.defineProperty(this, "destroyed", {
41
+ enumerable: true,
42
+ configurable: true,
43
+ writable: true,
44
+ value: void 0
45
+ });
46
+ Object.defineProperty(this, "pingTimeout", {
47
+ enumerable: true,
48
+ configurable: true,
49
+ writable: true,
50
+ value: void 0
51
+ });
52
+ Object.defineProperty(this, "pongTimeout", {
53
+ enumerable: true,
54
+ configurable: true,
55
+ writable: true,
56
+ value: void 0
57
+ });
58
+ Object.defineProperty(this, "reConnectTimeout", {
59
+ enumerable: true,
60
+ configurable: true,
61
+ writable: true,
62
+ value: void 0
63
+ });
64
+ this.url = config.url;
65
+ this.token = config.token;
66
+ this.wsRoute = config.wsRoute ?? null;
67
+ this.logger = config.logger;
68
+ this.ws = null;
69
+ this.destroyed = false;
70
+ this.pingTimeout = null;
71
+ this.pongTimeout = null;
72
+ this.reConnectTimeout = null;
73
+ this.reConnect = this.reConnect.bind(this);
74
+ window.addEventListener('online', this.reConnect);
75
+ this.connect();
76
+ }
77
+ disconnect() {
78
+ if (this.ws) {
79
+ this.ws.onopen = null;
80
+ this.ws.onerror = null;
81
+ this.ws.onmessage = null;
82
+ this.ws.onclose = null;
83
+ this.ws.close();
84
+ this.ws = null;
85
+ }
86
+ if (this.pingTimeout !== null) {
87
+ clearTimeout(this.pingTimeout);
88
+ this.pingTimeout = null;
89
+ }
90
+ if (this.pongTimeout !== null) {
91
+ clearTimeout(this.pongTimeout);
92
+ this.pongTimeout = null;
93
+ }
94
+ if (this.reConnectTimeout !== null) {
95
+ clearTimeout(this.reConnectTimeout);
96
+ this.reConnectTimeout = null;
97
+ }
98
+ }
99
+ connect() {
100
+ if (this.ws) {
101
+ this.logger.warn('ReConnectWebsocket try connect but already connected');
102
+ return;
103
+ }
104
+ const ws = new WebSocket(buildWebSocketConnectUrl(this.url, {
105
+ platform: 'web',
106
+ wsRoute: this.wsRoute,
107
+ }), buildWebSocketAuthProtocols(this.token));
108
+ this.ws = ws;
109
+ ws.onopen = () => {
110
+ this.delaySendPing();
111
+ };
112
+ ws.onerror = (e) => {
113
+ this.logger.info('ReConnectWebsocket error', e);
114
+ };
115
+ ws.onmessage = (e) => {
116
+ try {
117
+ const pushMessage = JSON.parse(e.data);
118
+ if (pushMessage.type === PushMessageType.PONG_MESSAGE) {
119
+ if (this.pongTimeout !== null) {
120
+ clearTimeout(this.pongTimeout);
121
+ this.pongTimeout = null;
122
+ this.delaySendPing();
123
+ }
124
+ }
125
+ else {
126
+ this.sendAck(pushMessage.id);
127
+ }
128
+ if (pushMessage.type === PushMessageType.BIG_PACKAGE_PUSH) {
129
+ for (const item of pushMessage.content.big_push) {
130
+ this.emit('message', item);
131
+ }
132
+ }
133
+ else {
134
+ this.emit('message', pushMessage);
135
+ }
136
+ }
137
+ catch (e) {
138
+ this.logger.error('ReConnectWebsocket message parse failed', e);
139
+ }
140
+ };
141
+ ws.onclose = (e) => {
142
+ if (e.code === 4001) {
143
+ // kick off
144
+ this.kickOff();
145
+ }
146
+ else {
147
+ this.reConnect();
148
+ }
149
+ };
150
+ }
151
+ reConnect() {
152
+ this.disconnect();
153
+ if (!this.destroyed) {
154
+ this.reConnectTimeout = setTimeout(() => {
155
+ this.reConnectTimeout = null;
156
+ this.connect();
157
+ }, RE_CONNECT_TIMEOUT_MS);
158
+ }
159
+ }
160
+ send(message) {
161
+ if (this.destroyed) {
162
+ return false;
163
+ }
164
+ if (!this.ws) {
165
+ this.logger.warn('ReConnectWebsocket send before connect');
166
+ return false;
167
+ }
168
+ try {
169
+ if (this.ws.readyState !== this.ws.OPEN) {
170
+ this.logger.warn('ReConnectWebsocket send but not open', this.ws.readyState);
171
+ return false;
172
+ }
173
+ this.ws.send(JSON.stringify(message));
174
+ return true;
175
+ }
176
+ catch (e) {
177
+ this.logger.warn('ReConnectWebsocket send error', e);
178
+ return false;
179
+ }
180
+ }
181
+ sendAck(id) {
182
+ this.send({
183
+ type: 1,
184
+ ids: [id],
185
+ });
186
+ }
187
+ destroy() {
188
+ if (this.destroyed) {
189
+ return;
190
+ }
191
+ this.destroyed = true;
192
+ this.disconnect();
193
+ window.removeEventListener('online', this.reConnect);
194
+ }
195
+ delaySendPing() {
196
+ if (this.pingTimeout !== null) {
197
+ clearTimeout(this.pingTimeout);
198
+ this.pingTimeout = null;
199
+ }
200
+ this.pingTimeout = setTimeout(() => {
201
+ this.pingTimeout = null;
202
+ const success = this.send({
203
+ type: 0,
204
+ });
205
+ if (success) {
206
+ this.waitPong();
207
+ }
208
+ else {
209
+ this.reConnect();
210
+ }
211
+ }, PING_TIMEOUT_MS);
212
+ }
213
+ waitPong() {
214
+ this.pongTimeout = setTimeout(() => {
215
+ this.logger.info('ReConnectWebsocket pong timeout');
216
+ this.reConnect();
217
+ }, PONG_TIMEOUT_MS);
218
+ }
219
+ kickOff() {
220
+ this.destroy();
221
+ this.emit('kickoff');
222
+ }
223
+ }
@@ -0,0 +1,27 @@
1
+ class Storage {
2
+ static set(value) {
3
+ localStorage.setItem(this.key, JSON.stringify(value));
4
+ }
5
+ static get() {
6
+ try {
7
+ const raw = localStorage.getItem(this.key);
8
+ if (!raw)
9
+ return null;
10
+ const data = JSON.parse(raw);
11
+ return data;
12
+ }
13
+ catch {
14
+ return null;
15
+ }
16
+ }
17
+ static clear() {
18
+ localStorage.removeItem(this.key);
19
+ }
20
+ }
21
+ Object.defineProperty(Storage, "key", {
22
+ enumerable: true,
23
+ configurable: true,
24
+ writable: true,
25
+ value: '__typex_sdk_data__'
26
+ });
27
+ export default Storage;