livekit-client 1.9.3 → 1.9.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. package/README.md +2 -0
  2. package/dist/livekit-client.esm.mjs +125 -908
  3. package/dist/livekit-client.esm.mjs.map +1 -1
  4. package/dist/livekit-client.umd.js +1 -1
  5. package/dist/livekit-client.umd.js.map +1 -1
  6. package/dist/src/api/SignalClient.d.ts +2 -3
  7. package/dist/src/api/SignalClient.d.ts.map +1 -1
  8. package/dist/src/room/PCTransport.d.ts +1 -2
  9. package/dist/src/room/PCTransport.d.ts.map +1 -1
  10. package/dist/src/room/Room.d.ts +1 -0
  11. package/dist/src/room/Room.d.ts.map +1 -1
  12. package/dist/src/room/participant/LocalParticipant.d.ts +0 -1
  13. package/dist/src/room/participant/LocalParticipant.d.ts.map +1 -1
  14. package/dist/src/room/timers.d.ts +4 -5
  15. package/dist/src/room/timers.d.ts.map +1 -1
  16. package/dist/src/room/utils.d.ts.map +1 -1
  17. package/dist/src/utils/AsyncQueue.d.ts +23 -0
  18. package/dist/src/utils/AsyncQueue.d.ts.map +1 -0
  19. package/dist/src/utils/browserParser.d.ts +10 -0
  20. package/dist/src/utils/browserParser.d.ts.map +1 -0
  21. package/dist/ts4.2/src/api/SignalClient.d.ts +2 -3
  22. package/dist/ts4.2/src/room/PCTransport.d.ts +1 -2
  23. package/dist/ts4.2/src/room/Room.d.ts +1 -0
  24. package/dist/ts4.2/src/room/participant/LocalParticipant.d.ts +0 -1
  25. package/dist/ts4.2/src/room/timers.d.ts +4 -5
  26. package/dist/ts4.2/src/utils/AsyncQueue.d.ts +23 -0
  27. package/dist/ts4.2/src/utils/browserParser.d.ts +10 -0
  28. package/package.json +11 -22
  29. package/src/api/SignalClient.ts +4 -5
  30. package/src/connectionHelper/ConnectionCheck.ts +1 -1
  31. package/src/room/PCTransport.ts +1 -1
  32. package/src/room/Room.ts +5 -2
  33. package/src/room/participant/LocalParticipant.ts +0 -1
  34. package/src/room/utils.ts +17 -16
  35. package/src/utils/AsyncQueue.test.ts +99 -0
  36. package/src/utils/AsyncQueue.ts +57 -0
  37. package/src/utils/browserParser.test.ts +58 -0
  38. package/src/utils/browserParser.ts +72 -0
@@ -0,0 +1,99 @@
1
+ import { sleep } from '../room/utils';
2
+ import { AsyncQueue } from './AsyncQueue';
3
+
4
+ describe('asyncQueue', () => {
5
+ it('runs multiple tasks in order', async () => {
6
+ const queue = new AsyncQueue();
7
+ const tasksExecuted: number[] = [];
8
+
9
+ for (let i = 0; i < 5; i++) {
10
+ queue.run(async () => {
11
+ await sleep(50);
12
+ tasksExecuted.push(i);
13
+ });
14
+ }
15
+ await queue.flush();
16
+ expect(tasksExecuted).toMatchObject([0, 1, 2, 3, 4]);
17
+ });
18
+ it('runs tasks sequentially and not in parallel', async () => {
19
+ const queue = new AsyncQueue();
20
+ const results: number[] = [];
21
+ for (let i = 0; i < 5; i++) {
22
+ queue.run(async () => {
23
+ results.push(i);
24
+ await sleep(10);
25
+ results.push(i);
26
+ });
27
+ }
28
+ await queue.flush();
29
+ expect(results).toMatchObject([0, 0, 1, 1, 2, 2, 3, 3, 4, 4]);
30
+ });
31
+ it('continues executing tasks if one task throws an error', async () => {
32
+ const queue = new AsyncQueue();
33
+
34
+ let task1threw = false;
35
+ let task2Executed = false;
36
+
37
+ queue
38
+ .run(async () => {
39
+ await sleep(100);
40
+ throw Error('task 1 throws');
41
+ })
42
+ .catch(() => {
43
+ task1threw = true;
44
+ });
45
+
46
+ await queue
47
+ .run(async () => {
48
+ task2Executed = true;
49
+ })
50
+ .catch(() => {
51
+ fail('task 2 should not have thrown');
52
+ });
53
+
54
+ expect(task1threw).toBeTruthy();
55
+ expect(task2Executed).toBeTruthy();
56
+ });
57
+ it('returns the result of the task', async () => {
58
+ const queue = new AsyncQueue();
59
+
60
+ const result = await queue.run(async () => {
61
+ await sleep(10);
62
+ return 'result';
63
+ });
64
+
65
+ expect(result).toBe('result');
66
+ });
67
+ it('returns only when the enqueued task and all previous tasks have completed', async () => {
68
+ const queue = new AsyncQueue();
69
+ const tasksExecuted: number[] = [];
70
+ for (let i = 0; i < 10; i += 1) {
71
+ queue.run(async () => {
72
+ await sleep(10);
73
+ tasksExecuted.push(i);
74
+ return i;
75
+ });
76
+ }
77
+
78
+ const result = await queue.run(async () => {
79
+ await sleep(10);
80
+ tasksExecuted.push(999);
81
+ return 'result';
82
+ });
83
+
84
+ expect(result).toBe('result');
85
+ expect(tasksExecuted).toMatchObject([...new Array(10).fill(0).map((_, idx) => idx), 999]);
86
+ });
87
+ it('can handle queue sizes of up to 10_000 tasks', async () => {
88
+ const queue = new AsyncQueue();
89
+ const tasksExecuted: number[] = [];
90
+
91
+ for (let i = 0; i < 10_000; i++) {
92
+ queue.run(async () => {
93
+ tasksExecuted.push(i);
94
+ });
95
+ }
96
+ await queue.flush();
97
+ expect(tasksExecuted).toMatchObject(new Array(10_000).fill(0).map((_, idx) => idx));
98
+ });
99
+ });
@@ -0,0 +1,57 @@
1
+ import { Mutex } from '../room/utils';
2
+
3
+ type QueueTask<T> = () => PromiseLike<T>;
4
+
5
+ enum QueueTaskStatus {
6
+ 'WAITING',
7
+ 'RUNNING',
8
+ 'COMPLETED',
9
+ }
10
+
11
+ type QueueTaskInfo = {
12
+ id: number;
13
+ enqueuedAt: number;
14
+ executedAt?: number;
15
+ status: QueueTaskStatus;
16
+ };
17
+
18
+ export class AsyncQueue {
19
+ private pendingTasks: Map<number, QueueTaskInfo>;
20
+
21
+ private taskMutex: Mutex;
22
+
23
+ private nextTaskIndex: number;
24
+
25
+ constructor() {
26
+ this.pendingTasks = new Map();
27
+ this.taskMutex = new Mutex();
28
+ this.nextTaskIndex = 0;
29
+ }
30
+
31
+ async run<T>(task: QueueTask<T>) {
32
+ const taskInfo: QueueTaskInfo = {
33
+ id: this.nextTaskIndex++,
34
+ enqueuedAt: Date.now(),
35
+ status: QueueTaskStatus.WAITING,
36
+ };
37
+ this.pendingTasks.set(taskInfo.id, taskInfo);
38
+ const unlock = await this.taskMutex.lock();
39
+ try {
40
+ taskInfo.executedAt = Date.now();
41
+ taskInfo.status = QueueTaskStatus.RUNNING;
42
+ return await task();
43
+ } finally {
44
+ taskInfo.status = QueueTaskStatus.COMPLETED;
45
+ this.pendingTasks.delete(taskInfo.id);
46
+ unlock();
47
+ }
48
+ }
49
+
50
+ async flush() {
51
+ return this.run(async () => {});
52
+ }
53
+
54
+ snapshot() {
55
+ return Array.from(this.pendingTasks.values());
56
+ }
57
+ }
@@ -0,0 +1,58 @@
1
+ import { compareVersions } from '../room/utils';
2
+ import { getBrowser } from './browserParser';
3
+
4
+ describe('browser parser', () => {
5
+ const safariUA =
6
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.3 Safari/605.1.15';
7
+ const firefoxUA =
8
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/112.0';
9
+
10
+ const chromeUA =
11
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36';
12
+
13
+ const braveUA =
14
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36';
15
+
16
+ it('parses Safari correctly', () => {
17
+ const details = getBrowser(safariUA, true);
18
+ expect(details?.name).toBe('Safari');
19
+ expect(details?.version).toBe('16.3');
20
+ });
21
+ it('parses Firefox correctly', () => {
22
+ const details = getBrowser(firefoxUA, true);
23
+ expect(details?.name).toBe('Firefox');
24
+ expect(details?.version).toBe('112.0');
25
+ });
26
+ it('parses Chrome correctly', () => {
27
+ const details = getBrowser(chromeUA, true);
28
+ expect(details?.name).toBe('Chrome');
29
+ expect(details?.version).toBe('112.0.0.0');
30
+ });
31
+ it('detects brave as chromium based', () => {
32
+ const details = getBrowser(braveUA, true);
33
+ expect(details?.name).toBe('Chrome');
34
+ expect(details?.version).toBe('103.0.5060.134');
35
+ });
36
+ });
37
+
38
+ describe('version compare', () => {
39
+ it('compares versions correctly', () => {
40
+ expect(compareVersions('12.3.5', '11.8.9')).toBe(1);
41
+ expect(compareVersions('12.3.5', '12.3.5')).toBe(0);
42
+ expect(compareVersions('12.3.5', '14.1.5')).toBe(-1);
43
+ });
44
+ it('can handle different version lengths', () => {
45
+ expect(compareVersions('12', '11.8.9')).toBe(1);
46
+ expect(compareVersions('12', '12.0.0')).toBe(0);
47
+ expect(compareVersions('12', '14.1.5')).toBe(-1);
48
+
49
+ expect(compareVersions('12.3.5', '11')).toBe(1);
50
+ expect(compareVersions('12.0.0', '12')).toBe(0);
51
+ expect(compareVersions('12.3.5', '14')).toBe(-1);
52
+ });
53
+
54
+ it('treats empty strings as smaller', () => {
55
+ expect(compareVersions('12', '')).toBe(1);
56
+ expect(compareVersions('', '12.0.0')).toBe(-1);
57
+ });
58
+ });
@@ -0,0 +1,72 @@
1
+ // tiny, simplified version of https://github.com/lancedikson/bowser/blob/master/src/parser-browsers.js
2
+ // reduced to only differentiate Chrome(ium) based browsers / Firefox / Safari
3
+
4
+ const commonVersionIdentifier = /version\/(\d+(\.?_?\d+)+)/i;
5
+
6
+ export type DetectableBrowser = 'Chrome' | 'Firefox' | 'Safari';
7
+
8
+ export type BrowserDetails = {
9
+ name: DetectableBrowser;
10
+ version: string;
11
+ };
12
+
13
+ let browserDetails: BrowserDetails | undefined;
14
+
15
+ /**
16
+ * @internal
17
+ */
18
+ export function getBrowser(userAgent?: string, force = true) {
19
+ if (
20
+ userAgent === undefined &&
21
+ (typeof document !== 'undefined' || typeof navigator === 'undefined')
22
+ ) {
23
+ return;
24
+ }
25
+ const ua = (userAgent ?? navigator.userAgent).toLowerCase();
26
+ if (browserDetails === undefined || force) {
27
+ const browser = browsersList.find(({ test }) => test.test(ua));
28
+ browserDetails = browser?.describe(ua);
29
+ }
30
+ return browserDetails;
31
+ }
32
+
33
+ const browsersList = [
34
+ {
35
+ test: /firefox|iceweasel|fxios/i,
36
+ describe(ua: string) {
37
+ const browser: BrowserDetails = {
38
+ name: 'Firefox',
39
+ version: getMatch(/(?:firefox|iceweasel|fxios)[\s/](\d+(\.?_?\d+)+)/i, ua),
40
+ };
41
+ return browser;
42
+ },
43
+ },
44
+ {
45
+ test: /chrom|crios|crmo/i,
46
+ describe(ua: string) {
47
+ const browser: BrowserDetails = {
48
+ name: 'Chrome',
49
+ version: getMatch(/(?:chrome|chromium|crios|crmo)\/(\d+(\.?_?\d+)+)/i, ua),
50
+ };
51
+
52
+ return browser;
53
+ },
54
+ },
55
+ /* Safari */
56
+ {
57
+ test: /safari|applewebkit/i,
58
+ describe(ua: string) {
59
+ const browser: BrowserDetails = {
60
+ name: 'Safari',
61
+ version: getMatch(commonVersionIdentifier, ua),
62
+ };
63
+
64
+ return browser;
65
+ },
66
+ },
67
+ ];
68
+
69
+ function getMatch(exp: RegExp, ua: string, id = 1) {
70
+ const match = ua.match(exp);
71
+ return (match && match.length >= id && match[id]) || '';
72
+ }