@ermis-network/ermis-chat-sdk 1.0.9 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +330 -0
- package/bin/init-call.js +9 -0
- package/dist/encryption/index.browser.cjs +13045 -0
- package/dist/encryption/index.browser.cjs.map +1 -0
- package/dist/encryption/index.browser.mjs +12959 -0
- package/dist/encryption/index.browser.mjs.map +1 -0
- package/dist/encryption/index.cjs +13045 -0
- package/dist/encryption/index.cjs.map +1 -0
- package/dist/encryption/index.d.mts +3 -0
- package/dist/encryption/index.d.ts +3 -0
- package/dist/encryption/index.mjs +12959 -0
- package/dist/encryption/index.mjs.map +1 -0
- package/dist/index-CcvHIY5q.d.mts +4988 -0
- package/dist/index-CcvHIY5q.d.ts +4988 -0
- package/dist/index.browser.cjs +20399 -6823
- package/dist/index.browser.cjs.map +1 -1
- package/dist/index.browser.full-bundle.min.js +20 -18
- package/dist/index.browser.full-bundle.min.js.map +1 -1
- package/dist/index.browser.mjs +20315 -6790
- package/dist/index.browser.mjs.map +1 -1
- package/dist/index.cjs +20400 -6824
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +167 -1356
- package/dist/index.d.ts +167 -1356
- package/dist/index.mjs +20312 -6787
- package/dist/index.mjs.map +1 -1
- package/dist/wasm_worker.worker.mjs +1600 -0
- package/dist/wasm_worker.worker.mjs.map +1 -0
- package/package.json +22 -7
- package/public/e2ee-media-stream-worker.js +627 -0
- package/public/ermis_call_node_wasm_bg.wasm +0 -0
- package/public/openmls_wasm_bg.wasm +0 -0
- package/src/attachment_utils.ts +0 -148
- package/src/auth.ts +0 -352
- package/src/channel.ts +0 -1806
- package/src/channel_state.ts +0 -607
- package/src/client.ts +0 -1617
- package/src/client_state.ts +0 -55
- package/src/connection.ts +0 -587
- package/src/ermis_call_node.ts +0 -978
- package/src/errors.ts +0 -60
- package/src/events.ts +0 -46
- package/src/hevc_decoder_config.ts +0 -305
- package/src/index.ts +0 -16
- package/src/media_stream_receiver.ts +0 -525
- package/src/media_stream_sender.ts +0 -400
- package/src/shims/empty.ts +0 -1
- package/src/signal_message.ts +0 -146
- package/src/system_message.ts +0 -117
- package/src/token_manager.ts +0 -48
- package/src/types.ts +0 -581
- package/src/utils.ts +0 -534
- package/src/wasm/ermis_call_node_wasm.d.ts +0 -154
- package/src/wasm/ermis_call_node_wasm.js +0 -1498
package/src/utils.ts
DELETED
|
@@ -1,534 +0,0 @@
|
|
|
1
|
-
import FormData from 'form-data';
|
|
2
|
-
import { ExtendableGenerics, DefaultGenerics, MessageResponse, FormatMessageResponse, ForwardMessage } from './types';
|
|
3
|
-
import { AxiosRequestConfig } from 'axios';
|
|
4
|
-
import { ErmisChat } from './client';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* logChatPromiseExecution - utility function for logging the execution of a promise..
|
|
8
|
-
* use this when you want to run the promise and handle errors by logging a warning
|
|
9
|
-
*
|
|
10
|
-
* @param {Promise<T>} promise The promise you want to run and log
|
|
11
|
-
* @param {string} name A descriptive name of what the promise does for log output
|
|
12
|
-
*
|
|
13
|
-
*/
|
|
14
|
-
export function logChatPromiseExecution<T>(promise: Promise<T>, name: string) {
|
|
15
|
-
promise.then().catch((error) => {
|
|
16
|
-
console.warn(`failed to do ${name}, ran into error: `, error);
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const sleep = (m: number): Promise<void> => new Promise((r) => setTimeout(r, m));
|
|
21
|
-
|
|
22
|
-
export function isFunction<T>(value: Function | T): value is Function {
|
|
23
|
-
return (
|
|
24
|
-
value &&
|
|
25
|
-
(Object.prototype.toString.call(value) === '[object Function]' ||
|
|
26
|
-
'function' === typeof value ||
|
|
27
|
-
value instanceof Function)
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export const chatCodes = {
|
|
32
|
-
TOKEN_EXPIRED: 40,
|
|
33
|
-
WS_CLOSED_SUCCESS: 1000,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
function isReadableStream(obj: unknown): obj is NodeJS.ReadStream {
|
|
37
|
-
return (
|
|
38
|
-
obj !== null &&
|
|
39
|
-
typeof obj === 'object' &&
|
|
40
|
-
((obj as NodeJS.ReadStream).readable || typeof (obj as NodeJS.ReadStream)._read === 'function')
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function isBuffer(obj: unknown): obj is Buffer {
|
|
45
|
-
return (
|
|
46
|
-
obj != null &&
|
|
47
|
-
(obj as Buffer).constructor != null &&
|
|
48
|
-
// @ts-expect-error
|
|
49
|
-
typeof obj.constructor.isBuffer === 'function' &&
|
|
50
|
-
// @ts-expect-error
|
|
51
|
-
obj.constructor.isBuffer(obj)
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function isFileWebAPI(uri: unknown): uri is File {
|
|
56
|
-
return typeof window !== 'undefined' && 'File' in window && uri instanceof File;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function isBlobWebAPI(uri: unknown): uri is Blob {
|
|
60
|
-
return typeof window !== 'undefined' && 'Blob' in window && uri instanceof Blob;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function addFileToFormData(
|
|
64
|
-
uri: string | NodeJS.ReadableStream | Buffer | File,
|
|
65
|
-
name?: string,
|
|
66
|
-
contentType?: string,
|
|
67
|
-
) {
|
|
68
|
-
const data = new FormData();
|
|
69
|
-
|
|
70
|
-
if (isReadableStream(uri) || isBuffer(uri) || isFileWebAPI(uri) || isBlobWebAPI(uri)) {
|
|
71
|
-
if (name) data.append('file', uri, name);
|
|
72
|
-
else data.append('file', uri);
|
|
73
|
-
} else {
|
|
74
|
-
data.append('file', {
|
|
75
|
-
uri,
|
|
76
|
-
name: name || (uri as string).split('/').reverse()[0],
|
|
77
|
-
contentType: contentType || undefined,
|
|
78
|
-
type: contentType || undefined,
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return data;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* retryInterval - A retry interval which increases acc to number of failures
|
|
88
|
-
*
|
|
89
|
-
* @return {number} Duration to wait in milliseconds
|
|
90
|
-
*/
|
|
91
|
-
export function retryInterval(numberOfFailures: number) {
|
|
92
|
-
// try to reconnect in 0.25-25 seconds (random to spread out the load from failures)
|
|
93
|
-
const max = Math.min(500 + numberOfFailures * 2000, 25000);
|
|
94
|
-
const min = Math.min(Math.max(250, (numberOfFailures - 1) * 2000), 25000);
|
|
95
|
-
return Math.floor(Math.random() * (max - min) + min);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export function randomId() {
|
|
99
|
-
return generateUUIDv4();
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function hex(bytes: Uint8Array): string {
|
|
103
|
-
let s = '';
|
|
104
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
105
|
-
s += bytes[i].toString(16).padStart(2, '0');
|
|
106
|
-
}
|
|
107
|
-
return s;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// https://tools.ietf.org/html/rfc4122
|
|
111
|
-
export function generateUUIDv4() {
|
|
112
|
-
const bytes = getRandomBytes(16);
|
|
113
|
-
bytes[6] = (bytes[6] & 0x0f) | 0x40; // version
|
|
114
|
-
bytes[8] = (bytes[8] & 0xbf) | 0x80; // variant
|
|
115
|
-
|
|
116
|
-
return (
|
|
117
|
-
hex(bytes.subarray(0, 4)) +
|
|
118
|
-
'-' +
|
|
119
|
-
hex(bytes.subarray(4, 6)) +
|
|
120
|
-
'-' +
|
|
121
|
-
hex(bytes.subarray(6, 8)) +
|
|
122
|
-
'-' +
|
|
123
|
-
hex(bytes.subarray(8, 10)) +
|
|
124
|
-
'-' +
|
|
125
|
-
hex(bytes.subarray(10, 16))
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function getRandomValuesWithMathRandom(bytes: Uint8Array): void {
|
|
130
|
-
const max = Math.pow(2, (8 * bytes.byteLength) / bytes.length);
|
|
131
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
132
|
-
bytes[i] = Math.random() * max;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
declare const msCrypto: Crypto;
|
|
136
|
-
|
|
137
|
-
const getRandomValues = (() => {
|
|
138
|
-
if (typeof crypto !== 'undefined' && typeof crypto?.getRandomValues !== 'undefined') {
|
|
139
|
-
return crypto.getRandomValues.bind(crypto);
|
|
140
|
-
} else if (typeof msCrypto !== 'undefined') {
|
|
141
|
-
return msCrypto.getRandomValues.bind(msCrypto);
|
|
142
|
-
} else {
|
|
143
|
-
return getRandomValuesWithMathRandom;
|
|
144
|
-
}
|
|
145
|
-
})();
|
|
146
|
-
|
|
147
|
-
function getRandomBytes(length: number): Uint8Array {
|
|
148
|
-
const bytes = new Uint8Array(length);
|
|
149
|
-
getRandomValues(bytes);
|
|
150
|
-
return bytes;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* listenForConnectionChanges - Adds an event listener fired on browser going online or offline
|
|
159
|
-
*/
|
|
160
|
-
export function addConnectionEventListeners(cb: (e: Event) => void) {
|
|
161
|
-
if (typeof window !== 'undefined' && window.addEventListener) {
|
|
162
|
-
window.addEventListener('offline', cb);
|
|
163
|
-
window.addEventListener('online', cb);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
export function removeConnectionEventListeners(cb: (e: Event) => void) {
|
|
168
|
-
if (typeof window !== 'undefined' && window.removeEventListener) {
|
|
169
|
-
window.removeEventListener('offline', cb);
|
|
170
|
-
window.removeEventListener('online', cb);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export const axiosParamsSerializer: AxiosRequestConfig['paramsSerializer'] = (params) => {
|
|
175
|
-
const newParams = [];
|
|
176
|
-
for (const k in params) {
|
|
177
|
-
// Ermis backend doesn't treat "undefined" value same as value not being present.
|
|
178
|
-
// So, we need to skip the undefined values.
|
|
179
|
-
if (params[k] === undefined) continue;
|
|
180
|
-
|
|
181
|
-
if (Array.isArray(params[k]) || typeof params[k] === 'object') {
|
|
182
|
-
newParams.push(`${k}=${encodeURIComponent(JSON.stringify(params[k]))}`);
|
|
183
|
-
} else {
|
|
184
|
-
newParams.push(`${k}=${encodeURIComponent(params[k])}`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
return newParams.join('&');
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* formatMessage - Takes the message object. Parses the dates, sets __html
|
|
193
|
-
* and sets the status to received if missing. Returns a message object
|
|
194
|
-
*
|
|
195
|
-
* @param {MessageResponse<ErmisChatGenerics>} message a message object
|
|
196
|
-
*
|
|
197
|
-
*/
|
|
198
|
-
export function formatMessage<ErmisChatGenerics extends ExtendableGenerics = DefaultGenerics>(
|
|
199
|
-
message: MessageResponse<ErmisChatGenerics>,
|
|
200
|
-
): FormatMessageResponse<ErmisChatGenerics> {
|
|
201
|
-
return {
|
|
202
|
-
...message,
|
|
203
|
-
/**
|
|
204
|
-
* @deprecated please use `html`
|
|
205
|
-
*/
|
|
206
|
-
__html: message.html,
|
|
207
|
-
// parse the date..
|
|
208
|
-
pinned_at: message.pinned_at ? new Date(message.pinned_at) : null,
|
|
209
|
-
created_at: message.created_at ? new Date(message.created_at) : new Date(),
|
|
210
|
-
updated_at: message.updated_at ? new Date(message.updated_at) : new Date(),
|
|
211
|
-
status: message.status || 'received',
|
|
212
|
-
};
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
export function addToMessageList<ErmisChatGenerics extends ExtendableGenerics = DefaultGenerics>(
|
|
216
|
-
messages: Array<FormatMessageResponse<ErmisChatGenerics>>,
|
|
217
|
-
message: FormatMessageResponse<ErmisChatGenerics>,
|
|
218
|
-
timestampChanged = false,
|
|
219
|
-
sortBy: 'pinned_at' | 'created_at' = 'created_at',
|
|
220
|
-
addIfDoesNotExist = true,
|
|
221
|
-
) {
|
|
222
|
-
const addMessageToList = addIfDoesNotExist || timestampChanged;
|
|
223
|
-
let messageArr = messages;
|
|
224
|
-
|
|
225
|
-
// if created_at has changed, message should be filtered and re-inserted in correct order
|
|
226
|
-
// slow op but usually this only happens for a message inserted to state before actual response with correct timestamp
|
|
227
|
-
if (timestampChanged) {
|
|
228
|
-
messageArr = messageArr.filter((msg) => !(msg.id && message.id === msg.id));
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// Get array length after filtering
|
|
232
|
-
const messageArrayLength = messageArr.length;
|
|
233
|
-
|
|
234
|
-
// for empty list just concat and return unless it's an update or deletion
|
|
235
|
-
if (messageArrayLength === 0 && addMessageToList) {
|
|
236
|
-
return messageArr.concat(message);
|
|
237
|
-
} else if (messageArrayLength === 0) {
|
|
238
|
-
return [...messageArr];
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (sortBy === 'pinned_at') {
|
|
242
|
-
return messageArr.concat(message);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
const messageTime = (message[sortBy] as Date).getTime();
|
|
246
|
-
const messageIsNewest = (messageArr[messageArrayLength - 1][sortBy] as Date).getTime() < messageTime;
|
|
247
|
-
|
|
248
|
-
// if message is newer than last item in the list concat and return unless it's an update or deletion
|
|
249
|
-
if (messageIsNewest && addMessageToList) {
|
|
250
|
-
return messageArr.concat(message);
|
|
251
|
-
} else if (messageIsNewest) {
|
|
252
|
-
return [...messageArr];
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// find the closest index to push the new message
|
|
256
|
-
let left = 0;
|
|
257
|
-
let middle = 0;
|
|
258
|
-
let right = messageArrayLength - 1;
|
|
259
|
-
while (left <= right) {
|
|
260
|
-
middle = Math.floor((right + left) / 2);
|
|
261
|
-
if ((messageArr[middle][sortBy] as Date).getTime() <= messageTime) left = middle + 1;
|
|
262
|
-
else right = middle - 1;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// message already exists and not filtered due to timestampChanged, update and return
|
|
266
|
-
if (!timestampChanged && message.id) {
|
|
267
|
-
if (messageArr[left] && message.id === messageArr[left].id) {
|
|
268
|
-
messageArr[left] = message;
|
|
269
|
-
return [...messageArr];
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
if (messageArr[left - 1] && message.id === messageArr[left - 1].id) {
|
|
273
|
-
messageArr[left - 1] = message;
|
|
274
|
-
return [...messageArr];
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Do not add updated or deleted messages to the list if they do not already exist
|
|
279
|
-
// or have a timestamp change.
|
|
280
|
-
if (addMessageToList) {
|
|
281
|
-
messageArr.splice(left, 0, message);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Remove duplicate messages by ID
|
|
285
|
-
const map = new Map();
|
|
286
|
-
const uniqueMessages = [];
|
|
287
|
-
|
|
288
|
-
for (const msg of messageArr) {
|
|
289
|
-
if (!map.has(msg.id)) {
|
|
290
|
-
map.set(msg.id, true);
|
|
291
|
-
uniqueMessages.push(msg);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
return uniqueMessages;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
export const enrichWithUserInfo = (items: any[], users: any[]) => {
|
|
298
|
-
if (items.length === 0) return [];
|
|
299
|
-
|
|
300
|
-
if (users.length === 0) {
|
|
301
|
-
return items.map((item) => {
|
|
302
|
-
item.user = { id: item.user?.id, name: item.user?.id, avatar: '' };
|
|
303
|
-
return item;
|
|
304
|
-
});
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
return items.map((item) => {
|
|
308
|
-
const userId = item.user?.id;
|
|
309
|
-
const lastestReactionMsg = item?.latest_reactions;
|
|
310
|
-
const quotedMsg = item?.quoted_message;
|
|
311
|
-
const user = users.find((u) => u.id === userId);
|
|
312
|
-
if (user) {
|
|
313
|
-
item.user = { id: user.id, name: user.name || user.id, avatar: user.avatar || '' };
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
if (lastestReactionMsg) {
|
|
317
|
-
item.latest_reactions = lastestReactionMsg.map((reaction: any) => {
|
|
318
|
-
const reactionUser = users.find((u) => u.id === reaction.user_id);
|
|
319
|
-
return {
|
|
320
|
-
...reaction,
|
|
321
|
-
user: {
|
|
322
|
-
id: reactionUser?.id || reaction.user_id,
|
|
323
|
-
name: reactionUser?.name || reaction.user_id,
|
|
324
|
-
avatar: reactionUser?.avatar || '',
|
|
325
|
-
},
|
|
326
|
-
};
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
if (quotedMsg) {
|
|
331
|
-
const quotedUser = users.find((u) => u.id === quotedMsg.user?.id);
|
|
332
|
-
item.quoted_message.user = {
|
|
333
|
-
id: quotedUser?.id || quotedMsg.user?.id,
|
|
334
|
-
name: quotedUser?.name || quotedMsg.user?.id,
|
|
335
|
-
avatar: quotedUser?.avatar || '',
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return item;
|
|
340
|
-
});
|
|
341
|
-
};
|
|
342
|
-
|
|
343
|
-
export const getUserInfo = (id: string, users: any[]) => {
|
|
344
|
-
if (users.length === 0) {
|
|
345
|
-
return {
|
|
346
|
-
id,
|
|
347
|
-
name: id,
|
|
348
|
-
avatar: '',
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
const user = users.find((u) => u.id === id);
|
|
353
|
-
return {
|
|
354
|
-
id,
|
|
355
|
-
name: user?.name || id,
|
|
356
|
-
avatar: user?.avatar || '',
|
|
357
|
-
};
|
|
358
|
-
};
|
|
359
|
-
|
|
360
|
-
export const getDirectChannelName = (members: any[], currentUserId: string) => {
|
|
361
|
-
if (members.length === 0) {
|
|
362
|
-
return 'Empty channel';
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
const otherMember = members.find((member) => member.user.id !== currentUserId);
|
|
366
|
-
if (otherMember) {
|
|
367
|
-
return otherMember.user.name || otherMember.user.id;
|
|
368
|
-
}
|
|
369
|
-
return 'Empty channel';
|
|
370
|
-
};
|
|
371
|
-
|
|
372
|
-
export const getDirectChannelImage = (members: any[], currentUserId: string) => {
|
|
373
|
-
if (members.length === 0) {
|
|
374
|
-
return '';
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
const otherMember = members.find((member) => member.user.id !== currentUserId);
|
|
378
|
-
if (otherMember) {
|
|
379
|
-
return otherMember.user.avatar || '';
|
|
380
|
-
}
|
|
381
|
-
return '';
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Ensure all members' user info are loaded in state.users.
|
|
386
|
-
* @param client ErmisChat client instance
|
|
387
|
-
* @param members Array of channel members (each member must have user?.id)
|
|
388
|
-
*/
|
|
389
|
-
export async function ensureMembersUserInfoLoaded<ErmisChatGenerics extends ExtendableGenerics = DefaultGenerics>(
|
|
390
|
-
client: ErmisChat<ErmisChatGenerics>,
|
|
391
|
-
members: any[],
|
|
392
|
-
) {
|
|
393
|
-
// Get all memberIds
|
|
394
|
-
const memberIds = (members || []).map((m: any) => m.user?.id).filter((id: string | undefined) => !!id);
|
|
395
|
-
|
|
396
|
-
// Filter out ids that do not exist in users
|
|
397
|
-
const users = client.state.users;
|
|
398
|
-
const missingUserIds = memberIds.filter((id: string) => !users[id]);
|
|
399
|
-
|
|
400
|
-
// If there are users missing, fetch and update them into state
|
|
401
|
-
if (missingUserIds.length > 0) {
|
|
402
|
-
await client.getBatchUsers(missingUserIds);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
export const getLatestCreatedAt = (messages: any[] = []) =>
|
|
407
|
-
messages.length > 0 ? Math.max(...messages.map((msg) => new Date(msg.created_at).getTime())) : 0;
|
|
408
|
-
|
|
409
|
-
export const createPacketWithHeader = (
|
|
410
|
-
data: ArrayBuffer | null,
|
|
411
|
-
timestamp: number | null,
|
|
412
|
-
type: string,
|
|
413
|
-
configMsg: any,
|
|
414
|
-
): Uint8Array => {
|
|
415
|
-
let HEADER_SIZE: number;
|
|
416
|
-
let payload: Uint8Array;
|
|
417
|
-
|
|
418
|
-
// Config messages
|
|
419
|
-
if (['videoConfig', 'audioConfig', 'transciverState'].includes(type) && configMsg) {
|
|
420
|
-
HEADER_SIZE = 1;
|
|
421
|
-
const jsonString = JSON.stringify(configMsg);
|
|
422
|
-
const encoder = new TextEncoder();
|
|
423
|
-
payload = encoder.encode(jsonString);
|
|
424
|
-
} else if (type === 'connected') {
|
|
425
|
-
HEADER_SIZE = 1;
|
|
426
|
-
payload = new Uint8Array(0);
|
|
427
|
-
} else {
|
|
428
|
-
// Data packets
|
|
429
|
-
// HEADER_SIZE = 5;
|
|
430
|
-
HEADER_SIZE = 9;
|
|
431
|
-
payload = new Uint8Array(data!);
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const packet = new Uint8Array(HEADER_SIZE + payload.byteLength);
|
|
435
|
-
|
|
436
|
-
let typeCode: number = 0;
|
|
437
|
-
switch (type) {
|
|
438
|
-
case 'videoConfig':
|
|
439
|
-
typeCode = 0;
|
|
440
|
-
break;
|
|
441
|
-
case 'audioConfig':
|
|
442
|
-
typeCode = 1;
|
|
443
|
-
break;
|
|
444
|
-
case 'video-key':
|
|
445
|
-
typeCode = 2;
|
|
446
|
-
break;
|
|
447
|
-
case 'video-delta':
|
|
448
|
-
typeCode = 3;
|
|
449
|
-
break;
|
|
450
|
-
case 'audio':
|
|
451
|
-
typeCode = 4;
|
|
452
|
-
break;
|
|
453
|
-
case 'connected':
|
|
454
|
-
typeCode = 6;
|
|
455
|
-
break;
|
|
456
|
-
case 'transciverState':
|
|
457
|
-
typeCode = 7;
|
|
458
|
-
break;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
// Byte 0: Type code
|
|
462
|
-
packet[0] = typeCode;
|
|
463
|
-
|
|
464
|
-
// Byte 1-8: Timestamp
|
|
465
|
-
if (timestamp !== null) {
|
|
466
|
-
const view = new DataView(packet.buffer);
|
|
467
|
-
// view.setUint32(1, timestamp, false); // Little-endian = false (Big-endian)
|
|
468
|
-
view.setBigUint64(1, BigInt(timestamp), false);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
packet.set(payload, HEADER_SIZE);
|
|
472
|
-
|
|
473
|
-
return packet;
|
|
474
|
-
};
|
|
475
|
-
|
|
476
|
-
export const base64Encode = (arrayBuffer: ArrayBuffer): string => {
|
|
477
|
-
let binary = '';
|
|
478
|
-
const bytes = new Uint8Array(arrayBuffer);
|
|
479
|
-
const len = bytes.byteLength;
|
|
480
|
-
for (let i = 0; i < len; i++) {
|
|
481
|
-
binary += String.fromCharCode(bytes[i]);
|
|
482
|
-
}
|
|
483
|
-
return btoa(binary);
|
|
484
|
-
};
|
|
485
|
-
|
|
486
|
-
export const replaceCodecNumber = (input: string): string => {
|
|
487
|
-
const map: Record<string, string> = {
|
|
488
|
-
'2048': '123',
|
|
489
|
-
'4096': '153',
|
|
490
|
-
'8192': '156',
|
|
491
|
-
'16384': '183',
|
|
492
|
-
'32768': '186',
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
// Regex để tìm các key
|
|
496
|
-
const regex = /2048|4096|8192|16384|32768/g;
|
|
497
|
-
|
|
498
|
-
// Kiểm tra: Nếu input KHÔNG match bất kỳ số nào trong regex
|
|
499
|
-
// thì trả về chuỗi mặc định
|
|
500
|
-
if (!input.match(regex)) {
|
|
501
|
-
return 'hev1.1.6.L123.B0';
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
// Nếu có match, thực hiện thay thế
|
|
505
|
-
return input.replace(regex, (match) => map[match]);
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
export const createForwardMessagePayload = <ErmisChatGenerics extends ExtendableGenerics = DefaultGenerics>(
|
|
509
|
-
message: FormatMessageResponse<ErmisChatGenerics>,
|
|
510
|
-
targetCid: string,
|
|
511
|
-
activeCid: string,
|
|
512
|
-
): ForwardMessage<ErmisChatGenerics> => {
|
|
513
|
-
const forwardPayload: ForwardMessage<ErmisChatGenerics> = {
|
|
514
|
-
cid: targetCid,
|
|
515
|
-
forward_cid: activeCid,
|
|
516
|
-
forward_message_id: message.id as string,
|
|
517
|
-
};
|
|
518
|
-
|
|
519
|
-
if (
|
|
520
|
-
message.sticker_url &&
|
|
521
|
-
(!message.text || message.text === '') &&
|
|
522
|
-
(!message.attachments || (Array.isArray(message.attachments) && message.attachments.length === 0))
|
|
523
|
-
) {
|
|
524
|
-
forwardPayload.sticker_url = message.sticker_url as string;
|
|
525
|
-
forwardPayload.text = message.text;
|
|
526
|
-
} else {
|
|
527
|
-
forwardPayload.text = message.text || '';
|
|
528
|
-
if (message.attachments && message.attachments.length > 0) {
|
|
529
|
-
forwardPayload.attachments = message.attachments.filter((item: any) => item.type !== 'linkPreview');
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
return forwardPayload;
|
|
534
|
-
};
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
/* tslint:disable */
|
|
2
|
-
/* eslint-disable */
|
|
3
|
-
/**
|
|
4
|
-
* The `ReadableStreamType` enum.
|
|
5
|
-
*
|
|
6
|
-
* *This API requires the following crate features to be activated: `ReadableStreamType`*
|
|
7
|
-
*/
|
|
8
|
-
type ReadableStreamType = "bytes";
|
|
9
|
-
export class ConnectionStats {
|
|
10
|
-
free(): void;
|
|
11
|
-
[Symbol.dispose](): void;
|
|
12
|
-
constructor(connection_type?: string | null, rtt_ms?: number | null, packet_loss?: number | null);
|
|
13
|
-
get rtt_ms(): number | undefined;
|
|
14
|
-
set rtt_ms(value: number | null | undefined);
|
|
15
|
-
get packet_loss(): number | undefined;
|
|
16
|
-
set packet_loss(value: number | null | undefined);
|
|
17
|
-
get connection_type(): string | undefined;
|
|
18
|
-
set connection_type(value: string | null | undefined);
|
|
19
|
-
}
|
|
20
|
-
export class ErmisCall {
|
|
21
|
-
free(): void;
|
|
22
|
-
[Symbol.dispose](): void;
|
|
23
|
-
constructor();
|
|
24
|
-
spawn(relay_urls: any, secret_key?: Uint8Array | null): Promise<void>;
|
|
25
|
-
getLocalEndpointAddr(): Promise<string>;
|
|
26
|
-
connect(addr: string): Promise<void>;
|
|
27
|
-
closeEndpoint(): Promise<void>;
|
|
28
|
-
closeConnection(): void;
|
|
29
|
-
acceptConnection(): Promise<void>;
|
|
30
|
-
sendControlFrame(data: Uint8Array): void;
|
|
31
|
-
sendAudioFrame(data: Uint8Array): void;
|
|
32
|
-
sendFrame(data: Uint8Array): void;
|
|
33
|
-
notifyNewGop(): void;
|
|
34
|
-
recv(): Uint8Array;
|
|
35
|
-
asyncRecv(): Promise<Uint8Array>;
|
|
36
|
-
beginWithGop(data: Uint8Array): void;
|
|
37
|
-
connectionType(): string | undefined;
|
|
38
|
-
roundTripTime(): number | undefined;
|
|
39
|
-
currentPacketLoss(): number | undefined;
|
|
40
|
-
networkChange(): void;
|
|
41
|
-
getStats(): any;
|
|
42
|
-
}
|
|
43
|
-
export class IntoUnderlyingByteSource {
|
|
44
|
-
private constructor();
|
|
45
|
-
free(): void;
|
|
46
|
-
[Symbol.dispose](): void;
|
|
47
|
-
start(controller: ReadableByteStreamController): void;
|
|
48
|
-
pull(controller: ReadableByteStreamController): Promise<any>;
|
|
49
|
-
cancel(): void;
|
|
50
|
-
readonly type: ReadableStreamType;
|
|
51
|
-
readonly autoAllocateChunkSize: number;
|
|
52
|
-
}
|
|
53
|
-
export class IntoUnderlyingSink {
|
|
54
|
-
private constructor();
|
|
55
|
-
free(): void;
|
|
56
|
-
[Symbol.dispose](): void;
|
|
57
|
-
write(chunk: any): Promise<any>;
|
|
58
|
-
close(): Promise<any>;
|
|
59
|
-
abort(reason: any): Promise<any>;
|
|
60
|
-
}
|
|
61
|
-
export class IntoUnderlyingSource {
|
|
62
|
-
private constructor();
|
|
63
|
-
free(): void;
|
|
64
|
-
[Symbol.dispose](): void;
|
|
65
|
-
pull(controller: ReadableStreamDefaultController): Promise<any>;
|
|
66
|
-
cancel(): void;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
|
70
|
-
|
|
71
|
-
export interface InitOutput {
|
|
72
|
-
readonly memory: WebAssembly.Memory;
|
|
73
|
-
readonly __wbg_ermiscall_free: (a: number, b: number) => void;
|
|
74
|
-
readonly ermiscall_new: () => number;
|
|
75
|
-
readonly ermiscall_spawn: (a: number, b: number, c: number, d: number) => number;
|
|
76
|
-
readonly ermiscall_getLocalEndpointAddr: (a: number) => number;
|
|
77
|
-
readonly ermiscall_connect: (a: number, b: number, c: number) => number;
|
|
78
|
-
readonly ermiscall_closeEndpoint: (a: number) => number;
|
|
79
|
-
readonly ermiscall_closeConnection: (a: number, b: number) => void;
|
|
80
|
-
readonly ermiscall_acceptConnection: (a: number) => number;
|
|
81
|
-
readonly ermiscall_sendControlFrame: (a: number, b: number, c: number, d: number) => void;
|
|
82
|
-
readonly ermiscall_sendAudioFrame: (a: number, b: number, c: number, d: number) => void;
|
|
83
|
-
readonly ermiscall_sendFrame: (a: number, b: number, c: number, d: number) => void;
|
|
84
|
-
readonly ermiscall_notifyNewGop: (a: number, b: number) => void;
|
|
85
|
-
readonly ermiscall_recv: (a: number, b: number) => void;
|
|
86
|
-
readonly ermiscall_asyncRecv: (a: number) => number;
|
|
87
|
-
readonly ermiscall_beginWithGop: (a: number, b: number, c: number, d: number) => void;
|
|
88
|
-
readonly ermiscall_connectionType: (a: number, b: number) => void;
|
|
89
|
-
readonly ermiscall_roundTripTime: (a: number, b: number) => void;
|
|
90
|
-
readonly ermiscall_currentPacketLoss: (a: number, b: number) => void;
|
|
91
|
-
readonly ermiscall_networkChange: (a: number) => void;
|
|
92
|
-
readonly __wbg_connectionstats_free: (a: number, b: number) => void;
|
|
93
|
-
readonly __wbg_get_connectionstats_rtt_ms: (a: number, b: number) => void;
|
|
94
|
-
readonly __wbg_set_connectionstats_rtt_ms: (a: number, b: number, c: number) => void;
|
|
95
|
-
readonly __wbg_get_connectionstats_packet_loss: (a: number, b: number) => void;
|
|
96
|
-
readonly __wbg_set_connectionstats_packet_loss: (a: number, b: number, c: number) => void;
|
|
97
|
-
readonly connectionstats_new: (a: number, b: number, c: number, d: number, e: number, f: number) => number;
|
|
98
|
-
readonly connectionstats_connection_type: (a: number, b: number) => void;
|
|
99
|
-
readonly connectionstats_set_connection_type: (a: number, b: number, c: number) => void;
|
|
100
|
-
readonly ermiscall_getStats: (a: number, b: number) => void;
|
|
101
|
-
readonly __wbg_intounderlyingbytesource_free: (a: number, b: number) => void;
|
|
102
|
-
readonly intounderlyingbytesource_type: (a: number) => number;
|
|
103
|
-
readonly intounderlyingbytesource_autoAllocateChunkSize: (a: number) => number;
|
|
104
|
-
readonly intounderlyingbytesource_start: (a: number, b: number) => void;
|
|
105
|
-
readonly intounderlyingbytesource_pull: (a: number, b: number) => number;
|
|
106
|
-
readonly intounderlyingbytesource_cancel: (a: number) => void;
|
|
107
|
-
readonly __wbg_intounderlyingsource_free: (a: number, b: number) => void;
|
|
108
|
-
readonly intounderlyingsource_pull: (a: number, b: number) => number;
|
|
109
|
-
readonly intounderlyingsource_cancel: (a: number) => void;
|
|
110
|
-
readonly __wbg_intounderlyingsink_free: (a: number, b: number) => void;
|
|
111
|
-
readonly intounderlyingsink_write: (a: number, b: number) => number;
|
|
112
|
-
readonly intounderlyingsink_close: (a: number) => number;
|
|
113
|
-
readonly intounderlyingsink_abort: (a: number, b: number) => number;
|
|
114
|
-
readonly ring_core_0_17_14__bn_mul_mont: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
|
115
|
-
readonly __wasm_bindgen_func_elem_12858: (a: number, b: number) => void;
|
|
116
|
-
readonly __wasm_bindgen_func_elem_12841: (a: number, b: number) => void;
|
|
117
|
-
readonly __wasm_bindgen_func_elem_11688: (a: number, b: number, c: number) => void;
|
|
118
|
-
readonly __wasm_bindgen_func_elem_11664: (a: number, b: number) => void;
|
|
119
|
-
readonly __wasm_bindgen_func_elem_6230: (a: number, b: number) => void;
|
|
120
|
-
readonly __wasm_bindgen_func_elem_6219: (a: number, b: number) => void;
|
|
121
|
-
readonly __wasm_bindgen_func_elem_2287: (a: number, b: number, c: number) => void;
|
|
122
|
-
readonly __wasm_bindgen_func_elem_2083: (a: number, b: number) => void;
|
|
123
|
-
readonly __wasm_bindgen_func_elem_12912: (a: number, b: number, c: number) => void;
|
|
124
|
-
readonly __wasm_bindgen_func_elem_12896: (a: number, b: number) => void;
|
|
125
|
-
readonly __wasm_bindgen_func_elem_5748: (a: number, b: number) => void;
|
|
126
|
-
readonly __wasm_bindgen_func_elem_5735: (a: number, b: number) => void;
|
|
127
|
-
readonly __wasm_bindgen_func_elem_14376: (a: number, b: number, c: number, d: number) => void;
|
|
128
|
-
readonly __wbindgen_export: (a: number, b: number) => number;
|
|
129
|
-
readonly __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
|
|
130
|
-
readonly __wbindgen_export3: (a: number) => void;
|
|
131
|
-
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
|
|
132
|
-
readonly __wbindgen_export4: (a: number, b: number, c: number) => void;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export type SyncInitInput = BufferSource | WebAssembly.Module;
|
|
136
|
-
/**
|
|
137
|
-
* Instantiates the given `module`, which can either be bytes or
|
|
138
|
-
* a precompiled `WebAssembly.Module`.
|
|
139
|
-
*
|
|
140
|
-
* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
|
|
141
|
-
*
|
|
142
|
-
* @returns {InitOutput}
|
|
143
|
-
*/
|
|
144
|
-
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
|
|
148
|
-
* for everything else, calls `WebAssembly.instantiate` directly.
|
|
149
|
-
*
|
|
150
|
-
* @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
|
|
151
|
-
*
|
|
152
|
-
* @returns {Promise<InitOutput>}
|
|
153
|
-
*/
|
|
154
|
-
export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
|