@stream-io/video-client 0.4.5 → 0.4.7
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 +14 -0
- package/dist/index.browser.es.js +156 -99
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +155 -103
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +156 -99
- package/dist/index.es.js.map +1 -1
- package/dist/src/devices/InputMediaDeviceManager.d.ts +8 -3
- package/dist/src/devices/InputMediaDeviceManagerState.d.ts +20 -7
- package/dist/src/devices/SpeakerManager.d.ts +3 -0
- package/dist/src/devices/devices.d.ts +2 -41
- package/package.json +1 -1
- package/src/Call.ts +10 -1
- package/src/devices/CameraManagerState.ts +7 -2
- package/src/devices/InputMediaDeviceManager.ts +100 -7
- package/src/devices/InputMediaDeviceManagerState.ts +44 -1
- package/src/devices/MicrophoneManagerState.ts +7 -2
- package/src/devices/SpeakerManager.ts +27 -1
- package/src/devices/__tests__/CameraManager.test.ts +7 -1
- package/src/devices/__tests__/InputMediaDeviceManager.test.ts +113 -3
- package/src/devices/__tests__/InputMediaDeviceManagerState.test.ts +88 -0
- package/src/devices/__tests__/MicrophoneManager.test.ts +7 -1
- package/src/devices/__tests__/ScreenShareManager.test.ts +2 -1
- package/src/devices/__tests__/SpeakerManager.test.ts +12 -1
- package/src/devices/__tests__/mocks.ts +56 -7
- package/src/devices/devices.ts +11 -123
package/dist/index.cjs.js
CHANGED
|
@@ -10001,8 +10001,7 @@ const getDevices = (constraints, kind) => {
|
|
|
10001
10001
|
/**
|
|
10002
10002
|
* [Tells if the browser supports audio output change on 'audio' elements](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId).
|
|
10003
10003
|
*
|
|
10004
|
-
*
|
|
10005
|
-
*/
|
|
10004
|
+
* */
|
|
10006
10005
|
const checkIfAudioOutputChangeSupported = () => {
|
|
10007
10006
|
if (typeof document === 'undefined')
|
|
10008
10007
|
return false;
|
|
@@ -10162,90 +10161,10 @@ const getScreenShareStream = async (options) => {
|
|
|
10162
10161
|
throw e;
|
|
10163
10162
|
}
|
|
10164
10163
|
};
|
|
10165
|
-
const
|
|
10166
|
-
|
|
10167
|
-
|
|
10168
|
-
|
|
10169
|
-
devices$ = getAudioDevices();
|
|
10170
|
-
break;
|
|
10171
|
-
case 'videoinput':
|
|
10172
|
-
devices$ = getVideoDevices();
|
|
10173
|
-
break;
|
|
10174
|
-
case 'audiooutput':
|
|
10175
|
-
devices$ = getAudioOutputDevices();
|
|
10176
|
-
break;
|
|
10177
|
-
}
|
|
10178
|
-
return rxjs.combineLatest([devices$, deviceId$]).pipe(rxjs.filter(([devices, deviceId]) => !!deviceId && !devices.find((d) => d.deviceId === deviceId)), rxjs.map(() => true));
|
|
10179
|
-
};
|
|
10180
|
-
/**
|
|
10181
|
-
* Notifies the subscriber if a given 'audioinput' device is disconnected
|
|
10182
|
-
*
|
|
10183
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
10184
|
-
* @param deviceId$ an Observable that specifies which device to watch for
|
|
10185
|
-
* @returns
|
|
10186
|
-
*/
|
|
10187
|
-
const watchForDisconnectedAudioDevice = (deviceId$) => {
|
|
10188
|
-
return watchForDisconnectedDevice('audioinput', deviceId$);
|
|
10189
|
-
};
|
|
10190
|
-
/**
|
|
10191
|
-
* Notifies the subscriber if a given 'videoinput' device is disconnected
|
|
10192
|
-
*
|
|
10193
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
10194
|
-
* @param deviceId$ an Observable that specifies which device to watch for
|
|
10195
|
-
* @returns
|
|
10196
|
-
*/
|
|
10197
|
-
const watchForDisconnectedVideoDevice = (deviceId$) => {
|
|
10198
|
-
return watchForDisconnectedDevice('videoinput', deviceId$);
|
|
10199
|
-
};
|
|
10200
|
-
/**
|
|
10201
|
-
* Notifies the subscriber if a given 'audiooutput' device is disconnected
|
|
10202
|
-
*
|
|
10203
|
-
* @angular It's recommended to use the [`DeviceManagerService`](./DeviceManagerService.md) for a higher level API, use this low-level method only if the `DeviceManagerService` doesn't suit your requirements.
|
|
10204
|
-
* @param deviceId$ an Observable that specifies which device to watch for
|
|
10205
|
-
* @returns
|
|
10206
|
-
*/
|
|
10207
|
-
const watchForDisconnectedAudioOutputDevice = (deviceId$) => {
|
|
10208
|
-
return watchForDisconnectedDevice('audiooutput', deviceId$);
|
|
10209
|
-
};
|
|
10210
|
-
const watchForAddedDefaultDevice = (kind) => {
|
|
10211
|
-
let devices$;
|
|
10212
|
-
switch (kind) {
|
|
10213
|
-
case 'audioinput':
|
|
10214
|
-
devices$ = getAudioDevices();
|
|
10215
|
-
break;
|
|
10216
|
-
case 'videoinput':
|
|
10217
|
-
devices$ = getVideoDevices();
|
|
10218
|
-
break;
|
|
10219
|
-
case 'audiooutput':
|
|
10220
|
-
devices$ = getAudioOutputDevices();
|
|
10221
|
-
break;
|
|
10222
|
-
default:
|
|
10223
|
-
throw new Error('Unknown MediaDeviceKind', kind);
|
|
10224
|
-
}
|
|
10225
|
-
return devices$.pipe(rxjs.pairwise(), rxjs.filter(([prev, current]) => {
|
|
10226
|
-
const prevDefault = prev.find((device) => device.deviceId === 'default');
|
|
10227
|
-
const currentDefault = current.find((device) => device.deviceId === 'default');
|
|
10228
|
-
return !!(current.length > prev.length &&
|
|
10229
|
-
prevDefault &&
|
|
10230
|
-
currentDefault &&
|
|
10231
|
-
prevDefault.groupId !== currentDefault.groupId);
|
|
10232
|
-
}), rxjs.map(() => true));
|
|
10233
|
-
};
|
|
10234
|
-
/**
|
|
10235
|
-
* Notifies the subscriber about newly added default audio input device.
|
|
10236
|
-
* @returns Observable<boolean>
|
|
10237
|
-
*/
|
|
10238
|
-
const watchForAddedDefaultAudioDevice = () => watchForAddedDefaultDevice('audioinput');
|
|
10239
|
-
/**
|
|
10240
|
-
* Notifies the subscriber about newly added default audio output device.
|
|
10241
|
-
* @returns Observable<boolean>
|
|
10242
|
-
*/
|
|
10243
|
-
const watchForAddedDefaultAudioOutputDevice = () => watchForAddedDefaultDevice('audiooutput');
|
|
10244
|
-
/**
|
|
10245
|
-
* Notifies the subscriber about newly added default video input device.
|
|
10246
|
-
* @returns Observable<boolean>
|
|
10247
|
-
*/
|
|
10248
|
-
const watchForAddedDefaultVideoDevice = () => watchForAddedDefaultDevice('videoinput');
|
|
10164
|
+
const deviceIds$ = typeof navigator !== 'undefined' &&
|
|
10165
|
+
typeof navigator.mediaDevices !== 'undefined'
|
|
10166
|
+
? memoizedObservable(() => rxjs.merge(rxjs.from(navigator.mediaDevices.enumerateDevices()), getDeviceChangeObserver()).pipe(rxjs.shareReplay(1)))()
|
|
10167
|
+
: undefined;
|
|
10249
10168
|
/**
|
|
10250
10169
|
* Deactivates MediaStream (stops and removes tracks) to be later garbage collected
|
|
10251
10170
|
*
|
|
@@ -10271,7 +10190,17 @@ class InputMediaDeviceManager {
|
|
|
10271
10190
|
this.call = call;
|
|
10272
10191
|
this.state = state;
|
|
10273
10192
|
this.trackType = trackType;
|
|
10193
|
+
this.subscriptions = [];
|
|
10194
|
+
this.isTrackStoppedDueToTrackEnd = false;
|
|
10195
|
+
this.removeSubscriptions = () => {
|
|
10196
|
+
this.subscriptions.forEach((s) => s.unsubscribe());
|
|
10197
|
+
};
|
|
10274
10198
|
this.logger = getLogger([`${TrackType[trackType].toLowerCase()} manager`]);
|
|
10199
|
+
if (deviceIds$ &&
|
|
10200
|
+
!isReactNative() &&
|
|
10201
|
+
(this.trackType === TrackType.AUDIO || this.trackType === TrackType.VIDEO)) {
|
|
10202
|
+
this.handleDisconnectedOrReplacedDevices();
|
|
10203
|
+
}
|
|
10275
10204
|
}
|
|
10276
10205
|
/**
|
|
10277
10206
|
* Lists the available audio/video devices
|
|
@@ -10349,11 +10278,10 @@ class InputMediaDeviceManager {
|
|
|
10349
10278
|
this.state.setDefaultConstraints(constraints);
|
|
10350
10279
|
}
|
|
10351
10280
|
/**
|
|
10352
|
-
*
|
|
10281
|
+
* Selects a device.
|
|
10353
10282
|
*
|
|
10354
10283
|
* Note: this method is not supported in React Native
|
|
10355
|
-
*
|
|
10356
|
-
* @param deviceId
|
|
10284
|
+
* @param deviceId the device id to select.
|
|
10357
10285
|
*/
|
|
10358
10286
|
async select(deviceId) {
|
|
10359
10287
|
if (isReactNative()) {
|
|
@@ -10431,9 +10359,6 @@ class InputMediaDeviceManager {
|
|
|
10431
10359
|
this.unmuteTracks();
|
|
10432
10360
|
}
|
|
10433
10361
|
else {
|
|
10434
|
-
if (this.state.mediaStream) {
|
|
10435
|
-
this.stopTracks();
|
|
10436
|
-
}
|
|
10437
10362
|
const defaultConstraints = this.state.defaultConstraints;
|
|
10438
10363
|
const constraints = {
|
|
10439
10364
|
...defaultConstraints,
|
|
@@ -10446,13 +10371,93 @@ class InputMediaDeviceManager {
|
|
|
10446
10371
|
}
|
|
10447
10372
|
if (this.state.mediaStream !== stream) {
|
|
10448
10373
|
this.state.setMediaStream(stream);
|
|
10374
|
+
this.getTracks().forEach((track) => {
|
|
10375
|
+
track.addEventListener('ended', async () => {
|
|
10376
|
+
if (this.enablePromise) {
|
|
10377
|
+
await this.enablePromise;
|
|
10378
|
+
}
|
|
10379
|
+
if (this.disablePromise) {
|
|
10380
|
+
await this.disablePromise;
|
|
10381
|
+
}
|
|
10382
|
+
if (this.state.status === 'enabled') {
|
|
10383
|
+
this.isTrackStoppedDueToTrackEnd = true;
|
|
10384
|
+
setTimeout(() => {
|
|
10385
|
+
this.isTrackStoppedDueToTrackEnd = false;
|
|
10386
|
+
}, 2000);
|
|
10387
|
+
await this.disable();
|
|
10388
|
+
}
|
|
10389
|
+
});
|
|
10390
|
+
});
|
|
10391
|
+
}
|
|
10392
|
+
}
|
|
10393
|
+
get mediaDeviceKind() {
|
|
10394
|
+
if (this.trackType === TrackType.AUDIO) {
|
|
10395
|
+
return 'audioinput';
|
|
10449
10396
|
}
|
|
10397
|
+
if (this.trackType === TrackType.VIDEO) {
|
|
10398
|
+
return 'videoinput';
|
|
10399
|
+
}
|
|
10400
|
+
return '';
|
|
10401
|
+
}
|
|
10402
|
+
handleDisconnectedOrReplacedDevices() {
|
|
10403
|
+
this.subscriptions.push(rxjs.combineLatest([
|
|
10404
|
+
deviceIds$.pipe(rxjs.pairwise()),
|
|
10405
|
+
this.state.selectedDevice$,
|
|
10406
|
+
]).subscribe(async ([[prevDevices, currentDevices], deviceId]) => {
|
|
10407
|
+
if (!deviceId) {
|
|
10408
|
+
return;
|
|
10409
|
+
}
|
|
10410
|
+
if (this.enablePromise) {
|
|
10411
|
+
await this.enablePromise;
|
|
10412
|
+
}
|
|
10413
|
+
if (this.disablePromise) {
|
|
10414
|
+
await this.disablePromise;
|
|
10415
|
+
}
|
|
10416
|
+
let isDeviceDisconnected = false;
|
|
10417
|
+
let isDeviceReplaced = false;
|
|
10418
|
+
const currentDevice = this.findDeviceInList(currentDevices, deviceId);
|
|
10419
|
+
const prevDevice = this.findDeviceInList(prevDevices, deviceId);
|
|
10420
|
+
if (!currentDevice && prevDevice) {
|
|
10421
|
+
isDeviceDisconnected = true;
|
|
10422
|
+
}
|
|
10423
|
+
else if (currentDevice &&
|
|
10424
|
+
prevDevice &&
|
|
10425
|
+
currentDevice.deviceId === prevDevice.deviceId &&
|
|
10426
|
+
currentDevice.groupId !== prevDevice.groupId) {
|
|
10427
|
+
isDeviceReplaced = true;
|
|
10428
|
+
}
|
|
10429
|
+
if (isDeviceDisconnected) {
|
|
10430
|
+
await this.disable();
|
|
10431
|
+
this.select(undefined);
|
|
10432
|
+
}
|
|
10433
|
+
if (isDeviceReplaced) {
|
|
10434
|
+
if (this.isTrackStoppedDueToTrackEnd &&
|
|
10435
|
+
this.state.status === 'disabled') {
|
|
10436
|
+
await this.enable();
|
|
10437
|
+
this.isTrackStoppedDueToTrackEnd = false;
|
|
10438
|
+
}
|
|
10439
|
+
else {
|
|
10440
|
+
await this.applySettingsToStream();
|
|
10441
|
+
}
|
|
10442
|
+
}
|
|
10443
|
+
}));
|
|
10444
|
+
}
|
|
10445
|
+
findDeviceInList(devices, deviceId) {
|
|
10446
|
+
return devices.find((d) => d.deviceId === deviceId && d.kind === this.mediaDeviceKind);
|
|
10450
10447
|
}
|
|
10451
10448
|
}
|
|
10452
10449
|
|
|
10453
10450
|
class InputMediaDeviceManagerState {
|
|
10454
|
-
|
|
10451
|
+
/**
|
|
10452
|
+
* Constructs new InputMediaDeviceManagerState instance.
|
|
10453
|
+
*
|
|
10454
|
+
* @param disableMode the disable mode to use.
|
|
10455
|
+
* @param permissionName the permission name to use for querying.
|
|
10456
|
+
* `undefined` means no permission is required.
|
|
10457
|
+
*/
|
|
10458
|
+
constructor(disableMode = 'stop-tracks', permissionName = undefined) {
|
|
10455
10459
|
this.disableMode = disableMode;
|
|
10460
|
+
this.permissionName = permissionName;
|
|
10456
10461
|
this.statusSubject = new rxjs.BehaviorSubject(undefined);
|
|
10457
10462
|
this.mediaStreamSubject = new rxjs.BehaviorSubject(undefined);
|
|
10458
10463
|
this.selectedDeviceSubject = new rxjs.BehaviorSubject(undefined);
|
|
@@ -10476,6 +10481,33 @@ class InputMediaDeviceManagerState {
|
|
|
10476
10481
|
* The default constraints for the device.
|
|
10477
10482
|
*/
|
|
10478
10483
|
this.defaultConstraints$ = this.defaultConstraintsSubject.asObservable();
|
|
10484
|
+
/**
|
|
10485
|
+
* An observable that will emit `true` if browser/system permission
|
|
10486
|
+
* is granted, `false` otherwise.
|
|
10487
|
+
*/
|
|
10488
|
+
this.hasBrowserPermission$ = new rxjs.Observable((subscriber) => {
|
|
10489
|
+
const notifyGranted = () => subscriber.next(true);
|
|
10490
|
+
if (isReactNative() || !this.permissionName)
|
|
10491
|
+
return notifyGranted();
|
|
10492
|
+
let permissionState;
|
|
10493
|
+
const notify = () => subscriber.next(permissionState.state === 'granted');
|
|
10494
|
+
navigator.permissions
|
|
10495
|
+
.query({ name: this.permissionName })
|
|
10496
|
+
.then((permissionStatus) => {
|
|
10497
|
+
permissionState = permissionStatus;
|
|
10498
|
+
permissionState.addEventListener('change', notify);
|
|
10499
|
+
notify();
|
|
10500
|
+
})
|
|
10501
|
+
.catch(() => {
|
|
10502
|
+
// permission doesn't exist or can't be queried -> assume it's granted
|
|
10503
|
+
// an example would be Firefox,
|
|
10504
|
+
// where neither camera microphone permission can be queried
|
|
10505
|
+
notifyGranted();
|
|
10506
|
+
});
|
|
10507
|
+
return () => {
|
|
10508
|
+
permissionState?.removeEventListener('change', notify);
|
|
10509
|
+
};
|
|
10510
|
+
}).pipe(rxjs.shareReplay(1));
|
|
10479
10511
|
/**
|
|
10480
10512
|
* Gets the current value of an observable, or undefined if the observable has
|
|
10481
10513
|
* not emitted a value yet.
|
|
@@ -10557,7 +10589,10 @@ class InputMediaDeviceManagerState {
|
|
|
10557
10589
|
|
|
10558
10590
|
class CameraManagerState extends InputMediaDeviceManagerState {
|
|
10559
10591
|
constructor() {
|
|
10560
|
-
super('stop-tracks'
|
|
10592
|
+
super('stop-tracks',
|
|
10593
|
+
// `camera` is not in the W3C standard yet,
|
|
10594
|
+
// but it's supported by Chrome and Safari.
|
|
10595
|
+
'camera');
|
|
10561
10596
|
this.directionSubject = new rxjs.BehaviorSubject(undefined);
|
|
10562
10597
|
this.direction$ = this.directionSubject
|
|
10563
10598
|
.asObservable()
|
|
@@ -10687,7 +10722,10 @@ class CameraManager extends InputMediaDeviceManager {
|
|
|
10687
10722
|
|
|
10688
10723
|
class MicrophoneManagerState extends InputMediaDeviceManagerState {
|
|
10689
10724
|
constructor() {
|
|
10690
|
-
super('disable-tracks'
|
|
10725
|
+
super('disable-tracks',
|
|
10726
|
+
// `microphone` is not in the W3C standard yet,
|
|
10727
|
+
// but it's supported by Chrome and Safari.
|
|
10728
|
+
'microphone');
|
|
10691
10729
|
this.speakingWhileMutedSubject = new rxjs.BehaviorSubject(false);
|
|
10692
10730
|
this.speakingWhileMuted$ = this.speakingWhileMutedSubject
|
|
10693
10731
|
.asObservable()
|
|
@@ -11014,6 +11052,21 @@ class SpeakerState {
|
|
|
11014
11052
|
class SpeakerManager {
|
|
11015
11053
|
constructor() {
|
|
11016
11054
|
this.state = new SpeakerState();
|
|
11055
|
+
this.subscriptions = [];
|
|
11056
|
+
this.removeSubscriptions = () => {
|
|
11057
|
+
this.subscriptions.forEach((s) => s.unsubscribe());
|
|
11058
|
+
};
|
|
11059
|
+
if (deviceIds$ && !isReactNative()) {
|
|
11060
|
+
this.subscriptions.push(rxjs.combineLatest([deviceIds$, this.state.selectedDevice$]).subscribe(([devices, deviceId]) => {
|
|
11061
|
+
if (!deviceId) {
|
|
11062
|
+
return;
|
|
11063
|
+
}
|
|
11064
|
+
const device = devices.find((d) => d.deviceId === deviceId && d.kind === 'audiooutput');
|
|
11065
|
+
if (!device) {
|
|
11066
|
+
this.select('');
|
|
11067
|
+
}
|
|
11068
|
+
}));
|
|
11069
|
+
}
|
|
11017
11070
|
}
|
|
11018
11071
|
/**
|
|
11019
11072
|
* Lists the available audio output devices
|
|
@@ -11131,6 +11184,10 @@ class Call {
|
|
|
11131
11184
|
this.leaveCallHooks.forEach((hook) => hook());
|
|
11132
11185
|
this.clientStore.unregisterCall(this);
|
|
11133
11186
|
this.state.setCallingState(exports.CallingState.LEFT);
|
|
11187
|
+
this.camera.removeSubscriptions();
|
|
11188
|
+
this.microphone.removeSubscriptions();
|
|
11189
|
+
this.screenShare.removeSubscriptions();
|
|
11190
|
+
this.speaker.removeSubscriptions();
|
|
11134
11191
|
};
|
|
11135
11192
|
/**
|
|
11136
11193
|
* Loads the information about the call.
|
|
@@ -11504,7 +11561,7 @@ class Call {
|
|
|
11504
11561
|
await this.initMic({ setStatus: true });
|
|
11505
11562
|
}
|
|
11506
11563
|
catch (error) {
|
|
11507
|
-
this.logger('warn', 'Camera and/or mic init failed during join call');
|
|
11564
|
+
this.logger('warn', 'Camera and/or mic init failed during join call', error);
|
|
11508
11565
|
}
|
|
11509
11566
|
// 3. once we have the "joinResponse", and possibly reconciled the local state
|
|
11510
11567
|
// we schedule a fast subscription update for all remote participants
|
|
@@ -13977,7 +14034,7 @@ class StreamClient {
|
|
|
13977
14034
|
});
|
|
13978
14035
|
};
|
|
13979
14036
|
this.getUserAgent = () => {
|
|
13980
|
-
const version = "0.4.
|
|
14037
|
+
const version = "0.4.7" ;
|
|
13981
14038
|
return (this.userAgent ||
|
|
13982
14039
|
`stream-video-javascript-client-${this.node ? 'node' : 'browser'}-${version}`);
|
|
13983
14040
|
};
|
|
@@ -14560,6 +14617,7 @@ exports.conditional = conditional;
|
|
|
14560
14617
|
exports.createSoundDetector = createSoundDetector;
|
|
14561
14618
|
exports.defaultSortPreset = defaultSortPreset;
|
|
14562
14619
|
exports.descending = descending;
|
|
14620
|
+
exports.deviceIds$ = deviceIds$;
|
|
14563
14621
|
exports.disposeOfMediaStream = disposeOfMediaStream;
|
|
14564
14622
|
exports.dominantSpeaker = dominantSpeaker;
|
|
14565
14623
|
exports.getAudioDevices = getAudioDevices;
|
|
@@ -14592,10 +14650,4 @@ exports.setOSInfo = setOSInfo;
|
|
|
14592
14650
|
exports.setSdkInfo = setSdkInfo;
|
|
14593
14651
|
exports.speakerLayoutSortPreset = speakerLayoutSortPreset;
|
|
14594
14652
|
exports.speaking = speaking;
|
|
14595
|
-
exports.watchForAddedDefaultAudioDevice = watchForAddedDefaultAudioDevice;
|
|
14596
|
-
exports.watchForAddedDefaultAudioOutputDevice = watchForAddedDefaultAudioOutputDevice;
|
|
14597
|
-
exports.watchForAddedDefaultVideoDevice = watchForAddedDefaultVideoDevice;
|
|
14598
|
-
exports.watchForDisconnectedAudioDevice = watchForDisconnectedAudioDevice;
|
|
14599
|
-
exports.watchForDisconnectedAudioOutputDevice = watchForDisconnectedAudioOutputDevice;
|
|
14600
|
-
exports.watchForDisconnectedVideoDevice = watchForDisconnectedVideoDevice;
|
|
14601
14653
|
//# sourceMappingURL=index.cjs.js.map
|