@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.
Files changed (54) hide show
  1. package/README.md +330 -0
  2. package/bin/init-call.js +9 -0
  3. package/dist/encryption/index.browser.cjs +13045 -0
  4. package/dist/encryption/index.browser.cjs.map +1 -0
  5. package/dist/encryption/index.browser.mjs +12959 -0
  6. package/dist/encryption/index.browser.mjs.map +1 -0
  7. package/dist/encryption/index.cjs +13045 -0
  8. package/dist/encryption/index.cjs.map +1 -0
  9. package/dist/encryption/index.d.mts +3 -0
  10. package/dist/encryption/index.d.ts +3 -0
  11. package/dist/encryption/index.mjs +12959 -0
  12. package/dist/encryption/index.mjs.map +1 -0
  13. package/dist/index-CcvHIY5q.d.mts +4988 -0
  14. package/dist/index-CcvHIY5q.d.ts +4988 -0
  15. package/dist/index.browser.cjs +20399 -6823
  16. package/dist/index.browser.cjs.map +1 -1
  17. package/dist/index.browser.full-bundle.min.js +20 -18
  18. package/dist/index.browser.full-bundle.min.js.map +1 -1
  19. package/dist/index.browser.mjs +20315 -6790
  20. package/dist/index.browser.mjs.map +1 -1
  21. package/dist/index.cjs +20400 -6824
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.mts +167 -1356
  24. package/dist/index.d.ts +167 -1356
  25. package/dist/index.mjs +20312 -6787
  26. package/dist/index.mjs.map +1 -1
  27. package/dist/wasm_worker.worker.mjs +1600 -0
  28. package/dist/wasm_worker.worker.mjs.map +1 -0
  29. package/package.json +22 -7
  30. package/public/e2ee-media-stream-worker.js +627 -0
  31. package/public/ermis_call_node_wasm_bg.wasm +0 -0
  32. package/public/openmls_wasm_bg.wasm +0 -0
  33. package/src/attachment_utils.ts +0 -148
  34. package/src/auth.ts +0 -352
  35. package/src/channel.ts +0 -1806
  36. package/src/channel_state.ts +0 -607
  37. package/src/client.ts +0 -1617
  38. package/src/client_state.ts +0 -55
  39. package/src/connection.ts +0 -587
  40. package/src/ermis_call_node.ts +0 -978
  41. package/src/errors.ts +0 -60
  42. package/src/events.ts +0 -46
  43. package/src/hevc_decoder_config.ts +0 -305
  44. package/src/index.ts +0 -16
  45. package/src/media_stream_receiver.ts +0 -525
  46. package/src/media_stream_sender.ts +0 -400
  47. package/src/shims/empty.ts +0 -1
  48. package/src/signal_message.ts +0 -146
  49. package/src/system_message.ts +0 -117
  50. package/src/token_manager.ts +0 -48
  51. package/src/types.ts +0 -581
  52. package/src/utils.ts +0 -534
  53. package/src/wasm/ermis_call_node_wasm.d.ts +0 -154
  54. package/src/wasm/ermis_call_node_wasm.js +0 -1498
package/src/errors.ts DELETED
@@ -1,60 +0,0 @@
1
- import { AxiosResponse } from 'axios';
2
- import { APIErrorResponse } from './types';
3
-
4
- export const APIErrorCodes: Record<string, { name: string; retryable: boolean }> = {
5
- '-1': { name: 'InternalSystemError', retryable: true },
6
- '2': { name: 'AccessKeyError', retryable: false },
7
- '3': { name: 'AuthenticationFailedError', retryable: true },
8
- '4': { name: 'InputError', retryable: false },
9
- '6': { name: 'DuplicateUsernameError', retryable: false },
10
- '9': { name: 'RateLimitError', retryable: true },
11
- '16': { name: 'DoesNotExistError', retryable: false },
12
- '17': { name: 'NotAllowedError', retryable: false },
13
- '18': { name: 'EventNotSupportedError', retryable: false },
14
- '19': { name: 'ChannelFeatureNotSupportedError', retryable: false },
15
- '20': { name: 'MessageTooLongError', retryable: false },
16
- '21': { name: 'MultipleNestingLevelError', retryable: false },
17
- '22': { name: 'PayloadTooBigError', retryable: false },
18
- '23': { name: 'RequestTimeoutError', retryable: true },
19
- '24': { name: 'MaxHeaderSizeExceededError', retryable: false },
20
- '40': { name: 'AuthErrorTokenExpired', retryable: false },
21
- '41': { name: 'AuthErrorTokenNotValidYet', retryable: false },
22
- '42': { name: 'AuthErrorTokenUsedBeforeIssuedAt', retryable: false },
23
- '43': { name: 'AuthErrorTokenSignatureInvalid', retryable: false },
24
- '44': { name: 'CustomCommandEndpointMissingError', retryable: false },
25
- '45': { name: 'CustomCommandEndpointCallError', retryable: true },
26
- '60': { name: 'CoolDownError', retryable: true },
27
- '69': { name: 'ErrWrongRegion', retryable: false },
28
- '70': { name: 'ErrQueryChannelPermissions', retryable: false },
29
- '71': { name: 'ErrTooManyConnections', retryable: true },
30
- '99': { name: 'AppSuspendedError', retryable: false },
31
- };
32
-
33
- type APIError = Error & { code: number; isWSFailure?: boolean };
34
-
35
- export function isAPIError(error: Error): error is APIError {
36
- return (error as APIError).code !== undefined;
37
- }
38
-
39
- export function isErrorRetryable(error: APIError) {
40
- if (!error.code) return false;
41
- const err = APIErrorCodes[`${error.code}`];
42
- if (!err) return false;
43
- return err.retryable;
44
- }
45
-
46
- export function isWSFailure(err: APIError): boolean {
47
- if (typeof err.isWSFailure === 'boolean') {
48
- return err.isWSFailure;
49
- }
50
-
51
- try {
52
- return JSON.parse(err.message).isWSFailure;
53
- } catch (_) {
54
- return false;
55
- }
56
- }
57
-
58
- export function isErrorResponse(res: AxiosResponse<unknown>): res is AxiosResponse<APIErrorResponse> {
59
- return !res.status || res.status < 200 || 300 <= res.status;
60
- }
package/src/events.ts DELETED
@@ -1,46 +0,0 @@
1
- export const EVENT_MAP = {
2
- 'channel.created': true,
3
- 'channel.deleted': true,
4
- 'channel.truncate': true,
5
- 'channel.updated': true,
6
- 'channel.pinned': true,
7
- 'channel.unpinned': true,
8
- 'health.check': true,
9
- 'member.added': true,
10
- 'member.removed': true,
11
- 'member.updated': true,
12
- 'member.joined': true,
13
- 'member.promoted': true,
14
- 'member.demoted': true,
15
- 'member.banned': true,
16
- 'member.unbanned': true,
17
- 'member.blocked': true,
18
- 'member.unblocked': true,
19
- 'message.deleted': true,
20
- 'message.deleted_for_me': true,
21
- 'message.new': true,
22
- 'message.read': true,
23
- 'message.updated': true,
24
- 'message.pinned': true,
25
- 'message.unpinned': true,
26
- 'notification.channel_deleted': true,
27
- 'notification.invite_accepted': true,
28
- 'notification.invite_rejected': true,
29
- 'notification.invite_messaging_skipped': true,
30
- 'pollchoice.new': true,
31
- 'reaction.deleted': true,
32
- 'reaction.new': true,
33
- 'typing.start': true,
34
- 'typing.stop': true,
35
- 'user.watching.start': true,
36
- 'user.watching.stop': true,
37
- 'connection.changed': true,
38
- 'connection.recovered': true,
39
- 'capabilities.changed': true,
40
- 'channel.topic.disabled': true,
41
- 'channel.topic.enabled': true,
42
- 'channel.topic.created': true,
43
- 'channel.topic.closed': true,
44
- 'channel.topic.reopen': true,
45
- 'channel.topic.updated': true,
46
- };
@@ -1,305 +0,0 @@
1
- // 1. Định nghĩa các hằng số NAL Unit
2
- export const NALUnitType = {
3
- VPS_NUT: 32,
4
- SPS_NUT: 33,
5
- PPS_NUT: 34,
6
- PREFIX_SEI_NUT: 39,
7
- SUFFIX_SEI_NUT: 40,
8
-
9
- fromValue(value: number): string | number {
10
- const types: Record<number, string> = {
11
- 32: 'VPS_NUT',
12
- 33: 'SPS_NUT',
13
- 34: 'PPS_NUT',
14
- 39: 'PREFIX_SEI_NUT',
15
- 40: 'SUFFIX_SEI_NUT',
16
- };
17
- return types[value] || value;
18
- },
19
- } as const;
20
-
21
- // 2. Interface cho mảng NAL Unit bên trong config
22
- export interface INALArray {
23
- arrayCompleteness: boolean;
24
- nalUnitType: string | number;
25
- nalus: Uint8Array[];
26
- }
27
-
28
- // 3. Interface cho cấu hình HEVC (giúp strict type checking)
29
- export interface IHEVCConfig {
30
- generalProfileSpace: number;
31
- generalTierFlag: boolean;
32
- generalProfileIdc: number;
33
- generalProfileCompatibilityFlags: number;
34
- generalConstraintIndicatorFlags: number;
35
- generalLevelIdc: number;
36
- minSpatialSegmentationIdc: number;
37
- parallelismType: number;
38
- chromaFormatIdc: number;
39
- bitDepthLumaMinus8: number;
40
- bitDepthChromaMinus8: number;
41
- avgFrameRate: number;
42
- constantFrameRate: number;
43
- numTemporalLayers: number;
44
- temporalIdNested: boolean;
45
- lengthSizeMinusOne: number;
46
- arrays: INALArray[];
47
- }
48
-
49
- export class HEVCDecoderConfigurationRecord implements IHEVCConfig {
50
- // Khai báo các thuộc tính của class
51
- public generalProfileSpace: number = 0;
52
- public generalTierFlag: boolean = false;
53
- public generalProfileIdc: number = 0;
54
- public generalProfileCompatibilityFlags: number = 0;
55
- public generalConstraintIndicatorFlags: number = 0;
56
- public generalLevelIdc: number = 0;
57
- public minSpatialSegmentationIdc: number = 0;
58
- public parallelismType: number = 0;
59
- public chromaFormatIdc: number = 0;
60
- public bitDepthLumaMinus8: number = 0;
61
- public bitDepthChromaMinus8: number = 0;
62
- public avgFrameRate: number = 0;
63
- public constantFrameRate: number = 0;
64
- public numTemporalLayers: number = 0;
65
- public temporalIdNested: boolean = false;
66
- public lengthSizeMinusOne: number = 0;
67
- public arrays: INALArray[] = [];
68
-
69
- constructor(config: IHEVCConfig) {
70
- Object.assign(this, config);
71
- }
72
-
73
- /**
74
- * Demuxes an HEVCDecoderConfigurationRecord from a byte buffer.
75
- * @param data - The byte data to parse
76
- */
77
- static demux(data: ArrayBuffer | Uint8Array): HEVCDecoderConfigurationRecord {
78
- const buffer = data instanceof Uint8Array ? data : new Uint8Array(data);
79
- const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
80
-
81
- let offset = 0;
82
- let bitOffset = 0;
83
-
84
- // Helper to read bits
85
- const readBits = (numBits: number): number => {
86
- let result = 0;
87
- for (let i = 0; i < numBits; i++) {
88
- if (offset >= buffer.length) throw new Error('End of buffer');
89
- const bit = (buffer[offset] >> (7 - bitOffset)) & 1;
90
- result = (result << 1) | bit;
91
- bitOffset++;
92
- if (bitOffset === 8) {
93
- bitOffset = 0;
94
- offset++;
95
- }
96
- }
97
- return result;
98
- };
99
-
100
- // Helper to read a byte
101
- const readU8 = (): number => {
102
- if (bitOffset !== 0) return readBits(8);
103
- if (offset >= buffer.length) throw new Error('End of buffer');
104
- return buffer[offset++];
105
- };
106
-
107
- // Helper to read 16-bit big-endian
108
- const readU16BE = (): number => {
109
- if (bitOffset !== 0) return readBits(16);
110
- const val = view.getUint16(offset, false);
111
- offset += 2;
112
- return val;
113
- };
114
-
115
- // Helper to read 32-bit big-endian
116
- const readU32BE = (): number => {
117
- if (bitOffset !== 0) return readBits(32);
118
- const val = view.getUint32(offset, false);
119
- offset += 4;
120
- return val;
121
- };
122
-
123
- // Helper to read 48-bit big-endian
124
- const readU48BE = (): number => {
125
- const high = readU16BE();
126
- const low = readU32BE();
127
- return high * 0x100000000 + low;
128
- };
129
-
130
- // Helper to read exact bytes
131
- const readExact = (length: number): Uint8Array => {
132
- if (bitOffset !== 0) {
133
- const result = new Uint8Array(length);
134
- for (let i = 0; i < length; i++) {
135
- result[i] = readBits(8);
136
- }
137
- return result;
138
- }
139
- if (offset + length > buffer.length) throw new Error('End of buffer');
140
- const result = buffer.slice(offset, offset + length);
141
- offset += length;
142
- return result;
143
- };
144
-
145
- // Parse configuration version
146
- const configurationVersion = readU8();
147
- if (configurationVersion !== 1) {
148
- throw new Error('Invalid configuration version');
149
- }
150
-
151
- // Parse profile information
152
- const generalProfileSpace = readBits(2);
153
- const generalTierFlag = readBits(1) === 1;
154
- const generalProfileIdc = readBits(5);
155
- const generalProfileCompatibilityFlags = readU32BE();
156
- const generalConstraintIndicatorFlags = readU48BE();
157
- const generalLevelIdc = readU8();
158
-
159
- // Parse spatial segmentation
160
- readBits(4); // reserved_4bits
161
- const minSpatialSegmentationIdc = readBits(12);
162
-
163
- // Parse parallelism type
164
- readBits(6); // reserved_6bits
165
- const parallelismType = readBits(2);
166
-
167
- // Parse chroma format
168
- readBits(6); // reserved_6bits
169
- const chromaFormatIdc = readBits(2);
170
-
171
- // Parse bit depth (luma)
172
- readBits(5); // reserved_5bits
173
- const bitDepthLumaMinus8 = readBits(3);
174
-
175
- // Parse bit depth (chroma)
176
- readBits(5); // reserved_5bits
177
- const bitDepthChromaMinus8 = readBits(3);
178
-
179
- // Parse frame rate and temporal information
180
- const avgFrameRate = readU16BE();
181
- const constantFrameRate = readBits(2);
182
- const numTemporalLayers = readBits(3);
183
- const temporalIdNested = readBits(1) === 1;
184
- const lengthSizeMinusOne = readBits(2);
185
-
186
- if (lengthSizeMinusOne === 2) {
187
- throw new Error('length_size_minus_one must be 0, 1, or 3');
188
- }
189
-
190
- // Parse NALU arrays
191
- const numOfArrays = readU8();
192
- const arrays: INALArray[] = [];
193
-
194
- for (let i = 0; i < numOfArrays; i++) {
195
- const arrayCompleteness = readBits(1) === 1;
196
- readBits(1); // reserved
197
- const nalUnitType = readBits(6);
198
- const nalUnitTypeName = NALUnitType.fromValue(nalUnitType);
199
-
200
- if (
201
- nalUnitType !== NALUnitType.VPS_NUT &&
202
- nalUnitType !== NALUnitType.SPS_NUT &&
203
- nalUnitType !== NALUnitType.PPS_NUT &&
204
- nalUnitType !== NALUnitType.PREFIX_SEI_NUT &&
205
- nalUnitType !== NALUnitType.SUFFIX_SEI_NUT
206
- ) {
207
- // Có thể comment dòng này nếu muốn hỗ trợ các loại NALU khác không chuẩn
208
- // throw new Error('Invalid nal_unit_type');
209
- }
210
-
211
- const numNalus = readU16BE();
212
- const nalus: Uint8Array[] = [];
213
-
214
- for (let j = 0; j < numNalus; j++) {
215
- const nalUnitLength = readU16BE();
216
- const naluData = readExact(nalUnitLength);
217
- nalus.push(naluData);
218
- }
219
-
220
- arrays.push({
221
- arrayCompleteness,
222
- nalUnitType: nalUnitTypeName,
223
- nalus,
224
- });
225
- }
226
-
227
- return new HEVCDecoderConfigurationRecord({
228
- generalProfileSpace,
229
- generalTierFlag,
230
- generalProfileIdc,
231
- generalProfileCompatibilityFlags,
232
- generalConstraintIndicatorFlags,
233
- generalLevelIdc,
234
- minSpatialSegmentationIdc,
235
- parallelismType,
236
- chromaFormatIdc,
237
- bitDepthLumaMinus8,
238
- bitDepthChromaMinus8,
239
- avgFrameRate,
240
- constantFrameRate,
241
- numTemporalLayers,
242
- temporalIdNested,
243
- lengthSizeMinusOne,
244
- arrays,
245
- });
246
- }
247
-
248
- /**
249
- * Converts the HEVC configuration to a codec string (RFC 6381 format).
250
- * @returns Codec string like "hev1.1.6.L93.B0"
251
- */
252
- toCodecString(): string {
253
- const profileSpaceMap: Record<number, string> = { 0: '', 1: 'A', 2: 'B', 3: 'C' };
254
- const generalProfileSpace = profileSpaceMap[this.generalProfileSpace];
255
-
256
- if (generalProfileSpace === undefined) {
257
- throw new Error('Unknown profile space');
258
- }
259
-
260
- const profileAndSpace = `${generalProfileSpace}${this.generalProfileIdc}`;
261
-
262
- // Format profile compatibility flags (reverse hex and strip trailing zeros)
263
- let profileCompatibilityFlagsUnfiltered = this.generalProfileCompatibilityFlags
264
- .toString(16)
265
- .padStart(8, '0')
266
- .split('')
267
- .reverse()
268
- .join('');
269
-
270
- let profileCompatibilityFlags = '';
271
- for (let i = 0; i < profileCompatibilityFlagsUnfiltered.length; i++) {
272
- const char = profileCompatibilityFlagsUnfiltered[i];
273
- if (char !== '0' || i === 0) {
274
- profileCompatibilityFlags += char;
275
- }
276
- }
277
-
278
- // Format tier and level
279
- const generalTierFlag = this.generalTierFlag ? 'H' : 'L';
280
- const tierAndLevel = `${generalTierFlag}${this.generalLevelIdc}`;
281
-
282
- // Format constraint flags (skip first 2 bytes of 48-bit value)
283
- let constraintFlags = '';
284
-
285
- // Convert 48-bit number to 6 bytes
286
- const constraint = this.generalConstraintIndicatorFlags;
287
- const bytes = [
288
- Math.floor(constraint / 0x10000000000) & 0xff,
289
- Math.floor(constraint / 0x100000000) & 0xff,
290
- Math.floor(constraint / 0x1000000) & 0xff,
291
- Math.floor(constraint / 0x10000) & 0xff,
292
- Math.floor(constraint / 0x100) & 0xff,
293
- constraint & 0xff,
294
- ];
295
-
296
- // Skip first 2 bytes (bytes[0] and bytes[1]) per Logic
297
- for (let i = 2; i < 6; i++) {
298
- if (bytes[i] !== 0) {
299
- constraintFlags += `.${bytes[i].toString(16).padStart(2, '0')}`;
300
- }
301
- }
302
-
303
- return `hev1.${profileAndSpace}.${profileCompatibilityFlags}.${tierAndLevel}${constraintFlags}`;
304
- }
305
- }
package/src/index.ts DELETED
@@ -1,16 +0,0 @@
1
- export * from './client';
2
- export * from './client_state';
3
- export * from './channel';
4
- export * from './channel_state';
5
- export * from './connection';
6
- export * from './events';
7
- export * from './token_manager';
8
- export * from './types';
9
- export * from './ermis_call_node';
10
- export * from './auth';
11
- export { chatCodes, logChatPromiseExecution, formatMessage, createForwardMessagePayload } from './utils';
12
- export { parseSystemMessage } from './system_message';
13
- export { parseSignalMessage, CallType } from './signal_message';
14
- export type { SignalMessageResult, CallTypeValue } from './signal_message';
15
- export { normalizeFileName, getAttachmentCategory, isVideoFile, isHeicFile, buildAttachmentPayload } from './attachment_utils';
16
- export type { VoiceRecordingMeta } from './attachment_utils';