vanshi-sdk 1.0.6 → 1.2.26
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/LOCAL_STORAGE.md +166 -0
- package/README.md +190 -8
- package/dist/index.cjs +3869 -274
- package/dist/index.d.ts +3033 -798
- package/dist/index.js +32559 -3461
- package/dist/index.mjs +3873 -271
- package/package.json +12 -4
package/dist/index.cjs
CHANGED
|
@@ -29,160 +29,1184 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
29
29
|
// src/sdk/index.ts
|
|
30
30
|
var sdk_exports = {};
|
|
31
31
|
__export(sdk_exports, {
|
|
32
|
+
LocalSyncError: () => LocalSyncError,
|
|
33
|
+
SEDMessageType: () => SEDMessageType,
|
|
34
|
+
SdkRuntimeError: () => SdkRuntimeError,
|
|
35
|
+
ZIMCallAction: () => ZIMCallAction,
|
|
36
|
+
ZIMCallConversationType: () => ZIMCallConversationType,
|
|
37
|
+
ZIMCallEventEnum: () => ZIMCallEventEnum,
|
|
38
|
+
ZIMCallMode: () => ZIMCallMode,
|
|
39
|
+
ZIMCallType: () => ZIMCallType,
|
|
40
|
+
ZIMConnectionEvent: () => ZIMConnectionEvent,
|
|
41
|
+
ZIMConnectionState: () => ZIMConnectionState,
|
|
42
|
+
ZIMConversationEvent: () => ZIMConversationEvent,
|
|
43
|
+
ZIMConversationNotificationStatus: () => ZIMConversationNotificationStatus,
|
|
44
|
+
ZIMConversationPinnedFilter: () => ZIMConversationPinnedFilter,
|
|
45
|
+
ZIMEventEnum: () => ZIMEventEnum,
|
|
46
|
+
ZIMFriendApplicationState: () => ZIMFriendApplicationState,
|
|
47
|
+
ZIMFriendApplicationType: () => ZIMFriendApplicationType,
|
|
48
|
+
ZIMFriendDeleteType: () => ZIMFriendDeleteType,
|
|
49
|
+
ZIMGroupApplicationState: () => ZIMGroupApplicationState,
|
|
50
|
+
ZIMGroupApplicationType: () => ZIMGroupApplicationType,
|
|
51
|
+
ZIMGroupBeInviteMode: () => ZIMGroupBeInviteMode,
|
|
52
|
+
ZIMGroupEnterType: () => ZIMGroupEnterType,
|
|
53
|
+
ZIMGroupInviteMode: () => ZIMGroupInviteMode,
|
|
54
|
+
ZIMGroupJoinMode: () => ZIMGroupJoinMode,
|
|
55
|
+
ZIMGroupMessageNotificationStatus: () => ZIMGroupMessageNotificationStatus,
|
|
56
|
+
ZIMGroupMuteMode: () => ZIMGroupMuteMode,
|
|
57
|
+
ZIMMessageOrder: () => ZIMMessageOrder,
|
|
58
|
+
ZIMUserOnlineStatus: () => ZIMUserOnlineStatus,
|
|
59
|
+
ZIMUserRelationType: () => ZIMUserRelationType,
|
|
60
|
+
ZIM_LOCAL_CALL_EVENTS: () => ZIM_LOCAL_CALL_EVENTS,
|
|
61
|
+
acceptFriendApplication: () => acceptFriendApplication,
|
|
62
|
+
acceptGroupInviteApplication: () => acceptGroupInviteApplication,
|
|
63
|
+
acceptGroupJoinApplication: () => acceptGroupJoinApplication,
|
|
64
|
+
addUsersToBlacklist: () => addUsersToBlacklist,
|
|
65
|
+
callAccept: () => callAccept,
|
|
66
|
+
callCancel: () => callCancel,
|
|
67
|
+
callGetLiveKitToken: () => callGetLiveKitToken,
|
|
68
|
+
callGetMediaState: () => callGetMediaState,
|
|
69
|
+
callGetRoom: () => callGetRoom,
|
|
70
|
+
callHangup: () => callHangup,
|
|
71
|
+
callHasOngoingCall: () => callHasOngoingCall,
|
|
72
|
+
callInvite: () => callInvite,
|
|
73
|
+
callInviteMembers: () => callInviteMembers,
|
|
74
|
+
callJoinMedia: () => callJoinMedia,
|
|
75
|
+
callLeaveMedia: () => callLeaveMedia,
|
|
76
|
+
callQueryMembers: () => callQueryMembers,
|
|
77
|
+
callReject: () => callReject,
|
|
78
|
+
callSetCameraEnabled: () => callSetCameraEnabled,
|
|
79
|
+
callSetMicrophoneEnabled: () => callSetMicrophoneEnabled,
|
|
80
|
+
callStartScreenShare: () => callStartScreenShare,
|
|
81
|
+
callStopScreenShare: () => callStopScreenShare,
|
|
82
|
+
checkUserIsInBlacklist: () => checkUserIsInBlacklist,
|
|
32
83
|
clearConversationTotalUnreadMessageCount: () => clearConversationTotalUnreadMessageCount,
|
|
33
84
|
clearConversationUnreadMessageCount: () => clearConversationUnreadMessageCount,
|
|
85
|
+
clearLocalMessages: () => clearLocalMessages,
|
|
34
86
|
create: () => initSocket,
|
|
87
|
+
createGroup: () => createGroup,
|
|
35
88
|
default: () => sdk_default,
|
|
36
89
|
deleteAllConversationMessages: () => deleteAllConversationMessages,
|
|
37
90
|
deleteAllConversations: () => deleteAllConversations,
|
|
38
91
|
deleteAllMessage: () => deleteAllMessage,
|
|
39
92
|
deleteConversation: () => deleteConversation,
|
|
93
|
+
deleteFriends: () => deleteFriends,
|
|
40
94
|
deleteMessages: () => deleteMessages,
|
|
95
|
+
dismissGroup: () => dismissGroup,
|
|
96
|
+
editMessage: () => editMessage,
|
|
97
|
+
getLocalStorageStatus: () => getLocalStorageStatus,
|
|
98
|
+
inviteUsersIntoGroup: () => inviteUsersIntoGroup,
|
|
41
99
|
isConnected: () => isSocketConnected,
|
|
100
|
+
isSdkRuntimeErrorObject: () => isSdkRuntimeErrorObject,
|
|
101
|
+
joinGroup: () => joinGroup,
|
|
102
|
+
kickGroupMembers: () => kickGroupMembers,
|
|
103
|
+
leaveGroup: () => leaveGroup,
|
|
42
104
|
login: () => login,
|
|
43
105
|
logout: () => logout,
|
|
106
|
+
muteGroup: () => muteGroup,
|
|
107
|
+
muteGroupMembers: () => muteGroupMembers,
|
|
44
108
|
off: () => off,
|
|
45
109
|
on: () => on,
|
|
110
|
+
queryBlacklist: () => queryBlacklist,
|
|
111
|
+
queryCombineMessageDetail: () => queryCombineMessageDetail,
|
|
46
112
|
queryConversation: () => queryConversation,
|
|
113
|
+
queryConversationList: () => queryConversationList,
|
|
114
|
+
queryConversationPinnedList: () => queryConversationPinnedList,
|
|
115
|
+
queryConversationTotalUnreadMessageCount: () => queryConversationTotalUnreadMessageCount,
|
|
116
|
+
queryFailedMessages: () => queryFailedMessages,
|
|
117
|
+
queryFriendApplicationList: () => queryFriendApplicationList,
|
|
118
|
+
queryFriendList: () => queryFriendList,
|
|
119
|
+
queryFriendsInfo: () => queryFriendsInfo,
|
|
120
|
+
queryGroupApplicationList: () => queryGroupApplicationList,
|
|
121
|
+
queryGroupInfo: () => queryGroupInfo,
|
|
122
|
+
queryGroupList: () => queryGroupList,
|
|
123
|
+
queryGroupMemberCount: () => queryGroupMemberCount,
|
|
124
|
+
queryGroupMemberInfo: () => queryGroupMemberInfo,
|
|
125
|
+
queryGroupMemberList: () => queryGroupMemberList,
|
|
126
|
+
queryGroupMemberMutedList: () => queryGroupMemberMutedList,
|
|
47
127
|
queryGroupMessageReceiptReadMemberList: () => queryGroupMessageReceiptReadMemberList,
|
|
48
128
|
queryGroupMessageReceiptUnreadMemberList: () => queryGroupMessageReceiptUnreadMemberList,
|
|
49
129
|
queryHistoryMessage: () => queryHistoryMessage,
|
|
130
|
+
queryLocalMessages: () => queryLocalMessages,
|
|
50
131
|
queryMessageReceiptsInfo: () => queryMessageReceiptsInfo,
|
|
132
|
+
queryMessageRepliedList: () => queryMessageRepliedList,
|
|
133
|
+
queryMessages: () => queryMessages,
|
|
134
|
+
querySelfUserInfo: () => querySelfUserInfo,
|
|
135
|
+
queryUsersInfo: () => queryUsersInfo,
|
|
136
|
+
queryUsersStatus: () => queryUsersStatus,
|
|
137
|
+
rejectFriendApplication: () => rejectFriendApplication,
|
|
138
|
+
rejectGroupInviteApplication: () => rejectGroupInviteApplication,
|
|
139
|
+
rejectGroupJoinApplication: () => rejectGroupJoinApplication,
|
|
140
|
+
removeUsersFromBlacklist: () => removeUsersFromBlacklist,
|
|
141
|
+
renewToken: () => renewToken,
|
|
142
|
+
replyMessage: () => replyMessage,
|
|
51
143
|
revokeMessage: () => revokeMessage,
|
|
144
|
+
searchLocalMessages: () => searchLocalMessages,
|
|
145
|
+
sendFriendApplication: () => sendFriendApplication,
|
|
146
|
+
sendGroupInviteApplications: () => sendGroupInviteApplications,
|
|
147
|
+
sendGroupJoinApplication: () => sendGroupJoinApplication,
|
|
52
148
|
sendMediaMessage: () => sendMediaMessage,
|
|
53
149
|
sendMessage: () => sendMessage,
|
|
54
|
-
sendMessageReceiptsRead: () => sendMessageReceiptsRead
|
|
150
|
+
sendMessageReceiptsRead: () => sendMessageReceiptsRead,
|
|
151
|
+
setConversationNotificationStatus: () => setConversationNotificationStatus,
|
|
152
|
+
setGroupMemberNickname: () => setGroupMemberNickname,
|
|
153
|
+
setGroupMemberRole: () => setGroupMemberRole,
|
|
154
|
+
subscribeUsersStatus: () => subscribeUsersStatus,
|
|
155
|
+
syncConversationMessages: () => syncConversationMessages,
|
|
156
|
+
syncLocalMessages: () => syncLocalMessages,
|
|
157
|
+
transferGroupOwner: () => transferGroupOwner,
|
|
158
|
+
unsubscribeUsersStatus: () => unsubscribeUsersStatus,
|
|
159
|
+
updateConversationPinnedState: () => updateConversationPinnedState,
|
|
160
|
+
updateFriendAlias: () => updateFriendAlias,
|
|
161
|
+
updateGroupAlias: () => updateGroupAlias,
|
|
162
|
+
updateGroupAvatarUrl: () => updateGroupAvatarUrl,
|
|
163
|
+
updateGroupBeInviteMode: () => updateGroupBeInviteMode,
|
|
164
|
+
updateGroupInviteMode: () => updateGroupInviteMode,
|
|
165
|
+
updateGroupJoinMode: () => updateGroupJoinMode,
|
|
166
|
+
updateGroupName: () => updateGroupName,
|
|
167
|
+
updateGroupNotice: () => updateGroupNotice,
|
|
168
|
+
updateUserAvatarUrl: () => updateUserAvatarUrl,
|
|
169
|
+
updateUserName: () => updateUserName
|
|
55
170
|
});
|
|
56
171
|
module.exports = __toCommonJS(sdk_exports);
|
|
57
172
|
|
|
58
|
-
// src/
|
|
59
|
-
var
|
|
173
|
+
// src/sdk/storage/store.ts
|
|
174
|
+
var import_dexie = __toESM(require("dexie"), 1);
|
|
175
|
+
|
|
176
|
+
// src/sdk/storage/sendState.ts
|
|
177
|
+
function numericSendState(value) {
|
|
178
|
+
if (value === 0 || value === 1 || value === 2)
|
|
179
|
+
return value;
|
|
180
|
+
if (value === "0" || value === "1" || value === "2")
|
|
181
|
+
return Number(value);
|
|
182
|
+
}
|
|
183
|
+
function messageSendState(data, fallback = 1) {
|
|
184
|
+
const state = numericSendState(data.sentStatus) ?? numericSendState(data.sendState);
|
|
185
|
+
if (state !== void 0)
|
|
186
|
+
return state;
|
|
187
|
+
switch (data.sendState) {
|
|
188
|
+
case "pending":
|
|
189
|
+
case "sending":
|
|
190
|
+
case "unknown":
|
|
191
|
+
return 0;
|
|
192
|
+
case "sent":
|
|
193
|
+
return 1;
|
|
194
|
+
case "failed":
|
|
195
|
+
return 2;
|
|
196
|
+
default:
|
|
197
|
+
return fallback;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// src/sdk/message/replyIdentity.ts
|
|
202
|
+
var INVALID_REPLY_RESPONSE = "INVALID_REPLY_RESPONSE";
|
|
203
|
+
function isSelfReferencingReply(row) {
|
|
204
|
+
const id = row?.messageID;
|
|
205
|
+
const quoted = row?.repliedInfo;
|
|
206
|
+
return !!id && [quoted?.messageID, quoted?.messageInfo?.messageID].some((originalID) => originalID && String(originalID) === String(id));
|
|
207
|
+
}
|
|
208
|
+
function filterInvalidReplyMessages(data) {
|
|
209
|
+
if (!data || typeof data !== "object")
|
|
210
|
+
return data;
|
|
211
|
+
if (Array.isArray(data)) {
|
|
212
|
+
const filtered2 = data.map(filterInvalidReplyMessages).filter((row) => row !== void 0);
|
|
213
|
+
return filtered2.length === data.length && filtered2.every((row, index) => row === data[index]) ? data : filtered2;
|
|
214
|
+
}
|
|
215
|
+
if (isSelfReferencingReply(data))
|
|
216
|
+
return void 0;
|
|
217
|
+
let filtered = data;
|
|
218
|
+
for (const key of ["messageList", "infos", "message"]) {
|
|
219
|
+
if (filtered[key] && typeof filtered[key] === "object") {
|
|
220
|
+
const value = filterInvalidReplyMessages(filtered[key]);
|
|
221
|
+
if (value === void 0)
|
|
222
|
+
return void 0;
|
|
223
|
+
if (value !== filtered[key])
|
|
224
|
+
filtered = { ...filtered, [key]: value };
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return filtered;
|
|
228
|
+
}
|
|
229
|
+
var MESSAGE_EVENTS = /* @__PURE__ */ new Set(["receivePeerMessage", "receiveGroupMessage", "messageSentStatusChanged", "messageEdited", "messageRevokeReceived", "messageDeleted", "messageReceiptChanged"]);
|
|
230
|
+
function filterReplyPushArgs(event, args) {
|
|
231
|
+
if (!MESSAGE_EVENTS.has(event))
|
|
232
|
+
return args;
|
|
233
|
+
const filtered = args.map(filterInvalidReplyMessages);
|
|
234
|
+
return filtered.some((value, index) => value === void 0 && args[index] !== void 0) ? void 0 : filtered;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// src/sdk/storage/mediaPreview.ts
|
|
238
|
+
var previews = /* @__PURE__ */ new Map();
|
|
239
|
+
function preview(row, field) {
|
|
240
|
+
const blob = row[field];
|
|
241
|
+
if (typeof Blob === "undefined" || !(blob instanceof Blob) || typeof URL === "undefined" || typeof URL.createObjectURL !== "function")
|
|
242
|
+
return;
|
|
243
|
+
const key = `${row.localID}:${field}`;
|
|
244
|
+
const existing = previews.get(key);
|
|
245
|
+
if (existing?.version === row.updatedAt)
|
|
246
|
+
return existing.url;
|
|
247
|
+
if (existing)
|
|
248
|
+
URL.revokeObjectURL(existing.url);
|
|
249
|
+
const url = URL.createObjectURL(blob);
|
|
250
|
+
previews.set(key, { version: row.updatedAt, url });
|
|
251
|
+
return url;
|
|
252
|
+
}
|
|
253
|
+
function restoreMediaPreviews(row) {
|
|
254
|
+
if (!row.file && !row.thumbnailFile)
|
|
255
|
+
return row;
|
|
256
|
+
return {
|
|
257
|
+
...row,
|
|
258
|
+
fileDownloadUrl: row.fileDownloadUrl || preview(row, "file"),
|
|
259
|
+
thumbnailDownloadUrl: row.thumbnailDownloadUrl || preview(row, "thumbnailFile") || (String(row.type) === "11" ? preview(row, "file") : void 0)
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
function clearMediaPreviews() {
|
|
263
|
+
for (const { url } of previews.values())
|
|
264
|
+
URL.revokeObjectURL(url);
|
|
265
|
+
previews.clear();
|
|
266
|
+
}
|
|
267
|
+
function invalidateMediaPreviews(localID) {
|
|
268
|
+
for (const field of ["file", "thumbnailFile"]) {
|
|
269
|
+
const key = `${localID}:${field}`;
|
|
270
|
+
const existing = previews.get(key);
|
|
271
|
+
if (existing)
|
|
272
|
+
URL.revokeObjectURL(existing.url);
|
|
273
|
+
previews.delete(key);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// src/sdk/storage/store.ts
|
|
278
|
+
var listeners = /* @__PURE__ */ new Map();
|
|
279
|
+
function onStorageEvent(event, handler) {
|
|
280
|
+
const set = listeners.get(event) || /* @__PURE__ */ new Set();
|
|
281
|
+
set.add(handler);
|
|
282
|
+
listeners.set(event, set);
|
|
283
|
+
}
|
|
284
|
+
function offStorageEvent(event, handler) {
|
|
285
|
+
if (handler)
|
|
286
|
+
listeners.get(event)?.delete(handler);
|
|
287
|
+
else
|
|
288
|
+
listeners.delete(event);
|
|
289
|
+
}
|
|
290
|
+
function emitStorageEvent(event, data) {
|
|
291
|
+
listeners.get(event)?.forEach((handler) => {
|
|
292
|
+
try {
|
|
293
|
+
const result = handler(data);
|
|
294
|
+
if (result && typeof result.then === "function")
|
|
295
|
+
Promise.resolve(result).catch((error) => console.error("[VanshiSdk] async storage event handler failed", error));
|
|
296
|
+
} catch (error) {
|
|
297
|
+
console.error("[VanshiSdk] storage event handler failed", error);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
var STORAGE_EVENTS = /* @__PURE__ */ new Set(["localMessagesChanged", "localStorageError", "localSyncStateChanged"]);
|
|
302
|
+
function migrateLegacySendState(row) {
|
|
303
|
+
const unconfirmed = ["pending", "sending", "unknown"].includes(row.sendState);
|
|
304
|
+
row.sendState = unconfirmed ? 0 : messageSendState(row);
|
|
305
|
+
if (unconfirmed) {
|
|
306
|
+
row.sentStatus = 0;
|
|
307
|
+
row._deliveryUnconfirmed = true;
|
|
308
|
+
} else if (row.sentStatus === void 0)
|
|
309
|
+
row.sentStatus = row.sendState;
|
|
310
|
+
}
|
|
311
|
+
var MessageDatabase = class extends import_dexie.default {
|
|
312
|
+
constructor(name) {
|
|
313
|
+
super(name);
|
|
314
|
+
const schema = {
|
|
315
|
+
messages: "&localID, &[conversationKey+messageID], &[conversationKey+clientBizId], [conversationKey+timestamp], timestamp, sendState",
|
|
316
|
+
meta: "&key"
|
|
317
|
+
};
|
|
318
|
+
this.version(1).stores(schema);
|
|
319
|
+
this.version(2).stores(schema).upgrade(async (tx) => {
|
|
320
|
+
await tx.table("messages").toCollection().modify(migrateLegacySendState);
|
|
321
|
+
await tx.table("meta").toCollection().modify((row) => {
|
|
322
|
+
if (row.patch && ("sendState" in row.patch || "sentStatus" in row.patch))
|
|
323
|
+
migrateLegacySendState(row.patch);
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
this.version(3).stores({ ...schema, messages: `${schema.messages}, [conversationKey+sendState], [conversationKey+hasServerID], conversationKey` }).upgrade((tx) => tx.table("messages").toCollection().modify((row) => {
|
|
327
|
+
row.hasServerID = row.messageID ? 1 : 0;
|
|
328
|
+
}));
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
var active;
|
|
332
|
+
var generation = 0;
|
|
333
|
+
var lastError;
|
|
334
|
+
var captureStorage = () => active;
|
|
335
|
+
var isCurrentStorage = (ctx) => !!ctx && ctx === active && ctx.active;
|
|
336
|
+
var conversationKey = (id, type) => JSON.stringify([String(type), String(id)]);
|
|
337
|
+
var newLocalID = () => `local_${Date.now()}_${Math.random().toString(36).slice(2)}_${Math.random().toString(36).slice(2)}`;
|
|
338
|
+
function reportStorageError(error, ctx) {
|
|
339
|
+
if (ctx && !isCurrentStorage(ctx))
|
|
340
|
+
return;
|
|
341
|
+
if (ctx)
|
|
342
|
+
ctx.failureCount = (ctx.failureCount || 0) + 1;
|
|
343
|
+
lastError = error instanceof Error ? error.message : String(error);
|
|
344
|
+
emitStorageEvent("localStorageError", { userId: ctx?.userId, message: lastError });
|
|
345
|
+
}
|
|
346
|
+
function closeLocalStorage() {
|
|
347
|
+
clearMediaPreviews();
|
|
348
|
+
generation++;
|
|
349
|
+
if (active) {
|
|
350
|
+
active.active = false;
|
|
351
|
+
active.channel?.close();
|
|
352
|
+
active.db.close();
|
|
353
|
+
}
|
|
354
|
+
active = void 0;
|
|
355
|
+
lastError = void 0;
|
|
356
|
+
}
|
|
357
|
+
function getLocalStorageStatus() {
|
|
358
|
+
return { enabled: !!active, userId: active?.userId, databaseName: active?.db.name, error: lastError };
|
|
359
|
+
}
|
|
360
|
+
async function openLocalStorage(userId, environment) {
|
|
361
|
+
closeLocalStorage();
|
|
362
|
+
const name = `vanshi_chat_${encodeURIComponent(environment)}_${encodeURIComponent(userId)}`;
|
|
363
|
+
const db = new MessageDatabase(name);
|
|
364
|
+
const ctx = { generation, epoch: newLocalID(), userId, db, active: true, ready: Promise.resolve() };
|
|
365
|
+
active = ctx;
|
|
366
|
+
ctx.ready = (async () => {
|
|
367
|
+
await db.open();
|
|
368
|
+
if (!isCurrentStorage(ctx)) {
|
|
369
|
+
db.close();
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
await db.messages.where("sendState").equals(0).modify((row) => {
|
|
373
|
+
if (!row._deliveryUnconfirmed)
|
|
374
|
+
row.errorMessage = "Sending interrupted; delivery not confirmed";
|
|
375
|
+
row._deliveryUnconfirmed = true;
|
|
376
|
+
row.sentStatus = 0;
|
|
377
|
+
row.updatedAt = Date.now();
|
|
378
|
+
});
|
|
379
|
+
if (typeof BroadcastChannel !== "undefined" && isCurrentStorage(ctx)) {
|
|
380
|
+
ctx.channel = new BroadcastChannel(name);
|
|
381
|
+
ctx.channel.onmessage = ({ data }) => {
|
|
382
|
+
if (isCurrentStorage(ctx))
|
|
383
|
+
emitStorageEvent("localMessagesChanged", { ...data, userId });
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
})();
|
|
387
|
+
try {
|
|
388
|
+
await ctx.ready;
|
|
389
|
+
} catch (error) {
|
|
390
|
+
if (isCurrentStorage(ctx)) {
|
|
391
|
+
reportStorageError(error, ctx);
|
|
392
|
+
ctx.active = false;
|
|
393
|
+
db.close();
|
|
394
|
+
active = void 0;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
async function storageWork(ctx, work) {
|
|
399
|
+
if (!isCurrentStorage(ctx))
|
|
400
|
+
return;
|
|
401
|
+
try {
|
|
402
|
+
await ctx.ready;
|
|
403
|
+
if (!isCurrentStorage(ctx))
|
|
404
|
+
return;
|
|
405
|
+
return await work(ctx);
|
|
406
|
+
} catch (error) {
|
|
407
|
+
reportStorageError(error, ctx);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
function changed(ctx, key) {
|
|
411
|
+
if (!isCurrentStorage(ctx))
|
|
412
|
+
return;
|
|
413
|
+
const data = { userId: ctx.userId, conversationKey: key };
|
|
414
|
+
emitStorageEvent("localMessagesChanged", data);
|
|
415
|
+
ctx.channel?.postMessage(data);
|
|
416
|
+
}
|
|
417
|
+
function clean(input) {
|
|
418
|
+
const output = {};
|
|
419
|
+
for (const [key, value] of Object.entries(input)) {
|
|
420
|
+
if (value !== void 0 && typeof value !== "function" && key !== "localPreviewUrl") {
|
|
421
|
+
output[key] = value;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
for (const key of ["fileDownloadUrl", "thumbnailDownloadUrl"]) {
|
|
425
|
+
if (typeof output[key] === "string" && output[key].startsWith("blob:"))
|
|
426
|
+
delete output[key];
|
|
427
|
+
}
|
|
428
|
+
return output;
|
|
429
|
+
}
|
|
430
|
+
function version(row) {
|
|
431
|
+
return Number(row.editedTime || row.editedAt || 0) || 0;
|
|
432
|
+
}
|
|
433
|
+
async function saveMessages(ctx, messages, fallback = {}, source = "server") {
|
|
434
|
+
const fromServer = source === "server" || source === "receive";
|
|
435
|
+
return storageWork(ctx, async (ctx2) => {
|
|
436
|
+
const released = /* @__PURE__ */ new Set();
|
|
437
|
+
await ctx2.db.transaction("rw", ctx2.db.messages, ctx2.db.meta, async () => {
|
|
438
|
+
for (const input of messages) {
|
|
439
|
+
if (!input || typeof input !== "object")
|
|
440
|
+
continue;
|
|
441
|
+
const data = clean({ ...fallback, ...input });
|
|
442
|
+
if (isSelfReferencingReply(data))
|
|
443
|
+
continue;
|
|
444
|
+
const id = data.conversationID ?? fallback.toConversationID;
|
|
445
|
+
const type = data.conversationType;
|
|
446
|
+
if (id === void 0 || type === void 0)
|
|
447
|
+
continue;
|
|
448
|
+
const key = conversationKey(id, type);
|
|
449
|
+
const messageID = data.messageID ? String(data.messageID) : void 0;
|
|
450
|
+
let clientBizId = data.clientBizId ? String(data.clientBizId) : void 0;
|
|
451
|
+
const byServer = messageID ? await ctx2.db.messages.where("[conversationKey+messageID]").equals([key, messageID]).first() : void 0;
|
|
452
|
+
let byClient = clientBizId ? await ctx2.db.messages.where("[conversationKey+clientBizId]").equals([key, clientBizId]).first() : void 0;
|
|
453
|
+
if (messageID && byClient?.messageID && byClient.messageID !== messageID) {
|
|
454
|
+
byClient = void 0;
|
|
455
|
+
clientBizId = void 0;
|
|
456
|
+
delete data.clientBizId;
|
|
457
|
+
delete data.localID;
|
|
458
|
+
delete data.localMessageID;
|
|
459
|
+
}
|
|
460
|
+
let previous = byClient && byServer && byClient.localID !== byServer.localID ? { ...byServer, ...byClient, deleted: byServer.deleted || byClient.deleted, revoked: byServer.revoked || byClient.revoked } : byClient || byServer;
|
|
461
|
+
if (!previous && data.localID) {
|
|
462
|
+
const candidate = await ctx2.db.messages.get(data.localID);
|
|
463
|
+
if (candidate?.conversationKey === key)
|
|
464
|
+
previous = candidate;
|
|
465
|
+
}
|
|
466
|
+
if (byServer && byClient && byServer.localID !== byClient.localID)
|
|
467
|
+
await ctx2.db.messages.delete(byServer.localID);
|
|
468
|
+
if (source === "receive" && data.direction == null) {
|
|
469
|
+
data.direction = data.senderUserID != null ? String(data.senderUserID) === ctx2.userId ? 0 : 1 : previous?.direction ?? 1;
|
|
470
|
+
}
|
|
471
|
+
const globalClear = await ctx2.db.meta.get("clear:all");
|
|
472
|
+
const cleared = await ctx2.db.meta.get(`clear:${key}`);
|
|
473
|
+
const timestamp = Number(data.timestamp ?? previous?.timestamp ?? (source === "patch" ? 0 : Date.now()));
|
|
474
|
+
const row = {
|
|
475
|
+
type: 0,
|
|
476
|
+
...previous,
|
|
477
|
+
...data,
|
|
478
|
+
localID: previous?.localID || data.localID || newLocalID(),
|
|
479
|
+
conversationKey: key,
|
|
480
|
+
conversationID: String(id),
|
|
481
|
+
conversationType: String(type),
|
|
482
|
+
hasServerID: messageID || previous?.messageID ? 1 : 0,
|
|
483
|
+
timestamp: Number.isFinite(timestamp) ? timestamp : Date.now(),
|
|
484
|
+
sendState: messageSendState(data, fromServer ? 1 : previous?.sendState ?? (source === "patch" ? 1 : 0)),
|
|
485
|
+
updatedAt: Date.now()
|
|
486
|
+
};
|
|
487
|
+
if (fromServer)
|
|
488
|
+
row.sentStatus = data.sentStatus ?? row.sendState;
|
|
489
|
+
if (fromServer)
|
|
490
|
+
delete row._deliveryUnconfirmed;
|
|
491
|
+
if (messageID) {
|
|
492
|
+
row.messageID = messageID;
|
|
493
|
+
const deferred = await ctx2.db.meta.get(`patch:${messageID}`);
|
|
494
|
+
if (deferred?.patch) {
|
|
495
|
+
const patch = { ...deferred.patch };
|
|
496
|
+
if (fromServer && data._fetchSequence !== void 0) {
|
|
497
|
+
const newer = (epoch, sequence2) => patch[epoch] === ctx2.epoch && patch[sequence2] > data._fetchSequence;
|
|
498
|
+
if (!newer("_sendEpoch", "_sendSequence")) {
|
|
499
|
+
for (const field of ["sentStatus", "sendState", "_sendEpoch", "_sendSequence", "_deliveryUnconfirmed"])
|
|
500
|
+
delete patch[field];
|
|
501
|
+
}
|
|
502
|
+
if (!newer("_mutationEpoch", "_receiptSequence")) {
|
|
503
|
+
for (const field of ["receiptStatus", "_receiptSequence"])
|
|
504
|
+
delete patch[field];
|
|
505
|
+
}
|
|
506
|
+
if (version(patch) <= version(data) && !newer("_mutationEpoch", "_contentSequence")) {
|
|
507
|
+
for (const field of ["message", "massage", "extendedData", "editedTime", "editedAt", "_contentSequence"])
|
|
508
|
+
delete patch[field];
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
Object.assign(row, patch, { localID: row.localID, conversationKey: key, conversationID: String(id), conversationType: String(type) });
|
|
512
|
+
await ctx2.db.meta.delete(`patch:${messageID}`);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
row.sendState = messageSendState(row, row.sendState);
|
|
516
|
+
if (clientBizId)
|
|
517
|
+
row.clientBizId = clientBizId;
|
|
518
|
+
if (!row.messageID)
|
|
519
|
+
delete row.messageID;
|
|
520
|
+
if (!row.clientBizId)
|
|
521
|
+
delete row.clientBizId;
|
|
522
|
+
if (previous?.sendState === 1 && source === "local") {
|
|
523
|
+
row.sendState = 1;
|
|
524
|
+
row.sentStatus = previous.sentStatus ?? 1;
|
|
525
|
+
delete row.errorCode;
|
|
526
|
+
delete row.errorMessage;
|
|
527
|
+
}
|
|
528
|
+
if (fromServer) {
|
|
529
|
+
delete row.errorCode;
|
|
530
|
+
delete row.errorMessage;
|
|
531
|
+
}
|
|
532
|
+
const staleContent = previous && (version(previous) > version(data) || // A replay of the creation event is not a new edit, even after reopening the DB.
|
|
533
|
+
source === "receive" && previous._contentSequence > 0 && version(data) <= version(previous) || fromServer && data._fetchSequence !== void 0 && previous._mutationEpoch === ctx2.epoch && previous._contentSequence > data._fetchSequence && version(data) <= version(previous) || fromServer && data._fetchedAt !== void 0 && previous._mutationAt > data._fetchedAt && version(data) <= version(previous));
|
|
534
|
+
if (staleContent) {
|
|
535
|
+
for (const field of ["message", "massage", "editedTime", "editedAt", "extendedData", "repliedInfo", "fileName", "fileSize", "fileDownloadUrl", "thumbnailDownloadUrl"]) {
|
|
536
|
+
if (field in previous)
|
|
537
|
+
row[field] = previous[field];
|
|
538
|
+
else
|
|
539
|
+
delete row[field];
|
|
540
|
+
}
|
|
541
|
+
row._contentSequence = previous._contentSequence;
|
|
542
|
+
row._mutationEpoch = previous._mutationEpoch;
|
|
543
|
+
}
|
|
544
|
+
if (previous && (source === "receive" && previous._receiptSequence > 0 || fromServer && data._fetchSequence !== void 0 && previous._mutationEpoch === ctx2.epoch && previous._receiptSequence > data._fetchSequence)) {
|
|
545
|
+
row.receiptStatus = previous.receiptStatus;
|
|
546
|
+
row._receiptSequence = previous._receiptSequence;
|
|
547
|
+
}
|
|
548
|
+
if (previous && fromServer && data._fetchSequence !== void 0 && previous._sendEpoch === ctx2.epoch && previous._sendSequence > data._fetchSequence) {
|
|
549
|
+
row.sendState = previous.sendState;
|
|
550
|
+
row.sentStatus = previous.sentStatus;
|
|
551
|
+
row._sendSequence = previous._sendSequence;
|
|
552
|
+
row._sendEpoch = previous._sendEpoch;
|
|
553
|
+
if (previous._deliveryUnconfirmed)
|
|
554
|
+
row._deliveryUnconfirmed = true;
|
|
555
|
+
}
|
|
556
|
+
if (row.sendState !== 0)
|
|
557
|
+
delete row._deliveryUnconfirmed;
|
|
558
|
+
if (row.sendState === 1) {
|
|
559
|
+
delete row.errorCode;
|
|
560
|
+
delete row.errorMessage;
|
|
561
|
+
if (fromServer) {
|
|
562
|
+
delete row.file;
|
|
563
|
+
delete row.thumbnailFile;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
if (previous?.deleted || data.deleted || (globalClear || cleared) && row.timestamp <= Math.max(globalClear?.at || 0, cleared?.at || 0))
|
|
567
|
+
row.deleted = true;
|
|
568
|
+
if (row.deleted) {
|
|
569
|
+
row.message = "";
|
|
570
|
+
row.massage = "";
|
|
571
|
+
delete row.file;
|
|
572
|
+
delete row.thumbnailFile;
|
|
573
|
+
delete row.fileDownloadUrl;
|
|
574
|
+
delete row.thumbnailDownloadUrl;
|
|
575
|
+
}
|
|
576
|
+
if (row.revoked || previous?.revoked || data.revoked) {
|
|
577
|
+
row.revoked = true;
|
|
578
|
+
row.message = "";
|
|
579
|
+
row.massage = "";
|
|
580
|
+
delete row.file;
|
|
581
|
+
delete row.thumbnailFile;
|
|
582
|
+
delete row.fileDownloadUrl;
|
|
583
|
+
delete row.thumbnailDownloadUrl;
|
|
584
|
+
}
|
|
585
|
+
delete row._fetchedAt;
|
|
586
|
+
delete row._fetchSequence;
|
|
587
|
+
await ctx2.db.messages.put(row);
|
|
588
|
+
if (!row.file && !row.thumbnailFile)
|
|
589
|
+
released.add(row.localID);
|
|
590
|
+
else
|
|
591
|
+
released.delete(row.localID);
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
for (const localID of released)
|
|
595
|
+
invalidateMediaPreviews(localID);
|
|
596
|
+
changed(ctx2);
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
async function markSendError(ctx, clientBizId, fallback, error) {
|
|
600
|
+
const unknown = error?.code === INVALID_REPLY_RESPONSE || /timeout|disconnected|reconnect|socket not connected|socket not initialized/i.test(error?.message || String(error));
|
|
601
|
+
await saveMessages(ctx, [{
|
|
602
|
+
clientBizId,
|
|
603
|
+
sendState: unknown ? 0 : 2,
|
|
604
|
+
_deliveryUnconfirmed: unknown,
|
|
605
|
+
sentStatus: unknown ? 0 : 2,
|
|
606
|
+
errorCode: error?.code,
|
|
607
|
+
errorMessage: error?.message || String(error)
|
|
608
|
+
}], fallback, "local");
|
|
609
|
+
}
|
|
610
|
+
async function deleteStoredMessages(ctx, id, type, ids) {
|
|
611
|
+
if (id === void 0 !== (type === void 0))
|
|
612
|
+
throw new Error("Both conversationID and conversationType are required");
|
|
613
|
+
await storageWork(ctx, async (ctx2) => {
|
|
614
|
+
const released = [];
|
|
615
|
+
const key = id !== void 0 && type !== void 0 ? conversationKey(id, type) : void 0;
|
|
616
|
+
await ctx2.db.transaction("rw", ctx2.db.messages, ctx2.db.meta, async () => {
|
|
617
|
+
const rows = key ? await ctx2.db.messages.where("[conversationKey+timestamp]").between([key, import_dexie.default.minKey], [key, import_dexie.default.maxKey]).toArray() : await ctx2.db.messages.toArray();
|
|
618
|
+
const selected = ids ? rows.filter((row) => ids.includes(row.messageID || "") || ids.includes(row.localID)) : rows;
|
|
619
|
+
for (const row of selected) {
|
|
620
|
+
const removed = { ...row, deleted: true, message: "", massage: "", updatedAt: Date.now() };
|
|
621
|
+
delete removed.file;
|
|
622
|
+
delete removed.thumbnailFile;
|
|
623
|
+
delete removed.fileDownloadUrl;
|
|
624
|
+
delete removed.thumbnailDownloadUrl;
|
|
625
|
+
await ctx2.db.messages.put(removed);
|
|
626
|
+
released.push(row.localID);
|
|
627
|
+
}
|
|
628
|
+
if (!ids)
|
|
629
|
+
await ctx2.db.meta.put({ key: key ? `clear:${key}` : "clear:all", at: Date.now() });
|
|
630
|
+
if (ids && key)
|
|
631
|
+
for (const messageID of ids) {
|
|
632
|
+
if (!selected.some((row) => row.messageID === messageID))
|
|
633
|
+
await ctx2.db.messages.put({ localID: newLocalID(), conversationID: String(id), conversationType: String(type), conversationKey: key, messageID, hasServerID: 1, type: 0, timestamp: 0, sendState: 1, sentStatus: 1, deleted: true, updatedAt: Date.now() });
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
for (const localID of released)
|
|
637
|
+
invalidateMediaPreviews(localID);
|
|
638
|
+
changed(ctx2, key);
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
async function queryStoredMessages(query, failedOnly = false) {
|
|
642
|
+
const ctx = active;
|
|
643
|
+
if (!ctx)
|
|
644
|
+
throw new Error("Local message storage is not enabled; login with userId first");
|
|
645
|
+
await ctx.ready;
|
|
646
|
+
await ctx.pending;
|
|
647
|
+
if (!isCurrentStorage(ctx))
|
|
648
|
+
throw new Error("Local storage account changed");
|
|
649
|
+
const count = Math.min(500, Math.max(1, Math.floor(query.count || 30)));
|
|
650
|
+
const key = query.conversationID !== void 0 && query.conversationType !== void 0 ? conversationKey(query.conversationID, query.conversationType) : void 0;
|
|
651
|
+
let collection = key ? ctx.db.messages.where("[conversationKey+timestamp]").between([key, import_dexie.default.minKey], [key, import_dexie.default.maxKey]) : ctx.db.messages.orderBy("timestamp");
|
|
652
|
+
if (query.order !== "asc")
|
|
653
|
+
collection = collection.reverse();
|
|
654
|
+
const rows = await collection.filter((row) => {
|
|
655
|
+
if (row.deleted)
|
|
656
|
+
return false;
|
|
657
|
+
if (failedOnly && row.sendState !== 2 && !(row.sendState === 0 && row._deliveryUnconfirmed))
|
|
658
|
+
return false;
|
|
659
|
+
if (query.conversationID !== void 0 && row.conversationID !== String(query.conversationID))
|
|
660
|
+
return false;
|
|
661
|
+
if (query.conversationType !== void 0 && row.conversationType !== String(query.conversationType))
|
|
662
|
+
return false;
|
|
663
|
+
if (query.sendStates?.length && !query.sendStates.includes(row.sendState))
|
|
664
|
+
return false;
|
|
665
|
+
if (query.startTime !== void 0 && row.timestamp < query.startTime)
|
|
666
|
+
return false;
|
|
667
|
+
if (query.endTime !== void 0 && row.timestamp > query.endTime)
|
|
668
|
+
return false;
|
|
669
|
+
if (query.messageTypes?.length && !query.messageTypes.some((type) => String(type) === String(row.type)))
|
|
670
|
+
return false;
|
|
671
|
+
if (query.senderUserIDs?.length && !query.senderUserIDs.includes(row.senderUserID))
|
|
672
|
+
return false;
|
|
673
|
+
if (query.keywords?.some((word) => !String(row.message ?? row.massage ?? "").toLocaleLowerCase().includes(word.toLocaleLowerCase())))
|
|
674
|
+
return false;
|
|
675
|
+
if (query.before) {
|
|
676
|
+
const cmp = row.timestamp - query.before.timestamp || (row.localID < query.before.localID ? -1 : row.localID > query.before.localID ? 1 : 0);
|
|
677
|
+
if (query.order === "asc" ? cmp <= 0 : cmp >= 0)
|
|
678
|
+
return false;
|
|
679
|
+
}
|
|
680
|
+
return true;
|
|
681
|
+
}).limit(count + 1).toArray();
|
|
682
|
+
rows.sort((a, b) => (query.order === "asc" ? 1 : -1) * (a.timestamp - b.timestamp || (a.localID < b.localID ? -1 : a.localID > b.localID ? 1 : 0)));
|
|
683
|
+
if (!isCurrentStorage(ctx))
|
|
684
|
+
throw new Error("Local storage account changed");
|
|
685
|
+
const messageList = rows.slice(0, count);
|
|
686
|
+
const last = messageList[messageList.length - 1];
|
|
687
|
+
return { messageList, hasMore: rows.length > count, nextCursor: last ? { timestamp: last.timestamp, localID: last.localID } : void 0 };
|
|
688
|
+
}
|
|
689
|
+
function queryLocalMessages(query = {}) {
|
|
690
|
+
return queryStoredMessages(query);
|
|
691
|
+
}
|
|
692
|
+
function queryFailedMessages(query = {}) {
|
|
693
|
+
return queryStoredMessages({ ...query, sendStates: void 0 }, true);
|
|
694
|
+
}
|
|
695
|
+
async function clearLocalMessages(query = {}) {
|
|
696
|
+
if (!active)
|
|
697
|
+
throw new Error("Local message storage is not enabled");
|
|
698
|
+
await deleteStoredMessages(active, query.conversationID, query.conversationType);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// src/sdk/sessionGuard.ts
|
|
702
|
+
var generation2 = 0;
|
|
703
|
+
var authenticating = false;
|
|
704
|
+
var listeners2 = /* @__PURE__ */ new Set();
|
|
705
|
+
var authenticationWaiters = /* @__PURE__ */ new Set();
|
|
706
|
+
function releaseAuthenticationWaiters() {
|
|
707
|
+
for (const resolve of authenticationWaiters)
|
|
708
|
+
resolve();
|
|
709
|
+
authenticationWaiters.clear();
|
|
710
|
+
}
|
|
711
|
+
var captureSession = () => generation2;
|
|
712
|
+
var isCurrentSession = (value) => value === generation2;
|
|
713
|
+
var isAuthenticating = () => authenticating;
|
|
714
|
+
function invalidateSession() {
|
|
715
|
+
generation2++;
|
|
716
|
+
authenticating = false;
|
|
717
|
+
releaseAuthenticationWaiters();
|
|
718
|
+
for (const listener of listeners2)
|
|
719
|
+
listener();
|
|
720
|
+
return generation2;
|
|
721
|
+
}
|
|
722
|
+
function beginAuthentication() {
|
|
723
|
+
authenticating = true;
|
|
724
|
+
return generation2;
|
|
725
|
+
}
|
|
726
|
+
function finishAuthentication(value) {
|
|
727
|
+
if (isCurrentSession(value)) {
|
|
728
|
+
authenticating = false;
|
|
729
|
+
releaseAuthenticationWaiters();
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
async function waitForAuthentication(value) {
|
|
733
|
+
if (authenticating && isCurrentSession(value))
|
|
734
|
+
await new Promise((resolve) => authenticationWaiters.add(resolve));
|
|
735
|
+
assertCurrentSession(value);
|
|
736
|
+
}
|
|
737
|
+
function onSessionInvalidated(listener) {
|
|
738
|
+
listeners2.add(listener);
|
|
739
|
+
return () => {
|
|
740
|
+
listeners2.delete(listener);
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
function assertCurrentSession(value) {
|
|
744
|
+
if (!isCurrentSession(value))
|
|
745
|
+
throw new Error("SDK session changed; operation canceled");
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// src/sdk/storage/bridge.ts
|
|
749
|
+
function extractMessages(data) {
|
|
750
|
+
if (!data)
|
|
751
|
+
return [];
|
|
752
|
+
if (Array.isArray(data))
|
|
753
|
+
return data.flatMap((item) => extractMessages(item));
|
|
754
|
+
if (typeof data !== "object")
|
|
755
|
+
return [];
|
|
756
|
+
if (Array.isArray(data.messageList))
|
|
757
|
+
return data.messageList;
|
|
758
|
+
if (Array.isArray(data.infos))
|
|
759
|
+
return data.infos.flatMap((info) => extractMessages(info));
|
|
760
|
+
if (data.message && typeof data.message === "object")
|
|
761
|
+
return [data.message];
|
|
762
|
+
if (data.messageID || data.clientBizId)
|
|
763
|
+
return [data];
|
|
764
|
+
return [];
|
|
765
|
+
}
|
|
766
|
+
function makeClientBizId() {
|
|
767
|
+
return `cbiz_${newLocalID()}`;
|
|
768
|
+
}
|
|
769
|
+
function outgoingFallback(payload, ctx) {
|
|
770
|
+
return {
|
|
771
|
+
conversationID: payload.toConversationID ?? payload.conversationID ?? payload.toOriginalMessage?.conversationID ?? payload.message?.conversationID,
|
|
772
|
+
conversationType: payload.conversationType ?? payload.toOriginalMessage?.conversationType ?? payload.message?.conversationType,
|
|
773
|
+
senderUserID: ctx?.userId,
|
|
774
|
+
direction: 0
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
async function persistOutgoing(ctx, payload) {
|
|
778
|
+
await saveMessages(ctx, [{ ...payload.message, sendState: 0, sentStatus: 0, _deliveryUnconfirmed: false }], outgoingFallback(payload, ctx), "local");
|
|
779
|
+
}
|
|
780
|
+
async function cacheApiResult(ctx, method, payload, data, startedAt = Date.now(), fetchSequence = ctx?.mutationSequence || 0) {
|
|
781
|
+
const fallback = { ...outgoingFallback(payload || {}, ctx), _fetchedAt: startedAt, _fetchSequence: fetchSequence };
|
|
782
|
+
if (!/^(sendMessage|sendMediaMessage|replyMessage)$/.test(method)) {
|
|
783
|
+
delete fallback.senderUserID;
|
|
784
|
+
delete fallback.direction;
|
|
785
|
+
}
|
|
786
|
+
if (/^(sendMessage|sendMediaMessage|replyMessage)$/.test(method)) {
|
|
787
|
+
const confirmation = { _sendSequence: nextMutation(ctx), _sendEpoch: ctx?.epoch };
|
|
788
|
+
const messages = extractMessages(data).map((row) => {
|
|
789
|
+
const sendState = messageSendState(row);
|
|
790
|
+
const normalized = { ...row, ...confirmation, sentStatus: row.sentStatus ?? sendState, sendState, clientBizId: row.clientBizId || payload.message?.clientBizId };
|
|
791
|
+
return normalized;
|
|
792
|
+
});
|
|
793
|
+
await saveMessages(ctx, messages.length ? messages : [{ ...payload.message, ...confirmation, sentStatus: 1, sendState: 1 }], fallback);
|
|
794
|
+
} else if (/^(queryHistoryMessage|queryMessages|queryMessageRepliedList|queryCombineMessageDetail|editMessage)$/.test(method)) {
|
|
795
|
+
await saveMessages(ctx, extractMessages(data).map((row) => ({
|
|
796
|
+
...row,
|
|
797
|
+
_sendSequence: fetchSequence,
|
|
798
|
+
_sendEpoch: ctx?.epoch,
|
|
799
|
+
...method === "editMessage" ? { _mutationAt: Date.now(), _contentSequence: nextMutation(ctx), _mutationEpoch: ctx?.epoch } : {}
|
|
800
|
+
})), { ...fallback, conversationID: data?.conversationID ?? fallback.conversationID, conversationType: data?.conversationType ?? fallback.conversationType });
|
|
801
|
+
} else if (method === "queryMessageReceiptsInfo") {
|
|
802
|
+
for (const row of extractMessages(data))
|
|
803
|
+
await applyMessagePatch(ctx, row, fallback);
|
|
804
|
+
} else if (method === "sendMessageReceiptsRead") {
|
|
805
|
+
for (const messageID of payload.messageList || [])
|
|
806
|
+
await applyMessagePatch(ctx, { messageID, locallyRead: true }, fallback);
|
|
807
|
+
} else if (method === "deleteMessages") {
|
|
808
|
+
await deleteStoredMessages(ctx, payload.conversationID, payload.conversationType, payload.messageList?.map((m) => m.messageID));
|
|
809
|
+
} else if (method === "deleteAllMessage") {
|
|
810
|
+
await deleteStoredMessages(ctx, payload.conversationID, payload.conversationType);
|
|
811
|
+
} else if (method === "deleteAllConversationMessages") {
|
|
812
|
+
await deleteStoredMessages(ctx);
|
|
813
|
+
} else if (method === "revokeMessage") {
|
|
814
|
+
await applyMessagePatch(ctx, { ...payload.message, revoked: true }, {});
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
function nextMutation(ctx) {
|
|
818
|
+
if (!ctx)
|
|
819
|
+
return 0;
|
|
820
|
+
return ctx.mutationSequence = (ctx.mutationSequence || 0) + 1;
|
|
821
|
+
}
|
|
822
|
+
function mergeDeferred(previous = {}, patch) {
|
|
823
|
+
const merged = { ...previous, ...patch };
|
|
824
|
+
if (previous.revoked || patch.revoked)
|
|
825
|
+
merged.revoked = true;
|
|
826
|
+
if (previous.deleted || patch.deleted)
|
|
827
|
+
merged.deleted = true;
|
|
828
|
+
const oldVersion = Number(previous.editedTime || previous.editedAt || 0);
|
|
829
|
+
const newVersion = Number(patch.editedTime || patch.editedAt || 0);
|
|
830
|
+
if (oldVersion > newVersion && newVersion > 0) {
|
|
831
|
+
for (const field of ["message", "massage", "editedTime", "editedAt", "extendedData"]) {
|
|
832
|
+
if (field in previous)
|
|
833
|
+
merged[field] = previous[field];
|
|
834
|
+
else
|
|
835
|
+
delete merged[field];
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
return merged;
|
|
839
|
+
}
|
|
840
|
+
async function applyMessagePatch(ctx, patch, fallback) {
|
|
841
|
+
if (!patch?.messageID && !patch?.clientBizId)
|
|
842
|
+
return;
|
|
843
|
+
patch = { ...patch, _mutationAt: Date.now(), _mutationEpoch: ctx?.epoch };
|
|
844
|
+
const sequence2 = nextMutation(ctx);
|
|
845
|
+
if ("message" in patch || "massage" in patch || "editedTime" in patch || "extendedData" in patch)
|
|
846
|
+
patch._contentSequence = sequence2;
|
|
847
|
+
if ("receiptStatus" in patch)
|
|
848
|
+
patch._receiptSequence = sequence2;
|
|
849
|
+
if ("sentStatus" in patch || "sendState" in patch) {
|
|
850
|
+
patch._sendSequence = sequence2;
|
|
851
|
+
patch._sendEpoch = ctx?.epoch;
|
|
852
|
+
}
|
|
853
|
+
if ((patch.conversationID ?? fallback.conversationID) !== void 0 && (patch.conversationType ?? fallback.conversationType) !== void 0) {
|
|
854
|
+
await saveMessages(ctx, [{ ...patch, _mutationAt: Date.now() }], fallback, "patch");
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
await storageWork(ctx, async (ctx2) => {
|
|
858
|
+
const rows = await ctx2.db.messages.filter((row) => patch.messageID ? row.messageID === String(patch.messageID) : row.clientBizId === String(patch.clientBizId)).toArray();
|
|
859
|
+
if (!rows.length && patch.messageID) {
|
|
860
|
+
await ctx2.db.transaction("rw", ctx2.db.meta, async () => {
|
|
861
|
+
const key = `patch:${String(patch.messageID)}`;
|
|
862
|
+
const prior = await ctx2.db.meta.get(key);
|
|
863
|
+
await ctx2.db.meta.put({ key, patch: mergeDeferred(prior?.patch, patch) });
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
for (const row of rows)
|
|
867
|
+
await saveMessages(ctx2, [patch], { conversationID: row.conversationID, conversationType: row.conversationType }, "patch");
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
var PERSISTED_PUSH_EVENTS = /* @__PURE__ */ new Set(["receivePeerMessage", "receiveGroupMessage", "messageSentStatusChanged", "messageDeleted", "messageRevokeReceived", "messageEdited", "messageReceiptChanged"]);
|
|
871
|
+
var loginBuffer;
|
|
872
|
+
onSessionInvalidated(() => {
|
|
873
|
+
loginBuffer = void 0;
|
|
874
|
+
});
|
|
875
|
+
function beginLoginMessageBuffer(session) {
|
|
876
|
+
loginBuffer = { session, events: [] };
|
|
877
|
+
}
|
|
878
|
+
function discardLoginMessageBuffer(session) {
|
|
879
|
+
if (loginBuffer?.session === session)
|
|
880
|
+
loginBuffer = void 0;
|
|
881
|
+
}
|
|
882
|
+
async function flushLoginMessageBuffer(session) {
|
|
883
|
+
const buffer = loginBuffer;
|
|
884
|
+
if (buffer?.session !== session || !isCurrentSession(session))
|
|
885
|
+
return;
|
|
886
|
+
loginBuffer = void 0;
|
|
887
|
+
for (const { event, args } of buffer.events)
|
|
888
|
+
observeMessagePush(event, args);
|
|
889
|
+
await captureStorage()?.pending;
|
|
890
|
+
}
|
|
891
|
+
function snapshotPushData(value) {
|
|
892
|
+
if (typeof structuredClone === "function") {
|
|
893
|
+
try {
|
|
894
|
+
return structuredClone(value);
|
|
895
|
+
} catch {
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
if (Array.isArray(value))
|
|
899
|
+
return value.map(snapshotPushData);
|
|
900
|
+
if (value && Object.prototype.toString.call(value) === "[object Object]") {
|
|
901
|
+
return Object.fromEntries(Object.entries(value).filter(([, item]) => typeof item !== "function").map(([key, item]) => [key, snapshotPushData(item)]));
|
|
902
|
+
}
|
|
903
|
+
if (ArrayBuffer.isView(value)) {
|
|
904
|
+
const bytes = value.buffer.slice(value.byteOffset, value.byteOffset + value.byteLength);
|
|
905
|
+
return new value.constructor(bytes);
|
|
906
|
+
}
|
|
907
|
+
if (Object.prototype.toString.call(value) === "[object ArrayBuffer]")
|
|
908
|
+
return value.slice(0);
|
|
909
|
+
if (Object.prototype.toString.call(value) === "[object Date]")
|
|
910
|
+
return new Date(value.getTime());
|
|
911
|
+
return value;
|
|
912
|
+
}
|
|
913
|
+
function observeMessagePush(event, args) {
|
|
914
|
+
if (!PERSISTED_PUSH_EVENTS.has(event))
|
|
915
|
+
return;
|
|
916
|
+
if (loginBuffer && isCurrentSession(loginBuffer.session)) {
|
|
917
|
+
loginBuffer.events.push({ event, args: snapshotPushData(args.filter((arg) => typeof arg !== "function")) });
|
|
918
|
+
return;
|
|
919
|
+
}
|
|
920
|
+
const filtered = filterReplyPushArgs(event, args);
|
|
921
|
+
if (!filtered)
|
|
922
|
+
return;
|
|
923
|
+
args = filtered;
|
|
924
|
+
const ctx = captureStorage();
|
|
925
|
+
if (!ctx)
|
|
926
|
+
return;
|
|
927
|
+
const received = event === "receivePeerMessage" || event === "receiveGroupMessage";
|
|
928
|
+
const payload = args.find((arg) => arg && typeof arg === "object" && !Array.isArray(arg) && (arg.messageList || arg.message || arg.infos || arg.conversationID || arg.fromConversationID)) || args[0];
|
|
929
|
+
const data = snapshotPushData(payload);
|
|
930
|
+
const run = async () => {
|
|
931
|
+
const fallback = {
|
|
932
|
+
_fetchedAt: Date.now(),
|
|
933
|
+
_fetchSequence: ctx.mutationSequence || 0,
|
|
934
|
+
conversationID: data?.conversationID ?? data?.fromConversationID,
|
|
935
|
+
conversationType: data?.conversationType ?? (event === "receivePeerMessage" ? 0 : event === "receiveGroupMessage" ? 2 : void 0)
|
|
936
|
+
};
|
|
937
|
+
if (event === "messageDeleted") {
|
|
938
|
+
if (data?.isDeleteConversationAllMessage && fallback.conversationID !== void 0 && fallback.conversationType === void 0) {
|
|
939
|
+
for (const type of [0, 1, 2, 3])
|
|
940
|
+
await deleteStoredMessages(ctx, fallback.conversationID, type);
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
if (fallback.conversationID === void 0 || fallback.conversationType === void 0) {
|
|
944
|
+
for (const message of extractMessages(data))
|
|
945
|
+
await applyMessagePatch(ctx, { ...message, deleted: true }, fallback);
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
await deleteStoredMessages(
|
|
949
|
+
ctx,
|
|
950
|
+
fallback.conversationID,
|
|
951
|
+
fallback.conversationType,
|
|
952
|
+
data?.isDeleteConversationAllMessage ? void 0 : (data?.messageList || []).map((row) => row.messageID)
|
|
953
|
+
);
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
const messages = extractMessages(data);
|
|
957
|
+
if (received) {
|
|
958
|
+
await saveMessages(ctx, messages.filter((message) => message && typeof message === "object" && (message.messageID || message.clientBizId)).map((message) => ({
|
|
959
|
+
...message,
|
|
960
|
+
sentStatus: message.sentStatus ?? messageSendState(message),
|
|
961
|
+
sendState: messageSendState(message),
|
|
962
|
+
_sendSequence: nextMutation(ctx),
|
|
963
|
+
_sendEpoch: ctx.epoch
|
|
964
|
+
})), fallback, "receive");
|
|
965
|
+
} else {
|
|
966
|
+
for (const message of messages) {
|
|
967
|
+
const patch = { ...message };
|
|
968
|
+
if (event === "messageRevokeReceived")
|
|
969
|
+
patch.revoked = true;
|
|
970
|
+
if (event === "messageSentStatusChanged") {
|
|
971
|
+
const info = data?.infos?.find((item) => item.message?.messageID === message.messageID);
|
|
972
|
+
const status = info?.status ?? message.sentStatus;
|
|
973
|
+
if (status !== void 0) {
|
|
974
|
+
patch.sentStatus = status;
|
|
975
|
+
patch.sendState = Number(status) === 1 ? 1 : Number(status) === 2 ? 2 : 0;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
await applyMessagePatch(ctx, patch, fallback);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
};
|
|
982
|
+
ctx.pending = (ctx.pending || Promise.resolve()).then(run).catch((error) => {
|
|
983
|
+
console.error("[VanshiSdk] message persistence failed", error);
|
|
984
|
+
});
|
|
985
|
+
}
|
|
60
986
|
|
|
61
987
|
// src/sdk/runtime.ts
|
|
62
988
|
var SDK_TOKEN_KEY = "VanshiSdk_Token";
|
|
63
989
|
var SDK_LOGIN_KEY = "VanshiSdk_isLogin";
|
|
990
|
+
var inMemorySdkToken = "";
|
|
991
|
+
var sessionTokenInitialized = false;
|
|
992
|
+
var inMemorySdkUserID = "";
|
|
993
|
+
function setSdkUserID(userID) {
|
|
994
|
+
inMemorySdkUserID = userID == null ? "" : String(userID).trim();
|
|
995
|
+
}
|
|
996
|
+
function getSdkUserID() {
|
|
997
|
+
return inMemorySdkUserID;
|
|
998
|
+
}
|
|
64
999
|
function getBrowserStorage() {
|
|
65
|
-
|
|
1000
|
+
try {
|
|
1001
|
+
if (typeof localStorage === "undefined") {
|
|
1002
|
+
return void 0;
|
|
1003
|
+
}
|
|
1004
|
+
return localStorage;
|
|
1005
|
+
} catch {
|
|
66
1006
|
return void 0;
|
|
67
1007
|
}
|
|
68
|
-
|
|
1008
|
+
}
|
|
1009
|
+
function getSdkErrorMessage(result) {
|
|
1010
|
+
return result.message || `SDK request failed${result.code !== void 0 ? `: ${String(result.code)}` : ""}`;
|
|
69
1011
|
}
|
|
70
1012
|
var SdkRuntimeError = class extends Error {
|
|
71
1013
|
constructor(result) {
|
|
72
|
-
super(
|
|
1014
|
+
super(getSdkErrorMessage(result));
|
|
73
1015
|
this.name = "SdkRuntimeError";
|
|
1016
|
+
this.success = false;
|
|
74
1017
|
this.code = result.code;
|
|
75
1018
|
this.data = result.data;
|
|
76
1019
|
this.raw = result.raw;
|
|
77
|
-
this
|
|
1020
|
+
Object.defineProperties(this, {
|
|
1021
|
+
name: { value: this.name, enumerable: true },
|
|
1022
|
+
message: { value: this.message, enumerable: true },
|
|
1023
|
+
success: { value: this.success, enumerable: true },
|
|
1024
|
+
code: { value: this.code, enumerable: true },
|
|
1025
|
+
data: { value: this.data, enumerable: true },
|
|
1026
|
+
raw: { value: this.raw, enumerable: true }
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
toObject() {
|
|
1030
|
+
return {
|
|
1031
|
+
name: "SdkRuntimeError",
|
|
1032
|
+
success: false,
|
|
1033
|
+
code: this.code,
|
|
1034
|
+
message: this.message,
|
|
1035
|
+
data: this.data,
|
|
1036
|
+
raw: this.raw
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
toJSON() {
|
|
1040
|
+
return this.toObject();
|
|
78
1041
|
}
|
|
79
1042
|
};
|
|
80
|
-
function
|
|
81
|
-
|
|
82
|
-
|
|
1043
|
+
function isRecord(value) {
|
|
1044
|
+
return Boolean(value) && typeof value === "object";
|
|
1045
|
+
}
|
|
1046
|
+
function getErrorField(error, field) {
|
|
1047
|
+
return isRecord(error) ? error[field] : void 0;
|
|
1048
|
+
}
|
|
1049
|
+
function getSdkErrorCode(error) {
|
|
1050
|
+
const code = getErrorField(error, "code");
|
|
1051
|
+
return typeof code === "string" || typeof code === "number" ? code : void 0;
|
|
1052
|
+
}
|
|
1053
|
+
function getSdkErrorMessageFromUnknown(error, fallback = "SDK request failed") {
|
|
1054
|
+
const message = getErrorField(error, "message");
|
|
1055
|
+
if (typeof message === "string" && message) {
|
|
1056
|
+
return message;
|
|
83
1057
|
}
|
|
84
|
-
if (
|
|
85
|
-
return
|
|
1058
|
+
if (error instanceof Error && error.message) {
|
|
1059
|
+
return error.message;
|
|
86
1060
|
}
|
|
87
|
-
|
|
88
|
-
return
|
|
89
|
-
} catch {
|
|
90
|
-
return void 0;
|
|
1061
|
+
if (typeof error === "string" && error) {
|
|
1062
|
+
return error;
|
|
91
1063
|
}
|
|
1064
|
+
return fallback;
|
|
92
1065
|
}
|
|
93
|
-
function
|
|
94
|
-
return
|
|
1066
|
+
function isSdkRuntimeErrorObject(value) {
|
|
1067
|
+
return isRecord(value) && value.name === "SdkRuntimeError" && value.success === false && typeof value.message === "string";
|
|
95
1068
|
}
|
|
96
|
-
function
|
|
97
|
-
|
|
98
|
-
|
|
1069
|
+
function isAuthFailureCode(code) {
|
|
1070
|
+
return code === 3 || code === "3" || code === 4 || code === "4" || code === 303 || code === "303";
|
|
1071
|
+
}
|
|
1072
|
+
function hasSdkCode(value) {
|
|
1073
|
+
return isRecord(value) && "code" in value;
|
|
1074
|
+
}
|
|
1075
|
+
function logSdkRuntimeError(result) {
|
|
1076
|
+
if (typeof console === "undefined" || typeof console.error !== "function") {
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
console.error("[VanshiSdk] API request failed", {
|
|
1080
|
+
code: result.code,
|
|
1081
|
+
message: result.message,
|
|
1082
|
+
data: result.data,
|
|
1083
|
+
raw: result.raw
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
function throwSdkRuntimeError(result) {
|
|
1087
|
+
const detailedResult = {
|
|
1088
|
+
...result,
|
|
1089
|
+
success: false
|
|
1090
|
+
};
|
|
1091
|
+
logSdkRuntimeError(detailedResult);
|
|
1092
|
+
if (isAuthFailureCode(detailedResult.code)) {
|
|
1093
|
+
clearSdkSession();
|
|
99
1094
|
}
|
|
100
|
-
|
|
1095
|
+
throw new SdkRuntimeError(detailedResult).toObject();
|
|
1096
|
+
}
|
|
1097
|
+
function throwSdkTransportError(error, fallbackMessage = "SDK request failed") {
|
|
1098
|
+
if (isSdkRuntimeErrorObject(error)) {
|
|
1099
|
+
throw error;
|
|
1100
|
+
}
|
|
1101
|
+
throwSdkRuntimeError({
|
|
1102
|
+
code: getSdkErrorCode(error),
|
|
1103
|
+
message: getSdkErrorMessageFromUnknown(error, fallbackMessage),
|
|
1104
|
+
raw: error
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
function isSuccessCode(code) {
|
|
1108
|
+
return code === 0 || code === "0" || code === true;
|
|
101
1109
|
}
|
|
102
1110
|
function unwrapSdkData(response) {
|
|
1111
|
+
const result = assertSdkSuccess(response);
|
|
1112
|
+
return result.data;
|
|
1113
|
+
}
|
|
1114
|
+
function assertSdkSuccess(response) {
|
|
103
1115
|
const result = unwrapSdkDetailedData(response);
|
|
104
1116
|
if (!result.success) {
|
|
105
|
-
|
|
1117
|
+
throwSdkRuntimeError(result);
|
|
106
1118
|
}
|
|
107
|
-
return result
|
|
1119
|
+
return result;
|
|
108
1120
|
}
|
|
109
1121
|
function unwrapSdkResponse(response) {
|
|
1122
|
+
const result = assertSdkSuccess(response);
|
|
110
1123
|
const envelope = toSdkEnvelope(response);
|
|
111
|
-
const parsed = parseJsonSafely(envelope.data);
|
|
112
|
-
if (parsed && typeof parsed === "object" && "code" in parsed) {
|
|
113
|
-
return parsed;
|
|
114
|
-
}
|
|
115
1124
|
return {
|
|
116
1125
|
code: envelope.code,
|
|
117
1126
|
message: envelope.message,
|
|
118
|
-
data:
|
|
1127
|
+
data: result.data
|
|
119
1128
|
};
|
|
120
1129
|
}
|
|
121
1130
|
function unwrapSdkDetailedData(response) {
|
|
122
1131
|
const envelope = toSdkEnvelope(response);
|
|
123
|
-
const parsed = parseJsonSafely(envelope.data);
|
|
124
|
-
if (parsed && typeof parsed === "object" && "code" in parsed) {
|
|
125
|
-
const success = isSuccessCode(parsed.code);
|
|
126
|
-
return {
|
|
127
|
-
success,
|
|
128
|
-
code: parsed.code,
|
|
129
|
-
message: parsed.message || envelope.message,
|
|
130
|
-
data: parsed.data,
|
|
131
|
-
raw: response,
|
|
132
|
-
parsed
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
1132
|
if (envelope.code !== void 0 || envelope.message !== void 0) {
|
|
136
1133
|
return {
|
|
137
1134
|
success: isSuccessCode(envelope.code),
|
|
138
1135
|
code: envelope.code,
|
|
139
1136
|
message: envelope.message,
|
|
140
|
-
data:
|
|
141
|
-
raw: response
|
|
142
|
-
parsed
|
|
1137
|
+
data: envelope.data,
|
|
1138
|
+
raw: response
|
|
143
1139
|
};
|
|
144
1140
|
}
|
|
145
1141
|
return {
|
|
146
1142
|
success: true,
|
|
147
|
-
data:
|
|
148
|
-
raw: response
|
|
149
|
-
parsed
|
|
1143
|
+
data: envelope.data,
|
|
1144
|
+
raw: response
|
|
150
1145
|
};
|
|
151
1146
|
}
|
|
1147
|
+
function toSdkEnvelope(response) {
|
|
1148
|
+
return isRecord(response) ? response : {};
|
|
1149
|
+
}
|
|
152
1150
|
function getStoredToken() {
|
|
153
|
-
|
|
1151
|
+
const memoryToken = inMemorySdkToken;
|
|
1152
|
+
try {
|
|
1153
|
+
return sessionTokenInitialized ? memoryToken : getBrowserStorage()?.getItem(SDK_TOKEN_KEY) || "";
|
|
1154
|
+
} catch {
|
|
1155
|
+
return memoryToken;
|
|
1156
|
+
}
|
|
154
1157
|
}
|
|
155
1158
|
function setSdkSession(token) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
1159
|
+
inMemorySdkToken = token;
|
|
1160
|
+
sessionTokenInitialized = true;
|
|
1161
|
+
try {
|
|
1162
|
+
const storage = getBrowserStorage();
|
|
1163
|
+
if (!storage) {
|
|
1164
|
+
return;
|
|
1165
|
+
}
|
|
1166
|
+
storage.setItem(SDK_TOKEN_KEY, token);
|
|
1167
|
+
storage.setItem(SDK_LOGIN_KEY, "true");
|
|
1168
|
+
} catch {
|
|
159
1169
|
}
|
|
160
|
-
storage.setItem(SDK_TOKEN_KEY, token);
|
|
161
|
-
storage.setItem(SDK_LOGIN_KEY, "true");
|
|
162
1170
|
}
|
|
163
1171
|
function clearSdkSession() {
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
1172
|
+
const ownedToken = inMemorySdkToken;
|
|
1173
|
+
const hadOwnedSession = sessionTokenInitialized;
|
|
1174
|
+
sessionTokenInitialized = true;
|
|
1175
|
+
invalidateSession();
|
|
1176
|
+
closeLocalStorage();
|
|
1177
|
+
inMemorySdkToken = "";
|
|
1178
|
+
inMemorySdkUserID = "";
|
|
1179
|
+
try {
|
|
1180
|
+
const storage = getBrowserStorage();
|
|
1181
|
+
if (!storage) {
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
if (!hadOwnedSession || ownedToken && storage.getItem(SDK_TOKEN_KEY) === ownedToken) {
|
|
1185
|
+
storage.removeItem(SDK_TOKEN_KEY);
|
|
1186
|
+
storage.removeItem(SDK_LOGIN_KEY);
|
|
1187
|
+
}
|
|
1188
|
+
} catch {
|
|
167
1189
|
}
|
|
168
|
-
storage.removeItem(SDK_TOKEN_KEY);
|
|
169
|
-
storage.removeItem(SDK_LOGIN_KEY);
|
|
170
1190
|
}
|
|
171
1191
|
function getSocketUrl() {
|
|
172
1192
|
const globalUrl = typeof window !== "undefined" ? window.__VANSHI_SOCKET_URL : void 0;
|
|
173
|
-
return globalUrl || "wss://ws-
|
|
1193
|
+
return globalUrl || "wss://ws-baobaoshibu.bnrfdv.com";
|
|
174
1194
|
}
|
|
175
1195
|
function getUploadUrl() {
|
|
176
1196
|
const globalHttpUrl = typeof window !== "undefined" ? window.__VANSHI_HTTP_URL : void 0;
|
|
177
|
-
return globalHttpUrl || "https://
|
|
1197
|
+
return globalHttpUrl || "https://baobaoshibu.bnrfdv.com/api/files/sdkUpload";
|
|
178
1198
|
}
|
|
179
1199
|
|
|
1200
|
+
// src/plugins/socketio/client.ts
|
|
1201
|
+
var import_socket = __toESM(require("socket.io-client"), 1);
|
|
1202
|
+
|
|
180
1203
|
// src/sdk/session.ts
|
|
181
1204
|
var reconnectLoginHandler = null;
|
|
182
1205
|
function registerReconnectLoginHandler(handler) {
|
|
183
1206
|
reconnectLoginHandler = handler;
|
|
184
1207
|
}
|
|
185
1208
|
async function restoreSessionAfterReconnect() {
|
|
1209
|
+
const session = captureSession();
|
|
186
1210
|
if (!reconnectLoginHandler) {
|
|
187
1211
|
return false;
|
|
188
1212
|
}
|
|
@@ -191,7 +1215,8 @@ async function restoreSessionAfterReconnect() {
|
|
|
191
1215
|
return false;
|
|
192
1216
|
}
|
|
193
1217
|
try {
|
|
194
|
-
|
|
1218
|
+
const success = await reconnectLoginHandler(token);
|
|
1219
|
+
return isCurrentSession(session) && success;
|
|
195
1220
|
} catch {
|
|
196
1221
|
return false;
|
|
197
1222
|
}
|
|
@@ -200,7 +1225,99 @@ function clearSessionState() {
|
|
|
200
1225
|
clearSdkSession();
|
|
201
1226
|
}
|
|
202
1227
|
|
|
1228
|
+
// src/constants/eventListenerOn.ts
|
|
1229
|
+
var ZIMConnectionState = /* @__PURE__ */ ((ZIMConnectionState2) => {
|
|
1230
|
+
ZIMConnectionState2[ZIMConnectionState2["Disconnected"] = 0] = "Disconnected";
|
|
1231
|
+
ZIMConnectionState2[ZIMConnectionState2["Connecting"] = 1] = "Connecting";
|
|
1232
|
+
ZIMConnectionState2[ZIMConnectionState2["Connected"] = 2] = "Connected";
|
|
1233
|
+
ZIMConnectionState2[ZIMConnectionState2["Reconnecting"] = 3] = "Reconnecting";
|
|
1234
|
+
return ZIMConnectionState2;
|
|
1235
|
+
})(ZIMConnectionState || {});
|
|
1236
|
+
var ZIMConnectionEvent = /* @__PURE__ */ ((ZIMConnectionEvent2) => {
|
|
1237
|
+
ZIMConnectionEvent2[ZIMConnectionEvent2["Success"] = 0] = "Success";
|
|
1238
|
+
ZIMConnectionEvent2[ZIMConnectionEvent2["ActiveLogin"] = 1] = "ActiveLogin";
|
|
1239
|
+
ZIMConnectionEvent2[ZIMConnectionEvent2["LoginTimeout"] = 2] = "LoginTimeout";
|
|
1240
|
+
ZIMConnectionEvent2[ZIMConnectionEvent2["LoginInterrupted"] = 3] = "LoginInterrupted";
|
|
1241
|
+
ZIMConnectionEvent2[ZIMConnectionEvent2["KickedOut"] = 4] = "KickedOut";
|
|
1242
|
+
ZIMConnectionEvent2[ZIMConnectionEvent2["TokenExpired"] = 5] = "TokenExpired";
|
|
1243
|
+
return ZIMConnectionEvent2;
|
|
1244
|
+
})(ZIMConnectionEvent || {});
|
|
1245
|
+
var ZIMEventEnum = /* @__PURE__ */ ((ZIMEventEnum2) => {
|
|
1246
|
+
ZIMEventEnum2["connect"] = "connect";
|
|
1247
|
+
ZIMEventEnum2["disconnect"] = "disconnect";
|
|
1248
|
+
ZIMEventEnum2["connectError"] = "connect_error";
|
|
1249
|
+
ZIMEventEnum2["connectionStateChanged"] = "connectionStateChanged";
|
|
1250
|
+
ZIMEventEnum2["reconnect"] = "reconnect";
|
|
1251
|
+
ZIMEventEnum2["reconnectAttempt"] = "reconnect_attempt";
|
|
1252
|
+
ZIMEventEnum2["reconnectError"] = "reconnect_error";
|
|
1253
|
+
ZIMEventEnum2["reconnectFailed"] = "reconnect_failed";
|
|
1254
|
+
ZIMEventEnum2["reconnectLoginSuccess"] = "reconnectLoginSuccess";
|
|
1255
|
+
ZIMEventEnum2["reconnectLoginFailed"] = "reconnectLoginFailed";
|
|
1256
|
+
ZIMEventEnum2["receiveGroupMessage"] = "receiveGroupMessage";
|
|
1257
|
+
ZIMEventEnum2["receivePeerMessage"] = "receivePeerMessage";
|
|
1258
|
+
ZIMEventEnum2["sendSingLing"] = "sendSingLing";
|
|
1259
|
+
ZIMEventEnum2["conversationChanged"] = "conversationChanged";
|
|
1260
|
+
ZIMEventEnum2["messageSentStatusChanged"] = "messageSentStatusChanged";
|
|
1261
|
+
ZIMEventEnum2["messageDeleted"] = "messageDeleted";
|
|
1262
|
+
ZIMEventEnum2["messageRevokeReceived"] = "messageRevokeReceived";
|
|
1263
|
+
ZIMEventEnum2["messageEdited"] = "messageEdited";
|
|
1264
|
+
ZIMEventEnum2["messageReceiptChanged"] = "messageReceiptChanged";
|
|
1265
|
+
ZIMEventEnum2["tokenWillExpire"] = "tokenWillExpire";
|
|
1266
|
+
ZIMEventEnum2["error"] = "error";
|
|
1267
|
+
ZIMEventEnum2["userInfoUpdated"] = "userInfoUpdated";
|
|
1268
|
+
ZIMEventEnum2["userStatusUpdated"] = "userStatusUpdated";
|
|
1269
|
+
ZIMEventEnum2["groupStateChanged"] = "groupStateChanged";
|
|
1270
|
+
ZIMEventEnum2["friendListChanged"] = "friendListChanged";
|
|
1271
|
+
ZIMEventEnum2["blacklistChanged"] = "blacklistChanged";
|
|
1272
|
+
ZIMEventEnum2["callInvitationReceived"] = "callInvitationReceived";
|
|
1273
|
+
ZIMEventEnum2["callAccepted"] = "callAccepted";
|
|
1274
|
+
ZIMEventEnum2["callRejected"] = "callRejected";
|
|
1275
|
+
ZIMEventEnum2["callCanceled"] = "callCanceled";
|
|
1276
|
+
ZIMEventEnum2["callEnded"] = "callEnded";
|
|
1277
|
+
ZIMEventEnum2["callTimeout"] = "callTimeout";
|
|
1278
|
+
ZIMEventEnum2["callParticipantJoined"] = "callParticipantJoined";
|
|
1279
|
+
ZIMEventEnum2["callParticipantLeft"] = "callParticipantLeft";
|
|
1280
|
+
ZIMEventEnum2["callMediaStateChanged"] = "callMediaStateChanged";
|
|
1281
|
+
ZIMEventEnum2["callConnectionStateChanged"] = "callConnectionStateChanged";
|
|
1282
|
+
ZIMEventEnum2["callMediaTrackSubscribed"] = "callMediaTrackSubscribed";
|
|
1283
|
+
ZIMEventEnum2["callMediaTrackUnsubscribed"] = "callMediaTrackUnsubscribed";
|
|
1284
|
+
return ZIMEventEnum2;
|
|
1285
|
+
})(ZIMEventEnum || {});
|
|
1286
|
+
|
|
203
1287
|
// src/plugins/socketio/client.ts
|
|
1288
|
+
var SOCKET_NAMESPACE = "/im/user";
|
|
1289
|
+
var DEFAULT_RECONNECT_DELAY_MS = 1e4;
|
|
1290
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 6e4;
|
|
1291
|
+
var RECONNECT_LOGIN_DELAY_MS = 200;
|
|
1292
|
+
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
1293
|
+
var HEARTBEAT_TIMEOUT_MS = 9e4;
|
|
1294
|
+
var HEARTBEAT_PACKET_PREFIX = "ping:";
|
|
1295
|
+
var MAX_OPERATION_QUEUE_SIZE = 1e3;
|
|
1296
|
+
var CALL_PUSH_EVENT = "push:call";
|
|
1297
|
+
var AUTO_ACK_EVENTS = /* @__PURE__ */ new Set(["conversationChanged", "receivePeerMessage", "receiveGroupMessage"]);
|
|
1298
|
+
var CALL_PUSH_EVENTS = /* @__PURE__ */ new Set([
|
|
1299
|
+
"callInvitationReceived",
|
|
1300
|
+
"callAccepted",
|
|
1301
|
+
"callRejected",
|
|
1302
|
+
"callCanceled",
|
|
1303
|
+
"callEnded",
|
|
1304
|
+
"callTimeout",
|
|
1305
|
+
"callParticipantJoined",
|
|
1306
|
+
"callParticipantLeft",
|
|
1307
|
+
"callMediaStateChanged"
|
|
1308
|
+
]);
|
|
1309
|
+
var LOCAL_CONNECTION_EVENTS = /* @__PURE__ */ new Set([
|
|
1310
|
+
"connect",
|
|
1311
|
+
"disconnect",
|
|
1312
|
+
"connect_error",
|
|
1313
|
+
"connectionStateChanged",
|
|
1314
|
+
"reconnect",
|
|
1315
|
+
"reconnect_attempt",
|
|
1316
|
+
"reconnect_error",
|
|
1317
|
+
"reconnect_failed",
|
|
1318
|
+
"reconnectLoginSuccess",
|
|
1319
|
+
"reconnectLoginFailed"
|
|
1320
|
+
]);
|
|
204
1321
|
function parseSocketConnectErrorPayload(value) {
|
|
205
1322
|
if (!value) {
|
|
206
1323
|
return void 0;
|
|
@@ -220,27 +1337,71 @@ function parseSocketConnectErrorPayload(value) {
|
|
|
220
1337
|
}
|
|
221
1338
|
return void 0;
|
|
222
1339
|
}
|
|
223
|
-
function
|
|
1340
|
+
function getErrorRecord(error) {
|
|
1341
|
+
return error && typeof error === "object" ? error : void 0;
|
|
1342
|
+
}
|
|
1343
|
+
function getSocketConnectErrorDetails(error, url) {
|
|
1344
|
+
const record = getErrorRecord(error);
|
|
1345
|
+
const message = typeof record?.message === "string" && record.message ? record.message : typeof error === "string" && error ? error : "";
|
|
1346
|
+
return {
|
|
1347
|
+
message,
|
|
1348
|
+
type: typeof record?.type === "string" ? record.type : void 0,
|
|
1349
|
+
description: record?.description,
|
|
1350
|
+
transport: typeof record?.transport === "string" ? record.transport : void 0,
|
|
1351
|
+
url
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1354
|
+
function normalizeSocketConnectError(error, url) {
|
|
224
1355
|
const rawMessage = error && typeof error === "object" && "message" in error ? error.message : void 0;
|
|
225
1356
|
const rawData = error && typeof error === "object" && "data" in error ? error.data : void 0;
|
|
226
1357
|
const payload = parseSocketConnectErrorPayload(rawData) || parseSocketConnectErrorPayload(rawMessage);
|
|
1358
|
+
const details = getSocketConnectErrorDetails(error, url);
|
|
227
1359
|
const normalized = new Error(
|
|
228
|
-
payload?.message || (typeof rawMessage === "string" ? rawMessage : "") || "socket connect failed"
|
|
1360
|
+
payload?.message || details.message || (details.type ? `socket connect failed: ${details.type}` : "") || (typeof rawMessage === "string" ? rawMessage : "") || "socket connect failed"
|
|
229
1361
|
);
|
|
230
1362
|
normalized.name = "SocketConnectError";
|
|
231
1363
|
normalized.code = payload?.code;
|
|
232
1364
|
normalized.data = payload;
|
|
1365
|
+
normalized.details = details;
|
|
233
1366
|
normalized.requestId = payload?.requestId;
|
|
234
1367
|
normalized.raw = error;
|
|
235
1368
|
return normalized;
|
|
236
1369
|
}
|
|
1370
|
+
function debugSocketLog(...args) {
|
|
1371
|
+
if (typeof window !== "undefined" && window.__VANSHI_SDK_DEBUG__) {
|
|
1372
|
+
console.log(...args);
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
function normalizeTimeoutMs(timeoutMs, fallback) {
|
|
1376
|
+
return typeof timeoutMs === "number" && Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : fallback;
|
|
1377
|
+
}
|
|
237
1378
|
var SocketClient = class {
|
|
238
1379
|
constructor() {
|
|
239
1380
|
this.pending = /* @__PURE__ */ new Map();
|
|
240
|
-
this.
|
|
1381
|
+
this.pendingAcks = /* @__PURE__ */ new Map();
|
|
1382
|
+
this.eventHandlers = /* @__PURE__ */ new Map();
|
|
1383
|
+
this.operationQueue = [];
|
|
1384
|
+
this.operationQueueProcessing = false;
|
|
1385
|
+
this.operationQueueRunId = 0;
|
|
241
1386
|
this.connectPromise = null;
|
|
242
|
-
this.
|
|
1387
|
+
this.connectReject = null;
|
|
1388
|
+
this.intentionallyDisconnected = false;
|
|
1389
|
+
this.latestReconnectAttempt = 0;
|
|
1390
|
+
this.reconnectRestorePromise = null;
|
|
1391
|
+
this.reconnectRestoreGeneration = 0;
|
|
1392
|
+
this.reconnecting = false;
|
|
1393
|
+
this.restoringSession = false;
|
|
1394
|
+
this.hasEstablishedConnection = false;
|
|
1395
|
+
this.heartbeatSequence = 0;
|
|
1396
|
+
this.connectionStatePayload = {
|
|
1397
|
+
state: 0 /* Disconnected */,
|
|
1398
|
+
event: 3 /* LoginInterrupted */,
|
|
1399
|
+
extendedData: ""
|
|
1400
|
+
};
|
|
1401
|
+
this.socketHandlers = /* @__PURE__ */ new WeakMap();
|
|
243
1402
|
this.handleResponse = (res) => {
|
|
1403
|
+
if (!res || typeof res.id !== "string")
|
|
1404
|
+
return;
|
|
244
1405
|
const entry = this.pending.get(res.id);
|
|
245
1406
|
if (!entry)
|
|
246
1407
|
return;
|
|
@@ -248,141 +1409,492 @@ var SocketClient = class {
|
|
|
248
1409
|
this.pending.delete(res.id);
|
|
249
1410
|
res.error ? entry.reject(res.error) : entry.resolve(res.payload);
|
|
250
1411
|
};
|
|
1412
|
+
this.handleCallPush = (message, ackCallback) => {
|
|
1413
|
+
const valid = typeof message?.event === "string" && message.event.length > 0 && message.payload !== null && typeof message.payload === "object" && !Array.isArray(message.payload);
|
|
1414
|
+
if (typeof ackCallback === "function") {
|
|
1415
|
+
const ack = {
|
|
1416
|
+
success: valid,
|
|
1417
|
+
receivedAt: Date.now(),
|
|
1418
|
+
platform: "web",
|
|
1419
|
+
uuids: [message?.wsId],
|
|
1420
|
+
appId: message?.appid,
|
|
1421
|
+
userId: message?.userId,
|
|
1422
|
+
...valid ? {
|
|
1423
|
+
event: message.event,
|
|
1424
|
+
...typeof message.payload.callID === "string" ? { callId: message.payload.callID } : {}
|
|
1425
|
+
} : { error: "Invalid data format" }
|
|
1426
|
+
};
|
|
1427
|
+
try {
|
|
1428
|
+
ackCallback(ack);
|
|
1429
|
+
} catch (error) {
|
|
1430
|
+
console.error("[SocketClient] call push ACK failed:", error);
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
if (!valid)
|
|
1434
|
+
return;
|
|
1435
|
+
const handlers = this.eventHandlers.get(message.event) || /* @__PURE__ */ new Set();
|
|
1436
|
+
handlers.forEach((handler) => {
|
|
1437
|
+
try {
|
|
1438
|
+
this.invokeHandler(message.event, handler, [message.payload]);
|
|
1439
|
+
} catch (err) {
|
|
1440
|
+
console.error("[SocketClient] call event handler failed:", message.event, err);
|
|
1441
|
+
}
|
|
1442
|
+
});
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1445
|
+
watchSession() {
|
|
1446
|
+
if (!this.removeSessionListener)
|
|
1447
|
+
this.removeSessionListener = onSessionInvalidated(() => {
|
|
1448
|
+
this.reconnectRestoreGeneration++;
|
|
1449
|
+
this.reconnectRestorePromise = null;
|
|
1450
|
+
this.restoringSession = false;
|
|
1451
|
+
this.invalidateOperationQueueProcessor();
|
|
1452
|
+
this.cleanupAllPending(new Error("SDK session changed; operation canceled"), true);
|
|
1453
|
+
});
|
|
251
1454
|
}
|
|
252
1455
|
connect(url, auth, opts = {}) {
|
|
1456
|
+
this.watchSession();
|
|
253
1457
|
if (this.connectPromise)
|
|
254
1458
|
return this.connectPromise;
|
|
255
1459
|
if (this.isConnected())
|
|
256
1460
|
return Promise.resolve();
|
|
1461
|
+
if (this.socket && !this.intentionallyDisconnected && (this.hasEstablishedConnection || this.reconnecting || this.restoringSession)) {
|
|
1462
|
+
return this.waitForSocketConnected(
|
|
1463
|
+
normalizeTimeoutMs(opts.timeout, DEFAULT_CONNECT_TIMEOUT_MS)
|
|
1464
|
+
);
|
|
1465
|
+
}
|
|
1466
|
+
this.intentionallyDisconnected = false;
|
|
1467
|
+
this.latestReconnectAttempt = 0;
|
|
1468
|
+
this.reconnecting = false;
|
|
1469
|
+
this.restoringSession = false;
|
|
1470
|
+
this.hasEstablishedConnection = false;
|
|
1471
|
+
this.reconnectRestoreGeneration += 1;
|
|
1472
|
+
this.reconnectRestorePromise = null;
|
|
1473
|
+
this.invalidateOperationQueueProcessor();
|
|
1474
|
+
this.stopHeartbeat();
|
|
1475
|
+
this.cleanupAllPending(new Error("socket reinitialized"), true);
|
|
257
1476
|
if (this.socket) {
|
|
1477
|
+
const previousSocket = this.socket;
|
|
1478
|
+
this.socket = void 0;
|
|
258
1479
|
try {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
1480
|
+
previousSocket.off();
|
|
1481
|
+
previousSocket.io.off();
|
|
1482
|
+
previousSocket.disconnect();
|
|
262
1483
|
} catch {
|
|
263
1484
|
}
|
|
264
1485
|
}
|
|
265
1486
|
if (this.isConnected())
|
|
266
1487
|
return Promise.resolve();
|
|
267
1488
|
const { baseUrl, namespace } = this.parseUrl(url);
|
|
268
|
-
|
|
1489
|
+
const connectTimeoutMs = normalizeTimeoutMs(
|
|
1490
|
+
opts.timeout,
|
|
1491
|
+
DEFAULT_CONNECT_TIMEOUT_MS
|
|
1492
|
+
);
|
|
269
1493
|
const ioOpts = {
|
|
270
1494
|
...opts,
|
|
1495
|
+
auth,
|
|
271
1496
|
transports: ["websocket"],
|
|
272
|
-
// 🔥 只保留 websocket,不会多条连接
|
|
273
1497
|
query: { namespace },
|
|
274
1498
|
forceNew: true,
|
|
275
1499
|
reconnection: true,
|
|
276
1500
|
reconnectionAttempts: 9999,
|
|
277
|
-
reconnectionDelay:
|
|
278
|
-
timeout:
|
|
1501
|
+
reconnectionDelay: DEFAULT_RECONNECT_DELAY_MS,
|
|
1502
|
+
timeout: connectTimeoutMs
|
|
279
1503
|
};
|
|
280
1504
|
this.connectPromise = new Promise((resolve, reject) => {
|
|
281
|
-
|
|
1505
|
+
this.connectReject = reject;
|
|
1506
|
+
const socket = (0, import_socket.default)(`${baseUrl}${SOCKET_NAMESPACE}`, ioOpts);
|
|
282
1507
|
this.socket = socket;
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
};
|
|
290
|
-
const handleError = (err) => {
|
|
291
|
-
const normalizedError = normalizeSocketConnectError(err);
|
|
292
|
-
console.error("[SocketClient] \u8FDE\u63A5\u5931\u8D25\uFF1A:", normalizedError);
|
|
293
|
-
socket.off("connect", handleConnect);
|
|
294
|
-
reject(normalizedError);
|
|
295
|
-
};
|
|
296
|
-
socket.once("connect", handleConnect);
|
|
297
|
-
socket.once("connect_error", handleError);
|
|
298
|
-
socket.on("disconnect", (reason) => {
|
|
299
|
-
this.cleanupAllPending("disconnected: " + reason);
|
|
300
|
-
this.connectPromise = null;
|
|
1508
|
+
socket.onAny((event, ...args) => {
|
|
1509
|
+
if (this.socket !== socket)
|
|
1510
|
+
return;
|
|
1511
|
+
if (AUTO_ACK_EVENTS.has(event))
|
|
1512
|
+
this.ackPush(socket, event, args);
|
|
1513
|
+
observeMessagePush(event, args);
|
|
301
1514
|
});
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
1515
|
+
this.emitConnectionStateChanged(
|
|
1516
|
+
1 /* Connecting */,
|
|
1517
|
+
1 /* ActiveLogin */
|
|
1518
|
+
);
|
|
1519
|
+
debugSocketLog(
|
|
1520
|
+
"[SocketClient] connected target:",
|
|
1521
|
+
`${baseUrl}${SOCKET_NAMESPACE}`
|
|
1522
|
+
);
|
|
1523
|
+
let isInitialConnect = true;
|
|
1524
|
+
let initialConnectSettled = false;
|
|
1525
|
+
const handleConnect = () => {
|
|
1526
|
+
if (this.socket !== socket) {
|
|
1527
|
+
return;
|
|
1528
|
+
}
|
|
1529
|
+
if (isInitialConnect) {
|
|
1530
|
+
this.hasEstablishedConnection = true;
|
|
1531
|
+
this.reconnecting = false;
|
|
1532
|
+
this.restoringSession = false;
|
|
1533
|
+
socket.on("api:response", this.handleResponse);
|
|
1534
|
+
socket.on(CALL_PUSH_EVENT, this.handleCallPush);
|
|
1535
|
+
this.bindEventHandlers(socket);
|
|
1536
|
+
this.processOperationQueue();
|
|
1537
|
+
isInitialConnect = false;
|
|
1538
|
+
if (!initialConnectSettled) {
|
|
1539
|
+
initialConnectSettled = true;
|
|
1540
|
+
resolve();
|
|
1541
|
+
}
|
|
1542
|
+
} else {
|
|
1543
|
+
this.reconnecting = false;
|
|
1544
|
+
this.restoringSession = true;
|
|
1545
|
+
this.emitLocalEvent("reconnect", this.latestReconnectAttempt);
|
|
1546
|
+
const generation3 = ++this.reconnectRestoreGeneration;
|
|
1547
|
+
void this.restoreAfterReconnect(generation3);
|
|
1548
|
+
}
|
|
1549
|
+
this.startHeartbeat(socket);
|
|
1550
|
+
this.emitLocalEvent("connect");
|
|
1551
|
+
this.emitConnectionStateChanged(
|
|
1552
|
+
2 /* Connected */,
|
|
1553
|
+
0 /* Success */
|
|
307
1554
|
);
|
|
308
|
-
|
|
309
|
-
|
|
1555
|
+
};
|
|
1556
|
+
const handleError = (err) => {
|
|
1557
|
+
if (this.socket !== socket) {
|
|
310
1558
|
return;
|
|
311
1559
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
1560
|
+
const normalizedError = normalizeSocketConnectError(
|
|
1561
|
+
err,
|
|
1562
|
+
`${baseUrl}${SOCKET_NAMESPACE}`
|
|
1563
|
+
);
|
|
1564
|
+
console.error("[SocketClient] connect failed:", normalizedError);
|
|
1565
|
+
this.emitLocalEvent("connect_error", normalizedError);
|
|
1566
|
+
this.emitConnectionStateChanged(
|
|
1567
|
+
0 /* Disconnected */,
|
|
1568
|
+
2 /* LoginTimeout */,
|
|
1569
|
+
normalizedError.message
|
|
1570
|
+
);
|
|
1571
|
+
if (isInitialConnect && !initialConnectSettled) {
|
|
1572
|
+
initialConnectSettled = true;
|
|
1573
|
+
this.connectReject = null;
|
|
1574
|
+
this.rejectQueuedOperations(normalizedError);
|
|
1575
|
+
try {
|
|
1576
|
+
socket.io.opts.reconnection = false;
|
|
1577
|
+
socket.disconnect();
|
|
1578
|
+
} catch {
|
|
319
1579
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
1580
|
+
reject(normalizedError);
|
|
1581
|
+
}
|
|
1582
|
+
};
|
|
1583
|
+
socket.on("connect", handleConnect);
|
|
1584
|
+
socket.on("connect_error", handleError);
|
|
1585
|
+
socket.on("disconnect", (reason) => {
|
|
1586
|
+
if (this.socket !== socket) {
|
|
1587
|
+
return;
|
|
1588
|
+
}
|
|
1589
|
+
const hadEstablishedConnection = this.hasEstablishedConnection;
|
|
1590
|
+
const shouldReconnect = !this.intentionallyDisconnected && hadEstablishedConnection;
|
|
1591
|
+
const disconnectError = new Error("disconnected: " + reason);
|
|
1592
|
+
this.stopHeartbeat();
|
|
1593
|
+
this.reconnectRestoreGeneration += 1;
|
|
1594
|
+
this.reconnectRestorePromise = null;
|
|
1595
|
+
this.restoringSession = false;
|
|
1596
|
+
this.reconnecting = shouldReconnect;
|
|
1597
|
+
this.cleanupAllPending(disconnectError, !shouldReconnect);
|
|
1598
|
+
if (!hadEstablishedConnection && !initialConnectSettled) {
|
|
1599
|
+
initialConnectSettled = true;
|
|
1600
|
+
this.connectReject?.(disconnectError);
|
|
1601
|
+
this.connectReject = null;
|
|
1602
|
+
this.rejectQueuedOperations(disconnectError);
|
|
1603
|
+
}
|
|
1604
|
+
this.emitLocalEvent("disconnect", reason);
|
|
1605
|
+
this.emitConnectionStateChanged(
|
|
1606
|
+
0 /* Disconnected */,
|
|
1607
|
+
this.getDisconnectEvent(reason),
|
|
1608
|
+
String(reason || "")
|
|
1609
|
+
);
|
|
1610
|
+
if (reason === "io server disconnect" && !this.intentionallyDisconnected) {
|
|
1611
|
+
this.latestReconnectAttempt += 1;
|
|
1612
|
+
this.emitLocalEvent("reconnect_attempt", this.latestReconnectAttempt);
|
|
1613
|
+
this.emitConnectionStateChanged(
|
|
1614
|
+
3 /* Reconnecting */,
|
|
1615
|
+
3 /* LoginInterrupted */,
|
|
1616
|
+
String(this.latestReconnectAttempt)
|
|
1617
|
+
);
|
|
1618
|
+
socket.connect();
|
|
323
1619
|
}
|
|
324
1620
|
});
|
|
1621
|
+
socket.io.off("reconnect");
|
|
1622
|
+
socket.io.off("reconnect_attempt");
|
|
1623
|
+
socket.io.off("reconnect_error");
|
|
1624
|
+
socket.io.off("reconnect_failed");
|
|
1625
|
+
socket.io.on("reconnect_attempt", (attempt) => {
|
|
1626
|
+
if (this.socket !== socket) {
|
|
1627
|
+
return;
|
|
1628
|
+
}
|
|
1629
|
+
this.latestReconnectAttempt = attempt;
|
|
1630
|
+
this.emitLocalEvent("reconnect_attempt", attempt);
|
|
1631
|
+
this.emitConnectionStateChanged(
|
|
1632
|
+
3 /* Reconnecting */,
|
|
1633
|
+
3 /* LoginInterrupted */,
|
|
1634
|
+
String(attempt)
|
|
1635
|
+
);
|
|
1636
|
+
});
|
|
1637
|
+
socket.io.on("reconnect_error", (err) => {
|
|
1638
|
+
if (this.socket !== socket) {
|
|
1639
|
+
return;
|
|
1640
|
+
}
|
|
1641
|
+
this.emitLocalEvent("reconnect_error", err);
|
|
1642
|
+
});
|
|
1643
|
+
socket.io.on("reconnect_failed", () => {
|
|
1644
|
+
if (this.socket !== socket) {
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
this.reconnecting = false;
|
|
1648
|
+
this.restoringSession = false;
|
|
1649
|
+
this.hasEstablishedConnection = false;
|
|
1650
|
+
this.rejectQueuedOperations(new Error("reconnect failed"));
|
|
1651
|
+
this.emitConnectionStateChanged(
|
|
1652
|
+
0 /* Disconnected */,
|
|
1653
|
+
3 /* LoginInterrupted */,
|
|
1654
|
+
"reconnect failed"
|
|
1655
|
+
);
|
|
1656
|
+
this.emitLocalEvent("reconnect_failed");
|
|
1657
|
+
});
|
|
1658
|
+
socket.io.on("reconnect", (attempt) => {
|
|
1659
|
+
if (this.socket !== socket) {
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1662
|
+
debugSocketLog("[SocketClient] reconnect:", this.socket?.connected);
|
|
1663
|
+
this.latestReconnectAttempt = attempt;
|
|
1664
|
+
});
|
|
325
1665
|
});
|
|
326
|
-
this.connectPromise
|
|
327
|
-
|
|
328
|
-
|
|
1666
|
+
const trackedConnectPromise = this.connectPromise;
|
|
1667
|
+
trackedConnectPromise.then(
|
|
1668
|
+
() => {
|
|
1669
|
+
if (this.connectPromise === trackedConnectPromise) {
|
|
1670
|
+
this.connectPromise = null;
|
|
1671
|
+
this.connectReject = null;
|
|
1672
|
+
}
|
|
1673
|
+
},
|
|
1674
|
+
() => {
|
|
1675
|
+
if (this.connectPromise === trackedConnectPromise) {
|
|
1676
|
+
this.connectPromise = null;
|
|
1677
|
+
this.connectReject = null;
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1680
|
+
);
|
|
329
1681
|
return this.connectPromise;
|
|
330
1682
|
}
|
|
331
1683
|
disconnect() {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
1684
|
+
this.intentionallyDisconnected = true;
|
|
1685
|
+
this.reconnecting = false;
|
|
1686
|
+
this.restoringSession = false;
|
|
1687
|
+
this.hasEstablishedConnection = false;
|
|
1688
|
+
this.reconnectRestoreGeneration += 1;
|
|
1689
|
+
this.reconnectRestorePromise = null;
|
|
1690
|
+
this.invalidateOperationQueueProcessor();
|
|
1691
|
+
this.stopHeartbeat();
|
|
1692
|
+
const disconnectError = new Error("client disconnected");
|
|
1693
|
+
this.connectReject?.(disconnectError);
|
|
1694
|
+
this.connectReject = null;
|
|
1695
|
+
if (this.socket) {
|
|
1696
|
+
const currentSocket = this.socket;
|
|
1697
|
+
try {
|
|
1698
|
+
currentSocket.off("api:response", this.handleResponse);
|
|
1699
|
+
currentSocket.off(CALL_PUSH_EVENT, this.handleCallPush);
|
|
1700
|
+
currentSocket.io.off("reconnect");
|
|
1701
|
+
currentSocket.io.off("reconnect_attempt");
|
|
1702
|
+
currentSocket.io.off("reconnect_error");
|
|
1703
|
+
currentSocket.io.off("reconnect_failed");
|
|
1704
|
+
currentSocket.disconnect();
|
|
1705
|
+
} catch {
|
|
1706
|
+
} finally {
|
|
1707
|
+
try {
|
|
1708
|
+
currentSocket.off();
|
|
1709
|
+
currentSocket.io.off();
|
|
1710
|
+
} catch {
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
339
1713
|
}
|
|
340
1714
|
this.socket = void 0;
|
|
341
|
-
this.
|
|
1715
|
+
this.connectPromise = null;
|
|
1716
|
+
this.cleanupAllPending(disconnectError, true);
|
|
1717
|
+
this.removeSessionListener?.();
|
|
1718
|
+
this.removeSessionListener = void 0;
|
|
342
1719
|
}
|
|
343
1720
|
emitWithAck(event, payload, timeoutMs = 1e4) {
|
|
344
|
-
|
|
1721
|
+
this.watchSession();
|
|
1722
|
+
timeoutMs = normalizeTimeoutMs(timeoutMs, 1e4);
|
|
1723
|
+
const canSendDuringRestore = event === "login";
|
|
1724
|
+
const hasQueuedOperations = this.operationQueueProcessing || this.operationQueue.length > 0;
|
|
1725
|
+
if (this.isConnected() && (!hasQueuedOperations || canSendDuringRestore) && (!this.restoringSession && !isAuthenticating() || canSendDuringRestore)) {
|
|
345
1726
|
return this.createEmitPromise(event, payload, timeoutMs);
|
|
346
1727
|
}
|
|
347
|
-
if (this.connectPromise) {
|
|
348
|
-
return
|
|
349
|
-
this.
|
|
350
|
-
|
|
1728
|
+
if (this.connectPromise || this.reconnecting || isAuthenticating() && !canSendDuringRestore || hasQueuedOperations || this.restoringSession && !canSendDuringRestore) {
|
|
1729
|
+
return this.queueOperation(
|
|
1730
|
+
() => this.createEmitPromise(event, payload, timeoutMs),
|
|
1731
|
+
canSendDuringRestore ? "login" : "request"
|
|
1732
|
+
);
|
|
351
1733
|
}
|
|
352
|
-
return Promise.reject(new Error("socket not
|
|
1734
|
+
return Promise.reject(new Error("socket not connected"));
|
|
353
1735
|
}
|
|
354
1736
|
request(path, payload, timeoutMs = 1e4) {
|
|
355
|
-
|
|
356
|
-
|
|
1737
|
+
this.watchSession();
|
|
1738
|
+
timeoutMs = normalizeTimeoutMs(timeoutMs, 1e4);
|
|
1739
|
+
const hasQueuedOperations = this.operationQueueProcessing || this.operationQueue.length > 0;
|
|
1740
|
+
if (this.isConnected() && !this.restoringSession && !isAuthenticating() && !hasQueuedOperations) {
|
|
1741
|
+
return this.createRequestPromise(path, payload, timeoutMs);
|
|
357
1742
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
1743
|
+
if (this.connectPromise || this.reconnecting || this.restoringSession || isAuthenticating() || hasQueuedOperations) {
|
|
1744
|
+
return this.queueOperation(
|
|
1745
|
+
() => this.createRequestPromise(path, payload, timeoutMs)
|
|
1746
|
+
);
|
|
1747
|
+
}
|
|
1748
|
+
return Promise.reject(new Error("socket not connected"));
|
|
1749
|
+
}
|
|
1750
|
+
resumeQueuedRequestsAfterLogin() {
|
|
1751
|
+
if (!this.isConnected()) {
|
|
1752
|
+
return;
|
|
1753
|
+
}
|
|
1754
|
+
this.reconnectRestoreGeneration += 1;
|
|
1755
|
+
this.reconnecting = false;
|
|
1756
|
+
this.restoringSession = false;
|
|
1757
|
+
this.processOperationQueue();
|
|
1758
|
+
}
|
|
1759
|
+
rejectQueuedRequestsAfterLoginFailure(reason = new Error("login failed")) {
|
|
1760
|
+
this.rejectQueuedOperations(reason, true);
|
|
374
1761
|
}
|
|
375
1762
|
on(event, handler) {
|
|
376
|
-
this.
|
|
1763
|
+
const handlers = this.eventHandlers.get(event) || /* @__PURE__ */ new Set();
|
|
1764
|
+
if (handlers.has(handler))
|
|
1765
|
+
return;
|
|
1766
|
+
handlers.add(handler);
|
|
1767
|
+
this.eventHandlers.set(event, handlers);
|
|
1768
|
+
if (!LOCAL_CONNECTION_EVENTS.has(event) && !CALL_PUSH_EVENTS.has(event)) {
|
|
1769
|
+
this.socket?.on(event, this.socketHandler(event, handler));
|
|
1770
|
+
} else if (event === "connect" && this.isConnected()) {
|
|
1771
|
+
queueMicrotask(() => {
|
|
1772
|
+
if (this.eventHandlers.get(event) === handlers && handlers.has(handler))
|
|
1773
|
+
this.invokeHandler(event, handler, []);
|
|
1774
|
+
});
|
|
1775
|
+
} else if (event === "connectionStateChanged") {
|
|
1776
|
+
queueMicrotask(() => {
|
|
1777
|
+
if (this.eventHandlers.get(event) === handlers && handlers.has(handler))
|
|
1778
|
+
this.invokeHandler(event, handler, [this.connectionStatePayload]);
|
|
1779
|
+
});
|
|
1780
|
+
}
|
|
377
1781
|
}
|
|
378
1782
|
off(event, handler) {
|
|
379
|
-
if (
|
|
1783
|
+
if (handler) {
|
|
1784
|
+
const handlers = this.eventHandlers.get(event);
|
|
1785
|
+
handlers?.delete(handler);
|
|
1786
|
+
if (handlers?.size === 0) {
|
|
1787
|
+
this.eventHandlers.delete(event);
|
|
1788
|
+
}
|
|
1789
|
+
} else {
|
|
1790
|
+
this.eventHandlers.delete(event);
|
|
1791
|
+
}
|
|
1792
|
+
if (!this.socket || LOCAL_CONNECTION_EVENTS.has(event) || CALL_PUSH_EVENTS.has(event)) {
|
|
380
1793
|
return;
|
|
381
|
-
|
|
1794
|
+
}
|
|
1795
|
+
handler ? this.socket.off(event, this.socketHandler(event, handler)) : this.socket.off(event);
|
|
1796
|
+
}
|
|
1797
|
+
socketHandler(event, handler) {
|
|
1798
|
+
let events = this.socketHandlers.get(handler);
|
|
1799
|
+
if (!events) {
|
|
1800
|
+
events = /* @__PURE__ */ new Map();
|
|
1801
|
+
this.socketHandlers.set(handler, events);
|
|
1802
|
+
}
|
|
1803
|
+
let wrapped = events.get(event);
|
|
1804
|
+
if (!wrapped) {
|
|
1805
|
+
wrapped = (...args) => {
|
|
1806
|
+
const publicArgs = AUTO_ACK_EVENTS.has(event) ? args.filter((arg) => typeof arg !== "function") : args;
|
|
1807
|
+
const filtered = filterReplyPushArgs(event, publicArgs);
|
|
1808
|
+
if (filtered)
|
|
1809
|
+
this.invokeHandler(event, handler, filtered);
|
|
1810
|
+
};
|
|
1811
|
+
events.set(event, wrapped);
|
|
1812
|
+
}
|
|
1813
|
+
return wrapped;
|
|
382
1814
|
}
|
|
383
1815
|
isConnected() {
|
|
384
1816
|
return !!this.socket?.connected;
|
|
385
1817
|
}
|
|
1818
|
+
invokeHandler(event, handler, args) {
|
|
1819
|
+
try {
|
|
1820
|
+
const result = handler.apply(this.socket, args);
|
|
1821
|
+
if (result && typeof result.then === "function")
|
|
1822
|
+
Promise.resolve(result).catch((error) => {
|
|
1823
|
+
console.error("[SocketClient] async event handler failed:", event, error);
|
|
1824
|
+
});
|
|
1825
|
+
} catch (error) {
|
|
1826
|
+
console.error("[SocketClient] event handler failed:", event, error);
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
startHeartbeat(socket) {
|
|
1830
|
+
this.stopHeartbeat();
|
|
1831
|
+
const engine = socket?.io?.engine;
|
|
1832
|
+
if (!engine || typeof engine._sendPacket !== "function") {
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
const handlePacket = (packet) => {
|
|
1836
|
+
if (packet?.type !== "pong" || typeof packet.data !== "string" || packet.data !== this.pendingHeartbeatID) {
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
debugSocketLog("[SocketClient] heartbeat pong:", packet.data);
|
|
1840
|
+
this.pendingHeartbeatID = void 0;
|
|
1841
|
+
if (this.heartbeatTimeout !== void 0) {
|
|
1842
|
+
clearTimeout(this.heartbeatTimeout);
|
|
1843
|
+
this.heartbeatTimeout = void 0;
|
|
1844
|
+
}
|
|
1845
|
+
};
|
|
1846
|
+
const sendHeartbeat = () => {
|
|
1847
|
+
if (this.socket !== socket || socket.io?.engine !== engine || !socket.connected || engine.readyState !== "open" || this.pendingHeartbeatID) {
|
|
1848
|
+
return;
|
|
1849
|
+
}
|
|
1850
|
+
const heartbeatID = `${HEARTBEAT_PACKET_PREFIX}${++this.heartbeatSequence}`;
|
|
1851
|
+
this.pendingHeartbeatID = heartbeatID;
|
|
1852
|
+
debugSocketLog("[SocketClient] heartbeat ping:", heartbeatID);
|
|
1853
|
+
try {
|
|
1854
|
+
engine._sendPacket("ping", heartbeatID);
|
|
1855
|
+
} catch (error) {
|
|
1856
|
+
debugSocketLog("[SocketClient] heartbeat send failed:", error);
|
|
1857
|
+
this.stopHeartbeat();
|
|
1858
|
+
engine.close();
|
|
1859
|
+
return;
|
|
1860
|
+
}
|
|
1861
|
+
this.heartbeatTimeout = setTimeout(() => {
|
|
1862
|
+
this.heartbeatTimeout = void 0;
|
|
1863
|
+
if (this.socket !== socket || socket.io?.engine !== engine || !socket.connected || this.pendingHeartbeatID !== heartbeatID) {
|
|
1864
|
+
return;
|
|
1865
|
+
}
|
|
1866
|
+
debugSocketLog(
|
|
1867
|
+
`[SocketClient] heartbeat timeout after ${HEARTBEAT_TIMEOUT_MS}ms`
|
|
1868
|
+
);
|
|
1869
|
+
this.stopHeartbeat();
|
|
1870
|
+
engine.close();
|
|
1871
|
+
}, HEARTBEAT_TIMEOUT_MS);
|
|
1872
|
+
};
|
|
1873
|
+
this.heartbeatEngine = engine;
|
|
1874
|
+
this.heartbeatPacketHandler = handlePacket;
|
|
1875
|
+
engine.on("packet", handlePacket);
|
|
1876
|
+
sendHeartbeat();
|
|
1877
|
+
this.heartbeatInterval = setInterval(
|
|
1878
|
+
sendHeartbeat,
|
|
1879
|
+
HEARTBEAT_INTERVAL_MS
|
|
1880
|
+
);
|
|
1881
|
+
}
|
|
1882
|
+
stopHeartbeat() {
|
|
1883
|
+
if (this.heartbeatInterval !== void 0) {
|
|
1884
|
+
clearInterval(this.heartbeatInterval);
|
|
1885
|
+
this.heartbeatInterval = void 0;
|
|
1886
|
+
}
|
|
1887
|
+
if (this.heartbeatTimeout !== void 0) {
|
|
1888
|
+
clearTimeout(this.heartbeatTimeout);
|
|
1889
|
+
this.heartbeatTimeout = void 0;
|
|
1890
|
+
}
|
|
1891
|
+
if (this.heartbeatEngine && this.heartbeatPacketHandler) {
|
|
1892
|
+
this.heartbeatEngine.off("packet", this.heartbeatPacketHandler);
|
|
1893
|
+
}
|
|
1894
|
+
this.heartbeatEngine = void 0;
|
|
1895
|
+
this.heartbeatPacketHandler = void 0;
|
|
1896
|
+
this.pendingHeartbeatID = void 0;
|
|
1897
|
+
}
|
|
386
1898
|
parseUrl(url) {
|
|
387
1899
|
let baseUrl = url;
|
|
388
1900
|
let namespace = "/im/user";
|
|
@@ -393,95 +1905,601 @@ var SocketClient = class {
|
|
|
393
1905
|
namespace = queryNs;
|
|
394
1906
|
baseUrl = urlObj.origin + urlObj.pathname.replace(/\/$/, "");
|
|
395
1907
|
} catch {
|
|
396
|
-
console.warn("[
|
|
1908
|
+
console.warn("[SocketClient] url parse failed:", url);
|
|
397
1909
|
}
|
|
398
1910
|
return { baseUrl, namespace };
|
|
399
1911
|
}
|
|
1912
|
+
ackPush(socket, event, args) {
|
|
1913
|
+
const ack = args.find((arg) => typeof arg === "function");
|
|
1914
|
+
if (typeof ack !== "function" || !socket.id)
|
|
1915
|
+
return;
|
|
1916
|
+
const data = args[0];
|
|
1917
|
+
let receipt;
|
|
1918
|
+
const normalizeIds = (ids) => [...new Set(ids.filter((id) => typeof id === "string" && id.length > 0 || typeof id === "number" && Number.isFinite(id)).map(String))];
|
|
1919
|
+
if (event === "conversationChanged") {
|
|
1920
|
+
const infos = Array.isArray(data) ? data : Array.isArray(data?.infoList) ? data.infoList : [];
|
|
1921
|
+
const ackIds = normalizeIds(infos.map((info) => info?.conversation?.ackId));
|
|
1922
|
+
const userId = getSdkUserID();
|
|
1923
|
+
receipt = { clientId: socket.id, platform: "web", ...ackIds.length ? { ackIds } : {}, ...userId ? { userId } : {} };
|
|
1924
|
+
} else {
|
|
1925
|
+
const messages = Array.isArray(data?.messageList) ? data.messageList : [];
|
|
1926
|
+
const msgid = normalizeIds(messages.map((message) => message?.messageID));
|
|
1927
|
+
receipt = { clientId: socket.id, platform: "web", ...msgid.length ? { msgid } : {} };
|
|
1928
|
+
}
|
|
1929
|
+
try {
|
|
1930
|
+
ack(receipt);
|
|
1931
|
+
} catch (error) {
|
|
1932
|
+
console.error("[SocketClient] push ACK failed:", event, error);
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
bindEventHandlers(socket) {
|
|
1936
|
+
this.eventHandlers.forEach((handlers, event) => {
|
|
1937
|
+
if (LOCAL_CONNECTION_EVENTS.has(event) || CALL_PUSH_EVENTS.has(event)) {
|
|
1938
|
+
return;
|
|
1939
|
+
}
|
|
1940
|
+
handlers.forEach((handler) => {
|
|
1941
|
+
socket.on(event, this.socketHandler(event, handler));
|
|
1942
|
+
});
|
|
1943
|
+
});
|
|
1944
|
+
}
|
|
1945
|
+
emitLocalEvent(event, ...args) {
|
|
1946
|
+
const handlers = this.eventHandlers.get(event);
|
|
1947
|
+
if (!handlers)
|
|
1948
|
+
return;
|
|
1949
|
+
handlers.forEach((handler) => {
|
|
1950
|
+
try {
|
|
1951
|
+
this.invokeHandler(event, handler, args);
|
|
1952
|
+
} catch (err) {
|
|
1953
|
+
console.error("[SocketClient] event handler failed:", event, err);
|
|
1954
|
+
}
|
|
1955
|
+
});
|
|
1956
|
+
}
|
|
1957
|
+
emitConnectionStateChanged(state, event, extendedData = "") {
|
|
1958
|
+
const payload = {
|
|
1959
|
+
state,
|
|
1960
|
+
event,
|
|
1961
|
+
extendedData
|
|
1962
|
+
};
|
|
1963
|
+
this.connectionStatePayload = payload;
|
|
1964
|
+
this.emitLocalEvent("connectionStateChanged", payload);
|
|
1965
|
+
}
|
|
1966
|
+
getDisconnectEvent(reason) {
|
|
1967
|
+
if (reason === "io server disconnect") {
|
|
1968
|
+
return 4 /* KickedOut */;
|
|
1969
|
+
}
|
|
1970
|
+
return 3 /* LoginInterrupted */;
|
|
1971
|
+
}
|
|
1972
|
+
restoreAfterReconnect(generation3) {
|
|
1973
|
+
if (this.reconnectRestorePromise) {
|
|
1974
|
+
return this.reconnectRestorePromise;
|
|
1975
|
+
}
|
|
1976
|
+
const restorePromise = (async () => {
|
|
1977
|
+
await new Promise(
|
|
1978
|
+
(resolveReconnect) => setTimeout(resolveReconnect, RECONNECT_LOGIN_DELAY_MS)
|
|
1979
|
+
);
|
|
1980
|
+
if (generation3 !== this.reconnectRestoreGeneration || !this.isConnected() || !this.socket) {
|
|
1981
|
+
debugSocketLog("[SocketClient] skip reconnect login: socket not ready");
|
|
1982
|
+
return;
|
|
1983
|
+
}
|
|
1984
|
+
try {
|
|
1985
|
+
debugSocketLog("[SocketClient] reconnect login start");
|
|
1986
|
+
const res = await restoreSessionAfterReconnect();
|
|
1987
|
+
if (generation3 !== this.reconnectRestoreGeneration) {
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
if (res) {
|
|
1991
|
+
this.restoringSession = false;
|
|
1992
|
+
this.processOperationQueue();
|
|
1993
|
+
this.emitLocalEvent("reconnectLoginSuccess");
|
|
1994
|
+
} else {
|
|
1995
|
+
this.restoringSession = false;
|
|
1996
|
+
clearSessionState();
|
|
1997
|
+
this.rejectQueuedOperations(new Error("restore login failed"), true);
|
|
1998
|
+
this.processOperationQueue();
|
|
1999
|
+
this.emitLocalEvent("reconnectLoginFailed", {
|
|
2000
|
+
message: "restore login failed"
|
|
2001
|
+
});
|
|
2002
|
+
}
|
|
2003
|
+
} catch (err) {
|
|
2004
|
+
if (generation3 !== this.reconnectRestoreGeneration) {
|
|
2005
|
+
return;
|
|
2006
|
+
}
|
|
2007
|
+
console.error("[SocketClient] reconnect login failed:", err);
|
|
2008
|
+
this.restoringSession = false;
|
|
2009
|
+
clearSessionState();
|
|
2010
|
+
this.rejectQueuedOperations(err, true);
|
|
2011
|
+
this.processOperationQueue();
|
|
2012
|
+
this.emitLocalEvent("reconnectLoginFailed", err);
|
|
2013
|
+
}
|
|
2014
|
+
})();
|
|
2015
|
+
const trackedRestorePromise = restorePromise.finally(() => {
|
|
2016
|
+
if (this.reconnectRestorePromise === trackedRestorePromise) {
|
|
2017
|
+
this.reconnectRestorePromise = null;
|
|
2018
|
+
}
|
|
2019
|
+
});
|
|
2020
|
+
this.reconnectRestorePromise = trackedRestorePromise;
|
|
2021
|
+
return this.reconnectRestorePromise;
|
|
2022
|
+
}
|
|
400
2023
|
generateId() {
|
|
401
2024
|
return Date.now().toString(36) + Math.random().toString(36).slice(2, 9);
|
|
402
2025
|
}
|
|
2026
|
+
waitForSocketConnected(timeoutMs) {
|
|
2027
|
+
if (this.isConnected()) {
|
|
2028
|
+
return Promise.resolve();
|
|
2029
|
+
}
|
|
2030
|
+
return new Promise((resolve, reject) => {
|
|
2031
|
+
const cleanup = () => {
|
|
2032
|
+
clearTimeout(timer);
|
|
2033
|
+
this.off("connect", handleConnect);
|
|
2034
|
+
this.off("reconnect_failed", handleReconnectFailed);
|
|
2035
|
+
this.off("disconnect", handleDisconnect);
|
|
2036
|
+
};
|
|
2037
|
+
const handleConnect = () => {
|
|
2038
|
+
cleanup();
|
|
2039
|
+
resolve();
|
|
2040
|
+
};
|
|
2041
|
+
const handleReconnectFailed = () => {
|
|
2042
|
+
cleanup();
|
|
2043
|
+
reject(new Error("reconnect failed"));
|
|
2044
|
+
};
|
|
2045
|
+
const handleDisconnect = (reason) => {
|
|
2046
|
+
if (!this.reconnecting && !this.restoringSession) {
|
|
2047
|
+
cleanup();
|
|
2048
|
+
reject(new Error("disconnected: " + String(reason || "")));
|
|
2049
|
+
}
|
|
2050
|
+
};
|
|
2051
|
+
const timer = setTimeout(() => {
|
|
2052
|
+
cleanup();
|
|
2053
|
+
reject(new Error("connect timeout"));
|
|
2054
|
+
}, timeoutMs);
|
|
2055
|
+
this.on("connect", handleConnect);
|
|
2056
|
+
this.on("reconnect_failed", handleReconnectFailed);
|
|
2057
|
+
this.on("disconnect", handleDisconnect);
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
2060
|
+
createRequestPromise(path, payload, timeoutMs) {
|
|
2061
|
+
const id = this.generateId();
|
|
2062
|
+
const envelope = { id, path, payload };
|
|
2063
|
+
return new Promise((resolve, reject) => {
|
|
2064
|
+
if (!this.isConnected() || this.restoringSession) {
|
|
2065
|
+
reject(new Error("socket not connected"));
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
const timer = setTimeout(() => {
|
|
2069
|
+
this.pending.delete(id);
|
|
2070
|
+
reject(new Error("request timeout"));
|
|
2071
|
+
}, timeoutMs);
|
|
2072
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
2073
|
+
try {
|
|
2074
|
+
if (!this.socket) {
|
|
2075
|
+
throw new Error("socket not initialized");
|
|
2076
|
+
}
|
|
2077
|
+
this.socket.emit("api:request", envelope);
|
|
2078
|
+
} catch (err) {
|
|
2079
|
+
clearTimeout(timer);
|
|
2080
|
+
this.pending.delete(id);
|
|
2081
|
+
reject(err);
|
|
2082
|
+
}
|
|
2083
|
+
});
|
|
2084
|
+
}
|
|
403
2085
|
createEmitPromise(event, payload, timeoutMs) {
|
|
2086
|
+
const id = this.generateId();
|
|
404
2087
|
return new Promise((resolve, reject) => {
|
|
405
|
-
|
|
2088
|
+
if (!this.isConnected()) {
|
|
2089
|
+
reject(new Error("socket not connected"));
|
|
2090
|
+
return;
|
|
2091
|
+
}
|
|
406
2092
|
const timer = setTimeout(() => {
|
|
407
|
-
|
|
2093
|
+
this.pendingAcks.delete(id);
|
|
408
2094
|
reject(new Error("ack timeout"));
|
|
409
2095
|
}, timeoutMs);
|
|
2096
|
+
this.pendingAcks.set(id, { resolve, reject, timer });
|
|
410
2097
|
try {
|
|
2098
|
+
if (!this.socket) {
|
|
2099
|
+
throw new Error("socket not initialized");
|
|
2100
|
+
}
|
|
411
2101
|
this.socket.emit(event, payload, (response) => {
|
|
412
|
-
|
|
2102
|
+
const entry = this.pendingAcks.get(id);
|
|
2103
|
+
if (!entry)
|
|
413
2104
|
return;
|
|
414
|
-
clearTimeout(timer);
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
} else {
|
|
418
|
-
resolve(response);
|
|
419
|
-
}
|
|
2105
|
+
clearTimeout(entry.timer);
|
|
2106
|
+
this.pendingAcks.delete(id);
|
|
2107
|
+
entry.resolve(response);
|
|
420
2108
|
});
|
|
421
2109
|
} catch (err) {
|
|
422
2110
|
clearTimeout(timer);
|
|
2111
|
+
this.pendingAcks.delete(id);
|
|
423
2112
|
reject(err);
|
|
424
2113
|
}
|
|
425
2114
|
});
|
|
426
2115
|
}
|
|
427
|
-
|
|
428
|
-
|
|
2116
|
+
queueOperation(execute, kind = "request") {
|
|
2117
|
+
return new Promise((resolve, reject) => {
|
|
2118
|
+
if (this.operationQueue.length >= MAX_OPERATION_QUEUE_SIZE) {
|
|
2119
|
+
reject(new Error("socket operation queue is full"));
|
|
2120
|
+
return;
|
|
2121
|
+
}
|
|
2122
|
+
const operation = {
|
|
2123
|
+
session: captureSession(),
|
|
2124
|
+
execute,
|
|
2125
|
+
resolve,
|
|
2126
|
+
reject,
|
|
2127
|
+
kind
|
|
2128
|
+
};
|
|
2129
|
+
if (kind === "login") {
|
|
2130
|
+
const firstRequestIndex = this.operationQueue.findIndex(
|
|
2131
|
+
(item) => item.kind !== "login"
|
|
2132
|
+
);
|
|
2133
|
+
if (firstRequestIndex < 0) {
|
|
2134
|
+
this.operationQueue.push(operation);
|
|
2135
|
+
} else {
|
|
2136
|
+
this.operationQueue.splice(firstRequestIndex, 0, operation);
|
|
2137
|
+
}
|
|
2138
|
+
} else {
|
|
2139
|
+
this.operationQueue.push(operation);
|
|
2140
|
+
}
|
|
2141
|
+
this.processOperationQueue();
|
|
2142
|
+
});
|
|
2143
|
+
}
|
|
2144
|
+
processOperationQueue() {
|
|
2145
|
+
if (!this.isConnected() || (this.restoringSession || isAuthenticating()) && this.operationQueue[0]?.kind !== "login" || this.operationQueueProcessing) {
|
|
429
2146
|
return;
|
|
430
|
-
while (this.emitQueue.length) {
|
|
431
|
-
const item = this.emitQueue.shift();
|
|
432
|
-
this.createEmitPromise(item.event, item.payload, item.timeoutMs).then(item.resolve).catch(item.reject);
|
|
433
2147
|
}
|
|
2148
|
+
this.operationQueueProcessing = true;
|
|
2149
|
+
const runId = ++this.operationQueueRunId;
|
|
2150
|
+
const processNext = () => {
|
|
2151
|
+
if (runId !== this.operationQueueRunId) {
|
|
2152
|
+
return;
|
|
2153
|
+
}
|
|
2154
|
+
if (!this.isConnected() || (this.restoringSession || isAuthenticating()) && this.operationQueue[0]?.kind !== "login") {
|
|
2155
|
+
this.operationQueueProcessing = false;
|
|
2156
|
+
return;
|
|
2157
|
+
}
|
|
2158
|
+
const item = this.operationQueue.shift();
|
|
2159
|
+
if (!item) {
|
|
2160
|
+
this.operationQueueProcessing = false;
|
|
2161
|
+
return;
|
|
2162
|
+
}
|
|
2163
|
+
Promise.resolve().then(() => {
|
|
2164
|
+
assertCurrentSession(item.session);
|
|
2165
|
+
return item.execute();
|
|
2166
|
+
}).then(
|
|
2167
|
+
(value) => {
|
|
2168
|
+
item.resolve(value);
|
|
2169
|
+
},
|
|
2170
|
+
(error) => {
|
|
2171
|
+
item.reject(error);
|
|
2172
|
+
if (item.kind === "login" && runId === this.operationQueueRunId) {
|
|
2173
|
+
this.rejectQueuedOperations(error);
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
).finally(processNext);
|
|
2177
|
+
};
|
|
2178
|
+
processNext();
|
|
2179
|
+
}
|
|
2180
|
+
invalidateOperationQueueProcessor() {
|
|
2181
|
+
this.operationQueueRunId += 1;
|
|
2182
|
+
this.operationQueueProcessing = false;
|
|
2183
|
+
}
|
|
2184
|
+
rejectQueuedOperations(reason, preserveLoginOperations = false) {
|
|
2185
|
+
const queue = this.operationQueue.splice(0);
|
|
2186
|
+
const preserved = [];
|
|
2187
|
+
queue.forEach((item) => {
|
|
2188
|
+
if (preserveLoginOperations && item.kind === "login") {
|
|
2189
|
+
preserved.push(item);
|
|
2190
|
+
} else {
|
|
2191
|
+
item.reject(reason);
|
|
2192
|
+
}
|
|
2193
|
+
});
|
|
2194
|
+
this.operationQueue.unshift(...preserved);
|
|
434
2195
|
}
|
|
435
|
-
cleanupAllPending(reason) {
|
|
2196
|
+
cleanupAllPending(reason, clearQueue) {
|
|
436
2197
|
for (const [, entry] of this.pending) {
|
|
437
2198
|
clearTimeout(entry.timer);
|
|
438
|
-
entry.reject(
|
|
2199
|
+
entry.reject(reason);
|
|
439
2200
|
}
|
|
440
2201
|
this.pending.clear();
|
|
441
|
-
for (const
|
|
442
|
-
|
|
2202
|
+
for (const [, entry] of this.pendingAcks) {
|
|
2203
|
+
clearTimeout(entry.timer);
|
|
2204
|
+
entry.reject(reason);
|
|
2205
|
+
}
|
|
2206
|
+
this.pendingAcks.clear();
|
|
2207
|
+
if (clearQueue) {
|
|
2208
|
+
this.rejectQueuedOperations(reason);
|
|
443
2209
|
}
|
|
444
|
-
this.emitQueue = [];
|
|
445
2210
|
}
|
|
446
2211
|
};
|
|
447
2212
|
var socketClient = new SocketClient();
|
|
448
2213
|
var client_default = socketClient;
|
|
449
2214
|
|
|
2215
|
+
// src/sdk/message/replyResult.ts
|
|
2216
|
+
function normalizeReplyResult(result, payload) {
|
|
2217
|
+
const sent = payload.message || {};
|
|
2218
|
+
const original = payload.toOriginalMessage || {};
|
|
2219
|
+
const received = result?.message && typeof result.message === "object" ? result.message : result;
|
|
2220
|
+
const hasReplyIdentity = received?.messageID && (!original.messageID || String(received.messageID) !== String(original.messageID)) && !isSelfReferencingReply(received);
|
|
2221
|
+
const row = hasReplyIdentity ? received : {};
|
|
2222
|
+
const normalize = (row2) => {
|
|
2223
|
+
const reply = {
|
|
2224
|
+
...sent,
|
|
2225
|
+
...row2,
|
|
2226
|
+
clientBizId: sent.clientBizId,
|
|
2227
|
+
localMessageID: sent.localMessageID || sent.clientBizId,
|
|
2228
|
+
conversationID: sent.conversationID ?? original.conversationID,
|
|
2229
|
+
conversationType: sent.conversationType ?? original.conversationType,
|
|
2230
|
+
direction: 0,
|
|
2231
|
+
sentStatus: 1,
|
|
2232
|
+
sendState: 1,
|
|
2233
|
+
repliedInfo: {
|
|
2234
|
+
...sent.repliedInfo,
|
|
2235
|
+
...row2.repliedInfo,
|
|
2236
|
+
messageInfo: row2.repliedInfo?.messageInfo ?? sent.repliedInfo?.messageInfo
|
|
2237
|
+
}
|
|
2238
|
+
};
|
|
2239
|
+
delete reply.localID;
|
|
2240
|
+
delete reply.errorCode;
|
|
2241
|
+
delete reply.errorMessage;
|
|
2242
|
+
return reply;
|
|
2243
|
+
};
|
|
2244
|
+
if (result?.message && typeof result.message === "object")
|
|
2245
|
+
return { ...result, message: normalize(row) };
|
|
2246
|
+
return normalize(row);
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
// src/sdk/message/sendResult.ts
|
|
2250
|
+
function normalizeSendResult(method, result, payload) {
|
|
2251
|
+
if (method === "replyMessage")
|
|
2252
|
+
return normalizeReplyResult(result, payload);
|
|
2253
|
+
const sent = payload.message || {};
|
|
2254
|
+
const normalize = (row = {}) => {
|
|
2255
|
+
const sendState = messageSendState(row);
|
|
2256
|
+
return {
|
|
2257
|
+
...row,
|
|
2258
|
+
clientBizId: sent.clientBizId || row.clientBizId,
|
|
2259
|
+
localMessageID: row.localMessageID || sent.localMessageID || sent.clientBizId,
|
|
2260
|
+
sendState,
|
|
2261
|
+
sentStatus: row.sentStatus ?? sendState
|
|
2262
|
+
};
|
|
2263
|
+
};
|
|
2264
|
+
if (result?.message && typeof result.message === "object")
|
|
2265
|
+
return { ...result, message: normalize(result.message) };
|
|
2266
|
+
return normalize(result && typeof result === "object" ? result : {});
|
|
2267
|
+
}
|
|
2268
|
+
|
|
450
2269
|
// src/plugins/request/index.ts
|
|
2270
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
2271
|
+
function getTimeoutMs(config) {
|
|
2272
|
+
return typeof config.timeoutMs === "number" && Number.isFinite(config.timeoutMs) && config.timeoutMs > 0 ? config.timeoutMs : DEFAULT_TIMEOUT_MS;
|
|
2273
|
+
}
|
|
451
2274
|
async function request(config) {
|
|
452
2275
|
if (!config || !config.path) {
|
|
453
|
-
|
|
2276
|
+
throwSdkTransportError(new Error("invalid request config"));
|
|
454
2277
|
}
|
|
455
|
-
const
|
|
456
|
-
const
|
|
457
|
-
if (
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
2278
|
+
const session = captureSession();
|
|
2279
|
+
const method = config.path.replace(/^\/?sdk\//, "");
|
|
2280
|
+
if (method !== "login" && method !== "logout" && isAuthenticating())
|
|
2281
|
+
await waitForAuthentication(session);
|
|
2282
|
+
const storage = captureStorage();
|
|
2283
|
+
const sending = ["sendMessage", "sendMediaMessage", "replyMessage"].includes(method);
|
|
2284
|
+
if (storage && sending && config.data?.message) {
|
|
2285
|
+
config = { ...config, data: { ...config.data, message: {
|
|
2286
|
+
...config.data.message,
|
|
2287
|
+
clientBizId: config.data.message.clientBizId || makeClientBizId()
|
|
2288
|
+
} } };
|
|
2289
|
+
await persistOutgoing(storage, config.data);
|
|
2290
|
+
}
|
|
2291
|
+
const startedAt = Date.now();
|
|
2292
|
+
const fetchSequence = storage ? storage.mutationSequence = (storage.mutationSequence || 0) + 1 : 0;
|
|
2293
|
+
try {
|
|
2294
|
+
assertCurrentSession(session);
|
|
2295
|
+
if (storage && !isCurrentStorage(storage))
|
|
2296
|
+
throw new Error("Local storage account changed before request");
|
|
2297
|
+
const { path } = config;
|
|
2298
|
+
const isSdkApi = path.startsWith("/sdk/") || path.startsWith("sdk/");
|
|
2299
|
+
const timeoutMs = getTimeoutMs(config);
|
|
2300
|
+
if (isSdkApi) {
|
|
2301
|
+
const eventName = path.replace(/^\/?sdk\//, "");
|
|
2302
|
+
const response2 = await client_default.emitWithAck(
|
|
465
2303
|
eventName,
|
|
466
2304
|
config.data,
|
|
467
|
-
|
|
2305
|
+
timeoutMs
|
|
468
2306
|
);
|
|
469
|
-
|
|
470
|
-
|
|
2307
|
+
assertCurrentSession(session);
|
|
2308
|
+
const envelope = hasSdkCode(response2) ? response2 : { code: 0, message: "", data: response2 };
|
|
2309
|
+
const normalizedEnvelope = sending && isSuccessCode(envelope.code) ? { ...envelope, data: normalizeSendResult(method, envelope.data, config.data || {}) } : envelope;
|
|
2310
|
+
if (isSuccessCode(envelope.code)) {
|
|
2311
|
+
await cacheApiResult(storage, method, config.data || {}, normalizedEnvelope.data, startedAt, fetchSequence);
|
|
2312
|
+
} else if (sending) {
|
|
2313
|
+
await markSendError(storage, config.data?.message?.clientBizId, outgoingFallback(config.data || {}, storage), envelope);
|
|
471
2314
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
2315
|
+
assertCurrentSession(session);
|
|
2316
|
+
return normalizedEnvelope;
|
|
2317
|
+
}
|
|
2318
|
+
const response = await client_default.request(path, config.data, timeoutMs);
|
|
2319
|
+
assertCurrentSession(session);
|
|
2320
|
+
return response;
|
|
2321
|
+
} catch (error) {
|
|
2322
|
+
if (sending)
|
|
2323
|
+
await markSendError(storage, config.data?.message?.clientBizId, outgoingFallback(config.data || {}, storage), error);
|
|
2324
|
+
assertCurrentSession(session);
|
|
2325
|
+
if (isSdkRuntimeErrorObject(error)) {
|
|
2326
|
+
throw error;
|
|
475
2327
|
}
|
|
2328
|
+
throwSdkTransportError(error);
|
|
476
2329
|
}
|
|
477
|
-
|
|
478
|
-
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
// src/sdk/storage/types.ts
|
|
2333
|
+
var LocalSyncError = class extends Error {
|
|
2334
|
+
constructor(results, failures) {
|
|
2335
|
+
super(`Local synchronization incomplete: ${failures.length} failure(s)`);
|
|
2336
|
+
this.results = results;
|
|
2337
|
+
this.failures = failures;
|
|
2338
|
+
this.name = "LocalSyncError";
|
|
2339
|
+
this.fullyReconciled = false;
|
|
479
2340
|
}
|
|
480
|
-
|
|
481
|
-
|
|
2341
|
+
toJSON() {
|
|
2342
|
+
return { name: this.name, message: this.message, results: this.results, failures: this.failures, fullyReconciled: false };
|
|
2343
|
+
}
|
|
2344
|
+
};
|
|
2345
|
+
|
|
2346
|
+
// src/sdk/storage/sync.ts
|
|
2347
|
+
var running = /* @__PURE__ */ new WeakMap();
|
|
2348
|
+
async function syncConversationMessages(options) {
|
|
2349
|
+
const ctx = captureStorage();
|
|
2350
|
+
if (!ctx)
|
|
2351
|
+
throw new Error("Local message storage is not enabled");
|
|
2352
|
+
const { conversationID } = options;
|
|
2353
|
+
const conversationType = String(options.conversationType);
|
|
2354
|
+
const key = JSON.stringify([conversationType, conversationID]);
|
|
2355
|
+
let jobs = running.get(ctx);
|
|
2356
|
+
if (!jobs) {
|
|
2357
|
+
jobs = /* @__PURE__ */ new Map();
|
|
2358
|
+
running.set(ctx, jobs);
|
|
2359
|
+
}
|
|
2360
|
+
const existing = jobs.get(key);
|
|
2361
|
+
if (existing)
|
|
2362
|
+
return existing;
|
|
2363
|
+
const job = (async () => {
|
|
2364
|
+
emitStorageEvent("localSyncStateChanged", { state: "syncing", conversationID, conversationType });
|
|
2365
|
+
try {
|
|
2366
|
+
await ctx.ready;
|
|
2367
|
+
const failuresBefore = ctx.failureCount || 0;
|
|
2368
|
+
let nextMessage;
|
|
2369
|
+
let exhausted = false;
|
|
2370
|
+
const cursors = /* @__PURE__ */ new Set();
|
|
2371
|
+
for (let page = 0; page < 100; page++) {
|
|
2372
|
+
if (!isCurrentStorage(ctx))
|
|
2373
|
+
throw new Error("Local storage account changed");
|
|
2374
|
+
const response = await request({ path: "/sdk/queryHistoryMessage", data: {
|
|
2375
|
+
conversationID,
|
|
2376
|
+
conversationType,
|
|
2377
|
+
config: { count: "100", ...nextMessage ? { nextMessage } : {} }
|
|
2378
|
+
} });
|
|
2379
|
+
const data = unwrapSdkData(response);
|
|
2380
|
+
if (!isCurrentStorage(ctx))
|
|
2381
|
+
throw new Error("Local storage account changed");
|
|
2382
|
+
const list = data?.messageList;
|
|
2383
|
+
if (!Array.isArray(list))
|
|
2384
|
+
throw new Error("Invalid history response during local synchronization");
|
|
2385
|
+
if (list.length < 100) {
|
|
2386
|
+
exhausted = true;
|
|
2387
|
+
break;
|
|
2388
|
+
}
|
|
2389
|
+
const last = list[list.length - 1];
|
|
2390
|
+
if (!last.messageID)
|
|
2391
|
+
throw new Error("History cursor is missing messageID");
|
|
2392
|
+
const cursor = String(last.messageID);
|
|
2393
|
+
if (cursors.has(cursor))
|
|
2394
|
+
throw new Error("History pagination cursor did not advance");
|
|
2395
|
+
cursors.add(cursor);
|
|
2396
|
+
nextMessage = { messageID: last.messageID, id: last.id || "", type: String(last.type) };
|
|
2397
|
+
}
|
|
2398
|
+
if (!exhausted)
|
|
2399
|
+
throw new Error("History synchronization page limit reached; synchronization is incomplete");
|
|
2400
|
+
if ((ctx.failureCount || 0) !== failuresBefore)
|
|
2401
|
+
throw new Error("Messages could not be persisted during synchronization");
|
|
2402
|
+
const result = { conversationID, conversationType, syncedAt: Date.now(), fullyReconciled: false };
|
|
2403
|
+
await storageWork(ctx, async (ctx2) => {
|
|
2404
|
+
await ctx2.db.meta.put({ key: `sync:${key}`, ...result });
|
|
2405
|
+
});
|
|
2406
|
+
if ((ctx.failureCount || 0) !== failuresBefore)
|
|
2407
|
+
throw new Error("Synchronization metadata could not be persisted");
|
|
2408
|
+
if (isCurrentStorage(ctx))
|
|
2409
|
+
emitStorageEvent("localSyncStateChanged", { state: "synced", ...result });
|
|
2410
|
+
return result;
|
|
2411
|
+
} catch (error) {
|
|
2412
|
+
if (isCurrentStorage(ctx))
|
|
2413
|
+
emitStorageEvent("localSyncStateChanged", { state: "failed", conversationID, conversationType, message: error instanceof Error ? error.message : String(error), fullyReconciled: false });
|
|
2414
|
+
throw error;
|
|
2415
|
+
}
|
|
2416
|
+
})();
|
|
2417
|
+
jobs.set(key, job);
|
|
2418
|
+
try {
|
|
2419
|
+
return await job;
|
|
2420
|
+
} finally {
|
|
2421
|
+
jobs.delete(key);
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
async function syncLocalMessages() {
|
|
2425
|
+
const ctx = captureStorage();
|
|
2426
|
+
if (!ctx)
|
|
2427
|
+
return [];
|
|
2428
|
+
const conversations = await storageWork(ctx, async (ctx2) => {
|
|
2429
|
+
const keys = await ctx2.db.messages.orderBy("conversationKey").uniqueKeys();
|
|
2430
|
+
return keys.map((key) => {
|
|
2431
|
+
const [conversationType, conversationID] = JSON.parse(String(key));
|
|
2432
|
+
return { conversationType: String(conversationType), conversationID: String(conversationID) };
|
|
2433
|
+
});
|
|
2434
|
+
});
|
|
2435
|
+
const failures = [];
|
|
2436
|
+
if (!conversations)
|
|
2437
|
+
failures.push({ conversationID: "", conversationType: "", message: "Cached conversations could not be read" });
|
|
2438
|
+
const known = new Map((conversations || []).map((row) => [JSON.stringify([String(row.conversationType), row.conversationID]), row]));
|
|
2439
|
+
try {
|
|
2440
|
+
let nextConversation;
|
|
2441
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2442
|
+
let exhausted = false;
|
|
2443
|
+
for (let page = 0; page < 100 && isCurrentStorage(ctx); page++) {
|
|
2444
|
+
const data = unwrapSdkData(await request({ path: "/sdk/queryConversationList", data: { count: 100, ...nextConversation ? { nextConversation } : {} } }));
|
|
2445
|
+
if (!isCurrentStorage(ctx))
|
|
2446
|
+
throw new Error("Local storage account changed");
|
|
2447
|
+
const list = Array.isArray(data) ? data : data?.conversationList;
|
|
2448
|
+
if (!Array.isArray(list))
|
|
2449
|
+
throw new Error("Invalid conversation list during local synchronization");
|
|
2450
|
+
for (const row of list) {
|
|
2451
|
+
const conversation = row.conversation || row;
|
|
2452
|
+
if (conversation.conversationID === void 0 || (conversation.conversationType ?? conversation.type) === void 0)
|
|
2453
|
+
continue;
|
|
2454
|
+
const entry = { conversationID: String(conversation.conversationID), conversationType: String(conversation.conversationType ?? conversation.type) };
|
|
2455
|
+
known.set(JSON.stringify([entry.conversationType, entry.conversationID]), entry);
|
|
2456
|
+
}
|
|
2457
|
+
if (list.length < 100) {
|
|
2458
|
+
exhausted = true;
|
|
2459
|
+
break;
|
|
2460
|
+
}
|
|
2461
|
+
nextConversation = list[list.length - 1].conversation || list[list.length - 1];
|
|
2462
|
+
const key = JSON.stringify([nextConversation.conversationType ?? nextConversation.type, nextConversation.conversationID]);
|
|
2463
|
+
if (seen.has(key))
|
|
2464
|
+
throw new Error("Conversation pagination cursor did not advance");
|
|
2465
|
+
seen.add(key);
|
|
2466
|
+
}
|
|
2467
|
+
if (!exhausted)
|
|
2468
|
+
throw new Error("Conversation synchronization page limit reached; synchronization is incomplete");
|
|
2469
|
+
} catch (error) {
|
|
2470
|
+
failures.push({ conversationID: "", conversationType: "", message: error instanceof Error ? error.message : String(error) });
|
|
2471
|
+
if (isCurrentStorage(ctx))
|
|
2472
|
+
emitStorageEvent("localSyncStateChanged", { state: "failed", conversationID: "", conversationType: "", message: error instanceof Error ? error.message : String(error), fullyReconciled: false });
|
|
2473
|
+
}
|
|
2474
|
+
const results = [];
|
|
2475
|
+
for (const conversation of known.values()) {
|
|
2476
|
+
if (!isCurrentStorage(ctx)) {
|
|
2477
|
+
failures.push({ ...conversation, message: "Local storage account changed" });
|
|
2478
|
+
break;
|
|
2479
|
+
}
|
|
2480
|
+
try {
|
|
2481
|
+
results.push(await syncConversationMessages(conversation));
|
|
2482
|
+
} catch (error) {
|
|
2483
|
+
failures.push({ ...conversation, message: error instanceof Error ? error.message : String(error) });
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
if (failures.length)
|
|
2487
|
+
throw new LocalSyncError(results, failures);
|
|
2488
|
+
return results;
|
|
482
2489
|
}
|
|
483
2490
|
|
|
2491
|
+
// src/sdk/storage/index.ts
|
|
2492
|
+
var LocalStorageApis = { queryLocalMessages, queryFailedMessages, clearLocalMessages, getLocalStorageStatus, syncConversationMessages, syncLocalMessages };
|
|
2493
|
+
var storage_default = LocalStorageApis;
|
|
2494
|
+
|
|
484
2495
|
// src/apis/SdkQueryConversationPostApi.ts
|
|
2496
|
+
var postSdkQueryConversationListApiRequest = (data) => {
|
|
2497
|
+
return request({
|
|
2498
|
+
path: "/sdk/queryConversationList",
|
|
2499
|
+
method: "POST",
|
|
2500
|
+
data
|
|
2501
|
+
});
|
|
2502
|
+
};
|
|
485
2503
|
var postSdkQueryConversationApiRequest = (data) => {
|
|
486
2504
|
return request({
|
|
487
2505
|
path: "/sdk/queryConversation",
|
|
@@ -526,11 +2544,24 @@ var postSdkClearConversationUnreadMessageCountApiRequest = (data) => {
|
|
|
526
2544
|
});
|
|
527
2545
|
};
|
|
528
2546
|
|
|
529
|
-
// src/sdk/conversation.ts
|
|
530
|
-
|
|
531
|
-
|
|
2547
|
+
// src/sdk/conversation/conversation.ts
|
|
2548
|
+
function isConversationQueriedResult(value) {
|
|
2549
|
+
return !!value && typeof value === "object" && "conversation" in value;
|
|
2550
|
+
}
|
|
2551
|
+
async function queryConversationList(payload) {
|
|
2552
|
+
const response = await postSdkQueryConversationListApiRequest(
|
|
2553
|
+
payload
|
|
2554
|
+
);
|
|
532
2555
|
return unwrapSdkData(response) ?? [];
|
|
533
2556
|
}
|
|
2557
|
+
async function queryConversation(conversationID, conversationType) {
|
|
2558
|
+
const response = await postSdkQueryConversationApiRequest({
|
|
2559
|
+
conversationID,
|
|
2560
|
+
conversationType
|
|
2561
|
+
});
|
|
2562
|
+
const data = unwrapSdkData(response);
|
|
2563
|
+
return isConversationQueriedResult(data) ? data : { conversation: data };
|
|
2564
|
+
}
|
|
534
2565
|
async function deleteAllConversations() {
|
|
535
2566
|
const response = await postSdkDeleteAllConversationsApiRequest(
|
|
536
2567
|
{ config: true }
|
|
@@ -557,20 +2588,131 @@ async function clearConversationUnreadMessageCount(conversationID, conversationT
|
|
|
557
2588
|
return unwrapSdkResponse(response);
|
|
558
2589
|
}
|
|
559
2590
|
|
|
2591
|
+
// src/constants/call/ZIMCall.ts
|
|
2592
|
+
var ZIMCallType = /* @__PURE__ */ ((ZIMCallType2) => {
|
|
2593
|
+
ZIMCallType2["Audio"] = "audio";
|
|
2594
|
+
ZIMCallType2["Video"] = "video";
|
|
2595
|
+
return ZIMCallType2;
|
|
2596
|
+
})(ZIMCallType || {});
|
|
2597
|
+
var ZIMCallMode = /* @__PURE__ */ ((ZIMCallMode2) => {
|
|
2598
|
+
ZIMCallMode2["OneOnOne"] = "one_on_one";
|
|
2599
|
+
ZIMCallMode2["Group"] = "group";
|
|
2600
|
+
return ZIMCallMode2;
|
|
2601
|
+
})(ZIMCallMode || {});
|
|
2602
|
+
var ZIMCallConversationType = /* @__PURE__ */ ((ZIMCallConversationType2) => {
|
|
2603
|
+
ZIMCallConversationType2[ZIMCallConversationType2["Peer"] = 0] = "Peer";
|
|
2604
|
+
ZIMCallConversationType2[ZIMCallConversationType2["Group"] = 1] = "Group";
|
|
2605
|
+
return ZIMCallConversationType2;
|
|
2606
|
+
})(ZIMCallConversationType || {});
|
|
2607
|
+
var ZIMCallAction = /* @__PURE__ */ ((ZIMCallAction2) => {
|
|
2608
|
+
ZIMCallAction2["Invite"] = "invite";
|
|
2609
|
+
ZIMCallAction2["Accept"] = "accept";
|
|
2610
|
+
ZIMCallAction2["Reject"] = "reject";
|
|
2611
|
+
ZIMCallAction2["Cancel"] = "cancel";
|
|
2612
|
+
ZIMCallAction2["Hangup"] = "hangup";
|
|
2613
|
+
ZIMCallAction2["Timeout"] = "timeout";
|
|
2614
|
+
ZIMCallAction2["MemberJoined"] = "member_joined";
|
|
2615
|
+
ZIMCallAction2["MemberLeft"] = "member_left";
|
|
2616
|
+
ZIMCallAction2["MediaStateChanged"] = "media_state_changed";
|
|
2617
|
+
return ZIMCallAction2;
|
|
2618
|
+
})(ZIMCallAction || {});
|
|
2619
|
+
var ZIMCallEventEnum = /* @__PURE__ */ ((ZIMCallEventEnum2) => {
|
|
2620
|
+
ZIMCallEventEnum2["CallInvitationReceived"] = "callInvitationReceived";
|
|
2621
|
+
ZIMCallEventEnum2["CallAccepted"] = "callAccepted";
|
|
2622
|
+
ZIMCallEventEnum2["CallRejected"] = "callRejected";
|
|
2623
|
+
ZIMCallEventEnum2["CallCanceled"] = "callCanceled";
|
|
2624
|
+
ZIMCallEventEnum2["CallEnded"] = "callEnded";
|
|
2625
|
+
ZIMCallEventEnum2["CallTimeout"] = "callTimeout";
|
|
2626
|
+
ZIMCallEventEnum2["CallParticipantJoined"] = "callParticipantJoined";
|
|
2627
|
+
ZIMCallEventEnum2["CallParticipantLeft"] = "callParticipantLeft";
|
|
2628
|
+
ZIMCallEventEnum2["CallMediaStateChanged"] = "callMediaStateChanged";
|
|
2629
|
+
ZIMCallEventEnum2["CallConnectionStateChanged"] = "callConnectionStateChanged";
|
|
2630
|
+
ZIMCallEventEnum2["CallMediaTrackSubscribed"] = "callMediaTrackSubscribed";
|
|
2631
|
+
ZIMCallEventEnum2["CallMediaTrackUnsubscribed"] = "callMediaTrackUnsubscribed";
|
|
2632
|
+
return ZIMCallEventEnum2;
|
|
2633
|
+
})(ZIMCallEventEnum || {});
|
|
2634
|
+
var ZIM_LOCAL_CALL_EVENTS = /* @__PURE__ */ new Set([
|
|
2635
|
+
"callMediaStateChanged" /* CallMediaStateChanged */,
|
|
2636
|
+
"callConnectionStateChanged" /* CallConnectionStateChanged */,
|
|
2637
|
+
"callMediaTrackSubscribed" /* CallMediaTrackSubscribed */,
|
|
2638
|
+
"callMediaTrackUnsubscribed" /* CallMediaTrackUnsubscribed */
|
|
2639
|
+
]);
|
|
2640
|
+
|
|
2641
|
+
// src/sdk/call/callEvents.ts
|
|
2642
|
+
var listeners3 = /* @__PURE__ */ new Map();
|
|
2643
|
+
function onCallEvent(event, handler) {
|
|
2644
|
+
const handlers = listeners3.get(event) || /* @__PURE__ */ new Set();
|
|
2645
|
+
handlers.add(handler);
|
|
2646
|
+
listeners3.set(event, handlers);
|
|
2647
|
+
}
|
|
2648
|
+
function offCallEvent(event, handler) {
|
|
2649
|
+
if (!handler) {
|
|
2650
|
+
listeners3.delete(event);
|
|
2651
|
+
return;
|
|
2652
|
+
}
|
|
2653
|
+
const handlers = listeners3.get(event);
|
|
2654
|
+
if (!handlers)
|
|
2655
|
+
return;
|
|
2656
|
+
handlers.delete(handler);
|
|
2657
|
+
if (handlers.size === 0) {
|
|
2658
|
+
listeners3.delete(event);
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2661
|
+
function emitCallEvent(event, ...args) {
|
|
2662
|
+
listeners3.get(event)?.forEach((handler) => {
|
|
2663
|
+
try {
|
|
2664
|
+
const result = handler(...args);
|
|
2665
|
+
if (result && typeof result.then === "function")
|
|
2666
|
+
Promise.resolve(result).catch((error) => {
|
|
2667
|
+
console.error("[VanshiSdk] async call event handler failed:", event, error);
|
|
2668
|
+
});
|
|
2669
|
+
} catch (error) {
|
|
2670
|
+
console.error("[VanshiSdk] call event handler failed:", event, error);
|
|
2671
|
+
}
|
|
2672
|
+
});
|
|
2673
|
+
}
|
|
2674
|
+
|
|
560
2675
|
// src/sdk/initSocket.ts
|
|
561
2676
|
async function initSocket() {
|
|
562
2677
|
const baseUrl = getSocketUrl();
|
|
563
|
-
|
|
564
|
-
|
|
2678
|
+
try {
|
|
2679
|
+
if (!client_default.isConnected()) {
|
|
2680
|
+
await client_default.connect(baseUrl);
|
|
2681
|
+
}
|
|
2682
|
+
} catch (error) {
|
|
2683
|
+
throwSdkTransportError(error, "socket connect failed");
|
|
565
2684
|
}
|
|
566
2685
|
}
|
|
2686
|
+
function disconnectSocket() {
|
|
2687
|
+
client_default.disconnect();
|
|
2688
|
+
}
|
|
567
2689
|
function isSocketConnected() {
|
|
568
2690
|
return client_default.isConnected();
|
|
569
2691
|
}
|
|
2692
|
+
function resumeQueuedRequestsAfterLogin() {
|
|
2693
|
+
client_default.resumeQueuedRequestsAfterLogin();
|
|
2694
|
+
}
|
|
2695
|
+
function rejectQueuedRequestsAfterLoginFailure(reason) {
|
|
2696
|
+
client_default.rejectQueuedRequestsAfterLoginFailure(reason);
|
|
2697
|
+
}
|
|
570
2698
|
function on(event, handler) {
|
|
2699
|
+
if (STORAGE_EVENTS.has(event)) {
|
|
2700
|
+
onStorageEvent(event, handler);
|
|
2701
|
+
return;
|
|
2702
|
+
}
|
|
2703
|
+
if (ZIM_LOCAL_CALL_EVENTS.has(event)) {
|
|
2704
|
+
onCallEvent(event, handler);
|
|
2705
|
+
}
|
|
571
2706
|
client_default.on(event, handler);
|
|
572
2707
|
}
|
|
573
2708
|
function off(event, handler) {
|
|
2709
|
+
if (STORAGE_EVENTS.has(event)) {
|
|
2710
|
+
offStorageEvent(event, handler);
|
|
2711
|
+
return;
|
|
2712
|
+
}
|
|
2713
|
+
if (ZIM_LOCAL_CALL_EVENTS.has(event)) {
|
|
2714
|
+
offCallEvent(event, handler);
|
|
2715
|
+
}
|
|
574
2716
|
client_default.off(event, handler);
|
|
575
2717
|
}
|
|
576
2718
|
|
|
@@ -591,14 +2733,21 @@ var postSdkLogoutApiRequest = (data) => {
|
|
|
591
2733
|
};
|
|
592
2734
|
|
|
593
2735
|
// src/sdk/loginCore.ts
|
|
594
|
-
async function performLogin(payload, { requestLogin, setSession = setSdkSession, clearSession = clearSdkSession }) {
|
|
2736
|
+
async function performLogin(payload, { requestLogin, setSession = setSdkSession, clearSession = clearSdkSession, isCurrent = () => true }) {
|
|
595
2737
|
try {
|
|
596
2738
|
const resp = await requestLogin(payload);
|
|
597
|
-
if (
|
|
2739
|
+
if (!isCurrent())
|
|
2740
|
+
return false;
|
|
2741
|
+
const result = unwrapSdkDetailedData(resp);
|
|
2742
|
+
if (!result.success)
|
|
2743
|
+
throw new SdkRuntimeError(result).toObject();
|
|
2744
|
+
if (result.data) {
|
|
598
2745
|
setSession(payload.token);
|
|
599
2746
|
return true;
|
|
600
2747
|
}
|
|
601
2748
|
} catch (error) {
|
|
2749
|
+
if (!isCurrent())
|
|
2750
|
+
return false;
|
|
602
2751
|
clearSession();
|
|
603
2752
|
throw error;
|
|
604
2753
|
}
|
|
@@ -606,28 +2755,678 @@ async function performLogin(payload, { requestLogin, setSession = setSdkSession,
|
|
|
606
2755
|
return false;
|
|
607
2756
|
}
|
|
608
2757
|
|
|
2758
|
+
// src/sdk/call/callMedia.ts
|
|
2759
|
+
var import_livekit_client = require("livekit-client");
|
|
2760
|
+
var DEFAULT_JOIN_MEDIA_CONFIG = {
|
|
2761
|
+
audio: true,
|
|
2762
|
+
video: true
|
|
2763
|
+
};
|
|
2764
|
+
var LiveKitCallMediaAdapter = class {
|
|
2765
|
+
constructor() {
|
|
2766
|
+
this.localTracks = [];
|
|
2767
|
+
this.screenTracks = [];
|
|
2768
|
+
this.generation = 0;
|
|
2769
|
+
this.screenGeneration = 0;
|
|
2770
|
+
this.controls = /* @__PURE__ */ new Map();
|
|
2771
|
+
this.disconnecting = /* @__PURE__ */ new Set();
|
|
2772
|
+
}
|
|
2773
|
+
assertRoom(room, generation3) {
|
|
2774
|
+
if (this.room !== room || this.generation !== generation3)
|
|
2775
|
+
throw new Error("Media operation canceled");
|
|
2776
|
+
}
|
|
2777
|
+
stopTracks(tracks) {
|
|
2778
|
+
for (const track of tracks) {
|
|
2779
|
+
try {
|
|
2780
|
+
track.stop();
|
|
2781
|
+
} catch {
|
|
2782
|
+
}
|
|
2783
|
+
try {
|
|
2784
|
+
track.detach();
|
|
2785
|
+
} catch {
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
async releaseRoom() {
|
|
2790
|
+
const room = this.room;
|
|
2791
|
+
this.room = void 0;
|
|
2792
|
+
this.callID = void 0;
|
|
2793
|
+
this.stopTracks([...this.localTracks, ...this.screenTracks]);
|
|
2794
|
+
this.localTracks = [];
|
|
2795
|
+
this.screenTracks = [];
|
|
2796
|
+
this.controls.clear();
|
|
2797
|
+
if (room) {
|
|
2798
|
+
room.removeAllListeners();
|
|
2799
|
+
const completion = Promise.resolve(room.disconnect());
|
|
2800
|
+
this.disconnecting.add(completion);
|
|
2801
|
+
try {
|
|
2802
|
+
await completion;
|
|
2803
|
+
} finally {
|
|
2804
|
+
this.disconnecting.delete(completion);
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
await Promise.all([...this.disconnecting]);
|
|
2808
|
+
}
|
|
2809
|
+
control(key, operation) {
|
|
2810
|
+
const previous = this.controls.get(key) || Promise.resolve();
|
|
2811
|
+
const result = previous.catch(() => {
|
|
2812
|
+
}).then(operation);
|
|
2813
|
+
this.controls.set(key, result);
|
|
2814
|
+
void result.finally(() => {
|
|
2815
|
+
if (this.controls.get(key) === result)
|
|
2816
|
+
this.controls.delete(key);
|
|
2817
|
+
}).catch(() => {
|
|
2818
|
+
});
|
|
2819
|
+
return result;
|
|
2820
|
+
}
|
|
2821
|
+
async joinMedia(config, connectOptions) {
|
|
2822
|
+
const generation3 = ++this.generation;
|
|
2823
|
+
this.screenGeneration++;
|
|
2824
|
+
await this.releaseRoom();
|
|
2825
|
+
if (generation3 !== this.generation)
|
|
2826
|
+
throw new Error("Media operation canceled");
|
|
2827
|
+
const liveKit = normalizeLiveKitInfo(config);
|
|
2828
|
+
if (!liveKit.token) {
|
|
2829
|
+
throwSdkRuntimeError({
|
|
2830
|
+
message: "LiveKit token is required",
|
|
2831
|
+
raw: config
|
|
2832
|
+
});
|
|
2833
|
+
}
|
|
2834
|
+
const liveKitUrl = liveKit.livekitUrl || liveKit.liveKitUrl || config.livekitUrl || config.liveKitUrl;
|
|
2835
|
+
if (!liveKitUrl) {
|
|
2836
|
+
throwSdkRuntimeError({
|
|
2837
|
+
message: "LiveKit URL is required",
|
|
2838
|
+
raw: config
|
|
2839
|
+
});
|
|
2840
|
+
}
|
|
2841
|
+
const room = new import_livekit_client.Room({
|
|
2842
|
+
adaptiveStream: true,
|
|
2843
|
+
dynacast: true
|
|
2844
|
+
});
|
|
2845
|
+
this.callID = config.callID;
|
|
2846
|
+
this.room = room;
|
|
2847
|
+
this.bindRoomEvents(room);
|
|
2848
|
+
try {
|
|
2849
|
+
await room.connect(liveKitUrl, liveKit.token, connectOptions);
|
|
2850
|
+
this.assertRoom(room, generation3);
|
|
2851
|
+
await this.publishInitialTracks(config, room, generation3);
|
|
2852
|
+
this.assertRoom(room, generation3);
|
|
2853
|
+
return { callID: config.callID, room, localTracks: [...this.localTracks] };
|
|
2854
|
+
} catch (error) {
|
|
2855
|
+
try {
|
|
2856
|
+
if (this.room === room && this.generation === generation3)
|
|
2857
|
+
await this.leaveMedia();
|
|
2858
|
+
else {
|
|
2859
|
+
room.removeAllListeners();
|
|
2860
|
+
await room.disconnect();
|
|
2861
|
+
}
|
|
2862
|
+
} catch {
|
|
2863
|
+
}
|
|
2864
|
+
throw error;
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
async leaveMedia() {
|
|
2868
|
+
this.generation++;
|
|
2869
|
+
this.screenGeneration++;
|
|
2870
|
+
await this.releaseRoom();
|
|
2871
|
+
}
|
|
2872
|
+
getRoom() {
|
|
2873
|
+
return this.room;
|
|
2874
|
+
}
|
|
2875
|
+
getLocalTracks() {
|
|
2876
|
+
return [...this.localTracks];
|
|
2877
|
+
}
|
|
2878
|
+
getMediaState() {
|
|
2879
|
+
return {
|
|
2880
|
+
microphoneEnabled: this.localTracks.some((track) => track.kind === import_livekit_client.Track.Kind.Audio && !track.isMuted),
|
|
2881
|
+
cameraEnabled: this.localTracks.some((track) => track.kind === import_livekit_client.Track.Kind.Video && track.source !== import_livekit_client.Track.Source.ScreenShare && !track.isMuted),
|
|
2882
|
+
screenShareEnabled: this.screenTracks.length > 0
|
|
2883
|
+
};
|
|
2884
|
+
}
|
|
2885
|
+
setMicrophoneEnabled(enabled) {
|
|
2886
|
+
return this.setDeviceEnabled("microphone", enabled);
|
|
2887
|
+
}
|
|
2888
|
+
setCameraEnabled(enabled) {
|
|
2889
|
+
return this.setDeviceEnabled("camera", enabled);
|
|
2890
|
+
}
|
|
2891
|
+
setDeviceEnabled(device, enabled) {
|
|
2892
|
+
const room = this.room;
|
|
2893
|
+
const generation3 = this.generation;
|
|
2894
|
+
return this.control(device, async () => {
|
|
2895
|
+
if (!room)
|
|
2896
|
+
throw new Error("LiveKit room is not joined");
|
|
2897
|
+
this.assertRoom(room, generation3);
|
|
2898
|
+
const kind = device === "microphone" ? import_livekit_client.Track.Kind.Audio : import_livekit_client.Track.Kind.Video;
|
|
2899
|
+
let track = this.localTracks.find((item) => item.kind === kind && item.source !== import_livekit_client.Track.Source.ScreenShare);
|
|
2900
|
+
if (!track && enabled) {
|
|
2901
|
+
track = await this.acquireTrack(device === "microphone" ? import_livekit_client.createLocalAudioTrack : import_livekit_client.createLocalVideoTrack, room, generation3);
|
|
2902
|
+
}
|
|
2903
|
+
if (track)
|
|
2904
|
+
await setLocalTrackEnabled(track, enabled);
|
|
2905
|
+
this.assertRoom(room, generation3);
|
|
2906
|
+
return this.emitMediaState();
|
|
2907
|
+
});
|
|
2908
|
+
}
|
|
2909
|
+
startScreenShare() {
|
|
2910
|
+
const room = this.room;
|
|
2911
|
+
const generation3 = this.generation;
|
|
2912
|
+
const screenGeneration = this.screenGeneration;
|
|
2913
|
+
return this.control("screen", async () => {
|
|
2914
|
+
if (!room)
|
|
2915
|
+
throw new Error("LiveKit room is not joined");
|
|
2916
|
+
this.assertRoom(room, generation3);
|
|
2917
|
+
if (this.screenTracks.length)
|
|
2918
|
+
return { tracks: [...this.screenTracks] };
|
|
2919
|
+
let tracks = [];
|
|
2920
|
+
const assertActive = () => {
|
|
2921
|
+
this.assertRoom(room, generation3);
|
|
2922
|
+
if (screenGeneration !== this.screenGeneration)
|
|
2923
|
+
throw new Error("Screen share canceled");
|
|
2924
|
+
};
|
|
2925
|
+
try {
|
|
2926
|
+
assertActive();
|
|
2927
|
+
tracks = await (0, import_livekit_client.createLocalScreenTracks)({ audio: true, video: true });
|
|
2928
|
+
assertActive();
|
|
2929
|
+
this.screenTracks = tracks;
|
|
2930
|
+
for (const track of tracks) {
|
|
2931
|
+
await room.localParticipant.publishTrack(track);
|
|
2932
|
+
assertActive();
|
|
2933
|
+
}
|
|
2934
|
+
this.emitMediaState();
|
|
2935
|
+
return { tracks: [...tracks] };
|
|
2936
|
+
} catch (error) {
|
|
2937
|
+
this.stopTracks(tracks);
|
|
2938
|
+
await Promise.allSettled(tracks.map((track) => room.localParticipant.unpublishTrack(track)));
|
|
2939
|
+
if (this.room === room)
|
|
2940
|
+
this.screenTracks = this.screenTracks.filter((track) => !tracks.includes(track));
|
|
2941
|
+
throw error;
|
|
2942
|
+
}
|
|
2943
|
+
});
|
|
2944
|
+
}
|
|
2945
|
+
async stopScreenShare() {
|
|
2946
|
+
this.screenGeneration++;
|
|
2947
|
+
const room = this.room;
|
|
2948
|
+
const tracks = this.screenTracks;
|
|
2949
|
+
this.screenTracks = [];
|
|
2950
|
+
this.stopTracks(tracks);
|
|
2951
|
+
await Promise.all(tracks.map((track) => room?.localParticipant.unpublishTrack(track)));
|
|
2952
|
+
return this.emitMediaState();
|
|
2953
|
+
}
|
|
2954
|
+
bindRoomEvents(room) {
|
|
2955
|
+
room.on(import_livekit_client.RoomEvent.ConnectionStateChanged, (state) => {
|
|
2956
|
+
emitCallEvent("callConnectionStateChanged" /* CallConnectionStateChanged */, {
|
|
2957
|
+
callID: this.callID,
|
|
2958
|
+
state
|
|
2959
|
+
});
|
|
2960
|
+
}).on(import_livekit_client.RoomEvent.TrackSubscribed, (track, publication, participant) => {
|
|
2961
|
+
emitCallEvent("callMediaTrackSubscribed" /* CallMediaTrackSubscribed */, {
|
|
2962
|
+
callID: this.callID,
|
|
2963
|
+
track,
|
|
2964
|
+
publication,
|
|
2965
|
+
participantID: participant.identity,
|
|
2966
|
+
participantName: participant.name
|
|
2967
|
+
});
|
|
2968
|
+
}).on(import_livekit_client.RoomEvent.TrackUnsubscribed, (track, publication, participant) => {
|
|
2969
|
+
emitCallEvent("callMediaTrackUnsubscribed" /* CallMediaTrackUnsubscribed */, {
|
|
2970
|
+
callID: this.callID,
|
|
2971
|
+
track,
|
|
2972
|
+
publication,
|
|
2973
|
+
participantID: participant.identity,
|
|
2974
|
+
participantName: participant.name
|
|
2975
|
+
});
|
|
2976
|
+
});
|
|
2977
|
+
}
|
|
2978
|
+
async publishInitialTracks(config, room, generation3) {
|
|
2979
|
+
const merged = { ...DEFAULT_JOIN_MEDIA_CONFIG, ...config };
|
|
2980
|
+
const ensureTrack = (device) => this.control(device, async () => {
|
|
2981
|
+
this.assertRoom(room, generation3);
|
|
2982
|
+
const kind = device === "microphone" ? import_livekit_client.Track.Kind.Audio : import_livekit_client.Track.Kind.Video;
|
|
2983
|
+
if (!this.localTracks.some((track) => track.kind === kind && track.source !== import_livekit_client.Track.Source.ScreenShare)) {
|
|
2984
|
+
await this.acquireTrack(device === "microphone" ? import_livekit_client.createLocalAudioTrack : import_livekit_client.createLocalVideoTrack, room, generation3);
|
|
2985
|
+
}
|
|
2986
|
+
});
|
|
2987
|
+
if (merged.audio)
|
|
2988
|
+
await ensureTrack("microphone");
|
|
2989
|
+
if (merged.video)
|
|
2990
|
+
await ensureTrack("camera");
|
|
2991
|
+
this.assertRoom(room, generation3);
|
|
2992
|
+
this.emitMediaState();
|
|
2993
|
+
}
|
|
2994
|
+
async acquireTrack(create, room, generation3) {
|
|
2995
|
+
this.assertRoom(room, generation3);
|
|
2996
|
+
const track = await create();
|
|
2997
|
+
try {
|
|
2998
|
+
this.assertRoom(room, generation3);
|
|
2999
|
+
this.localTracks.push(track);
|
|
3000
|
+
await room.localParticipant.publishTrack(track);
|
|
3001
|
+
this.assertRoom(room, generation3);
|
|
3002
|
+
return track;
|
|
3003
|
+
} catch (error) {
|
|
3004
|
+
this.stopTracks([track]);
|
|
3005
|
+
this.localTracks = this.localTracks.filter((item) => item !== track);
|
|
3006
|
+
try {
|
|
3007
|
+
await room.localParticipant.unpublishTrack(track);
|
|
3008
|
+
} catch {
|
|
3009
|
+
}
|
|
3010
|
+
throw error;
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
emitMediaState() {
|
|
3014
|
+
const state = this.getMediaState();
|
|
3015
|
+
emitCallEvent("callMediaStateChanged" /* CallMediaStateChanged */, {
|
|
3016
|
+
callID: this.callID,
|
|
3017
|
+
...state
|
|
3018
|
+
});
|
|
3019
|
+
return state;
|
|
3020
|
+
}
|
|
3021
|
+
};
|
|
3022
|
+
function normalizeLiveKitInfo(config) {
|
|
3023
|
+
return {
|
|
3024
|
+
...config.liveKit,
|
|
3025
|
+
token: config.token || config.liveKit?.token || "",
|
|
3026
|
+
livekitUrl: config.livekitUrl || config.liveKit?.livekitUrl,
|
|
3027
|
+
liveKitUrl: config.liveKitUrl || config.liveKit?.liveKitUrl,
|
|
3028
|
+
roomName: config.roomName || config.liveKit?.roomName
|
|
3029
|
+
};
|
|
3030
|
+
}
|
|
3031
|
+
function setLocalTrackEnabled(track, enabled) {
|
|
3032
|
+
return enabled ? track.unmute() : track.mute();
|
|
3033
|
+
}
|
|
3034
|
+
var liveKitCallMediaAdapter = new LiveKitCallMediaAdapter();
|
|
3035
|
+
onSessionInvalidated(() => {
|
|
3036
|
+
void liveKitCallMediaAdapter.leaveMedia().catch((error) => console.error("[VanshiSdk] media cleanup failed:", error));
|
|
3037
|
+
});
|
|
3038
|
+
|
|
3039
|
+
// src/sdk/call/call.ts
|
|
3040
|
+
var CALL_SOCKET_EVENTS = {
|
|
3041
|
+
create: "call/create",
|
|
3042
|
+
inviteMembers: "call/inviteMembers",
|
|
3043
|
+
accept: "call/accept",
|
|
3044
|
+
reject: "call/reject",
|
|
3045
|
+
cancel: "call/cancel",
|
|
3046
|
+
hangup: "call/hangup",
|
|
3047
|
+
members: "call/members",
|
|
3048
|
+
token: "call/token",
|
|
3049
|
+
hasOngoingCall: "call/hasOngoingCall"
|
|
3050
|
+
};
|
|
3051
|
+
function callInvite(config) {
|
|
3052
|
+
const conversationType = normalizeCallConversationType(
|
|
3053
|
+
config.conversationType
|
|
3054
|
+
);
|
|
3055
|
+
return callRequest(CALL_SOCKET_EVENTS.create, {
|
|
3056
|
+
conversationID: config.conversationID,
|
|
3057
|
+
conversationType,
|
|
3058
|
+
invitees: config.invitees,
|
|
3059
|
+
callType: config.callType,
|
|
3060
|
+
mode: config.mode || (conversationType === 1 /* Group */ ? "group" /* Group */ : "one_on_one" /* OneOnOne */),
|
|
3061
|
+
...config.timeout !== void 0 ? { timeout: config.timeout } : {},
|
|
3062
|
+
...config.extendedData !== void 0 ? { extendedData: config.extendedData } : {}
|
|
3063
|
+
});
|
|
3064
|
+
}
|
|
3065
|
+
function callInviteMembers(params) {
|
|
3066
|
+
return callRequest(CALL_SOCKET_EVENTS.inviteMembers, {
|
|
3067
|
+
...getCallBasePayload(params),
|
|
3068
|
+
invitees: params.invitees
|
|
3069
|
+
});
|
|
3070
|
+
}
|
|
3071
|
+
function callAccept(params) {
|
|
3072
|
+
return callRequest(
|
|
3073
|
+
CALL_SOCKET_EVENTS.accept,
|
|
3074
|
+
getCallBasePayload(params)
|
|
3075
|
+
);
|
|
3076
|
+
}
|
|
3077
|
+
function callReject(params) {
|
|
3078
|
+
return callRequest(
|
|
3079
|
+
CALL_SOCKET_EVENTS.reject,
|
|
3080
|
+
getCallBasePayload(params)
|
|
3081
|
+
);
|
|
3082
|
+
}
|
|
3083
|
+
function callCancel(params) {
|
|
3084
|
+
return callRequest(
|
|
3085
|
+
CALL_SOCKET_EVENTS.cancel,
|
|
3086
|
+
getCallBasePayload(params)
|
|
3087
|
+
);
|
|
3088
|
+
}
|
|
3089
|
+
async function callHangup(params) {
|
|
3090
|
+
try {
|
|
3091
|
+
const result = await callRequest(
|
|
3092
|
+
CALL_SOCKET_EVENTS.hangup,
|
|
3093
|
+
getCallBasePayload(params)
|
|
3094
|
+
);
|
|
3095
|
+
await liveKitCallMediaAdapter.leaveMedia();
|
|
3096
|
+
return result;
|
|
3097
|
+
} catch (error) {
|
|
3098
|
+
throwCallTransportError(error, "call hangup failed");
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
function callQueryMembers(params) {
|
|
3102
|
+
return callRequest(
|
|
3103
|
+
CALL_SOCKET_EVENTS.members,
|
|
3104
|
+
getCallBasePayload(params)
|
|
3105
|
+
);
|
|
3106
|
+
}
|
|
3107
|
+
function callHasOngoingCall(params) {
|
|
3108
|
+
return callRequest(CALL_SOCKET_EVENTS.hasOngoingCall, {
|
|
3109
|
+
groupId: params.groupId
|
|
3110
|
+
});
|
|
3111
|
+
}
|
|
3112
|
+
function callGetLiveKitToken(params) {
|
|
3113
|
+
return callRequest(CALL_SOCKET_EVENTS.token, {
|
|
3114
|
+
...getCallBasePayload(params),
|
|
3115
|
+
...params.roomName !== void 0 ? { roomName: params.roomName } : {}
|
|
3116
|
+
});
|
|
3117
|
+
}
|
|
3118
|
+
async function callJoinMedia(config, connectOptions) {
|
|
3119
|
+
const session = captureSession();
|
|
3120
|
+
try {
|
|
3121
|
+
const liveKit = hasLiveKitToken(config) ? {
|
|
3122
|
+
...config.liveKit,
|
|
3123
|
+
token: config.token || config.liveKit?.token || "",
|
|
3124
|
+
livekitUrl: config.livekitUrl || config.liveKit?.livekitUrl,
|
|
3125
|
+
liveKitUrl: config.liveKitUrl || config.liveKit?.liveKitUrl,
|
|
3126
|
+
roomName: config.roomName || config.liveKit?.roomName
|
|
3127
|
+
} : await callGetLiveKitToken(config);
|
|
3128
|
+
assertCurrentSession(session);
|
|
3129
|
+
return await liveKitCallMediaAdapter.joinMedia(
|
|
3130
|
+
{ ...config, liveKit },
|
|
3131
|
+
connectOptions
|
|
3132
|
+
);
|
|
3133
|
+
} catch (error) {
|
|
3134
|
+
throwCallTransportError(error, "call media join failed");
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
async function callLeaveMedia() {
|
|
3138
|
+
try {
|
|
3139
|
+
await liveKitCallMediaAdapter.leaveMedia();
|
|
3140
|
+
} catch (error) {
|
|
3141
|
+
throwCallTransportError(error, "call media leave failed");
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
async function callSetMicrophoneEnabled(enabled) {
|
|
3145
|
+
try {
|
|
3146
|
+
return await liveKitCallMediaAdapter.setMicrophoneEnabled(enabled);
|
|
3147
|
+
} catch (error) {
|
|
3148
|
+
throwCallTransportError(error, "microphone state update failed");
|
|
3149
|
+
}
|
|
3150
|
+
}
|
|
3151
|
+
async function callSetCameraEnabled(enabled) {
|
|
3152
|
+
try {
|
|
3153
|
+
return await liveKitCallMediaAdapter.setCameraEnabled(enabled);
|
|
3154
|
+
} catch (error) {
|
|
3155
|
+
throwCallTransportError(error, "camera state update failed");
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
async function callStartScreenShare() {
|
|
3159
|
+
try {
|
|
3160
|
+
return await liveKitCallMediaAdapter.startScreenShare();
|
|
3161
|
+
} catch (error) {
|
|
3162
|
+
throwCallTransportError(error, "screen share start failed");
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
async function callStopScreenShare() {
|
|
3166
|
+
try {
|
|
3167
|
+
return await liveKitCallMediaAdapter.stopScreenShare();
|
|
3168
|
+
} catch (error) {
|
|
3169
|
+
throwCallTransportError(error, "screen share stop failed");
|
|
3170
|
+
}
|
|
3171
|
+
}
|
|
3172
|
+
function callGetMediaState() {
|
|
3173
|
+
return liveKitCallMediaAdapter.getMediaState();
|
|
3174
|
+
}
|
|
3175
|
+
function callGetRoom() {
|
|
3176
|
+
return liveKitCallMediaAdapter.getRoom();
|
|
3177
|
+
}
|
|
3178
|
+
function hasLiveKitToken(config) {
|
|
3179
|
+
return Boolean(config.liveKit?.token || config.token);
|
|
3180
|
+
}
|
|
3181
|
+
function normalizeCallConversationType(conversationType) {
|
|
3182
|
+
return Number(conversationType) === 2 ? 1 /* Group */ : Number(conversationType);
|
|
3183
|
+
}
|
|
3184
|
+
function getCallBasePayload(params) {
|
|
3185
|
+
return {
|
|
3186
|
+
callID: params.callID,
|
|
3187
|
+
...params.extendedData !== void 0 ? { extendedData: params.extendedData } : {}
|
|
3188
|
+
};
|
|
3189
|
+
}
|
|
3190
|
+
async function callRequest(event, payload) {
|
|
3191
|
+
try {
|
|
3192
|
+
return unwrapSdkData(
|
|
3193
|
+
await request({
|
|
3194
|
+
path: `/sdk/${event}`,
|
|
3195
|
+
method: "POST",
|
|
3196
|
+
data: payload
|
|
3197
|
+
})
|
|
3198
|
+
);
|
|
3199
|
+
} catch (error) {
|
|
3200
|
+
throwCallTransportError(error);
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3203
|
+
function throwCallTransportError(error, fallbackMessage = "call request failed") {
|
|
3204
|
+
if (isSdkRuntimeErrorObject(error)) {
|
|
3205
|
+
throw error;
|
|
3206
|
+
}
|
|
3207
|
+
throwSdkTransportError(error, fallbackMessage);
|
|
3208
|
+
}
|
|
3209
|
+
var call_default = {
|
|
3210
|
+
callInvite,
|
|
3211
|
+
callInviteMembers,
|
|
3212
|
+
callAccept,
|
|
3213
|
+
callReject,
|
|
3214
|
+
callCancel,
|
|
3215
|
+
callHangup,
|
|
3216
|
+
callQueryMembers,
|
|
3217
|
+
callHasOngoingCall,
|
|
3218
|
+
callGetLiveKitToken,
|
|
3219
|
+
callJoinMedia,
|
|
3220
|
+
callLeaveMedia,
|
|
3221
|
+
callSetMicrophoneEnabled,
|
|
3222
|
+
callSetCameraEnabled,
|
|
3223
|
+
callStartScreenShare,
|
|
3224
|
+
callStopScreenShare,
|
|
3225
|
+
callGetMediaState,
|
|
3226
|
+
callGetRoom
|
|
3227
|
+
};
|
|
3228
|
+
|
|
609
3229
|
// src/sdk/login.ts
|
|
610
|
-
async function
|
|
3230
|
+
async function loginInternal(payload, session) {
|
|
611
3231
|
return performLogin(payload, {
|
|
612
|
-
requestLogin: postSdkLoginApiRequest
|
|
3232
|
+
requestLogin: postSdkLoginApiRequest,
|
|
3233
|
+
isCurrent: () => isCurrentSession(session),
|
|
3234
|
+
clearSession: () => {
|
|
3235
|
+
}
|
|
3236
|
+
});
|
|
3237
|
+
}
|
|
3238
|
+
async function login(payload) {
|
|
3239
|
+
clearSdkSession();
|
|
3240
|
+
const attempt = beginAuthentication();
|
|
3241
|
+
setSdkUserID(payload.userID || payload.userId);
|
|
3242
|
+
if (payload.userId?.trim())
|
|
3243
|
+
beginLoginMessageBuffer(attempt);
|
|
3244
|
+
try {
|
|
3245
|
+
const success = await loginInternal({ token: payload.token }, attempt);
|
|
3246
|
+
if (!isCurrentSession(attempt))
|
|
3247
|
+
return false;
|
|
3248
|
+
if (!success) {
|
|
3249
|
+
clearSdkSession();
|
|
3250
|
+
rejectQueuedRequestsAfterLoginFailure();
|
|
3251
|
+
return false;
|
|
3252
|
+
}
|
|
3253
|
+
if (payload.userId?.trim()) {
|
|
3254
|
+
await openLocalStorage(payload.userId.trim(), JSON.stringify([getSocketUrl(), getUploadUrl()]));
|
|
3255
|
+
if (!isCurrentSession(attempt))
|
|
3256
|
+
return false;
|
|
3257
|
+
await flushLoginMessageBuffer(attempt);
|
|
3258
|
+
}
|
|
3259
|
+
if (!isCurrentSession(attempt))
|
|
3260
|
+
return false;
|
|
3261
|
+
finishAuthentication(attempt);
|
|
3262
|
+
resumeQueuedRequestsAfterLogin();
|
|
3263
|
+
return true;
|
|
3264
|
+
} catch (error) {
|
|
3265
|
+
if (!isCurrentSession(attempt))
|
|
3266
|
+
return false;
|
|
3267
|
+
clearSdkSession();
|
|
3268
|
+
rejectQueuedRequestsAfterLoginFailure(error);
|
|
3269
|
+
throw error;
|
|
3270
|
+
} finally {
|
|
3271
|
+
discardLoginMessageBuffer(attempt);
|
|
3272
|
+
finishAuthentication(attempt);
|
|
3273
|
+
}
|
|
3274
|
+
}
|
|
3275
|
+
registerReconnectLoginHandler((token) => loginInternal({ token }, captureSession()));
|
|
3276
|
+
function isLogoutFinalizationError(error) {
|
|
3277
|
+
const message = getSdkErrorMessageFromUnknown(error, "");
|
|
3278
|
+
const code = getSdkErrorCode(error);
|
|
3279
|
+
return code === 3 || code === "3" || code === 4 || code === "4" || code === 303 || code === "303" || /ack timeout|request timeout|socket not connected|socket not initialized|disconnected|client disconnected|connect timeout|reconnect failed|restore login failed|socket operation queue is full|认证失败|token验证失败/i.test(message);
|
|
3280
|
+
}
|
|
3281
|
+
async function logout(disconnect = false) {
|
|
3282
|
+
clearSdkSession();
|
|
3283
|
+
const attempt = captureSession();
|
|
3284
|
+
try {
|
|
3285
|
+
try {
|
|
3286
|
+
await callLeaveMedia();
|
|
3287
|
+
} catch (error) {
|
|
3288
|
+
console.error("[VanshiSdk] leave media during logout failed:", error);
|
|
3289
|
+
}
|
|
3290
|
+
if (!isCurrentSession(attempt))
|
|
3291
|
+
return false;
|
|
3292
|
+
const response = await postSdkLogoutApiRequest({});
|
|
3293
|
+
if (!isCurrentSession(attempt))
|
|
3294
|
+
return false;
|
|
3295
|
+
const result = unwrapSdkResponse(response);
|
|
3296
|
+
return Boolean(result.data) || isSuccessCode(result.code);
|
|
3297
|
+
} catch (error) {
|
|
3298
|
+
if (!isCurrentSession(attempt))
|
|
3299
|
+
return false;
|
|
3300
|
+
if (isLogoutFinalizationError(error)) {
|
|
3301
|
+
return false;
|
|
3302
|
+
}
|
|
3303
|
+
throw error;
|
|
3304
|
+
} finally {
|
|
3305
|
+
if (isCurrentSession(attempt)) {
|
|
3306
|
+
clearSdkSession();
|
|
3307
|
+
if (disconnect)
|
|
3308
|
+
disconnectSocket();
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
|
|
3313
|
+
// src/sdk/storage/history.ts
|
|
3314
|
+
var import_dexie2 = __toESM(require("dexie"), 1);
|
|
3315
|
+
async function mergeHistoryWithLocalMessages(ctx, query, result) {
|
|
3316
|
+
if (!Array.isArray(result?.messageList))
|
|
3317
|
+
return result;
|
|
3318
|
+
if (!ctx)
|
|
3319
|
+
return filterInvalidReplyMessages(result);
|
|
3320
|
+
if (!isCurrentStorage(ctx))
|
|
3321
|
+
throw new Error("Local storage account changed during history query");
|
|
3322
|
+
await ctx.pending;
|
|
3323
|
+
const merged = await storageWork(ctx, async (ctx2) => {
|
|
3324
|
+
const key = conversationKey(query.conversationID, query.conversationType);
|
|
3325
|
+
return ctx2.db.transaction("r", ctx2.db.messages, async () => {
|
|
3326
|
+
const serverIDs = result.messageList.filter((row) => row.messageID).map((row) => [key, String(row.messageID)]);
|
|
3327
|
+
const clientIDs = result.messageList.filter((row) => row.clientBizId).map((row) => [key, String(row.clientBizId)]);
|
|
3328
|
+
const rowsByID = /* @__PURE__ */ new Map();
|
|
3329
|
+
const include = (rows2) => rows2.forEach((row) => rowsByID.set(row.localID, row));
|
|
3330
|
+
if (serverIDs.length)
|
|
3331
|
+
include(await ctx2.db.messages.where("[conversationKey+messageID]").anyOf(serverIDs).toArray());
|
|
3332
|
+
if (clientIDs.length)
|
|
3333
|
+
include(await ctx2.db.messages.where("[conversationKey+clientBizId]").anyOf(clientIDs).toArray());
|
|
3334
|
+
if (!query.config?.nextMessage) {
|
|
3335
|
+
const timestamps = result.messageList.map((row) => Number(row.timestamp)).filter(Number.isFinite);
|
|
3336
|
+
const oldest = timestamps.reduce((min, value) => Math.min(min, value), Infinity);
|
|
3337
|
+
include(await ctx2.db.messages.where("[conversationKey+timestamp]").between([key, timestamps.length ? oldest : import_dexie2.default.minKey], [key, import_dexie2.default.maxKey], true, true).toArray());
|
|
3338
|
+
include(await ctx2.db.messages.where("[conversationKey+sendState]").anyOf([[key, 0], [key, 2]]).toArray());
|
|
3339
|
+
include(await ctx2.db.messages.where("[conversationKey+hasServerID]").equals([key, 0]).toArray());
|
|
3340
|
+
}
|
|
3341
|
+
const rows = [...rowsByID.values()];
|
|
3342
|
+
const byServer = new Map(rows.filter((row) => row.messageID).map((row) => [String(row.messageID), row]));
|
|
3343
|
+
const byClient = new Map(rows.filter((row) => row.clientBizId).map((row) => [String(row.clientBizId), row]));
|
|
3344
|
+
const included = /* @__PURE__ */ new Set();
|
|
3345
|
+
const messageList = [];
|
|
3346
|
+
const add = (message) => {
|
|
3347
|
+
const identities = [
|
|
3348
|
+
message.localID && `local:${message.localID}`,
|
|
3349
|
+
message.messageID && `server:${message.messageID}`,
|
|
3350
|
+
message.clientBizId && `client:${message.clientBizId}`
|
|
3351
|
+
].filter(Boolean);
|
|
3352
|
+
if (identities.some((id) => included.has(id)))
|
|
3353
|
+
return;
|
|
3354
|
+
identities.forEach((id) => included.add(id));
|
|
3355
|
+
messageList.push(message);
|
|
3356
|
+
};
|
|
3357
|
+
const first = Number(result.messageList[0]?.timestamp);
|
|
3358
|
+
const last = Number(result.messageList[result.messageList.length - 1]?.timestamp);
|
|
3359
|
+
const descending = Number.isFinite(first) && Number.isFinite(last) && first !== last ? first > last : query.config?.reverse !== false;
|
|
3360
|
+
for (const message of result.messageList) {
|
|
3361
|
+
const client = byClient.get(String(message.clientBizId));
|
|
3362
|
+
const local = byServer.get(String(message.messageID)) || (client && (!message.messageID || !client.messageID || String(message.messageID) === client.messageID) ? client : void 0);
|
|
3363
|
+
if (local?.deleted)
|
|
3364
|
+
continue;
|
|
3365
|
+
if (isSelfReferencingReply(message)) {
|
|
3366
|
+
if (local)
|
|
3367
|
+
add(displayMessage(local));
|
|
3368
|
+
continue;
|
|
3369
|
+
}
|
|
3370
|
+
if (local?.revoked) {
|
|
3371
|
+
add(displayMessage(local));
|
|
3372
|
+
continue;
|
|
3373
|
+
}
|
|
3374
|
+
add(local ? { ...message, ...displayMessage(local) } : message);
|
|
3375
|
+
}
|
|
3376
|
+
if (!query.config?.nextMessage) {
|
|
3377
|
+
const timestamps = result.messageList.map((message) => Number(message.timestamp)).filter(Number.isFinite);
|
|
3378
|
+
const oldest = timestamps.reduce((min, timestamp) => Math.min(min, timestamp), Infinity);
|
|
3379
|
+
for (const row of rows) {
|
|
3380
|
+
if (!row.deleted && (row.sendState !== 1 || !row.messageID || !timestamps.length || row.timestamp >= oldest))
|
|
3381
|
+
add(displayMessage(row));
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
messageList.sort((a, b) => {
|
|
3385
|
+
const timeA = Number(a.timestamp) || 0;
|
|
3386
|
+
const timeB = Number(b.timestamp) || 0;
|
|
3387
|
+
const keyA = String(a.localID || a.messageID || a.clientBizId || "");
|
|
3388
|
+
const keyB = String(b.localID || b.messageID || b.clientBizId || "");
|
|
3389
|
+
return (descending ? -1 : 1) * (timeA - timeB || compareOrderKey(a.orderKey, b.orderKey) || keyA.localeCompare(keyB));
|
|
3390
|
+
});
|
|
3391
|
+
return { ...result, messageList };
|
|
3392
|
+
});
|
|
613
3393
|
});
|
|
3394
|
+
if (!isCurrentStorage(ctx))
|
|
3395
|
+
throw new Error("Local storage account changed during history query");
|
|
3396
|
+
return merged || filterInvalidReplyMessages(result);
|
|
3397
|
+
}
|
|
3398
|
+
function compareOrderKey(a, b) {
|
|
3399
|
+
const validA = /^\d+$/.test(String(a));
|
|
3400
|
+
const validB = /^\d+$/.test(String(b));
|
|
3401
|
+
if (validA !== validB)
|
|
3402
|
+
return validA ? -1 : 1;
|
|
3403
|
+
if (!validA)
|
|
3404
|
+
return 0;
|
|
3405
|
+
const left = String(a).replace(/^0+(?=\d)/, "");
|
|
3406
|
+
const right = String(b).replace(/^0+(?=\d)/, "");
|
|
3407
|
+
return left.length - right.length || (left < right ? -1 : left > right ? 1 : 0);
|
|
3408
|
+
}
|
|
3409
|
+
function displayMessage(row) {
|
|
3410
|
+
const { _mutationAt, _mutationEpoch, _contentSequence, _receiptSequence, _sendSequence, _sendEpoch, ...message } = row;
|
|
3411
|
+
return {
|
|
3412
|
+
...restoreMediaPreviews(message),
|
|
3413
|
+
localMessageID: row.localMessageID || row.localID,
|
|
3414
|
+
messageID: row.messageID || "",
|
|
3415
|
+
clientBizId: row.clientBizId || "",
|
|
3416
|
+
message: row.message ?? row.massage ?? "",
|
|
3417
|
+
massage: row.massage ?? row.message ?? "",
|
|
3418
|
+
sentStatus: row.sentStatus ?? row.sendState
|
|
3419
|
+
};
|
|
614
3420
|
}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
success = Boolean(result) || isSuccessCode(res.code);
|
|
625
|
-
} catch {
|
|
626
|
-
success = false;
|
|
627
|
-
} finally {
|
|
628
|
-
clearSdkSession();
|
|
629
|
-
}
|
|
630
|
-
return success;
|
|
3421
|
+
|
|
3422
|
+
// src/sdk/message/clientBizId.ts
|
|
3423
|
+
var sequence = 0;
|
|
3424
|
+
function withClientBizId(message) {
|
|
3425
|
+
sequence = (sequence + 1) % 1e6;
|
|
3426
|
+
return {
|
|
3427
|
+
...message,
|
|
3428
|
+
clientBizId: message.clientBizId || `cbiz_${Date.now()}_${sequence.toString(36)}_${Math.random().toString(36).slice(2, 10)}`
|
|
3429
|
+
};
|
|
631
3430
|
}
|
|
632
3431
|
|
|
633
3432
|
// src/apis/SdkSendMessagePostApi.ts
|
|
@@ -703,7 +3502,6 @@ var getVideoDurationAndFirstFrame = (file) => {
|
|
|
703
3502
|
video.onloadedmetadata = () => {
|
|
704
3503
|
canvas.width = video.videoWidth || 640;
|
|
705
3504
|
canvas.height = video.videoHeight || 360;
|
|
706
|
-
window.URL.revokeObjectURL(video.src);
|
|
707
3505
|
duration = video?.duration;
|
|
708
3506
|
videoWidth = video.videoWidth || 640;
|
|
709
3507
|
videoHeight = video.videoHeight || 360;
|
|
@@ -764,6 +3562,24 @@ function getAudioDuration(file) {
|
|
|
764
3562
|
});
|
|
765
3563
|
}
|
|
766
3564
|
|
|
3565
|
+
// src/constants/messages/Message.ts
|
|
3566
|
+
var SEDMessageType = /* @__PURE__ */ ((SEDMessageType2) => {
|
|
3567
|
+
SEDMessageType2["Unknown"] = "0";
|
|
3568
|
+
SEDMessageType2["Command"] = "2";
|
|
3569
|
+
SEDMessageType2["Barrage"] = "20";
|
|
3570
|
+
SEDMessageType2["Text"] = "1";
|
|
3571
|
+
SEDMessageType2["Image"] = "11";
|
|
3572
|
+
SEDMessageType2["File"] = "12";
|
|
3573
|
+
SEDMessageType2["Audio"] = "13";
|
|
3574
|
+
SEDMessageType2["Video"] = "14";
|
|
3575
|
+
SEDMessageType2["System"] = "30";
|
|
3576
|
+
SEDMessageType2["Revoke"] = "31";
|
|
3577
|
+
SEDMessageType2["Tips"] = "32";
|
|
3578
|
+
SEDMessageType2["Combine"] = "100";
|
|
3579
|
+
SEDMessageType2["Custom"] = "200";
|
|
3580
|
+
return SEDMessageType2;
|
|
3581
|
+
})(SEDMessageType || {});
|
|
3582
|
+
|
|
767
3583
|
// src/apis/SdkDeleteAllMessagePostApi.ts
|
|
768
3584
|
var postSdkDeleteAllMessageApiRequest = (data) => {
|
|
769
3585
|
return request({
|
|
@@ -773,28 +3589,78 @@ var postSdkDeleteAllMessageApiRequest = (data) => {
|
|
|
773
3589
|
});
|
|
774
3590
|
};
|
|
775
3591
|
|
|
776
|
-
// src/sdk/message.ts
|
|
777
|
-
var clientBizIdSeq = 0;
|
|
3592
|
+
// src/sdk/message/message.ts
|
|
778
3593
|
var MAX_FILE_NAME_LENGTH = 20;
|
|
779
|
-
function
|
|
780
|
-
|
|
781
|
-
const timestamp = Date.now();
|
|
782
|
-
const sequence = clientBizIdSeq.toString(36);
|
|
783
|
-
const random = Math.random().toString(36).slice(2, 10);
|
|
784
|
-
return `cbiz_${timestamp}_${sequence}_${random}`;
|
|
785
|
-
}
|
|
786
|
-
function withClientBizId(message) {
|
|
787
|
-
return {
|
|
788
|
-
...message,
|
|
789
|
-
clientBizId: message.clientBizId || generateClientBizId()
|
|
790
|
-
};
|
|
3594
|
+
function sliceChars(value, length) {
|
|
3595
|
+
return Array.from(value).slice(0, length).join("");
|
|
791
3596
|
}
|
|
792
3597
|
function truncateFileName(fileName) {
|
|
793
|
-
|
|
3598
|
+
const lastDotIndex = fileName.lastIndexOf(".");
|
|
3599
|
+
const hasExtension = lastDotIndex > 0 && lastDotIndex < fileName.length - 1;
|
|
3600
|
+
if (!hasExtension) {
|
|
3601
|
+
return sliceChars(fileName, MAX_FILE_NAME_LENGTH);
|
|
3602
|
+
}
|
|
3603
|
+
const baseName = fileName.slice(0, lastDotIndex);
|
|
3604
|
+
const extension = fileName.slice(lastDotIndex);
|
|
3605
|
+
return `${sliceChars(baseName, MAX_FILE_NAME_LENGTH)}${extension}`;
|
|
794
3606
|
}
|
|
795
3607
|
function getDisplayFileName(file, fallback = "") {
|
|
796
3608
|
return truncateFileName(file?.name || fallback || "");
|
|
797
3609
|
}
|
|
3610
|
+
function appendUploadFile(formData, file, fileName) {
|
|
3611
|
+
const uploadFileName = getDisplayFileName(file, fileName);
|
|
3612
|
+
if (uploadFileName) {
|
|
3613
|
+
formData.append("file", file, uploadFileName);
|
|
3614
|
+
return;
|
|
3615
|
+
}
|
|
3616
|
+
formData.append("file", file);
|
|
3617
|
+
}
|
|
3618
|
+
function assertMediaFileHasContent(file, fileName) {
|
|
3619
|
+
if (!file || typeof file.size !== "number" || file.size <= 0) {
|
|
3620
|
+
throwSdkRuntimeError({
|
|
3621
|
+
code: 2,
|
|
3622
|
+
message: "media message file is empty",
|
|
3623
|
+
raw: {
|
|
3624
|
+
fileName: fileName || file?.name || "",
|
|
3625
|
+
fileSize: file?.size ?? 0,
|
|
3626
|
+
fileType: file?.type || ""
|
|
3627
|
+
}
|
|
3628
|
+
});
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
function debugUploadFile(file, fileName) {
|
|
3632
|
+
if (typeof window !== "undefined" && window.__VANSHI_SDK_DEBUG__) {
|
|
3633
|
+
console.debug("[VanshiSdk] uploading media file", {
|
|
3634
|
+
fileName: fileName || file?.name || "",
|
|
3635
|
+
fileSize: file.size,
|
|
3636
|
+
fileType: file.type || ""
|
|
3637
|
+
});
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3640
|
+
async function createUploadBlob(file, fileName) {
|
|
3641
|
+
assertMediaFileHasContent(file, fileName);
|
|
3642
|
+
let bytes;
|
|
3643
|
+
try {
|
|
3644
|
+
bytes = await file.arrayBuffer();
|
|
3645
|
+
} catch (error) {
|
|
3646
|
+
throwSdkTransportError(error, "media message file cannot be read");
|
|
3647
|
+
}
|
|
3648
|
+
if (bytes.byteLength <= 0) {
|
|
3649
|
+
throwSdkRuntimeError({
|
|
3650
|
+
code: 2,
|
|
3651
|
+
message: "media message file is empty",
|
|
3652
|
+
raw: {
|
|
3653
|
+
fileName: fileName || file?.name || "",
|
|
3654
|
+
fileSize: file.size,
|
|
3655
|
+
readSize: bytes.byteLength,
|
|
3656
|
+
fileType: file.type || ""
|
|
3657
|
+
}
|
|
3658
|
+
});
|
|
3659
|
+
}
|
|
3660
|
+
return new Blob([bytes], {
|
|
3661
|
+
type: file.type || "application/octet-stream"
|
|
3662
|
+
});
|
|
3663
|
+
}
|
|
798
3664
|
function createLocalMediaMessage(message, toConversationID, conversationType) {
|
|
799
3665
|
const file = message.file;
|
|
800
3666
|
const localPreviewUrl = file && typeof URL !== "undefined" && URL.createObjectURL ? URL.createObjectURL(file) : void 0;
|
|
@@ -810,9 +3676,10 @@ function createLocalMediaMessage(message, toConversationID, conversationType) {
|
|
|
810
3676
|
clientBizId: message.clientBizId,
|
|
811
3677
|
conversationID: toConversationID,
|
|
812
3678
|
conversationType,
|
|
813
|
-
senderUserID:
|
|
3679
|
+
senderUserID: getSdkUserID(),
|
|
814
3680
|
direction: 0,
|
|
815
3681
|
sentStatus: 0,
|
|
3682
|
+
sendState: 0,
|
|
816
3683
|
timestamp: Date.now(),
|
|
817
3684
|
receiptStatus: 0,
|
|
818
3685
|
isServerMessage: false,
|
|
@@ -823,13 +3690,38 @@ function createLocalMediaMessage(message, toConversationID, conversationType) {
|
|
|
823
3690
|
fileName: getDisplayFileName(file, message.fileName),
|
|
824
3691
|
fileSize: file ? String(file.size) : message.fileSize || "",
|
|
825
3692
|
fileDownloadUrl: message.fileDownloadUrl || localPreviewUrl || "",
|
|
826
|
-
thumbnailDownloadUrl: message.thumbnailDownloadUrl || localPreviewUrl || "",
|
|
3693
|
+
thumbnailDownloadUrl: message.thumbnailDownloadUrl || (isSameUid(message.type, "11" /* Image */) ? localPreviewUrl : "") || "",
|
|
827
3694
|
thumbnailWidth: message.thumbnailWidth || "",
|
|
828
3695
|
thumbnailHeight: message.thumbnailHeight || "",
|
|
829
3696
|
duration: message.duration || "",
|
|
830
3697
|
localPreviewUrl
|
|
831
3698
|
};
|
|
832
3699
|
}
|
|
3700
|
+
function createLocalTextMessage(message, toConversationID, conversationType) {
|
|
3701
|
+
return {
|
|
3702
|
+
massage: message.message,
|
|
3703
|
+
message: message.message,
|
|
3704
|
+
type: message.type,
|
|
3705
|
+
extendedData: message.extendedData,
|
|
3706
|
+
messageID: "",
|
|
3707
|
+
orderKey: "",
|
|
3708
|
+
clientSid: "",
|
|
3709
|
+
localMessageID: message.clientBizId,
|
|
3710
|
+
clientBizId: message.clientBizId,
|
|
3711
|
+
conversationID: toConversationID,
|
|
3712
|
+
conversationType,
|
|
3713
|
+
senderUserID: "",
|
|
3714
|
+
direction: 0,
|
|
3715
|
+
sentStatus: 0,
|
|
3716
|
+
sendState: 0,
|
|
3717
|
+
timestamp: String(Date.now()),
|
|
3718
|
+
receiptStatus: 0,
|
|
3719
|
+
isServerMessage: false,
|
|
3720
|
+
isBroadcastMessage: false,
|
|
3721
|
+
isGroupTargetedMessage: "",
|
|
3722
|
+
id: ""
|
|
3723
|
+
};
|
|
3724
|
+
}
|
|
833
3725
|
async function getImageSize(file) {
|
|
834
3726
|
return new Promise((resolve, reject) => {
|
|
835
3727
|
const url = URL.createObjectURL(file);
|
|
@@ -849,37 +3741,65 @@ async function getImageSize(file) {
|
|
|
849
3741
|
});
|
|
850
3742
|
}
|
|
851
3743
|
async function uploadSdkFile(file, fileName) {
|
|
3744
|
+
const session = captureSession();
|
|
3745
|
+
const storage = captureStorage();
|
|
3746
|
+
const uploadFile = await createUploadBlob(file, fileName);
|
|
3747
|
+
const uploadFileName = getDisplayFileName(file, fileName) || "file";
|
|
3748
|
+
debugUploadFile(uploadFile, uploadFileName);
|
|
852
3749
|
const formData = new FormData();
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
formData.append("file", file);
|
|
858
|
-
}
|
|
859
|
-
const response = await fetch(getUploadUrl(), {
|
|
860
|
-
method: "POST",
|
|
861
|
-
headers: {
|
|
862
|
-
Authorization: getStoredToken()
|
|
863
|
-
},
|
|
864
|
-
body: formData
|
|
865
|
-
});
|
|
866
|
-
if (!response.ok) {
|
|
867
|
-
throw new Error(`file upload failed: ${response.status}`);
|
|
3750
|
+
appendUploadFile(formData, uploadFile, uploadFileName);
|
|
3751
|
+
const formDataFile = formData.get("file");
|
|
3752
|
+
if (formDataFile instanceof Blob) {
|
|
3753
|
+
assertMediaFileHasContent(formDataFile, uploadFileName);
|
|
868
3754
|
}
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
3755
|
+
try {
|
|
3756
|
+
assertCurrentSession(session);
|
|
3757
|
+
if (storage && !isCurrentStorage(storage))
|
|
3758
|
+
throw new Error("Local storage account changed before upload");
|
|
3759
|
+
const response = await fetch(getUploadUrl(), {
|
|
3760
|
+
method: "POST",
|
|
3761
|
+
headers: {
|
|
3762
|
+
Authorization: getStoredToken()
|
|
3763
|
+
},
|
|
3764
|
+
body: formData
|
|
3765
|
+
});
|
|
3766
|
+
assertCurrentSession(session);
|
|
3767
|
+
if (!response.ok) {
|
|
3768
|
+
throwSdkRuntimeError({
|
|
3769
|
+
code: response.status,
|
|
3770
|
+
message: `file upload failed: ${response.status}`,
|
|
3771
|
+
raw: response
|
|
3772
|
+
});
|
|
3773
|
+
}
|
|
3774
|
+
const payload = await response.json();
|
|
3775
|
+
assertCurrentSession(session);
|
|
3776
|
+
const result = assertSdkSuccess({
|
|
3777
|
+
code: payload.Code,
|
|
3778
|
+
message: payload.Message,
|
|
3779
|
+
data: payload.Result || payload.data,
|
|
3780
|
+
raw: payload
|
|
3781
|
+
});
|
|
3782
|
+
if (!result.data) {
|
|
3783
|
+
throwSdkRuntimeError({
|
|
3784
|
+
message: "file upload result is empty",
|
|
3785
|
+
raw: payload
|
|
3786
|
+
});
|
|
3787
|
+
}
|
|
3788
|
+
return result.data;
|
|
3789
|
+
} catch (error) {
|
|
3790
|
+
throwSdkTransportError(error, "file upload failed");
|
|
875
3791
|
}
|
|
876
|
-
return payload.Result;
|
|
877
3792
|
}
|
|
878
|
-
async function enrichMediaMessage(message) {
|
|
3793
|
+
async function enrichMediaMessage(message, onVideoPrepared, assertSession = () => {
|
|
3794
|
+
}) {
|
|
879
3795
|
const file = message.file;
|
|
880
3796
|
if (!file) {
|
|
881
|
-
|
|
3797
|
+
throwSdkRuntimeError({
|
|
3798
|
+
message: "media message file is required",
|
|
3799
|
+
raw: message
|
|
3800
|
+
});
|
|
882
3801
|
}
|
|
3802
|
+
assertMediaFileHasContent(file, message.fileName);
|
|
883
3803
|
const enrichedMessage = {
|
|
884
3804
|
...message,
|
|
885
3805
|
fileName: getDisplayFileName(file, message.fileName),
|
|
@@ -897,11 +3817,14 @@ async function enrichMediaMessage(message) {
|
|
|
897
3817
|
enrichedMessage.duration = String(res.duration);
|
|
898
3818
|
enrichedMessage.thumbnailWidth = String(res.videoWidth);
|
|
899
3819
|
enrichedMessage.thumbnailHeight = String(res.videoHeight);
|
|
3820
|
+
await onVideoPrepared?.(res);
|
|
3821
|
+
assertSession();
|
|
900
3822
|
enrichedMessage.thumbnailDownloadUrl = await uploadSdkFile(
|
|
901
3823
|
res.firstFrameFile,
|
|
902
3824
|
res.firstFrameFile.name
|
|
903
3825
|
);
|
|
904
3826
|
}
|
|
3827
|
+
assertSession();
|
|
905
3828
|
const fileDownloadUrl = await uploadSdkFile(file, enrichedMessage.fileName);
|
|
906
3829
|
enrichedMessage.fileDownloadUrl = fileDownloadUrl;
|
|
907
3830
|
if (isSameUid(message.type, "11" /* Image */)) {
|
|
@@ -910,19 +3833,20 @@ async function enrichMediaMessage(message) {
|
|
|
910
3833
|
delete enrichedMessage.file;
|
|
911
3834
|
return enrichedMessage;
|
|
912
3835
|
}
|
|
913
|
-
async function sendMessage(payload) {
|
|
914
|
-
const
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
return unwrapSdkData(response);
|
|
919
|
-
}
|
|
920
|
-
async function sendMediaMessage(payload, options) {
|
|
3836
|
+
async function sendMessage(payload, options) {
|
|
3837
|
+
const session = captureSession();
|
|
3838
|
+
if (isAuthenticating())
|
|
3839
|
+
await waitForAuthentication(session);
|
|
3840
|
+
const storage = captureStorage();
|
|
921
3841
|
const messageWithClientBizId = withClientBizId(payload.message);
|
|
3842
|
+
await persistOutgoing(storage, { ...payload, message: messageWithClientBizId });
|
|
3843
|
+
if (storage && !isCurrentStorage(storage))
|
|
3844
|
+
throw new Error("Local storage account changed before sending");
|
|
3845
|
+
assertCurrentSession(session);
|
|
922
3846
|
if (options?.onMessageAttached) {
|
|
923
3847
|
try {
|
|
924
3848
|
options.onMessageAttached(
|
|
925
|
-
|
|
3849
|
+
createLocalTextMessage(
|
|
926
3850
|
messageWithClientBizId,
|
|
927
3851
|
payload.toConversationID,
|
|
928
3852
|
payload.conversationType
|
|
@@ -931,15 +3855,77 @@ async function sendMediaMessage(payload, options) {
|
|
|
931
3855
|
} catch {
|
|
932
3856
|
}
|
|
933
3857
|
}
|
|
934
|
-
|
|
3858
|
+
assertCurrentSession(session);
|
|
3859
|
+
const response = await postSdkSendMessageApiRequest({
|
|
935
3860
|
...payload,
|
|
936
|
-
message:
|
|
3861
|
+
message: messageWithClientBizId
|
|
937
3862
|
});
|
|
938
|
-
|
|
3863
|
+
const result = unwrapSdkData(response);
|
|
3864
|
+
return result ? {
|
|
3865
|
+
...result,
|
|
3866
|
+
message: result.message || result.massage
|
|
3867
|
+
} : result;
|
|
3868
|
+
}
|
|
3869
|
+
async function sendMediaMessage(payload, options) {
|
|
3870
|
+
const session = captureSession();
|
|
3871
|
+
if (isAuthenticating())
|
|
3872
|
+
await waitForAuthentication(session);
|
|
3873
|
+
const storage = captureStorage();
|
|
3874
|
+
const messageWithClientBizId = withClientBizId(payload.message);
|
|
3875
|
+
const localMessage = createLocalMediaMessage(messageWithClientBizId, payload.toConversationID, payload.conversationType);
|
|
3876
|
+
await persistOutgoing(storage, { ...payload, message: localMessage });
|
|
3877
|
+
const notify = () => {
|
|
3878
|
+
assertCurrentSession(session);
|
|
3879
|
+
if (storage && !isCurrentStorage(storage))
|
|
3880
|
+
throw new Error("Local storage account changed during media preparation");
|
|
3881
|
+
try {
|
|
3882
|
+
options?.onMessageAttached?.({ ...localMessage });
|
|
3883
|
+
} catch {
|
|
3884
|
+
}
|
|
3885
|
+
};
|
|
3886
|
+
try {
|
|
3887
|
+
notify();
|
|
3888
|
+
const enriched = await enrichMediaMessage(messageWithClientBizId, async (video) => {
|
|
3889
|
+
assertCurrentSession(session);
|
|
3890
|
+
if (storage && !isCurrentStorage(storage))
|
|
3891
|
+
throw new Error("Local storage account changed during media preparation");
|
|
3892
|
+
Object.assign(localMessage, {
|
|
3893
|
+
duration: String(video.duration),
|
|
3894
|
+
thumbnailWidth: String(video.videoWidth),
|
|
3895
|
+
thumbnailHeight: String(video.videoHeight),
|
|
3896
|
+
thumbnailFile: video.firstFrameFile,
|
|
3897
|
+
thumbnailDownloadUrl: URL.createObjectURL(video.firstFrameFile)
|
|
3898
|
+
});
|
|
3899
|
+
await persistOutgoing(storage, { ...payload, message: localMessage });
|
|
3900
|
+
notify();
|
|
3901
|
+
}, () => assertCurrentSession(session));
|
|
3902
|
+
if (storage && !isCurrentStorage(storage))
|
|
3903
|
+
throw new Error("Local storage account changed during media preparation");
|
|
3904
|
+
assertCurrentSession(session);
|
|
3905
|
+
const response = await postSdkSendMediaMessageApiRequest({
|
|
3906
|
+
...payload,
|
|
3907
|
+
message: enriched
|
|
3908
|
+
});
|
|
3909
|
+
return unwrapSdkData(response);
|
|
3910
|
+
} catch (error) {
|
|
3911
|
+
await markSendError(storage, messageWithClientBizId.clientBizId, outgoingFallback(payload, storage), error);
|
|
3912
|
+
if (isSdkRuntimeErrorObject(error)) {
|
|
3913
|
+
throw error;
|
|
3914
|
+
}
|
|
3915
|
+
throwSdkTransportError(error, "send media message failed");
|
|
3916
|
+
}
|
|
939
3917
|
}
|
|
940
3918
|
async function queryHistoryMessage(payload) {
|
|
3919
|
+
const session = captureSession();
|
|
3920
|
+
if (isAuthenticating())
|
|
3921
|
+
await waitForAuthentication(session);
|
|
3922
|
+
const storage = captureStorage();
|
|
941
3923
|
const response = await postSdkQueryHistoryMessageApiRequest(payload);
|
|
942
|
-
|
|
3924
|
+
assertCurrentSession(session);
|
|
3925
|
+
const result = unwrapSdkData(response);
|
|
3926
|
+
const merged = await mergeHistoryWithLocalMessages(storage, payload, result);
|
|
3927
|
+
assertCurrentSession(session);
|
|
3928
|
+
return merged;
|
|
943
3929
|
}
|
|
944
3930
|
async function deleteAllConversationMessages() {
|
|
945
3931
|
const response = await postSdkDeleteAllConversationMessagesApiRequest(
|
|
@@ -954,7 +3940,7 @@ async function deleteAllConversationMessages() {
|
|
|
954
3940
|
}
|
|
955
3941
|
async function deleteMessages(conversationID, conversationType, messageList) {
|
|
956
3942
|
const response = await postSdkDeleteMessagesApiRequest({
|
|
957
|
-
conversationID
|
|
3943
|
+
conversationID,
|
|
958
3944
|
conversationType: conversationType.toString(),
|
|
959
3945
|
messageList: messageList.map((msg) => ({
|
|
960
3946
|
messageID: msg.messageID,
|
|
@@ -969,11 +3955,20 @@ async function revokeMessage(message, config) {
|
|
|
969
3955
|
}
|
|
970
3956
|
async function deleteAllMessage(conversationID, conversationType) {
|
|
971
3957
|
const response = await postSdkDeleteAllMessageApiRequest({
|
|
972
|
-
conversationID
|
|
3958
|
+
conversationID,
|
|
973
3959
|
conversationType: conversationType.toString()
|
|
974
3960
|
});
|
|
975
3961
|
return unwrapSdkResponse(response);
|
|
976
3962
|
}
|
|
3963
|
+
var message_default = {
|
|
3964
|
+
sendMessage,
|
|
3965
|
+
sendMediaMessage,
|
|
3966
|
+
queryHistoryMessage,
|
|
3967
|
+
deleteAllConversationMessages,
|
|
3968
|
+
deleteMessages,
|
|
3969
|
+
revokeMessage,
|
|
3970
|
+
deleteAllMessage
|
|
3971
|
+
};
|
|
977
3972
|
|
|
978
3973
|
// src/apis/SdkQueryGroupMessageReceiptReadMemberListPostApi.ts
|
|
979
3974
|
var postSdkQueryGroupMessageReceiptReadMemberListApiRequest = (data) => {
|
|
@@ -1011,7 +4006,7 @@ var postSdkSendMessageReceiptsReadApiRequest = (data) => {
|
|
|
1011
4006
|
});
|
|
1012
4007
|
};
|
|
1013
4008
|
|
|
1014
|
-
// src/sdk/messageReceipts.ts
|
|
4009
|
+
// src/sdk/message/messageReceipts.ts
|
|
1015
4010
|
async function sendMessageReceiptsRead(conversationID, conversationType, messageList) {
|
|
1016
4011
|
const response = await postSdkSendMessageReceiptsReadApiRequest({
|
|
1017
4012
|
conversationID,
|
|
@@ -1022,7 +4017,7 @@ async function sendMessageReceiptsRead(conversationID, conversationType, message
|
|
|
1022
4017
|
}
|
|
1023
4018
|
async function queryMessageReceiptsInfo(conversationID, conversationType, messageList) {
|
|
1024
4019
|
const response = await postSdkQueryMessageReceiptsInfoApiRequest({
|
|
1025
|
-
conversationID
|
|
4020
|
+
conversationID,
|
|
1026
4021
|
conversationType: conversationType.toString(),
|
|
1027
4022
|
messageList
|
|
1028
4023
|
});
|
|
@@ -1044,12 +4039,606 @@ async function queryGroupMessageReceiptReadMemberList(groupID, config, message)
|
|
|
1044
4039
|
});
|
|
1045
4040
|
return unwrapSdkResponse(response);
|
|
1046
4041
|
}
|
|
4042
|
+
var messageReceipts_default = {
|
|
4043
|
+
sendMessageReceiptsRead,
|
|
4044
|
+
queryMessageReceiptsInfo,
|
|
4045
|
+
queryGroupMessageReceiptUnreadMemberList,
|
|
4046
|
+
queryGroupMessageReceiptReadMemberList
|
|
4047
|
+
};
|
|
4048
|
+
|
|
4049
|
+
// src/sdk/message/index.ts
|
|
4050
|
+
var MessageIndexApis = {
|
|
4051
|
+
...message_default,
|
|
4052
|
+
...messageReceipts_default
|
|
4053
|
+
};
|
|
4054
|
+
|
|
4055
|
+
// src/sdk/zimApiCore.ts
|
|
4056
|
+
function isFileLike(value) {
|
|
4057
|
+
return typeof File !== "undefined" && value instanceof File;
|
|
4058
|
+
}
|
|
4059
|
+
function isBlobLike(value) {
|
|
4060
|
+
return typeof Blob !== "undefined" && value instanceof Blob;
|
|
4061
|
+
}
|
|
4062
|
+
function normalizeSdkPayload(value, omitLocalMessageFiles = false) {
|
|
4063
|
+
if (!value || typeof value !== "object") {
|
|
4064
|
+
return value;
|
|
4065
|
+
}
|
|
4066
|
+
if (value instanceof Date || value instanceof ArrayBuffer || ArrayBuffer.isView(value) || isFileLike(value) || isBlobLike(value)) {
|
|
4067
|
+
return value;
|
|
4068
|
+
}
|
|
4069
|
+
if (value instanceof Map) {
|
|
4070
|
+
const entries = Object.fromEntries(value);
|
|
4071
|
+
return omitLocalMessageFiles ? normalizeSdkPayload(entries, true) : entries;
|
|
4072
|
+
}
|
|
4073
|
+
if (Array.isArray(value)) {
|
|
4074
|
+
return value.map((item) => normalizeSdkPayload(item, omitLocalMessageFiles));
|
|
4075
|
+
}
|
|
4076
|
+
const normalized = {};
|
|
4077
|
+
Object.entries(value).forEach(([key, item]) => {
|
|
4078
|
+
if (omitLocalMessageFiles && (["fileLocalPath", "file", "thumbnailFile", "localPreviewUrl", "localID", "conversationKey", "updatedAt", "errorCode", "errorMessage"].includes(key) || key.startsWith("_")))
|
|
4079
|
+
return;
|
|
4080
|
+
if (omitLocalMessageFiles && ["fileDownloadUrl", "thumbnailDownloadUrl"].includes(key) && typeof item === "string" && item.startsWith("blob:"))
|
|
4081
|
+
return;
|
|
4082
|
+
if (typeof item !== "function" && item !== void 0) {
|
|
4083
|
+
normalized[key] = normalizeSdkPayload(item, omitLocalMessageFiles);
|
|
4084
|
+
}
|
|
4085
|
+
});
|
|
4086
|
+
return normalized;
|
|
4087
|
+
}
|
|
4088
|
+
async function callSdkApi(method, payload = {}) {
|
|
4089
|
+
const response = await request({
|
|
4090
|
+
path: `/sdk/${method}`,
|
|
4091
|
+
method: "POST",
|
|
4092
|
+
data: normalizeSdkPayload(payload, method === "replyMessage")
|
|
4093
|
+
});
|
|
4094
|
+
return unwrapSdkData(response);
|
|
4095
|
+
}
|
|
4096
|
+
|
|
4097
|
+
// src/sdk/social/blacklist.ts
|
|
4098
|
+
function addUsersToBlacklist(userIDs) {
|
|
4099
|
+
return callSdkApi("addUsersToBlacklist", { userIDs });
|
|
4100
|
+
}
|
|
4101
|
+
function removeUsersFromBlacklist(userIDs) {
|
|
4102
|
+
return callSdkApi("removeUsersFromBlacklist", { userIDs });
|
|
4103
|
+
}
|
|
4104
|
+
function queryBlacklist(config) {
|
|
4105
|
+
return callSdkApi("queryBlacklist", { config });
|
|
4106
|
+
}
|
|
4107
|
+
function checkUserIsInBlacklist(userID) {
|
|
4108
|
+
return callSdkApi("checkUserIsInBlacklist", { userID });
|
|
4109
|
+
}
|
|
4110
|
+
var blacklist_default = {
|
|
4111
|
+
addUsersToBlacklist,
|
|
4112
|
+
removeUsersFromBlacklist,
|
|
4113
|
+
queryBlacklist,
|
|
4114
|
+
checkUserIsInBlacklist
|
|
4115
|
+
};
|
|
4116
|
+
|
|
4117
|
+
// src/sdk/social/friend.ts
|
|
4118
|
+
function sendFriendApplication(userID, config) {
|
|
4119
|
+
return callSdkApi("sendFriendApplication", { userID, config });
|
|
4120
|
+
}
|
|
4121
|
+
function deleteFriends(userIDs, config) {
|
|
4122
|
+
return callSdkApi("deleteFriends", { userIDs, config });
|
|
4123
|
+
}
|
|
4124
|
+
function updateFriendAlias(friendAlias, userID) {
|
|
4125
|
+
return callSdkApi("updateFriendAlias", { friendAlias, userID });
|
|
4126
|
+
}
|
|
4127
|
+
function queryFriendApplicationList(config) {
|
|
4128
|
+
return callSdkApi("queryFriendApplicationList", { config });
|
|
4129
|
+
}
|
|
4130
|
+
function acceptFriendApplication(userID, config) {
|
|
4131
|
+
return callSdkApi("acceptFriendApplication", { userID, config });
|
|
4132
|
+
}
|
|
4133
|
+
function rejectFriendApplication(userID, config) {
|
|
4134
|
+
return callSdkApi("rejectFriendApplication", { userID, config });
|
|
4135
|
+
}
|
|
4136
|
+
function queryFriendList(config) {
|
|
4137
|
+
return callSdkApi("queryFriendList", { config });
|
|
4138
|
+
}
|
|
4139
|
+
function queryFriendsInfo(userIDs) {
|
|
4140
|
+
return callSdkApi("queryFriendsInfo", { userIDs });
|
|
4141
|
+
}
|
|
4142
|
+
var friend_default = {
|
|
4143
|
+
sendFriendApplication,
|
|
4144
|
+
deleteFriends,
|
|
4145
|
+
updateFriendAlias,
|
|
4146
|
+
queryFriendApplicationList,
|
|
4147
|
+
acceptFriendApplication,
|
|
4148
|
+
rejectFriendApplication,
|
|
4149
|
+
queryFriendList,
|
|
4150
|
+
queryFriendsInfo
|
|
4151
|
+
};
|
|
4152
|
+
|
|
4153
|
+
// src/sdk/social/user.ts
|
|
4154
|
+
function querySelfUserInfo() {
|
|
4155
|
+
return callSdkApi("querySelfUserInfo");
|
|
4156
|
+
}
|
|
4157
|
+
async function renewToken(token) {
|
|
4158
|
+
const session = captureSession();
|
|
4159
|
+
const result = await callSdkApi("renewToken", {
|
|
4160
|
+
token
|
|
4161
|
+
});
|
|
4162
|
+
assertCurrentSession(session);
|
|
4163
|
+
setSdkSession(result?.token || token);
|
|
4164
|
+
return result ?? { token };
|
|
4165
|
+
}
|
|
4166
|
+
function queryUsersInfo(userIDs, config) {
|
|
4167
|
+
return callSdkApi("queryUsersInfo", { userIDs, config });
|
|
4168
|
+
}
|
|
4169
|
+
function queryUsersStatus(userIDs) {
|
|
4170
|
+
return callSdkApi("queryUsersStatus", { userIDs });
|
|
4171
|
+
}
|
|
4172
|
+
function subscribeUsersStatus(userIDs, config) {
|
|
4173
|
+
return callSdkApi("subscribeUsersStatus", { userIDs, config });
|
|
4174
|
+
}
|
|
4175
|
+
function unsubscribeUsersStatus(userIDs) {
|
|
4176
|
+
return callSdkApi("unsubscribeUsersStatus", { userIDs });
|
|
4177
|
+
}
|
|
4178
|
+
function updateUserName(userName) {
|
|
4179
|
+
return callSdkApi("updateUserName", { userName });
|
|
4180
|
+
}
|
|
4181
|
+
function updateUserAvatarUrl(userAvatarUrl) {
|
|
4182
|
+
return callSdkApi("updateUserAvatarUrl", { userAvatarUrl });
|
|
4183
|
+
}
|
|
4184
|
+
var user_default = {
|
|
4185
|
+
querySelfUserInfo,
|
|
4186
|
+
renewToken,
|
|
4187
|
+
queryUsersInfo,
|
|
4188
|
+
queryUsersStatus,
|
|
4189
|
+
subscribeUsersStatus,
|
|
4190
|
+
unsubscribeUsersStatus,
|
|
4191
|
+
updateUserName,
|
|
4192
|
+
updateUserAvatarUrl
|
|
4193
|
+
};
|
|
4194
|
+
|
|
4195
|
+
// src/sdk/social/index.ts
|
|
4196
|
+
var SocialApis = {
|
|
4197
|
+
...friend_default,
|
|
4198
|
+
...blacklist_default,
|
|
4199
|
+
...user_default
|
|
4200
|
+
};
|
|
4201
|
+
var social_default = SocialApis;
|
|
4202
|
+
|
|
4203
|
+
// src/sdk/group/group.ts
|
|
4204
|
+
function createGroup(groupInfo, userIDs, config) {
|
|
4205
|
+
return callSdkApi("createGroup", { groupInfo, userIDs, config });
|
|
4206
|
+
}
|
|
4207
|
+
function joinGroup(groupID) {
|
|
4208
|
+
return callSdkApi("joinGroup", { groupID });
|
|
4209
|
+
}
|
|
4210
|
+
function leaveGroup(groupID) {
|
|
4211
|
+
return callSdkApi("leaveGroup", { groupID });
|
|
4212
|
+
}
|
|
4213
|
+
function dismissGroup(groupID) {
|
|
4214
|
+
return callSdkApi("dismissGroup", { groupID });
|
|
4215
|
+
}
|
|
4216
|
+
function kickGroupMembers(userIDs, groupID) {
|
|
4217
|
+
return callSdkApi("kickGroupMembers", { userIDs, groupID });
|
|
4218
|
+
}
|
|
4219
|
+
function inviteUsersIntoGroup(userIDs, groupID) {
|
|
4220
|
+
return callSdkApi("inviteUsersIntoGroup", { userIDs, groupID });
|
|
4221
|
+
}
|
|
4222
|
+
function transferGroupOwner(toUserID, groupID) {
|
|
4223
|
+
return callSdkApi("transferGroupOwner", { toUserID, groupID });
|
|
4224
|
+
}
|
|
4225
|
+
function updateGroupAlias(groupAlias, groupID) {
|
|
4226
|
+
return callSdkApi("updateGroupAlias", { groupAlias, groupID });
|
|
4227
|
+
}
|
|
4228
|
+
function updateGroupName(groupName, groupID) {
|
|
4229
|
+
return callSdkApi("updateGroupName", { groupName, groupID });
|
|
4230
|
+
}
|
|
4231
|
+
function muteGroup(isMute, groupID, config) {
|
|
4232
|
+
return callSdkApi("muteGroup", { isMute, groupID, config });
|
|
4233
|
+
}
|
|
4234
|
+
function muteGroupMembers(isMute, userIDs, groupID, config) {
|
|
4235
|
+
return callSdkApi("muteGroupMembers", { isMute, userIDs, groupID, config });
|
|
4236
|
+
}
|
|
4237
|
+
function updateGroupAvatarUrl(groupAvatarUrl, groupID) {
|
|
4238
|
+
return callSdkApi("updateGroupAvatarUrl", { groupAvatarUrl, groupID });
|
|
4239
|
+
}
|
|
4240
|
+
function updateGroupNotice(groupNotice, groupID) {
|
|
4241
|
+
return callSdkApi("updateGroupNotice", { groupNotice, groupID });
|
|
4242
|
+
}
|
|
4243
|
+
function updateGroupJoinMode(mode, groupID) {
|
|
4244
|
+
return callSdkApi("updateGroupJoinMode", { mode, groupID });
|
|
4245
|
+
}
|
|
4246
|
+
function updateGroupInviteMode(mode, groupID) {
|
|
4247
|
+
return callSdkApi("updateGroupInviteMode", { mode, groupID });
|
|
4248
|
+
}
|
|
4249
|
+
function acceptGroupInviteApplication(inviterUserID, groupID, config) {
|
|
4250
|
+
return callSdkApi("acceptGroupInviteApplication", {
|
|
4251
|
+
inviterUserID,
|
|
4252
|
+
groupID,
|
|
4253
|
+
config
|
|
4254
|
+
});
|
|
4255
|
+
}
|
|
4256
|
+
function acceptGroupJoinApplication(userID, groupID, config) {
|
|
4257
|
+
return callSdkApi("acceptGroupJoinApplication", { userID, groupID, config });
|
|
4258
|
+
}
|
|
4259
|
+
function queryGroupApplicationList(config) {
|
|
4260
|
+
return callSdkApi("queryGroupApplicationList", { config });
|
|
4261
|
+
}
|
|
4262
|
+
function rejectGroupInviteApplication(inviterUserID, groupID, config) {
|
|
4263
|
+
return callSdkApi("rejectGroupInviteApplication", {
|
|
4264
|
+
inviterUserID,
|
|
4265
|
+
groupID,
|
|
4266
|
+
config
|
|
4267
|
+
});
|
|
4268
|
+
}
|
|
4269
|
+
function rejectGroupJoinApplication(userID, groupID, config) {
|
|
4270
|
+
return callSdkApi("rejectGroupJoinApplication", { userID, groupID, config });
|
|
4271
|
+
}
|
|
4272
|
+
function sendGroupInviteApplications(userIDs, groupID, config) {
|
|
4273
|
+
return callSdkApi("sendGroupInviteApplications", {
|
|
4274
|
+
userIDs,
|
|
4275
|
+
groupID,
|
|
4276
|
+
config
|
|
4277
|
+
});
|
|
4278
|
+
}
|
|
4279
|
+
function sendGroupJoinApplication(groupID, config) {
|
|
4280
|
+
return callSdkApi("sendGroupJoinApplication", { groupID, config });
|
|
4281
|
+
}
|
|
4282
|
+
function updateGroupBeInviteMode(mode, groupID) {
|
|
4283
|
+
return callSdkApi("updateGroupBeInviteMode", { mode, groupID });
|
|
4284
|
+
}
|
|
4285
|
+
function queryGroupInfo(groupID) {
|
|
4286
|
+
return callSdkApi("queryGroupInfo", { groupID });
|
|
4287
|
+
}
|
|
4288
|
+
function queryGroupList(count, config) {
|
|
4289
|
+
return callSdkApi("queryGroupList", { count, config });
|
|
4290
|
+
}
|
|
4291
|
+
function setGroupMemberRole(role, forUserID, groupID) {
|
|
4292
|
+
return callSdkApi("setGroupMemberRole", { role, forUserID, groupID });
|
|
4293
|
+
}
|
|
4294
|
+
function setGroupMemberNickname(nickname, forUserID, groupID) {
|
|
4295
|
+
return callSdkApi("setGroupMemberNickname", {
|
|
4296
|
+
nickname,
|
|
4297
|
+
forUserID,
|
|
4298
|
+
groupID
|
|
4299
|
+
});
|
|
4300
|
+
}
|
|
4301
|
+
function queryGroupMemberInfo(userID, groupID) {
|
|
4302
|
+
return callSdkApi("queryGroupMemberInfo", { userID, groupID });
|
|
4303
|
+
}
|
|
4304
|
+
function queryGroupMemberList(groupID, config) {
|
|
4305
|
+
return callSdkApi("queryGroupMemberList", { groupID, config });
|
|
4306
|
+
}
|
|
4307
|
+
function queryGroupMemberMutedList(groupID, config) {
|
|
4308
|
+
return callSdkApi("queryGroupMemberMutedList", { groupID, config });
|
|
4309
|
+
}
|
|
4310
|
+
function queryGroupMemberCount(groupID) {
|
|
4311
|
+
return callSdkApi("queryGroupMemberCount", { groupID });
|
|
4312
|
+
}
|
|
4313
|
+
var group_default = {
|
|
4314
|
+
createGroup,
|
|
4315
|
+
joinGroup,
|
|
4316
|
+
leaveGroup,
|
|
4317
|
+
dismissGroup,
|
|
4318
|
+
kickGroupMembers,
|
|
4319
|
+
inviteUsersIntoGroup,
|
|
4320
|
+
transferGroupOwner,
|
|
4321
|
+
updateGroupAlias,
|
|
4322
|
+
updateGroupName,
|
|
4323
|
+
muteGroup,
|
|
4324
|
+
muteGroupMembers,
|
|
4325
|
+
updateGroupAvatarUrl,
|
|
4326
|
+
updateGroupNotice,
|
|
4327
|
+
updateGroupJoinMode,
|
|
4328
|
+
updateGroupInviteMode,
|
|
4329
|
+
acceptGroupInviteApplication,
|
|
4330
|
+
acceptGroupJoinApplication,
|
|
4331
|
+
queryGroupApplicationList,
|
|
4332
|
+
rejectGroupInviteApplication,
|
|
4333
|
+
rejectGroupJoinApplication,
|
|
4334
|
+
sendGroupInviteApplications,
|
|
4335
|
+
sendGroupJoinApplication,
|
|
4336
|
+
updateGroupBeInviteMode,
|
|
4337
|
+
queryGroupInfo,
|
|
4338
|
+
queryGroupList,
|
|
4339
|
+
setGroupMemberRole,
|
|
4340
|
+
setGroupMemberNickname,
|
|
4341
|
+
queryGroupMemberInfo,
|
|
4342
|
+
queryGroupMemberList,
|
|
4343
|
+
queryGroupMemberMutedList,
|
|
4344
|
+
queryGroupMemberCount
|
|
4345
|
+
};
|
|
4346
|
+
|
|
4347
|
+
// src/sdk/conversation/conversationExt.ts
|
|
4348
|
+
function queryConversationPinnedList(config) {
|
|
4349
|
+
return callSdkApi("queryConversationPinnedList", { config });
|
|
4350
|
+
}
|
|
4351
|
+
function queryConversationTotalUnreadMessageCount(config) {
|
|
4352
|
+
return callSdkApi("queryConversationTotalUnreadMessageCount", { config });
|
|
4353
|
+
}
|
|
4354
|
+
function updateConversationPinnedState(isPinned, conversationID, conversationType) {
|
|
4355
|
+
return callSdkApi("updateConversationPinnedState", {
|
|
4356
|
+
isPinned,
|
|
4357
|
+
conversationID,
|
|
4358
|
+
conversationType
|
|
4359
|
+
});
|
|
4360
|
+
}
|
|
4361
|
+
function setConversationNotificationStatus(status, conversationID, conversationType) {
|
|
4362
|
+
return callSdkApi("setConversationNotificationStatus", {
|
|
4363
|
+
status,
|
|
4364
|
+
conversationID,
|
|
4365
|
+
conversationType
|
|
4366
|
+
});
|
|
4367
|
+
}
|
|
4368
|
+
var conversationExt_default = {
|
|
4369
|
+
queryConversationPinnedList,
|
|
4370
|
+
queryConversationTotalUnreadMessageCount,
|
|
4371
|
+
updateConversationPinnedState,
|
|
4372
|
+
setConversationNotificationStatus
|
|
4373
|
+
};
|
|
4374
|
+
|
|
4375
|
+
// src/sdk/message/messageExt.ts
|
|
4376
|
+
function notifyMessageAttached(notification, message) {
|
|
4377
|
+
try {
|
|
4378
|
+
notification?.onMessageAttached?.(message);
|
|
4379
|
+
} catch {
|
|
4380
|
+
}
|
|
4381
|
+
}
|
|
4382
|
+
function editMessage(message, config, notification) {
|
|
4383
|
+
notifyMessageAttached(notification, message);
|
|
4384
|
+
return callSdkApi("editMessage", { message, config });
|
|
4385
|
+
}
|
|
4386
|
+
async function replyMessage(message, toOriginalMessage, config, notification) {
|
|
4387
|
+
const session = captureSession();
|
|
4388
|
+
if (isAuthenticating())
|
|
4389
|
+
await waitForAuthentication(session);
|
|
4390
|
+
const storage = captureStorage();
|
|
4391
|
+
const preparedReply = prepareReplyMessage(message, toOriginalMessage);
|
|
4392
|
+
await persistOutgoing(storage, {
|
|
4393
|
+
toOriginalMessage,
|
|
4394
|
+
message: preparedReply
|
|
4395
|
+
});
|
|
4396
|
+
if (storage && !isCurrentStorage(storage))
|
|
4397
|
+
throw new Error("Local storage account changed before sending reply");
|
|
4398
|
+
notifyMessageAttached(notification, { ...preparedReply });
|
|
4399
|
+
assertCurrentSession(session);
|
|
4400
|
+
const result = await callSdkApi("replyMessage", { message: preparedReply, toOriginalMessage, config });
|
|
4401
|
+
if (result?.message && typeof result.message === "object") {
|
|
4402
|
+
return { ...result, message: { ...result.message, clientBizId: preparedReply.clientBizId } };
|
|
4403
|
+
}
|
|
4404
|
+
return result && typeof result === "object" ? { ...result, clientBizId: preparedReply.clientBizId } : result;
|
|
4405
|
+
}
|
|
4406
|
+
function prepareReplyMessage(message, original) {
|
|
4407
|
+
const candidate = { ...message };
|
|
4408
|
+
delete candidate.messageID;
|
|
4409
|
+
delete candidate.localMessageID;
|
|
4410
|
+
delete candidate.localID;
|
|
4411
|
+
delete candidate.orderKey;
|
|
4412
|
+
delete candidate.messageSeq;
|
|
4413
|
+
delete candidate.conversationSeq;
|
|
4414
|
+
delete candidate.id;
|
|
4415
|
+
delete candidate.c2cSeq;
|
|
4416
|
+
delete candidate.clientSid;
|
|
4417
|
+
delete candidate.errorCode;
|
|
4418
|
+
delete candidate.errorMessage;
|
|
4419
|
+
if (candidate.clientBizId && candidate.clientBizId === original.clientBizId)
|
|
4420
|
+
delete candidate.clientBizId;
|
|
4421
|
+
const prepared = withClientBizId(candidate);
|
|
4422
|
+
return {
|
|
4423
|
+
...prepared,
|
|
4424
|
+
localMessageID: prepared.clientBizId,
|
|
4425
|
+
conversationID: original.conversationID ?? candidate.conversationID,
|
|
4426
|
+
conversationType: original.conversationType ?? candidate.conversationType,
|
|
4427
|
+
timestamp: Date.now(),
|
|
4428
|
+
direction: 0,
|
|
4429
|
+
sentStatus: 0,
|
|
4430
|
+
sendState: 0,
|
|
4431
|
+
// Build the quote before persistence/notification, independently of the ACK.
|
|
4432
|
+
// Copy display fields only so editing the draft never changes the original.
|
|
4433
|
+
repliedInfo: {
|
|
4434
|
+
state: original.deleted ? 1 : 0,
|
|
4435
|
+
messageID: original.messageID,
|
|
4436
|
+
messageSeq: original.messageSeq ?? original.id ?? original.c2cSeq,
|
|
4437
|
+
senderUserID: original.senderUserID,
|
|
4438
|
+
sentTime: original.timestamp,
|
|
4439
|
+
messageInfo: {
|
|
4440
|
+
type: original.type,
|
|
4441
|
+
message: original.message instanceof Uint8Array ? original.message.slice() : original.message ?? original.massage ?? "",
|
|
4442
|
+
extendedData: original.extendedData,
|
|
4443
|
+
subType: original.subType,
|
|
4444
|
+
fileName: original.fileName
|
|
4445
|
+
}
|
|
4446
|
+
}
|
|
4447
|
+
};
|
|
4448
|
+
}
|
|
4449
|
+
function queryMessageRepliedList(message, config) {
|
|
4450
|
+
return callSdkApi("queryMessageRepliedList", { message, config });
|
|
4451
|
+
}
|
|
4452
|
+
function queryCombineMessageDetail(config) {
|
|
4453
|
+
return callSdkApi("queryCombineMessageDetail", {
|
|
4454
|
+
combineID: config.combineID
|
|
4455
|
+
});
|
|
4456
|
+
}
|
|
4457
|
+
function searchLocalMessages(conversationID, conversationType, config) {
|
|
4458
|
+
if (captureStorage()) {
|
|
4459
|
+
const read = async () => {
|
|
4460
|
+
const result = await queryLocalMessages({
|
|
4461
|
+
conversationID,
|
|
4462
|
+
conversationType,
|
|
4463
|
+
count: config.count,
|
|
4464
|
+
order: config.order === 1 ? "asc" : "desc",
|
|
4465
|
+
keywords: config.keywords,
|
|
4466
|
+
messageTypes: config.messageTypes,
|
|
4467
|
+
senderUserIDs: config.senderUserIDs,
|
|
4468
|
+
startTime: config.startTime,
|
|
4469
|
+
endTime: config.endTime,
|
|
4470
|
+
before: config.nextMessage ? { timestamp: Number(config.nextMessage.timestamp), localID: String(config.nextMessage.localID || config.nextMessage.localMessageID || "") } : void 0
|
|
4471
|
+
});
|
|
4472
|
+
return {
|
|
4473
|
+
conversationID,
|
|
4474
|
+
conversationType,
|
|
4475
|
+
messageList: result.messageList,
|
|
4476
|
+
nextMessage: result.hasMore ? result.messageList[result.messageList.length - 1] : void 0
|
|
4477
|
+
};
|
|
4478
|
+
};
|
|
4479
|
+
return read();
|
|
4480
|
+
}
|
|
4481
|
+
return callSdkApi("searchLocalMessages", {
|
|
4482
|
+
conversationID,
|
|
4483
|
+
conversationType,
|
|
4484
|
+
config
|
|
4485
|
+
});
|
|
4486
|
+
}
|
|
4487
|
+
function queryMessages(messageIds, conversationID, conversationType) {
|
|
4488
|
+
return callSdkApi("queryMessages", {
|
|
4489
|
+
messageIds,
|
|
4490
|
+
conversationID,
|
|
4491
|
+
conversationType
|
|
4492
|
+
});
|
|
4493
|
+
}
|
|
4494
|
+
var messageExt_default = {
|
|
4495
|
+
editMessage,
|
|
4496
|
+
replyMessage,
|
|
4497
|
+
queryMessageRepliedList,
|
|
4498
|
+
queryCombineMessageDetail,
|
|
4499
|
+
searchLocalMessages,
|
|
4500
|
+
queryMessages
|
|
4501
|
+
};
|
|
4502
|
+
|
|
4503
|
+
// src/sdk/zimApis.ts
|
|
4504
|
+
var ZimApis = {
|
|
4505
|
+
...social_default,
|
|
4506
|
+
...group_default,
|
|
4507
|
+
...conversationExt_default,
|
|
4508
|
+
...messageExt_default
|
|
4509
|
+
};
|
|
4510
|
+
var zimApis_default = ZimApis;
|
|
4511
|
+
|
|
4512
|
+
// src/constants/social/ZIMUserExtension.ts
|
|
4513
|
+
var ZIMUserRelationType = /* @__PURE__ */ ((ZIMUserRelationType2) => {
|
|
4514
|
+
ZIMUserRelationType2[ZIMUserRelationType2["Unknown"] = -1] = "Unknown";
|
|
4515
|
+
ZIMUserRelationType2[ZIMUserRelationType2["None"] = 0] = "None";
|
|
4516
|
+
ZIMUserRelationType2[ZIMUserRelationType2["Friend"] = 1] = "Friend";
|
|
4517
|
+
return ZIMUserRelationType2;
|
|
4518
|
+
})(ZIMUserRelationType || {});
|
|
4519
|
+
var ZIMUserOnlineStatus = /* @__PURE__ */ ((ZIMUserOnlineStatus2) => {
|
|
4520
|
+
ZIMUserOnlineStatus2[ZIMUserOnlineStatus2["Online"] = 0] = "Online";
|
|
4521
|
+
ZIMUserOnlineStatus2[ZIMUserOnlineStatus2["Offline"] = 1] = "Offline";
|
|
4522
|
+
ZIMUserOnlineStatus2[ZIMUserOnlineStatus2["Logout"] = 2] = "Logout";
|
|
4523
|
+
ZIMUserOnlineStatus2[ZIMUserOnlineStatus2["Unknown"] = 99] = "Unknown";
|
|
4524
|
+
return ZIMUserOnlineStatus2;
|
|
4525
|
+
})(ZIMUserOnlineStatus || {});
|
|
4526
|
+
|
|
4527
|
+
// src/constants/social/ZIMFriendExtension.ts
|
|
4528
|
+
var ZIMFriendApplicationType = /* @__PURE__ */ ((ZIMFriendApplicationType2) => {
|
|
4529
|
+
ZIMFriendApplicationType2[ZIMFriendApplicationType2["Unknown"] = -1] = "Unknown";
|
|
4530
|
+
ZIMFriendApplicationType2[ZIMFriendApplicationType2["None"] = 0] = "None";
|
|
4531
|
+
ZIMFriendApplicationType2[ZIMFriendApplicationType2["Received"] = 1] = "Received";
|
|
4532
|
+
ZIMFriendApplicationType2[ZIMFriendApplicationType2["Sent"] = 2] = "Sent";
|
|
4533
|
+
ZIMFriendApplicationType2[ZIMFriendApplicationType2["Both"] = 3] = "Both";
|
|
4534
|
+
return ZIMFriendApplicationType2;
|
|
4535
|
+
})(ZIMFriendApplicationType || {});
|
|
4536
|
+
var ZIMFriendApplicationState = /* @__PURE__ */ ((ZIMFriendApplicationState2) => {
|
|
4537
|
+
ZIMFriendApplicationState2[ZIMFriendApplicationState2["Unknown"] = -1] = "Unknown";
|
|
4538
|
+
ZIMFriendApplicationState2[ZIMFriendApplicationState2["Waiting"] = 1] = "Waiting";
|
|
4539
|
+
ZIMFriendApplicationState2[ZIMFriendApplicationState2["Accepted"] = 2] = "Accepted";
|
|
4540
|
+
ZIMFriendApplicationState2[ZIMFriendApplicationState2["Rejected"] = 3] = "Rejected";
|
|
4541
|
+
ZIMFriendApplicationState2[ZIMFriendApplicationState2["Expired"] = 4] = "Expired";
|
|
4542
|
+
ZIMFriendApplicationState2[ZIMFriendApplicationState2["Disabled"] = 5] = "Disabled";
|
|
4543
|
+
return ZIMFriendApplicationState2;
|
|
4544
|
+
})(ZIMFriendApplicationState || {});
|
|
4545
|
+
var ZIMFriendDeleteType = /* @__PURE__ */ ((ZIMFriendDeleteType2) => {
|
|
4546
|
+
ZIMFriendDeleteType2[ZIMFriendDeleteType2["Both"] = 0] = "Both";
|
|
4547
|
+
ZIMFriendDeleteType2[ZIMFriendDeleteType2["Single"] = 1] = "Single";
|
|
4548
|
+
return ZIMFriendDeleteType2;
|
|
4549
|
+
})(ZIMFriendDeleteType || {});
|
|
4550
|
+
|
|
4551
|
+
// src/constants/group/ZIMGroupExtension.ts
|
|
4552
|
+
var ZIMGroupMessageNotificationStatus = /* @__PURE__ */ ((ZIMGroupMessageNotificationStatus2) => {
|
|
4553
|
+
ZIMGroupMessageNotificationStatus2[ZIMGroupMessageNotificationStatus2["Notify"] = 1] = "Notify";
|
|
4554
|
+
ZIMGroupMessageNotificationStatus2[ZIMGroupMessageNotificationStatus2["DoNotDisturb"] = 2] = "DoNotDisturb";
|
|
4555
|
+
return ZIMGroupMessageNotificationStatus2;
|
|
4556
|
+
})(ZIMGroupMessageNotificationStatus || {});
|
|
4557
|
+
var ZIMGroupMuteMode = /* @__PURE__ */ ((ZIMGroupMuteMode2) => {
|
|
4558
|
+
ZIMGroupMuteMode2[ZIMGroupMuteMode2["None"] = 0] = "None";
|
|
4559
|
+
ZIMGroupMuteMode2[ZIMGroupMuteMode2["Normal"] = 1] = "Normal";
|
|
4560
|
+
ZIMGroupMuteMode2[ZIMGroupMuteMode2["All"] = 2] = "All";
|
|
4561
|
+
ZIMGroupMuteMode2[ZIMGroupMuteMode2["Custom"] = 3] = "Custom";
|
|
4562
|
+
return ZIMGroupMuteMode2;
|
|
4563
|
+
})(ZIMGroupMuteMode || {});
|
|
4564
|
+
var ZIMGroupJoinMode = /* @__PURE__ */ ((ZIMGroupJoinMode2) => {
|
|
4565
|
+
ZIMGroupJoinMode2[ZIMGroupJoinMode2["Any"] = 0] = "Any";
|
|
4566
|
+
ZIMGroupJoinMode2[ZIMGroupJoinMode2["Auth"] = 1] = "Auth";
|
|
4567
|
+
ZIMGroupJoinMode2[ZIMGroupJoinMode2["Forbid"] = 2] = "Forbid";
|
|
4568
|
+
return ZIMGroupJoinMode2;
|
|
4569
|
+
})(ZIMGroupJoinMode || {});
|
|
4570
|
+
var ZIMGroupInviteMode = /* @__PURE__ */ ((ZIMGroupInviteMode2) => {
|
|
4571
|
+
ZIMGroupInviteMode2[ZIMGroupInviteMode2["Any"] = 0] = "Any";
|
|
4572
|
+
ZIMGroupInviteMode2[ZIMGroupInviteMode2["Admin"] = 1] = "Admin";
|
|
4573
|
+
return ZIMGroupInviteMode2;
|
|
4574
|
+
})(ZIMGroupInviteMode || {});
|
|
4575
|
+
var ZIMGroupBeInviteMode = /* @__PURE__ */ ((ZIMGroupBeInviteMode2) => {
|
|
4576
|
+
ZIMGroupBeInviteMode2[ZIMGroupBeInviteMode2["None"] = 0] = "None";
|
|
4577
|
+
ZIMGroupBeInviteMode2[ZIMGroupBeInviteMode2["Auth"] = 1] = "Auth";
|
|
4578
|
+
return ZIMGroupBeInviteMode2;
|
|
4579
|
+
})(ZIMGroupBeInviteMode || {});
|
|
4580
|
+
var ZIMGroupEnterType = /* @__PURE__ */ ((ZIMGroupEnterType2) => {
|
|
4581
|
+
ZIMGroupEnterType2[ZIMGroupEnterType2["Unknown"] = 0] = "Unknown";
|
|
4582
|
+
ZIMGroupEnterType2[ZIMGroupEnterType2["Created"] = 1] = "Created";
|
|
4583
|
+
ZIMGroupEnterType2[ZIMGroupEnterType2["JoinApply"] = 2] = "JoinApply";
|
|
4584
|
+
ZIMGroupEnterType2[ZIMGroupEnterType2["Joined"] = 3] = "Joined";
|
|
4585
|
+
ZIMGroupEnterType2[ZIMGroupEnterType2["Invited"] = 4] = "Invited";
|
|
4586
|
+
ZIMGroupEnterType2[ZIMGroupEnterType2["InviteApply"] = 5] = "InviteApply";
|
|
4587
|
+
return ZIMGroupEnterType2;
|
|
4588
|
+
})(ZIMGroupEnterType || {});
|
|
4589
|
+
var ZIMGroupApplicationType = /* @__PURE__ */ ((ZIMGroupApplicationType2) => {
|
|
4590
|
+
ZIMGroupApplicationType2[ZIMGroupApplicationType2["Unknown"] = -1] = "Unknown";
|
|
4591
|
+
ZIMGroupApplicationType2[ZIMGroupApplicationType2["None"] = 0] = "None";
|
|
4592
|
+
ZIMGroupApplicationType2[ZIMGroupApplicationType2["Join"] = 1] = "Join";
|
|
4593
|
+
ZIMGroupApplicationType2[ZIMGroupApplicationType2["Invite"] = 2] = "Invite";
|
|
4594
|
+
ZIMGroupApplicationType2[ZIMGroupApplicationType2["BeInvite"] = 3] = "BeInvite";
|
|
4595
|
+
return ZIMGroupApplicationType2;
|
|
4596
|
+
})(ZIMGroupApplicationType || {});
|
|
4597
|
+
var ZIMGroupApplicationState = /* @__PURE__ */ ((ZIMGroupApplicationState2) => {
|
|
4598
|
+
ZIMGroupApplicationState2[ZIMGroupApplicationState2["Unknown"] = -1] = "Unknown";
|
|
4599
|
+
ZIMGroupApplicationState2[ZIMGroupApplicationState2["Waiting"] = 1] = "Waiting";
|
|
4600
|
+
ZIMGroupApplicationState2[ZIMGroupApplicationState2["Accepted"] = 2] = "Accepted";
|
|
4601
|
+
ZIMGroupApplicationState2[ZIMGroupApplicationState2["Rejected"] = 3] = "Rejected";
|
|
4602
|
+
ZIMGroupApplicationState2[ZIMGroupApplicationState2["Expired"] = 4] = "Expired";
|
|
4603
|
+
ZIMGroupApplicationState2[ZIMGroupApplicationState2["Disabled"] = 5] = "Disabled";
|
|
4604
|
+
return ZIMGroupApplicationState2;
|
|
4605
|
+
})(ZIMGroupApplicationState || {});
|
|
4606
|
+
|
|
4607
|
+
// src/constants/conversations/ZIMConversationExtension.ts
|
|
4608
|
+
var ZIMConversationNotificationStatus = /* @__PURE__ */ ((ZIMConversationNotificationStatus2) => {
|
|
4609
|
+
ZIMConversationNotificationStatus2[ZIMConversationNotificationStatus2["Notify"] = 1] = "Notify";
|
|
4610
|
+
ZIMConversationNotificationStatus2[ZIMConversationNotificationStatus2["DoNotDisturb"] = 2] = "DoNotDisturb";
|
|
4611
|
+
return ZIMConversationNotificationStatus2;
|
|
4612
|
+
})(ZIMConversationNotificationStatus || {});
|
|
4613
|
+
var ZIMConversationPinnedFilter = /* @__PURE__ */ ((ZIMConversationPinnedFilter2) => {
|
|
4614
|
+
ZIMConversationPinnedFilter2[ZIMConversationPinnedFilter2["All"] = 0] = "All";
|
|
4615
|
+
ZIMConversationPinnedFilter2[ZIMConversationPinnedFilter2["OnlyPinned"] = 1] = "OnlyPinned";
|
|
4616
|
+
ZIMConversationPinnedFilter2[ZIMConversationPinnedFilter2["OnlyUnpinned"] = 2] = "OnlyUnpinned";
|
|
4617
|
+
return ZIMConversationPinnedFilter2;
|
|
4618
|
+
})(ZIMConversationPinnedFilter || {});
|
|
4619
|
+
|
|
4620
|
+
// src/constants/conversations/ZIMConversationDefines.ts
|
|
4621
|
+
var ZIMConversationEvent = /* @__PURE__ */ ((ZIMConversationEvent2) => {
|
|
4622
|
+
ZIMConversationEvent2[ZIMConversationEvent2["Added"] = 0] = "Added";
|
|
4623
|
+
ZIMConversationEvent2[ZIMConversationEvent2["Updated"] = 1] = "Updated";
|
|
4624
|
+
ZIMConversationEvent2[ZIMConversationEvent2["Disabled"] = 2] = "Disabled";
|
|
4625
|
+
ZIMConversationEvent2[ZIMConversationEvent2["Deleted"] = 3] = "Deleted";
|
|
4626
|
+
return ZIMConversationEvent2;
|
|
4627
|
+
})(ZIMConversationEvent || {});
|
|
4628
|
+
|
|
4629
|
+
// src/constants/messages/ZIMMessageExtension.ts
|
|
4630
|
+
var ZIMMessageOrder = /* @__PURE__ */ ((ZIMMessageOrder2) => {
|
|
4631
|
+
ZIMMessageOrder2[ZIMMessageOrder2["Descending"] = 0] = "Descending";
|
|
4632
|
+
ZIMMessageOrder2[ZIMMessageOrder2["Ascending"] = 1] = "Ascending";
|
|
4633
|
+
return ZIMMessageOrder2;
|
|
4634
|
+
})(ZIMMessageOrder || {});
|
|
1047
4635
|
|
|
1048
4636
|
// src/sdk/index.ts
|
|
1049
4637
|
var VanshiSdk = {
|
|
4638
|
+
...storage_default,
|
|
1050
4639
|
// 创建 ws 实例
|
|
1051
4640
|
create: initSocket,
|
|
1052
|
-
// 退出 SDK
|
|
4641
|
+
// 退出 SDK 登录,默认不断开 ws 连接
|
|
1053
4642
|
logout,
|
|
1054
4643
|
// 判断当前 ws 是否连接
|
|
1055
4644
|
isConnected: isSocketConnected,
|
|
@@ -1059,8 +4648,12 @@ var VanshiSdk = {
|
|
|
1059
4648
|
off,
|
|
1060
4649
|
// 登录 SDK
|
|
1061
4650
|
login,
|
|
1062
|
-
//
|
|
4651
|
+
// 音视频通话
|
|
4652
|
+
...call_default,
|
|
4653
|
+
// 查询单个会话
|
|
1063
4654
|
queryConversation,
|
|
4655
|
+
// 查询会话列表
|
|
4656
|
+
queryConversationList,
|
|
1064
4657
|
// 删除全部会话列表
|
|
1065
4658
|
deleteAllConversations,
|
|
1066
4659
|
// 删除单个会话
|
|
@@ -1090,6 +4683,8 @@ var VanshiSdk = {
|
|
|
1090
4683
|
// 查询群消息未读成员列表。
|
|
1091
4684
|
queryGroupMessageReceiptUnreadMemberList,
|
|
1092
4685
|
// 查询群消息已读成员列表。
|
|
1093
|
-
queryGroupMessageReceiptReadMemberList
|
|
4686
|
+
queryGroupMessageReceiptReadMemberList,
|
|
4687
|
+
// 好友、黑名单、用户、群组、会话与消息扩展 API
|
|
4688
|
+
...zimApis_default
|
|
1094
4689
|
};
|
|
1095
4690
|
var sdk_default = VanshiSdk;
|