@typexim/web-sdk 0.0.6 → 0.0.8
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.
- package/README.md +3 -1
- package/dist/types/enums/sdk.d.ts +0 -1
- package/dist/types/modules/ChatSDK.d.ts +8 -2
- package/dist/types/modules/ReConnectWebsocket.d.ts +3 -0
- package/dist/types/modules/TabSessionCoordinator.d.ts +9 -5
- package/dist/types/utils/websocket.d.ts +4 -0
- package/dist/web-sdk.esm.js +1 -1
- package/dist/web-sdk.js +1 -1
- package/dist-test/enums/business.js +139 -0
- package/dist-test/enums/index.js +2 -0
- package/dist-test/enums/sdk.js +24 -0
- package/dist-test/events.js +50 -0
- package/dist-test/index.js +26 -0
- package/dist-test/interfaces/business.js +1 -0
- package/dist-test/interfaces/index.js +3 -0
- package/dist-test/interfaces/pushMessage.js +1 -0
- package/dist-test/interfaces/sdk/api.js +1 -0
- package/dist-test/interfaces/sdk/common.js +1 -0
- package/dist-test/interfaces/sdk/index.js +2 -0
- package/dist-test/modules/Base.js +70 -0
- package/dist-test/modules/BusinessWebsocket.js +68 -0
- package/dist-test/modules/ChatSDK.js +698 -0
- package/dist-test/modules/FeedCache.js +211 -0
- package/dist-test/modules/HttpClient.js +104 -0
- package/dist-test/modules/Logger.js +73 -0
- package/dist-test/modules/PushMessageProcessor.js +437 -0
- package/dist-test/modules/ReConnectWebsocket.js +223 -0
- package/dist-test/modules/Storage.js +27 -0
- package/dist-test/modules/TabSessionCoordinator.js +289 -0
- package/dist-test/modules/Version.js +20 -0
- package/dist-test/utils/date.js +4 -0
- package/dist-test/utils/http.js +13 -0
- package/dist-test/utils/makeSign.js +79 -0
- package/dist-test/utils/message.js +146 -0
- package/dist-test/utils/misc.js +13 -0
- package/dist-test/utils/promise.js +10 -0
- package/dist-test/utils/sleep.js +3 -0
- package/dist-test/utils/websocket.js +24 -0
- package/package.json +1 -1
- package/test/{chat-sdk-restore-login.test.mjs → chat-sdk-independent-login.test.mjs} +50 -62
- package/test/chat-sdk-session-restore.test.mjs +331 -0
- package/test/tab-session-coordinator.test.mjs +65 -64
- package/test/websocket-url.test.mjs +24 -0
- package/dist/types/modules/SingletonLock.d.ts +0 -12
- package/test/singleton-lock.test.mjs +0 -75
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { FeedType } from '../enums/index.js';
|
|
2
|
+
import { withResolvers } from '../utils/promise.js';
|
|
3
|
+
export default class FeedCache {
|
|
4
|
+
constructor() {
|
|
5
|
+
Object.defineProperty(this, "syncCompleted", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
writable: true,
|
|
9
|
+
value: void 0
|
|
10
|
+
});
|
|
11
|
+
// feed_id -> Feed
|
|
12
|
+
Object.defineProperty(this, "map", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
configurable: true,
|
|
15
|
+
writable: true,
|
|
16
|
+
value: void 0
|
|
17
|
+
});
|
|
18
|
+
// chat_id -> feed_id
|
|
19
|
+
Object.defineProperty(this, "chatMap", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
configurable: true,
|
|
22
|
+
writable: true,
|
|
23
|
+
value: void 0
|
|
24
|
+
});
|
|
25
|
+
// thread_id -> feed_id
|
|
26
|
+
Object.defineProperty(this, "threadMap", {
|
|
27
|
+
enumerable: true,
|
|
28
|
+
configurable: true,
|
|
29
|
+
writable: true,
|
|
30
|
+
value: void 0
|
|
31
|
+
});
|
|
32
|
+
// target_id -> feed_id
|
|
33
|
+
Object.defineProperty(this, "targetMap", {
|
|
34
|
+
enumerable: true,
|
|
35
|
+
configurable: true,
|
|
36
|
+
writable: true,
|
|
37
|
+
value: void 0
|
|
38
|
+
});
|
|
39
|
+
Object.defineProperty(this, "list", {
|
|
40
|
+
enumerable: true,
|
|
41
|
+
configurable: true,
|
|
42
|
+
writable: true,
|
|
43
|
+
value: void 0
|
|
44
|
+
});
|
|
45
|
+
Object.defineProperty(this, "waitMap", {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
configurable: true,
|
|
48
|
+
writable: true,
|
|
49
|
+
value: void 0
|
|
50
|
+
});
|
|
51
|
+
this.syncCompleted = false;
|
|
52
|
+
this.map = new Map();
|
|
53
|
+
this.chatMap = new Map();
|
|
54
|
+
this.threadMap = new Map();
|
|
55
|
+
this.targetMap = new Map();
|
|
56
|
+
this.waitMap = new Map();
|
|
57
|
+
this.list = [];
|
|
58
|
+
}
|
|
59
|
+
getAll() {
|
|
60
|
+
const result = [];
|
|
61
|
+
for (const id of this.list) {
|
|
62
|
+
const feed = this.map.get(id);
|
|
63
|
+
if (feed) {
|
|
64
|
+
result.push(feed);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
get(feedId) {
|
|
70
|
+
return this.map.get(feedId) ?? null;
|
|
71
|
+
}
|
|
72
|
+
getByChat(chatId, threadId) {
|
|
73
|
+
let feedId;
|
|
74
|
+
if (threadId && threadId !== '0') {
|
|
75
|
+
feedId = this.threadMap.get(threadId);
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
feedId = this.chatMap.get(chatId);
|
|
79
|
+
}
|
|
80
|
+
if (feedId !== undefined) {
|
|
81
|
+
return this.get(feedId);
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
getByTargetId(targetId) {
|
|
86
|
+
const set = this.targetMap.get(targetId);
|
|
87
|
+
if (set === undefined) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
const list = [];
|
|
91
|
+
for (const id of set) {
|
|
92
|
+
const feed = this.get(id);
|
|
93
|
+
if (feed !== null) {
|
|
94
|
+
list.push(feed);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return list;
|
|
98
|
+
}
|
|
99
|
+
async waitFor(feedId) {
|
|
100
|
+
const feed = this.get(feedId);
|
|
101
|
+
if (feed) {
|
|
102
|
+
return feed;
|
|
103
|
+
}
|
|
104
|
+
if (this.syncCompleted) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
let resolver = this.waitMap.get(feedId);
|
|
108
|
+
if (!resolver) {
|
|
109
|
+
resolver = withResolvers();
|
|
110
|
+
this.waitMap.set(feedId, resolver);
|
|
111
|
+
}
|
|
112
|
+
await resolver.promise;
|
|
113
|
+
return this.get(feedId);
|
|
114
|
+
}
|
|
115
|
+
resolveWait(feedId) {
|
|
116
|
+
const resolver = this.waitMap.get(feedId);
|
|
117
|
+
if (resolver) {
|
|
118
|
+
resolver.resolve();
|
|
119
|
+
this.waitMap.delete(feedId);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
removeFromList(feedId) {
|
|
123
|
+
const index = this.list.indexOf(feedId);
|
|
124
|
+
if (index > -1) {
|
|
125
|
+
this.list.splice(index, 1);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
remove(feedId) {
|
|
129
|
+
const feed = this.map.get(feedId);
|
|
130
|
+
if (feed) {
|
|
131
|
+
this.map.delete(feedId);
|
|
132
|
+
if (feed.feed_type === FeedType.thread) {
|
|
133
|
+
this.threadMap.delete(feed.thread_id);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
this.chatMap.delete(feed.chat_id);
|
|
137
|
+
if (feed.target_id && feed.target_id !== '0') {
|
|
138
|
+
const set = this.targetMap.get(feed.target_id);
|
|
139
|
+
if (set !== undefined) {
|
|
140
|
+
set.delete(feed.id);
|
|
141
|
+
if (set.size === 0) {
|
|
142
|
+
this.targetMap.delete(feed.target_id);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
this.removeFromList(feedId);
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
beforeSave(feed) {
|
|
153
|
+
if (this.map.has(feed.id)) {
|
|
154
|
+
this.removeFromList(feed.id);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
if (feed.feed_type === FeedType.thread) {
|
|
158
|
+
this.threadMap.set(feed.thread_id, feed.id);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
this.chatMap.set(feed.chat_id, feed.id);
|
|
162
|
+
if (feed.target_id && feed.target_id !== '0') {
|
|
163
|
+
if (!this.targetMap.has(feed.target_id)) {
|
|
164
|
+
const set = new Set();
|
|
165
|
+
this.targetMap.set(feed.target_id, set);
|
|
166
|
+
}
|
|
167
|
+
this.targetMap.get(feed.target_id)?.add(feed.id);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
this.map.set(feed.id, feed);
|
|
172
|
+
}
|
|
173
|
+
afterSave(feed) {
|
|
174
|
+
this.resolveWait(feed.id);
|
|
175
|
+
}
|
|
176
|
+
push(feed) {
|
|
177
|
+
this.beforeSave(feed);
|
|
178
|
+
this.list.push(feed.id);
|
|
179
|
+
this.afterSave(feed);
|
|
180
|
+
}
|
|
181
|
+
unshift(feed) {
|
|
182
|
+
this.beforeSave(feed);
|
|
183
|
+
this.list.unshift(feed.id);
|
|
184
|
+
this.afterSave(feed);
|
|
185
|
+
}
|
|
186
|
+
update(feed) {
|
|
187
|
+
if (!this.map.has(feed.id)) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
this.map.set(feed.id, feed);
|
|
191
|
+
}
|
|
192
|
+
markSyncComplete() {
|
|
193
|
+
this.syncCompleted = true;
|
|
194
|
+
for (const [_, resolver] of this.waitMap) {
|
|
195
|
+
resolver.resolve();
|
|
196
|
+
}
|
|
197
|
+
this.waitMap.clear();
|
|
198
|
+
}
|
|
199
|
+
isSyncCompleted() {
|
|
200
|
+
return this.syncCompleted;
|
|
201
|
+
}
|
|
202
|
+
reset() {
|
|
203
|
+
this.syncCompleted = false;
|
|
204
|
+
this.map.clear();
|
|
205
|
+
this.chatMap.clear();
|
|
206
|
+
this.threadMap.clear();
|
|
207
|
+
this.targetMap.clear();
|
|
208
|
+
this.waitMap.clear();
|
|
209
|
+
this.list = [];
|
|
210
|
+
}
|
|
211
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { HttpClientResponseCode } from '../enums/index.js';
|
|
3
|
+
import { createErrorResponse } from '../utils/http.js';
|
|
4
|
+
import makeSign from '../utils/makeSign.js';
|
|
5
|
+
function createMakeSignErrorResponse() {
|
|
6
|
+
return createErrorResponse(HttpClientResponseCode.MAKE_SIGN_FAIL, 'make sign fail');
|
|
7
|
+
}
|
|
8
|
+
export default class HttpClient {
|
|
9
|
+
constructor(config) {
|
|
10
|
+
Object.defineProperty(this, "api", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
writable: true,
|
|
14
|
+
value: void 0
|
|
15
|
+
});
|
|
16
|
+
Object.defineProperty(this, "context", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
writable: true,
|
|
20
|
+
value: void 0
|
|
21
|
+
});
|
|
22
|
+
Object.defineProperty(this, "logger", {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
value: void 0
|
|
27
|
+
});
|
|
28
|
+
this.api = axios.create({
|
|
29
|
+
baseURL: config.host,
|
|
30
|
+
headers: {
|
|
31
|
+
'x-developer': config.developer,
|
|
32
|
+
},
|
|
33
|
+
withCredentials: true,
|
|
34
|
+
});
|
|
35
|
+
this.context = config.context;
|
|
36
|
+
this.logger = config.logger;
|
|
37
|
+
}
|
|
38
|
+
async request(config) {
|
|
39
|
+
try {
|
|
40
|
+
const { needSign = true, ...axiosConfig } = config;
|
|
41
|
+
if (!axiosConfig.headers) {
|
|
42
|
+
axiosConfig.headers = {};
|
|
43
|
+
}
|
|
44
|
+
axiosConfig.headers['platform'] = 'web';
|
|
45
|
+
if (needSign &&
|
|
46
|
+
config.method?.toUpperCase() === 'POST' &&
|
|
47
|
+
axiosConfig.data) {
|
|
48
|
+
if (this.context.loginUser === null) {
|
|
49
|
+
this.logger.warn('HttpClient needs make sign but not login');
|
|
50
|
+
return createMakeSignErrorResponse();
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const sign = await makeSign(axiosConfig.data, this.context.loginUser.secretKey);
|
|
54
|
+
axiosConfig.headers['sign'] = sign;
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
this.logger.error('HttpClient make sign error', e);
|
|
58
|
+
return createMakeSignErrorResponse();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (this.context.loginUser) {
|
|
62
|
+
axiosConfig.headers['X-Sid'] = this.context.loginUser.sessionId;
|
|
63
|
+
}
|
|
64
|
+
const res = await this.api(axiosConfig);
|
|
65
|
+
const body = res.data;
|
|
66
|
+
if (body.code === HttpClientResponseCode.SUCCESS) {
|
|
67
|
+
return {
|
|
68
|
+
ok: true,
|
|
69
|
+
data: body.data,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
this.logger.info('HttpClient server error', res);
|
|
73
|
+
return {
|
|
74
|
+
ok: false,
|
|
75
|
+
code: body.code,
|
|
76
|
+
msg: body.msg,
|
|
77
|
+
msg_i18n: body.msg_i18n,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return {
|
|
82
|
+
ok: false,
|
|
83
|
+
code: HttpClientResponseCode.NETWORK_ERROR,
|
|
84
|
+
msg: 'network error',
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
get(url, params, config) {
|
|
89
|
+
return this.request({
|
|
90
|
+
url,
|
|
91
|
+
method: 'GET',
|
|
92
|
+
params,
|
|
93
|
+
...config,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
post(url, data, config) {
|
|
97
|
+
return this.request({
|
|
98
|
+
url,
|
|
99
|
+
method: 'POST',
|
|
100
|
+
data,
|
|
101
|
+
...config,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { LogLevel } from '../enums/index.js';
|
|
2
|
+
function padNumStart(num) {
|
|
3
|
+
return `${num}`.padStart(2, '0');
|
|
4
|
+
}
|
|
5
|
+
export default class Logger {
|
|
6
|
+
constructor() {
|
|
7
|
+
Object.defineProperty(this, "level", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
configurable: true,
|
|
10
|
+
writable: true,
|
|
11
|
+
value: void 0
|
|
12
|
+
});
|
|
13
|
+
Object.defineProperty(this, "logHandler", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
configurable: true,
|
|
16
|
+
writable: true,
|
|
17
|
+
value: void 0
|
|
18
|
+
});
|
|
19
|
+
this.level = LogLevel.error;
|
|
20
|
+
this.logHandler = this.createLogHandler();
|
|
21
|
+
}
|
|
22
|
+
getPriority(level) {
|
|
23
|
+
switch (level) {
|
|
24
|
+
case LogLevel.error:
|
|
25
|
+
return 3;
|
|
26
|
+
case LogLevel.warning:
|
|
27
|
+
return 2;
|
|
28
|
+
case LogLevel.info:
|
|
29
|
+
return 1;
|
|
30
|
+
default:
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
createLogHandler() {
|
|
35
|
+
return (level, ...args) => {
|
|
36
|
+
const date = new Date();
|
|
37
|
+
const timestamp = `${date.getFullYear()}-${padNumStart(date.getMonth() + 1)}-${padNumStart(date.getDate())} ${padNumStart(date.getHours())}:${padNumStart(date.getMinutes())}:${padNumStart(date.getSeconds())}.${date.getMilliseconds()}`;
|
|
38
|
+
const prefix = `TypeX >> [${timestamp}]`;
|
|
39
|
+
switch (level) {
|
|
40
|
+
case LogLevel.error:
|
|
41
|
+
console.error(prefix, '[ERR]', ...args);
|
|
42
|
+
break;
|
|
43
|
+
case LogLevel.warning:
|
|
44
|
+
console.warn(prefix, '[WARN]', ...args);
|
|
45
|
+
break;
|
|
46
|
+
case LogLevel.info:
|
|
47
|
+
console.info(prefix, '[INFO]', ...args);
|
|
48
|
+
break;
|
|
49
|
+
default:
|
|
50
|
+
console.log(prefix, ...args);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
log(level, ...args) {
|
|
55
|
+
if (this.getPriority(level) >= this.getPriority(this.level)) {
|
|
56
|
+
this.logHandler(level, ...args);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
setLogLevel(level) {
|
|
60
|
+
this.level = level;
|
|
61
|
+
// 重新创建logHandler以确保使用新的日志级别
|
|
62
|
+
this.logHandler = this.createLogHandler();
|
|
63
|
+
}
|
|
64
|
+
info(...args) {
|
|
65
|
+
this.log(LogLevel.info, ...args);
|
|
66
|
+
}
|
|
67
|
+
warn(...args) {
|
|
68
|
+
this.log(LogLevel.warning, ...args);
|
|
69
|
+
}
|
|
70
|
+
error(...args) {
|
|
71
|
+
this.log(LogLevel.error, ...args);
|
|
72
|
+
}
|
|
73
|
+
}
|