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