@pexip/media-control 19.1.0 → 20.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/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  # Changelog
2
2
 
3
+ ## 20.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - @pexip/utils@17.0.0
8
+
9
+ ## 20.0.0
10
+
11
+ ### Major Changes
12
+
13
+ - 2bfd9e1: Adds esm entry points.
14
+
15
+ ### Minor Changes
16
+
17
+ - 3555d9d: Adds `build:sourcemap` script.
18
+ - 7d94f5c: Take unauthorized device into account
19
+ - ed53b05: Upgrade Typescript
20
+
21
+ ### Patch Changes
22
+
23
+ - b0d8af9: Enable recommended lint rules
24
+ - e76a15e: Migrate to biome linter
25
+ - Updated dependencies [2bfd9e1]
26
+ - Updated dependencies [4fe77de]
27
+ - Updated dependencies [2bbff64]
28
+ - Updated dependencies [4ea0492]
29
+ - Updated dependencies [3555d9d]
30
+ - Updated dependencies [1601985]
31
+ - Updated dependencies [84956b8]
32
+ - Updated dependencies [ed53b05]
33
+ - Updated dependencies [d681fd3]
34
+ - Updated dependencies [e76a15e]
35
+ - @pexip/utils@17.0.0
36
+
3
37
  ## 19.1.0
4
38
 
5
39
  ## 19.0.0
@@ -9,7 +9,7 @@ export declare enum LogLevels {
9
9
  warn = 40,
10
10
  error = 50,
11
11
  fatal = 60,
12
- silent
12
+ silent = 9007199254740991
13
13
  }
14
14
  export type LogLevelsString = keyof typeof LogLevels;
15
15
  export type LogMethods = {
@@ -21,14 +21,23 @@ export type LogMethods = {
21
21
  */
22
22
  export interface Logger extends LogMethods {
23
23
  /**
24
- * Adds a value to the redaction set, which makes it replaced by [REDACTED] when logged to file.
24
+ * Add a pattern to the redactor and an optional mask for the redaction.
25
25
  *
26
- * @remarks
27
- * The redaction set is applied globally, and only applies to the log file, not console logs.
26
+ * @see {@link Redactor}
28
27
  *
29
- * @param value - the string to redact
28
+ * @param value - The pattern to add.
29
+ * @param replaceTo - The mask to use for redaction.
30
30
  */
31
- redact(value: string): void;
31
+ addRedactPattern(value: string, redactTo?: string): void;
32
+ /**
33
+ * Redact the provided string by replacing all occurrences of the patterns
34
+ * and return a new string with redacted values.
35
+ *
36
+ * @see {@link Redactor}
37
+ *
38
+ * @param text - The string to redact.
39
+ */
40
+ redact(text: string): string;
32
41
  }
33
42
  /**
34
43
  * Create a logger with console API, and map fatal to error, skipping trace
@@ -6,8 +6,7 @@ export var LogLevels;
6
6
  LogLevels[LogLevels["warn"] = 40] = "warn";
7
7
  LogLevels[LogLevels["error"] = 50] = "error";
8
8
  LogLevels[LogLevels["fatal"] = 60] = "fatal";
9
- // eslint-disable-next-line @typescript-eslint/prefer-literal-enum-member -- needs infinity
10
- LogLevels[LogLevels["silent"] = Number.MAX_SAFE_INTEGER] = "silent";
9
+ LogLevels[LogLevels["silent"] = 9007199254740991] = "silent";
11
10
  })(LogLevels || (LogLevels = {}));
12
11
  /**
13
12
  * Create a logger with console API, and map fatal to error, skipping trace
@@ -15,15 +14,22 @@ export var LogLevels;
15
14
  */
16
15
  export function createConsoleLogger() {
17
16
  return Object.freeze({
18
- /* eslint-disable no-console -- set logger to console */
19
17
  fatal: (meta, message) => console.error(message, meta),
20
18
  error: (meta, message) => console.error(message, meta),
21
19
  warn: (meta, message) => console.warn(message, meta),
22
20
  info: (meta, message) => console.info(message, meta),
23
21
  debug: (meta, message) => console.debug(message, meta),
24
- trace() { }, // Noop
25
- silent() { }, // Noop
26
- redact() { }, // Noop
27
- /* eslint-enable no-console -- set logger to console */
22
+ trace() {
23
+ // Noop
24
+ },
25
+ silent() {
26
+ // Noop
27
+ },
28
+ redact(text) {
29
+ return text;
30
+ },
31
+ addRedactPattern() {
32
+ // Noop
33
+ },
28
34
  });
29
35
  }
@@ -19,7 +19,7 @@ export declare const mergeConstraints: (baseConstraints: InputConstraintSet | bo
19
19
  *
20
20
  * Check test cases for the details
21
21
  */
22
- export declare const normalizeDevice: (device: InputConstraintSet['device']) => MediaDeviceInfo[] | undefined;
22
+ export declare const normalizeDevice: (device: InputConstraintSet["device"]) => MediaDeviceInfo[] | undefined;
23
23
  /**
24
24
  * Normalize Device Constraint
25
25
  * Convert Device Constraints into a form of `ConstraintDeviceParameters`
@@ -32,12 +32,12 @@ export declare const normalizeDevice: (device: InputConstraintSet['device']) =>
32
32
  * `undefined` if nothing is meaningful for the constraint, otherwise,
33
33
  * a normalized form of `ConstraintDeviceParameters`
34
34
  */
35
- export declare const normalizeDeviceConstraint: (constraints: InputConstraintSet['device']) => NormalizedConstraintDeviceParameters | undefined;
35
+ export declare const normalizeDeviceConstraint: (constraints: InputConstraintSet["device"]) => NormalizedConstraintDeviceParameters | undefined;
36
36
  /**
37
37
  * Convert `InputConstraintSet['device']` into
38
38
  * `MediaTrackConstraintSet['deviceId']` in a normalized form
39
39
  */
40
- export declare const toDeviceIdConstraintSet: (constraint: InputConstraintSet['device']) => MediaTrackConstraints['deviceId'];
40
+ export declare const toDeviceIdConstraintSet: (constraint: InputConstraintSet["device"]) => MediaTrackConstraints["deviceId"];
41
41
  export declare const toArray: <T>(t: T | T[]) => T[];
42
42
  export type ConstrainNoneTuple = [undefined, 'ideal'];
43
43
  export declare const NONE: ConstrainNoneTuple;
@@ -104,8 +104,8 @@ export declare const getMediaConstraints: ({ audio, video, defaultConstraints, }
104
104
  */
105
105
  export declare const applyConstraints: (tracks: MediaStreamTrack[] | undefined, constraints: MediaDeviceRequest) => Promise<void>;
106
106
  export declare const findDeviceFrom: (devicesToFind: MediaDeviceInfoLike[], devices: IndexedDevices) => MediaDeviceInfoLike[];
107
- export declare const findDeviceFromDeviceConstraints: (device: InputConstraintSet['device'], devices: IndexedDevices) => MediaDeviceInfoLike[] | undefined;
108
- export declare const relaxDevice: (device: InputConstraintSet['device'], devices: IndexedDevices) => MediaDeviceInfoLike[] | undefined;
107
+ export declare const findDeviceFromDeviceConstraints: (device: InputConstraintSet["device"], devices: IndexedDevices) => MediaDeviceInfoLike[] | undefined;
108
+ export declare const relaxDevice: (device: InputConstraintSet["device"], devices: IndexedDevices) => MediaDeviceInfoLike[] | undefined;
109
109
  export declare const resolveOnlyDevice: (devices: IndexedDevices) => true | MediaDeviceInfoLike | undefined;
110
110
  type ConstrainNumberKeys = ConstrainULongKeys | ConstrainDoubleKeys | ExtendedConstrainDoubleKeys | ExtendedConstrainULongKeys;
111
111
  type ConstrainTuples = ConstrainDeviceTuple | ConstrainNumberTuple | ConstrainStringTuple | ConstrainBooleanTuple | ConstrainNoneTuple;
@@ -143,7 +143,7 @@ export type Constraints = ConstrainStrings & ConstrainNumbers & ConstrainBoolean
143
143
  * expect(noiseSuppressionParam).toEqual('ideal');
144
144
  * ```
145
145
  */
146
- export declare const extractConstraintsWithKeys: <T extends "deviceId" | "groupId" | "device" | "videoSegmentation" | "videoSegmentationModel" | "denoise" | "vad" | "asd" | "mixWithAdditionalMedia" | "backgroundImageUrl" | "resizeMode" | "pan" | "tilt" | "zoom" | "contentHint" | "facingMode" | "echoCancellation" | "autoGainControl" | "noiseSuppression" | ConstrainNumberKeys>(keys: readonly T[]) => (constraints: InputDeviceConstraint | undefined) => Pick<Constraints, T>;
146
+ export declare const extractConstraintsWithKeys: <T extends keyof Constraints>(keys: readonly T[]) => (constraints: InputDeviceConstraint | undefined) => Pick<Constraints, T>;
147
147
  /**
148
148
  * Extract deviceId from constraints
149
149
  */
@@ -167,7 +167,7 @@ export declare const findDeviceFromConstraints: (constraints: InputDeviceConstra
167
167
  * @param input - The input constraints to be relaxed
168
168
  * @param devices - The current device list
169
169
  */
170
- export declare const relaxInputConstraint: (kind: 'audioinput' | 'videoinput', input: InputDeviceConstraint | undefined, devices: IndexedDevices) => InputDeviceConstraint | undefined;
170
+ export declare const relaxInputConstraint: (kind: "audioinput" | "videoinput", input: InputDeviceConstraint | undefined, devices: IndexedDevices) => InputDeviceConstraint | undefined;
171
171
  export declare const getConstraintsHandlers: () => {
172
172
  getDefaultConstraints: () => MediaStreamConstraints;
173
173
  setDefaultConstraints: (newConstraints: MediaStreamConstraints) => void;
@@ -18,10 +18,13 @@ const getConstraintsSetFilter = (supportedConstraints) => (trackConstraints) =>
18
18
  if (!isMediaTrackConstraints(trackConstraints)) {
19
19
  return trackConstraints;
20
20
  }
21
- const constraints = Object.entries(trackConstraints).reduce((acc, [key, val]) => key === 'advanced' ||
22
- supportedConstraints.has(key)
23
- ? { ...acc, [key]: val }
24
- : acc, {});
21
+ const constraints = {};
22
+ for (const [key, value] of Object.entries(trackConstraints)) {
23
+ if (key === 'advanced' ||
24
+ supportedConstraints.has(key)) {
25
+ constraints[key] = value;
26
+ }
27
+ }
25
28
  // If we don't have any valid constraints it seems sensible to fallback to a boolean constraint -ea
26
29
  if (Object.keys(constraints).length === 0) {
27
30
  return true;
@@ -29,7 +32,13 @@ const getConstraintsSetFilter = (supportedConstraints) => (trackConstraints) =>
29
32
  return constraints;
30
33
  };
31
34
  const getDefinedOnly = (obj) => {
32
- return Object.entries(obj).reduce((acc, [key, val]) => typeof val === 'undefined' ? acc : { ...acc, [key]: val }, {});
35
+ const result = {};
36
+ for (const [key, value] of Object.entries(obj)) {
37
+ if (typeof value !== 'undefined') {
38
+ result[key] = value;
39
+ }
40
+ }
41
+ return result;
33
42
  };
34
43
  /**
35
44
  * Use navigator.mediaDevices.getSupportedConstraints to remove constraints not supported by agent.
@@ -41,11 +50,7 @@ export const removeUnsupportedConstraints = (constraints) => {
41
50
  }
42
51
  const supportedConstraints = Object.entries(navigator.mediaDevices.getSupportedConstraints());
43
52
  logger.debug({ supportedConstraints }, 'Supported constraints');
44
- const constraintsSetFilter = getConstraintsSetFilter(supportedConstraints.reduce((set, [key, value]) =>
45
- // FIXME: Cast inserted to unblock typescript upgrade, will have to be verified and properly fixed.
46
- value && isMediaTrackConstraintSetKey(key)
47
- ? set.add(key)
48
- : set, new Set()));
53
+ const constraintsSetFilter = getConstraintsSetFilter(supportedConstraints.reduce((set, [key, value]) => value && isMediaTrackConstraintSetKey(key) ? set.add(key) : set, new Set()));
49
54
  return getDefinedOnly({
50
55
  audio: constraintsSetFilter(constraints.audio),
51
56
  peerIdentity: constraints.peerIdentity,
@@ -73,9 +78,9 @@ export const mergeConstraints = (baseConstraints) => (constraints) => {
73
78
  ...baseConstraints,
74
79
  device: constraints,
75
80
  };
76
- delete result.facingMode;
77
- delete result.deviceId;
78
- return result;
81
+ result.facingMode = undefined;
82
+ result.deviceId = undefined;
83
+ return getDefinedOnly(result);
79
84
  }
80
85
  if (isInputConstraintSet(constraints)) {
81
86
  const combined = { ...baseConstraints, ...constraints };
@@ -87,13 +92,13 @@ export const mergeConstraints = (baseConstraints) => (constraints) => {
87
92
  const result = {
88
93
  ...combined,
89
94
  };
90
- delete result.facingMode;
91
- delete result.deviceId;
92
- return result;
95
+ result.facingMode = undefined;
96
+ result.deviceId = undefined;
97
+ return getDefinedOnly(result);
93
98
  }
94
99
  if (hasDevice || hasDeviceId) {
95
- delete combined.facingMode;
96
- return combined;
100
+ combined.facingMode = undefined;
101
+ return getDefinedOnly(combined);
97
102
  }
98
103
  return combined;
99
104
  }
@@ -271,7 +276,7 @@ export const extractConstrainDevice = (constraints, initialParam = 'ideal') => {
271
276
  * @param numDigits - The number of digits to check after the decimal point @defaultValue 5 digits
272
277
  */
273
278
  export const closedTo = (a, b, numDigits = 5) => {
274
- const multiplier = Math.pow(10, numDigits);
279
+ const multiplier = 10 ** numDigits;
275
280
  return Math.round(a * multiplier) === Math.round(b * multiplier);
276
281
  };
277
282
  /**
@@ -374,12 +379,12 @@ export const resolveMediaDeviceConstraints = (constraints, base) => {
374
379
  return merge(Object.keys(constraints).reduce((cs, k) => {
375
380
  const key = k;
376
381
  if (key === 'device') {
377
- return {
378
- ...cs,
379
- deviceId: toDeviceIdConstraintSet(constraints.device),
380
- };
382
+ cs.deviceId = toDeviceIdConstraintSet(constraints.device);
383
+ return cs;
381
384
  }
382
- return { ...cs, [key]: constraints[key] };
385
+ // @ts-expect-error --- for performance
386
+ cs[key] = constraints[key];
387
+ return cs;
383
388
  }, {}));
384
389
  }
385
390
  return merge(constraints);
@@ -532,38 +537,14 @@ export function extractConstraints(key) {
532
537
  * expect(noiseSuppressionParam).toEqual('ideal');
533
538
  * ```
534
539
  */
535
- export const extractConstraintsWithKeys = (keys) => (constraints) => keys.reduce((result, key) => {
536
- if (key === 'device') {
537
- return {
538
- ...result,
539
- [key]: extractConstraints(key)(constraints),
540
- };
541
- }
542
- if (isConstrainULongKeys(key) ||
543
- isConstrainDoubleKeys(key) ||
544
- isExtendedConstrainULongKeys(key) ||
545
- isExtendedConstrainDoubleKeys(key)) {
546
- return {
547
- ...result,
548
- [key]: extractConstraints(key)(constraints),
549
- };
550
- }
551
- if (isConstrainStringKeys(key) ||
552
- isExtendedConstrainStringKeys(key)) {
553
- return {
554
- ...result,
555
- [key]: extractConstraints(key)(constraints),
556
- };
540
+ export const extractConstraintsWithKeys = (keys) => (constraints) => {
541
+ const extracted = {};
542
+ for (const key of keys) {
543
+ // @ts-expect-error --- subpress ts error for performance
544
+ extracted[key] = extractConstraints(key)(constraints);
557
545
  }
558
- if (isConstrainBooleanKeys(key) ||
559
- isExtendedConstrainBooleanKeys(key)) {
560
- return {
561
- ...result,
562
- [key]: extractConstraints(key)(constraints),
563
- };
564
- }
565
- return result;
566
- }, {});
546
+ return extracted;
547
+ };
567
548
  /**
568
549
  * Extract deviceId from constraints
569
550
  */
package/dist/devices.d.ts CHANGED
@@ -4,17 +4,11 @@ import type { FacingMode, IndexedDevices, InputConstraintSet, InputDeviceConstra
4
4
  *
5
5
  * ```
6
6
  * devices (raw)
7
- * |--- authorized
8
- * | |--- found
9
- * | |--- lost
10
- * |--- unauthorized
11
7
  * ```
12
8
  *
13
9
  * @beta
14
10
  */
15
11
  export type DeviceChangedChanges = {
16
- authorized: MediaDeviceInfoLike[];
17
- unauthorized: MediaDeviceInfoLike[];
18
12
  found: MediaDeviceInfoLike[];
19
13
  lost: MediaDeviceInfoLike[];
20
14
  devices: MediaDeviceInfoLike[];
@@ -30,7 +24,7 @@ interface ToKeyOptions {
30
24
  * @beta
31
25
  */
32
26
  export declare const toKey: ({ id, kind, label }: ToKeyOptions) => string;
33
- export declare const toMediaDeviceInputKind: (track: Pick<MediaStreamTrack, 'kind'>) => 'audioinput' | 'videoinput';
27
+ export declare const toMediaDeviceInputKind: (track: Pick<MediaStreamTrack, "kind">) => "audioinput" | "videoinput";
34
28
  /**
35
29
  * Future proofing: in case we want to alter the values or type returned
36
30
  * by {@link https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices | enumerateDevices}
@@ -52,10 +46,7 @@ export declare const getDevices: () => Promise<MediaDeviceInfo[]>;
52
46
  export declare const toDeviceKey: (device: MediaDeviceInfoLike) => string;
53
47
  export declare const toDeviceTuple: (device: MediaDeviceInfoLike) => readonly [string, MediaDeviceInfoLike];
54
48
  export declare const toDevicesMap: (devices: MediaDeviceInfoLike[]) => Map<string, MediaDeviceInfoLike>;
55
- export declare const toUniqueDevices: (devices: MediaDeviceInfoLike[]) => MediaDeviceInfoLike[];
56
49
  export declare const createTrackDevicesChanges: (prevDevices?: MediaDeviceInfoLike[]) => (devices: MediaDeviceInfoLike[]) => {
57
- unauthorized: MediaDeviceInfoLike[];
58
- authorized: MediaDeviceInfoLike[];
59
50
  found: MediaDeviceInfoLike[];
60
51
  lost: MediaDeviceInfoLike[];
61
52
  devices: MediaDeviceInfoLike[];
@@ -90,7 +81,7 @@ export declare const toMediaDeviceInfoLike: (track: MediaStreamTrack) => MediaDe
90
81
  *
91
82
  * @beta
92
83
  */
93
- export declare const compareMediaDeviceToMediaTrack: (track: Pick<MediaStreamTrack, 'kind' | 'getSettings' | 'label'>) => (device: MediaDeviceInfoLike) => boolean;
84
+ export declare const compareMediaDeviceToMediaTrack: (track: Pick<MediaStreamTrack, "kind" | "getSettings" | "label">) => (device: MediaDeviceInfoLike) => boolean;
94
85
  export declare const toMediaDeviceInfo: (info: MediaDeviceInfoLike) => {
95
86
  deviceId: string;
96
87
  groupId: string;
@@ -121,7 +112,7 @@ export declare const findMediaInputFromMediaStreamTrack: (devices: IndexedDevice
121
112
  * @beta
122
113
  */
123
114
  export declare const findMediaInputFromStream: (devices: IndexedDevices) => (stream: MediaStream | undefined) => MediaInput;
124
- export declare const compareDeviceConstraintAndTrackDevice: (device: MediaDeviceInfoLike | undefined) => (constraint: InputConstraintSet['device']) => boolean;
115
+ export declare const compareDeviceConstraintAndTrackDevice: (device: MediaDeviceInfoLike | undefined) => (constraint: InputConstraintSet["device"]) => boolean;
125
116
  export declare const isRequestedResolution: (request: InputDeviceConstraint | undefined, response: MediaTrackSettings | undefined) => boolean;
126
117
  export declare const isRequestedInputDevice: (request: InputDeviceConstraint | undefined, response: MediaDeviceInfoLike | MediaDeviceTrackInfo | undefined) => boolean;
127
118
  /**
@@ -204,8 +195,8 @@ export declare const findPermissionGrantedDevices: (devices: MediaDeviceInfoLike
204
195
  * guess the state more accurately
205
196
  */
206
197
  export declare const toPermissionState: (anyGrantedDevice: boolean, anyLiveTrack?: boolean) => PermissionState;
207
- export declare const queryPermissionFallback: (name: 'camera' | 'microphone', everActiveTrack?: boolean, getDevices?: () => Promise<MediaDeviceInfo[]>) => Promise<PermissionState>;
208
- export declare const queryPermission: (name: 'camera' | 'microphone', everActiveTrack?: boolean, getDevices?: () => Promise<MediaDeviceInfo[]>) => Promise<PermissionState>;
198
+ export declare const queryPermissionFallback: (name: "camera" | "microphone", everActiveTrack?: boolean, getDevices?: () => Promise<MediaDeviceInfo[]>) => Promise<PermissionState>;
199
+ export declare const queryPermission: (name: "camera" | "microphone", everActiveTrack?: boolean, getDevices?: () => Promise<MediaDeviceInfo[]>) => Promise<PermissionState>;
209
200
  /**
210
201
  * A wrapper for `navigator.permissions.query` with fallback to use
211
202
  * `navigator.mediaDevices.enumerateDevices` to guess the `PermissionState`
@@ -313,7 +304,7 @@ export declare const findAudioOutputDevices: (devices: MediaDeviceInfoLike[]) =>
313
304
  *
314
305
  * @beta
315
306
  */
316
- export declare const muteStreamTrack: (stream?: MediaStream) => (mute: boolean, mediaType?: 'audio' | 'video' | 'all') => void;
307
+ export declare const muteStreamTrack: (stream?: MediaStream) => (mute: boolean, mediaType?: "audio" | "video" | "all") => void;
317
308
  /**
318
309
  * Stops all tracks in the given stream
319
310
  *
@@ -324,7 +315,7 @@ export declare const muteStreamTrack: (stream?: MediaStream) => (mute: boolean,
324
315
  * @param stream - `MediaStream` which we mutate
325
316
  * @param onStopped - callback to be called when the track is stopped
326
317
  */
327
- export declare const stopMediaStream: (stream: MediaStream | undefined, onStopped?: ((track: MediaStreamTrack) => void) | undefined) => void;
318
+ export declare const stopMediaStream: (stream: MediaStream | undefined, onStopped?: (track: MediaStreamTrack) => void) => void;
328
319
  /**
329
320
  * Checks that tracks with a given type are enabled in the stream
330
321
  *
@@ -335,7 +326,7 @@ export declare const stopMediaStream: (stream: MediaStream | undefined, onStoppe
335
326
  *
336
327
  * @beta
337
328
  */
338
- export declare const areTracksEnabled: (stream: MediaStream | undefined, type: 'audio' | 'video') => boolean;
329
+ export declare const areTracksEnabled: (stream: MediaStream | undefined, type: "audio" | "video") => boolean;
339
330
  /**
340
331
  * Check if list contains media inputs
341
332
  *
package/dist/devices.js CHANGED
@@ -49,39 +49,29 @@ export const getDevices = async () => {
49
49
  export const toDeviceKey = (device) => toKey({ id: device.deviceId, kind: device.kind, label: device.label });
50
50
  export const toDeviceTuple = (device) => [toDeviceKey(device), device];
51
51
  export const toDevicesMap = (devices) => {
52
- return new Map(devices.map(toDeviceTuple));
53
- };
54
- export const toUniqueDevices = (devices) => {
55
- const map = toDevicesMap(devices);
56
- return Array.from(map.values());
52
+ const map = new Map();
53
+ for (const device of devices) {
54
+ const key = toDeviceKey(device);
55
+ if (!map.has(key)) {
56
+ map.set(key, device);
57
+ }
58
+ }
59
+ return map;
57
60
  };
58
61
  export const createTrackDevicesChanges = (prevDevices = []) => {
59
62
  let seen = toDevicesMap(prevDevices);
60
63
  return (devices) => {
61
64
  const found = [];
62
- const lost = [];
63
65
  // Remove duplicated
64
- const uniqueDevices = toUniqueDevices(devices);
65
- const { authorized, unauthorized } = uniqueDevices.reduce((ds, d) => {
66
- // Use label to differentiate un/authorized
67
- if (d.label) {
68
- ds.authorized.push(d);
69
- }
70
- else {
71
- ds.unauthorized.push(d);
72
- }
73
- return ds;
74
- }, { authorized: [], unauthorized: [] });
75
- for (const device of authorized) {
76
- if (!seen.delete(toDeviceKey(device))) {
66
+ const nextDeviceMap = toDevicesMap(devices);
67
+ for (const [key, device] of nextDeviceMap) {
68
+ if (!seen.delete(key)) {
77
69
  found.push(device);
78
70
  }
79
71
  }
80
- for (const device of seen.values()) {
81
- lost.push(device);
82
- }
83
- seen = new Map(authorized.map(toDeviceTuple));
84
- return { unauthorized, authorized, found, lost, devices: uniqueDevices };
72
+ const lost = Array.from(seen.values());
73
+ seen = nextDeviceMap;
74
+ return { found, lost, devices: Array.from(nextDeviceMap.values()) };
85
75
  };
86
76
  };
87
77
  /**
@@ -103,9 +93,9 @@ export const deviceChanged = (fn) => {
103
93
  //
104
94
  // Ref. https://caniuse.com/#search=ondevicechange
105
95
  if (navigator.mediaDevices && 'ondevicechange' in navigator.mediaDevices) {
106
- navigator.mediaDevices.ondevicechange = odc;
96
+ navigator.mediaDevices.addEventListener('devicechange', odc);
107
97
  return () => {
108
- navigator.mediaDevices.ondevicechange = null;
98
+ navigator.mediaDevices.removeEventListener('devicechange', odc);
109
99
  };
110
100
  }
111
101
  const it = window.setInterval(() => void odc(), 5000);
@@ -348,7 +338,6 @@ export const shouldRequestDevice = ({ kind, permission, request, tracks, current
348
338
  }
349
339
  switch (permission) {
350
340
  case 'prompt':
351
- return true;
352
341
  case 'granted': {
353
342
  if (currentDevices.size(kind) === 0) {
354
343
  return false;
@@ -473,10 +462,13 @@ export const queryPermission = async (name, everActiveTrack = false, getDevices
473
462
  * guess the state more accurately
474
463
  * @param getDevices - A function to get the list of devices, e.g. navigator.mediaDevices.enumerateDevices
475
464
  */
476
- export const getInputDevicePermissionState = async (anyActiveAudioTrack = false, anyActiveVideoTrack = false, getDevices = () => navigator.mediaDevices.enumerateDevices()) => ({
477
- audio: await queryPermission('microphone', anyActiveAudioTrack, getDevices),
478
- video: await queryPermission('camera', anyActiveVideoTrack, getDevices),
479
- });
465
+ export const getInputDevicePermissionState = async (anyActiveAudioTrack = false, anyActiveVideoTrack = false, getDevices = () => navigator.mediaDevices.enumerateDevices()) => {
466
+ const [audio, video] = await Promise.all([
467
+ queryPermission('microphone', anyActiveAudioTrack, getDevices),
468
+ queryPermission('camera', anyActiveVideoTrack, getDevices),
469
+ ]);
470
+ return { audio, video };
471
+ };
480
472
  /**
481
473
  * Find current audio output id to be used to set as sinkId
482
474
  *
@@ -572,6 +564,11 @@ export const findVideoInputDevices = findDevicesByKind(MediaDeviceKinds.VIDEOINP
572
564
  * @beta
573
565
  */
574
566
  export const findAudioOutputDevices = findDevicesByKind(MediaDeviceKinds.AUDIOOUTPUT);
567
+ const muteTrack = (tracks, muted) => {
568
+ for (const track of tracks) {
569
+ track.enabled = !muted;
570
+ }
571
+ };
575
572
  /**
576
573
  * Set `MediaStreamTrack['enabled']` according to `mute` param for the provided `stream`
577
574
  *
@@ -586,21 +583,18 @@ export const findAudioOutputDevices = findDevicesByKind(MediaDeviceKinds.AUDIOOU
586
583
  * @beta
587
584
  */
588
585
  export const muteStreamTrack = (stream) => (mute, mediaType = 'all') => {
586
+ if (!stream) {
587
+ return;
588
+ }
589
589
  switch (mediaType) {
590
590
  case 'audio':
591
- stream?.getAudioTracks().forEach(track => {
592
- track.enabled = !mute;
593
- });
591
+ muteTrack(stream?.getAudioTracks(), mute);
594
592
  break;
595
593
  case 'video':
596
- stream?.getVideoTracks().forEach(track => {
597
- track.enabled = !mute;
598
- });
594
+ muteTrack(stream.getVideoTracks(), mute);
599
595
  break;
600
596
  default:
601
- stream?.getTracks().forEach(track => {
602
- track.enabled = !mute;
603
- });
597
+ muteTrack(stream.getTracks(), mute);
604
598
  break;
605
599
  }
606
600
  };
@@ -618,10 +612,10 @@ export const stopMediaStream = (stream, onStopped) => {
618
612
  if (!stream) {
619
613
  return;
620
614
  }
621
- stream.getTracks().forEach(track => {
615
+ for (const track of stream.getTracks()) {
622
616
  track.stop();
623
617
  onStopped?.(track);
624
- });
618
+ }
625
619
  };
626
620
  /**
627
621
  * Checks that tracks with a given type are enabled in the stream
package/dist/errors.d.ts CHANGED
@@ -8,6 +8,6 @@ export interface InputNotFoundErrorParams {
8
8
  export declare const isInputNotFoundError: ({ input, kind, devices }: InputNotFoundErrorParams) => (error: string) => boolean;
9
9
  export declare const normalizeGetUserMediaError: (browserError: Error, constraints: MediaStreamConstraints, devices: MediaDeviceInfoLike[]) => MediaDeviceFailure | string;
10
10
  export declare const normalizeDeviceError: ({ audio, video, streamingAudioInput, streamingVideoInput, }: {
11
- streamingAudioInput?: boolean | undefined;
12
- streamingVideoInput?: boolean | undefined;
11
+ streamingAudioInput?: boolean;
12
+ streamingVideoInput?: boolean;
13
13
  } & MediaDeviceRequest) => false | MediaDeviceFailure;
@@ -44,10 +44,6 @@ export declare enum MediaEventType {
44
44
  * Lost device from authorized device list
45
45
  */
46
46
  DeviceLost = "device:lost",
47
- /**
48
- * Unauthorized devices
49
- */
50
- DevicesUnauthorized = "devices:unauthorized",
51
47
  /**
52
48
  * No Input Devices, and no further device events will be emitted
53
49
  */
@@ -80,18 +76,12 @@ export type Events = {
80
76
  type: MediaEventType.DevicesChanged;
81
77
  } | {
82
78
  devices: MediaDeviceInfoLike[];
83
- authorizedDevices: MediaDeviceInfoLike[];
84
- unauthorizedDevices: MediaDeviceInfoLike[];
79
+ devicesFound: MediaDeviceInfoLike[];
85
80
  type: MediaEventType.DevicesFound;
86
81
  } | {
87
82
  devices: MediaDeviceInfoLike[];
88
- authorizedDevices: MediaDeviceInfoLike[];
89
- unauthorizedDevices: MediaDeviceInfoLike[];
83
+ devicesLost: MediaDeviceInfoLike[];
90
84
  type: MediaEventType.DevicesLost;
91
- } | {
92
- devices: MediaDeviceInfoLike[];
93
- authorizedDevices: MediaDeviceInfoLike[];
94
- type: MediaEventType.DevicesUnauthorized;
95
85
  } | {
96
86
  devices: MediaDeviceInfoLike[];
97
87
  type: MediaEventType.NoInputDevices;
@@ -44,10 +44,6 @@ export var MediaEventType;
44
44
  * Lost device from authorized device list
45
45
  */
46
46
  MediaEventType["DeviceLost"] = "device:lost";
47
- /**
48
- * Unauthorized devices
49
- */
50
- MediaEventType["DevicesUnauthorized"] = "devices:unauthorized";
51
47
  /**
52
48
  * No Input Devices, and no further device events will be emitted
53
49
  */
package/dist/index.js CHANGED
@@ -43,29 +43,20 @@ const state = () => {
43
43
  devices: event.devices,
44
44
  });
45
45
  }
46
- if (event.unauthorized.length) {
47
- dispatch({
48
- type: MediaEventType.DevicesUnauthorized,
49
- devices: event.unauthorized,
50
- authorizedDevices: event.authorized,
51
- });
52
- }
53
46
  if (event.found.length) {
54
47
  // Can be used to trigger user notification of a potentially better device being available
55
48
  dispatch({
56
49
  type: MediaEventType.DevicesFound,
57
- authorizedDevices: event.authorized,
58
- unauthorizedDevices: event.unauthorized,
59
- devices: event.found,
50
+ devicesFound: event.found,
51
+ devices: event.devices,
60
52
  });
61
53
  }
62
54
  if (event.lost.length) {
63
55
  // Can be used to trigger user notification of no longer seen devices
64
56
  dispatch({
65
57
  type: MediaEventType.DevicesLost,
66
- authorizedDevices: event.authorized,
67
- unauthorizedDevices: event.unauthorized,
68
- devices: event.lost,
58
+ devicesLost: event.lost,
59
+ devices: event.devices,
69
60
  });
70
61
  for (const device of event.lost) {
71
62
  if (streamTrackMap.has(device)) {
@@ -52,9 +52,9 @@ export const createStreamTrackMap = (tracks) => {
52
52
  * Stop all tracks and empty `streamTrackMap`
53
53
  */
54
54
  const clear = () => {
55
- streamTrackMap.forEach(track => {
55
+ for (const track of streamTrackMap.values()) {
56
56
  track.stop();
57
- });
57
+ }
58
58
  streamTrackMap.clear();
59
59
  };
60
60
  /**
package/dist/streams.js CHANGED
@@ -94,6 +94,8 @@ export const createStreamTrackEventSubscriptions = (track, handlers) => {
94
94
  return [];
95
95
  });
96
96
  return () => {
97
- trackSubscriptions.forEach(unsubscribeEvent => unsubscribeEvent());
97
+ for (const unsubscribe of trackSubscriptions) {
98
+ unsubscribe();
99
+ }
98
100
  };
99
101
  };
@@ -0,0 +1 @@
1
+ {"root":["../src/baseLogger.ts","../src/constants.ts","../src/constraints.ts","../src/devices.ts","../src/displayMedia.ts","../src/errors.ts","../src/eventEmitter.ts","../src/getMediaStream.ts","../src/index.ts","../src/logger.ts","../src/streamTrackMap.ts","../src/streams.ts","../src/typeGuards.ts","../src/types.ts","../src/utils.ts","../../../@types/globals.d.ts"],"version":"5.7.3"}
@@ -1,4 +1,4 @@
1
- import type { ConstraintDeviceParameters, DeviceConstraint, IndexedDevices, InputConstraintSet, MediaDeviceTrackInfo } from './types';
1
+ import type { ConstraintDeviceParameters, DeviceConstraint, FacingMode, IndexedDevices, InputConstraintSet, MediaDeviceTrackInfo } from './types';
2
2
  export declare const isBoolean: (t: unknown) => t is boolean;
3
3
  export declare const isUndefined: (t: unknown) => t is undefined;
4
4
  /**
@@ -40,14 +40,14 @@ export type ConstrainBooleanKeys = (typeof CONSTRAIN_BOOLEAN_KEYS)[number];
40
40
  * The keys from the `MediaTrackConstraintSet`
41
41
  */
42
42
  export declare const CONSTRAINT_SET_KEYS: readonly ["aspectRatio", "frameRate", "latency", "width", "height", "sampleRate", "sampleSize", "channelCount", "facingMode", "resizeMode", "deviceId", "groupId", "echoCancellation", "autoGainControl", "noiseSuppression", "pan", "tilt", "zoom"];
43
- export declare const isConstrainStringKeys: (t: unknown) => t is "deviceId" | "groupId" | "resizeMode" | "facingMode";
44
- export declare const isExtendedConstrainStringKeys: (t: unknown) => t is "videoSegmentation" | "videoSegmentationModel" | "backgroundImageUrl" | "contentHint";
45
- export declare const isConstrainULongKeys: (t: unknown) => t is "width" | "height" | "sampleRate" | "sampleSize" | "channelCount";
46
- export declare const isExtendedConstrainULongKeys: (t: unknown) => t is "backgroundBlurAmount" | "edgeBlurAmount";
47
- export declare const isConstrainDoubleKeys: (t: unknown) => t is "aspectRatio" | "frameRate" | "latency";
48
- export declare const isExtendedConstrainDoubleKeys: (t: unknown) => t is "foregroundThreshold" | "maskCombineRatio";
49
- export declare const isConstrainBooleanKeys: (t: unknown) => t is "pan" | "tilt" | "zoom" | "echoCancellation" | "autoGainControl" | "noiseSuppression";
50
- export declare const isExtendedConstrainBooleanKeys: (t: unknown) => t is "denoise" | "vad" | "asd" | "mixWithAdditionalMedia";
43
+ export declare const isConstrainStringKeys: (t: unknown) => t is ConstrainStringKeys;
44
+ export declare const isExtendedConstrainStringKeys: (t: unknown) => t is ExtendedConstrainStringKeys;
45
+ export declare const isConstrainULongKeys: (t: unknown) => t is ConstrainULongKeys;
46
+ export declare const isExtendedConstrainULongKeys: (t: unknown) => t is ExtendedConstrainULongKeys;
47
+ export declare const isConstrainDoubleKeys: (t: unknown) => t is ConstrainDoubleKeys;
48
+ export declare const isExtendedConstrainDoubleKeys: (t: unknown) => t is ExtendedConstrainDoubleKeys;
49
+ export declare const isConstrainBooleanKeys: (t: unknown) => t is ConstrainBooleanKeys;
50
+ export declare const isExtendedConstrainBooleanKeys: (t: unknown) => t is ExtendedConstrainBooleanKeys;
51
51
  export declare const isMediaTrackConstraintSetKey: (t: string) => t is keyof MediaTrackConstraintSet;
52
52
  export declare const isMediaTrackConstraintsKey: (t: string) => t is keyof MediaTrackConstraints;
53
53
  export declare const isMediaTrackConstraints: (t: unknown) => t is MediaTrackConstraints;
@@ -75,7 +75,7 @@ export declare const isConstrainRange: (t: unknown) => t is ConstrainDoubleRange
75
75
  export declare const isConstrainDoubleRange: (t: unknown) => t is ConstrainDoubleRange;
76
76
  export declare const isConstrainULongRange: (t: unknown) => t is ConstrainULongRange;
77
77
  export declare const isConstraintDeviceParameters: (t: unknown) => t is ConstraintDeviceParameters;
78
- export declare const isConstraintSetDevice: (t: unknown) => t is DeviceConstraint | ConstraintDeviceParameters | undefined;
78
+ export declare const isConstraintSetDevice: (t: unknown) => t is InputConstraintSet["device"];
79
79
  type ExtendedConstraintSet = Pick<InputConstraintSet, ExtendedConstrainULongKeys | ExtendedConstrainDoubleKeys | ExtendedConstrainStringKeys | ExtendedConstrainBooleanKeys | 'device'>;
80
80
  export declare const isExtendedConstraint: (t: unknown) => t is ExtendedConstraintSet;
81
81
  export declare const isInputConstraintSet: (t: unknown) => t is InputConstraintSet;
@@ -85,7 +85,7 @@ export declare const isInputConstraintSet: (t: unknown) => t is InputConstraintS
85
85
  * @beta
86
86
  */
87
87
  export declare const isMediaStreamTrack: (m: unknown) => m is MediaStreamTrack;
88
- export declare const isFacingMode: (s: unknown) => s is "user" | "environment" | "left" | "right";
88
+ export declare const isFacingMode: (s: unknown) => s is FacingMode;
89
89
  export declare const isIndexedDevices: (t: unknown) => t is IndexedDevices;
90
90
  export declare const isMediaDeviceTrackInfo: (t: unknown) => t is MediaDeviceTrackInfo;
91
91
  export {};
package/dist/types.d.ts CHANGED
@@ -21,15 +21,29 @@ export interface IndexedDevices {
21
21
  /**
22
22
  * Get devices by kind and device id or label
23
23
  * When both `deviceId` and `label` are provided, it will use `deviceId` to
24
- * to find the device, and when it's not found, it will use `label` to find
24
+ * find the device, and when it's not found, it will use `label` to find
25
+ *
26
+ * When device is not provided, it returns all devices.
25
27
  *
26
28
  * @param device - the device to find
27
29
  * @returns found devices otherwise empty array
28
30
  */
29
31
  get(device?: Pick<Partial<MediaDeviceInfoLike>, 'deviceId' | 'groupId' | 'label' | 'kind'>): MediaDeviceInfoLike[];
32
+ /**
33
+ * Size of particular kind of devices. When kind is not specified, it
34
+ * returns the total size.
35
+ */
30
36
  size(kind?: MediaDeviceKind): number;
37
+ /**
38
+ * First device of the kind
39
+ */
31
40
  first(kind: MediaDeviceInfo['kind']): MediaDeviceInfoLike | undefined;
32
41
  toJSON(): Record<MediaDeviceKind, MediaDeviceInfoLike[]>;
42
+ /**
43
+ * `true` when there is any authorized device of the kind. When kind is not
44
+ * provided, it checks for any audio or video input device.
45
+ */
46
+ anyAuthorizedDevice(kind?: MediaDeviceKind): boolean;
33
47
  }
34
48
  export type DeviceConstraint = MediaDeviceInfoLike | MediaDeviceInfoLike[];
35
49
  export interface NormalizedConstraintDeviceParameters {
package/dist/utils.d.ts CHANGED
@@ -16,12 +16,12 @@ export declare const isDeviceGranted: (device: MediaDeviceInfoLike) => boolean;
16
16
  export declare const not: <T = void>(fn: (arg: T) => boolean) => (arg: T) => boolean;
17
17
  /**
18
18
  * Create a device ID from provided `device`.
19
- * The device ID here is in the format of `groupId:deviceId:kind`, be default.
19
+ * The device ID here is in the format of `deviceId:kind`, be default.
20
20
  *
21
21
  * @param device - The device to create the ID from
22
22
  * @param separator - The separator to use to join the device ID
23
23
  */
24
- export declare const getDeviceId: (device: Pick<MediaDeviceInfoLike, 'groupId' | 'deviceId' | 'kind'>, separator?: string) => string;
24
+ export declare const getDeviceId: (device: Pick<MediaDeviceInfoLike, "deviceId" | "kind">, separator?: string) => string;
25
25
  /**
26
26
  * Reverse the device ID to its original form i.e. `MediaDeviceInfo`
27
27
  * The device ID here is in the format of `groupId:deviceId:kind`, be default.
@@ -31,7 +31,6 @@ export declare const getDeviceId: (device: Pick<MediaDeviceInfoLike, 'groupId' |
31
31
  */
32
32
  export declare const reverseDeviceId: (id: string, separator?: string) => {
33
33
  deviceId: string;
34
- groupId: string;
35
34
  kind: MediaDeviceKind;
36
35
  };
37
36
  /**
@@ -45,7 +44,7 @@ export declare const createIndexedDevices: (devices: MediaDeviceInfoLike[]) => I
45
44
  *
46
45
  * @beta
47
46
  */
48
- export declare const compareDevices: (deviceInfo: MediaDeviceInfoLike, key?: Exclude<keyof MediaDeviceInfoLike, 'kind' | 'settings'>) => (anotherDeviceInfo: MediaDeviceInfoLike) => boolean;
47
+ export declare const compareDevices: (deviceInfo: MediaDeviceInfoLike, key?: Exclude<keyof MediaDeviceInfoLike, "kind" | "settings">) => (anotherDeviceInfo: MediaDeviceInfoLike) => boolean;
49
48
  /**
50
49
  * Lookup the `device` from `devices` list
51
50
  *
package/dist/utils.js CHANGED
@@ -17,12 +17,12 @@ export const isDeviceGranted = (device) => Boolean(device.label);
17
17
  export const not = (fn) => (arg) => !fn(arg);
18
18
  /**
19
19
  * Create a device ID from provided `device`.
20
- * The device ID here is in the format of `groupId:deviceId:kind`, be default.
20
+ * The device ID here is in the format of `deviceId:kind`, be default.
21
21
  *
22
22
  * @param device - The device to create the ID from
23
23
  * @param separator - The separator to use to join the device ID
24
24
  */
25
- export const getDeviceId = (device, separator = DEVICE_ID_SEPARATOR) => [device.groupId, device.deviceId, device.kind].join(separator);
25
+ export const getDeviceId = (device, separator = DEVICE_ID_SEPARATOR) => [device.deviceId, device.kind].join(separator);
26
26
  /**
27
27
  * Reverse the device ID to its original form i.e. `MediaDeviceInfo`
28
28
  * The device ID here is in the format of `groupId:deviceId:kind`, be default.
@@ -31,20 +31,35 @@ export const getDeviceId = (device, separator = DEVICE_ID_SEPARATOR) => [device.
31
31
  * @param separator - The separator used to split the device ID
32
32
  */
33
33
  export const reverseDeviceId = (id, separator = DEVICE_ID_SEPARATOR) => {
34
- const [groupId, deviceId, kind] = id.split(separator);
35
- assert(groupId !== undefined, `Invalid id[${id}] format: groupId`);
34
+ const [deviceId, kind] = id.split(separator);
36
35
  assert(deviceId !== undefined, `Invalid id[${id}] format: deviceId`);
37
36
  assert(kind === 'audioinput' ||
38
37
  kind === 'videoinput' ||
39
- kind === 'audiooutput', `Invalid id[${id}] format: kind`);
40
- return { deviceId, groupId, kind: kind };
38
+ kind === 'audiooutput', `Invalid id[${id}] format: kind[${kind}]`);
39
+ return { deviceId, kind: kind };
41
40
  };
41
+ const EMPTY = [];
42
42
  /**
43
43
  * Create an `IndexedDevices` construct from provided `devices` which index the
44
44
  * device by device ID or kind.
45
45
  */
46
46
  export const createIndexedDevices = (devices) => {
47
+ const anyAuthorizedDevice = {
48
+ audioinput: false,
49
+ videoinput: false,
50
+ audiooutput: false,
51
+ };
52
+ const deviceIdCache = new Map();
53
+ const kindCache = new Map();
47
54
  const emptyIndex = {
55
+ anyAuthorizedDevice(kind) {
56
+ if (kind) {
57
+ return anyAuthorizedDevice[kind];
58
+ }
59
+ // This is a handy check to input device
60
+ return (anyAuthorizedDevice['audioinput'] ||
61
+ anyAuthorizedDevice['videoinput']);
62
+ },
48
63
  audioinput: {
49
64
  deviceId: new Map(),
50
65
  label: new Map(),
@@ -92,19 +107,32 @@ export const createIndexedDevices = (devices) => {
92
107
  const deviceIdMap = this[kind].deviceId;
93
108
  const findSimilarDevices = (label) => {
94
109
  const foundSimilar = this[kind].label.get(label);
95
- return foundSimilar ? foundSimilar : [];
110
+ return foundSimilar ?? EMPTY;
96
111
  };
97
112
  if (deviceId !== undefined) {
113
+ const cacheId = getDeviceId({ deviceId, kind });
114
+ const cachedDevice = deviceIdCache.get(cacheId);
115
+ if (cachedDevice) {
116
+ return cachedDevice;
117
+ }
98
118
  const foundExact = deviceIdMap.get(deviceId);
99
119
  if (!foundExact && label) {
100
120
  return findSimilarDevices(label);
101
121
  }
102
- return foundExact ? [foundExact] : [];
122
+ const devicesFound = foundExact ? [foundExact] : EMPTY;
123
+ deviceIdCache.set(cacheId, devicesFound);
124
+ return devicesFound;
103
125
  }
104
126
  if (label) {
105
127
  return findSimilarDevices(label);
106
128
  }
107
- return [...deviceIdMap.values()];
129
+ const cachedDevices = kindCache.get(kind);
130
+ if (cachedDevices) {
131
+ return cachedDevices;
132
+ }
133
+ const devices = Array.from(deviceIdMap.values());
134
+ kindCache.set(kind, devices);
135
+ return devices;
108
136
  },
109
137
  first(kind) {
110
138
  if (!kind) {
@@ -124,14 +152,16 @@ export const createIndexedDevices = (devices) => {
124
152
  };
125
153
  return devices.reduce((acc, device) => {
126
154
  // We don't want to index devices that are not granted
127
- if (device.label && device.deviceId !== undefined) {
155
+ if (device.deviceId !== undefined) {
128
156
  acc[device.kind].deviceId.set(device.deviceId, device);
129
157
  }
130
- if (device.label) {
131
- const labelDevices = acc[device.kind].label.get(device.label) ?? [];
132
- labelDevices.push(device);
133
- acc[device.kind].label.set(device.label, labelDevices);
158
+ if (anyAuthorizedDevice[device.kind] === false &&
159
+ isDeviceGranted(device)) {
160
+ anyAuthorizedDevice[device.kind] = true;
134
161
  }
162
+ const labelDevices = acc[device.kind].label.get(device.label) ?? [];
163
+ labelDevices.push(device);
164
+ acc[device.kind].label.set(device.label, labelDevices);
135
165
  return acc;
136
166
  }, emptyIndex);
137
167
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pexip/media-control",
3
- "version": "19.1.0",
3
+ "version": "20.0.1",
4
4
  "homepage": "https://gitlab.com/pexip/zoo",
5
5
  "bugs": "https://gitlab.com/pexip/zoo/issues",
6
6
  "repository": {
@@ -13,34 +13,49 @@
13
13
  "author": "Pexip <pexip@pexip.com>",
14
14
  "module": "dist/index.js",
15
15
  "types": "dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js"
20
+ },
21
+ "./*": {
22
+ "types": "./dist/*.d.ts",
23
+ "import": "./dist/*.js"
24
+ },
25
+ "./*.js": {
26
+ "types": "./dist/*.d.ts",
27
+ "import": "./dist/*.js"
28
+ }
29
+ },
16
30
  "files": [
17
31
  "dist"
18
32
  ],
19
33
  "scripts": {
20
34
  "build": "pexip-bundler build",
35
+ "build:sourcemap": "pexip-bundler build --sourcemap",
21
36
  "clean": "rm -rf dist",
22
37
  "dev": "pexip-bundler dev",
23
- "prepack": "yarn clean && yarn build --no-sourcemap",
38
+ "prepack": "yarn clean && yarn build",
24
39
  "test": "jest",
25
40
  "check-format": "prettier --ignore-path=../../.prettierignore --check .",
26
41
  "format": "prettier --ignore-path=../../.prettierignore --write .",
27
- "lint": "yarn run -T eslint --ext .js,.ts,.tsx --report-unused-disable-directives .",
42
+ "lint": "yarn run -T biome lint",
28
43
  "typecheck": "yarn tsc --noEmit -p tsconfig.build.json"
29
44
  },
30
45
  "dependencies": {
31
- "@pexip/utils": "16.13.0"
46
+ "@pexip/utils": "17.0.0"
32
47
  },
33
48
  "devDependencies": {
34
49
  "@jest/globals": "^29.7.0",
35
- "@pexip/bundler": "17.1.0",
36
- "@swc/core": "^1.4.6",
37
- "@swc/jest": "^0.2.36",
50
+ "@pexip/bundler": "18.1.0",
51
+ "@swc/core": "^1.10.12",
52
+ "@swc/jest": "^0.2.37",
38
53
  "@types/uuid": "^8.3.0",
39
54
  "@types/webrtc": "^0.0.31",
40
55
  "jest": "^29.5.12",
41
56
  "jest-junit": "^16.0.0",
42
57
  "prettier": "^3.2.5",
43
- "typescript": "~5.3.0",
58
+ "typescript": "~5.7.3",
44
59
  "uuid": "^11.0.0"
45
60
  },
46
61
  "publishConfig": {