diff --git a/.gitignore b/.gitignore
index 5396725..30d8e6c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,7 @@
node_modules/
-/app/config.*
-!/app/config.example.js
-
/server/config.*
!/server/config.example.js
/server/public/
-/server/certs/*
-!/server/certs/mediasoup-demo.localhost.cert.pem
-!/server/certs/mediasoup-demo.localhost.key.pem
+/server/certs/
+!/server/certs/mediasoup-demo.localhost.*
diff --git a/README.md b/README.md
index c1cce77..c437d73 100644
--- a/README.md
+++ b/README.md
@@ -34,12 +34,6 @@ $ cd app
$ npm install
```
-* Copy `config.example.js` as `config.js`:
-
-```bash
-$ cp config.example.js config.js
-```
-
* Globally install `gulp-cli` NPM module (may need `sudo`):
```bash
@@ -77,7 +71,7 @@ $ gulp prod
* Upload the entire `server` folder to your server and make your web server (Apache, Nginx...) expose the `server/public` folder.
-* Edit your `server/config.js` with appropriate settings (listening IP/port, logging options, **valid** TLS certificate, etc). Also set the proper remote WebSocket port in `client/config.js`.
+* Edit your `server/config.js` with appropriate settings (listening IP/port, logging options, **valid** TLS certificate, etc).
* Within your server, run the server side Node.js application. We recommend using the [forever](https://www.npmjs.com/package/forever) NPM daemon launcher, but any other can be used:
diff --git a/app/.eslintrc.js b/app/.eslintrc.js
index 88e6e51..70a5569 100644
--- a/app/.eslintrc.js
+++ b/app/.eslintrc.js
@@ -1,96 +1,229 @@
module.exports =
{
- env :
+ env:
{
- 'browser' : true,
- 'es6' : true,
- 'node' : true,
- 'commonjs' : true
+ browser: true,
+ es6: true,
+ node: true
},
- plugins :
+ plugins:
[
- 'react',
- 'import'
+ 'import',
+ 'react'
],
- extends :
+ extends:
[
'eslint:recommended',
'plugin:react/recommended'
],
- settings :
+ settings:
{
- react :
+ react:
{
- pragma : 'React',
- version : '15'
+ pragma: 'React',
+ version: '15'
}
},
- parserOptions :
+ parserOptions:
{
- ecmaVersion : 6,
- sourceType : 'module',
- ecmaFeatures :
+ ecmaVersion: 6,
+ sourceType: 'module',
+ ecmaFeatures:
{
- impliedStrict : true,
- jsx : true
+ impliedStrict: true,
+ experimentalObjectRestSpread: true,
+ jsx: true
}
},
- rules :
+ rules:
{
- 'no-console' : 0,
- 'no-undef' : 2,
- 'no-unused-vars' : [ 1, { vars: 'all', args: 'after-used' }],
- 'no-empty' : 0,
- 'quotes' : [ 2, 'single', { avoidEscape: true } ],
- 'semi' : [ 2, 'always' ],
- 'no-multi-spaces' : 0,
- 'no-whitespace-before-property' : 2,
- 'space-before-blocks' : 2,
- 'space-before-function-paren' : [ 2, 'never' ],
- 'space-in-parens' : [ 2, 'never' ],
- 'spaced-comment' : [ 2, 'always' ],
- 'comma-spacing' : [ 2, { before: false, after: true } ],
- 'jsx-quotes' : [ 2, 'prefer-single' ],
- 'react/display-name' : [ 2, { ignoreTranspilerName: false } ],
- 'react/forbid-prop-types' : 0,
- 'react/jsx-boolean-value' : 1,
- 'react/jsx-closing-bracket-location' : 1,
- 'react/jsx-curly-spacing' : 1,
- 'react/jsx-equals-spacing' : 1,
- 'react/jsx-handler-names' : 1,
- 'react/jsx-indent-props' : [ 2, 'tab' ],
- 'react/jsx-indent' : [ 2, 'tab' ],
- 'react/jsx-key' : 1,
- 'react/jsx-max-props-per-line' : 0,
- 'react/jsx-no-bind' : 0,
- 'react/jsx-no-duplicate-props' : 1,
- 'react/jsx-no-literals' : 0,
- 'react/jsx-no-undef' : 1,
- 'react/jsx-pascal-case' : 1,
- 'react/jsx-sort-prop-types' : 0,
- 'react/jsx-sort-props' : 0,
- 'react/jsx-uses-react' : 1,
- 'react/jsx-uses-vars' : 1,
- 'react/no-danger' : 1,
- 'react/no-deprecated' : 1,
- 'react/no-did-mount-set-state' : 1,
- 'react/no-did-update-set-state' : 1,
- 'react/no-direct-mutation-state' : 1,
- 'react/no-is-mounted' : 1,
- 'react/no-multi-comp' : 0,
- 'react/no-set-state' : 0,
- 'react/no-string-refs' : 0,
- 'react/no-unknown-property' : 1,
- 'react/prefer-es6-class' : 1,
- 'react/prop-types' : 1,
- 'react/react-in-jsx-scope' : 1,
- 'react/self-closing-comp' : 1,
- 'react/sort-comp' : 0,
- 'react/jsx-wrap-multilines' :
- [
- 1,
- { declaration: false, assignment: false, return: true }
- ],
- 'import/extensions' : 1
+ 'array-bracket-spacing': [ 2, 'always',
+ {
+ objectsInArrays: true,
+ arraysInArrays: true
+ }],
+ 'arrow-parens': [ 2, 'always' ],
+ 'arrow-spacing': 2,
+ 'block-spacing': [ 2, 'always' ],
+ 'brace-style': [ 2, 'allman', { allowSingleLine: true } ],
+ 'camelcase': 2,
+ 'comma-dangle': 2,
+ 'comma-spacing': [ 2, { before: false, after: true } ],
+ 'comma-style': 2,
+ 'computed-property-spacing': 2,
+ 'constructor-super': 2,
+ 'func-call-spacing': 2,
+ 'generator-star-spacing': 2,
+ 'guard-for-in': 2,
+ 'indent': [ 2, 'tab', { 'SwitchCase': 1 } ],
+ 'key-spacing': [ 2,
+ {
+ singleLine:
+ {
+ beforeColon: false,
+ afterColon: true
+ },
+ multiLine:
+ {
+ beforeColon: true,
+ afterColon: true,
+ align: 'colon'
+ }
+ }],
+ 'keyword-spacing': 2,
+ 'linebreak-style': [ 2, 'unix' ],
+ 'lines-around-comment': [ 2,
+ {
+ allowBlockStart: true,
+ allowObjectStart: true,
+ beforeBlockComment: true,
+ beforeLineComment: false
+ }],
+ 'max-len': [ 2, 90,
+ {
+ tabWidth: 2,
+ comments: 110,
+ ignoreUrls: true,
+ ignoreStrings: true,
+ ignoreTemplateLiterals: true,
+ ignoreRegExpLiterals: true
+ }],
+ 'newline-after-var': 2,
+ 'newline-before-return': 2,
+ 'newline-per-chained-call': 2,
+ 'no-alert': 2,
+ 'no-caller': 2,
+ 'no-case-declarations': 2,
+ 'no-catch-shadow': 2,
+ 'no-class-assign': 2,
+ 'no-confusing-arrow': 2,
+ 'no-console': 2,
+ 'no-const-assign': 2,
+ 'no-debugger': 2,
+ 'no-dupe-args': 2,
+ 'no-dupe-keys': 2,
+ 'no-duplicate-case': 2,
+ 'no-div-regex': 2,
+ 'no-empty': [ 2, { allowEmptyCatch: true } ],
+ 'no-empty-pattern': 2,
+ 'no-else-return': 0,
+ 'no-eval': 2,
+ 'no-extend-native': 2,
+ 'no-ex-assign': 2,
+ 'no-extra-bind': 2,
+ 'no-extra-boolean-cast': 2,
+ 'no-extra-label': 2,
+ 'no-extra-semi': 2,
+ 'no-fallthrough': 2,
+ 'no-func-assign': 2,
+ 'no-global-assign': 2,
+ 'no-implicit-coercion': 2,
+ 'no-implicit-globals': 2,
+ 'no-inner-declarations': 2,
+ 'no-invalid-regexp': 2,
+ 'no-invalid-this': 2,
+ 'no-irregular-whitespace': 2,
+ 'no-lonely-if': 2,
+ 'no-mixed-operators': 2,
+ 'no-mixed-spaces-and-tabs': 2,
+ 'no-multi-spaces': 2,
+ 'no-multi-str': 2,
+ 'no-multiple-empty-lines': [ 2, { max: 1, maxEOF: 0, maxBOF: 0 } ],
+ 'no-native-reassign': 2,
+ 'no-negated-in-lhs': 2,
+ 'no-new': 2,
+ 'no-new-func': 2,
+ 'no-new-wrappers': 2,
+ 'no-obj-calls': 2,
+ 'no-proto': 2,
+ 'no-prototype-builtins': 0,
+ 'no-redeclare': 2,
+ 'no-regex-spaces': 2,
+ 'no-restricted-imports': 2,
+ 'no-return-assign': 2,
+ 'no-self-assign': 2,
+ 'no-self-compare': 2,
+ 'no-sequences': 2,
+ 'no-shadow': 2,
+ 'no-shadow-restricted-names': 2,
+ 'no-spaced-func': 2,
+ 'no-sparse-arrays': 2,
+ 'no-this-before-super': 2,
+ 'no-throw-literal': 2,
+ 'no-undef': 2,
+ 'no-unexpected-multiline': 2,
+ 'no-unmodified-loop-condition': 2,
+ 'no-unreachable': 2,
+ 'no-unused-vars': [ 1, { vars: 'all', args: 'after-used' }],
+ 'no-use-before-define': [ 2, { functions: false } ],
+ 'no-useless-call': 2,
+ 'no-useless-computed-key': 2,
+ 'no-useless-concat': 2,
+ 'no-useless-rename': 2,
+ 'no-var': 2,
+ 'no-whitespace-before-property': 2,
+ 'object-curly-newline': 0,
+ 'object-curly-spacing': [ 2, 'always' ],
+ 'object-property-newline': [ 2, { allowMultiplePropertiesPerLine: true } ],
+ 'prefer-const': 2,
+ 'prefer-rest-params': 2,
+ 'prefer-spread': 2,
+ 'prefer-template': 2,
+ 'quotes': [ 2, 'single', { avoidEscape: true } ],
+ 'semi': [ 2, 'always' ],
+ 'semi-spacing': 2,
+ 'space-before-blocks': 2,
+ 'space-before-function-paren': [ 2, 'never' ],
+ 'space-in-parens': [ 2, 'never' ],
+ 'spaced-comment': [ 2, 'always' ],
+ 'strict': 2,
+ 'valid-typeof': 2,
+ 'yoda': 2,
+ // eslint-plugin-import options.
+ 'import/extensions': 2,
+ 'import/no-duplicates': 2,
+ // eslint-plugin-react options.
+ 'jsx-quotes': [ 2, 'prefer-single' ],
+ 'react/display-name': [ 2, { ignoreTranspilerName: false } ],
+ 'react/forbid-prop-types': 0,
+ 'react/jsx-boolean-value': 2,
+ 'react/jsx-closing-bracket-location': 2,
+ 'react/jsx-curly-spacing': 2,
+ 'react/jsx-equals-spacing': 2,
+ 'react/jsx-handler-names': 2,
+ 'react/jsx-indent-props': [ 2, 'tab' ],
+ 'react/jsx-indent': [ 2, 'tab' ],
+ 'react/jsx-key': 2,
+ 'react/jsx-max-props-per-line': 0,
+ 'react/jsx-no-bind': 0,
+ 'react/jsx-no-duplicate-props': 2,
+ 'react/jsx-no-literals': 0,
+ 'react/jsx-no-undef': 2,
+ 'react/jsx-pascal-case': 2,
+ 'react/jsx-sort-prop-types': 0,
+ 'react/jsx-sort-props': 0,
+ 'react/jsx-uses-react': 2,
+ 'react/jsx-uses-vars': 2,
+ 'react/no-danger': 2,
+ 'react/no-deprecated': 2,
+ 'react/no-did-mount-set-state': 2,
+ 'react/no-did-update-set-state': 2,
+ 'react/no-direct-mutation-state': 2,
+ 'react/no-is-mounted': 2,
+ 'react/no-multi-comp': 0,
+ 'react/no-set-state': 0,
+ 'react/no-string-refs': 0,
+ 'react/no-unknown-property': 2,
+ 'react/prefer-es6-class': 2,
+ 'react/prop-types': 2,
+ 'react/react-in-jsx-scope': 2,
+ 'react/self-closing-comp': 2,
+ 'react/sort-comp': 0,
+ 'react/jsx-wrap-multilines': [ 2,
+ {
+ declaration: false,
+ assignment: false,
+ return: true
+ }]
}
};
diff --git a/app/config.example.js b/app/config.example.js
deleted file mode 100644
index 87bf913..0000000
--- a/app/config.example.js
+++ /dev/null
@@ -1,7 +0,0 @@
-module.exports =
-{
- protoo :
- {
- listenPort : 3443
- }
-};
diff --git a/app/gulpfile.js b/app/gulpfile.js
index 9e3b147..6f06c06 100644
--- a/app/gulpfile.js
+++ b/app/gulpfile.js
@@ -1,17 +1,13 @@
-'use strict';
-
/**
* Tasks:
*
- * gulp prod
- * Generates the browser app in production mode.
- *
- * gulp dev
- * Generates the browser app in development mode.
+ * gulp dist
+ * Generates the browser app in development mode (unless NODE_ENV is set
+ * to 'production').
*
* gulp live
- * Generates the browser app in development mode, opens it and watches
- * for changes in the source code.
+ * Generates the browser app in development mode (unless NODE_ENV is set
+ * to 'production'), opens it and watches for changes in the source code.
*
* gulp
* Alias for `gulp live`.
@@ -23,9 +19,9 @@ const gulp = require('gulp');
const gulpif = require('gulp-if');
const gutil = require('gulp-util');
const plumber = require('gulp-plumber');
-const touch = require('gulp-touch');
const rename = require('gulp-rename');
const header = require('gulp-header');
+const touch = require('gulp-touch-cmd');
const browserify = require('browserify');
const watchify = require('watchify');
const envify = require('envify/custom');
@@ -50,24 +46,25 @@ const BANNER_OPTIONS =
};
const OUTPUT_DIR = '../server/public';
-// Default environment.
-process.env.NODE_ENV = 'development';
+// Set Node 'development' environment (unless externally set).
+process.env.NODE_ENV = process.env.NODE_ENV || 'development';
+
+gutil.log(`NODE_ENV: ${process.env.NODE_ENV}`);
function logError(error)
{
- gutil.log(gutil.colors.red(String(error)));
-
- throw error;
+ gutil.log(gutil.colors.red(error.stack));
}
function bundle(options)
{
options = options || {};
- let watch = !!options.watch;
+ const watch = Boolean(options.watch);
+
let bundler = browserify(
{
- entries : path.join(__dirname, PKG.main),
+ entries : PKG.main,
extensions : [ '.js', '.jsx' ],
// required for sourcemaps (must be false otherwise).
debug : process.env.NODE_ENV === 'development',
@@ -81,7 +78,12 @@ function bundle(options)
.transform('babelify',
{
presets : [ 'es2015', 'react' ],
- plugins : [ 'transform-runtime', 'transform-object-assign' ]
+ plugins :
+ [
+ 'transform-runtime',
+ 'transform-object-assign',
+ 'transform-object-rest-spread'
+ ]
})
.transform(envify(
{
@@ -95,7 +97,7 @@ function bundle(options)
bundler.on('update', () =>
{
- let start = Date.now();
+ const start = Date.now();
gutil.log('bundling...');
rebundle();
@@ -107,6 +109,7 @@ function bundle(options)
{
return bundler.bundle()
.on('error', logError)
+ .pipe(plumber())
.pipe(source(`${PKG.name}.js`))
.pipe(buffer())
.pipe(rename(`${PKG.name}.js`))
@@ -122,25 +125,14 @@ function bundle(options)
gulp.task('clean', () => del(OUTPUT_DIR, { force: true }));
-gulp.task('env:dev', (done) =>
-{
- gutil.log('setting "dev" environment');
-
- process.env.NODE_ENV = 'development';
- done();
-});
-
-gulp.task('env:prod', (done) =>
-{
- gutil.log('setting "prod" environment');
-
- process.env.NODE_ENV = 'production';
- done();
-});
-
gulp.task('lint', () =>
{
- let src = [ 'gulpfile.js', 'lib/**/*.js', 'lib/**/*.jsx' ];
+ const src =
+ [
+ 'gulpfile.js',
+ 'lib/**/*.js',
+ 'lib/**/*.jsx'
+ ];
return gulp.src(src)
.pipe(plumber())
@@ -176,7 +168,7 @@ gulp.task('html', () =>
gulp.task('resources', (done) =>
{
- let dst = path.join(OUTPUT_DIR, 'resources');
+ const dst = path.join(OUTPUT_DIR, 'resources');
mkdirp.sync(dst);
ncp('resources', dst, { stopOnErr: true }, (error) =>
@@ -204,9 +196,9 @@ gulp.task('livebrowser', (done) =>
browserSync(
{
- open : 'external',
- host : config.domain,
- server :
+ open : 'external',
+ host : config.domain,
+ server :
{
baseDir : OUTPUT_DIR
},
@@ -224,9 +216,9 @@ gulp.task('browser', (done) =>
browserSync(
{
- open : 'external',
- host : config.domain,
- server :
+ open : 'external',
+ host : config.domain,
+ server :
{
baseDir : OUTPUT_DIR
},
@@ -262,18 +254,7 @@ gulp.task('watch', (done) =>
done();
});
-gulp.task('prod', gulp.series(
- 'env:prod',
- 'clean',
- 'lint',
- 'bundle',
- 'html',
- 'css',
- 'resources'
-));
-
-gulp.task('dev', gulp.series(
- 'env:dev',
+gulp.task('dist', gulp.series(
'clean',
'lint',
'bundle',
@@ -283,7 +264,6 @@ gulp.task('dev', gulp.series(
));
gulp.task('live', gulp.series(
- 'env:dev',
'clean',
'lint',
'bundle:watch',
diff --git a/app/index.html b/app/index.html
index 85a16d6..17a3312 100644
--- a/app/index.html
+++ b/app/index.html
@@ -2,21 +2,21 @@
- mediasoup demo
+ mediasoup v2 demo
-
+
diff --git a/app/lib/Client.js b/app/lib/Client.js
deleted file mode 100644
index 0ba266a..0000000
--- a/app/lib/Client.js
+++ /dev/null
@@ -1,934 +0,0 @@
-'use strict';
-
-import events from 'events';
-import browser from 'bowser';
-import sdpTransform from 'sdp-transform';
-import Logger from './Logger';
-import protooClient from 'protoo-client';
-import * as urlFactory from './urlFactory';
-import * as utils from './utils';
-
-const logger = new Logger('Client');
-
-const DO_GETUSERMEDIA = true;
-const ENABLE_SIMULCAST = false;
-const VIDEO_CONSTRAINS =
-{
- qvga : { width: { ideal: 320 }, height: { ideal: 240 }},
- vga : { width: { ideal: 640 }, height: { ideal: 480 }},
- hd : { width: { ideal: 1280 }, height: { ideal: 720 }}
-};
-
-export default class Client extends events.EventEmitter
-{
- constructor(peerId, roomId)
- {
- logger.debug('constructor() [peerId:"%s", roomId:"%s"]', peerId, roomId);
-
- super();
- this.setMaxListeners(Infinity);
-
- // TODO: TMP
- global.CLIENT = this;
-
- let url = urlFactory.getProtooUrl(peerId, roomId);
- let transport = new protooClient.WebSocketTransport(url);
-
- // protoo-client Peer instance.
- this._protooPeer = new protooClient.Peer(transport);
-
- // RTCPeerConnection instance.
- this._peerconnection = null;
-
- // Webcam map indexed by deviceId.
- this._webcams = new Map();
-
- // Local Webcam device.
- this._webcam = null;
-
- // Local MediaStream instance.
- this._localStream = null;
-
- // Closed flag.
- this._closed = false;
-
- // Local video resolution.
- this._localVideoResolution = 'vga';
-
- this._protooPeer.on('open', () =>
- {
- logger.debug('protoo Peer "open" event');
- });
-
- this._protooPeer.on('disconnected', () =>
- {
- logger.warn('protoo Peer "disconnected" event');
-
- // Close RTCPeerConnection.
- try
- {
- this._peerconnection.close();
- }
- catch (error) {}
-
- // Close local MediaStream.
- if (this._localStream)
- utils.closeMediaStream(this._localStream);
-
- this.emit('disconnected');
- });
-
- this._protooPeer.on('close', () =>
- {
- if (this._closed)
- return;
-
- logger.warn('protoo Peer "close" event');
-
- this.close();
- });
-
- this._protooPeer.on('request', this._handleRequest.bind(this));
- }
-
- close()
- {
- if (this._closed)
- return;
-
- this._closed = true;
-
- logger.debug('close()');
-
- // Close protoo Peer.
- this._protooPeer.close();
-
- // Close RTCPeerConnection.
- try
- {
- this._peerconnection.close();
- }
- catch (error) {}
-
- // Close local MediaStream.
- if (this._localStream)
- utils.closeMediaStream(this._localStream);
-
- // Emit 'close' event.
- this.emit('close');
- }
-
- removeVideo(dontNegotiate)
- {
- logger.debug('removeVideo()');
-
- let stream = this._localStream;
- let videoTrack = stream.getVideoTracks()[0];
-
- if (!videoTrack)
- {
- logger.warn('removeVideo() | no video track');
-
- return Promise.reject(new Error('no video track'));
- }
-
- videoTrack.stop();
- stream.removeTrack(videoTrack);
-
- // New API.
- if (this._peerconnection.removeTrack)
- {
- let sender;
-
- for (sender of this._peerconnection.getSenders())
- {
- if (sender.track === videoTrack)
- break;
- }
-
- this._peerconnection.removeTrack(sender);
- }
- // Old API.
- else
- {
- this._peerconnection.addStream(stream);
- }
-
- if (!dontNegotiate)
- {
- this.emit('localstream', stream, null);
-
- return this._requestRenegotiation();
- }
- }
-
- addVideo()
- {
- logger.debug('addVideo()');
-
- let stream = this._localStream;
- let videoTrack;
- let videoResolution = this._localVideoResolution; // Keep previous resolution.
-
- if (stream)
- videoTrack = stream.getVideoTracks()[0];
-
- if (videoTrack)
- {
- logger.warn('addVideo() | there is already a video track');
-
- return Promise.reject(new Error('there is already a video track'));
- }
-
- return this._getLocalStream(
- {
- video : VIDEO_CONSTRAINS[videoResolution]
- })
- .then((newStream) =>
- {
- let newVideoTrack = newStream.getVideoTracks()[0];
-
- if (stream)
- {
- stream.addTrack(newVideoTrack);
-
- // New API.
- if (this._peerconnection.addTrack)
- {
- this._peerconnection.addTrack(newVideoTrack, stream);
- }
- // Old API.
- else
- {
- this._peerconnection.addStream(stream);
- }
- }
- else
- {
- this._localStream = newStream;
-
- // New API.
- if (this._peerconnection.addTrack)
- {
- this._peerconnection.addTrack(newVideoTrack, stream);
- }
- // Old API.
- else
- {
- this._peerconnection.addStream(stream);
- }
- }
-
- this.emit('localstream', this._localStream, videoResolution);
- })
- .then(() =>
- {
- return this._requestRenegotiation();
- })
- .catch((error) =>
- {
- logger.error('addVideo() failed: %o', error);
-
- throw error;
- });
- }
-
- changeWebcam()
- {
- logger.debug('changeWebcam()');
-
- return Promise.resolve()
- .then(() =>
- {
- return this._updateWebcams();
- })
- .then(() =>
- {
- let array = Array.from(this._webcams.keys());
- let len = array.length;
- let deviceId = this._webcam ? this._webcam.deviceId : undefined;
- let idx = array.indexOf(deviceId);
-
- if (idx < len - 1)
- idx++;
- else
- idx = 0;
-
- this._webcam = this._webcams.get(array[idx]);
-
- this._emitWebcamType();
-
- if (len < 2)
- return;
-
- logger.debug(
- 'changeWebcam() | new selected webcam [deviceId:"%s"]',
- this._webcam.deviceId);
-
- // Reset video resolution to VGA.
- this._localVideoResolution = 'vga';
-
- // For Chrome (old WenRTC API).
- // Replace the track (so new SSRC) and renegotiate.
- if (!this._peerconnection.removeTrack)
- {
- this.removeVideo(true);
-
- return this.addVideo();
- }
- // For Firefox (modern WebRTC API).
- // Avoid renegotiation.
- else
- {
- return this._getLocalStream(
- {
- video : VIDEO_CONSTRAINS[this._localVideoResolution]
- })
- .then((newStream) =>
- {
- let newVideoTrack = newStream.getVideoTracks()[0];
- let stream = this._localStream;
- let oldVideoTrack = stream.getVideoTracks()[0];
- let sender;
-
- for (sender of this._peerconnection.getSenders())
- {
- if (sender.track === oldVideoTrack)
- break;
- }
-
- sender.replaceTrack(newVideoTrack);
- stream.removeTrack(oldVideoTrack);
- oldVideoTrack.stop();
- stream.addTrack(newVideoTrack);
-
- this.emit('localstream', stream, this._localVideoResolution);
- });
- }
- })
- .catch((error) =>
- {
- logger.error('changeWebcam() failed: %o', error);
- });
- }
-
- changeVideoResolution()
- {
- logger.debug('changeVideoResolution()');
-
- let newVideoResolution;
-
- switch (this._localVideoResolution)
- {
- case 'qvga':
- newVideoResolution = 'vga';
- break;
- case 'vga':
- newVideoResolution = 'hd';
- break;
- case 'hd':
- newVideoResolution = 'qvga';
- break;
- default:
- throw new Error(`unknown resolution "${this._localVideoResolution}"`);
- }
-
- this._localVideoResolution = newVideoResolution;
-
- // For Chrome (old WenRTC API).
- // Replace the track (so new SSRC) and renegotiate.
- if (!this._peerconnection.removeTrack)
- {
- this.removeVideo(true);
-
- return this.addVideo();
- }
- // For Firefox (modern WebRTC API).
- // Avoid renegotiation.
- else
- {
- return this._getLocalStream(
- {
- video : VIDEO_CONSTRAINS[this._localVideoResolution]
- })
- .then((newStream) =>
- {
- let newVideoTrack = newStream.getVideoTracks()[0];
- let stream = this._localStream;
- let oldVideoTrack = stream.getVideoTracks()[0];
- let sender;
-
- for (sender of this._peerconnection.getSenders())
- {
- if (sender.track === oldVideoTrack)
- break;
- }
-
- sender.replaceTrack(newVideoTrack);
- stream.removeTrack(oldVideoTrack);
- oldVideoTrack.stop();
- stream.addTrack(newVideoTrack);
-
- this.emit('localstream', stream, newVideoResolution);
- })
- .catch((error) =>
- {
- logger.error('changeVideoResolution() failed: %o', error);
- });
- }
- }
-
- getStats()
- {
- return this._peerconnection.getStats()
- .catch((error) =>
- {
- logger.error('pc.getStats() failed: %o', error);
-
- throw error;
- });
- }
-
- disableRemoteVideo(msid)
- {
- return this._protooPeer.send('disableremotevideo', { msid, disable: true })
- .catch((error) =>
- {
- logger.warn('disableRemoteVideo() failed: %o', error);
- });
- }
-
- enableRemoteVideo(msid)
- {
- return this._protooPeer.send('disableremotevideo', { msid, disable: false })
- .catch((error) =>
- {
- logger.warn('enableRemoteVideo() failed: %o', error);
- });
- }
-
- _handleRequest(request, accept, reject)
- {
- logger.debug('_handleRequest() [method:%s, data:%o]', request.method, request.data);
-
- switch(request.method)
- {
- case 'joinme':
- {
- let videoResolution = this._localVideoResolution;
-
- Promise.resolve()
- .then(() =>
- {
- return this._updateWebcams();
- })
- .then(() =>
- {
- if (DO_GETUSERMEDIA)
- {
- return this._getLocalStream(
- {
- audio : true,
- video : VIDEO_CONSTRAINS[videoResolution]
- })
- .then((stream) =>
- {
- logger.debug('got local stream [resolution:%s]', videoResolution);
-
- // Close local MediaStream if any.
- if (this._localStream)
- utils.closeMediaStream(this._localStream);
-
- this._localStream = stream;
-
- // Emit 'localstream' event.
- this.emit('localstream', stream, videoResolution);
- });
- }
- })
- .then(() =>
- {
- return this._createPeerConnection();
- })
- .then(() =>
- {
- return this._peerconnection.createOffer(
- {
- offerToReceiveAudio : 1,
- offerToReceiveVideo : 1
- });
- })
- .then((offer) =>
- {
- let capabilities = offer.sdp;
- let parsedSdp = sdpTransform.parse(capabilities);
-
- logger.debug('capabilities [parsed:%O, sdp:%s]', parsedSdp, capabilities);
-
- // Accept the protoo request.
- accept(
- {
- capabilities : capabilities,
- usePlanB : utils.isPlanB()
- });
- })
- .then(() =>
- {
- logger.debug('"joinme" request accepted');
-
- // Emit 'join' event.
- this.emit('join');
- })
- .catch((error) =>
- {
- logger.error('"joinme" request failed: %o', error);
-
- reject(500, error.message);
- throw error;
- });
-
- break;
- }
-
- case 'peers':
- {
- this.emit('peers', request.data.peers);
- accept();
-
- break;
- }
-
- case 'addpeer':
- {
- this.emit('addpeer', request.data.peer);
- accept();
-
- break;
- }
-
- case 'updatepeer':
- {
- this.emit('updatepeer', request.data.peer);
- accept();
-
- break;
- }
-
- case 'removepeer':
- {
- this.emit('removepeer', request.data.peer);
- accept();
-
- break;
- }
-
- case 'offer':
- {
- let offer = new RTCSessionDescription(request.data.offer);
- let parsedSdp = sdpTransform.parse(offer.sdp);
-
- logger.debug('received offer [parsed:%O, sdp:%s]', parsedSdp, offer.sdp);
-
- Promise.resolve()
- .then(() =>
- {
- return this._peerconnection.setRemoteDescription(offer);
- })
- .then(() =>
- {
- return this._peerconnection.createAnswer();
- })
- // Play with simulcast.
- .then((answer) =>
- {
- if (!ENABLE_SIMULCAST)
- return answer;
-
- // Chrome Plan B simulcast.
- if (utils.isPlanB())
- {
- // Just for the initial offer.
- // NOTE: Otherwise Chrome crashes.
- // TODO: This prevents simulcast to be applied to new tracks.
- if (this._peerconnection.localDescription && this._peerconnection.localDescription.sdp)
- return answer;
-
- // TODO: Should be done just for VP8.
- let parsedSdp = sdpTransform.parse(answer.sdp);
- let videoMedia;
-
- for (let m of parsedSdp.media)
- {
- if (m.type === 'video')
- {
- videoMedia = m;
- break;
- }
- }
-
- if (!videoMedia || !videoMedia.ssrcs)
- return answer;
-
- logger.debug('setting video simulcast (PlanB)');
-
- let ssrc1;
- let ssrc2;
- let ssrc3;
- let cname;
- let msid;
-
- for (let ssrcObj of videoMedia.ssrcs)
- {
- // Chrome uses:
- // a=ssrc:xxxx msid:yyyy zzzz
- // a=ssrc:xxxx mslabel:yyyy
- // a=ssrc:xxxx label:zzzz
- // Where yyyy is the MediaStream.id and zzzz the MediaStreamTrack.id.
- switch (ssrcObj.attribute)
- {
- case 'cname':
- ssrc1 = ssrcObj.id;
- cname = ssrcObj.value;
- break;
-
- case 'msid':
- msid = ssrcObj.value;
- break;
- }
- }
-
- ssrc2 = ssrc1 + 1;
- ssrc3 = ssrc1 + 2;
-
- videoMedia.ssrcGroups =
- [
- {
- semantics : 'SIM',
- ssrcs : `${ssrc1} ${ssrc2} ${ssrc3}`
- }
- ];
-
- videoMedia.ssrcs =
- [
- {
- id : ssrc1,
- attribute : 'cname',
- value : cname,
- },
- {
- id : ssrc1,
- attribute : 'msid',
- value : msid,
- },
- {
- id : ssrc2,
- attribute : 'cname',
- value : cname,
- },
- {
- id : ssrc2,
- attribute : 'msid',
- value : msid,
- },
- {
- id : ssrc3,
- attribute : 'cname',
- value : cname,
- },
- {
- id : ssrc3,
- attribute : 'msid',
- value : msid,
- }
- ];
-
- let modifiedAnswer =
- {
- type : 'answer',
- sdp : sdpTransform.write(parsedSdp)
- };
-
- return modifiedAnswer;
- }
- // Firefox way.
- else
- {
- let parsedSdp = sdpTransform.parse(answer.sdp);
- let videoMedia;
-
- logger.debug('created answer [parsed:%O, sdp:%s]', parsedSdp, answer.sdp);
-
- for (let m of parsedSdp.media)
- {
- if (m.type === 'video' && m.direction === 'sendonly')
- {
- videoMedia = m;
- break;
- }
- }
-
- if (!videoMedia)
- return answer;
-
- logger.debug('setting video simulcast (Unified-Plan)');
-
- videoMedia.simulcast_03 =
- {
- value : 'send rid=1,2'
- };
-
- videoMedia.rids =
- [
- { id: '1', direction: 'send' },
- { id: '2', direction: 'send' }
- ];
-
- let modifiedAnswer =
- {
- type : 'answer',
- sdp : sdpTransform.write(parsedSdp)
- };
-
- return modifiedAnswer;
- }
- })
- .then((answer) =>
- {
- return this._peerconnection.setLocalDescription(answer);
- })
- .then(() =>
- {
- let answer = this._peerconnection.localDescription;
- let parsedSdp = sdpTransform.parse(answer.sdp);
-
- logger.debug('sent answer [parsed:%O, sdp:%s]', parsedSdp, answer.sdp);
-
- accept(
- {
- answer :
- {
- type : answer.type,
- sdp : answer.sdp
- }
- });
- })
- .catch((error) =>
- {
- logger.error('"offer" request failed: %o', error);
-
- reject(500, error.message);
- throw error;
- })
- .then(() =>
- {
- // If Firefox trigger 'forcestreamsupdate' event due to bug:
- // https://bugzilla.mozilla.org/show_bug.cgi?id=1347578
- if (browser.firefox || browser.gecko)
- {
- // Not sure, but it thinks that the timeout does the trick.
- setTimeout(() => this.emit('forcestreamsupdate'), 500);
- }
- });
-
- break;
- }
-
- case 'activespeaker':
- {
- let data = request.data;
-
- this.emit('activespeaker', data.peer, data.level);
- accept();
-
- break;
- }
-
- default:
- {
- logger.error('unknown method');
-
- reject(404, 'unknown method');
- }
- }
- }
-
- _updateWebcams()
- {
- logger.debug('_updateWebcams()');
-
- // Reset the list.
- this._webcams = new Map();
-
- return Promise.resolve()
- .then(() =>
- {
- return navigator.mediaDevices.enumerateDevices();
- })
- .then((devices) =>
- {
- for (let device of devices)
- {
- if (device.kind !== 'videoinput')
- continue;
-
- this._webcams.set(device.deviceId, device);
- }
- })
- .then(() =>
- {
- let array = Array.from(this._webcams.values());
- let len = array.length;
- let currentWebcamId = this._webcam ? this._webcam.deviceId : undefined;
-
- logger.debug('_updateWebcams() [webcams:%o]', array);
-
- if (len === 0)
- this._webcam = null;
- else if (!this._webcams.has(currentWebcamId))
- this._webcam = array[0];
-
- this.emit('numwebcams', len);
-
- this._emitWebcamType();
- });
- }
-
- _getLocalStream(constraints)
- {
- logger.debug('_getLocalStream() [constraints:%o, webcam:%o]',
- constraints, this._webcam);
-
- if (this._webcam)
- constraints.video.deviceId = { exact: this._webcam.deviceId };
-
- return navigator.mediaDevices.getUserMedia(constraints);
- }
-
- _createPeerConnection()
- {
- logger.debug('_createPeerConnection()');
-
- this._peerconnection = new RTCPeerConnection({ iceServers: [] });
-
- // TODO: TMP
- global.PC = this._peerconnection;
-
- if (this._localStream)
- this._peerconnection.addStream(this._localStream);
-
- this._peerconnection.addEventListener('iceconnectionstatechange', () =>
- {
- let state = this._peerconnection.iceConnectionState;
-
- if (state === 'failed')
- logger.warn('peerconnection "iceconnectionstatechange" event [state:failed]');
- else
- logger.debug('peerconnection "iceconnectionstatechange" event [state:%s]', state);
-
- this.emit('connectionstate', state);
- });
-
- this._peerconnection.addEventListener('addstream', (event) =>
- {
- let stream = event.stream;
-
- logger.debug('peerconnection "addstream" event [stream:%o]', stream);
-
- this.emit('addstream', stream);
-
- // NOTE: For testing.
- let interval = setInterval(() =>
- {
- if (!stream.active)
- {
- logger.warn('stream inactive [stream:%o]', stream);
-
- clearInterval(interval);
- }
- }, 2000);
-
- stream.addEventListener('addtrack', (event) =>
- {
- let track = event.track;
-
- logger.debug('stream "addtrack" event [track:%o]', track);
-
- this.emit('addtrack', track);
-
- // Firefox does not implement 'stream.onremovetrack' so let's use 'track.ended'.
- // But... track "ended" is neither fired.
- // https://bugzilla.mozilla.org/show_bug.cgi?id=1347578
- track.addEventListener('ended', () =>
- {
- logger.debug('track "ended" event [track:%o]', track);
-
- this.emit('removetrack', track);
- });
- });
-
- // NOTE: Not implemented in Firefox.
- stream.addEventListener('removetrack', (event) =>
- {
- let track = event.track;
-
- logger.debug('stream "removetrack" event [track:%o]', track);
-
- this.emit('removetrack', track);
- });
- });
-
- this._peerconnection.addEventListener('removestream', (event) =>
- {
- let stream = event.stream;
-
- logger.debug('peerconnection "removestream" event [stream:%o]', stream);
-
- this.emit('removestream', stream);
- });
- }
-
- _requestRenegotiation()
- {
- logger.debug('_requestRenegotiation()');
-
- return this._protooPeer.send('reofferme');
- }
-
- _restartIce()
- {
- logger.debug('_restartIce()');
-
- return this._protooPeer.send('restartice')
- .then(() =>
- {
- logger.debug('_restartIce() succeded');
- })
- .catch((error) =>
- {
- logger.error('_restartIce() failed: %o', error);
-
- throw error;
- });
- }
-
- _emitWebcamType()
- {
- let webcam = this._webcam;
-
- if (!webcam)
- return;
-
- if (/(back|rear)/i.test(webcam.label))
- {
- logger.debug('_emitWebcamType() | it seems to be a back camera');
-
- this.emit('webcamtype', 'back');
- }
- else
- {
- logger.debug('_emitWebcamType() | it seems to be a front camera');
-
- this.emit('webcamtype', 'front');
- }
- }
-}
diff --git a/app/lib/Logger.js b/app/lib/Logger.js
index f2f9acf..7d1baa1 100644
--- a/app/lib/Logger.js
+++ b/app/lib/Logger.js
@@ -1,5 +1,3 @@
-'use strict';
-
import debug from 'debug';
const APP_NAME = 'mediasoup-demo';
@@ -10,20 +8,22 @@ export default class Logger
{
if (prefix)
{
- this._debug = debug(APP_NAME + ':' + prefix);
- this._warn = debug(APP_NAME + ':WARN:' + prefix);
- this._error = debug(APP_NAME + ':ERROR:' + prefix);
+ this._debug = debug(`${APP_NAME}:${prefix}`);
+ this._warn = debug(`${APP_NAME}:WARN:${prefix}`);
+ this._error = debug(`${APP_NAME}:ERROR:${prefix}`);
}
else
{
this._debug = debug(APP_NAME);
- this._warn = debug(APP_NAME + ':WARN');
- this._error = debug(APP_NAME + ':ERROR');
+ this._warn = debug(`${APP_NAME}:WARN`);
+ this._error = debug(`${APP_NAME}:ERROR`);
}
+ /* eslint-disable no-console */
this._debug.log = console.info.bind(console);
this._warn.log = console.warn.bind(console);
this._error.log = console.error.bind(console);
+ /* eslint-enable no-console */
}
get debug()
diff --git a/app/lib/RoomClient.js b/app/lib/RoomClient.js
new file mode 100644
index 0000000..268621e
--- /dev/null
+++ b/app/lib/RoomClient.js
@@ -0,0 +1,1148 @@
+import protooClient from 'protoo-client';
+import * as mediasoupClient from 'mediasoup-client';
+import Logger from './Logger';
+import { getProtooUrl } from './urlFactory';
+import * as cookiesManager from './cookiesManager';
+import * as requestActions from './redux/requestActions';
+import * as stateActions from './redux/stateActions';
+
+const logger = new Logger('RoomClient');
+
+const ROOM_OPTIONS =
+{
+ requestTimeout : 10000,
+ transportOptions :
+ {
+ tcp : false
+ }
+};
+
+const VIDEO_CONSTRAINS =
+{
+ qvga : { width: { ideal: 320 }, height: { ideal: 240 } },
+ vga : { width: { ideal: 640 }, height: { ideal: 480 } },
+ hd : { width: { ideal: 1280 }, height: { ideal: 720 } }
+};
+
+export default class RoomClient
+{
+ constructor(
+ { roomId, peerName, displayName, device, useSimulcast, produce, dispatch, getState })
+ {
+ logger.debug(
+ 'constructor() [roomId:"%s", peerName:"%s", displayName:"%s", device:%s]',
+ roomId, peerName, displayName, device.flag);
+
+ const protooUrl = getProtooUrl(peerName, roomId);
+ const protooTransport = new protooClient.WebSocketTransport(protooUrl);
+
+ // Closed flag.
+ this._closed = false;
+
+ // Whether we should produce.
+ this._produce = produce;
+
+ // Whether simulcast should be used.
+ this._useSimulcast = useSimulcast;
+
+ // Redux store dispatch function.
+ this._dispatch = dispatch;
+
+ // Redux store getState function.
+ this._getState = getState;
+
+ // My peer name.
+ this._peerName = peerName;
+
+ // protoo-client Peer instance.
+ this._protoo = new protooClient.Peer(protooTransport);
+
+ // mediasoup-client Room instance.
+ this._room = new mediasoupClient.Room(ROOM_OPTIONS);
+
+ // Transport for sending.
+ this._sendTransport = null;
+
+ // Transport for receiving.
+ this._recvTransport = null;
+
+ // Local mic mediasoup Producer.
+ this._micProducer = null;
+
+ // Local webcam mediasoup Producer.
+ this._webcamProducer = null;
+
+ // Map of webcam MediaDeviceInfos indexed by deviceId.
+ // @type {Map}
+ this._webcams = new Map();
+
+ // Local Webcam. Object with:
+ // - {MediaDeviceInfo} [device]
+ // - {String} [resolution] - 'qvga' / 'vga' / 'hd'.
+ this._webcam =
+ {
+ device : null,
+ resolution : 'hd'
+ };
+
+ this._join({ displayName, device });
+ }
+
+ close()
+ {
+ if (this._closed)
+ return;
+
+ this._closed = true;
+
+ logger.debug('close()');
+
+ // Leave the mediasoup Room.
+ this._room.leave();
+
+ // Close protoo Peer (wait a bit so mediasoup-client can send
+ // the 'leaveRoom' notification).
+ setTimeout(() => this._protoo.close(), 250);
+
+ this._dispatch(stateActions.setRoomState('closed'));
+ }
+
+ changeDisplayName(displayName)
+ {
+ logger.debug('changeDisplayName() [displayName:"%s"]', displayName);
+
+ // Store in cookie.
+ cookiesManager.setUser({ displayName });
+
+ return this._protoo.send('change-display-name', { displayName })
+ .then(() =>
+ {
+ this._dispatch(
+ stateActions.setDisplayName(displayName));
+
+ this._dispatch(requestActions.notify(
+ {
+ text : 'Display name changed'
+ }));
+ })
+ .catch((error) =>
+ {
+ logger.error('changeDisplayName() | failed: %o', error);
+
+ this._dispatch(requestActions.notify(
+ {
+ type : 'error',
+ text : `Could not change display name: ${error}`
+ }));
+
+ // We need to refresh the component for it to render the previous
+ // displayName again.
+ this._dispatch(stateActions.setDisplayName());
+ });
+ }
+
+ muteMic()
+ {
+ logger.debug('muteMic()');
+
+ this._micProducer.pause();
+ }
+
+ unmuteMic()
+ {
+ logger.debug('unmuteMic()');
+
+ this._micProducer.resume();
+ }
+
+ enableWebcam()
+ {
+ logger.debug('enableWebcam()');
+
+ // Store in cookie.
+ cookiesManager.setDevices({ webcamEnabled: true });
+
+ this._dispatch(
+ stateActions.setWebcamInProgress(true));
+
+ return Promise.resolve()
+ .then(() =>
+ {
+ return this._updateWebcams();
+ })
+ .then(() =>
+ {
+ return this._setWebcamProducer();
+ })
+ .then(() =>
+ {
+ this._dispatch(
+ stateActions.setWebcamInProgress(false));
+ })
+ .catch((error) =>
+ {
+ logger.error('enableWebcam() | failed: %o', error);
+
+ this._dispatch(
+ stateActions.setWebcamInProgress(false));
+ });
+ }
+
+ disableWebcam()
+ {
+ logger.debug('disableWebcam()');
+
+ // Store in cookie.
+ cookiesManager.setDevices({ webcamEnabled: false });
+
+ this._dispatch(
+ stateActions.setWebcamInProgress(true));
+
+ return Promise.resolve()
+ .then(() =>
+ {
+ this._webcamProducer.close();
+
+ this._dispatch(
+ stateActions.setWebcamInProgress(false));
+ })
+ .catch((error) =>
+ {
+ logger.error('disableWebcam() | failed: %o', error);
+
+ this._dispatch(
+ stateActions.setWebcamInProgress(false));
+ });
+ }
+
+ changeWebcam()
+ {
+ logger.debug('changeWebcam()');
+
+ this._dispatch(
+ stateActions.setWebcamInProgress(true));
+
+ return Promise.resolve()
+ .then(() =>
+ {
+ return this._updateWebcams();
+ })
+ .then(() =>
+ {
+ const array = Array.from(this._webcams.keys());
+ const len = array.length;
+ const deviceId =
+ this._webcam.device ? this._webcam.device.deviceId : undefined;
+ let idx = array.indexOf(deviceId);
+
+ if (idx < len - 1)
+ idx++;
+ else
+ idx = 0;
+
+ this._webcam.device = this._webcams.get(array[idx]);
+
+ logger.debug(
+ 'changeWebcam() | new selected webcam [device:%o]',
+ this._webcam.device);
+
+ // Reset video resolution to HD.
+ this._webcam.resolution = 'hd';
+ })
+ .then(() =>
+ {
+ const { device, resolution } = this._webcam;
+
+ if (!device)
+ throw new Error('no webcam devices');
+
+ logger.debug('changeWebcam() | calling getUserMedia()');
+
+ return navigator.mediaDevices.getUserMedia(
+ {
+ video :
+ {
+ deviceId : { exact: device.deviceId },
+ ...VIDEO_CONSTRAINS[resolution]
+ }
+ });
+ })
+ .then((stream) =>
+ {
+ const track = stream.getVideoTracks()[0];
+
+ return this._webcamProducer.replaceTrack(track)
+ .then((newTrack) =>
+ {
+ track.stop();
+
+ return newTrack;
+ });
+ })
+ .then((newTrack) =>
+ {
+ this._dispatch(
+ stateActions.setProducerTrack(this._webcamProducer.id, newTrack));
+
+ this._dispatch(
+ stateActions.setWebcamInProgress(false));
+ })
+ .catch((error) =>
+ {
+ logger.error('changeWebcam() failed: %o', error);
+
+ this._dispatch(
+ stateActions.setWebcamInProgress(false));
+ });
+ }
+
+ changeWebcamResolution()
+ {
+ logger.debug('changeWebcamResolution()');
+
+ let oldResolution;
+ let newResolution;
+
+ this._dispatch(
+ stateActions.setWebcamInProgress(true));
+
+ return Promise.resolve()
+ .then(() =>
+ {
+ oldResolution = this._webcam.resolution;
+
+ switch (oldResolution)
+ {
+ case 'qvga':
+ newResolution = 'vga';
+ break;
+ case 'vga':
+ newResolution = 'hd';
+ break;
+ case 'hd':
+ newResolution = 'qvga';
+ break;
+ }
+
+ this._webcam.resolution = newResolution;
+ })
+ .then(() =>
+ {
+ const { device, resolution } = this._webcam;
+
+ logger.debug('changeWebcamResolution() | calling getUserMedia()');
+
+ return navigator.mediaDevices.getUserMedia(
+ {
+ video :
+ {
+ deviceId : { exact: device.deviceId },
+ ...VIDEO_CONSTRAINS[resolution]
+ }
+ });
+ })
+ .then((stream) =>
+ {
+ const track = stream.getVideoTracks()[0];
+
+ return this._webcamProducer.replaceTrack(track)
+ .then((newTrack) =>
+ {
+ track.stop();
+
+ return newTrack;
+ });
+ })
+ .then((newTrack) =>
+ {
+ this._dispatch(
+ stateActions.setProducerTrack(this._webcamProducer.id, newTrack));
+
+ this._dispatch(
+ stateActions.setWebcamInProgress(false));
+ })
+ .catch((error) =>
+ {
+ logger.error('changeWebcamResolution() failed: %o', error);
+
+ this._dispatch(
+ stateActions.setWebcamInProgress(false));
+
+ this._webcam.resolution = oldResolution;
+ });
+ }
+
+ enableAudioOnly()
+ {
+ logger.debug('enableAudioOnly()');
+
+ this._dispatch(
+ stateActions.setAudioOnlyInProgress(true));
+
+ return Promise.resolve()
+ .then(() =>
+ {
+ if (this._webcamProducer)
+ this._webcamProducer.close();
+
+ for (const peer of this._room.peers)
+ {
+ for (const consumer of peer.consumers)
+ {
+ if (consumer.kind !== 'video')
+ continue;
+
+ consumer.pause('audio-only-mode');
+ }
+ }
+
+ this._dispatch(
+ stateActions.setAudioOnlyState(true));
+
+ this._dispatch(
+ stateActions.setAudioOnlyInProgress(false));
+ })
+ .catch((error) =>
+ {
+ logger.error('enableAudioOnly() failed: %o', error);
+
+ this._dispatch(
+ stateActions.setAudioOnlyInProgress(false));
+ });
+ }
+
+ disableAudioOnly()
+ {
+ logger.debug('disableAudioOnly()');
+
+ this._dispatch(
+ stateActions.setAudioOnlyInProgress(true));
+
+ return Promise.resolve()
+ .then(() =>
+ {
+ if (!this._webcamProducer && this._room.canSend('video'))
+ return this.enableWebcam();
+ })
+ .then(() =>
+ {
+ for (const peer of this._room.peers)
+ {
+ for (const consumer of peer.consumers)
+ {
+ if (consumer.kind !== 'video' || !consumer.supported)
+ continue;
+
+ consumer.resume();
+ }
+ }
+
+ this._dispatch(
+ stateActions.setAudioOnlyState(false));
+
+ this._dispatch(
+ stateActions.setAudioOnlyInProgress(false));
+ })
+ .catch((error) =>
+ {
+ logger.error('disableAudioOnly() failed: %o', error);
+
+ this._dispatch(
+ stateActions.setAudioOnlyInProgress(false));
+ });
+ }
+
+ restartIce()
+ {
+ logger.debug('restartIce()');
+
+ this._dispatch(
+ stateActions.setRestartIceInProgress(true));
+
+ return Promise.resolve()
+ .then(() =>
+ {
+ this._room.restartIce();
+
+ // Make it artificially longer.
+ setTimeout(() =>
+ {
+ this._dispatch(
+ stateActions.setRestartIceInProgress(false));
+ }, 500);
+ })
+ .catch((error) =>
+ {
+ logger.error('restartIce() failed: %o', error);
+
+ this._dispatch(
+ stateActions.setRestartIceInProgress(false));
+ });
+ }
+
+ _join({ displayName, device })
+ {
+ this._dispatch(stateActions.setRoomState('connecting'));
+
+ this._protoo.on('open', () =>
+ {
+ logger.debug('protoo Peer "open" event');
+
+ this._joinRoom({ displayName, device });
+ });
+
+ this._protoo.on('disconnected', () =>
+ {
+ logger.warn('protoo Peer "disconnected" event');
+
+ this._dispatch(requestActions.notify(
+ {
+ type : 'error',
+ text : 'WebSocket disconnected'
+ }));
+
+ // Leave Room.
+ try { this._room.remoteClose({ cause: 'protoo disconnected' }); }
+ catch (error) {}
+
+ this._dispatch(stateActions.setRoomState('connecting'));
+ });
+
+ this._protoo.on('close', () =>
+ {
+ if (this._closed)
+ return;
+
+ logger.warn('protoo Peer "close" event');
+
+ this.close();
+ });
+
+ this._protoo.on('request', (request, accept, reject) =>
+ {
+ logger.debug(
+ '_handleProtooRequest() [method:%s, data:%o]',
+ request.method, request.data);
+
+ switch (request.method)
+ {
+ case 'mediasoup-notification':
+ {
+ accept();
+
+ const notification = request.data;
+
+ this._room.receiveNotification(notification);
+
+ break;
+ }
+
+ case 'active-speaker':
+ {
+ accept();
+
+ const { peerName } = request.data;
+
+ this._dispatch(
+ stateActions.setRoomActiveSpeaker(peerName));
+
+ break;
+ }
+
+ case 'display-name-changed':
+ {
+ accept();
+
+ // eslint-disable-next-line no-shadow
+ const { peerName, displayName, oldDisplayName } = request.data;
+
+ // NOTE: Hack, we shouldn't do this, but this is just a demo.
+ const peer = this._room.getPeerByName(peerName);
+
+ if (!peer)
+ {
+ logger.error('peer not found');
+
+ break;
+ }
+
+ peer.appData.displayName = displayName;
+
+ this._dispatch(
+ stateActions.setPeerDisplayName(displayName, peerName));
+
+ this._dispatch(requestActions.notify(
+ {
+ text : `${oldDisplayName} is now ${displayName}`
+ }));
+
+ break;
+ }
+
+ default:
+ {
+ logger.error('unknown protoo method "%s"', request.method);
+
+ reject(404, 'unknown method');
+ }
+ }
+ });
+ }
+
+ _joinRoom({ displayName, device })
+ {
+ logger.debug('_joinRoom()');
+
+ // NOTE: We allow rejoining (room.join()) the same mediasoup Room when Protoo
+ // WebSocket re-connects, so we must clean existing event listeners. Otherwise
+ // they will be called twice after the reconnection.
+ this._room.removeAllListeners();
+
+ this._room.on('close', (originator, appData) =>
+ {
+ if (originator === 'remote')
+ {
+ logger.warn('mediasoup Peer/Room remotely closed [appData:%o]', appData);
+
+ this._dispatch(stateActions.setRoomState('closed'));
+
+ return;
+ }
+ });
+
+ this._room.on('request', (request, callback, errback) =>
+ {
+ logger.debug(
+ 'sending mediasoup request [method:%s]:%o', request.method, request);
+
+ this._protoo.send('mediasoup-request', request)
+ .then(callback)
+ .catch(errback);
+ });
+
+ this._room.on('notify', (notification) =>
+ {
+ logger.debug(
+ 'sending mediasoup notification [method:%s]:%o',
+ notification.method, notification);
+
+ this._protoo.send('mediasoup-notification', notification)
+ .catch((error) =>
+ {
+ logger.warn('could not send mediasoup notification:%o', error);
+ });
+ });
+
+ this._room.on('newpeer', (peer) =>
+ {
+ logger.debug(
+ 'room "newpeer" event [name:"%s", peer:%o]', peer.name, peer);
+
+ this._handlePeer(peer);
+ });
+
+ this._room.join(this._peerName, { displayName, device })
+ .then(() =>
+ {
+ // Create Transport for sending.
+ this._sendTransport =
+ this._room.createTransport('send', { media: 'SEND_MIC_WEBCAM' });
+
+ this._sendTransport.on('close', (originator) =>
+ {
+ logger.debug(
+ 'Transport "close" event [originator:%s]', originator);
+ });
+
+ // Create Transport for receiving.
+ this._recvTransport =
+ this._room.createTransport('recv', { media: 'RECV' });
+
+ this._recvTransport.on('close', (originator) =>
+ {
+ logger.debug(
+ 'receiving Transport "close" event [originator:%s]', originator);
+ });
+ })
+ .then(() =>
+ {
+ // Set our media capabilities.
+ this._dispatch(stateActions.setMediaCapabilities(
+ {
+ canSendMic : this._room.canSend('audio'),
+ canSendWebcam : this._room.canSend('video')
+ }));
+ })
+ .then(() =>
+ {
+ // Don't produce if explicitely requested to not to do it.
+ if (!this._produce)
+ return;
+
+ // NOTE: Don't depend on this Promise to continue (so we don't do return).
+ Promise.resolve()
+ // Add our mic.
+ .then(() =>
+ {
+ if (!this._room.canSend('audio'))
+ return;
+
+ this._setMicProducer()
+ .catch(() => {});
+ })
+ // Add our webcam (unless the cookie says no).
+ .then(() =>
+ {
+ if (!this._room.canSend('video'))
+ return;
+
+ const devicesCookie = cookiesManager.getDevices();
+
+ if (!devicesCookie || devicesCookie.webcamEnabled)
+ this.enableWebcam();
+ });
+ })
+ .then(() =>
+ {
+ this._dispatch(stateActions.setRoomState('connected'));
+
+ // Clean all the existing notifcations.
+ this._dispatch(stateActions.removeAllNotifications());
+
+ this._dispatch(requestActions.notify(
+ {
+ text : 'You are in the room',
+ timeout : 5000
+ }));
+
+ const peers = this._room.peers;
+
+ for (const peer of peers)
+ {
+ this._handlePeer(peer, { notify: false });
+ }
+ })
+ .catch((error) =>
+ {
+ logger.error('_joinRoom() failed:%o', error);
+
+ this._dispatch(requestActions.notify(
+ {
+ type : 'error',
+ text : `Could not join the room: ${error.toString()}`
+ }));
+
+ this.close();
+ });
+ }
+
+ _setMicProducer()
+ {
+ if (!this._room.canSend('audio'))
+ {
+ return Promise.reject(
+ new Error('cannot send audio'));
+ }
+
+ if (this._micProducer)
+ {
+ return Promise.reject(
+ new Error('mic Producer already exists'));
+ }
+
+ let producer;
+
+ return Promise.resolve()
+ .then(() =>
+ {
+ logger.debug('_setMicProducer() | calling getUserMedia()');
+
+ return navigator.mediaDevices.getUserMedia({ audio: true });
+ })
+ .then((stream) =>
+ {
+ const track = stream.getAudioTracks()[0];
+
+ producer = this._room.createProducer(track, null, { source: 'mic' });
+
+ // No need to keep original track.
+ track.stop();
+
+ // Send it.
+ return producer.send(this._sendTransport);
+ })
+ .then(() =>
+ {
+ this._micProducer = producer;
+
+ this._dispatch(stateActions.addProducer(
+ {
+ id : producer.id,
+ source : 'mic',
+ locallyPaused : producer.locallyPaused,
+ remotelyPaused : producer.remotelyPaused,
+ track : producer.track,
+ codec : producer.rtpParameters.codecs[0].name
+ }));
+
+ producer.on('close', (originator) =>
+ {
+ logger.debug(
+ 'mic Producer "close" event [originator:%s]', originator);
+
+ this._micProducer = null;
+ this._dispatch(stateActions.removeProducer(producer.id));
+ });
+
+ producer.on('pause', (originator) =>
+ {
+ logger.debug(
+ 'mic Producer "pause" event [originator:%s]', originator);
+
+ this._dispatch(stateActions.setProducerPaused(producer.id, originator));
+ });
+
+ producer.on('resume', (originator) =>
+ {
+ logger.debug(
+ 'mic Producer "resume" event [originator:%s]', originator);
+
+ this._dispatch(stateActions.setProducerResumed(producer.id, originator));
+ });
+
+ producer.on('handled', () =>
+ {
+ logger.debug('mic Producer "handled" event');
+ });
+
+ producer.on('unhandled', () =>
+ {
+ logger.debug('mic Producer "unhandled" event');
+ });
+ })
+ .then(() =>
+ {
+ logger.debug('_setMicProducer() succeeded');
+ })
+ .catch((error) =>
+ {
+ logger.error('_setMicProducer() failed:%o', error);
+
+ this._dispatch(requestActions.notify(
+ {
+ text : `Mic producer failed: ${error.name}:${error.message}`
+ }));
+
+ if (producer)
+ producer.close();
+
+ throw error;
+ });
+ }
+
+ _setWebcamProducer()
+ {
+ if (!this._room.canSend('video'))
+ {
+ return Promise.reject(
+ new Error('cannot send video'));
+ }
+
+ if (this._webcamProducer)
+ {
+ return Promise.reject(
+ new Error('webcam Producer already exists'));
+ }
+
+ let producer;
+
+ return Promise.resolve()
+ .then(() =>
+ {
+ const { device, resolution } = this._webcam;
+
+ if (!device)
+ throw new Error('no webcam devices');
+
+ logger.debug('_setWebcamProducer() | calling getUserMedia()');
+
+ return navigator.mediaDevices.getUserMedia(
+ {
+ video :
+ {
+ deviceId : { exact: device.deviceId },
+ ...VIDEO_CONSTRAINS[resolution]
+ }
+ });
+ })
+ .then((stream) =>
+ {
+ const track = stream.getVideoTracks()[0];
+
+ producer = this._room.createProducer(
+ track, { simulcast: this._useSimulcast }, { source: 'webcam' });
+
+ // No need to keep original track.
+ track.stop();
+
+ // Send it.
+ return producer.send(this._sendTransport);
+ })
+ .then(() =>
+ {
+ this._webcamProducer = producer;
+
+ const { device } = this._webcam;
+
+ this._dispatch(stateActions.addProducer(
+ {
+ id : producer.id,
+ source : 'webcam',
+ deviceLabel : device.label,
+ type : this._getWebcamType(device),
+ locallyPaused : producer.locallyPaused,
+ remotelyPaused : producer.remotelyPaused,
+ track : producer.track,
+ codec : producer.rtpParameters.codecs[0].name
+ }));
+
+ producer.on('close', (originator) =>
+ {
+ logger.debug(
+ 'webcam Producer "close" event [originator:%s]', originator);
+
+ this._webcamProducer = null;
+ this._dispatch(stateActions.removeProducer(producer.id));
+ });
+
+ producer.on('pause', (originator) =>
+ {
+ logger.debug(
+ 'webcam Producer "pause" event [originator:%s]', originator);
+
+ this._dispatch(stateActions.setProducerPaused(producer.id, originator));
+ });
+
+ producer.on('resume', (originator) =>
+ {
+ logger.debug(
+ 'webcam Producer "resume" event [originator:%s]', originator);
+
+ this._dispatch(stateActions.setProducerResumed(producer.id, originator));
+ });
+
+ producer.on('handled', () =>
+ {
+ logger.debug('webcam Producer "handled" event');
+ });
+
+ producer.on('unhandled', () =>
+ {
+ logger.debug('webcam Producer "unhandled" event');
+ });
+ })
+ .then(() =>
+ {
+ logger.debug('_setWebcamProducer() succeeded');
+ })
+ .catch((error) =>
+ {
+ logger.error('_setWebcamProducer() failed:%o', error);
+
+ this._dispatch(requestActions.notify(
+ {
+ text : `Webcam producer failed: ${error.name}:${error.message}`
+ }));
+
+ if (producer)
+ producer.close();
+
+ throw error;
+ });
+ }
+
+ _updateWebcams()
+ {
+ logger.debug('_updateWebcams()');
+
+ // Reset the list.
+ this._webcams = new Map();
+
+ return Promise.resolve()
+ .then(() =>
+ {
+ logger.debug('_updateWebcams() | calling enumerateDevices()');
+
+ return navigator.mediaDevices.enumerateDevices();
+ })
+ .then((devices) =>
+ {
+ for (const device of devices)
+ {
+ if (device.kind !== 'videoinput')
+ continue;
+
+ this._webcams.set(device.deviceId, device);
+ }
+ })
+ .then(() =>
+ {
+ const array = Array.from(this._webcams.values());
+ const len = array.length;
+ const currentWebcamId =
+ this._webcam.device ? this._webcam.device.deviceId : undefined;
+
+ logger.debug('_updateWebcams() [webcams:%o]', array);
+
+ if (len === 0)
+ this._webcam.device = null;
+ else if (!this._webcams.has(currentWebcamId))
+ this._webcam.device = array[0];
+
+ this._dispatch(
+ stateActions.setCanChangeWebcam(this._webcams.size >= 2));
+ });
+ }
+
+ _getWebcamType(device)
+ {
+ if (/(back|rear)/i.test(device.label))
+ {
+ logger.debug('_getWebcamType() | it seems to be a back camera');
+
+ return 'back';
+ }
+ else
+ {
+ logger.debug('_getWebcamType() | it seems to be a front camera');
+
+ return 'front';
+ }
+ }
+
+ _handlePeer(peer, { notify = true } = {})
+ {
+ const displayName = peer.appData.displayName;
+
+ this._dispatch(stateActions.addPeer(
+ {
+ name : peer.name,
+ displayName : displayName,
+ device : peer.appData.device,
+ consumers : []
+ }));
+
+ if (notify)
+ {
+ this._dispatch(requestActions.notify(
+ {
+ text : `${displayName} joined the room`
+ }));
+ }
+
+ for (const consumer of peer.consumers)
+ {
+ this._handleConsumer(consumer);
+ }
+
+ peer.on('close', (originator) =>
+ {
+ logger.debug(
+ 'peer "close" event [name:"%s", originator:%s]',
+ peer.name, originator);
+
+ this._dispatch(stateActions.removePeer(peer.name));
+
+ if (this._room.joined)
+ {
+ this._dispatch(requestActions.notify(
+ {
+ text : `${peer.appData.displayName} left the room`
+ }));
+ }
+ });
+
+ peer.on('newconsumer', (consumer) =>
+ {
+ logger.debug(
+ 'peer "newconsumer" event [name:"%s", id:%s, consumer:%o]',
+ peer.name, consumer.id, consumer);
+
+ this._handleConsumer(consumer);
+ });
+ }
+
+ _handleConsumer(consumer)
+ {
+ const codec = consumer.rtpParameters.codecs[0];
+
+ this._dispatch(stateActions.addConsumer(
+ {
+ id : consumer.id,
+ peerName : consumer.peer.name,
+ source : consumer.appData.source,
+ supported : consumer.supported,
+ locallyPaused : consumer.locallyPaused,
+ remotelyPaused : consumer.remotelyPaused,
+ track : null,
+ codec : codec ? codec.name : null
+ },
+ consumer.peer.name));
+
+ consumer.on('close', (originator) =>
+ {
+ logger.debug(
+ 'consumer "close" event [id:%s, originator:%s, consumer:%o]',
+ consumer.id, originator, consumer);
+
+ this._dispatch(stateActions.removeConsumer(
+ consumer.id, consumer.peer.name));
+ });
+
+ consumer.on('pause', (originator) =>
+ {
+ logger.debug(
+ 'consumer "pause" event [id:%s, originator:%s, consumer:%o]',
+ consumer.id, originator, consumer);
+
+ this._dispatch(stateActions.setConsumerPaused(consumer.id, originator));
+ });
+
+ consumer.on('resume', (originator) =>
+ {
+ logger.debug(
+ 'consumer "resume" event [id:%s, originator:%s, consumer:%o]',
+ consumer.id, originator, consumer);
+
+ this._dispatch(stateActions.setConsumerResumed(consumer.id, originator));
+ });
+
+ consumer.on('effectiveprofilechange', (profile) =>
+ {
+ logger.debug(
+ 'consumer "effectiveprofilechange" event [id:%s, consumer:%o, profile:%s]',
+ consumer.id, consumer, profile);
+
+ this._dispatch(stateActions.setConsumerEffectiveProfile(consumer.id, profile));
+ });
+
+ // Receive the consumer (if we can).
+ if (consumer.supported)
+ {
+ // Pause it if video and we are in audio-only mode.
+ if (consumer.kind === 'video' && this._getState().me.audioOnly)
+ consumer.pause('audio-only-mode');
+
+ consumer.receive(this._recvTransport)
+ .then((track) =>
+ {
+ this._dispatch(stateActions.setConsumerTrack(consumer.id, track));
+ })
+ .catch((error) =>
+ {
+ logger.error(
+ 'unexpected error while receiving a new Consumer:%o', error);
+ });
+ }
+ }
+}
diff --git a/app/lib/components/App.jsx b/app/lib/components/App.jsx
deleted file mode 100644
index 000fee1..0000000
--- a/app/lib/components/App.jsx
+++ /dev/null
@@ -1,57 +0,0 @@
-'use strict';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
-import Logger from '../Logger';
-import muiTheme from './muiTheme';
-import Notifier from './Notifier';
-import Room from './Room';
-
-const logger = new Logger('App'); // eslint-disable-line no-unused-vars
-
-export default class App extends React.Component
-{
- constructor()
- {
- super();
-
- this.state = {};
- }
-
- render()
- {
- let props = this.props;
-
- return (
-
-
-
-
-
-
-
- );
- }
-
- handleNotify(data)
- {
- this.refs.Notifier.notify(data);
- }
-
- handleHideNotification(uid)
- {
- this.refs.Notifier.hideNotification(uid);
- }
-}
-
-App.propTypes =
-{
- peerId : PropTypes.string.isRequired,
- roomId : PropTypes.string.isRequired
-};
diff --git a/app/lib/components/EditableInput.jsx b/app/lib/components/EditableInput.jsx
new file mode 100644
index 0000000..addf1f4
--- /dev/null
+++ b/app/lib/components/EditableInput.jsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { RIEInput } from 'riek';
+
+export default class EditableInput extends React.Component
+{
+ render()
+ {
+ const {
+ value,
+ propName,
+ className,
+ classLoading,
+ classInvalid,
+ editProps,
+ onChange
+ } = this.props;
+
+ return (
+ onChange(data)}
+ />
+ );
+ }
+
+ shouldComponentUpdate(nextProps)
+ {
+ if (nextProps.value === this.props.value)
+ return false;
+
+ return true;
+ }
+}
+
+EditableInput.propTypes =
+{
+ value : PropTypes.string,
+ propName : PropTypes.string.isRequired,
+ className : PropTypes.string,
+ classLoading : PropTypes.string,
+ classInvalid : PropTypes.string,
+ editProps : PropTypes.any,
+ onChange : PropTypes.func.isRequired
+};
diff --git a/app/lib/components/LocalVideo.jsx b/app/lib/components/LocalVideo.jsx
deleted file mode 100644
index 04d8f58..0000000
--- a/app/lib/components/LocalVideo.jsx
+++ /dev/null
@@ -1,156 +0,0 @@
-'use strict';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import IconButton from 'material-ui/IconButton/IconButton';
-import MicOffIcon from 'material-ui/svg-icons/av/mic-off';
-import VideoCamOffIcon from 'material-ui/svg-icons/av/videocam-off';
-import ChangeVideoCamIcon from 'material-ui/svg-icons/av/repeat';
-import classnames from 'classnames';
-import Video from './Video';
-import Logger from '../Logger';
-
-const logger = new Logger('LocalVideo'); // eslint-disable-line no-unused-vars
-
-export default class LocalVideo extends React.Component
-{
- constructor(props)
- {
- super(props);
-
- this.state =
- {
- micMuted : false,
- webcam : props.stream && !!props.stream.getVideoTracks()[0],
- togglingWebcam : false
- };
- }
-
- render()
- {
- let props = this.props;
- let state = this.state;
-
- return (
-
- {props.stream ?
-
- :null}
-
-
-
-
-
-
-
-
-
-
- {props.multipleWebcams ?
-
-
-
- :null}
-
-
-
-
- );
- }
-
- componentWillReceiveProps(nextProps)
- {
- this.setState({ webcam: nextProps.stream && !!nextProps.stream.getVideoTracks()[0] });
- }
-
- handleClickMuteMic()
- {
- logger.debug('handleClickMuteMic()');
-
- let value = !this.state.micMuted;
-
- this.props.onMicMute(value)
- .then(() =>
- {
- this.setState({ micMuted: value });
- });
- }
-
- handleClickWebcam()
- {
- logger.debug('handleClickWebcam()');
-
- let value = !this.state.webcam;
-
- this.setState({ togglingWebcam: true });
-
- this.props.onWebcamToggle(value)
- .then(() =>
- {
- this.setState({ webcam: value, togglingWebcam: false });
- })
- .catch(() =>
- {
- this.setState({ togglingWebcam: false });
- });
- }
-
- handleClickChangeWebcam()
- {
- logger.debug('handleClickChangeWebcam()');
-
- this.props.onWebcamChange();
- }
-
- handleResolutionChange()
- {
- logger.debug('handleResolutionChange()');
-
- this.props.onResolutionChange();
- }
-}
-
-LocalVideo.propTypes =
-{
- peerId : PropTypes.string.isRequired,
- stream : PropTypes.object,
- resolution : PropTypes.string,
- multipleWebcams : PropTypes.bool.isRequired,
- webcamType : PropTypes.string,
- connectionState : PropTypes.string,
- isActiveSpeaker : PropTypes.bool.isRequired,
- onMicMute : PropTypes.func.isRequired,
- onWebcamToggle : PropTypes.func.isRequired,
- onWebcamChange : PropTypes.func.isRequired,
- onResolutionChange : PropTypes.func.isRequired
-};
diff --git a/app/lib/components/Me.jsx b/app/lib/components/Me.jsx
new file mode 100644
index 0000000..36251c8
--- /dev/null
+++ b/app/lib/components/Me.jsx
@@ -0,0 +1,222 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import ReactTooltip from 'react-tooltip';
+import PropTypes from 'prop-types';
+import classnames from 'classnames';
+import { getDeviceInfo } from 'mediasoup-client';
+import * as appPropTypes from './appPropTypes';
+import * as requestActions from '../redux/requestActions';
+import PeerView from './PeerView';
+
+class Me extends React.Component
+{
+ constructor(props)
+ {
+ super(props);
+
+ this._mounted = false;
+ this._rootNode = null;
+ this._tooltip = true;
+
+ // TODO: Issue when using react-tooltip in Edge:
+ // https://github.com/wwayne/react-tooltip/issues/328
+ if (getDeviceInfo().flag === 'msedge')
+ this._tooltip = false;
+ }
+
+ render()
+ {
+ const {
+ connected,
+ me,
+ micProducer,
+ webcamProducer,
+ onChangeDisplayName,
+ onMuteMic,
+ onUnmuteMic,
+ onEnableWebcam,
+ onDisableWebcam,
+ onChangeWebcam
+ } = this.props;
+
+ let micState;
+
+ if (!me.canSendMic)
+ micState = 'unsupported';
+ else if (!micProducer)
+ micState = 'unsupported';
+ else if (!micProducer.locallyPaused && !micProducer.remotelyPaused)
+ micState = 'on';
+ else
+ micState = 'off';
+
+ let webcamState;
+
+ if (!me.canSendWebcam)
+ webcamState = 'unsupported';
+ else if (webcamProducer)
+ webcamState = 'on';
+ else
+ webcamState = 'off';
+
+ let changeWebcamState;
+
+ if (Boolean(webcamProducer) && me.canChangeWebcam)
+ changeWebcamState = 'on';
+ else
+ changeWebcamState = 'unsupported';
+
+ const videoVisible = (
+ Boolean(webcamProducer) &&
+ !webcamProducer.locallyPaused &&
+ !webcamProducer.remotelyPaused
+ );
+
+ let tip;
+
+ if (!me.displayNameSet)
+ tip = 'Click on your name to change it';
+
+ return (
+ (this._rootNode = node)}
+ data-tip={tip}
+ data-tip-disable={!tip}
+ data-type='dark'
+ >
+ {connected ?
+
+
+ {
+ micState === 'on' ? onMuteMic() : onUnmuteMic();
+ }}
+ />
+
+
+ {
+ webcamState === 'on' ? onDisableWebcam() : onEnableWebcam();
+ }}
+ />
+
+
onChangeWebcam()}
+ />
+
+ :null
+ }
+
+
onChangeDisplayName(displayName)}
+ />
+
+ {this._tooltip ?
+
+ :null
+ }
+
+ );
+ }
+
+ componentDidMount()
+ {
+ this._mounted = true;
+
+ if (this._tooltip)
+ {
+ setTimeout(() =>
+ {
+ if (!this._mounted || this.props.me.displayNameSet)
+ return;
+
+ ReactTooltip.show(this._rootNode);
+ }, 4000);
+ }
+ }
+
+ componentWillUnmount()
+ {
+ this._mounted = false;
+ }
+
+ componentWillReceiveProps(nextProps)
+ {
+ if (this._tooltip)
+ {
+ if (nextProps.me.displayNameSet)
+ ReactTooltip.hide(this._rootNode);
+ }
+ }
+}
+
+Me.propTypes =
+{
+ connected : PropTypes.bool.isRequired,
+ me : appPropTypes.Me.isRequired,
+ micProducer : appPropTypes.Producer,
+ webcamProducer : appPropTypes.Producer,
+ onChangeDisplayName : PropTypes.func.isRequired,
+ onMuteMic : PropTypes.func.isRequired,
+ onUnmuteMic : PropTypes.func.isRequired,
+ onEnableWebcam : PropTypes.func.isRequired,
+ onDisableWebcam : PropTypes.func.isRequired,
+ onChangeWebcam : PropTypes.func.isRequired
+};
+
+const mapStateToProps = (state) =>
+{
+ const producersArray = Object.values(state.producers);
+ const micProducer =
+ producersArray.find((producer) => producer.source === 'mic');
+ const webcamProducer =
+ producersArray.find((producer) => producer.source === 'webcam');
+
+ return {
+ connected : state.room.state === 'connected',
+ me : state.me,
+ micProducer : micProducer,
+ webcamProducer : webcamProducer
+ };
+};
+
+const mapDispatchToProps = (dispatch) =>
+{
+ return {
+ onChangeDisplayName : (displayName) =>
+ {
+ dispatch(requestActions.changeDisplayName(displayName));
+ },
+ onMuteMic : () => dispatch(requestActions.muteMic()),
+ onUnmuteMic : () => dispatch(requestActions.unmuteMic()),
+ onEnableWebcam : () => dispatch(requestActions.enableWebcam()),
+ onDisableWebcam : () => dispatch(requestActions.disableWebcam()),
+ onChangeWebcam : () => dispatch(requestActions.changeWebcam())
+ };
+};
+
+const MeContainer = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(Me);
+
+export default MeContainer;
diff --git a/app/lib/components/Notifications.jsx b/app/lib/components/Notifications.jsx
new file mode 100644
index 0000000..d850155
--- /dev/null
+++ b/app/lib/components/Notifications.jsx
@@ -0,0 +1,61 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import classnames from 'classnames';
+import PropTypes from 'prop-types';
+import * as appPropTypes from './appPropTypes';
+import * as stateActions from '../redux/stateActions';
+import { Appear } from './transitions';
+
+const Notifications = ({ notifications, onClick }) =>
+{
+ return (
+
+ {
+ notifications.map((notification) =>
+ {
+ return (
+
+ onClick(notification.id)}
+ >
+
+
{notification.text}
+
+
+ );
+ })
+ }
+
+ );
+};
+
+Notifications.propTypes =
+{
+ notifications : PropTypes.arrayOf(appPropTypes.Notification).isRequired,
+ onClick : PropTypes.func.isRequired
+};
+
+const mapStateToProps = (state) =>
+{
+ const { notifications } = state;
+
+ return { notifications };
+};
+
+const mapDispatchToProps = (dispatch) =>
+{
+ return {
+ onClick : (notificationId) =>
+ {
+ dispatch(stateActions.removeNotification(notificationId));
+ }
+ };
+};
+
+const NotificationsContainer = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(Notifications);
+
+export default NotificationsContainer;
diff --git a/app/lib/components/Notifier.jsx b/app/lib/components/Notifier.jsx
deleted file mode 100644
index 8f4cbaf..0000000
--- a/app/lib/components/Notifier.jsx
+++ /dev/null
@@ -1,151 +0,0 @@
-'use strict';
-
-import React from 'react';
-import NotificationSystem from 'react-notification-system';
-
-const STYLE =
-{
- NotificationItem :
- {
- DefaultStyle :
- {
- padding : '6px 10px',
- backgroundColor : 'rgba(255,255,255, 0.9)',
- fontFamily : 'Roboto',
- fontWeight : 400,
- fontSize : '1rem',
- cursor : 'default',
- WebkitUserSelect : 'none',
- MozUserSelect : 'none',
- userSelect : 'none',
- transition : '0.15s ease-in-out'
- },
- info :
- {
- color : '#000',
- borderTop : '2px solid rgba(255,0,78, 0.75)'
- },
- success :
- {
- color : '#000',
- borderTop : '4px solid rgba(73,206,62, 0.75)'
- },
- error :
- {
- color : '#000',
- borderTop : '4px solid #ff0014'
- }
- },
- Title :
- {
- DefaultStyle :
- {
- margin : '0 0 8px 0',
- fontFamily : 'Roboto',
- fontWeight : 500,
- fontSize : '1.1rem',
- userSelect : 'none',
- WebkitUserSelect : 'none',
- MozUserSelect : 'none'
- },
- info :
- {
- color : 'rgba(255,0,78, 0.85)'
- },
- success :
- {
- color : 'rgba(73,206,62, 0.9)'
- },
- error :
- {
- color : '#ff0014'
- }
- },
- Dismiss :
- {
- DefaultStyle :
- {
- display : 'none'
- }
- },
- Action :
- {
- DefaultStyle :
- {
- padding : '8px 24px',
- fontSize : '1.2rem',
- cursor : 'pointer',
- userSelect : 'none',
- WebkitUserSelect : 'none',
- MozUserSelect : 'none'
- },
- info :
- {
- backgroundColor : 'rgba(255,0,78, 1)'
- },
- success :
- {
- backgroundColor : 'rgba(73,206,62, 0.75)'
- }
- }
-};
-
-export default class Notifier extends React.Component
-{
- constructor(props)
- {
- super(props);
- }
-
- render()
- {
- return (
-
- );
- }
-
- notify(data)
- {
- let data2;
-
- switch (data.level)
- {
- case 'info' :
- data2 = Object.assign(
- {
- position : 'tr',
- dismissible : true,
- autoDismiss : 1
- }, data);
- break;
-
- case 'success' :
- data2 = Object.assign(
- {
- position : 'tr',
- dismissible : true,
- autoDismiss : 1
- }, data);
- break;
-
- case 'error' :
- data2 = Object.assign(
- {
- position : 'tr',
- dismissible : true,
- autoDismiss : 3
- }, data);
- break;
-
- default:
- throw new Error(`unknown level "${data.level}"`);
- }
-
- this.refs.NotificationSystem.addNotification(data2);
- }
-
- hideNotification(uid)
- {
- this.refs.NotificationSystem.removeNotification(uid);
- }
-}
diff --git a/app/lib/components/Peer.jsx b/app/lib/components/Peer.jsx
new file mode 100644
index 0000000..61ed633
--- /dev/null
+++ b/app/lib/components/Peer.jsx
@@ -0,0 +1,90 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import * as appPropTypes from './appPropTypes';
+import PeerView from './PeerView';
+
+const Peer = (props) =>
+{
+ const {
+ peer,
+ micConsumer,
+ webcamConsumer
+ } = props;
+
+ const micEnabled = (
+ Boolean(micConsumer) &&
+ !micConsumer.locallyPaused &&
+ !micConsumer.remotelyPaused
+ );
+
+ const videoVisible = (
+ Boolean(webcamConsumer) &&
+ !webcamConsumer.locallyPaused &&
+ !webcamConsumer.remotelyPaused
+ );
+
+ let videoProfile;
+
+ if (webcamConsumer)
+ videoProfile = webcamConsumer.profile;
+
+ return (
+
+
+ {!micEnabled ?
+
+ :null
+ }
+ {!videoVisible ?
+
+ :null
+ }
+
+
+ {videoVisible && !webcamConsumer.supported ?
+
+ :null
+ }
+
+
+
+ );
+};
+
+Peer.propTypes =
+{
+ peer : appPropTypes.Peer.isRequired,
+ micConsumer : appPropTypes.Consumer,
+ webcamConsumer : appPropTypes.Consumer
+};
+
+const mapStateToProps = (state, { name }) =>
+{
+ const peer = state.peers[name];
+ const consumersArray = peer.consumers
+ .map((consumerId) => state.consumers[consumerId]);
+ const micConsumer =
+ consumersArray.find((consumer) => consumer.source === 'mic');
+ const webcamConsumer =
+ consumersArray.find((consumer) => consumer.source === 'webcam');
+
+ return {
+ peer,
+ micConsumer,
+ webcamConsumer
+ };
+};
+
+const PeerContainer = connect(mapStateToProps)(Peer);
+
+export default PeerContainer;
diff --git a/app/lib/components/PeerView.jsx b/app/lib/components/PeerView.jsx
new file mode 100644
index 0000000..840badd
--- /dev/null
+++ b/app/lib/components/PeerView.jsx
@@ -0,0 +1,260 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import classnames from 'classnames';
+import Spinner from 'react-spinner';
+import hark from 'hark';
+import * as appPropTypes from './appPropTypes';
+import EditableInput from './EditableInput';
+
+export default class PeerView extends React.Component
+{
+ constructor(props)
+ {
+ super(props);
+
+ this.state =
+ {
+ volume : 0, // Integer from 0 to 10.,
+ videoWidth : null,
+ videoHeight : null
+ };
+
+ // Latest received video track.
+ // @type {MediaStreamTrack}
+ this._audioTrack = null;
+
+ // Latest received video track.
+ // @type {MediaStreamTrack}
+ this._videoTrack = null;
+
+ // Hark instance.
+ // @type {Object}
+ this._hark = null;
+
+ // Periodic timer for showing video resolution.
+ this._videoResolutionTimer = null;
+ }
+
+ render()
+ {
+ const {
+ isMe,
+ peer,
+ videoVisible,
+ videoProfile,
+ audioCodec,
+ videoCodec,
+ onChangeDisplayName
+ } = this.props;
+
+ const {
+ volume,
+ videoWidth,
+ videoHeight
+ } = this.state;
+
+ return (
+
+
+
+
+ {audioCodec ?
+
{audioCodec}
+ :null
+ }
+
+ {videoCodec ?
+
{videoCodec} {videoProfile}
+ :null
+ }
+
+ {(videoVisible && videoWidth !== null) ?
+
{videoWidth}x{videoHeight}
+ :null
+ }
+
+
+
+
+ {isMe ?
+
onChangeDisplayName(displayName)}
+ />
+ :
+
+ {peer.displayName}
+
+ }
+
+
+
+
+ {peer.device.name} {Math.floor(peer.device.version) || null}
+
+
+
+
+
+
+
+
+
+ {videoProfile === 'none' ?
+
+
+
+ :null
+ }
+
+ );
+ }
+
+ componentDidMount()
+ {
+ const { audioTrack, videoTrack } = this.props;
+
+ this._setTracks(audioTrack, videoTrack);
+ }
+
+ componentWillUnmount()
+ {
+ if (this._hark)
+ this._hark.stop();
+
+ clearInterval(this._videoResolutionTimer);
+ }
+
+ componentWillReceiveProps(nextProps)
+ {
+ const { audioTrack, videoTrack } = nextProps;
+
+ this._setTracks(audioTrack, videoTrack);
+ }
+
+ _setTracks(audioTrack, videoTrack)
+ {
+ if (this._audioTrack === audioTrack && this._videoTrack === videoTrack)
+ return;
+
+ this._audioTrack = audioTrack;
+ this._videoTrack = videoTrack;
+
+ if (this._hark)
+ this._hark.stop();
+
+ clearInterval(this._videoResolutionTimer);
+ this._hideVideoResolution();
+
+ const { video } = this.refs;
+
+ if (audioTrack || videoTrack)
+ {
+ const stream = new MediaStream;
+
+ if (audioTrack)
+ stream.addTrack(audioTrack);
+
+ if (videoTrack)
+ stream.addTrack(videoTrack);
+
+ video.srcObject = stream;
+
+ if (audioTrack)
+ this._runHark(stream);
+
+ if (videoTrack)
+ this._showVideoResolution();
+ }
+ else
+ {
+ video.srcObject = null;
+ }
+ }
+
+ _runHark(stream)
+ {
+ if (!stream.getAudioTracks()[0])
+ throw new Error('_runHark() | given stream has no audio track');
+
+ this._hark = hark(stream, { play: false });
+
+ // eslint-disable-next-line no-unused-vars
+ this._hark.on('volume_change', (dBs, threshold) =>
+ {
+ // The exact formula to convert from dBs (-100..0) to linear (0..1) is:
+ // Math.pow(10, dBs / 20)
+ // However it does not produce a visually useful output, so let exagerate
+ // it a bit. Also, let convert it from 0..1 to 0..10 and avoid value 1 to
+ // minimize component renderings.
+ let volume = Math.round(Math.pow(10, dBs / 85) * 10);
+
+ if (volume === 1)
+ volume = 0;
+
+ if (volume !== this.state.volume)
+ this.setState({ volume: volume });
+ });
+ }
+
+ _showVideoResolution()
+ {
+ this._videoResolutionTimer = setInterval(() =>
+ {
+ const { videoWidth, videoHeight } = this.state;
+ const { video } = this.refs;
+
+ // Don't re-render if nothing changed.
+ if (video.videoWidth === videoWidth && video.videoHeight === videoHeight)
+ return;
+
+ this.setState(
+ {
+ videoWidth : video.videoWidth,
+ videoHeight : video.videoHeight
+ });
+ }, 1000);
+ }
+
+ _hideVideoResolution()
+ {
+ this.setState({ videoWidth: null, videoHeight: null });
+ }
+}
+
+PeerView.propTypes =
+{
+ isMe : PropTypes.bool,
+ peer : PropTypes.oneOfType(
+ [ appPropTypes.Me, appPropTypes.Peer ]).isRequired,
+ audioTrack : PropTypes.any,
+ videoTrack : PropTypes.any,
+ videoVisible : PropTypes.bool.isRequired,
+ videoProfile : PropTypes.string,
+ audioCodec : PropTypes.string,
+ videoCodec : PropTypes.string,
+ onChangeDisplayName : PropTypes.func
+};
diff --git a/app/lib/components/Peers.jsx b/app/lib/components/Peers.jsx
new file mode 100644
index 0000000..789454e
--- /dev/null
+++ b/app/lib/components/Peers.jsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+import classnames from 'classnames';
+import * as appPropTypes from './appPropTypes';
+import { Appear } from './transitions';
+import Peer from './Peer';
+
+const Peers = ({ peers, activeSpeakerName }) =>
+{
+ return (
+
+ {
+ peers.map((peer) =>
+ {
+ return (
+
+
+
+ );
+ })
+ }
+
+ );
+};
+
+Peers.propTypes =
+{
+ peers : PropTypes.arrayOf(appPropTypes.Peer).isRequired,
+ activeSpeakerName : PropTypes.string
+};
+
+const mapStateToProps = (state) =>
+{
+ // TODO: This is not OK since it's creating a new array every time, so triggering a
+ // component rendering.
+ const peersArray = Object.values(state.peers);
+
+ return {
+ peers : peersArray,
+ activeSpeakerName : state.room.activeSpeakerName
+ };
+};
+
+const PeersContainer = connect(mapStateToProps)(Peers);
+
+export default PeersContainer;
diff --git a/app/lib/components/RemoteVideo.jsx b/app/lib/components/RemoteVideo.jsx
deleted file mode 100644
index 68b2d37..0000000
--- a/app/lib/components/RemoteVideo.jsx
+++ /dev/null
@@ -1,138 +0,0 @@
-'use strict';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import IconButton from 'material-ui/IconButton/IconButton';
-import VolumeOffIcon from 'material-ui/svg-icons/av/volume-off';
-import VideoOffIcon from 'material-ui/svg-icons/av/videocam-off';
-import classnames from 'classnames';
-import Video from './Video';
-import Logger from '../Logger';
-
-const logger = new Logger('RemoteVideo');
-
-export default class RemoteVideo extends React.Component
-{
- constructor(props)
- {
- super(props);
-
- this.state =
- {
- audioMuted : false
- };
-
- let videoTrack = props.stream.getVideoTracks()[0];
-
- if (videoTrack)
- {
- videoTrack.addEventListener('mute', () =>
- {
- logger.debug('video track "mute" event');
- });
-
- videoTrack.addEventListener('unmute', () =>
- {
- logger.debug('video track "unmute" event');
- });
- }
- }
-
- render()
- {
- let props = this.props;
- let state = this.state;
- let videoTrack = props.stream.getVideoTracks()[0];
- let videoEnabled = videoTrack && videoTrack.enabled;
-
- return (
-
-
-
-
-
-
-
-
- {videoTrack ?
-
-
-
- :null}
-
-
-
-
- );
- }
-
- handleClickMuteAudio()
- {
- logger.debug('handleClickMuteAudio()');
-
- let value = !this.state.audioMuted;
-
- this.setState({ audioMuted: value });
- }
-
- handleClickDisableVideo()
- {
- logger.debug('handleClickDisableVideo()');
-
- let videoTrack = this.props.stream.getVideoTracks()[0];
- let videoEnabled = videoTrack && videoTrack.enabled;
- let stream = this.props.stream;
- let msid = stream.jitsiRemoteId || stream.id;
-
- if (videoEnabled)
- {
- this.props.onDisableVideo(msid)
- .then(() =>
- {
- videoTrack.enabled = false;
- this.forceUpdate();
- });
- }
- else
- {
- this.props.onEnableVideo(msid)
- .then(() =>
- {
- videoTrack.enabled = true;
- this.forceUpdate();
- });
- }
- }
-}
-
-RemoteVideo.propTypes =
-{
- peer : PropTypes.object.isRequired,
- stream : PropTypes.object.isRequired,
- fullsize : PropTypes.bool,
- isActiveSpeaker : PropTypes.bool.isRequired,
- onDisableVideo : PropTypes.func.isRequired,
- onEnableVideo : PropTypes.func.isRequired
-};
diff --git a/app/lib/components/Room.jsx b/app/lib/components/Room.jsx
index ca8d9af..37786b5 100644
--- a/app/lib/components/Room.jsx
+++ b/app/lib/components/Room.jsx
@@ -1,531 +1,153 @@
-'use strict';
-
import React from 'react';
+import { connect } from 'react-redux';
+import ReactTooltip from 'react-tooltip';
import PropTypes from 'prop-types';
+import classnames from 'classnames';
import ClipboardButton from 'react-clipboard.js';
-import browser from 'bowser';
-import TransitionAppear from './TransitionAppear';
-import LocalVideo from './LocalVideo';
-import RemoteVideo from './RemoteVideo';
-import Stats from './Stats';
-import Logger from '../Logger';
-import * as utils from '../utils';
-import Client from '../Client';
+import * as appPropTypes from './appPropTypes';
+import * as requestActions from '../redux/requestActions';
+import { Appear } from './transitions';
+import Me from './Me';
+import Peers from './Peers';
+import Notifications from './Notifications';
-const logger = new Logger('Room');
-const STATS_INTERVAL = 1000;
-
-export default class Room extends React.Component
+const Room = (
+ {
+ room,
+ me,
+ amActiveSpeaker,
+ onRoomLinkCopy,
+ onSetAudioMode,
+ onRestartIce
+ }) =>
{
- constructor(props)
- {
- super(props);
+ return (
+
+
+
- this.state =
- {
- peers : {},
- localStream : null,
- localVideoResolution : null, // qvga / vga / hd / fullhd.
- multipleWebcams : false,
- webcamType : null,
- connectionState : null,
- remoteStreams : {},
- showStats : false,
- stats : null,
- activeSpeakerId : null
- };
+
- // Mounted flag
- this._mounted = false;
- // Client instance
- this._client = null;
- // Timer to retrieve RTC stats.
- this._statsTimer = null;
-
- // TODO: TMP
- global.ROOM = this;
- }
-
- render()
- {
- let props = this.props;
- let state = this.state;
- let numPeers = Object.keys(state.remoteStreams).length;
-
- return (
-
-
-
-
-
- {}} // Avoid link action.
- >
- invite people to this room
-
-
-
-
-
- {
- Object.keys(state.remoteStreams).map((msid) =>
+
+
+
{
- let stream = state.remoteStreams[msid];
- let peer;
-
- for (let peerId of Object.keys(state.peers))
+ // If this is a 'Open in new window/tab' don't prevent
+ // click default action.
+ if (
+ event.ctrlKey || event.shiftKey || event.metaKey ||
+ // Middle click (IE > 9 and everyone else).
+ (event.button && event.button === 1)
+ )
{
- peer = state.peers[peerId];
-
- if (peer.msids.indexOf(msid) !== -1)
- break;
+ return;
}
- if (!peer)
- return;
-
- return (
-
-
-
- );
- })
- }
+ event.preventDefault();
+ }}
+ >
+ invitation link
+
-
-
-
-
-
- {state.showStats ?
-
-
-
- :
-
- }
-
-
-
- );
- }
- componentDidMount()
- {
- // Set flag
- this._mounted = true;
-
- // Run the client
- this._runClient();
- }
-
- componentWillUnmount()
- {
- let state = this.state;
-
- // Unset flag
- this._mounted = false;
-
- // Close client
- this._client.removeAllListeners();
- this._client.close();
-
- // Close local MediaStream
- if (state.localStream)
- utils.closeMediaStream(state.localStream);
- }
-
- handleRoomLinkCopied()
- {
- logger.debug('handleRoomLinkCopied()');
-
- this.props.onNotify(
- {
- level : 'success',
- position : 'tr',
- title : 'Room URL copied to the clipboard',
- message : 'Share it with others to join this room'
- });
- }
-
- handleLocalMute(value)
- {
- logger.debug('handleLocalMute() [value:%s]', value);
-
- let micTrack = this.state.localStream.getAudioTracks()[0];
-
- if (!micTrack)
- return Promise.reject(new Error('no audio track'));
-
- micTrack.enabled = !value;
-
- return Promise.resolve();
- }
-
- handleLocalWebcamToggle(value)
- {
- logger.debug('handleLocalWebcamToggle() [value:%s]', value);
-
- return Promise.resolve()
- .then(() =>
- {
- if (value)
- return this._client.addVideo();
- else
- return this._client.removeVideo();
- })
- .then(() =>
- {
- let localStream = this.state.localStream;
-
- this.setState({ localStream });
- });
- }
-
- handleLocalWebcamChange()
- {
- logger.debug('handleLocalWebcamChange()');
-
- this._client.changeWebcam();
- }
-
- handleLocalResolutionChange()
- {
- logger.debug('handleLocalResolutionChange()');
-
- if (!utils.canChangeResolution())
- {
- logger.warn('changing local resolution not implemented for this browser');
-
- return;
- }
-
- this._client.changeVideoResolution();
- }
-
- handleStatsClose()
- {
- logger.debug('handleStatsClose()');
-
- this.setState({ showStats: false });
- this._stopStats();
- }
-
- handleClickShowStats()
- {
- logger.debug('handleClickShowStats()');
-
- this.setState({ showStats: true });
- this._startStats();
- }
-
- handleDisableRemoteVideo(msid)
- {
- logger.debug('handleDisableRemoteVideo() [msid:"%s"]', msid);
-
- return this._client.disableRemoteVideo(msid);
- }
-
- handleEnableRemoteVideo(msid)
- {
- logger.debug('handleEnableRemoteVideo() [msid:"%s"]', msid);
-
- return this._client.enableRemoteVideo(msid);
- }
-
- _runClient()
- {
- let peerId = this.props.peerId;
- let roomId = this.props.roomId;
-
- logger.debug('_runClient() [peerId:"%s", roomId:"%s"]', peerId, roomId);
-
- this._client = new Client(peerId, roomId);
-
- this._client.on('localstream', (stream, resolution) =>
- {
- this.setState(
- {
- localStream : stream,
- localVideoResolution : resolution
- });
- });
-
- this._client.on('join', () =>
- {
- // Clear remote streams (for reconnections).
- this.setState({ remoteStreams: {} });
-
- this.props.onNotify(
- {
- level : 'success',
- title : 'Yes!',
- message : 'You are in the room!',
- image : '/resources/images/room.svg',
- imageWidth : 80,
- imageHeight : 80
- });
-
- // Start retrieving WebRTC stats (unless mobile or Edge).
- if (utils.isDesktop() && !browser.msedge)
- {
- this.setState({ showStats: true });
-
- setTimeout(() =>
- {
- this._startStats();
- }, STATS_INTERVAL / 2);
- }
- });
-
- this._client.on('close', (error) =>
- {
- // Clear remote streams (for reconnections) and more stuff.
- this.setState(
- {
- remoteStreams : {},
- activeSpeakerId : null
- });
-
- if (error)
- {
- this.props.onNotify(
- {
- level : 'error',
- title : 'Error',
- message : error.message
- });
- }
-
- // Stop retrieving WebRTC stats.
- this._stopStats();
- });
-
- this._client.on('disconnected', () =>
- {
- // Clear remote streams (for reconnections).
- this.setState({ remoteStreams: {} });
-
- this.props.onNotify(
- {
- level : 'error',
- title : 'Warning',
- message : 'app disconnected'
- });
-
- // Stop retrieving WebRTC stats.
- this._stopStats();
- });
-
- this._client.on('numwebcams', (num) =>
- {
- this.setState(
- {
- multipleWebcams : (num > 1 ? true : false)
- });
- });
-
- this._client.on('webcamtype', (type) =>
- {
- this.setState({ webcamType: type });
- });
-
- this._client.on('peers', (peers) =>
- {
- let peersObject = {};
-
- for (let peer of peers)
- {
- peersObject[peer.id] = peer;
- }
-
- this.setState({ peers: peersObject });
- });
-
- this._client.on('addpeer', (peer) =>
- {
- this.props.onNotify(
- {
- level : 'success',
- message : `${peer.id} joined the room`
- });
-
- let peers = this.state.peers;
-
- peers[peer.id] = peer;
- this.setState({ peers });
- });
-
- this._client.on('updatepeer', (peer) =>
- {
- let peers = this.state.peers;
-
- peers[peer.id] = peer;
- this.setState({ peers });
- });
-
- this._client.on('removepeer', (peer) =>
- {
- this.props.onNotify(
- {
- level : 'info',
- message : `${peer.id} left the room`
- });
-
- let peers = this.state.peers;
-
- peer = peers[peer.id];
- if (!peer)
- return;
-
- delete peers[peer.id];
-
- // NOTE: This shouldn't be needed but Safari 11 does not fire pc "removestream"
- // nor stream "removetrack" nor track "ended", so we need to cleanup remote
- // streams when a peer leaves.
- let remoteStreams = this.state.remoteStreams;
-
- for (let msid of peer.msids)
- {
- delete remoteStreams[msid];
- }
-
- this.setState({ peers, remoteStreams });
- });
-
- this._client.on('connectionstate', (state) =>
- {
- this.setState({ connectionState: state });
- });
-
- this._client.on('addstream', (stream) =>
- {
- let remoteStreams = this.state.remoteStreams;
- let streamId = stream.jitsiRemoteId || stream.id;
-
- remoteStreams[streamId] = stream;
- this.setState({ remoteStreams });
- });
-
- this._client.on('removestream', (stream) =>
- {
- let remoteStreams = this.state.remoteStreams;
- let streamId = stream.jitsiRemoteId || stream.id;
-
- delete remoteStreams[streamId];
- this.setState({ remoteStreams });
- });
-
- this._client.on('addtrack', () =>
- {
- let remoteStreams = this.state.remoteStreams;
-
- this.setState({ remoteStreams });
- });
-
- this._client.on('removetrack', () =>
- {
- let remoteStreams = this.state.remoteStreams;
-
- this.setState({ remoteStreams });
- });
-
- this._client.on('forcestreamsupdate', () =>
- {
- // Just firef for Firefox due to bug:
- // https://bugzilla.mozilla.org/show_bug.cgi?id=1347578
- this.forceUpdate();
- });
-
- this._client.on('activespeaker', (peer) =>
- {
- this.setState(
- {
- activeSpeakerId : (peer ? peer.id : null)
- });
- });
- }
-
- _startStats()
- {
- logger.debug('_startStats()');
-
- getStats.call(this);
-
- function getStats()
- {
- this._client.getStats()
- .then((stats) =>
- {
- if (!this._mounted)
- return;
-
- this.setState({ stats });
-
- this._statsTimer = setTimeout(() =>
- {
- getStats.call(this);
- }, STATS_INTERVAL);
- })
- .catch((error) =>
- {
- logger.error('getStats() failed: %o', error);
-
- this.setState({ stats: null });
-
- // this._statsTimer = setTimeout(() =>
- // {
- // getStats.call(this);
- // }, STATS_INTERVAL);
- });
- }
- }
-
- _stopStats()
- {
- logger.debug('_stopStats()');
-
- this.setState({ stats: null });
-
- clearTimeout(this._statsTimer);
- }
-}
+
+
+
+
+
+
+
+
onSetAudioMode(!me.audioOnly)}
+ />
+
+
onRestartIce()}
+ />
+
+
+
+
+
+ );
+};
Room.propTypes =
{
- peerId : PropTypes.string.isRequired,
- roomId : PropTypes.string.isRequired,
- onNotify : PropTypes.func.isRequired,
- onHideNotification : PropTypes.func.isRequired
+ room : appPropTypes.Room.isRequired,
+ me : appPropTypes.Me.isRequired,
+ amActiveSpeaker : PropTypes.bool.isRequired,
+ onRoomLinkCopy : PropTypes.func.isRequired,
+ onSetAudioMode : PropTypes.func.isRequired,
+ onRestartIce : PropTypes.func.isRequired
};
+
+const mapStateToProps = (state) =>
+{
+ return {
+ room : state.room,
+ me : state.me,
+ amActiveSpeaker : state.me.name === state.room.activeSpeakerName
+ };
+};
+
+const mapDispatchToProps = (dispatch) =>
+{
+ return {
+ onRoomLinkCopy : () =>
+ {
+ dispatch(requestActions.notify(
+ {
+ text : 'Room link copied to the clipboard'
+ }));
+ },
+ onSetAudioMode : (enable) =>
+ {
+ if (enable)
+ dispatch(requestActions.enableAudioOnly());
+ else
+ dispatch(requestActions.disableAudioOnly());
+ },
+ onRestartIce : () =>
+ {
+ dispatch(requestActions.restartIce());
+ }
+ };
+};
+
+const RoomContainer = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(Room);
+
+export default RoomContainer;
diff --git a/app/lib/components/Stats.jsx b/app/lib/components/Stats.jsx
deleted file mode 100644
index bac7601..0000000
--- a/app/lib/components/Stats.jsx
+++ /dev/null
@@ -1,585 +0,0 @@
-'use strict';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import browser from 'bowser';
-import Logger from '../Logger';
-
-const logger = new Logger('Stats'); // eslint-disable-line no-unused-vars
-
-// TODO: TMP
-global.BROWSER = browser;
-
-export default class Stats extends React.Component
-{
- constructor(props)
- {
- super(props);
-
- this.state =
- {
- stats :
- {
- transport : null,
- audio : null,
- video : null
- }
- };
- }
-
- componentWillMount()
- {
- let stats = this.props.stats;
-
- this._processStats(stats);
- }
-
- componentWillReceiveProps(nextProps)
- {
- let stats = nextProps.stats;
-
- this._processStats(stats);
- }
-
- render()
- {
- let state = this.state;
-
- return (
-
-
- {
- Object.keys(state.stats).map((blockName) =>
- {
- let block = state.stats[blockName];
-
- if (!block)
- return;
-
- let items = Object.keys(block).map((itemName) =>
- {
- let value = block[itemName];
-
- if (value === undefined)
- return;
-
- return (
-
- );
- });
-
- if (!items.length)
- return null;
-
- return (
-
-
{blockName}
- {items}
-
- );
- })
- }
-
- );
- }
-
- handleCloseClick()
- {
- this.props.onClose();
- }
-
- _processStats(stats)
- {
- // global.STATS = stats; // TODO: REMOVE
-
- if (browser.check({ chrome: '58' }, true))
- {
- this._processStatsChrome58(stats);
- }
- else if (browser.check({ chrome: '40' }, true))
- {
- this._processStatsChromeOld(stats);
- }
- else if (browser.check({ firefox: '40' }, true))
- {
- this._processStatsFirefox(stats);
- }
- else if (browser.check({ safari: '11' }, true))
- {
- this._processStatsSafari11(stats);
- }
- else
- {
- logger.warn('_processStats() | unsupported browser [name:"%s", version:%s]',
- browser.name, browser.version);
- }
- }
-
- _processStatsChrome58(stats)
- {
- let transport = {};
- let audio = {};
- let video = {};
- let selectedCandidatePair = null;
- let localCandidates = {};
- let remoteCandidates = {};
-
- for (let group of stats.values())
- {
- switch (group.type)
- {
- case 'transport':
- {
- transport['bytes sent'] = group.bytesSent;
- transport['bytes received'] = group.bytesReceived;
-
- break;
- }
-
- case 'candidate-pair':
- {
- if (!group.writable)
- break;
-
- selectedCandidatePair = group;
-
- transport['available bitrate'] =
- Math.round(group.availableOutgoingBitrate / 1000) + ' kbps';
- transport['current RTT'] =
- Math.round(group.currentRoundTripTime * 1000) + ' ms';
-
- break;
- }
-
- case 'local-candidate':
- {
- localCandidates[group.id] = group;
-
- break;
- }
-
- case 'remote-candidate':
- {
- remoteCandidates[group.id] = group;
-
- break;
- }
-
- case 'codec':
- {
- let mimeType = group.mimeType.split('/');
- let kind = mimeType[0];
- let codec = mimeType[1];
- let block;
-
- switch (kind)
- {
- case 'audio':
- block = audio;
- break;
- case 'video':
- if (codec === 'rtx')
- break;
-
- block = video;
- break;
- }
-
- if (!block)
- break;
-
- block['codec'] = codec;
- block['payload type'] = group.payloadType;
-
- break;
- }
-
- case 'track':
- {
- if (group.kind !== 'video')
- break;
-
- video['frame size'] = group.frameWidth + ' x ' + group.frameHeight;
- video['frames sent'] = group.framesSent;
-
- break;
- }
-
- case 'outbound-rtp':
- {
- if (group.isRemote)
- break;
-
- let block;
-
- switch (group.mediaType)
- {
- case 'audio':
- block = audio;
- break;
- case 'video':
- block = video;
- break;
- }
-
- if (!block)
- break;
-
- block['ssrc'] = group.ssrc;
- block['bytes sent'] = group.bytesSent;
- block['packets sent'] = group.packetsSent;
-
- if (block === video)
- block['frames encoded'] = group.framesEncoded;
-
- block['NACK count'] = group.nackCount;
- block['PLI count'] = group.pliCount;
- block['FIR count'] = group.firCount;
-
- break;
- }
- }
- }
-
- // Post checks.
-
- if (!video.ssrc)
- video = {};
-
- if (!audio.ssrc)
- audio = {};
-
- if (selectedCandidatePair)
- {
- let localCandidate = localCandidates[selectedCandidatePair.localCandidateId];
- let remoteCandidate = remoteCandidates[selectedCandidatePair.remoteCandidateId];
-
- transport['protocol'] = localCandidate.protocol;
- transport['local IP'] = localCandidate.ip;
- transport['local port'] = localCandidate.port;
- transport['remote IP'] = remoteCandidate.ip;
- transport['remote port'] = remoteCandidate.port;
- }
-
- // Set state.
- this.setState(
- {
- stats :
- {
- transport,
- audio,
- video
- }
- });
- }
-
- _processStatsChromeOld(stats)
- {
- let transport = {};
- let audio = {};
- let video = {};
-
- for (let group of stats.values())
- {
- switch (group.type)
- {
- case 'googCandidatePair':
- {
- if (group.googActiveConnection !== 'true')
- break;
-
- let localAddress = group.googLocalAddress.split(':');
- let remoteAddress = group.googRemoteAddress.split(':');
- let localIP = localAddress[0];
- let localPort = localAddress[1];
- let remoteIP = remoteAddress[0];
- let remotePort = remoteAddress[1];
-
- transport['protocol'] = group.googTransportType;
- transport['local IP'] = localIP;
- transport['local port'] = localPort;
- transport['remote IP'] = remoteIP;
- transport['remote port'] = remotePort;
- transport['bytes sent'] = group.bytesSent;
- transport['bytes received'] = group.bytesReceived;
- transport['RTT'] = Math.round(group.googRtt) + ' ms';
-
- break;
- }
-
- case 'VideoBwe':
- {
- transport['available bitrate'] =
- Math.round(group.googAvailableSendBandwidth / 1000) + ' kbps';
- transport['transmit bitrate'] =
- Math.round(group.googTransmitBitrate / 1000) + ' kbps';
-
- break;
- }
-
- case 'ssrc':
- {
- if (group.packetsSent === undefined)
- break;
-
- let block;
-
- switch (group.mediaType)
- {
- case 'audio':
- block = audio;
- break;
- case 'video':
- block = video;
- break;
- }
-
- if (!block)
- break;
-
- block['codec'] = group.googCodecName;
- block['ssrc'] = group.ssrc;
- block['bytes sent'] = group.bytesSent;
- block['packets sent'] = group.packetsSent;
- block['packets lost'] = group.packetsLost;
-
- if (block === video)
- {
- block['frames encoded'] = group.framesEncoded;
- video['frame size'] =
- group.googFrameWidthSent + ' x ' + group.googFrameHeightSent;
- video['frame rate'] = group.googFrameRateSent;
- }
-
- block['NACK count'] = group.googNacksReceived;
- block['PLI count'] = group.googPlisReceived;
- block['FIR count'] = group.googFirsReceived;
-
- break;
- }
- }
- }
-
- // Post checks.
-
- if (!video.ssrc)
- video = {};
-
- if (!audio.ssrc)
- audio = {};
-
- // Set state.
- this.setState(
- {
- stats :
- {
- transport,
- audio,
- video
- }
- });
- }
-
- _processStatsFirefox(stats)
- {
- let transport = {};
- let audio = {};
- let video = {};
- let selectedCandidatePair = null;
- let localCandidates = {};
- let remoteCandidates = {};
-
- for (let group of stats.values())
- {
- switch (group.type)
- {
- case 'candidate-pair':
- {
- if (!group.selected)
- break;
-
- selectedCandidatePair = group;
-
- break;
- }
-
- case 'local-candidate':
- {
- localCandidates[group.id] = group;
-
- break;
- }
-
- case 'remote-candidate':
- {
- remoteCandidates[group.id] = group;
-
- break;
- }
-
- case 'outbound-rtp':
- {
- if (group.isRemote)
- break;
-
- let block;
-
- switch (group.mediaType)
- {
- case 'audio':
- block = audio;
- break;
- case 'video':
- block = video;
- break;
- }
-
- if (!block)
- break;
-
- block['ssrc'] = group.ssrc;
- block['bytes sent'] = group.bytesSent;
- block['packets sent'] = group.packetsSent;
-
- if (block === video)
- {
- block['bitrate'] =
- Math.round(group.bitrateMean / 1000) + ' kbps';
- block['frames encoded'] = group.framesEncoded;
- video['frame rate'] = Math.round(group.framerateMean);
- }
-
- block['NACK count'] = group.nackCount;
- block['PLI count'] = group.pliCount;
- block['FIR count'] = group.firCount;
-
- break;
- }
- }
- }
-
- // Post checks.
-
- if (!video.ssrc)
- video = {};
-
- if (!audio.ssrc)
- audio = {};
-
- if (selectedCandidatePair)
- {
- let localCandidate = localCandidates[selectedCandidatePair.localCandidateId];
- let remoteCandidate = remoteCandidates[selectedCandidatePair.remoteCandidateId];
-
- transport['protocol'] = localCandidate.transport;
- transport['local IP'] = localCandidate.ipAddress;
- transport['local port'] = localCandidate.portNumber;
- transport['remote IP'] = remoteCandidate.ipAddress;
- transport['remote port'] = remoteCandidate.portNumber;
- }
-
- // Set state.
- this.setState(
- {
- stats :
- {
- transport,
- audio,
- video
- }
- });
- }
-
- _processStatsSafari11(stats)
- {
- let transport = {};
- let audio = {};
- let video = {};
-
- for (let group of stats.values())
- {
- switch (group.type)
- {
- case 'candidate-pair':
- {
- if (!group.writable)
- break;
-
- transport['bytes sent'] = group.bytesSent;
- transport['bytes received'] = group.bytesReceived;
- transport['available bitrate'] =
- Math.round(group.availableOutgoingBitrate / 1000) + ' kbps';
- transport['current RTT'] =
- Math.round(group.currentRoundTripTime * 1000) + ' ms';
-
- break;
- }
-
- case 'outbound-rtp':
- {
- if (group.isRemote)
- break;
-
- let block;
-
- switch (group.mediaType)
- {
- case 'audio':
- block = audio;
- break;
- case 'video':
- block = video;
- break;
- }
-
- if (!block)
- break;
-
- block['ssrc'] = group.ssrc;
- block['bytes sent'] = group.bytesSent;
- block['packets sent'] = group.packetsSent;
-
- if (block === video)
- block['frames encoded'] = group.framesEncoded;
-
- block['NACK count'] = group.nackCount;
- block['PLI count'] = group.pliCount;
- block['FIR count'] = group.firCount;
-
- break;
- }
- }
- }
-
- // Post checks.
-
- if (!video.ssrc)
- video = {};
-
- if (!audio.ssrc)
- audio = {};
-
- // Set state.
- this.setState(
- {
- stats :
- {
- transport,
- audio,
- video
- }
- });
- }
-}
-
-Stats.propTypes =
-{
- stats : PropTypes.object.isRequired,
- onClose : PropTypes.func.isRequired
-};
diff --git a/app/lib/components/TransitionAppear.jsx b/app/lib/components/TransitionAppear.jsx
deleted file mode 100644
index addb64f..0000000
--- a/app/lib/components/TransitionAppear.jsx
+++ /dev/null
@@ -1,60 +0,0 @@
-'use strict';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import TransitionGroup from 'react-transition-group/TransitionGroup';
-
-const DEFAULT_DURATION = 1000;
-
-export default class TransitionAppear extends React.Component
-{
- constructor(props)
- {
- super(props);
- }
-
- render()
- {
- let props = this.props;
- let duration = props.hasOwnProperty('duration') ? props.duration : DEFAULT_DURATION;
-
- return (
-
- {this.props.children}
-
- );
- }
-}
-
-TransitionAppear.propTypes =
-{
- children : PropTypes.any,
- duration : PropTypes.number
-};
-
-class FakeTransitionWrapper extends React.Component
-{
- constructor(props)
- {
- super(props);
- }
-
- render()
- {
- let children = React.Children.toArray(this.props.children);
-
- return children[0] || null;
- }
-}
-
-FakeTransitionWrapper.propTypes =
-{
- children : PropTypes.any
-};
diff --git a/app/lib/components/Video.jsx b/app/lib/components/Video.jsx
deleted file mode 100644
index 7556eaa..0000000
--- a/app/lib/components/Video.jsx
+++ /dev/null
@@ -1,241 +0,0 @@
-'use strict';
-
-import React from 'react';
-import PropTypes from 'prop-types';
-import Logger from '../Logger';
-import classnames from 'classnames';
-import hark from 'hark';
-
-const logger = new Logger('Video'); // eslint-disable-line no-unused-vars
-
-export default class Video extends React.Component
-{
- constructor(props)
- {
- super(props);
-
- this.state =
- {
- width : 0,
- height : 0,
- resolution : null,
- volume : 0 // Integer from 0 to 10.
- };
-
- let stream = props.stream;
-
- // Clean stream.
- // Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1347578
- this._cleanStream(stream);
-
- // Current MediaStreamTracks info.
- this._tracksHash = this._getTracksHash(stream);
-
- // Periodic timer to show video dimensions.
- this._videoResolutionTimer = null;
-
- // Hark instance.
- this._hark = null;
- }
-
- render()
- {
- let props = this.props;
- let state = this.state;
-
- return (
-
- {state.width ?
- (
-
-
{state.width}x{state.height}
- {props.resolution ?
-
{props.resolution}
- :null}
-
- )
- :null}
-
-
-
-
- );
- }
-
- componentDidMount()
- {
- let stream = this.props.stream;
- let video = this.refs.video;
-
- video.srcObject = stream;
-
- this._showVideoResolution();
- this._videoResolutionTimer = setInterval(() =>
- {
- this._showVideoResolution();
- }, 500);
-
- if (stream.getAudioTracks().length > 0)
- {
- this._hark = hark(stream);
-
- this._hark.on('speaking', () =>
- {
- // logger.debug('hark "speaking" event');
- });
-
- this._hark.on('stopped_speaking', () =>
- {
- // logger.debug('hark "stopped_speaking" event');
-
- this.setState({ volume: 0 });
- });
-
- this._hark.on('volume_change', (volume, threshold) =>
- {
- if (volume < threshold)
- return;
-
- // logger.debug('hark "volume_change" event [volume:%sdB, threshold:%sdB]', volume, threshold);
-
- this.setState(
- {
- volume : Math.round((volume - threshold) * (-10) / threshold)
- });
- });
- }
- }
-
- componentWillUnmount()
- {
- clearInterval(this._videoResolutionTimer);
-
- if (this._hark)
- this._hark.stop();
- }
-
- componentWillReceiveProps(nextProps)
- {
- let stream = nextProps.stream;
-
- // Clean stream.
- // Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1347578
- this._cleanStream(stream);
-
- // If there is something different in the stream, re-render it.
-
- let previousTracksHash = this._tracksHash;
-
- this._tracksHash = this._getTracksHash(stream);
-
- if (this._tracksHash !== previousTracksHash)
- this.refs.video.srcObject = stream;
- }
-
- handleResolutionClick()
- {
- if (!this.props.resolution)
- return;
-
- logger.debug('handleResolutionClick()');
-
- this.props.onResolutionChange();
- }
-
- _getTracksHash(stream)
- {
- return stream.getTracks()
- .map((track) =>
- {
- let trackId = track.jitsiRemoteId || track.id;
-
- return trackId;
- })
- .join('|');
- }
-
- _showVideoResolution()
- {
- let video = this.refs.video;
-
- this.setState(
- {
- width : video.videoWidth,
- height : video.videoHeight
- });
- }
-
- _cleanStream(stream)
- {
- // Hack for Firefox bug:
- // https://bugzilla.mozilla.org/show_bug.cgi?id=1347578
-
- if (!stream)
- return;
-
- let tracks = stream.getTracks();
- let previousNumTracks = tracks.length;
-
- // Remove ended tracks.
- for (let track of tracks)
- {
- if (track.readyState === 'ended')
- {
- logger.warn('_cleanStream() | removing ended track [track:%o]', track);
-
- stream.removeTrack(track);
- }
- }
-
- // If there are multiple live audio tracks (related to the bug?) just keep
- // the last one.
- while (stream.getAudioTracks().length > 1)
- {
- let track = stream.getAudioTracks()[0];
-
- logger.warn('_cleanStream() | removing live audio track due the presence of others [track:%o]', track);
-
- stream.removeTrack(track);
- }
-
- // If there are multiple live video tracks (related to the bug?) just keep
- // the last one.
- while (stream.getVideoTracks().length > 1)
- {
- let track = stream.getVideoTracks()[0];
-
- logger.warn('_cleanStream() | removing live video track due the presence of others [track:%o]', track);
-
- stream.removeTrack(track);
- }
-
- let numTracks = stream.getTracks().length;
-
- if (numTracks !== previousNumTracks)
- logger.warn('_cleanStream() | num tracks changed from %s to %s', previousNumTracks, numTracks);
- }
-}
-
-Video.propTypes =
-{
- stream : PropTypes.object.isRequired,
- resolution : PropTypes.string,
- muted : PropTypes.bool,
- videoDisabled : PropTypes.bool,
- mirror : PropTypes.bool,
- onResolutionChange : PropTypes.func
-};
diff --git a/app/lib/components/appPropTypes.js b/app/lib/components/appPropTypes.js
new file mode 100644
index 0000000..795a781
--- /dev/null
+++ b/app/lib/components/appPropTypes.js
@@ -0,0 +1,71 @@
+import PropTypes from 'prop-types';
+
+export const Room = PropTypes.shape(
+ {
+ url : PropTypes.string.isRequired,
+ state : PropTypes.oneOf(
+ [ 'new', 'connecting', 'connected', 'closed' ]).isRequired,
+ activeSpeakerName : PropTypes.string
+ });
+
+export const Device = PropTypes.shape(
+ {
+ flag : PropTypes.string.isRequired,
+ name : PropTypes.string.isRequired,
+ version : PropTypes.string
+ });
+
+export const Me = PropTypes.shape(
+ {
+ name : PropTypes.string.isRequired,
+ displayName : PropTypes.string,
+ displayNameSet : PropTypes.bool.isRequired,
+ device : Device.isRequired,
+ canSendMic : PropTypes.bool.isRequired,
+ canSendWebcam : PropTypes.bool.isRequired,
+ canChangeWebcam : PropTypes.bool.isRequired,
+ webcamInProgress : PropTypes.bool.isRequired,
+ audioOnly : PropTypes.bool.isRequired,
+ audioOnlyInProgress : PropTypes.bool.isRequired,
+ restartIceInProgress : PropTypes.bool.isRequired
+ });
+
+export const Producer = PropTypes.shape(
+ {
+ id : PropTypes.number.isRequired,
+ source : PropTypes.oneOf([ 'mic', 'webcam' ]).isRequired,
+ deviceLabel : PropTypes.string,
+ type : PropTypes.oneOf([ 'front', 'back' ]),
+ locallyPaused : PropTypes.bool.isRequired,
+ remotelyPaused : PropTypes.bool.isRequired,
+ track : PropTypes.any,
+ codec : PropTypes.string.isRequired
+ });
+
+export const Peer = PropTypes.shape(
+ {
+ name : PropTypes.string.isRequired,
+ displayName : PropTypes.string,
+ device : Device.isRequired,
+ consumers : PropTypes.arrayOf(PropTypes.number).isRequired
+ });
+
+export const Consumer = PropTypes.shape(
+ {
+ id : PropTypes.number.isRequired,
+ peerName : PropTypes.string.isRequired,
+ source : PropTypes.oneOf([ 'mic', 'webcam' ]).isRequired,
+ supported : PropTypes.bool.isRequired,
+ locallyPaused : PropTypes.bool.isRequired,
+ remotelyPaused : PropTypes.bool.isRequired,
+ profile : PropTypes.oneOf([ 'none', 'low', 'medium', 'high' ]),
+ track : PropTypes.any,
+ codec : PropTypes.string
+ });
+
+export const Notification = PropTypes.shape(
+ {
+ id : PropTypes.string.isRequired,
+ type : PropTypes.oneOf([ 'info', 'error' ]).isRequired,
+ timeout : PropTypes.number
+ });
diff --git a/app/lib/components/muiTheme.js b/app/lib/components/muiTheme.js
deleted file mode 100644
index d8d8205..0000000
--- a/app/lib/components/muiTheme.js
+++ /dev/null
@@ -1,16 +0,0 @@
-'use strict';
-
-import getMuiTheme from 'material-ui/styles/getMuiTheme';
-import lightBaseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
-import { grey500 } from 'material-ui/styles/colors';
-
-// NOTE: I should clone it
-let theme = lightBaseTheme;
-
-theme.palette.borderColor = grey500;
-
-let muiTheme = getMuiTheme(lightBaseTheme);
-
-export default muiTheme;
-
-
diff --git a/app/lib/components/transitions.jsx b/app/lib/components/transitions.jsx
new file mode 100644
index 0000000..9f3f391
--- /dev/null
+++ b/app/lib/components/transitions.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { CSSTransition } from 'react-transition-group';
+
+const Appear = ({ duration, children }) => (
+
+ {children}
+
+);
+
+Appear.propTypes =
+{
+ duration : PropTypes.number,
+ children : PropTypes.any
+};
+
+export { Appear };
diff --git a/app/lib/cookiesManager.js b/app/lib/cookiesManager.js
new file mode 100644
index 0000000..7b25cfd
--- /dev/null
+++ b/app/lib/cookiesManager.js
@@ -0,0 +1,24 @@
+import jsCookie from 'js-cookie';
+
+const USER_COOKIE = 'mediasoup-demo.user';
+const DEVICES_COOKIE = 'mediasoup-demo.devices';
+
+export function getUser()
+{
+ return jsCookie.getJSON(USER_COOKIE);
+}
+
+export function setUser({ displayName })
+{
+ jsCookie.set(USER_COOKIE, { displayName });
+}
+
+export function getDevices()
+{
+ return jsCookie.getJSON(DEVICES_COOKIE);
+}
+
+export function setDevices({ webcamEnabled })
+{
+ jsCookie.set(DEVICES_COOKIE, { webcamEnabled });
+}
diff --git a/app/lib/edge/RTCPeerConnection.js b/app/lib/edge/RTCPeerConnection.js
deleted file mode 100644
index 93b4c26..0000000
--- a/app/lib/edge/RTCPeerConnection.js
+++ /dev/null
@@ -1,2502 +0,0 @@
-/* global __filename, RTCIceGatherer, RTCIceTransport, RTCDtlsTransport,
-RTCRtpSender, RTCRtpReceiver */
-
-import yaeti from 'yaeti';
-import Logger from '../Logger';
-import RTCSessionDescription from './RTCSessionDescription';
-import * as utils from '../utils';
-import * as ortcUtils from './ortcUtils';
-import { InvalidStateError } from './errors';
-
-const logger = new Logger('edge/RTCPeerConnection');
-
-const RTCSignalingState = {
- stable: 'stable',
- haveLocalOffer: 'have-local-offer',
- haveRemoteOffer: 'have-remote-offer',
- closed: 'closed'
-};
-
-const RTCIceGatheringState = {
- new: 'new',
- gathering: 'gathering',
- complete: 'complete'
-};
-
-const CNAME = `jitsi-ortc-cname-${utils.randomNumber()}`;
-
-/**
- * RTCPeerConnection shim for ORTC based endpoints (such as Edge).
- *
- * The interface is based on the W3C specification of 2015, which matches
- * the implementation of Chrome nowadays:
- *
- * https://www.w3.org/TR/2015/WD-webrtc-20150210/
- *
- * It also implements Plan-B for multi-stream, and assumes single BUNDLEd
- * transport and rtcp-mux.
- */
-export default class ortcRTCPeerConnection extends yaeti.EventTarget {
- /**
- */
- constructor(pcConfig) {
- super();
-
- logger.debug('constructor() pcConfig:', pcConfig);
-
- // Buffered local ICE candidates (in WebRTC format).
- // @type {sequence
}
- this._bufferedIceCandidates = [];
-
- // Closed flag.
- // @type {Boolean}
- this._closed = false;
-
- // RTCDtlsTransport.
- // @type {RTCDtlsTransport}
- this._dtlsTransport = null;
-
- // RTCIceGatherer.
- // @type {RTCIceGatherer}
- this._iceGatherer = null;
-
- // RTCPeerConnection iceGatheringState.
- // NOTE: This should not be needed, but Edge does not implement
- // iceGatherer.state.
- // @type {RTCIceGatheringState}
- this._iceGatheringState = RTCIceGatheringState.new;
-
- // RTCIceTransport.
- // @type {RTCIceTransport}
- this._iceTransport = null;
-
- // Local RTP capabilities (filtered with remote ones).
- // @type {RTCRtpCapabilities}
- this._localCapabilities = null;
-
- // Local RTCSessionDescription.
- // @type {RTCSessionDescription}
- this._localDescription = null;
-
- // Map with info regarding local media.
- // - index: MediaStreamTrack.id
- // - value: Object
- // - rtpSender: Associated RTCRtpSender instance
- // - stream: Associated MediaStream instance
- // - ssrc: Provisional or definitive SSRC
- // - rtxSsrc: Provisional or definitive SSRC for RTX
- // - sending: Boolean indicating whether rtpSender.send() was called.
- this._localTrackInfos = new Map();
-
- // Ordered Map with MID as key and kind as value.
- // @type {map}
- this._mids = new Map();
-
- // Remote RTCSessionDescription.
- // @type {RTCSessionDescription}
- this._remoteDescription = null;
-
- // Map of remote streams.
- // - index: MediaStream.jitsiRemoteId (as signaled in remote SDP)
- // - value: MediaStream (locally generated so id does not match)
- // @type {map}
- this._remoteStreams = new Map();
-
- // Map with info about receiving media.
- // - index: Media SSRC
- // - value: Object
- // - kind: 'audio' / 'video'
- // - ssrc: Media SSRC
- // - rtxSsrc: RTX SSRC (may be unset)
- // - streamId: MediaStream.jitsiRemoteId
- // - trackId: MediaStreamTrack.jitsiRemoteId
- // - cname: CNAME
- // - stream: MediaStream
- // - track: MediaStreamTrack
- // - rtpReceiver: Associated RTCRtpReceiver instance
- // @type {map}
- this._remoteTrackInfos = new Map();
-
- // Local SDP global fields.
- this._sdpGlobalFields = {
- id: utils.randomNumber(),
- version: 0
- };
-
- // RTCPeerConnection signalingState.
- // @type {RTCSignalingState}
- this._signalingState = RTCSignalingState.stable;
-
- // Create the RTCIceGatherer.
- this._setIceGatherer(pcConfig);
-
- // Create the RTCIceTransport.
- this._setIceTransport(this._iceGatherer);
-
- // Create the RTCDtlsTransport.
- this._setDtlsTransport(this._iceTransport);
- }
-
- /**
- * Current ICE+DTLS connection state.
- * @return {RTCPeerConnectionState}
- */
- get connectionState() {
- return this._dtlsTransport.state;
- }
-
- /**
- * Current ICE connection state.
- * @return {RTCIceConnectionState}
- */
- get iceConnectionState() {
- return this._iceTransport.state;
- }
-
- /**
- * Current ICE gathering state.
- * @return {RTCIceGatheringState}
- */
- get iceGatheringState() {
- return this._iceGatheringState;
- }
-
- /**
- * Gets the local description.
- * @return {RTCSessionDescription}
- */
- get localDescription() {
- return this._localDescription;
- }
-
- /**
- * Gets the remote description.
- * @return {RTCSessionDescription}
- */
- get remoteDescription() {
- return this._remoteDescription;
- }
-
- /**
- * Current signaling state.
- * @return {RTCSignalingState}
- */
- get signalingState() {
- return this._signalingState;
- }
-
- /**
- * Adds a remote ICE candidate. Implements both the old callbacks based
- * signature and the new Promise based style.
- *
- * Arguments in Promise mode:
- * @param {RTCIceCandidate} candidate
- *
- * Arguments in callbacks mode:
- * @param {RTCIceCandidate} candidate
- * @param {function()} callback
- * @param {function(error)} errback
- */
- addIceCandidate(candidate, ...args) {
- let usePromise;
- let callback;
- let errback;
-
- if (!candidate) {
- throw new TypeError('candidate missing');
- }
-
- if (args.length === 0) {
- usePromise = true;
- } else {
- usePromise = false;
- callback = args[0];
- errback = args[1];
-
- if (typeof callback !== 'function') {
- throw new TypeError('callback missing');
- }
-
- if (typeof errback !== 'function') {
- throw new TypeError('errback missing');
- }
- }
-
- logger.debug('addIceCandidate() candidate:', candidate);
-
- if (usePromise) {
- return this._addIceCandidate(candidate);
- }
-
- this._addIceCandidate(candidate)
- .then(() => callback())
- .catch(error => errback(error));
- }
-
- /**
- * Adds a local MediaStream.
- * @param {MediaStream} stream.
- * NOTE: Deprecated API.
- */
- addStream(stream) {
- logger.debug('addStream()');
-
- this._addStream(stream);
- }
-
- /**
- * Closes the RTCPeerConnection and all the underlying ORTC objects.
- */
- close() {
- if (this._closed) {
- return;
- }
-
- this._closed = true;
-
- logger.debug('close()');
-
- this._updateAndEmitSignalingStateChange(RTCSignalingState.closed);
-
- // Close RTCIceGatherer.
- // NOTE: Not yet implemented by Edge.
- try {
- this._iceGatherer.close();
- } catch (error) {
- logger.warn(`iceGatherer.close() failed:${error}`);
- }
-
- // Close RTCIceTransport.
- try {
- this._iceTransport.stop();
- } catch (error) {
- logger.warn(`iceTransport.stop() failed:${error}`);
- }
-
- // Close RTCDtlsTransport.
- try {
- this._dtlsTransport.stop();
- } catch (error) {
- logger.warn(`dtlsTransport.stop() failed:${error}`);
- }
-
- // Close and clear RTCRtpSenders.
- for (const info of this._localTrackInfos.values()) {
- const rtpSender = info.rtpSender;
-
- try {
- rtpSender.stop();
- } catch (error) {
- logger.warn(`rtpSender.stop() failed:${error}`);
- }
- }
-
- this._localTrackInfos.clear();
-
- // Close and clear RTCRtpReceivers.
- for (const info of this._remoteTrackInfos.values()) {
- const rtpReceiver = info.rtpReceiver;
-
- try {
- rtpReceiver.stop();
- } catch (error) {
- logger.warn(`rtpReceiver.stop() failed:${error}`);
- }
- }
-
- this._remoteTrackInfos.clear();
-
- // Clear remote streams.
- this._remoteStreams.clear();
- }
-
- /**
- * Creates a local answer. Implements both the old callbacks based signature
- * and the new Promise based style.
- *
- * Arguments in Promise mode:
- * @param {RTCOfferOptions} [options]
- *
- * Arguments in callbacks mode:
- * @param {function(desc)} callback
- * @param {function(error)} errback
- * @param {MediaConstraints} [constraints]
- */
- createAnswer(...args) {
- let usePromise;
- let options;
- let callback;
- let errback;
-
- if (args.length <= 1) {
- usePromise = true;
- options = args[0];
- } else {
- usePromise = false;
- callback = args[0];
- errback = args[1];
- options = args[2];
-
- if (typeof callback !== 'function') {
- throw new TypeError('callback missing');
- }
-
- if (typeof errback !== 'function') {
- throw new TypeError('errback missing');
- }
- }
-
- logger.debug('createAnswer() options:', options);
-
- if (usePromise) {
- return this._createAnswer(options);
- }
-
- this._createAnswer(options)
- .then(desc => callback(desc))
- .catch(error => errback(error));
- }
-
- /**
- * Creates a RTCDataChannel.
- */
- createDataChannel() {
- logger.debug('createDataChannel()');
-
- // NOTE: DataChannels not implemented in Edge.
- throw new Error('createDataChannel() not supported in Edge');
- }
-
- /**
- * Creates a local offer. Implements both the old callbacks based signature
- * and the new Promise based style.
- *
- * Arguments in Promise mode:
- * @param {RTCOfferOptions} [options]
- *
- * Arguments in callbacks mode:
- * @param {function(desc)} callback
- * @param {function(error)} errback
- * @param {MediaConstraints} [constraints]
- */
- createOffer(...args) {
- let usePromise;
- let options;
- let callback;
- let errback;
-
- if (args.length <= 1) {
- usePromise = true;
- options = args[0];
- } else {
- usePromise = false;
- callback = args[0];
- errback = args[1];
- options = args[2];
-
- if (typeof callback !== 'function') {
- throw new TypeError('callback missing');
- }
-
- if (typeof errback !== 'function') {
- throw new TypeError('errback missing');
- }
- }
-
- logger.debug('createOffer() options:', options);
-
- if (usePromise) {
- return this._createOffer(options);
- }
-
- this._createOffer(options)
- .then(desc => callback(desc))
- .catch(error => errback(error));
- }
-
- /**
- * Gets a sequence of local MediaStreams.
- * @return {sequence}
- */
- getLocalStreams() {
- return Array.from(this._localTrackInfos.values())
- .map(info => info.stream)
- .filter((elem, pos, arr) => arr.indexOf(elem) === pos);
- }
-
- /**
- * Gets a sequence of remote MediaStreams.
- * @return {sequence}
- */
- getRemoteStreams() {
- return Array.from(this._remoteStreams.values());
- }
-
- /**
- * Get RTP statistics. Implements both the old callbacks based signature
- * and the new Promise based style.
- *
- * Arguments in Promise mode:
- * @param {MediaStreamTrack} [selector]
- *
- * Arguments in callbacks mode:
- * @param {MediaStreamTrack} [selector]
- * @param {function(desc)} callback
- * @param {function(error)} errback
- */
- getStats(...args) {
- let usePromise;
- let selector;
- let callback;
- let errback;
-
- if (args.length <= 1) {
- usePromise = true;
- selector = args[0];
- } else {
- usePromise = false;
-
- if (args.length === 2) {
- callback = args[0];
- errback = args[1];
- } else {
- selector = args[0];
- callback = args[1];
- errback = args[2];
- }
-
- if (typeof callback !== 'function') {
- throw new TypeError('callback missing');
- }
-
- if (typeof errback !== 'function') {
- throw new TypeError('errback missing');
- }
- }
-
- logger.debug('getStats()');
-
- if (usePromise) {
- return this._getStats(selector);
- }
-
- this._getStats(selector)
- .then(stats => callback(stats))
- .catch(error => errback(error));
- }
-
- /**
- * Removes a local MediaStream.
- * @param {MediaStream} stream.
- * NOTE: Deprecated API.
- */
- removeStream(stream) {
- logger.debug('removeStream()');
-
- this._removeStream(stream);
- }
-
- /**
- * Applies a local description. Implements both the old callbacks based
- * signature and the new Promise based style.
- *
- * Arguments in Promise mode:
- * @param {RTCSessionDescriptionInit} desc
- *
- * Arguments in callbacks mode:
- * @param {RTCSessionDescription} desc
- * @param {function()} callback
- * @param {function(error)} errback
- */
- setLocalDescription(desc, ...args) {
- let usePromise;
- let callback;
- let errback;
-
- if (!desc) {
- throw new TypeError('description missing');
- }
-
- if (args.length === 0) {
- usePromise = true;
- } else {
- usePromise = false;
- callback = args[0];
- errback = args[1];
-
- if (typeof callback !== 'function') {
- throw new TypeError('callback missing');
- }
-
- if (typeof errback !== 'function') {
- throw new TypeError('errback missing');
- }
- }
-
- logger.debug('setLocalDescription() desc:', desc);
-
- if (usePromise) {
- return this._setLocalDescription(desc);
- }
-
- this._setLocalDescription(desc)
- .then(() => callback())
- .catch(error => errback(error));
- }
-
- /**
- * Applies a remote description. Implements both the old callbacks based
- * signature and the new Promise based style.
- *
- * Arguments in Promise mode:
- * @param {RTCSessionDescriptionInit} desc
- *
- * Arguments in callbacks mode:
- * @param {RTCSessionDescription} desc
- * @param {function()} callback
- * @param {function(error)} errback
- */
- setRemoteDescription(desc, ...args) {
- let usePromise;
- let callback;
- let errback;
-
- if (!desc) {
- throw new TypeError('description missing');
- }
-
- if (args.length === 0) {
- usePromise = true;
- } else {
- usePromise = false;
- callback = args[0];
- errback = args[1];
-
- if (typeof callback !== 'function') {
- throw new TypeError('callback missing');
- }
-
- if (typeof errback !== 'function') {
- throw new TypeError('errback missing');
- }
- }
-
- logger.debug('setRemoteDescription() desc:', desc);
-
- if (usePromise) {
- return this._setRemoteDescription(desc);
- }
-
- this._setRemoteDescription(desc)
- .then(() => callback())
- .catch(error => errback(error));
- }
-
- /**
- * Promise based implementation for addIceCandidate().
- * @return {Promise}
- * @private
- */
- _addIceCandidate(candidate) { // eslint-disable-line no-unused-vars
- if (this._closed) {
- return Promise.reject(
- new InvalidStateError('RTCPeerConnection closed'));
- }
-
- // NOTE: Edge does not support Trickle-ICE so just candidates in the
- // remote SDP are applied. Candidates given later would be just
- // ignored, so notify the called about that.
- return Promise.reject(new Error('addIceCandidate() not supported'));
- }
-
- /**
- * Implementation for addStream().
- * @private
- */
- _addStream(stream) {
- if (this._closed) {
- throw new InvalidStateError('RTCPeerConnection closed');
- }
-
- // Create a RTCRtpSender for each track.
- for (const track of stream.getTracks()) {
- // Ignore if ended.
- if (track.readyState === 'ended') {
- logger.warn('ignoring ended MediaStreamTrack');
-
- continue;
- }
-
- // Ignore if track is already present.
- if (this._localTrackInfos.has(track.id)) {
- logger.warn('ignoring already handled MediaStreamTrack');
-
- continue;
- }
-
- const rtpSender = new RTCRtpSender(track, this._dtlsTransport);
-
- // Store it in the map.
- this._localTrackInfos.set(track.id, {
- rtpSender,
- stream
- });
- }
-
- // Check for local tracks removal.
- for (const [ trackId, info ] of this._localTrackInfos) {
- const track = info.rtpSender.track;
-
- // Check if any of the local tracks has been stopped.
- if (track.readyState === 'ended') {
- logger.debug(
- `_addStream() an already handled track was stopped, track.id:${track.id}`);
-
- try {
- info.rtpSender.stop();
- } catch (error) {
- logger.warn(`rtpSender.stop() failed:${error}`);
- }
-
- // Remove from the map.
- this._localTrackInfos.delete(track.id);
-
- // Also, if the stream was already handled, check whether tracks
- // have been removed via stream.removeTrack() and, if so, stop
- // their RtpSenders.
- } else if (info.stream === stream && !stream.getTrackById(trackId)) {
- logger.debug(
- `_addStream() a track in this stream was removed, track.id:${trackId}`);
-
- try {
- info.rtpSender.stop();
- } catch (error) {
- logger.warn(`rtpSender.stop() failed:${error}`);
- }
-
- // Remove from the map.
- this._localTrackInfos.delete(track.id);
- }
- }
-
- // It may need to renegotiate.
- this._emitNegotiationNeeded();
- }
-
- /**
- * Promise based implementation for createAnswer().
- * @returns {Promise}
- * @private
- */
- _createAnswer(options) { // eslint-disable-line no-unused-vars
- if (this._closed) {
- return Promise.reject(
- new InvalidStateError('RTCPeerConnection closed'));
- }
-
- if (this.signalingState !== RTCSignalingState.haveRemoteOffer) {
- return Promise.reject(new InvalidStateError(
- `invalid signalingState "${this.signalingState}"`));
- }
-
- // Create an answer.
- const localDescription = this._createLocalDescription('answer');
-
- // Resolve with it.
- return Promise.resolve(localDescription);
- }
-
- /**
- * Creates the local RTCSessionDescription.
- * @param {String} type - 'offer' / 'answer'.
- * @return {RTCSessionDescription}
- */
- _createLocalDescription(type) {
- const sdpObject = {};
- const localIceParameters = this._iceGatherer.getLocalParameters();
- const localIceCandidates = this._iceGatherer.getLocalCandidates();
- const localDtlsParameters = this._dtlsTransport.getLocalParameters();
- const remoteDtlsParameters = this._dtlsTransport.getRemoteParameters();
- const localCapabilities = this._localCapabilities;
- const localTrackInfos = this._localTrackInfos;
-
- // Increase SDP version if an offer.
- if (type === 'offer') {
- this._sdpGlobalFields.version++;
- }
-
- // SDP global fields.
- sdpObject.version = 0;
- sdpObject.origin = {
- address: '127.0.0.1',
- ipVer: 4,
- netType: 'IN',
- sessionId: this._sdpGlobalFields.id,
- sessionVersion: this._sdpGlobalFields.version,
- username: 'jitsi-ortc-webrtc-shim'
- };
- sdpObject.name = '-';
- sdpObject.timing = {
- start: 0,
- stop: 0
- };
- sdpObject.msidSemantic = {
- semantic: 'WMS',
- token: '*'
- };
- sdpObject.groups = [
- {
- mids: Array.from(this._mids.keys()).join(' '),
- type: 'BUNDLE'
- }
- ];
- sdpObject.media = [];
-
- // DTLS fingerprint.
- sdpObject.fingerprint = {
- hash: localDtlsParameters.fingerprints[0].value,
- type: localDtlsParameters.fingerprints[0].algorithm
- };
-
- // Let's check whether there is video RTX.
- let hasVideoRtx = false;
-
- for (const codec of localCapabilities.codecs) {
- if (codec.kind === 'video' && codec.name === 'rtx') {
- hasVideoRtx = true;
- break;
- }
- }
-
- // Add m= sections.
- for (const [ mid, kind ] of this._mids) {
- addMediaSection.call(this, mid, kind);
- }
-
- // Create a RTCSessionDescription.
- const localDescription = new RTCSessionDescription({
- type,
- _sdpObject: sdpObject
- });
-
- logger.debug('_createLocalDescription():', localDescription);
-
- return localDescription;
-
- /**
- * Add a m= section.
- */
- function addMediaSection(mid, kind) {
- const mediaObject = {};
-
- // m= line.
- mediaObject.type = kind;
-
- switch (kind) {
- case 'audio':
- case 'video':
- mediaObject.protocol = 'RTP/SAVPF';
- mediaObject.port = 9;
- mediaObject.direction = 'sendrecv';
- break;
- case 'application':
- mediaObject.protocol = 'DTLS/SCTP';
- mediaObject.port = 0; // Reject m section.
- mediaObject.payloads = '0'; // Just put something.
- mediaObject.direction = 'inactive';
- break;
- }
-
- // c= line.
- mediaObject.connection = {
- ip: '127.0.0.1',
- version: 4
- };
-
- // a=mid attribute.
- mediaObject.mid = mid;
-
- // ICE.
- mediaObject.iceUfrag = localIceParameters.usernameFragment;
- mediaObject.icePwd = localIceParameters.password;
- mediaObject.candidates = [];
-
- for (const candidate of localIceCandidates) {
- const candidateObject = {};
-
- // rtcp-mux is assumed, so component is always 1 (RTP).
- candidateObject.component = 1;
- candidateObject.foundation = candidate.foundation;
- candidateObject.ip = candidate.ip;
- candidateObject.port = candidate.port;
- candidateObject.priority = candidate.priority;
- candidateObject.transport
- = candidate.protocol.toLowerCase();
- candidateObject.type = candidate.type;
- if (candidateObject.transport === 'tcp') {
- candidateObject.tcptype = candidate.tcpType;
- }
-
- mediaObject.candidates.push(candidateObject);
- }
-
- mediaObject.endOfCandidates = 'end-of-candidates';
-
- // DTLS.
- // If 'offer' always use 'actpass'.
- if (type === 'offer') {
- mediaObject.setup = 'actpass';
- } else {
- mediaObject.setup = remoteDtlsParameters.role === 'server'
- ? 'active' : 'passive';
- }
-
- if (kind === 'audio' || kind === 'video') {
- mediaObject.rtp = [];
- mediaObject.rtcpFb = [];
- mediaObject.fmtp = [];
-
- // Array of payload types.
- const payloads = [];
-
- // Add codecs.
- for (const codec of localCapabilities.codecs) {
- if (codec.kind && codec.kind !== kind)
- continue;
-
- payloads.push(codec.preferredPayloadType);
-
- const rtpObject = {
- codec: codec.name,
- payload: codec.preferredPayloadType,
- rate: codec.clockRate
- };
-
- if (codec.numChannels > 1) {
- rtpObject.encoding = codec.numChannels;
- }
-
- mediaObject.rtp.push(rtpObject);
-
- // If codec has parameters add them into a=fmtp attributes.
- if (codec.parameters) {
- const paramFmtp = {
- config: '',
- payload: codec.preferredPayloadType
- };
-
- for (const name of Object.keys(codec.parameters)) {
- /* eslint-disable max-depth */
- if (paramFmtp.config) {
- paramFmtp.config += ';';
- }
- /* eslint-enable max-depth */
-
- paramFmtp.config
- += `${name}=${codec.parameters[name]}`;
- }
-
- if (paramFmtp.config) {
- mediaObject.fmtp.push(paramFmtp);
- }
- }
-
- // Set RTCP feedback.
- for (const fb of codec.rtcpFeedback || []) {
- mediaObject.rtcpFb.push({
- payload: codec.preferredPayloadType,
- subtype: fb.parameter || undefined,
- type: fb.type
- });
- }
- }
-
- // If there are no codecs, set this m section as unavailable.
- if (payloads.length === 0) {
- mediaObject.payloads = '9'; // Just put something.
- mediaObject.port = 0;
- mediaObject.direction = 'inactive';
- } else {
- mediaObject.payloads = payloads.join(' ');
- }
-
- // SSRCs.
- mediaObject.ssrcs = [];
- mediaObject.ssrcGroups = [];
-
- // Add RTP sending stuff.
- for (const info of localTrackInfos.values()) {
- const rtpSender = info.rtpSender;
- const streamId = info.stream.id;
- const track = rtpSender.track;
-
- // Ignore if ended.
- if (track.readyState === 'ended')
- continue;
-
- if (track.kind !== kind)
- continue;
-
- // Set a random provisional SSRC if not set.
- if (!info.ssrc) {
- info.ssrc = utils.randomNumber();
- }
-
- // Whether RTX should be enabled.
- const enableRtx = hasVideoRtx && track.kind === 'video';
-
- // Set a random provisional RTX SSRC if not set.
- if (enableRtx && !info.rtxSsrc) {
- info.rtxSsrc = info.ssrc + 1;
- }
-
- mediaObject.ssrcs.push({
- attribute: 'cname',
- id: info.ssrc,
- value: CNAME
- });
-
- mediaObject.ssrcs.push({
- attribute: 'msid',
- id: info.ssrc,
- value: `${streamId} ${track.id}`
- });
-
- mediaObject.ssrcs.push({
- attribute: 'mslabel',
- id: info.ssrc,
- value: streamId
- });
-
- mediaObject.ssrcs.push({
- attribute: 'label',
- id: info.ssrc,
- value: track.id
- });
-
- if (enableRtx) {
- mediaObject.ssrcs.push({
- attribute: 'cname',
- id: info.rtxSsrc,
- value: CNAME
- });
-
- mediaObject.ssrcs.push({
- attribute: 'msid',
- id: info.rtxSsrc,
- value: `${streamId} ${track.id}`
- });
-
- mediaObject.ssrcs.push({
- attribute: 'mslabel',
- id: info.rtxSsrc,
- value: streamId
- });
-
- mediaObject.ssrcs.push({
- attribute: 'label',
- id: info.rtxSsrc,
- value: track.id
- });
-
- mediaObject.ssrcGroups.push({
- semantics: 'FID',
- ssrcs: `${info.ssrc} ${info.rtxSsrc}`
- });
- }
- }
-
- // RTP header extensions.
- mediaObject.ext = [];
-
- for (const extension of localCapabilities.headerExtensions) {
- if (extension.kind && extension.kind !== kind)
- continue;
-
- mediaObject.ext.push({
- value: extension.preferredId,
- uri: extension.uri
- });
- }
-
- // a=rtcp-mux attribute.
- mediaObject.rtcpMux = 'rtcp-mux';
-
- // a=rtcp-rsize.
- mediaObject.rtcpRsize = 'rtcp-rsize';
- }
-
- // Add the media section.
- sdpObject.media.push(mediaObject);
- }
- }
-
- /**
- * Promise based implementation for createOffer().
- * @returns {Promise}
- * @private
- */
- _createOffer(options) { // eslint-disable-line no-unused-vars
- if (this._closed) {
- return Promise.reject(
- new InvalidStateError('RTCPeerConnection closed'));
- }
-
- if (this.signalingState !== RTCSignalingState.stable) {
- return Promise.reject(new InvalidStateError(
- `invalid signalingState "${this.signalingState}"`));
- }
-
- // NOTE: P2P mode not yet supported, so createOffer() should never be
- // called.
- // return Promise.reject(new Error('createoOffer() not yet supported'));
-
- // HACK: Create an offer assuming this is called before any
- // setRemoteDescription() and assuming that setLocalDescription()
- // wont be called with this offer.
-
- const sdpObject = {};
- const localIceParameters = this._iceGatherer.getLocalParameters();
- const localIceCandidates = this._iceGatherer.getLocalCandidates();
- const localDtlsParameters = this._dtlsTransport.getLocalParameters();
- const localCapabilities = RTCRtpReceiver.getCapabilities();
- const localTrackInfos = this._localTrackInfos;
- const mids = new Map([ ['audio', 'audio'], ['video', 'video'] ]);
-
- // SDP global fields.
- sdpObject.version = 0;
- sdpObject.origin = {
- address: '127.0.0.1',
- ipVer: 4,
- netType: 'IN',
- sessionId: this._sdpGlobalFields.id,
- sessionVersion: this._sdpGlobalFields.version,
- username: 'jitsi-ortc-webrtc-shim'
- };
- sdpObject.name = '-';
- sdpObject.timing = {
- start: 0,
- stop: 0
- };
- sdpObject.msidSemantic = {
- semantic: 'WMS',
- token: '*'
- };
- sdpObject.groups = [
- {
- mids: Array.from(mids.keys()).join(' '),
- type: 'BUNDLE'
- }
- ];
- sdpObject.media = [];
-
- // DTLS fingerprint.
- sdpObject.fingerprint = {
- hash: localDtlsParameters.fingerprints[0].value,
- type: localDtlsParameters.fingerprints[0].algorithm
- };
-
- // Let's check whether there is video RTX.
- let hasVideoRtx = false;
-
- for (const codec of localCapabilities.codecs) {
- if (codec.kind === 'video' && codec.name === 'rtx') {
- hasVideoRtx = true;
- break;
- }
- }
-
- // Add m= sections.
- for (const [ mid, kind ] of mids) {
- addMediaSection.call(this, mid, kind);
- }
-
- // Create a RTCSessionDescription.
- const localDescription = new RTCSessionDescription({
- type: 'offer',
- _sdpObject: sdpObject
- });
-
- logger.debug('_createLocalDescription():', localDescription);
-
- // Resolve with it.
- return Promise.resolve(localDescription);
-
- /**
- * Add a m= section.
- */
- function addMediaSection(mid, kind) {
- const mediaObject = {};
-
- // m= line.
- mediaObject.type = kind;
-
- switch (kind) {
- case 'audio':
- case 'video':
- mediaObject.protocol = 'RTP/SAVPF';
- mediaObject.port = 9;
- mediaObject.direction = 'sendrecv';
- break;
- case 'application':
- mediaObject.protocol = 'DTLS/SCTP';
- mediaObject.port = 0; // Reject m section.
- mediaObject.payloads = '0'; // Just put something.
- mediaObject.direction = 'inactive';
- break;
- }
-
- // c= line.
- mediaObject.connection = {
- ip: '127.0.0.1',
- version: 4
- };
-
- // a=mid attribute.
- mediaObject.mid = mid;
-
- // ICE.
- mediaObject.iceUfrag = localIceParameters.usernameFragment;
- mediaObject.icePwd = localIceParameters.password;
- mediaObject.candidates = [];
-
- for (const candidate of localIceCandidates) {
- const candidateObject = {};
-
- // rtcp-mux is assumed, so component is always 1 (RTP).
- candidateObject.component = 1;
- candidateObject.foundation = candidate.foundation;
- candidateObject.ip = candidate.ip;
- candidateObject.port = candidate.port;
- candidateObject.priority = candidate.priority;
- candidateObject.transport
- = candidate.protocol.toLowerCase();
- candidateObject.type = candidate.type;
- if (candidateObject.transport === 'tcp') {
- candidateObject.tcptype = candidate.tcpType;
- }
-
- mediaObject.candidates.push(candidateObject);
- }
-
- mediaObject.endOfCandidates = 'end-of-candidates';
-
- // DTLS.
- // 'offer' so always use 'actpass'.
- mediaObject.setup = 'actpass';
-
- if (kind === 'audio' || kind === 'video') {
- mediaObject.rtp = [];
- mediaObject.rtcpFb = [];
- mediaObject.fmtp = [];
-
- // Array of payload types.
- const payloads = [];
-
- // Add codecs.
- for (const codec of localCapabilities.codecs) {
- if (codec.kind && codec.kind !== kind)
- continue;
-
- payloads.push(codec.preferredPayloadType);
-
- const rtpObject = {
- codec: codec.name,
- payload: codec.preferredPayloadType,
- rate: codec.clockRate
- };
-
- if (codec.numChannels > 1) {
- rtpObject.encoding = codec.numChannels;
- }
-
- mediaObject.rtp.push(rtpObject);
-
- // If codec has parameters add them into a=fmtp attributes.
- if (codec.parameters) {
- const paramFmtp = {
- config: '',
- payload: codec.preferredPayloadType
- };
-
- for (const name of Object.keys(codec.parameters)) {
- /* eslint-disable max-depth */
- if (paramFmtp.config) {
- paramFmtp.config += ';';
- }
- /* eslint-enable max-depth */
-
- paramFmtp.config
- += `${name}=${codec.parameters[name]}`;
- }
-
- if (paramFmtp.config) {
- mediaObject.fmtp.push(paramFmtp);
- }
- }
-
- // Set RTCP feedback.
- for (const fb of codec.rtcpFeedback || []) {
- mediaObject.rtcpFb.push({
- payload: codec.preferredPayloadType,
- subtype: fb.parameter || undefined,
- type: fb.type
- });
- }
- }
-
- // If there are no codecs, set this m section as unavailable.
- if (payloads.length === 0) {
- mediaObject.payloads = '9'; // Just put something.
- mediaObject.port = 0;
- mediaObject.direction = 'inactive';
- } else {
- mediaObject.payloads = payloads.join(' ');
- }
-
- // SSRCs.
- mediaObject.ssrcs = [];
- mediaObject.ssrcGroups = [];
-
- // Add RTP sending stuff.
- for (const info of localTrackInfos.values()) {
- const rtpSender = info.rtpSender;
- const streamId = info.stream.id;
- const track = rtpSender.track;
-
- // Ignore if ended.
- if (track.readyState === 'ended')
- continue;
-
- if (track.kind !== kind)
- continue;
-
- // Set a random provisional SSRC if not set.
- if (!info.ssrc) {
- info.ssrc = utils.randomNumber();
- }
-
- // Whether RTX should be enabled.
- const enableRtx = hasVideoRtx && track.kind === 'video';
-
- // Set a random provisional RTX SSRC if not set.
- if (enableRtx && !info.rtxSsrc) {
- info.rtxSsrc = info.ssrc + 1;
- }
-
- mediaObject.ssrcs.push({
- attribute: 'cname',
- id: info.ssrc,
- value: CNAME
- });
-
- mediaObject.ssrcs.push({
- attribute: 'msid',
- id: info.ssrc,
- value: `${streamId} ${track.id}`
- });
-
- mediaObject.ssrcs.push({
- attribute: 'mslabel',
- id: info.ssrc,
- value: streamId
- });
-
- mediaObject.ssrcs.push({
- attribute: 'label',
- id: info.ssrc,
- value: track.id
- });
-
- if (enableRtx) {
- mediaObject.ssrcs.push({
- attribute: 'cname',
- id: info.rtxSsrc,
- value: CNAME
- });
-
- mediaObject.ssrcs.push({
- attribute: 'msid',
- id: info.rtxSsrc,
- value: `${streamId} ${track.id}`
- });
-
- mediaObject.ssrcs.push({
- attribute: 'mslabel',
- id: info.rtxSsrc,
- value: streamId
- });
-
- mediaObject.ssrcs.push({
- attribute: 'label',
- id: info.rtxSsrc,
- value: track.id
- });
-
- mediaObject.ssrcGroups.push({
- semantics: 'FID',
- ssrcs: `${info.ssrc} ${info.rtxSsrc}`
- });
- }
- }
-
- // RTP header extensions.
- mediaObject.ext = [];
-
- for (const extension of localCapabilities.headerExtensions) {
- if (extension.kind && extension.kind !== kind)
- continue;
-
- mediaObject.ext.push({
- value: extension.preferredId,
- uri: extension.uri
- });
- }
-
- // a=rtcp-mux attribute.
- mediaObject.rtcpMux = 'rtcp-mux';
-
- // a=rtcp-rsize.
- mediaObject.rtcpRsize = 'rtcp-rsize';
- }
-
- // Add the media section.
- sdpObject.media.push(mediaObject);
- }
- }
-
- /**
- * Emit 'addstream' event.
- * @private
- */
- _emitAddStream(stream) {
- if (this._closed) {
- return;
- }
-
- logger.debug('emitting "addstream"');
-
- const event = new yaeti.Event('addstream');
-
- event.stream = stream;
- this.dispatchEvent(event);
- }
-
- /**
- * May emit buffered ICE candidates.
- * @private
- */
- _emitBufferedIceCandidates() {
- if (this._closed) {
- return;
- }
-
- for (const sdpCandidate of this._bufferedIceCandidates) {
- if (!sdpCandidate)
- continue;
-
- // Now we have set the MID values of the SDP O/A, so let's fill the
- // sdpMIndex of the candidate.
- sdpCandidate.sdpMIndex = this._mids.keys().next().value;
-
- logger.debug(
- 'emitting buffered "icecandidate", candidate:', sdpCandidate);
-
- const event = new yaeti.Event('icecandidate');
-
- event.candidate = sdpCandidate;
- this.dispatchEvent(event);
- }
-
- this._bufferedIceCandidates = [];
- }
-
- /**
- * May emit 'connectionstatechange' event.
- * @private
- */
- _emitConnectionStateChange() {
- if (this._closed && this.connectionState !== 'closed') {
- return;
- }
-
- logger.debug(
- 'emitting "connectionstatechange", connectionState:',
- this.connectionState);
-
- const event = new yaeti.Event('connectionstatechange');
-
- this.dispatchEvent(event);
- }
-
- /**
- * May emit 'icecandidate' event.
- * @private
- */
- _emitIceCandidate(candidate) {
- if (this._closed) {
- return;
- }
-
- let sdpCandidate = null;
-
- if (candidate) {
- // NOTE: We assume BUNDLE so let's just emit candidates for the
- // first m= section.
- const sdpMIndex = this._mids.keys().next().value;
- const sdpMLineIndex = 0;
- let sdpAttribute
- = `candidate:${candidate.foundation} 1 ${candidate.protocol}`
- + ` ${candidate.priority} ${candidate.ip} ${candidate.port}`
- + ` typ ${candidate.type}`;
-
- if (candidate.relatedAddress) {
- sdpAttribute += ` raddr ${candidate.relatedAddress}`;
- }
- if (candidate.relatedPort) {
- sdpAttribute += ` rport ${candidate.relatedPort}`;
- }
- if (candidate.protocol === 'tcp') {
- sdpAttribute += ` tcptype ${candidate.tcpType}`;
- }
-
- sdpCandidate = {
- candidate: sdpAttribute,
- component: 1, // rtcp-mux assumed, so always 1 (RTP).
- foundation: candidate.foundation,
- ip: candidate.ip,
- port: candidate.port,
- priority: candidate.priority,
- protocol: candidate.protocol,
- type: candidate.type,
- sdpMIndex,
- sdpMLineIndex
- };
-
- if (candidate.protocol === 'tcp') {
- sdpCandidate.tcptype = candidate.tcpType;
- }
- if (candidate.relatedAddress) {
- sdpCandidate.relatedAddress = candidate.relatedAddress;
- }
- if (candidate.relatedPort) {
- sdpCandidate.relatedPort = candidate.relatedPort;
- }
- }
-
- // If we don't have yet a local description, buffer the candidate.
- if (this._localDescription) {
- logger.debug(
- 'emitting "icecandidate", candidate:', sdpCandidate);
-
- const event = new yaeti.Event('icecandidate');
-
- event.candidate = sdpCandidate;
- this.dispatchEvent(event);
- } else {
- logger.debug(
- 'buffering gathered ICE candidate:', sdpCandidate);
-
- this._bufferedIceCandidates.push(sdpCandidate);
- }
- }
-
- /**
- * May emit 'iceconnectionstatechange' event.
- * @private
- */
- _emitIceConnectionStateChange() {
- if (this._closed && this.iceConnectionState !== 'closed') {
- return;
- }
-
- logger.debug(
- 'emitting "iceconnectionstatechange", iceConnectionState:',
- this.iceConnectionState);
-
- const event = new yaeti.Event('iceconnectionstatechange');
-
- this.dispatchEvent(event);
- }
-
- /**
- * May emit 'negotiationneeded' event.
- * @private
- */
- _emitNegotiationNeeded() {
- // Ignore if signalingState is not 'stable'.
- if (this.signalingState !== RTCSignalingState.stable) {
- return;
- }
-
- logger.debug('emitting "negotiationneeded"');
-
- const event = new yaeti.Event('negotiationneeded');
-
- this.dispatchEvent(event);
- }
-
- /**
- * Emit 'removestream' event.
- * @private
- */
- _emitRemoveStream(stream) {
- if (this._closed) {
- return;
- }
-
- logger.debug('emitting "removestream"');
-
- const event = new yaeti.Event('removestream');
-
- event.stream = stream;
- this.dispatchEvent(event);
- }
-
- /**
- * Get RTP parameters for a RTCRtpReceiver.
- * @private
- * @return {RTCRtpParameters}
- */
- _getParametersForRtpReceiver(kind, data) {
- const ssrc = data.ssrc;
- const rtxSsrc = data.rtxSsrc;
- const cname = data.cname;
- const localCapabilities = this._localCapabilities;
- const parameters = {
- codecs: [],
- degradationPreference: 'balanced',
- encodings: [],
- headerExtensions: [],
- muxId: '',
- rtcp: {
- cname,
- compound: true, // NOTE: Implemented in Edge.
- mux: true,
- reducedSize: true // NOTE: Not yet implemented in Edge.
- }
- };
-
- const codecs = [];
- let codecPayloadType;
-
- for (const codecCapability of localCapabilities.codecs)
- {
- if (codecCapability.kind !== kind
- || codecCapability.name === 'rtx')
- {
- continue;
- }
-
- codecPayloadType = codecCapability.preferredPayloadType;
- codecs.push({
- clockRate: codecCapability.clockRate,
- maxptime: codecCapability.maxptime,
- mimeType: codecCapability.mimeType,
- name: codecCapability.name,
- numChannels: codecCapability.numChannels,
- parameters: codecCapability.parameters,
- payloadType: codecCapability.preferredPayloadType,
- ptime: codecCapability.ptime,
- rtcpFeedback: codecCapability.rtcpFeedback
- });
-
- break;
- }
-
- if (rtxSsrc) {
- for (const codecCapability of localCapabilities.codecs)
- {
- if (codecCapability.kind !== kind
- || codecCapability.name !== 'rtx')
- {
- continue;
- }
-
- codecs.push({
- clockRate: codecCapability.clockRate,
- mimeType: codecCapability.mimeType,
- name: 'rtx',
- parameters: codecCapability.parameters,
- payloadType: codecCapability.preferredPayloadType,
- rtcpFeedback: codecCapability.rtcpFeedback
- });
-
- break;
- }
- }
-
- parameters.codecs = codecs;
-
- const encoding = {
- active: true,
- codecPayloadType,
- ssrc
- };
-
- if (rtxSsrc) {
- encoding.rtx = {
- ssrc: rtxSsrc
- };
- }
-
- parameters.encodings.push(encoding);
-
- for (const extension of localCapabilities.headerExtensions)
- {
- if (extension.kind !== kind)
- continue;
-
- parameters.headerExtensions.push({
- encrypt: extension.preferredEncrypt,
- id: extension.preferredId,
- uri: extension.uri
- });
- }
-
- return parameters;
- }
-
- /**
- * Get RTP parameters for a RTCRtpSender.
- * @private
- * @return {RTCRtpParameters}
- */
- _getParametersForRtpSender(kind, data) {
- const ssrc = data.ssrc;
- const rtxSsrc = data.rtxSsrc;
- const cname = CNAME;
- const localCapabilities = this._localCapabilities;
- const parameters = {
- codecs: [],
- degradationPreference: 'balanced',
- encodings: [],
- headerExtensions: [],
- muxId: '',
- rtcp: {
- cname,
- compound: true, // NOTE: Implemented in Edge.
- mux: true,
- reducedSize: true // NOTE: Not yet implemented in Edge.
- }
- };
-
- const codecs = [];
- let codecPayloadType;
-
- for (const codecCapability of localCapabilities.codecs) {
- if (codecCapability.kind !== kind
- || codecCapability.name === 'rtx')
- {
- continue;
- }
-
- codecPayloadType = codecCapability.preferredPayloadType;
- codecs.push({
- clockRate: codecCapability.clockRate,
- maxptime: codecCapability.maxptime,
- mimeType: codecCapability.mimeType,
- name: codecCapability.name,
- numChannels: codecCapability.numChannels,
- parameters: codecCapability.parameters,
- payloadType: codecCapability.preferredPayloadType,
- ptime: codecCapability.ptime,
- rtcpFeedback: codecCapability.rtcpFeedback
- });
-
- break;
- }
-
- if (rtxSsrc) {
- for (const codecCapability of localCapabilities.codecs) {
- if (codecCapability.kind !== kind
- || codecCapability.name !== 'rtx')
- {
- continue;
- }
-
- codecs.push({
- clockRate: codecCapability.clockRate,
- mimeType: codecCapability.mimeType,
- name: 'rtx',
- parameters: codecCapability.parameters,
- payloadType: codecCapability.preferredPayloadType,
- rtcpFeedback: codecCapability.rtcpFeedback
- });
-
- break;
- }
- }
-
- parameters.codecs = codecs;
-
- const encoding = {
- active: true,
- codecPayloadType,
- ssrc
- };
-
- if (rtxSsrc) {
- encoding.rtx = {
- ssrc: rtxSsrc
- };
- }
-
- parameters.encodings.push(encoding);
-
- for (const extension of localCapabilities.headerExtensions) {
- if (extension.kind !== kind)
- continue;
-
- parameters.headerExtensions.push({
- encrypt: extension.preferredEncrypt,
- id: extension.preferredId,
- uri: extension.uri
- });
- }
-
- return parameters;
- }
-
- /**
- * Promise based implementation for getStats().
- * @return {Promise}
- * @private
- */
- _getStats(selector) { // eslint-disable-line no-unused-vars
- if (this._closed) {
- return Promise.reject(
- new InvalidStateError('RTCPeerConnection closed'));
- }
-
- // TODO: TBD
- return Promise.reject(new Error('getStats() not yet implemented'));
- }
-
- /**
- * Handles the local initial answer.
- * @return {Promise}
- * @private
- */
- _handleLocalInitialAnswer(desc) {
- logger.debug('_handleLocalInitialAnswer(), desc:', desc);
-
- const sdpObject = desc.sdpObject;
-
- // Update local capabilities as decided by the app.
- this._localCapabilities = ortcUtils.extractCapabilities(sdpObject);
-
- logger.debug('local capabilities:', this._localCapabilities);
-
- // TODO: Should inspect the answer given by the app and update our
- // sending RTP parameters if, for example, the app modified SSRC
- // values.
- }
-
- /**
- * Handles a local re-answer.
- * @return {Promise}
- * @private
- */
- _handleLocalReAnswer(desc) {
- logger.debug('_handleLocalReAnswer(), desc:', desc);
-
- const sdpObject = desc.sdpObject;
-
- // Update local capabilities as decided by the app.
- this._localCapabilities = ortcUtils.extractCapabilities(sdpObject);
-
- logger.debug('local capabilities:', this._localCapabilities);
-
- // TODO: Should inspect the answer given by the app and update our
- // sending RTP parameters if, for example, the app modified SSRC
- // values.
- }
-
- /**
- * Handles the remote initial offer.
- * @return {Promise}
- * @private
- */
- _handleRemoteInitialOffer(desc) {
- logger.debug('_handleRemoteInitialOffer(), desc:', desc);
-
- const sdpObject = desc.sdpObject;
-
- // Set MID values.
- this._mids = ortcUtils.extractMids(sdpObject);
-
- // Get remote RTP capabilities.
- const remoteCapabilities = ortcUtils.extractCapabilities(sdpObject);
-
- logger.debug('remote capabilities:', remoteCapabilities);
-
- // Get local RTP capabilities (filter them with remote capabilities).
- this._localCapabilities
- = ortcUtils.getLocalCapabilities(remoteCapabilities);
-
- // Start ICE and DTLS.
- this._startIceAndDtls(desc);
- }
-
- /**
- * Handles a remote re-offer.
- * @return {Promise}
- * @private
- */
- _handleRemoteReOffer(desc) {
- logger.debug('_handleRemoteReOffer(), desc:', desc);
-
- const sdpObject = desc.sdpObject;
-
- // Update MID values (just in case).
- this._mids = ortcUtils.extractMids(sdpObject);
-
- // Get remote RTP capabilities (filter them with remote capabilities).
- const remoteCapabilities = ortcUtils.extractCapabilities(sdpObject);
-
- logger.debug('remote capabilities:', remoteCapabilities);
-
- // Update local RTP capabilities (just in case).
- this._localCapabilities
- = ortcUtils.getLocalCapabilities(remoteCapabilities);
- }
-
- /**
- * Start receiving remote media.
- */
- _receiveMedia() {
- logger.debug('_receiveMedia()');
-
- const currentRemoteSsrcs = new Set(this._remoteTrackInfos.keys());
- const newRemoteTrackInfos
- = ortcUtils.extractTrackInfos(this._remoteDescription.sdpObject);
-
- // Map of new remote MediaStream indexed by MediaStream.jitsiRemoteId.
- const addedRemoteStreams = new Map();
-
- // Map of remote MediaStream indexed by added MediaStreamTrack.
- // NOTE: Just filled for already existing streams.
- const addedRemoteTracks = new Map();
-
- // Map of remote MediaStream indexed by removed MediaStreamTrack.
- const removedRemoteTracks = new Map();
-
- logger.debug(
- '_receiveMedia() remote track infos:', newRemoteTrackInfos);
-
- // Check new tracks.
- for (const [ ssrc, info ] of newRemoteTrackInfos) {
- // If already handled, ignore it.
- if (currentRemoteSsrcs.has(ssrc))
- continue;
-
- logger.debug(`_receiveMedia() new remote track, ssrc:${ssrc}`);
-
- // Otherwise append to the map.
- this._remoteTrackInfos.set(ssrc, info);
-
- const kind = info.kind;
- const rtxSsrc = info.rtxSsrc;
- const streamRemoteId = info.streamId;
- const trackRemoteId = info.trackId;
- const cname = info.cname;
- const isNewStream = !this._remoteStreams.has(streamRemoteId);
- let stream;
-
- if (isNewStream) {
- logger.debug(
- `_receiveMedia() new remote stream, id:${streamRemoteId}`);
-
- // Create a new MediaStream.
- stream = new MediaStream();
-
- // Set custom property with the remote id.
- stream.jitsiRemoteId = streamRemoteId;
-
- addedRemoteStreams.set(streamRemoteId, stream);
- this._remoteStreams.set(streamRemoteId, stream);
- } else {
- stream = this._remoteStreams.get(streamRemoteId);
- }
-
- const rtpReceiver = new RTCRtpReceiver(this._dtlsTransport, kind);
- const parameters = this._getParametersForRtpReceiver(kind, {
- ssrc,
- rtxSsrc,
- cname
- });
-
- // Store the track into the info object.
- // NOTE: This should not be needed, but Edge has a bug:
- // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12399497/
- info.track = rtpReceiver.track;
-
- // Set error handler.
- rtpReceiver.onerror = ev => {
- logger.error('rtpReceiver "error" event, event:');
- logger.error(ev);
- };
-
- // Fill the info with the stream and rtpReceiver.
- info.stream = stream;
- info.rtpReceiver = rtpReceiver;
-
- logger.debug(
- 'calling rtpReceiver.receive(), parameters:', parameters);
-
- // Start receiving media.
- try {
- rtpReceiver.receive(parameters);
-
- // Get the associated MediaStreamTrack.
- const track = info.track;
-
- // Set custom property with the remote id.
- track.jitsiRemoteId = trackRemoteId;
-
- // Add the track to the stream.
- stream.addTrack(track);
-
- if (!addedRemoteStreams.has(streamRemoteId)) {
- addedRemoteTracks.set(track, stream);
- }
- } catch (error) {
- logger.error(`rtpReceiver.receive() failed:${error.message}`);
- logger.error(error);
- }
- }
-
- // Check track removal.
- for (const ssrc of currentRemoteSsrcs) {
- if (newRemoteTrackInfos.has(ssrc))
- continue;
-
- logger.debug(`_receiveMedia() remote track removed, ssrc:${ssrc}`);
-
- const info = this._remoteTrackInfos.get(ssrc);
- const stream = info.stream;
- const track = info.track;
- const rtpReceiver = info.rtpReceiver;
-
- try {
- rtpReceiver.stop();
- } catch (error) {
- logger.warn(`rtpReceiver.stop() failed:${error}`);
- }
-
- removedRemoteTracks.set(track, stream);
- stream.removeTrack(track);
- this._remoteTrackInfos.delete(ssrc);
- }
-
- // Emit MediaStream 'addtrack' for new tracks in already existing
- // streams.
- for (const [ track, stream ] of addedRemoteTracks) {
- const event = new Event('addtrack');
-
- event.track = track;
- stream.dispatchEvent(event);
- }
-
- // Emit MediaStream 'removetrack' for removed tracks.
- for (const [ track, stream ] of removedRemoteTracks) {
- const event = new Event('removetrack');
-
- event.track = track;
- stream.dispatchEvent(event);
- }
-
- // Emit RTCPeerConnection 'addstream' for new remote streams.
- for (const stream of addedRemoteStreams.values()) {
- // Check whether at least a track was added, otherwise ignore it.
- if (stream.getTracks().length === 0) {
- logger.warn(
- 'ignoring new stream for which no track could be added');
-
- addedRemoteStreams.delete(stream.jitsiRemoteId);
- this._remoteStreams.delete(stream.jitsiRemoteId);
- } else {
- this._emitAddStream(stream);
- }
- }
-
- // Emit RTCPeerConnection 'removestream' for removed remote streams.
- for (const [ streamRemoteId, stream ] of this._remoteStreams) {
- if (stream.getTracks().length > 0)
- continue;
-
- this._remoteStreams.delete(streamRemoteId);
- this._emitRemoveStream(stream);
- }
- }
-
- /**
- * Implementation for removeStream().
- * @private
- */
- _removeStream(stream) {
- if (this._closed) {
- throw new InvalidStateError('RTCPeerConnection closed');
- }
-
- // Stop and remove the RTCRtpSender associated to each track.
- for (const track of stream.getTracks()) {
- // Ignore if track not present.
- if (!this._localTrackInfos.has(track.id))
- continue;
-
- const rtpSender = this._localTrackInfos.get(track.id).rtpSender;
-
- try {
- rtpSender.stop();
- } catch (error) {
- logger.warn(`rtpSender.stop() failed:${error}`);
- }
-
- // Remove from the map.
- this._localTrackInfos.delete(track.id);
- }
-
- // It may need to renegotiate.
- this._emitNegotiationNeeded();
- }
-
- /**
- * Start sending our media to the remote.
- */
- _sendMedia() {
- logger.debug('_sendMedia()');
-
- for (const info of this._localTrackInfos.values()) {
- // Ignore if already sending.
- if (info.sending)
- continue;
-
- const rtpSender = info.rtpSender;
- const ssrc = info.ssrc;
- const rtxSsrc = info.rtxSsrc;
- const track = rtpSender.track;
- const kind = track.kind;
-
- const parameters = this._getParametersForRtpSender(kind, {
- ssrc,
- rtxSsrc
- });
-
- logger.debug(
- 'calling rtpSender.send(), parameters:', parameters);
-
- // Start sending media.
- try {
- rtpSender.send(parameters);
-
- // Update sending field.
- info.sending = true;
- } catch (error) {
- logger.error(`rtpSender.send() failed:${error.message}`);
- logger.error(error);
- }
- }
- }
-
- /**
- * Creates the RTCDtlsTransport.
- * @private
- */
- _setDtlsTransport(iceTransport) {
- const dtlsTransport = new RTCDtlsTransport(iceTransport);
-
- // NOTE: Not yet implemented by Edge.
- dtlsTransport.onstatechange = () => {
- logger.debug(
- 'dtlsTransport "statechange" event, '
- + `state:${dtlsTransport.state}`);
-
- this._emitConnectionStateChange();
- };
-
- // NOTE: Not standard, but implemented by Edge.
- dtlsTransport.ondtlsstatechange = () => {
- logger.debug(
- 'dtlsTransport "dtlsstatechange" event, '
- + `state:${dtlsTransport.state}`);
-
- this._emitConnectionStateChange();
- };
-
- dtlsTransport.onerror = ev => {
- let message;
-
- if (ev.message) {
- message = ev.message;
- } else if (ev.error) {
- message = ev.error.message;
- }
-
- logger.error(`dtlsTransport "error" event, message:${message}`);
-
- // TODO: Edge does not set state to 'failed' on error. We should
- // hack it.
-
- this._emitConnectionStateChange();
- };
-
- this._dtlsTransport = dtlsTransport;
- }
-
- /**
- * Creates the RTCIceGatherer.
- * @private
- */
- _setIceGatherer(pcConfig) {
- const iceGatherOptions = {
- gatherPolicy: pcConfig.iceTransportPolicy || 'all',
- iceServers: pcConfig.iceServers || []
- };
- const iceGatherer = new RTCIceGatherer(iceGatherOptions);
-
- // NOTE: Not yet implemented by Edge.
- iceGatherer.onstatechange = () => {
- logger.debug(
- `iceGatherer "statechange" event, state:${iceGatherer.state}`);
-
- this._updateAndEmitIceGatheringStateChange(iceGatherer.state);
- };
-
- iceGatherer.onlocalcandidate = ev => {
- let candidate = ev.candidate;
-
- // NOTE: Not yet implemented by Edge.
- const complete = ev.complete;
-
- logger.debug(
- 'iceGatherer "localcandidate" event, candidate:', candidate);
-
- // NOTE: Instead of null candidate or complete:true, current Edge
- // signals end of gathering with an empty candidate object.
- if (complete
- || !candidate
- || Object.keys(candidate).length === 0) {
-
- candidate = null;
-
- this._updateAndEmitIceGatheringStateChange(
- RTCIceGatheringState.complete);
- this._emitIceCandidate(null);
- } else {
- this._emitIceCandidate(candidate);
- }
- };
-
- iceGatherer.onerror = ev => {
- const errorCode = ev.errorCode;
- const errorText = ev.errorText;
-
- logger.error(
- `iceGatherer "error" event, errorCode:${errorCode}, `
- + `errorText:${errorText}`);
- };
-
- // NOTE: Not yet implemented by Edge, which starts gathering
- // automatically.
- try {
- iceGatherer.gather();
- } catch (error) {
- logger.warn(`iceGatherer.gather() failed:${error}`);
- }
-
- this._iceGatherer = iceGatherer;
- }
-
- /**
- * Creates the RTCIceTransport.
- * @private
- */
- _setIceTransport(iceGatherer) {
- const iceTransport = new RTCIceTransport(iceGatherer);
-
- // NOTE: Not yet implemented by Edge.
- iceTransport.onstatechange = () => {
- logger.debug(
- 'iceTransport "statechange" event, '
- + `state:${iceTransport.state}`);
-
- this._emitIceConnectionStateChange();
- };
-
- // NOTE: Not standard, but implemented by Edge.
- iceTransport.onicestatechange = () => {
- logger.debug(
- 'iceTransport "icestatechange" event, '
- + `state:${iceTransport.state}`);
-
- if (iceTransport.state === 'completed') {
- logger.debug(
- 'nominated candidate pair:',
- iceTransport.getNominatedCandidatePair());
- }
-
- this._emitIceConnectionStateChange();
- };
-
- iceTransport.oncandidatepairchange = ev => {
- logger.debug(
- 'iceTransport "candidatepairchange" event, '
- + `pair:${ev.pair}`);
- };
-
- this._iceTransport = iceTransport;
- }
-
- /**
- * Promise based implementation for setLocalDescription().
- * @returns {Promise}
- * @private
- */
- _setLocalDescription(desc) {
- if (this._closed) {
- return Promise.reject(
- new InvalidStateError('RTCPeerConnection closed'));
- }
-
- let localDescription;
-
- try {
- localDescription = new RTCSessionDescription(desc);
- } catch (error) {
- return Promise.reject(new TypeError(
- `invalid RTCSessionDescriptionInit: ${error}`));
- }
-
- switch (desc.type) {
- case 'offer': {
- if (this.signalingState !== RTCSignalingState.stable) {
- return Promise.reject(new InvalidStateError(
- `invalid signalingState "${this.signalingState}"`));
- }
-
- // NOTE: P2P mode not yet supported, so createOffer() should never
- // has been called, neither setLocalDescription() with an offer.
- return Promise.reject(new TypeError(
- 'setLocalDescription() with type "offer" not supported'));
- }
- case 'answer': {
- if (this.signalingState !== RTCSignalingState.haveRemoteOffer) {
- return Promise.reject(new InvalidStateError(
- `invalid signalingState "${this.signalingState}"`));
- }
-
- const isLocalInitialAnswer = Boolean(!this._localDescription);
-
- return Promise.resolve()
- .then(() => {
- // Different handling for initial answer and re-answer.
- if (isLocalInitialAnswer) {
- return this._handleLocalInitialAnswer(localDescription);
- } else { // eslint-disable-line no-else-return
- return this._handleLocalReAnswer(localDescription);
- }
- })
- .then(() => {
- logger.debug('setLocalDescription() succeed');
-
- // Update local description.
- this._localDescription = localDescription;
-
- // Update signaling state.
- this._updateAndEmitSignalingStateChange(
- RTCSignalingState.stable);
-
- // If initial answer, emit buffered ICE candidates.
- if (isLocalInitialAnswer) {
- this._emitBufferedIceCandidates();
- }
-
- // Send our RTP.
- this._sendMedia();
-
- // Receive remote RTP.
- this._receiveMedia();
- })
- .catch(error => {
- logger.error(
- `setLocalDescription() failed: ${error.message}`);
- logger.error(error);
-
- throw error;
- });
- }
- default:
- return Promise.reject(new TypeError(
- `unsupported description.type "${desc.type}"`));
- }
- }
-
- /**
- * Promise based implementation for setRemoteDescription().
- * @returns {Promise}
- * @private
- */
- _setRemoteDescription(desc) {
- if (this._closed) {
- return Promise.reject(
- new InvalidStateError('RTCPeerConnection closed'));
- }
-
- let remoteDescription;
-
- try {
- remoteDescription = new RTCSessionDescription(desc);
- } catch (error) {
- return Promise.reject(new TypeError(
- `invalid RTCSessionDescriptionInit: ${error}`));
- }
-
- switch (desc.type) {
- case 'offer': {
- if (this.signalingState !== RTCSignalingState.stable) {
- return Promise.reject(new InvalidStateError(
- `invalid signalingState "${this.signalingState}"`));
- }
-
- const isRemoteInitialOffer = Boolean(!this._remoteDescription);
-
- return Promise.resolve()
- .then(() => {
- // Different handling for initial answer and re-answer.
- if (isRemoteInitialOffer) {
- return this._handleRemoteInitialOffer(
- remoteDescription);
- } else { // eslint-disable-line no-else-return
- return this._handleRemoteReOffer(remoteDescription);
- }
- })
- .then(() => {
- logger.debug('setRemoteDescription() succeed');
-
- // Update remote description.
- this._remoteDescription = remoteDescription;
-
- // Update signaling state.
- this._updateAndEmitSignalingStateChange(
- RTCSignalingState.haveRemoteOffer);
- })
- .catch(error => {
- logger.error(`setRemoteDescription() failed: ${error}`);
-
- throw error;
- });
- }
- case 'answer': {
- if (this.signalingState !== RTCSignalingState.haveLocalOffer) {
- return Promise.reject(new InvalidStateError(
- `invalid signalingState "${this.signalingState}"`));
- }
-
- // NOTE: P2P mode not yet supported, so createOffer() should never
- // has been called, neither setRemoteDescription() with an answer.
- return Promise.reject(new TypeError(
- 'setRemoteDescription() with type "answer" not supported'));
- }
- default:
- return Promise.reject(new TypeError(
- `unsupported description.type "${desc.type}"`));
- }
- }
-
- /**
- * Start ICE and DTLS connection procedures.
- * @param {RTCSessionDescription} desc - Remote description.
- */
- _startIceAndDtls(desc) {
- const sdpObject = desc.sdpObject;
- const remoteIceParameters
- = ortcUtils.extractIceParameters(sdpObject);
- const remoteIceCandidates
- = ortcUtils.extractIceCandidates(sdpObject);
- const remoteDtlsParameters
- = ortcUtils.extractDtlsParameters(sdpObject);
-
- // Start the RTCIceTransport.
- switch (desc.type) {
- case 'offer':
- this._iceTransport.start(
- this._iceGatherer, remoteIceParameters, 'controlled');
- break;
- case 'answer':
- this._iceTransport.start(
- this._iceGatherer, remoteIceParameters, 'controlling');
- break;
- }
-
- // Add remote ICE candidates.
- // NOTE: Remove candidates that Edge doesn't like.
- for (const candidate of remoteIceCandidates) {
- if (candidate.port === 0 || candidate.port === 9)
- continue;
-
- this._iceTransport.addRemoteCandidate(candidate);
- }
-
- // Also signal a 'complete' candidate as per spec.
- // NOTE: It should be {complete: true} but Edge prefers {}.
- // NOTE: We know that addCandidate() is never used so we need to signal
- // end of candidates (otherwise the RTCIceTransport never enters the
- // 'completed' state).
- this._iceTransport.addRemoteCandidate({});
-
- // Set desired remote DTLS role (as we receive the offer).
- switch (desc.type) {
- case 'offer':
- remoteDtlsParameters.role = 'server';
- break;
- case 'answer':
- remoteDtlsParameters.role = 'client';
- break;
- }
-
- // Start RTCDtlsTransport.
- this._dtlsTransport.start(remoteDtlsParameters);
- }
-
- /**
- * May update iceGatheringState and emit 'icegatheringstatechange' event.
- * @private
- */
- _updateAndEmitIceGatheringStateChange(state) {
- if (this._closed || state === this.iceGatheringState) {
- return;
- }
-
- this._iceGatheringState = state;
-
- logger.debug(
- 'emitting "icegatheringstatechange", iceGatheringState:',
- this.iceGatheringState);
-
- const event = new yaeti.Event('icegatheringstatechange');
-
- this.dispatchEvent(event);
- }
-
- /**
- * May update signalingState and emit 'signalingstatechange' event.
- * @private
- */
- _updateAndEmitSignalingStateChange(state) {
- if (state === this.signalingState) {
- return;
- }
-
- this._signalingState = state;
-
- logger.debug(
- 'emitting "signalingstatechange", signalingState:',
- this.signalingState);
-
- const event = new yaeti.Event('signalingstatechange');
-
- this.dispatchEvent(event);
- }
-}
diff --git a/app/lib/edge/RTCSessionDescription.js b/app/lib/edge/RTCSessionDescription.js
deleted file mode 100644
index 62b91f5..0000000
--- a/app/lib/edge/RTCSessionDescription.js
+++ /dev/null
@@ -1,105 +0,0 @@
-import sdpTransform from 'sdp-transform';
-
-/**
- * RTCSessionDescription implementation.
- */
-export default class RTCSessionDescription {
- /**
- * RTCSessionDescription constructor.
- * @param {Object} [data]
- * @param {String} [data.type] - 'offer' / 'answer'.
- * @param {String} [data.sdp] - SDP string.
- * @param {Object} [data._sdpObject] - SDP object generated by the
- * sdp-transform library.
- */
- constructor(data) {
- // @type {String}
- this._sdp = null;
-
- // @type {Object}
- this._sdpObject = null;
-
- // @type {String}
- this._type = null;
-
- switch (data.type) {
- case 'offer':
- break;
- case 'answer':
- break;
- default:
- throw new TypeError(`invalid type "${data.type}"`);
- }
-
- this._type = data.type;
-
- if (typeof data.sdp === 'string') {
- this._sdp = data.sdp;
- try {
- this._sdpObject = sdpTransform.parse(data.sdp);
- } catch (error) {
- throw new Error(`invalid sdp: ${error}`);
- }
- } else if (typeof data._sdpObject === 'object') {
- this._sdpObject = data._sdpObject;
- try {
- this._sdp = sdpTransform.write(data._sdpObject);
- } catch (error) {
- throw new Error(`invalid sdp object: ${error}`);
- }
- } else {
- throw new TypeError('invalid sdp or _sdpObject');
- }
- }
-
- /**
- * Get sdp field.
- * @return {String}
- */
- get sdp() {
- return this._sdp;
- }
-
- /**
- * Set sdp field.
- * NOTE: This is not allowed per spec, but lib-jitsi-meet uses it.
- * @param {String} sdp
- */
- set sdp(sdp) {
- try {
- this._sdpObject = sdpTransform.parse(sdp);
- } catch (error) {
- throw new Error(`invalid sdp: ${error}`);
- }
-
- this._sdp = sdp;
- }
-
- /**
- * Gets the internal sdp object.
- * @return {Object}
- * @private
- */
- get sdpObject() {
- return this._sdpObject;
- }
-
- /**
- * Get type field.
- * @return {String}
- */
- get type() {
- return this._type;
- }
-
- /**
- * Returns an object with type and sdp fields.
- * @return {Object}
- */
- toJSON() {
- return {
- sdp: this._sdp,
- type: this._type
- };
- }
-}
diff --git a/app/lib/edge/errors.js b/app/lib/edge/errors.js
deleted file mode 100644
index 99197f9..0000000
--- a/app/lib/edge/errors.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * Create a class inheriting from Error.
- */
-function createErrorClass(name) {
- const klass = class extends Error {
- /**
- * Custom error class constructor.
- * @param {string} message
- */
- constructor(message) {
- super(message);
-
- // Override `name` property value and make it non enumerable.
- Object.defineProperty(this, 'name', { value: name });
- }
- };
-
- return klass;
-}
-
-export const InvalidStateError = createErrorClass('InvalidStateError');
diff --git a/app/lib/edge/ortcUtils.js b/app/lib/edge/ortcUtils.js
deleted file mode 100644
index a9f3aaa..0000000
--- a/app/lib/edge/ortcUtils.js
+++ /dev/null
@@ -1,458 +0,0 @@
-/* global RTCRtpReceiver */
-
-import sdpTransform from 'sdp-transform';
-
-/**
- * Extract RTP capabilities from remote description.
- * @param {Object} sdpObject - Remote SDP object generated by sdp-transform.
- * @return {RTCRtpCapabilities}
- */
-export function extractCapabilities(sdpObject) {
- // Map of RtpCodecParameters indexed by payload type.
- const codecsMap = new Map();
-
- // Array of RtpHeaderExtensions.
- const headerExtensions = [];
-
- for (const m of sdpObject.media) {
- // Media kind.
- const kind = m.type;
-
- if (kind !== 'audio' && kind !== 'video') {
- continue; // eslint-disable-line no-continue
- }
-
- // Get codecs.
- for (const rtp of m.rtp) {
- const codec = {
- clockRate: rtp.rate,
- kind,
- mimeType: `${kind}/${rtp.codec}`,
- name: rtp.codec,
- numChannels: rtp.encoding || 1,
- parameters: {},
- preferredPayloadType: rtp.payload,
- rtcpFeedback: []
- };
-
- codecsMap.set(codec.preferredPayloadType, codec);
- }
-
- // Get codec parameters.
- for (const fmtp of m.fmtp || []) {
- const parameters = sdpTransform.parseFmtpConfig(fmtp.config);
- const codec = codecsMap.get(fmtp.payload);
-
- if (!codec) {
- continue; // eslint-disable-line no-continue
- }
-
- codec.parameters = parameters;
- }
-
- // Get RTCP feedback for each codec.
- for (const fb of m.rtcpFb || []) {
- const codec = codecsMap.get(fb.payload);
-
- if (!codec) {
- continue; // eslint-disable-line no-continue
- }
-
- codec.rtcpFeedback.push({
- parameter: fb.subtype || '',
- type: fb.type
- });
- }
-
- // Get RTP header extensions.
- for (const ext of m.ext || []) {
- const preferredId = ext.value;
- const uri = ext.uri;
- const headerExtension = {
- kind,
- uri,
- preferredId
- };
-
- // Check if already present.
- const duplicated = headerExtensions.find(savedHeaderExtension =>
- headerExtension.kind === savedHeaderExtension.kind
- && headerExtension.uri === savedHeaderExtension.uri
- );
-
- if (!duplicated) {
- headerExtensions.push(headerExtension);
- }
- }
- }
-
- return {
- codecs: Array.from(codecsMap.values()),
- fecMechanisms: [], // TODO
- headerExtensions
- };
-}
-
-/**
- * Extract DTLS parameters from remote description.
- * @param {Object} sdpObject - Remote SDP object generated by sdp-transform.
- * @return {RTCDtlsParameters}
- */
-export function extractDtlsParameters(sdpObject) {
- const media = getFirstActiveMediaSection(sdpObject);
- const fingerprint = media.fingerprint || sdpObject.fingerprint;
- let role;
-
- switch (media.setup) {
- case 'active':
- role = 'client';
- break;
- case 'passive':
- role = 'server';
- break;
- case 'actpass':
- role = 'auto';
- break;
- }
-
- return {
- role,
- fingerprints: [
- {
- algorithm: fingerprint.type,
- value: fingerprint.hash
- }
- ]
- };
-}
-
-/**
- * Extract ICE candidates from remote description.
- * NOTE: This implementation assumes a single BUNDLEd transport and rtcp-mux.
- * @param {Object} sdpObject - Remote SDP object generated by sdp-transform.
- * @return {sequence}
- */
-export function extractIceCandidates(sdpObject) {
- const media = getFirstActiveMediaSection(sdpObject);
- const candidates = [];
-
- for (const c of media.candidates) {
- // Ignore RTCP candidates (we assume rtcp-mux).
- if (c.component !== 1) {
- continue; // eslint-disable-line no-continue
- }
-
- const candidate = {
- foundation: c.foundation,
- ip: c.ip,
- port: c.port,
- priority: c.priority,
- protocol: c.transport.toLowerCase(),
- type: c.type
- };
-
- candidates.push(candidate);
- }
-
- return candidates;
-}
-
-/**
- * Extract ICE parameters from remote description.
- * NOTE: This implementation assumes a single BUNDLEd transport.
- * @param {Object} sdpObject - Remote SDP object generated by sdp-transform.
- * @return {RTCIceParameters}
- */
-export function extractIceParameters(sdpObject) {
- const media = getFirstActiveMediaSection(sdpObject);
- const usernameFragment = media.iceUfrag;
- const password = media.icePwd;
- const icelite = sdpObject.icelite === 'ice-lite';
-
- return {
- icelite,
- password,
- usernameFragment
- };
-}
-
-/**
- * Extract MID values from remote description.
- * @param {Object} sdpObject - Remote SDP object generated by sdp-transform.
- * @return {map} Ordered Map with MID as key and kind as value.
- */
-export function extractMids(sdpObject) {
- const midToKind = new Map();
-
- // Ignore disabled media sections.
- for (const m of sdpObject.media) {
- midToKind.set(m.mid, m.type);
- }
-
- return midToKind;
-}
-
-/**
- * Extract tracks information.
- * @param {Object} sdpObject - Remote SDP object generated by sdp-transform.
- * @return {Map}
- */
-export function extractTrackInfos(sdpObject) {
- // Map with info about receiving media.
- // - index: Media SSRC
- // - value: Object
- // - kind: 'audio' / 'video'
- // - ssrc: Media SSRC
- // - rtxSsrc: RTX SSRC (may be unset)
- // - streamId: MediaStream.jitsiRemoteId
- // - trackId: MediaStreamTrack.jitsiRemoteId
- // - cname: CNAME
- // @type {map}
- const infos = new Map();
-
- // Map with stream SSRC as index and associated RTX SSRC as value.
- // @type {map}
- const rtxMap = new Map();
-
- // Set of RTX SSRC values.
- const rtxSet = new Set();
-
- for (const m of sdpObject.media) {
- const kind = m.type;
-
- if (kind !== 'audio' && kind !== 'video') {
- continue; // eslint-disable-line no-continue
- }
-
- // Get RTX information.
- for (const ssrcGroup of m.ssrcGroups || []) {
- // Just consider FID.
- if (ssrcGroup.semantics !== 'FID') {
- continue; // eslint-disable-line no-continue
- }
-
- const ssrcs
- = ssrcGroup.ssrcs.split(' ').map(ssrc => Number(ssrc));
- const ssrc = ssrcs[0];
- const rtxSsrc = ssrcs[1];
-
- rtxMap.set(ssrc, rtxSsrc);
- rtxSet.add(rtxSsrc);
- }
-
- for (const ssrcObject of m.ssrcs || []) {
- const ssrc = ssrcObject.id;
-
- // Ignore RTX.
- if (rtxSet.has(ssrc)) {
- continue; // eslint-disable-line no-continue
- }
-
- let info = infos.get(ssrc);
-
- if (!info) {
- info = {
- kind,
- rtxSsrc: rtxMap.get(ssrc),
- ssrc
- };
-
- infos.set(ssrc, info);
- }
-
- switch (ssrcObject.attribute) {
- case 'cname': {
- info.cname = ssrcObject.value;
- break;
- }
- case 'msid': {
- const values = ssrcObject.value.split(' ');
- const streamId = values[0];
- const trackId = values[1];
-
- info.streamId = streamId;
- info.trackId = trackId;
- break;
- }
- case 'mslabel': {
- const streamId = ssrcObject.value;
-
- info.streamId = streamId;
- break;
- }
- case 'label': {
- const trackId = ssrcObject.value;
-
- info.trackId = trackId;
- break;
- }
- }
- }
- }
-
- return infos;
-}
-
-/**
- * Get local ORTC RTP capabilities filtered and adapted to the given remote RTP
- * capabilities.
- * @param {RTCRtpCapabilities} filterWithCapabilities - RTP capabilities to
- * filter with.
- * @return {RTCRtpCapabilities}
- */
-export function getLocalCapabilities(filterWithCapabilities) {
- const localFullCapabilities = RTCRtpReceiver.getCapabilities();
- const localCapabilities = {
- codecs: [],
- fecMechanisms: [],
- headerExtensions: []
- };
-
- // Map of RTX and codec payloads.
- // - index: Codec payloadType
- // - value: Associated RTX payloadType
- // @type {map}
- const remoteRtxMap = new Map();
-
- // Set codecs.
- for (const remoteCodec of filterWithCapabilities.codecs) {
- const remoteCodecName = remoteCodec.name.toLowerCase();
-
- if (remoteCodecName === 'rtx') {
- remoteRtxMap.set(
- remoteCodec.parameters.apt, remoteCodec.preferredPayloadType);
-
- continue; // eslint-disable-line no-continue
- }
-
- const localCodec = localFullCapabilities.codecs.find(codec =>
- codec.name.toLowerCase() === remoteCodecName
- && codec.kind === remoteCodec.kind
- && codec.clockRate === remoteCodec.clockRate
- );
-
- if (!localCodec) {
- continue; // eslint-disable-line no-continue
- }
-
- const codec = {
- clockRate: localCodec.clockRate,
- kind: localCodec.kind,
- mimeType: `${localCodec.kind}/${localCodec.name}`,
- name: localCodec.name,
- numChannels: localCodec.numChannels || 1,
- parameters: {},
- preferredPayloadType: remoteCodec.preferredPayloadType,
- rtcpFeedback: []
- };
-
- for (const remoteParamName of Object.keys(remoteCodec.parameters)) {
- const remoteParamValue
- = remoteCodec.parameters[remoteParamName];
-
- for (const localParamName of Object.keys(localCodec.parameters)) {
- const localParamValue
- = localCodec.parameters[localParamName];
-
- if (localParamName !== remoteParamName) {
- continue; // eslint-disable-line no-continue
- }
-
- // TODO: We should consider much more cases here, but Edge
- // does not support many codec parameters.
- if (localParamValue === remoteParamValue) {
- // Use this RTP parameter.
- codec.parameters[localParamName] = localParamValue;
- break;
- }
- }
- }
-
- for (const remoteFb of remoteCodec.rtcpFeedback) {
- const localFb = localCodec.rtcpFeedback.find(fb =>
- fb.type === remoteFb.type
- && fb.parameter === remoteFb.parameter
- );
-
- if (localFb) {
- // Use this RTCP feedback.
- codec.rtcpFeedback.push(localFb);
- }
- }
-
- // Use this codec.
- localCapabilities.codecs.push(codec);
- }
-
- // Add RTX for video codecs.
- for (const codec of localCapabilities.codecs) {
- const payloadType = codec.preferredPayloadType;
-
- if (!remoteRtxMap.has(payloadType)) {
- continue; // eslint-disable-line no-continue
- }
-
- const rtxCodec = {
- clockRate: codec.clockRate,
- kind: codec.kind,
- mimeType: `${codec.kind}/rtx`,
- name: 'rtx',
- parameters: {
- apt: payloadType
- },
- preferredPayloadType: remoteRtxMap.get(payloadType),
- rtcpFeedback: []
- };
-
- // Add RTX codec.
- localCapabilities.codecs.push(rtxCodec);
- }
-
- // Add RTP header extensions.
- for (const remoteExtension of filterWithCapabilities.headerExtensions) {
- const localExtension
- = localFullCapabilities.headerExtensions.find(extension =>
- extension.kind === remoteExtension.kind
- && extension.uri === remoteExtension.uri
- );
-
- if (localExtension) {
- const extension = {
- kind: localExtension.kind,
- preferredEncrypt: Boolean(remoteExtension.preferredEncrypt),
- preferredId: remoteExtension.preferredId,
- uri: localExtension.uri
- };
-
- // Use this RTP header extension.
- localCapabilities.headerExtensions.push(extension);
- }
- }
-
- // Add FEC mechanisms.
- // NOTE: We don't support FEC yet and, in fact, neither does Edge.
- for (const remoteFecMechanism of filterWithCapabilities.fecMechanisms) {
- const localFecMechanism
- = localFullCapabilities.fecMechanisms.find(fec =>
- fec === remoteFecMechanism
- );
-
- if (localFecMechanism) {
- // Use this FEC mechanism.
- localCapabilities.fecMechanisms.push(localFecMechanism);
- }
- }
-
- return localCapabilities;
-}
-
-/**
- * Get the first acive media section.
- * @param {Object} sdpObject - SDP object generated by sdp-transform.
- * @return {Object} SDP media section as parsed by sdp-transform.
- */
-function getFirstActiveMediaSection(sdpObject) {
- return sdpObject.media.find(m =>
- m.iceUfrag && m.port !== 0
- );
-}
diff --git a/app/lib/index.jsx b/app/lib/index.jsx
index e4fcba6..40f63b5 100644
--- a/app/lib/index.jsx
+++ b/app/lib/index.jsx
@@ -1,74 +1,183 @@
-'use strict';
-
-import browser from 'bowser';
import domready from 'domready';
import UrlParse from 'url-parse';
import React from 'react';
-import ReactDOM from 'react-dom';
-import injectTapEventPlugin from 'react-tap-event-plugin';
+import { render } from 'react-dom';
+import { Provider } from 'react-redux';
+import {
+ applyMiddleware as applyReduxMiddleware,
+ createStore as createReduxStore
+} from 'redux';
+import thunk from 'redux-thunk';
+import { createLogger as createReduxLogger } from 'redux-logger';
+import { getDeviceInfo } from 'mediasoup-client';
import randomString from 'random-string';
+import randomName from 'node-random-name';
import Logger from './Logger';
import * as utils from './utils';
-import edgeRTCPeerConnection from './edge/RTCPeerConnection';
-import edgeRTCSessionDescription from './edge/RTCSessionDescription';
-import App from './components/App';
+import * as cookiesManager from './cookiesManager';
+import * as requestActions from './redux/requestActions';
+import * as stateActions from './redux/stateActions';
+import reducers from './redux/reducers';
+import roomClientMiddleware from './redux/roomClientMiddleware';
+import Room from './components/Room';
-const REGEXP_FRAGMENT_ROOM_ID = new RegExp('^#room-id=([0-9a-zA-Z_-]+)$');
const logger = new Logger();
+const reduxMiddlewares =
+[
+ thunk,
+ roomClientMiddleware
+];
-injectTapEventPlugin();
-
-logger.debug('detected browser [name:"%s", version:%s]', browser.name, browser.version);
-
-// If Edge, use the Jitsi RTCPeerConnection shim.
-if (browser.msedge)
+if (process.env.NODE_ENV === 'development')
{
- logger.debug('Edge detected, overriding RTCPeerConnection and RTCSessionDescription');
+ const reduxLogger = createReduxLogger(
+ {
+ duration : true,
+ timestamp : false,
+ level : 'log',
+ logErrors : true
+ });
- window.RTCPeerConnection = edgeRTCPeerConnection;
- window.RTCSessionDescription = edgeRTCSessionDescription;
-}
-// Otherwise, do almost anything.
-else
-{
- window.RTCPeerConnection =
- window.webkitRTCPeerConnection ||
- window.mozRTCPeerConnection ||
- window.RTCPeerConnection;
+ reduxMiddlewares.push(reduxLogger);
}
+const store = createReduxStore(
+ reducers,
+ undefined,
+ applyReduxMiddleware(...reduxMiddlewares)
+);
+
domready(() =>
{
logger.debug('DOM ready');
// Load stuff and run
utils.initialize()
- .then(run)
- .catch((error) =>
- {
- console.error(error);
- });
+ .then(run);
});
function run()
{
logger.debug('run() [environment:%s]', process.env.NODE_ENV);
- let container = document.getElementById('mediasoup-demo-app-container');
- let urlParser = new UrlParse(window.location.href, true);
- let match = urlParser.hash.match(REGEXP_FRAGMENT_ROOM_ID);
- let peerId = randomString({ length: 8 }).toLowerCase();
- let roomId;
+ const peerName = randomString({ length: 8 }).toLowerCase();
+ const urlParser = new UrlParse(window.location.href, true);
+ let roomId = urlParser.query.roomId;
+ const produce = urlParser.query.produce !== 'false';
+ let displayName = urlParser.query.displayName;
+ const isSipEndpoint = urlParser.query.sipEndpoint === 'true';
+ const useSimulcast = urlParser.query.simulcast !== 'false';
- if (match)
+ if (!roomId)
{
- roomId = match[1];
+ roomId = randomString({ length: 8 }).toLowerCase();
+
+ urlParser.query.roomId = roomId;
+ window.history.pushState('', '', urlParser.toString());
+ }
+
+ // Get the effective/shareable Room URL.
+ const roomUrlParser = new UrlParse(window.location.href, true);
+
+ for (const key of Object.keys(roomUrlParser.query))
+ {
+ // Don't keep some custom params.
+ switch (key)
+ {
+ case 'roomId':
+ case 'simulcast':
+ break;
+ default:
+ delete roomUrlParser.query[key];
+ }
+ }
+ delete roomUrlParser.hash;
+
+ const roomUrl = roomUrlParser.toString();
+
+ // Get displayName from cookie (if not already given as param).
+ const userCookie = cookiesManager.getUser() || {};
+ let displayNameSet;
+
+ if (!displayName)
+ displayName = userCookie.displayName;
+
+ if (displayName)
+ {
+ displayNameSet = true;
}
else
{
- roomId = randomString({ length: 8 }).toLowerCase();
- window.location = `#room-id=${roomId}`;
+ displayName = randomName();
+ displayNameSet = false;
}
- ReactDOM.render(, container);
+ // Get current device.
+ const device = getDeviceInfo();
+
+ // If a SIP endpoint mangle device info.
+ if (isSipEndpoint)
+ {
+ device.flag = 'sipendpoint';
+ device.name = 'SIP Endpoint';
+ device.version = undefined;
+ }
+
+ // NOTE: I don't like this.
+ store.dispatch(
+ stateActions.setRoomUrl(roomUrl));
+
+ // NOTE: I don't like this.
+ store.dispatch(
+ stateActions.setMe({ peerName, displayName, displayNameSet, device }));
+
+ // NOTE: I don't like this.
+ store.dispatch(
+ requestActions.joinRoom(
+ { roomId, peerName, displayName, device, useSimulcast, produce }));
+
+ render(
+
+
+ ,
+ document.getElementById('mediasoup-demo-app-container')
+ );
}
+
+// TODO: Debugging stuff.
+
+setInterval(() =>
+{
+ if (!global.CLIENT._room.peers[0])
+ {
+ delete global.CONSUMER;
+
+ return;
+ }
+
+ const peer = global.CLIENT._room.peers[0];
+
+ global.CONSUMER = peer.consumers[peer.consumers.length - 1];
+}, 2000);
+
+global.sendSdp = function()
+{
+ logger.debug('---------- SEND_TRANSPORT LOCAL SDP OFFER:');
+ logger.debug(
+ global.CLIENT._sendTransport._handler._pc.localDescription.sdp);
+
+ logger.debug('---------- SEND_TRANSPORT REMOTE SDP ANSWER:');
+ logger.debug(
+ global.CLIENT._sendTransport._handler._pc.remoteDescription.sdp);
+};
+
+global.recvSdp = function()
+{
+ logger.debug('---------- RECV_TRANSPORT REMOTE SDP OFFER:');
+ logger.debug(
+ global.CLIENT._recvTransport._handler._pc.remoteDescription.sdp);
+
+ logger.debug('---------- RECV_TRANSPORT LOCAL SDP ANSWER:');
+ logger.debug(
+ global.CLIENT._recvTransport._handler._pc.localDescription.sdp);
+};
diff --git a/app/lib/redux/STATE.md b/app/lib/redux/STATE.md
new file mode 100644
index 0000000..3171af9
--- /dev/null
+++ b/app/lib/redux/STATE.md
@@ -0,0 +1,99 @@
+# APP STATE
+
+```js
+{
+ room :
+ {
+ url : 'https://example.io/?&roomId=d0el8y34',
+ state : 'connected', // new/connecting/connected/closed
+ activeSpeakerName : 'alice'
+ },
+ me :
+ {
+ name : 'bob',
+ displayName : 'Bob McFLower',
+ displayNameSet : false, // true if got from cookie or manually set.
+ device : { flag: 'firefox', name: 'Firefox', version: '61' },
+ canSendMic : true,
+ canSendWebcam : true,
+ canChangeWebcam : false,
+ webcamInProgress : false,
+ audioOnly : false,
+ audioOnlyInProgress : false,
+ restartIceInProgress : false
+ },
+ producers :
+ {
+ 1111 :
+ {
+ id : 1111,
+ source : 'mic', // mic/webcam,
+ locallyPaused : true,
+ remotelyPaused : false,
+ track : MediaStreamTrack,
+ codec : 'opus'
+ },
+ 1112 :
+ {
+ id : 1112,
+ source : 'webcam', // mic/webcam
+ deviceLabel : 'Macbook Webcam',
+ type : 'front', // front/back
+ locallyPaused : false,
+ remotelyPaused : false,
+ track : MediaStreamTrack,
+ codec : 'vp8',
+ }
+ },
+ peers :
+ {
+ 'alice' :
+ {
+ name : 'alice',
+ displayName : 'Alice Thomsom',
+ device : { flag: 'chrome', name: 'Chrome', version: '58' },
+ consumers : [ 5551, 5552 ]
+ }
+ },
+ consumers :
+ {
+ 5551 :
+ {
+ id : 5551,
+ peerName : 'alice',
+ source : 'mic', // mic/webcam
+ supported : true,
+ locallyPaused : false,
+ remotelyPaused : false,
+ profile : 'default',
+ track : MediaStreamTrack,
+ codec : 'opus'
+ },
+ 5552 :
+ {
+ id : 5552,
+ peerName : 'alice',
+ source : 'webcam',
+ supported : false,
+ locallyPaused : false,
+ remotelyPaused : true,
+ profile : 'medium',
+ track : null,
+ codec : 'h264'
+ }
+ },
+ notifications :
+ [
+ {
+ id : 'qweasdw43we',
+ type : 'info' // info/error
+ text : 'You joined the room'
+ },
+ {
+ id : 'j7sdhkjjkcc',
+ type : 'error'
+ text : 'Could not add webcam'
+ }
+ ]
+}
+```
diff --git a/app/lib/redux/reducers/consumers.js b/app/lib/redux/reducers/consumers.js
new file mode 100644
index 0000000..81f0e1c
--- /dev/null
+++ b/app/lib/redux/reducers/consumers.js
@@ -0,0 +1,75 @@
+const initialState = {};
+
+const consumers = (state = initialState, action) =>
+{
+ switch (action.type)
+ {
+ case 'ADD_CONSUMER':
+ {
+ const { consumer } = action.payload;
+
+ return { ...state, [consumer.id]: consumer };
+ }
+
+ case 'REMOVE_CONSUMER':
+ {
+ const { consumerId } = action.payload;
+ const newState = { ...state };
+
+ delete newState[consumerId];
+
+ return newState;
+ }
+
+ case 'SET_CONSUMER_PAUSED':
+ {
+ const { consumerId, originator } = action.payload;
+ const consumer = state[consumerId];
+ let newConsumer;
+
+ if (originator === 'local')
+ newConsumer = { ...consumer, locallyPaused: true };
+ else
+ newConsumer = { ...consumer, remotelyPaused: true };
+
+ return { ...state, [consumerId]: newConsumer };
+ }
+
+ case 'SET_CONSUMER_RESUMED':
+ {
+ const { consumerId, originator } = action.payload;
+ const consumer = state[consumerId];
+ let newConsumer;
+
+ if (originator === 'local')
+ newConsumer = { ...consumer, locallyPaused: false };
+ else
+ newConsumer = { ...consumer, remotelyPaused: false };
+
+ return { ...state, [consumerId]: newConsumer };
+ }
+
+ case 'SET_CONSUMER_EFFECTIVE_PROFILE':
+ {
+ const { consumerId, profile } = action.payload;
+ const consumer = state[consumerId];
+ const newConsumer = { ...consumer, profile };
+
+ return { ...state, [consumerId]: newConsumer };
+ }
+
+ case 'SET_CONSUMER_TRACK':
+ {
+ const { consumerId, track } = action.payload;
+ const consumer = state[consumerId];
+ const newConsumer = { ...consumer, track };
+
+ return { ...state, [consumerId]: newConsumer };
+ }
+
+ default:
+ return state;
+ }
+};
+
+export default consumers;
diff --git a/app/lib/redux/reducers/index.js b/app/lib/redux/reducers/index.js
new file mode 100644
index 0000000..e71610b
--- /dev/null
+++ b/app/lib/redux/reducers/index.js
@@ -0,0 +1,19 @@
+import { combineReducers } from 'redux';
+import room from './room';
+import me from './me';
+import producers from './producers';
+import peers from './peers';
+import consumers from './consumers';
+import notifications from './notifications';
+
+const reducers = combineReducers(
+ {
+ room,
+ me,
+ producers,
+ peers,
+ consumers,
+ notifications
+ });
+
+export default reducers;
diff --git a/app/lib/redux/reducers/me.js b/app/lib/redux/reducers/me.js
new file mode 100644
index 0000000..b692b1d
--- /dev/null
+++ b/app/lib/redux/reducers/me.js
@@ -0,0 +1,85 @@
+const initialState =
+{
+ name : null,
+ displayName : null,
+ displayNameSet : false,
+ device : null,
+ canSendMic : false,
+ canSendWebcam : false,
+ canChangeWebcam : false,
+ webcamInProgress : false,
+ audioOnly : false,
+ audioOnlyInProgress : false,
+ restartIceInProgress : false
+};
+
+const me = (state = initialState, action) =>
+{
+ switch (action.type)
+ {
+ case 'SET_ME':
+ {
+ const { peerName, displayName, displayNameSet, device } = action.payload;
+
+ return { ...state, name: peerName, displayName, displayNameSet, device };
+ }
+
+ case 'SET_MEDIA_CAPABILITIES':
+ {
+ const { canSendMic, canSendWebcam } = action.payload;
+
+ return { ...state, canSendMic, canSendWebcam };
+ }
+
+ case 'SET_CAN_CHANGE_WEBCAM':
+ {
+ const canChangeWebcam = action.payload;
+
+ return { ...state, canChangeWebcam };
+ }
+
+ case 'SET_WEBCAM_IN_PROGRESS':
+ {
+ const { flag } = action.payload;
+
+ return { ...state, webcamInProgress: flag };
+ }
+
+ case 'SET_DISPLAY_NAME':
+ {
+ let { displayName } = action.payload;
+
+ // Be ready for undefined displayName (so keep previous one).
+ if (!displayName)
+ displayName = state.displayName;
+
+ return { ...state, displayName, displayNameSet: true };
+ }
+
+ case 'SET_AUDIO_ONLY_STATE':
+ {
+ const { enabled } = action.payload;
+
+ return { ...state, audioOnly: enabled };
+ }
+
+ case 'SET_AUDIO_ONLY_IN_PROGRESS':
+ {
+ const { flag } = action.payload;
+
+ return { ...state, audioOnlyInProgress: flag };
+ }
+
+ case 'SET_RESTART_ICE_IN_PROGRESS':
+ {
+ const { flag } = action.payload;
+
+ return { ...state, restartIceInProgress: flag };
+ }
+
+ default:
+ return state;
+ }
+};
+
+export default me;
diff --git a/app/lib/redux/reducers/notifications.js b/app/lib/redux/reducers/notifications.js
new file mode 100644
index 0000000..bf3e6c0
--- /dev/null
+++ b/app/lib/redux/reducers/notifications.js
@@ -0,0 +1,31 @@
+const initialState = [];
+
+const notifications = (state = initialState, action) =>
+{
+ switch (action.type)
+ {
+ case 'ADD_NOTIFICATION':
+ {
+ const { notification } = action.payload;
+
+ return [ ...state, notification ];
+ }
+
+ case 'REMOVE_NOTIFICATION':
+ {
+ const { notificationId } = action.payload;
+
+ return state.filter((notification) => notification.id !== notificationId);
+ }
+
+ case 'REMOVE_ALL_NOTIFICATIONS':
+ {
+ return [];
+ }
+
+ default:
+ return state;
+ }
+};
+
+export default notifications;
diff --git a/app/lib/redux/reducers/peers.js b/app/lib/redux/reducers/peers.js
new file mode 100644
index 0000000..59761e2
--- /dev/null
+++ b/app/lib/redux/reducers/peers.js
@@ -0,0 +1,79 @@
+const initialState = {};
+
+const peers = (state = initialState, action) =>
+{
+ switch (action.type)
+ {
+ case 'ADD_PEER':
+ {
+ const { peer } = action.payload;
+
+ return { ...state, [peer.name]: peer };
+ }
+
+ case 'REMOVE_PEER':
+ {
+ const { peerName } = action.payload;
+ const newState = { ...state };
+
+ delete newState[peerName];
+
+ return newState;
+ }
+
+ case 'SET_PEER_DISPLAY_NAME':
+ {
+ const { displayName, peerName } = action.payload;
+ const peer = state[peerName];
+
+ if (!peer)
+ throw new Error('no Peer found');
+
+ const newPeer = { ...peer, displayName };
+
+ return { ...state, [newPeer.name]: newPeer };
+ }
+
+ case 'ADD_CONSUMER':
+ {
+ const { consumer, peerName } = action.payload;
+ const peer = state[peerName];
+
+ if (!peer)
+ throw new Error('no Peer found for new Consumer');
+
+ const newConsumers = [ ...peer.consumers, consumer.id ];
+ const newPeer = { ...peer, consumers: newConsumers };
+
+ return { ...state, [newPeer.name]: newPeer };
+ }
+
+ case 'REMOVE_CONSUMER':
+ {
+ const { consumerId, peerName } = action.payload;
+ const peer = state[peerName];
+
+ // NOTE: This means that the Peer was closed before, so it's ok.
+ if (!peer)
+ return state;
+
+ const idx = peer.consumers.indexOf(consumerId);
+
+ if (idx === -1)
+ throw new Error('Consumer not found');
+
+ const newConsumers = peer.consumers.slice();
+
+ newConsumers.splice(idx, 1);
+
+ const newPeer = { ...peer, consumers: newConsumers };
+
+ return { ...state, [newPeer.name]: newPeer };
+ }
+
+ default:
+ return state;
+ }
+};
+
+export default peers;
diff --git a/app/lib/redux/reducers/producers.js b/app/lib/redux/reducers/producers.js
new file mode 100644
index 0000000..4562b8b
--- /dev/null
+++ b/app/lib/redux/reducers/producers.js
@@ -0,0 +1,66 @@
+const initialState = {};
+
+const producers = (state = initialState, action) =>
+{
+ switch (action.type)
+ {
+ case 'ADD_PRODUCER':
+ {
+ const { producer } = action.payload;
+
+ return { ...state, [producer.id]: producer };
+ }
+
+ case 'REMOVE_PRODUCER':
+ {
+ const { producerId } = action.payload;
+ const newState = { ...state };
+
+ delete newState[producerId];
+
+ return newState;
+ }
+
+ case 'SET_PRODUCER_PAUSED':
+ {
+ const { producerId, originator } = action.payload;
+ const producer = state[producerId];
+ let newProducer;
+
+ if (originator === 'local')
+ newProducer = { ...producer, locallyPaused: true };
+ else
+ newProducer = { ...producer, remotelyPaused: true };
+
+ return { ...state, [producerId]: newProducer };
+ }
+
+ case 'SET_PRODUCER_RESUMED':
+ {
+ const { producerId, originator } = action.payload;
+ const producer = state[producerId];
+ let newProducer;
+
+ if (originator === 'local')
+ newProducer = { ...producer, locallyPaused: false };
+ else
+ newProducer = { ...producer, remotelyPaused: false };
+
+ return { ...state, [producerId]: newProducer };
+ }
+
+ case 'SET_PRODUCER_TRACK':
+ {
+ const { producerId, track } = action.payload;
+ const producer = state[producerId];
+ const newProducer = { ...producer, track };
+
+ return { ...state, [producerId]: newProducer };
+ }
+
+ default:
+ return state;
+ }
+};
+
+export default producers;
diff --git a/app/lib/redux/reducers/room.js b/app/lib/redux/reducers/room.js
new file mode 100644
index 0000000..24d8a04
--- /dev/null
+++ b/app/lib/redux/reducers/room.js
@@ -0,0 +1,41 @@
+const initialState =
+{
+ url : null,
+ state : 'new', // new/connecting/connected/disconnected/closed,
+ activeSpeakerName : null
+};
+
+const room = (state = initialState, action) =>
+{
+ switch (action.type)
+ {
+ case 'SET_ROOM_URL':
+ {
+ const { url } = action.payload;
+
+ return { ...state, url };
+ }
+
+ case 'SET_ROOM_STATE':
+ {
+ const roomState = action.payload.state;
+
+ if (roomState == 'connected')
+ return { ...state, state: roomState };
+ else
+ return { ...state, state: roomState, activeSpeakerName: null };
+ }
+
+ case 'SET_ROOM_ACTIVE_SPEAKER':
+ {
+ const { peerName } = action.payload;
+
+ return { ...state, activeSpeakerName: peerName };
+ }
+
+ default:
+ return state;
+ }
+};
+
+export default room;
diff --git a/app/lib/redux/requestActions.js b/app/lib/redux/requestActions.js
new file mode 100644
index 0000000..6fdf36e
--- /dev/null
+++ b/app/lib/redux/requestActions.js
@@ -0,0 +1,117 @@
+import randomString from 'random-string';
+import * as stateActions from './stateActions';
+
+export const joinRoom = (
+ { roomId, peerName, displayName, device, useSimulcast, produce }) =>
+{
+ return {
+ type : 'JOIN_ROOM',
+ payload : { roomId, peerName, displayName, device, useSimulcast, produce }
+ };
+};
+
+export const leaveRoom = () =>
+{
+ return {
+ type : 'LEAVE_ROOM'
+ };
+};
+
+export const changeDisplayName = (displayName) =>
+{
+ return {
+ type : 'CHANGE_DISPLAY_NAME',
+ payload : { displayName }
+ };
+};
+
+export const muteMic = () =>
+{
+ return {
+ type : 'MUTE_MIC'
+ };
+};
+
+export const unmuteMic = () =>
+{
+ return {
+ type : 'UNMUTE_MIC'
+ };
+};
+
+export const enableWebcam = () =>
+{
+ return {
+ type : 'ENABLE_WEBCAM'
+ };
+};
+
+export const disableWebcam = () =>
+{
+ return {
+ type : 'DISABLE_WEBCAM'
+ };
+};
+
+export const changeWebcam = () =>
+{
+ return {
+ type : 'CHANGE_WEBCAM'
+ };
+};
+
+export const enableAudioOnly = () =>
+{
+ return {
+ type : 'ENABLE_AUDIO_ONLY'
+ };
+};
+
+export const disableAudioOnly = () =>
+{
+ return {
+ type : 'DISABLE_AUDIO_ONLY'
+ };
+};
+
+export const restartIce = () =>
+{
+ return {
+ type : 'RESTART_ICE'
+ };
+};
+
+// This returns a redux-thunk action (a function).
+export const notify = ({ type = 'info', text, timeout }) =>
+{
+ if (!timeout)
+ {
+ switch (type)
+ {
+ case 'info':
+ timeout = 3000;
+ break;
+ case 'error':
+ timeout = 5000;
+ break;
+ }
+ }
+
+ const notification =
+ {
+ id : randomString({ length: 6 }).toLowerCase(),
+ type : type,
+ text : text,
+ timeout : timeout
+ };
+
+ return (dispatch) =>
+ {
+ dispatch(stateActions.addNotification(notification));
+
+ setTimeout(() =>
+ {
+ dispatch(stateActions.removeNotification(notification.id));
+ }, timeout);
+ };
+};
diff --git a/app/lib/redux/roomClientMiddleware.js b/app/lib/redux/roomClientMiddleware.js
new file mode 100644
index 0000000..b73b1af
--- /dev/null
+++ b/app/lib/redux/roomClientMiddleware.js
@@ -0,0 +1,115 @@
+import RoomClient from '../RoomClient';
+
+export default ({ dispatch, getState }) => (next) =>
+{
+ let client;
+
+ return (action) =>
+ {
+ switch (action.type)
+ {
+ case 'JOIN_ROOM':
+ {
+ const {
+ roomId,
+ peerName,
+ displayName,
+ device,
+ useSimulcast,
+ produce
+ } = action.payload;
+
+ client = new RoomClient(
+ {
+ roomId,
+ peerName,
+ displayName,
+ device,
+ useSimulcast,
+ produce,
+ dispatch,
+ getState
+ });
+
+ // TODO: TMP
+ global.CLIENT = client;
+
+ break;
+ }
+
+ case 'LEAVE_ROOM':
+ {
+ client.close();
+
+ break;
+ }
+
+ case 'CHANGE_DISPLAY_NAME':
+ {
+ const { displayName } = action.payload;
+
+ client.changeDisplayName(displayName);
+
+ break;
+ }
+
+ case 'MUTE_MIC':
+ {
+ client.muteMic();
+
+ break;
+ }
+
+ case 'UNMUTE_MIC':
+ {
+ client.unmuteMic();
+
+ break;
+ }
+
+ case 'ENABLE_WEBCAM':
+ {
+ client.enableWebcam();
+
+ break;
+ }
+
+ case 'DISABLE_WEBCAM':
+ {
+ client.disableWebcam();
+
+ break;
+ }
+
+ case 'CHANGE_WEBCAM':
+ {
+ client.changeWebcam();
+
+ break;
+ }
+
+ case 'ENABLE_AUDIO_ONLY':
+ {
+ client.enableAudioOnly();
+
+ break;
+ }
+
+ case 'DISABLE_AUDIO_ONLY':
+ {
+ client.disableAudioOnly();
+
+ break;
+ }
+
+ case 'RESTART_ICE':
+ {
+ client.restartIce();
+
+ break;
+ }
+ }
+
+ return next(action);
+ };
+};
diff --git a/app/lib/redux/stateActions.js b/app/lib/redux/stateActions.js
new file mode 100644
index 0000000..edf0f3d
--- /dev/null
+++ b/app/lib/redux/stateActions.js
@@ -0,0 +1,222 @@
+export const setRoomUrl = (url) =>
+{
+ return {
+ type : 'SET_ROOM_URL',
+ payload : { url }
+ };
+};
+
+export const setRoomState = (state) =>
+{
+ return {
+ type : 'SET_ROOM_STATE',
+ payload : { state }
+ };
+};
+
+export const setRoomActiveSpeaker = (peerName) =>
+{
+ return {
+ type : 'SET_ROOM_ACTIVE_SPEAKER',
+ payload : { peerName }
+ };
+};
+
+export const setMe = ({ peerName, displayName, displayNameSet, device }) =>
+{
+ return {
+ type : 'SET_ME',
+ payload : { peerName, displayName, displayNameSet, device }
+ };
+};
+
+export const setMediaCapabilities = ({ canSendMic, canSendWebcam }) =>
+{
+ return {
+ type : 'SET_MEDIA_CAPABILITIES',
+ payload : { canSendMic, canSendWebcam }
+ };
+};
+
+export const setCanChangeWebcam = (flag) =>
+{
+ return {
+ type : 'SET_CAN_CHANGE_WEBCAM',
+ payload : flag
+ };
+};
+
+export const setDisplayName = (displayName) =>
+{
+ return {
+ type : 'SET_DISPLAY_NAME',
+ payload : { displayName }
+ };
+};
+
+export const setAudioOnlyState = (enabled) =>
+{
+ return {
+ type : 'SET_AUDIO_ONLY_STATE',
+ payload : { enabled }
+ };
+};
+
+export const setAudioOnlyInProgress = (flag) =>
+{
+ return {
+ type : 'SET_AUDIO_ONLY_IN_PROGRESS',
+ payload : { flag }
+ };
+};
+
+export const setRestartIceInProgress = (flag) =>
+{
+ return {
+ type : 'SET_RESTART_ICE_IN_PROGRESS',
+ payload : { flag }
+ };
+};
+
+export const addProducer = (producer) =>
+{
+ return {
+ type : 'ADD_PRODUCER',
+ payload : { producer }
+ };
+};
+
+export const removeProducer = (producerId) =>
+{
+ return {
+ type : 'REMOVE_PRODUCER',
+ payload : { producerId }
+ };
+};
+
+export const setProducerPaused = (producerId, originator) =>
+{
+ return {
+ type : 'SET_PRODUCER_PAUSED',
+ payload : { producerId, originator }
+ };
+};
+
+export const setProducerResumed = (producerId, originator) =>
+{
+ return {
+ type : 'SET_PRODUCER_RESUMED',
+ payload : { producerId, originator }
+ };
+};
+
+export const setProducerTrack = (producerId, track) =>
+{
+ return {
+ type : 'SET_PRODUCER_TRACK',
+ payload : { producerId, track }
+ };
+};
+
+export const setWebcamInProgress = (flag) =>
+{
+ return {
+ type : 'SET_WEBCAM_IN_PROGRESS',
+ payload : { flag }
+ };
+};
+
+export const addPeer = (peer) =>
+{
+ return {
+ type : 'ADD_PEER',
+ payload : { peer }
+ };
+};
+
+export const removePeer = (peerName) =>
+{
+ return {
+ type : 'REMOVE_PEER',
+ payload : { peerName }
+ };
+};
+
+export const setPeerDisplayName = (displayName, peerName) =>
+{
+ return {
+ type : 'SET_PEER_DISPLAY_NAME',
+ payload : { displayName, peerName }
+ };
+};
+
+export const addConsumer = (consumer, peerName) =>
+{
+ return {
+ type : 'ADD_CONSUMER',
+ payload : { consumer, peerName }
+ };
+};
+
+export const removeConsumer = (consumerId, peerName) =>
+{
+ return {
+ type : 'REMOVE_CONSUMER',
+ payload : { consumerId, peerName }
+ };
+};
+
+export const setConsumerPaused = (consumerId, originator) =>
+{
+ return {
+ type : 'SET_CONSUMER_PAUSED',
+ payload : { consumerId, originator }
+ };
+};
+
+export const setConsumerResumed = (consumerId, originator) =>
+{
+ return {
+ type : 'SET_CONSUMER_RESUMED',
+ payload : { consumerId, originator }
+ };
+};
+
+export const setConsumerEffectiveProfile = (consumerId, profile) =>
+{
+ return {
+ type : 'SET_CONSUMER_EFFECTIVE_PROFILE',
+ payload : { consumerId, profile }
+ };
+};
+
+export const setConsumerTrack = (consumerId, track) =>
+{
+ return {
+ type : 'SET_CONSUMER_TRACK',
+ payload : { consumerId, track }
+ };
+};
+
+export const addNotification = (notification) =>
+{
+ return {
+ type : 'ADD_NOTIFICATION',
+ payload : { notification }
+ };
+};
+
+export const removeNotification = (notificationId) =>
+{
+ return {
+ type : 'REMOVE_NOTIFICATION',
+ payload : { notificationId }
+ };
+};
+
+export const removeAllNotifications = () =>
+{
+ return {
+ type : 'REMOVE_ALL_NOTIFICATIONS'
+ };
+};
diff --git a/app/lib/urlFactory.js b/app/lib/urlFactory.js
index 94593a8..ca9c956 100644
--- a/app/lib/urlFactory.js
+++ b/app/lib/urlFactory.js
@@ -1,12 +1,7 @@
-'use strict';
-
-const config = require('../config');
-
-export function getProtooUrl(peerId, roomId)
+export function getProtooUrl(peerName, roomId)
{
- let hostname = window.location.hostname;
- let port = config.protoo.listenPort;
- let url = `wss://${hostname}:${port}/?peer-id=${peerId}&room-id=${roomId}`;
+ const hostname = window.location.hostname;
+ const url = `wss://${hostname}:3443/?peerName=${peerName}&roomId=${roomId}`;
return url;
}
diff --git a/app/lib/utils.js b/app/lib/utils.js
index 56a67eb..ebc220d 100644
--- a/app/lib/utils.js
+++ b/app/lib/utils.js
@@ -1,75 +1,20 @@
-'use strict';
-
-import browser from 'bowser';
-import randomNumberLib from 'random-number';
-import Logger from './Logger';
-
-global.BROWSER = browser;
-
-const logger = new Logger('utils');
-const randomNumberGenerator = randomNumberLib.generator(
- {
- min : 10000000,
- max : 99999999,
- integer : true
- });
-
let mediaQueryDetectorElem;
export function initialize()
{
- logger.debug('initialize()');
-
- // Media query detector stuff
- mediaQueryDetectorElem = document.getElementById('mediasoup-demo-app-media-query-detector');
+ // Media query detector stuff.
+ mediaQueryDetectorElem =
+ document.getElementById('mediasoup-demo-app-media-query-detector');
return Promise.resolve();
}
export function isDesktop()
{
- return !!mediaQueryDetectorElem.offsetParent;
+ return Boolean(mediaQueryDetectorElem.offsetParent);
}
export function isMobile()
{
return !mediaQueryDetectorElem.offsetParent;
}
-
-export function isPlanB()
-{
- if (browser.chrome || browser.chromium || browser.opera || browser.safari || browser.msedge)
- return true;
- else
- return false;
-}
-
-/**
- * Unfortunately Edge produces rtpSender.send() to fail when receiving media
- * from others and removing/adding a local track.
- */
-export function canChangeResolution()
-{
- if (browser.msedge)
- return false;
-
- return true;
-}
-
-export function randomNumber()
-{
- return randomNumberGenerator();
-}
-
-export function closeMediaStream(stream)
-{
- if (!stream)
- return;
-
- let tracks = stream.getTracks();
-
- for (let i=0, len=tracks.length; i < len; i++)
- {
- tracks[i].stop();
- }
-}
diff --git a/app/package-lock.json b/app/package-lock.json
index ff7b54f..f96766f 100644
--- a/app/package-lock.json
+++ b/app/package-lock.json
@@ -1,8 +1,19 @@
{
"name": "mediasoup-demo-app",
- "version": "1.2.0",
+ "version": "2.0.0",
"lockfileVersion": 1,
+ "requires": true,
"dependencies": {
+ "JSONStream": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz",
+ "integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=",
+ "dev": true,
+ "requires": {
+ "jsonparse": "1.3.1",
+ "through": "2.3.8"
+ }
+ },
"abbrev": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
@@ -13,13 +24,33 @@
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz",
"integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "mime-types": "2.1.16",
+ "negotiator": "0.6.1"
+ }
},
"accord": {
"version": "0.26.4",
"resolved": "https://registry.npmjs.org/accord/-/accord-0.26.4.tgz",
"integrity": "sha1-/EyNPrq0BqB8sogZuFllHESpLoA=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "convert-source-map": "1.5.0",
+ "glob": "7.1.2",
+ "indx": "0.2.3",
+ "lodash.clone": "4.5.0",
+ "lodash.defaults": "4.2.0",
+ "lodash.flatten": "4.4.0",
+ "lodash.merge": "4.6.0",
+ "lodash.partialright": "4.2.1",
+ "lodash.pick": "4.4.0",
+ "lodash.uniq": "4.5.0",
+ "resolve": "1.4.0",
+ "semver": "5.4.1",
+ "uglify-js": "2.8.29",
+ "when": "3.7.8"
+ }
},
"acorn": {
"version": "4.0.13",
@@ -32,6 +63,9 @@
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
"integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
"dev": true,
+ "requires": {
+ "acorn": "3.3.0"
+ },
"dependencies": {
"acorn": {
"version": "3.3.0",
@@ -52,13 +86,9 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
"integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
"dev": true,
- "dependencies": {
- "json-stable-stringify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
- "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
- "dev": true
- }
+ "requires": {
+ "co": "4.6.0",
+ "json-stable-stringify": "1.0.1"
}
},
"ajv-keywords": {
@@ -67,11 +97,21 @@
"integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=",
"dev": true
},
+ "alea": {
+ "version": "0.0.9",
+ "resolved": "https://registry.npmjs.org/alea/-/alea-0.0.9.tgz",
+ "integrity": "sha1-9zjLRfg0MAafRc9pzL8xLdV6nho="
+ },
"align-text": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
"integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2",
+ "longest": "1.0.1",
+ "repeat-string": "1.6.1"
+ }
},
"amdefine": {
"version": "1.0.1",
@@ -98,10 +138,14 @@
"dev": true
},
"anymatch": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz",
- "integrity": "sha1-o+Uvo5FoyCX/V7AkgSbOWo/5VQc=",
- "dev": true
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+ "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
+ "dev": true,
+ "requires": {
+ "micromatch": "2.3.11",
+ "normalize-path": "2.1.1"
+ }
},
"archy": {
"version": "1.0.0",
@@ -113,31 +157,43 @@
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
"integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "sprintf-js": "1.0.3"
+ }
},
"arr-diff": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
"integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "arr-flatten": "1.1.0"
+ }
},
"arr-filter": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz",
"integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "make-iterator": "1.0.0"
+ }
},
"arr-flatten": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.3.tgz",
- "integrity": "sha1-onTthawIhJtr14R8RYB0XcUa37E=",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
"dev": true
},
"arr-map": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz",
"integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "make-iterator": "1.0.0"
+ }
},
"array-differ": {
"version": "1.0.0",
@@ -157,37 +213,54 @@
"integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=",
"dev": true
},
- "array-initial": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.0.0.tgz",
- "integrity": "sha1-CbE8WNVqBQNC53erb/zllbEI2tk=",
+ "array-includes": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz",
+ "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=",
"dev": true,
+ "requires": {
+ "define-properties": "1.1.2",
+ "es-abstract": "1.8.0"
+ }
+ },
+ "array-initial": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.0.1.tgz",
+ "integrity": "sha1-hhIiIqKcHtQjR/YzQRGvpA+LIOw=",
+ "dev": true,
+ "requires": {
+ "array-slice": "1.0.0",
+ "is-number": "3.0.0"
+ },
"dependencies": {
- "array-slice": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
- "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=",
- "dev": true
- },
"is-number": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz",
- "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=",
- "dev": true
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ }
}
}
},
"array-last": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.1.1.tgz",
- "integrity": "sha1-9GWPmI2SEya1itARPPdtM3x7IKo=",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.2.0.tgz",
+ "integrity": "sha1-CISmfsKsKggTP8APZnec/tsBCYY=",
"dev": true,
+ "requires": {
+ "is-number": "3.0.0"
+ },
"dependencies": {
"is-number": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz",
- "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=",
- "dev": true
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ }
}
}
},
@@ -213,7 +286,10 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
"integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "array-uniq": "1.0.3"
+ }
},
"array-uniq": {
"version": "1.0.3",
@@ -240,9 +316,9 @@
"dev": true
},
"asap": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.5.tgz",
- "integrity": "sha1-UidltQw1EEkOUtfc/ghe+bqWlY8="
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
},
"asn1": {
"version": "0.2.3",
@@ -254,13 +330,21 @@
"version": "4.9.1",
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz",
"integrity": "sha1-SLokC0WpKA6UdImQull9IWYX/UA=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "bn.js": "4.11.8",
+ "inherits": "2.0.3",
+ "minimalistic-assert": "1.0.0"
+ }
},
"assert": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
"integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "util": "0.10.3"
+ }
},
"assert-plus": {
"version": "0.2.0",
@@ -272,7 +356,10 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz",
"integrity": "sha1-e9QXhNMkk5h66yOba04cV6hzuRc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "acorn": "4.0.13"
+ }
},
"async": {
"version": "1.5.2",
@@ -281,10 +368,16 @@
"dev": true
},
"async-done": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.2.2.tgz",
- "integrity": "sha1-ukKA2lWhbhX0u4vzqESpGHh0DjE=",
- "dev": true
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.2.3.tgz",
+ "integrity": "sha1-bHq8fWHKJ/5vHyujIG6prmCkOYM=",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "1.4.0",
+ "once": "1.4.0",
+ "process-nextick-args": "1.0.7",
+ "stream-exhaust": "1.0.1"
+ }
},
"async-each": {
"version": "1.0.1",
@@ -302,7 +395,10 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz",
"integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "async-done": "1.2.3"
+ }
},
"asynckit": {
"version": "0.4.0",
@@ -323,22 +419,69 @@
"dev": true
},
"babel-code-frame": {
- "version": "6.22.0",
- "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz",
- "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=",
- "dev": true
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+ "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+ "dev": true,
+ "requires": {
+ "chalk": "1.1.3",
+ "esutils": "2.0.2",
+ "js-tokens": "3.0.2"
+ }
},
"babel-core": {
- "version": "6.25.0",
- "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.25.0.tgz",
- "integrity": "sha1-fdQrBGPHQunVKW3rPsZ6kyLa1yk=",
- "dev": true
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz",
+ "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=",
+ "dev": true,
+ "requires": {
+ "babel-code-frame": "6.26.0",
+ "babel-generator": "6.26.0",
+ "babel-helpers": "6.24.1",
+ "babel-messages": "6.23.0",
+ "babel-register": "6.26.0",
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0",
+ "babel-traverse": "6.26.0",
+ "babel-types": "6.26.0",
+ "babylon": "6.18.0",
+ "convert-source-map": "1.5.0",
+ "debug": "2.6.9",
+ "json5": "0.5.1",
+ "lodash": "4.17.4",
+ "minimatch": "3.0.4",
+ "path-is-absolute": "1.0.1",
+ "private": "0.1.7",
+ "slash": "1.0.0",
+ "source-map": "0.5.6"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
},
"babel-generator": {
- "version": "6.25.0",
- "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.25.0.tgz",
- "integrity": "sha1-M6GvcNXyiQrrRlpKd5PB32qeqfw=",
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz",
+ "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=",
"dev": true,
+ "requires": {
+ "babel-messages": "6.23.0",
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0",
+ "detect-indent": "4.0.0",
+ "jsesc": "1.3.0",
+ "lodash": "4.17.4",
+ "source-map": "0.5.6",
+ "trim-right": "1.0.1"
+ },
"dependencies": {
"jsesc": {
"version": "1.3.0",
@@ -349,76 +492,135 @@
}
},
"babel-helper-builder-react-jsx": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.24.1.tgz",
- "integrity": "sha1-CteRfjPI11HmRtrKTnfMGTd9LLw=",
- "dev": true
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.26.0.tgz",
+ "integrity": "sha1-Of+DE7dci2Xc7/HzHTg+D/KkCKA=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0",
+ "esutils": "2.0.2"
+ }
},
"babel-helper-call-delegate": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
"integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-helper-hoist-variables": "6.24.1",
+ "babel-runtime": "6.26.0",
+ "babel-traverse": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-helper-define-map": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.24.1.tgz",
- "integrity": "sha1-epdH8ljYlH0y1RX2qhx70CIEoIA=",
- "dev": true
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
+ "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=",
+ "dev": true,
+ "requires": {
+ "babel-helper-function-name": "6.24.1",
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0",
+ "lodash": "4.17.4"
+ }
},
"babel-helper-function-name": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
"integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-helper-get-function-arity": "6.24.1",
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0",
+ "babel-traverse": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-helper-get-function-arity": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
"integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-helper-hoist-variables": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
"integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-helper-optimise-call-expression": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
"integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-helper-regex": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.24.1.tgz",
- "integrity": "sha1-024i+rEAjXnYhkjjIRaGgShFbOg=",
- "dev": true
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
+ "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0",
+ "lodash": "4.17.4"
+ }
},
"babel-helper-replace-supers": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
"integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-helper-optimise-call-expression": "6.24.1",
+ "babel-messages": "6.23.0",
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0",
+ "babel-traverse": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-helpers": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
"integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0"
+ }
},
"babel-messages": {
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
"integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-check-es2015-constants": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
"integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-syntax-flow": {
"version": "6.18.0",
@@ -432,256 +634,503 @@
"integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=",
"dev": true
},
+ "babel-plugin-syntax-object-rest-spread": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
+ "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
+ "dev": true
+ },
"babel-plugin-transform-es2015-arrow-functions": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
"integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-block-scoped-functions": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
"integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-block-scoping": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz",
- "integrity": "sha1-dsKV3DpHQbFmWt/TFnIV3P8ypXY=",
- "dev": true
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
+ "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0",
+ "babel-traverse": "6.26.0",
+ "babel-types": "6.26.0",
+ "lodash": "4.17.4"
+ }
},
"babel-plugin-transform-es2015-classes": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
"integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-helper-define-map": "6.26.0",
+ "babel-helper-function-name": "6.24.1",
+ "babel-helper-optimise-call-expression": "6.24.1",
+ "babel-helper-replace-supers": "6.24.1",
+ "babel-messages": "6.23.0",
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0",
+ "babel-traverse": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-computed-properties": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
"integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-destructuring": {
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
"integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-duplicate-keys": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
"integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-for-of": {
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
"integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-function-name": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
"integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-helper-function-name": "6.24.1",
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-literals": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
"integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-modules-amd": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
"integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-plugin-transform-es2015-modules-commonjs": "6.26.0",
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-modules-commonjs": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz",
- "integrity": "sha1-0+MQtA72ZKNmIiAAl8bUQCmPK/4=",
- "dev": true
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz",
+ "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=",
+ "dev": true,
+ "requires": {
+ "babel-plugin-transform-strict-mode": "6.24.1",
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-modules-systemjs": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz",
"integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-helper-hoist-variables": "6.24.1",
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-modules-umd": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz",
"integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-plugin-transform-es2015-modules-amd": "6.24.1",
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-object-super": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz",
"integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-helper-replace-supers": "6.24.1",
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-parameters": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz",
"integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-helper-call-delegate": "6.24.1",
+ "babel-helper-get-function-arity": "6.24.1",
+ "babel-runtime": "6.26.0",
+ "babel-template": "6.26.0",
+ "babel-traverse": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-shorthand-properties": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz",
"integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-spread": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
"integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-sticky-regex": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz",
"integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-helper-regex": "6.26.0",
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-template-literals": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
"integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-typeof-symbol": {
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
"integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-es2015-unicode-regex": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz",
"integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-helper-regex": "6.26.0",
+ "babel-runtime": "6.26.0",
+ "regexpu-core": "2.0.0"
+ }
},
"babel-plugin-transform-flow-strip-types": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz",
"integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-plugin-syntax-flow": "6.18.0",
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-object-assign": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-object-assign/-/babel-plugin-transform-object-assign-6.22.0.tgz",
"integrity": "sha1-+Z0vZvGgsNSY40bFNZaEdAyqILo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
+ },
+ "babel-plugin-transform-object-rest-spread": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz",
+ "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=",
+ "dev": true,
+ "requires": {
+ "babel-plugin-syntax-object-rest-spread": "6.13.0",
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-react-display-name": {
"version": "6.25.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.25.0.tgz",
"integrity": "sha1-Z+K/Hx6ck6sI25Z5LgU5K/LMKNE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-react-jsx": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.24.1.tgz",
"integrity": "sha1-hAoCjn30YN/DotKfDA2R9jduZqM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-helper-builder-react-jsx": "6.26.0",
+ "babel-plugin-syntax-jsx": "6.18.0",
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-react-jsx-self": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz",
"integrity": "sha1-322AqdomEqEh5t3XVYvL7PBuY24=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-plugin-syntax-jsx": "6.18.0",
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-react-jsx-source": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz",
"integrity": "sha1-ZqwSFT9c0tF7PBkmj0vwGX9E7NY=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-plugin-syntax-jsx": "6.18.0",
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-regenerator": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz",
- "integrity": "sha1-uNowWtQ8PJm0hI5P5AN7dw0jxBg=",
- "dev": true
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
+ "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=",
+ "dev": true,
+ "requires": {
+ "regenerator-transform": "0.10.1"
+ }
},
"babel-plugin-transform-runtime": {
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz",
"integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0"
+ }
},
"babel-plugin-transform-strict-mode": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
"integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0"
+ }
},
"babel-preset-es2015": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz",
"integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-plugin-check-es2015-constants": "6.22.0",
+ "babel-plugin-transform-es2015-arrow-functions": "6.22.0",
+ "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0",
+ "babel-plugin-transform-es2015-block-scoping": "6.26.0",
+ "babel-plugin-transform-es2015-classes": "6.24.1",
+ "babel-plugin-transform-es2015-computed-properties": "6.24.1",
+ "babel-plugin-transform-es2015-destructuring": "6.23.0",
+ "babel-plugin-transform-es2015-duplicate-keys": "6.24.1",
+ "babel-plugin-transform-es2015-for-of": "6.23.0",
+ "babel-plugin-transform-es2015-function-name": "6.24.1",
+ "babel-plugin-transform-es2015-literals": "6.22.0",
+ "babel-plugin-transform-es2015-modules-amd": "6.24.1",
+ "babel-plugin-transform-es2015-modules-commonjs": "6.26.0",
+ "babel-plugin-transform-es2015-modules-systemjs": "6.24.1",
+ "babel-plugin-transform-es2015-modules-umd": "6.24.1",
+ "babel-plugin-transform-es2015-object-super": "6.24.1",
+ "babel-plugin-transform-es2015-parameters": "6.24.1",
+ "babel-plugin-transform-es2015-shorthand-properties": "6.24.1",
+ "babel-plugin-transform-es2015-spread": "6.22.0",
+ "babel-plugin-transform-es2015-sticky-regex": "6.24.1",
+ "babel-plugin-transform-es2015-template-literals": "6.22.0",
+ "babel-plugin-transform-es2015-typeof-symbol": "6.23.0",
+ "babel-plugin-transform-es2015-unicode-regex": "6.24.1",
+ "babel-plugin-transform-regenerator": "6.26.0"
+ }
},
"babel-preset-flow": {
"version": "6.23.0",
"resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz",
"integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-plugin-transform-flow-strip-types": "6.22.0"
+ }
},
"babel-preset-react": {
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.24.1.tgz",
"integrity": "sha1-umnfrqRfw+xjm2pOzqbhdwLJE4A=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "babel-plugin-syntax-jsx": "6.18.0",
+ "babel-plugin-transform-react-display-name": "6.25.0",
+ "babel-plugin-transform-react-jsx": "6.24.1",
+ "babel-plugin-transform-react-jsx-self": "6.22.0",
+ "babel-plugin-transform-react-jsx-source": "6.22.0",
+ "babel-preset-flow": "6.23.0"
+ }
},
"babel-register": {
- "version": "6.24.1",
- "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.24.1.tgz",
- "integrity": "sha1-fhDhOi9xBlvfrVoXh7pFvKbe118=",
- "dev": true
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
+ "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
+ "dev": true,
+ "requires": {
+ "babel-core": "6.26.0",
+ "babel-runtime": "6.26.0",
+ "core-js": "2.5.0",
+ "home-or-tmp": "2.0.0",
+ "lodash": "4.17.4",
+ "mkdirp": "0.5.1",
+ "source-map-support": "0.4.18"
+ }
},
"babel-runtime": {
- "version": "6.23.0",
- "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz",
- "integrity": "sha1-CpSJ8UTecO+zzkMArM2zKeL8VDs="
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "requires": {
+ "core-js": "2.5.0",
+ "regenerator-runtime": "0.11.0"
+ }
},
"babel-template": {
- "version": "6.25.0",
- "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.25.0.tgz",
- "integrity": "sha1-ZlJBFmt8KqTGGdceGSlpVSsQwHE=",
- "dev": true
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+ "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-traverse": "6.26.0",
+ "babel-types": "6.26.0",
+ "babylon": "6.18.0",
+ "lodash": "4.17.4"
+ }
},
"babel-traverse": {
- "version": "6.25.0",
- "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.25.0.tgz",
- "integrity": "sha1-IldJfi/NGbie3BPEyROB+VEklvE=",
- "dev": true
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+ "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+ "dev": true,
+ "requires": {
+ "babel-code-frame": "6.26.0",
+ "babel-messages": "6.23.0",
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0",
+ "babylon": "6.18.0",
+ "debug": "2.6.8",
+ "globals": "9.18.0",
+ "invariant": "2.2.2",
+ "lodash": "4.17.4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.8",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
},
"babel-types": {
- "version": "6.25.0",
- "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.25.0.tgz",
- "integrity": "sha1-cK+ySNVmDl0Y+BHZHIMDtUE0oY4=",
- "dev": true
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "esutils": "2.0.2",
+ "lodash": "4.17.4",
+ "to-fast-properties": "1.0.3"
+ }
},
"babelify": {
- "version": "7.3.0",
- "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz",
- "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/babelify/-/babelify-8.0.0.tgz",
+ "integrity": "sha512-xVr63fKEvMWUrrIbqlHYsMcc5Zdw4FSVesAHgkgajyCE1W8gbm9rbMakqavhxKvikGYMhEcqxTwB/gQmQ6lBtw==",
"dev": true
},
"babylon": {
- "version": "6.17.4",
- "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.17.4.tgz",
- "integrity": "sha512-kChlV+0SXkjE0vUn9OZ7pBMWRFd8uq3mZe8x1K6jhuNcAFAtEnjchFAqB+dYEXKyd+JpT6eppRR78QAr5gTsUw==",
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
"dev": true
},
"bach": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/bach/-/bach-1.1.0.tgz",
- "integrity": "sha1-z+VC25Jcs3BR/EkK0QLHO8slioQ=",
- "dev": true
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz",
+ "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=",
+ "dev": true,
+ "requires": {
+ "arr-filter": "1.1.2",
+ "arr-flatten": "1.1.0",
+ "arr-map": "2.0.2",
+ "array-each": "1.0.1",
+ "array-initial": "1.0.1",
+ "array-last": "1.2.0",
+ "async-done": "1.2.3",
+ "async-settle": "1.0.0",
+ "now-and-later": "2.0.0"
+ }
},
"backo2": {
"version": "1.0.2",
@@ -724,7 +1173,10 @@
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
"integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "tweetnacl": "0.14.5"
+ }
},
"beeper": {
"version": "1.1.1",
@@ -736,12 +1188,15 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
"integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "callsite": "1.0.0"
+ }
},
"binary-extensions": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.8.0.tgz",
- "integrity": "sha1-SOyNFt9Dd+rl+liEaCSAr02Vx3Q=",
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz",
+ "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=",
"dev": true
},
"bl": {
@@ -749,6 +1204,9 @@
"resolved": "https://registry.npmjs.org/bl/-/bl-0.9.5.tgz",
"integrity": "sha1-wGt5evCF6gC8Unr8jvzxHeIjIFQ=",
"dev": true,
+ "requires": {
+ "readable-stream": "1.0.34"
+ },
"dependencies": {
"isarray": {
"version": "0.0.1",
@@ -760,7 +1218,13 @@
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ }
},
"string_decoder": {
"version": "0.10.31",
@@ -777,33 +1241,40 @@
"dev": true
},
"bn.js": {
- "version": "4.11.7",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.7.tgz",
- "integrity": "sha512-LxFiV5mefv0ley0SzqkOPR1bC4EbpPx8LkOz5vMe/Yi15t5hzwgO/G+tc7wOtL4PZTYjwHu8JnEiSLumuSjSfA==",
+ "version": "4.11.8",
+ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+ "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
"dev": true
},
"boom": {
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
"integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
- "dev": true
- },
- "bowser": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/bowser/-/bowser-1.7.0.tgz",
- "integrity": "sha1-Fp3kAYcR+ZQkK/+agAnneh814AM="
+ "dev": true,
+ "requires": {
+ "hoek": "2.16.3"
+ }
},
"brace-expansion": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
"integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "balanced-match": "1.0.0",
+ "concat-map": "0.0.1"
+ }
},
"braces": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
"integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "expand-range": "1.8.2",
+ "preserve": "0.2.0",
+ "repeat-element": "1.1.2"
+ }
},
"brorand": {
"version": "1.1.0",
@@ -815,13 +1286,23 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.0.2.tgz",
"integrity": "sha1-+GzWzvT1MAyOY+B6TVEvZfv/RTE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "JSONStream": "1.3.1",
+ "combine-source-map": "0.7.2",
+ "defined": "1.0.0",
+ "through2": "2.0.3",
+ "umd": "3.0.1"
+ }
},
"browser-resolve": {
"version": "1.11.2",
"resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz",
"integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=",
"dev": true,
+ "requires": {
+ "resolve": "1.1.7"
+ },
"dependencies": {
"resolve": {
"version": "1.1.7",
@@ -832,10 +1313,38 @@
}
},
"browser-sync": {
- "version": "2.18.12",
- "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.18.12.tgz",
- "integrity": "sha1-u6oKF6lh4rXwqOdg5pUCcYZmR3k=",
+ "version": "2.18.13",
+ "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.18.13.tgz",
+ "integrity": "sha512-qhdrmgshVGwweogT/bdOKkZDxVxqiF4+9mibaDeAxvDBeoUtdgABk5x7YQ1KCcLRchAfv8AVtp9NuITl5CTNqg==",
"dev": true,
+ "requires": {
+ "browser-sync-client": "2.5.1",
+ "browser-sync-ui": "0.6.3",
+ "bs-recipes": "1.3.4",
+ "chokidar": "1.7.0",
+ "connect": "3.5.0",
+ "dev-ip": "1.0.1",
+ "easy-extender": "2.3.2",
+ "eazy-logger": "3.0.2",
+ "emitter-steward": "1.0.0",
+ "fs-extra": "3.0.1",
+ "http-proxy": "1.15.2",
+ "immutable": "3.8.1",
+ "localtunnel": "1.8.3",
+ "micromatch": "2.3.11",
+ "opn": "4.0.2",
+ "portscanner": "2.1.1",
+ "qs": "6.2.1",
+ "resp-modifier": "6.0.2",
+ "rx": "4.1.0",
+ "serve-index": "1.8.0",
+ "serve-static": "1.12.2",
+ "server-destroy": "1.0.1",
+ "socket.io": "1.6.0",
+ "socket.io-client": "1.6.0",
+ "ua-parser-js": "0.7.12",
+ "yargs": "6.4.0"
+ },
"dependencies": {
"ua-parser-js": {
"version": "0.7.12",
@@ -849,55 +1358,163 @@
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.5.1.tgz",
"integrity": "sha1-7BrWmknC4tS2RbGLHAbCmz2a+Os=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "etag": "1.8.0",
+ "fresh": "0.3.0"
+ }
},
"browser-sync-ui": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-0.6.3.tgz",
"integrity": "sha1-ZApTfBgGiTA9W+krxHa568RBwLw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "async-each-series": "0.1.1",
+ "connect-history-api-fallback": "1.3.0",
+ "immutable": "3.8.1",
+ "server-destroy": "1.0.1",
+ "stream-throttle": "0.1.3",
+ "weinre": "2.0.0-pre-I0Z7U9OV"
+ }
},
"browserify": {
- "version": "14.4.0",
- "resolved": "https://registry.npmjs.org/browserify/-/browserify-14.4.0.tgz",
- "integrity": "sha1-CJo0Y69Y0OSNjNQHCz90ZU1avKk=",
- "dev": true
+ "version": "14.5.0",
+ "resolved": "https://registry.npmjs.org/browserify/-/browserify-14.5.0.tgz",
+ "integrity": "sha512-gKfOsNQv/toWz+60nSPfYzuwSEdzvV2WdxrVPUbPD/qui44rAkB3t3muNtmmGYHqrG56FGwX9SUEQmzNLAeS7g==",
+ "dev": true,
+ "requires": {
+ "JSONStream": "1.3.1",
+ "assert": "1.4.1",
+ "browser-pack": "6.0.2",
+ "browser-resolve": "1.11.2",
+ "browserify-zlib": "0.2.0",
+ "buffer": "5.0.7",
+ "cached-path-relative": "1.0.1",
+ "concat-stream": "1.5.2",
+ "console-browserify": "1.1.0",
+ "constants-browserify": "1.0.0",
+ "crypto-browserify": "3.11.1",
+ "defined": "1.0.0",
+ "deps-sort": "2.0.0",
+ "domain-browser": "1.1.7",
+ "duplexer2": "0.1.4",
+ "events": "1.1.1",
+ "glob": "7.1.2",
+ "has": "1.0.1",
+ "htmlescape": "1.1.1",
+ "https-browserify": "1.0.0",
+ "inherits": "2.0.3",
+ "insert-module-globals": "7.0.1",
+ "labeled-stream-splicer": "2.0.0",
+ "module-deps": "4.1.1",
+ "os-browserify": "0.3.0",
+ "parents": "1.0.1",
+ "path-browserify": "0.0.0",
+ "process": "0.11.10",
+ "punycode": "1.4.1",
+ "querystring-es3": "0.2.1",
+ "read-only-stream": "2.0.0",
+ "readable-stream": "2.3.3",
+ "resolve": "1.4.0",
+ "shasum": "1.0.2",
+ "shell-quote": "1.6.1",
+ "stream-browserify": "2.0.1",
+ "stream-http": "2.7.2",
+ "string_decoder": "1.0.3",
+ "subarg": "1.0.0",
+ "syntax-error": "1.3.0",
+ "through2": "2.0.3",
+ "timers-browserify": "1.4.2",
+ "tty-browserify": "0.0.0",
+ "url": "0.11.0",
+ "util": "0.10.3",
+ "vm-browserify": "0.0.4",
+ "xtend": "4.0.1"
+ },
+ "dependencies": {
+ "browserify-zlib": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+ "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+ "dev": true,
+ "requires": {
+ "pako": "1.0.6"
+ }
+ },
+ "os-browserify": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+ "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
+ "dev": true
+ },
+ "pako": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
+ "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==",
+ "dev": true
+ }
+ }
},
"browserify-aes": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.6.tgz",
"integrity": "sha1-Xncl297x/Vkw1OurSFZ85FHEigo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "buffer-xor": "1.0.3",
+ "cipher-base": "1.0.4",
+ "create-hash": "1.1.3",
+ "evp_bytestokey": "1.0.0",
+ "inherits": "2.0.3"
+ }
},
"browserify-cipher": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz",
"integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "browserify-aes": "1.0.6",
+ "browserify-des": "1.0.0",
+ "evp_bytestokey": "1.0.0"
+ }
},
"browserify-des": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz",
"integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "cipher-base": "1.0.4",
+ "des.js": "1.0.0",
+ "inherits": "2.0.3"
+ }
},
"browserify-rsa": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
"integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "bn.js": "4.11.8",
+ "randombytes": "2.0.5"
+ }
},
"browserify-sign": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
"integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
- "dev": true
- },
- "browserify-zlib": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
- "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "bn.js": "4.11.8",
+ "browserify-rsa": "4.0.1",
+ "create-hash": "1.1.3",
+ "create-hmac": "1.1.6",
+ "elliptic": "6.4.0",
+ "inherits": "2.0.3",
+ "parse-asn1": "5.1.0"
+ }
},
"bs-recipes": {
"version": "1.3.4",
@@ -906,10 +1523,14 @@
"dev": true
},
"buffer": {
- "version": "5.0.6",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.0.6.tgz",
- "integrity": "sha1-LqZp9+7Atu2gWwj4tf9mGyhXNYg=",
- "dev": true
+ "version": "5.0.7",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.0.7.tgz",
+ "integrity": "sha512-NeeHXWh5pCbPQCt2/6rLvXqapZfVsqw/YgRgaHpT3H9Uzgs+S0lSg5SQzouIuDvcmlQRqBe8hOO2scKCu3cxrg==",
+ "dev": true,
+ "requires": {
+ "base64-js": "1.2.1",
+ "ieee754": "1.1.8"
+ }
},
"buffer-xor": {
"version": "1.0.3",
@@ -945,7 +1566,10 @@
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
"integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "callsites": "0.2.0"
+ }
},
"callsite": {
"version": "1.0.0",
@@ -966,16 +1590,20 @@
"dev": true
},
"caseless": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
- "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=",
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
"dev": true
},
"center-align": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
"integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "align-text": "0.1.4",
+ "lazy-cache": "1.0.4"
+ }
},
"chain-function": {
"version": "1.0.0",
@@ -986,29 +1614,54 @@
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "dev": true
- },
- "change-emitter": {
- "version": "0.1.6",
- "resolved": "https://registry.npmjs.org/change-emitter/-/change-emitter-0.1.6.tgz",
- "integrity": "sha1-6LL+PX8at9aaMhma/5HqaTFAlRU="
+ "dev": true,
+ "requires": {
+ "ansi-styles": "2.2.1",
+ "escape-string-regexp": "1.0.5",
+ "has-ansi": "2.0.0",
+ "strip-ansi": "3.0.1",
+ "supports-color": "2.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+ "dev": true
+ }
+ }
},
"chokidar": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
"integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "anymatch": "1.3.2",
+ "async-each": "1.0.1",
+ "fsevents": "1.1.2",
+ "glob-parent": "2.0.0",
+ "inherits": "2.0.3",
+ "is-binary-path": "1.0.1",
+ "is-glob": "2.0.1",
+ "path-is-absolute": "1.0.1",
+ "readdirp": "2.1.0"
+ }
},
"cipher-base": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.3.tgz",
- "integrity": "sha1-7qvxlEGc6QDaMBjCB9IS8qbfCgc=",
- "dev": true
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+ "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3",
+ "safe-buffer": "5.1.1"
+ }
},
"circular-json": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz",
- "integrity": "sha1-vos2rvzN6LPKeqLWr8B6NyQsDS0=",
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
+ "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
"dev": true
},
"classnames": {
@@ -1020,24 +1673,37 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
"integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "restore-cursor": "2.0.0"
+ }
},
"cli-width": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz",
- "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
"dev": true
},
"clipboard": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-1.7.1.tgz",
- "integrity": "sha1-Ng1taUbpmnof7zleQrqStem1oWs="
+ "integrity": "sha1-Ng1taUbpmnof7zleQrqStem1oWs=",
+ "requires": {
+ "good-listener": "1.2.2",
+ "select": "1.1.2",
+ "tiny-emitter": "2.0.2"
+ }
},
"cliui": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
"integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "string-width": "1.0.2",
+ "strip-ansi": "3.0.1",
+ "wrap-ansi": "2.1.0"
+ }
},
"clone": {
"version": "1.0.2",
@@ -1064,24 +1730,53 @@
"dev": true
},
"collection-map": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-0.1.0.tgz",
- "integrity": "sha1-TP+R0lEI159O3uzObs7j5IjyZ8I=",
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz",
+ "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=",
"dev": true,
+ "requires": {
+ "arr-map": "2.0.2",
+ "for-own": "1.0.0",
+ "make-iterator": "1.0.0"
+ },
"dependencies": {
- "make-iterator": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-0.1.1.tgz",
- "integrity": "sha1-hz0nuBmKRlqBSDtvXRbaToY+z1s=",
- "dev": true
+ "for-own": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
+ "dev": true,
+ "requires": {
+ "for-in": "1.0.2"
+ }
}
}
},
+ "color-convert": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz",
+ "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=",
+ "dev": true,
+ "requires": {
+ "color-name": "1.1.3"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+ "dev": true
+ },
"combine-source-map": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.7.2.tgz",
"integrity": "sha1-CHAxKFazB6h8xKxIbzqaYq7MwJ4=",
"dev": true,
+ "requires": {
+ "convert-source-map": "1.1.3",
+ "inline-source-map": "0.6.2",
+ "lodash.memoize": "3.0.4",
+ "source-map": "0.5.6"
+ },
"dependencies": {
"convert-source-map": {
"version": "1.1.3",
@@ -1095,12 +1790,15 @@
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
"integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "delayed-stream": "1.0.0"
+ }
},
"commander": {
- "version": "2.10.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.10.0.tgz",
- "integrity": "sha512-q/r9trjmuikWDRJNTBHAVnWhuU6w+z80KgBq7j9YDclik5E7X4xi0KnlZBNFA1zOQ+SH/vHMWd2mC9QTOz7GpA==",
+ "version": "2.11.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
+ "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
"dev": true
},
"component-bind": {
@@ -1132,12 +1830,25 @@
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz",
"integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=",
"dev": true,
+ "requires": {
+ "inherits": "2.0.3",
+ "readable-stream": "2.0.6",
+ "typedarray": "0.0.6"
+ },
"dependencies": {
"readable-stream": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
"integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "1.0.0",
+ "process-nextick-args": "1.0.7",
+ "string_decoder": "0.10.31",
+ "util-deprecate": "1.0.2"
+ }
},
"string_decoder": {
"version": "0.10.31",
@@ -1151,19 +1862,31 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.0.4.tgz",
"integrity": "sha1-9Vs74q60dgGxCi1SWcz7cP0vHdY=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "source-map": "0.5.6"
+ }
},
"connect": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/connect/-/connect-3.5.0.tgz",
"integrity": "sha1-s1dSWgtMH1BZnNmD4dnv7qlncZg=",
"dev": true,
+ "requires": {
+ "debug": "2.2.0",
+ "finalhandler": "0.5.0",
+ "parseurl": "1.3.1",
+ "utils-merge": "1.0.0"
+ },
"dependencies": {
"debug": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
"integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "ms": "0.7.1"
+ }
},
"ms": {
"version": "0.7.1",
@@ -1183,7 +1906,10 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
"integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "date-now": "0.1.4"
+ }
},
"constants-browserify": {
"version": "1.0.0",
@@ -1213,12 +1939,16 @@
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/copy-props/-/copy-props-1.6.0.tgz",
"integrity": "sha1-8DJLvumXcRAeezraES8xPDk9uO0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "each-props": "1.3.1",
+ "is-plain-object": "2.0.4"
+ }
},
"core-js": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz",
- "integrity": "sha1-TekR5mew6ukSTjQlS1OupvxhjT4="
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.0.tgz",
+ "integrity": "sha1-VpwFCRi+ZIazg3VSAorgRmtxcIY="
},
"core-util-is": {
"version": "1.0.2",
@@ -1230,41 +1960,75 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz",
"integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "bn.js": "4.11.8",
+ "elliptic": "6.4.0"
+ }
},
"create-hash": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
"integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "cipher-base": "1.0.4",
+ "inherits": "2.0.3",
+ "ripemd160": "2.0.1",
+ "sha.js": "2.4.8"
+ }
},
"create-hmac": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz",
"integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "cipher-base": "1.0.4",
+ "create-hash": "1.1.3",
+ "inherits": "2.0.3",
+ "ripemd160": "2.0.1",
+ "safe-buffer": "5.1.1",
+ "sha.js": "2.4.8"
+ }
},
- "create-react-class": {
- "version": "15.6.0",
- "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.0.tgz",
- "integrity": "sha1-q0SEl8JlZuHilBPogyB9V8/nvtQ="
+ "cross-spawn": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+ "dev": true,
+ "requires": {
+ "lru-cache": "4.1.1",
+ "shebang-command": "1.2.0",
+ "which": "1.3.0"
+ }
},
"cryptiles": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
"integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "boom": "2.10.1"
+ }
},
"crypto-browserify": {
- "version": "3.11.0",
- "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.0.tgz",
- "integrity": "sha1-NlKgkGq5sqfgw85mpAjpV6JIVSI=",
- "dev": true
- },
- "css-in-js-utils": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-1.0.3.tgz",
- "integrity": "sha1-msfgL3Y8+F2UAXZmVl7WiltfMhU="
+ "version": "3.11.1",
+ "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.1.tgz",
+ "integrity": "sha512-Na7ZlwCOqoaW5RwUK1WpXws2kv8mNhWdTlzob0UXulk6G9BDbyiJaGTYBIX61Ozn9l1EPPJpICZb4DaOpT9NlQ==",
+ "dev": true,
+ "requires": {
+ "browserify-cipher": "1.0.0",
+ "browserify-sign": "4.0.4",
+ "create-ecdh": "4.0.0",
+ "create-hash": "1.1.3",
+ "create-hmac": "1.1.6",
+ "diffie-hellman": "5.0.2",
+ "inherits": "2.0.3",
+ "pbkdf2": "3.0.13",
+ "public-encrypt": "4.0.0",
+ "randombytes": "2.0.5"
+ }
},
"css-parse": {
"version": "1.7.0",
@@ -1276,13 +2040,19 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
"integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "es5-ext": "0.10.29"
+ }
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"dev": true,
+ "requires": {
+ "assert-plus": "1.0.0"
+ },
"dependencies": {
"assert-plus": {
"version": "1.0.0",
@@ -1305,9 +2075,12 @@
"dev": true
},
"debug": {
- "version": "2.6.8",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
- "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw="
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "requires": {
+ "ms": "2.0.0"
+ }
},
"decamelize": {
"version": "1.2.0",
@@ -1315,6 +2088,11 @@
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
"dev": true
},
+ "deep-diff": {
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz",
+ "integrity": "sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ="
+ },
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@@ -1327,6 +2105,16 @@
"integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=",
"dev": true
},
+ "define-properties": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
+ "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
+ "dev": true,
+ "requires": {
+ "foreach": "2.0.5",
+ "object-keys": "1.0.11"
+ }
+ },
"defined": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
@@ -1338,6 +2126,14 @@
"resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz",
"integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=",
"dev": true,
+ "requires": {
+ "globby": "6.1.0",
+ "is-path-cwd": "1.0.0",
+ "is-path-in-cwd": "1.0.0",
+ "p-map": "1.1.1",
+ "pify": "3.0.0",
+ "rimraf": "2.6.1"
+ },
"dependencies": {
"pify": {
"version": "3.0.0",
@@ -1359,22 +2155,32 @@
"integrity": "sha1-moJRp3fXAl+qVXN7w7BxdCEnqf0="
},
"depd": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz",
- "integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM=",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
+ "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=",
"dev": true
},
"deps-sort": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz",
"integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "JSONStream": "1.3.1",
+ "shasum": "1.0.2",
+ "subarg": "1.0.0",
+ "through2": "2.0.3"
+ }
},
"des.js": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz",
"integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3",
+ "minimalistic-assert": "1.0.0"
+ }
},
"destroy": {
"version": "1.0.4",
@@ -1386,19 +2192,29 @@
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz",
"integrity": "sha1-STXe39lIhkjgBrASlWbpOGcR6mM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "fs-exists-sync": "0.1.0"
+ }
},
"detect-indent": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
"integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "repeating": "2.0.1"
+ }
},
"detective": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/detective/-/detective-4.5.0.tgz",
"integrity": "sha1-blqMaybmx6JUsca210kNmOyR7dE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "acorn": "4.0.13",
+ "defined": "1.0.0"
+ }
},
"dev-ip": {
"version": "1.0.1",
@@ -1410,13 +2226,22 @@
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz",
"integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "bn.js": "4.11.8",
+ "miller-rabin": "4.0.0",
+ "randombytes": "2.0.5"
+ }
},
"doctrine": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz",
"integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "esutils": "2.0.2",
+ "isarray": "1.0.0"
+ }
},
"dom-helpers": {
"version": "3.2.1",
@@ -1438,39 +2263,41 @@
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
"integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "readable-stream": "2.3.3"
+ }
},
"duplexify": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.0.tgz",
- "integrity": "sha1-GqdzAC4VeEV+nZ1KULDMquvL1gQ=",
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.1.tgz",
+ "integrity": "sha512-j5goxHTwVED1Fpe5hh3q9R93Kip0Bg2KVAt4f8CEYM3UEwYcPSvWbXaUQOzdX/HtiNomipv+gU7ASQPDbV7pGQ==",
"dev": true,
- "dependencies": {
- "end-of-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.0.0.tgz",
- "integrity": "sha1-1FlucCc0qT5A6a+GQxnqvZn/Lw4=",
- "dev": true
- },
- "once": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz",
- "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=",
- "dev": true
- }
+ "requires": {
+ "end-of-stream": "1.4.0",
+ "inherits": "2.0.3",
+ "readable-stream": "2.3.3",
+ "stream-shift": "1.0.0"
}
},
"each-props": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.0.tgz",
- "integrity": "sha1-ftgDHJJ2iK7bSoluuRSFtEh7kOo=",
- "dev": true
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.1.tgz",
+ "integrity": "sha1-/BOPUeOid0KG1IWOAtbn3kYt4Vg=",
+ "dev": true,
+ "requires": {
+ "is-plain-object": "2.0.4",
+ "object.defaults": "1.1.0"
+ }
},
"easy-extender": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/easy-extender/-/easy-extender-2.3.2.tgz",
"integrity": "sha1-PTJI/r4rFZYHMW2PnPSRwWZIIh0=",
"dev": true,
+ "requires": {
+ "lodash": "3.10.1"
+ },
"dependencies": {
"lodash": {
"version": "3.10.1",
@@ -1484,14 +2311,20 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/eazy-logger/-/eazy-logger-3.0.2.tgz",
"integrity": "sha1-oyWqXlPROiIliJsqxBE7K5Y29Pw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "tfunk": "3.1.0"
+ }
},
"ecc-jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
"integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "jsbn": "0.1.1"
+ }
},
"ee-first": {
"version": "1.1.1",
@@ -1503,7 +2336,16 @@
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz",
"integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "bn.js": "4.11.8",
+ "brorand": "1.1.0",
+ "hash.js": "1.1.3",
+ "hmac-drbg": "1.0.1",
+ "inherits": "2.0.3",
+ "minimalistic-assert": "1.0.0",
+ "minimalistic-crypto-utils": "1.0.1"
+ }
},
"emitter-steward": {
"version": "1.0.0",
@@ -1520,25 +2362,42 @@
"encoding": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
- "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s="
+ "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
+ "requires": {
+ "iconv-lite": "0.4.18"
+ }
},
"end-of-stream": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz",
"integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "once": "1.4.0"
+ }
},
"engine.io": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.0.tgz",
"integrity": "sha1-PutfJky3XbvsG6rqJtYfWk6s4qo=",
"dev": true,
+ "requires": {
+ "accepts": "1.3.3",
+ "base64id": "0.1.0",
+ "cookie": "0.3.1",
+ "debug": "2.3.3",
+ "engine.io-parser": "1.3.1",
+ "ws": "1.1.1"
+ },
"dependencies": {
"debug": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "ms": "0.7.2"
+ }
},
"ms": {
"version": "0.7.2",
@@ -1553,6 +2412,20 @@
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.0.tgz",
"integrity": "sha1-e3MOQSdBQIdZbZvjyI0rxf22z1w=",
"dev": true,
+ "requires": {
+ "component-emitter": "1.2.1",
+ "component-inherit": "0.0.3",
+ "debug": "2.3.3",
+ "engine.io-parser": "1.3.1",
+ "has-cors": "1.1.0",
+ "indexof": "0.0.1",
+ "parsejson": "0.0.3",
+ "parseqs": "0.0.5",
+ "parseuri": "0.0.5",
+ "ws": "1.1.1",
+ "xmlhttprequest-ssl": "1.5.3",
+ "yeast": "0.1.2"
+ },
"dependencies": {
"component-emitter": {
"version": "1.2.1",
@@ -1564,7 +2437,10 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "ms": "0.7.2"
+ }
},
"ms": {
"version": "0.7.2",
@@ -1579,12 +2455,23 @@
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.1.tgz",
"integrity": "sha1-lVTxrjMQfW+9FwylRm0vgz9qB88=",
"dev": true,
+ "requires": {
+ "after": "0.8.1",
+ "arraybuffer.slice": "0.0.6",
+ "base64-arraybuffer": "0.1.5",
+ "blob": "0.0.4",
+ "has-binary": "0.1.6",
+ "wtf-8": "1.0.0"
+ },
"dependencies": {
"has-binary": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz",
"integrity": "sha1-JTJvOc+k9hath4eJTjryz7x7bhA=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "isarray": "0.0.1"
+ }
},
"isarray": {
"version": "0.0.1",
@@ -1595,40 +2482,90 @@
}
},
"envify": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/envify/-/envify-4.0.0.tgz",
- "integrity": "sha1-95E0Pj0RzCnM5BFQMAqK9hxmyrA=",
- "dev": true
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/envify/-/envify-4.1.0.tgz",
+ "integrity": "sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw==",
+ "dev": true,
+ "requires": {
+ "esprima": "4.0.0",
+ "through": "2.3.8"
+ }
},
"error-ex": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz",
"integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-arrayish": "0.2.1"
+ }
+ },
+ "es-abstract": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.8.0.tgz",
+ "integrity": "sha512-Cf9/h5MrXtExM20gSS55YFrGKCyPrRBjIVBtVyy8vmlsDfe0NPKMWj65tPLgzyfPuapWxh5whpXCtW4+AW5mRg==",
+ "dev": true,
+ "requires": {
+ "es-to-primitive": "1.1.1",
+ "function-bind": "1.1.0",
+ "has": "1.0.1",
+ "is-callable": "1.1.3",
+ "is-regex": "1.0.4"
+ }
+ },
+ "es-to-primitive": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz",
+ "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=",
+ "dev": true,
+ "requires": {
+ "is-callable": "1.1.3",
+ "is-date-object": "1.0.1",
+ "is-symbol": "1.0.1"
+ }
},
"es5-ext": {
- "version": "0.10.23",
- "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.23.tgz",
- "integrity": "sha1-dXi1G+l0IHpUh4IbVlOMIk5Oezg=",
- "dev": true
+ "version": "0.10.29",
+ "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.29.tgz",
+ "integrity": "sha512-KXla9NXo5sdaEkGSmbFPYgjH6m75kxsthL6GDRSug/Y2OiMoYm0I9giL39j4cgmaFmAbkIFJ6gG+SGKnLSmOvA==",
+ "dev": true,
+ "requires": {
+ "es6-iterator": "2.0.1",
+ "es6-symbol": "3.1.1"
+ }
},
"es6-iterator": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz",
"integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "d": "1.0.0",
+ "es5-ext": "0.10.29",
+ "es6-symbol": "3.1.1"
+ }
},
"es6-symbol": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
"integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "d": "1.0.0",
+ "es5-ext": "0.10.29"
+ }
},
"es6-weak-map": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
"integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "d": "1.0.0",
+ "es5-ext": "0.10.29",
+ "es6-iterator": "2.0.1",
+ "es6-symbol": "3.1.1"
+ }
},
"escape-html": {
"version": "1.0.3",
@@ -1643,78 +2580,270 @@
"dev": true
},
"eslint": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.1.1.tgz",
- "integrity": "sha1-+svfz+Pg+s06i4DcmMTmwTrlgt8=",
+ "version": "4.10.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.10.0.tgz",
+ "integrity": "sha512-MMVl8P/dYUFZEvolL8PYt7qc5LNdS2lwheq9BYa5Y07FblhcZqFyaUqlS8TW5QITGex21tV4Lk0a3fK8lsJIkA==",
"dev": true,
+ "requires": {
+ "ajv": "5.3.0",
+ "babel-code-frame": "6.26.0",
+ "chalk": "2.3.0",
+ "concat-stream": "1.6.0",
+ "cross-spawn": "5.1.0",
+ "debug": "3.1.0",
+ "doctrine": "2.0.0",
+ "eslint-scope": "3.7.1",
+ "espree": "3.5.1",
+ "esquery": "1.0.0",
+ "estraverse": "4.2.0",
+ "esutils": "2.0.2",
+ "file-entry-cache": "2.0.0",
+ "functional-red-black-tree": "1.0.1",
+ "glob": "7.1.2",
+ "globals": "9.18.0",
+ "ignore": "3.3.5",
+ "imurmurhash": "0.1.4",
+ "inquirer": "3.2.3",
+ "is-resolvable": "1.0.0",
+ "js-yaml": "3.9.1",
+ "json-stable-stringify": "1.0.1",
+ "levn": "0.3.0",
+ "lodash": "4.17.4",
+ "minimatch": "3.0.4",
+ "mkdirp": "0.5.1",
+ "natural-compare": "1.4.0",
+ "optionator": "0.8.2",
+ "path-is-inside": "1.0.2",
+ "pluralize": "7.0.0",
+ "progress": "2.0.0",
+ "require-uncached": "1.0.3",
+ "semver": "5.4.1",
+ "strip-ansi": "4.0.0",
+ "strip-json-comments": "2.0.1",
+ "table": "4.0.1",
+ "text-table": "0.2.0"
+ },
"dependencies": {
+ "acorn": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.0.tgz",
+ "integrity": "sha512-TJT3XkJ12+1vDj24PN5KO5rbUr34UzETv0ZJ4jLBy1IUhQFBb89xpGq9CgovdJfogOuwpFteHyl0jib4ElODzA==",
+ "dev": true
+ },
+ "ajv": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.3.0.tgz",
+ "integrity": "sha1-RBT/dKUIecII7l/cgm4ywwNUnto=",
+ "dev": true,
+ "requires": {
+ "co": "4.6.0",
+ "fast-deep-equal": "1.0.0",
+ "fast-json-stable-stringify": "2.0.0",
+ "json-schema-traverse": "0.3.1"
+ }
+ },
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
+ "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
+ "dev": true,
+ "requires": {
+ "color-convert": "1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
+ "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "3.2.0",
+ "escape-string-regexp": "1.0.5",
+ "supports-color": "4.5.0"
+ }
+ },
"concat-stream": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz",
"integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3",
+ "readable-stream": "2.3.3",
+ "typedarray": "0.0.6"
+ }
+ },
+ "espree": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.1.tgz",
+ "integrity": "sha1-DJiLirRttTEAoZVK5LqZXd0n2H4=",
+ "dev": true,
+ "requires": {
+ "acorn": "5.2.0",
+ "acorn-jsx": "3.0.1"
+ }
+ },
+ "pluralize": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
+ "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==",
"dev": true
},
- "json-stable-stringify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
- "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
- "dev": true
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "3.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
+ "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
+ "dev": true,
+ "requires": {
+ "has-flag": "2.0.0"
+ }
}
}
},
"eslint-import-resolver-node": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz",
- "integrity": "sha1-Wt2BBujJKNssuiMrzZ76hG49oWw=",
- "dev": true
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.1.tgz",
+ "integrity": "sha512-yUtXS15gIcij68NmXmP9Ni77AQuCN0itXbCc/jWd8C6/yKZaSNXicpC8cgvjnxVdmfsosIXrjpzFq7GcDryb6A==",
+ "dev": true,
+ "requires": {
+ "debug": "2.6.8",
+ "resolve": "1.4.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.8",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
},
"eslint-module-utils": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz",
"integrity": "sha512-jDI/X5l/6D1rRD/3T43q8Qgbls2nq5km5KSqiwlyUbGo5+04fXhMKdCPhjwbqAa6HXWaMxj8Q4hQDIh7IadJQw==",
- "dev": true
+ "dev": true,
+ "requires": {
+ "debug": "2.6.8",
+ "pkg-dir": "1.0.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.8",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
},
"eslint-plugin-import": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.6.0.tgz",
- "integrity": "sha512-JdkYDmMMjhxW6X/IVclD+vQXO6e2nJJT4cKcyTw95mvBCWkr8THXKFhc+WCvGvOscjGuLQzUB7tBeJddrg2jig==",
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.8.0.tgz",
+ "integrity": "sha512-Rf7dfKJxZ16QuTgVv1OYNxkZcsu/hULFnC+e+w0Gzi6jMC3guQoWQgxYxc54IDRinlb6/0v5z/PxxIKmVctN+g==",
"dev": true,
+ "requires": {
+ "builtin-modules": "1.1.1",
+ "contains-path": "0.1.0",
+ "debug": "2.6.9",
+ "doctrine": "1.5.0",
+ "eslint-import-resolver-node": "0.3.1",
+ "eslint-module-utils": "2.1.1",
+ "has": "1.0.1",
+ "lodash.cond": "4.5.2",
+ "minimatch": "3.0.4",
+ "read-pkg-up": "2.0.0"
+ },
"dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
"doctrine": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz",
"integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "esutils": "2.0.2",
+ "isarray": "1.0.0"
+ }
},
"find-up": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
"integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "locate-path": "2.0.0"
+ }
},
"load-json-file": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz",
"integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "parse-json": "2.2.0",
+ "pify": "2.3.0",
+ "strip-bom": "3.0.0"
+ }
},
"path-type": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
"integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "pify": "2.3.0"
+ }
},
"read-pkg": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
"integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "load-json-file": "2.0.0",
+ "normalize-package-data": "2.4.0",
+ "path-type": "2.0.0"
+ }
},
"read-pkg-up": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz",
"integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "find-up": "2.1.0",
+ "read-pkg": "2.0.0"
+ }
},
"strip-bom": {
"version": "3.0.0",
@@ -1725,48 +2854,51 @@
}
},
"eslint-plugin-react": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.1.0.tgz",
- "integrity": "sha1-J3cKzzn1/UnNCvQIPOWBBOs5DUw=",
- "dev": true
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.4.0.tgz",
+ "integrity": "sha512-tvjU9u3VqmW2vVuYnE8Qptq+6ji4JltjOjJ9u7VAOxVYkUkyBZWRvNYKbDv5fN+L6wiA+4we9+qQahZ0m63XEA==",
+ "dev": true,
+ "requires": {
+ "doctrine": "2.0.0",
+ "has": "1.0.1",
+ "jsx-ast-utils": "2.0.0",
+ "prop-types": "15.6.0"
+ }
},
"eslint-scope": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
"integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
- "dev": true
- },
- "espree": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz",
- "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=",
"dev": true,
- "dependencies": {
- "acorn": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.0.3.tgz",
- "integrity": "sha1-xGDfCEkUY/AozLguqzcwvwEIez0=",
- "dev": true
- }
+ "requires": {
+ "esrecurse": "4.2.0",
+ "estraverse": "4.2.0"
}
},
"esprima": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
- "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
+ "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==",
"dev": true
},
"esquery": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz",
"integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "estraverse": "4.2.0"
+ }
},
"esrecurse": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz",
"integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "estraverse": "4.2.0",
+ "object-assign": "4.1.1"
+ }
},
"estraverse": {
"version": "4.2.0",
@@ -1802,37 +2934,60 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz",
"integrity": "sha1-SXtmrZ/vZc18CKYYCCS6FHa2blM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "create-hash": "1.1.3"
+ }
},
"expand-brackets": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
"integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-posix-bracket": "0.1.1"
+ }
},
"expand-range": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
"integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "fill-range": "2.2.3"
+ }
},
"expand-tilde": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz",
"integrity": "sha1-C4HrqJflo9MdHD0QL48BRB5VlEk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "os-homedir": "1.0.2"
+ }
},
"express": {
"version": "2.5.11",
"resolved": "https://registry.npmjs.org/express/-/express-2.5.11.tgz",
"integrity": "sha1-TOjqHzY15p5J8Ou0l7aksKUc5vA=",
"dev": true,
+ "requires": {
+ "connect": "1.9.2",
+ "mime": "1.2.4",
+ "mkdirp": "0.3.0",
+ "qs": "0.4.2"
+ },
"dependencies": {
"connect": {
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/connect/-/connect-1.9.2.tgz",
"integrity": "sha1-QogKIulDiuWait105Df1iujlKAc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "formidable": "1.0.17",
+ "mime": "1.2.4",
+ "qs": "0.4.2"
+ }
},
"mkdirp": {
"version": "0.3.0",
@@ -1858,30 +3013,57 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-extendable": "0.1.1"
+ }
},
"external-editor": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.4.tgz",
"integrity": "sha1-HtkZnanL/i7y96MbL96LDRI2iXI=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "iconv-lite": "0.4.18",
+ "jschardet": "1.5.1",
+ "tmp": "0.0.31"
+ }
},
"extglob": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
"integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-extglob": "1.0.0"
+ }
},
"extsprintf": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz",
- "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
"dev": true
},
"fancy-log": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.0.tgz",
"integrity": "sha1-Rb4X0Cu5kX1gzP/UmVyZnmyMmUg=",
+ "dev": true,
+ "requires": {
+ "chalk": "1.1.3",
+ "time-stamp": "1.1.0"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",
+ "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=",
+ "dev": true
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
"dev": true
},
"fast-levenshtein": {
@@ -1890,29 +3072,24 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
- "fbjs": {
- "version": "0.8.12",
- "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.12.tgz",
- "integrity": "sha1-ELXZL3bUVXX9Y6IX1OoCvqL47QQ=",
- "dependencies": {
- "core-js": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
- "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
- }
- }
- },
"figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
"integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "escape-string-regexp": "1.0.5"
+ }
},
"file-entry-cache": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
"integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "flat-cache": "1.2.2",
+ "object-assign": "4.1.1"
+ }
},
"filename-regex": {
"version": "2.0.1",
@@ -1924,19 +3101,36 @@
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
"integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-number": "2.1.0",
+ "isobject": "2.1.0",
+ "randomatic": "1.1.7",
+ "repeat-element": "1.1.2",
+ "repeat-string": "1.6.1"
+ }
},
"finalhandler": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.0.tgz",
"integrity": "sha1-6VCKvs6bbbqHGmlCodeRG5GRGsc=",
"dev": true,
+ "requires": {
+ "debug": "2.2.0",
+ "escape-html": "1.0.3",
+ "on-finished": "2.3.0",
+ "statuses": "1.3.1",
+ "unpipe": "1.0.0"
+ },
"dependencies": {
"debug": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
"integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "ms": "0.7.1"
+ }
},
"ms": {
"version": "0.7.1",
@@ -1950,25 +3144,45 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "path-exists": "2.1.0",
+ "pinkie-promise": "2.0.1"
+ }
},
"findup-sync": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz",
"integrity": "sha1-QAQ5Kee8YK3wt/SCfExudaDeyhI=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "detect-file": "0.1.0",
+ "is-glob": "2.0.1",
+ "micromatch": "2.3.11",
+ "resolve-dir": "0.1.1"
+ }
},
"fined": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fined/-/fined-1.1.0.tgz",
"integrity": "sha1-s33IRLdqL15wgeiE98CuNE8VNHY=",
"dev": true,
+ "requires": {
+ "expand-tilde": "2.0.2",
+ "is-plain-object": "2.0.4",
+ "object.defaults": "1.1.0",
+ "object.pick": "1.3.0",
+ "parse-filepath": "1.0.1"
+ },
"dependencies": {
"expand-tilde": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
"integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "homedir-polyfill": "1.0.1"
+ }
}
}
},
@@ -1989,18 +3203,41 @@
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz",
"integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=",
"dev": true,
+ "requires": {
+ "circular-json": "0.3.3",
+ "del": "2.2.2",
+ "graceful-fs": "4.1.11",
+ "write": "0.2.1"
+ },
"dependencies": {
"del": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
"integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "globby": "5.0.0",
+ "is-path-cwd": "1.0.0",
+ "is-path-in-cwd": "1.0.0",
+ "object-assign": "4.1.1",
+ "pify": "2.3.0",
+ "pinkie-promise": "2.0.1",
+ "rimraf": "2.6.1"
+ }
},
"globby": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
"integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "array-union": "1.0.2",
+ "arrify": "1.0.1",
+ "glob": "7.1.2",
+ "object-assign": "4.1.1",
+ "pify": "2.3.0",
+ "pinkie-promise": "2.0.1"
+ }
}
}
},
@@ -2014,6 +3251,15 @@
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
"integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+ "dev": true,
+ "requires": {
+ "for-in": "1.0.2"
+ }
+ },
+ "foreach": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
+ "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=",
"dev": true
},
"forever-agent": {
@@ -2032,7 +3278,12 @@
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
"integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "asynckit": "0.4.0",
+ "combined-stream": "1.0.5",
+ "mime-types": "2.1.16"
+ }
},
"formidable": {
"version": "1.0.17",
@@ -2056,7 +3307,12 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz",
"integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "jsonfile": "3.0.1",
+ "universalify": "0.1.1"
+ }
},
"fs.realpath": {
"version": "1.0.0",
@@ -2070,6 +3326,10 @@
"integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==",
"dev": true,
"optional": true,
+ "requires": {
+ "nan": "2.6.2",
+ "node-pre-gyp": "0.6.36"
+ },
"dependencies": {
"abbrev": {
"version": "1.1.0",
@@ -2081,7 +3341,11 @@
"version": "4.11.8",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "co": "4.6.0",
+ "json-stable-stringify": "1.0.1"
+ }
},
"ansi-regex": {
"version": "2.1.1",
@@ -2098,7 +3362,11 @@
"version": "1.1.4",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "delegates": "1.0.0",
+ "readable-stream": "2.2.9"
+ }
},
"asn1": {
"version": "0.2.3",
@@ -2139,22 +3407,35 @@
"version": "1.0.1",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "tweetnacl": "0.14.5"
+ }
},
"block-stream": {
"version": "0.0.9",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3"
+ }
},
"boom": {
"version": "2.10.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "hoek": "2.16.3"
+ }
},
"brace-expansion": {
"version": "1.1.7",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "balanced-match": "0.4.2",
+ "concat-map": "0.0.1"
+ }
},
"buffer-shims": {
"version": "1.0.0",
@@ -2181,7 +3462,10 @@
"combined-stream": {
"version": "1.0.5",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "delayed-stream": "1.0.0"
+ }
},
"concat-map": {
"version": "0.0.1",
@@ -2202,13 +3486,19 @@
"version": "2.0.5",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "boom": "2.10.1"
+ }
},
"dashdash": {
"version": "1.14.1",
"bundled": true,
"dev": true,
"optional": true,
+ "requires": {
+ "assert-plus": "1.0.0"
+ },
"dependencies": {
"assert-plus": {
"version": "1.0.0",
@@ -2222,7 +3512,10 @@
"version": "2.6.8",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
},
"deep-extend": {
"version": "0.4.2",
@@ -2245,7 +3538,10 @@
"version": "0.1.1",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "jsbn": "0.1.1"
+ }
},
"extend": {
"version": "3.0.1",
@@ -2268,7 +3564,12 @@
"version": "2.1.4",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "asynckit": "0.4.0",
+ "combined-stream": "1.0.5",
+ "mime-types": "2.1.15"
+ }
},
"fs.realpath": {
"version": "1.0.0",
@@ -2278,25 +3579,49 @@
"fstream": {
"version": "1.0.11",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "inherits": "2.0.3",
+ "mkdirp": "0.5.1",
+ "rimraf": "2.6.1"
+ }
},
"fstream-ignore": {
"version": "1.0.5",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "fstream": "1.0.11",
+ "inherits": "2.0.3",
+ "minimatch": "3.0.4"
+ }
},
"gauge": {
"version": "2.7.4",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "aproba": "1.1.1",
+ "console-control-strings": "1.1.0",
+ "has-unicode": "2.0.1",
+ "object-assign": "4.1.1",
+ "signal-exit": "3.0.2",
+ "string-width": "1.0.2",
+ "strip-ansi": "3.0.1",
+ "wide-align": "1.1.2"
+ }
},
"getpass": {
"version": "0.1.7",
"bundled": true,
"dev": true,
"optional": true,
+ "requires": {
+ "assert-plus": "1.0.0"
+ },
"dependencies": {
"assert-plus": {
"version": "1.0.0",
@@ -2309,7 +3634,15 @@
"glob": {
"version": "7.1.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "fs.realpath": "1.0.0",
+ "inflight": "1.0.6",
+ "inherits": "2.0.3",
+ "minimatch": "3.0.4",
+ "once": "1.4.0",
+ "path-is-absolute": "1.0.1"
+ }
},
"graceful-fs": {
"version": "4.1.11",
@@ -2326,7 +3659,11 @@
"version": "4.2.1",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "ajv": "4.11.8",
+ "har-schema": "1.0.5"
+ }
},
"has-unicode": {
"version": "2.0.1",
@@ -2338,7 +3675,13 @@
"version": "3.1.3",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "boom": "2.10.1",
+ "cryptiles": "2.0.5",
+ "hoek": "2.16.3",
+ "sntp": "1.0.9"
+ }
},
"hoek": {
"version": "2.16.3",
@@ -2349,12 +3692,21 @@
"version": "1.1.1",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "assert-plus": "0.2.0",
+ "jsprim": "1.4.0",
+ "sshpk": "1.13.0"
+ }
},
"inflight": {
"version": "1.0.6",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "once": "1.4.0",
+ "wrappy": "1.0.2"
+ }
},
"inherits": {
"version": "2.0.3",
@@ -2370,7 +3722,10 @@
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "number-is-nan": "1.0.1"
+ }
},
"is-typedarray": {
"version": "1.0.0",
@@ -2393,7 +3748,10 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "jsbn": "0.1.1"
+ }
},
"jsbn": {
"version": "0.1.1",
@@ -2411,7 +3769,10 @@
"version": "1.0.1",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "jsonify": "0.0.0"
+ }
},
"json-stringify-safe": {
"version": "5.0.1",
@@ -2430,6 +3791,12 @@
"bundled": true,
"dev": true,
"optional": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.0.2",
+ "json-schema": "0.2.3",
+ "verror": "1.3.6"
+ },
"dependencies": {
"assert-plus": {
"version": "1.0.0",
@@ -2447,12 +3814,18 @@
"mime-types": {
"version": "2.1.15",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "mime-db": "1.27.0"
+ }
},
"minimatch": {
"version": "3.0.4",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "brace-expansion": "1.1.7"
+ }
},
"minimist": {
"version": "0.0.8",
@@ -2462,7 +3835,10 @@
"mkdirp": {
"version": "0.5.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
},
"ms": {
"version": "2.0.0",
@@ -2474,19 +3850,40 @@
"version": "0.6.36",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "mkdirp": "0.5.1",
+ "nopt": "4.0.1",
+ "npmlog": "4.1.0",
+ "rc": "1.2.1",
+ "request": "2.81.0",
+ "rimraf": "2.6.1",
+ "semver": "5.3.0",
+ "tar": "2.2.1",
+ "tar-pack": "3.4.0"
+ }
},
"nopt": {
"version": "4.0.1",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "abbrev": "1.1.0",
+ "osenv": "0.1.4"
+ }
},
"npmlog": {
"version": "4.1.0",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "are-we-there-yet": "1.1.4",
+ "console-control-strings": "1.1.0",
+ "gauge": "2.7.4",
+ "set-blocking": "2.0.0"
+ }
},
"number-is-nan": {
"version": "1.0.1",
@@ -2508,7 +3905,10 @@
"once": {
"version": "1.4.0",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "wrappy": "1.0.2"
+ }
},
"os-homedir": {
"version": "1.0.2",
@@ -2526,7 +3926,11 @@
"version": "0.1.4",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "os-homedir": "1.0.2",
+ "os-tmpdir": "1.0.2"
+ }
},
"path-is-absolute": {
"version": "1.0.1",
@@ -2561,6 +3965,12 @@
"bundled": true,
"dev": true,
"optional": true,
+ "requires": {
+ "deep-extend": "0.4.2",
+ "ini": "1.3.4",
+ "minimist": "1.2.0",
+ "strip-json-comments": "2.0.1"
+ },
"dependencies": {
"minimist": {
"version": "1.2.0",
@@ -2573,18 +3983,54 @@
"readable-stream": {
"version": "2.2.9",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "buffer-shims": "1.0.0",
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "1.0.0",
+ "process-nextick-args": "1.0.7",
+ "string_decoder": "1.0.1",
+ "util-deprecate": "1.0.2"
+ }
},
"request": {
"version": "2.81.0",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "aws-sign2": "0.6.0",
+ "aws4": "1.6.0",
+ "caseless": "0.12.0",
+ "combined-stream": "1.0.5",
+ "extend": "3.0.1",
+ "forever-agent": "0.6.1",
+ "form-data": "2.1.4",
+ "har-validator": "4.2.1",
+ "hawk": "3.1.3",
+ "http-signature": "1.1.1",
+ "is-typedarray": "1.0.0",
+ "isstream": "0.1.2",
+ "json-stringify-safe": "5.0.1",
+ "mime-types": "2.1.15",
+ "oauth-sign": "0.8.2",
+ "performance-now": "0.2.0",
+ "qs": "6.4.0",
+ "safe-buffer": "5.0.1",
+ "stringstream": "0.0.5",
+ "tough-cookie": "2.3.2",
+ "tunnel-agent": "0.6.0",
+ "uuid": "3.0.1"
+ }
},
"rimraf": {
"version": "2.6.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "glob": "7.1.2"
+ }
},
"safe-buffer": {
"version": "5.0.1",
@@ -2613,13 +4059,27 @@
"version": "1.0.9",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "hoek": "2.16.3"
+ }
},
"sshpk": {
"version": "1.13.0",
"bundled": true,
"dev": true,
"optional": true,
+ "requires": {
+ "asn1": "0.2.3",
+ "assert-plus": "1.0.0",
+ "bcrypt-pbkdf": "1.0.1",
+ "dashdash": "1.14.1",
+ "ecc-jsbn": "0.1.1",
+ "getpass": "0.1.7",
+ "jodid25519": "1.0.2",
+ "jsbn": "0.1.1",
+ "tweetnacl": "0.14.5"
+ },
"dependencies": {
"assert-plus": {
"version": "1.0.0",
@@ -2629,15 +4089,23 @@
}
}
},
- "string_decoder": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true
- },
"string-width": {
"version": "1.0.2",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "code-point-at": "1.1.0",
+ "is-fullwidth-code-point": "1.0.0",
+ "strip-ansi": "3.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.0.1"
+ }
},
"stringstream": {
"version": "0.0.5",
@@ -2648,7 +4116,10 @@
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "ansi-regex": "2.1.1"
+ }
},
"strip-json-comments": {
"version": "2.0.1",
@@ -2659,25 +4130,46 @@
"tar": {
"version": "2.2.1",
"bundled": true,
- "dev": true
+ "dev": true,
+ "requires": {
+ "block-stream": "0.0.9",
+ "fstream": "1.0.11",
+ "inherits": "2.0.3"
+ }
},
"tar-pack": {
"version": "3.4.0",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "debug": "2.6.8",
+ "fstream": "1.0.11",
+ "fstream-ignore": "1.0.5",
+ "once": "1.4.0",
+ "readable-stream": "2.2.9",
+ "rimraf": "2.6.1",
+ "tar": "2.2.1",
+ "uid-number": "0.0.6"
+ }
},
"tough-cookie": {
"version": "2.3.2",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "punycode": "1.4.1"
+ }
},
"tunnel-agent": {
"version": "0.6.0",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "safe-buffer": "5.0.1"
+ }
},
"tweetnacl": {
"version": "0.14.5",
@@ -2706,13 +4198,19 @@
"version": "1.3.6",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "extsprintf": "1.0.2"
+ }
},
"wide-align": {
"version": "1.1.2",
"bundled": true,
"dev": true,
- "optional": true
+ "optional": true,
+ "requires": {
+ "string-width": "1.0.2"
+ }
},
"wrappy": {
"version": "1.0.2",
@@ -2727,16 +4225,10 @@
"integrity": "sha1-FhdnFMgBeY5Ojyz391KUZ7tKV3E=",
"dev": true
},
- "generate-function": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
- "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=",
- "dev": true
- },
- "generate-object-property": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
- "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
+ "functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
"dev": true
},
"get-caller-file": {
@@ -2745,17 +4237,14 @@
"integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=",
"dev": true
},
- "get-values": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/get-values/-/get-values-0.1.0.tgz",
- "integrity": "sha1-OsA1tlpEkj012y/Ct7ojIrbD8p4=",
- "dev": true
- },
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"dev": true,
+ "requires": {
+ "assert-plus": "1.0.0"
+ },
"dependencies": {
"assert-plus": {
"version": "1.0.0",
@@ -2769,37 +4258,73 @@
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
- "dev": true
+ "dev": true,
+ "requires": {
+ "fs.realpath": "1.0.0",
+ "inflight": "1.0.6",
+ "inherits": "2.0.3",
+ "minimatch": "3.0.4",
+ "once": "1.4.0",
+ "path-is-absolute": "1.0.1"
+ }
},
"glob-base": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
"integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "glob-parent": "2.0.0",
+ "is-glob": "2.0.1"
+ }
},
"glob-parent": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
"integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-glob": "2.0.1"
+ }
},
"glob-stream": {
"version": "5.3.5",
"resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-5.3.5.tgz",
"integrity": "sha1-pVZlqajM3EGRWofHAeMtTgFvrSI=",
"dev": true,
+ "requires": {
+ "extend": "3.0.1",
+ "glob": "5.0.15",
+ "glob-parent": "3.1.0",
+ "micromatch": "2.3.11",
+ "ordered-read-streams": "0.3.0",
+ "through2": "0.6.5",
+ "to-absolute-glob": "0.1.1",
+ "unique-stream": "2.2.1"
+ },
"dependencies": {
"glob": {
"version": "5.0.15",
"resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
"integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "inflight": "1.0.6",
+ "inherits": "2.0.3",
+ "minimatch": "3.0.4",
+ "once": "1.4.0",
+ "path-is-absolute": "1.0.1"
+ }
},
"glob-parent": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
"integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-glob": "3.1.0",
+ "path-dirname": "1.0.2"
+ }
},
"is-extglob": {
"version": "2.1.1",
@@ -2811,7 +4336,10 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
"integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-extglob": "2.1.1"
+ }
},
"isarray": {
"version": "0.0.1",
@@ -2823,7 +4351,13 @@
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ }
},
"string_decoder": {
"version": "0.10.31",
@@ -2835,7 +4369,11 @@
"version": "0.6.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
"integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "readable-stream": "1.0.34",
+ "xtend": "4.0.1"
+ }
}
}
},
@@ -2843,19 +4381,35 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-3.2.0.tgz",
"integrity": "sha1-/8Gi09B3g7Zy9eIXmaTQs/7ZLa8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "async-done": "1.2.3",
+ "chokidar": "1.7.0",
+ "lodash.debounce": "4.0.8",
+ "object.defaults": "1.1.0"
+ }
},
"global-modules": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz",
"integrity": "sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "global-prefix": "0.1.5",
+ "is-windows": "0.2.0"
+ }
},
"global-prefix": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz",
"integrity": "sha1-jTvGuNo8qBEqFg2NSW/wRiv+948=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "homedir-polyfill": "1.0.1",
+ "ini": "1.3.4",
+ "is-windows": "0.2.0",
+ "which": "1.3.0"
+ }
},
"globals": {
"version": "9.18.0",
@@ -2867,18 +4421,31 @@
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
"integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "array-union": "1.0.2",
+ "glob": "7.1.2",
+ "object-assign": "4.1.1",
+ "pify": "2.3.0",
+ "pinkie-promise": "2.0.1"
+ }
},
"glogg": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz",
"integrity": "sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "sparkles": "1.0.0"
+ }
},
"good-listener": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
- "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA="
+ "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
+ "requires": {
+ "delegate": "3.1.3"
+ }
},
"graceful-fs": {
"version": "4.1.11",
@@ -2886,15 +4453,15 @@
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true
},
- "graceful-readlink": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
- "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
- "dev": true
- },
"gulp": {
- "version": "git://github.com/gulpjs/gulp.git#38246c3f8b6dbb8d4ef657183e92d90c8299e22f",
+ "version": "git://github.com/gulpjs/gulp.git#6d71a658c61edb3090221579d8f97dbe086ba2ed",
"dev": true,
+ "requires": {
+ "glob-watcher": "3.2.0",
+ "gulp-cli": "1.4.0",
+ "undertaker": "1.2.0",
+ "vinyl-fs": "2.4.4"
+ },
"dependencies": {
"camelcase": {
"version": "2.1.1",
@@ -2903,16 +4470,45 @@
"dev": true
},
"gulp-cli": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-1.3.0.tgz",
- "integrity": "sha1-pr+7i+NTQb4pCuRc0+QBBxIW7dQ=",
- "dev": true
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-1.4.0.tgz",
+ "integrity": "sha1-b1u+LNC9tISdEs+eEkalhh+LT4g=",
+ "dev": true,
+ "requires": {
+ "archy": "1.0.0",
+ "chalk": "1.1.3",
+ "copy-props": "1.6.0",
+ "fancy-log": "1.3.0",
+ "gulplog": "1.0.0",
+ "interpret": "1.0.3",
+ "liftoff": "2.3.0",
+ "lodash.isfunction": "3.0.8",
+ "lodash.isplainobject": "4.0.6",
+ "lodash.sortby": "4.7.0",
+ "matchdep": "1.0.1",
+ "mute-stdout": "1.0.0",
+ "pretty-hrtime": "1.0.3",
+ "semver-greatest-satisfied-range": "1.1.0",
+ "tildify": "1.2.0",
+ "v8flags": "2.1.1",
+ "wreck": "6.3.0",
+ "yargs": "3.32.0"
+ }
},
"yargs": {
"version": "3.32.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz",
"integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "camelcase": "2.1.1",
+ "cliui": "3.2.0",
+ "decamelize": "1.2.0",
+ "os-locale": "1.4.0",
+ "string-width": "1.0.2",
+ "window-size": "0.1.4",
+ "y18n": "3.2.1"
+ }
}
}
},
@@ -2921,6 +4517,15 @@
"resolved": "https://registry.npmjs.org/gulp-css-base64/-/gulp-css-base64-1.3.4.tgz",
"integrity": "sha1-r8pF6DQBBF9HLGe3dtGxUU4RSJ8=",
"dev": true,
+ "requires": {
+ "async": "1.5.2",
+ "buffers": "0.1.1",
+ "chalk": "1.1.3",
+ "gulp-util": "3.0.8",
+ "mime": "1.3.6",
+ "request": "2.81.0",
+ "through2": "2.0.3"
+ },
"dependencies": {
"mime": {
"version": "1.3.6",
@@ -2934,31 +4539,53 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-4.0.0.tgz",
"integrity": "sha512-+qsePo04v1O3JshpNvww9+bOgZEJ6Cc2/w3mEktfKz0NL0zsh1SWzjyIL2FIM2zzy6IYQYv+j8REZORF8dKX4g==",
- "dev": true
+ "dev": true,
+ "requires": {
+ "eslint": "4.10.0",
+ "gulp-util": "3.0.8"
+ }
},
"gulp-header": {
- "version": "1.8.8",
- "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-1.8.8.tgz",
- "integrity": "sha1-RQnGRneqtWte6ORmmnmxZVkzpJ4=",
- "dev": true
+ "version": "1.8.9",
+ "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-1.8.9.tgz",
+ "integrity": "sha1-yfEP7gYy2B6Tl4nG7PRaFRvzCYs=",
+ "dev": true,
+ "requires": {
+ "concat-with-sourcemaps": "1.0.4",
+ "gulp-util": "3.0.8",
+ "object-assign": "4.1.1",
+ "through2": "2.0.3"
+ }
},
"gulp-if": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/gulp-if/-/gulp-if-2.0.2.tgz",
"integrity": "sha1-pJe351cwBQQcqivIt92jyARE1ik=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "gulp-match": "1.0.3",
+ "ternary-stream": "2.0.1",
+ "through2": "2.0.3"
+ }
},
"gulp-match": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/gulp-match/-/gulp-match-1.0.3.tgz",
"integrity": "sha1-kcfA1/Kb7NZgbVfYCn+Hdqh6uo4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "minimatch": "3.0.4"
+ }
},
"gulp-plumber": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/gulp-plumber/-/gulp-plumber-1.1.0.tgz",
"integrity": "sha1-8SF2wtBCL2AwbCQv/2oBo5T6ugk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "gulp-util": "3.0.8",
+ "through2": "2.0.3"
+ }
},
"gulp-rename": {
"version": "1.2.2",
@@ -2970,37 +4597,64 @@
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz",
"integrity": "sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "convert-source-map": "1.5.0",
+ "graceful-fs": "4.1.11",
+ "strip-bom": "2.0.0",
+ "through2": "2.0.3",
+ "vinyl": "1.2.0"
+ }
},
"gulp-stylus": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/gulp-stylus/-/gulp-stylus-2.6.0.tgz",
"integrity": "sha1-sLf6TbhE5u6CsQdcqXQFZGlgg6E=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "accord": "0.26.4",
+ "gulp-util": "3.0.8",
+ "lodash.assign": "3.2.0",
+ "replace-ext": "0.0.1",
+ "stylus": "0.54.5",
+ "through2": "2.0.3",
+ "vinyl-sourcemaps-apply": "0.2.1"
+ }
},
- "gulp-touch": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/gulp-touch/-/gulp-touch-1.0.1.tgz",
- "integrity": "sha1-B+XX0p5eAfC6pPp2ZNg/zqim6Vg=",
- "dev": true
+ "gulp-touch-cmd": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/gulp-touch-cmd/-/gulp-touch-cmd-0.0.1.tgz",
+ "integrity": "sha1-c669BA9cv79Wegbj/beXbvD7iMw=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "through2": "2.0.3"
+ }
},
"gulp-uglify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.0.tgz",
"integrity": "sha1-DfAzHXKg0wLj434QlIXd3zPG0co=",
"dev": true,
+ "requires": {
+ "gulplog": "1.0.0",
+ "has-gulplog": "0.1.0",
+ "lodash": "4.17.4",
+ "make-error-cause": "1.2.2",
+ "through2": "2.0.3",
+ "uglify-js": "3.0.28",
+ "vinyl-sourcemaps-apply": "0.2.1"
+ },
"dependencies": {
- "commander": {
- "version": "2.9.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
- "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
- "dev": true
- },
"uglify-js": {
- "version": "3.0.20",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.0.20.tgz",
- "integrity": "sha512-O/c2/N97k1Ms+23VRx6gIAfGdijuW53SlASmXy0FVapK63rQrduHyE+5X6hUtqNiSLLao9Uv6ijotpNe8t991Q==",
- "dev": true
+ "version": "3.0.28",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.0.28.tgz",
+ "integrity": "sha512-0h/qGay016GG2lVav3Kz174F3T2Vjlz2v6HCt+WDQpoXfco0hWwF5gHK9yh88mUYvIC+N7Z8NT8WpjSp1yoqGA==",
+ "dev": true,
+ "requires": {
+ "commander": "2.11.0",
+ "source-map": "0.5.6"
+ }
}
}
},
@@ -3009,6 +4663,26 @@
"resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz",
"integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=",
"dev": true,
+ "requires": {
+ "array-differ": "1.0.0",
+ "array-uniq": "1.0.3",
+ "beeper": "1.1.1",
+ "chalk": "1.1.3",
+ "dateformat": "2.0.0",
+ "fancy-log": "1.3.0",
+ "gulplog": "1.0.0",
+ "has-gulplog": "0.1.0",
+ "lodash._reescape": "3.0.0",
+ "lodash._reevaluate": "3.0.0",
+ "lodash._reinterpolate": "3.0.0",
+ "lodash.template": "3.6.2",
+ "minimist": "1.2.0",
+ "multipipe": "0.1.2",
+ "object-assign": "3.0.0",
+ "replace-ext": "0.0.1",
+ "through2": "2.0.3",
+ "vinyl": "0.5.3"
+ },
"dependencies": {
"minimist": {
"version": "1.2.0",
@@ -3026,7 +4700,12 @@
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
"integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "clone": "1.0.2",
+ "clone-stats": "0.0.1",
+ "replace-ext": "0.0.1"
+ }
}
}
},
@@ -3034,34 +4713,61 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
"integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=",
+ "dev": true,
+ "requires": {
+ "glogg": "1.0.0"
+ }
+ },
+ "har-schema": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz",
+ "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=",
"dev": true
},
"har-validator": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
- "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=",
- "dev": true
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
+ "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=",
+ "dev": true,
+ "requires": {
+ "ajv": "4.11.8",
+ "har-schema": "1.0.5"
+ }
},
"hark": {
- "version": "github:ibc/hark#bc74011af5c30258a1902c893146c3e0c4b1f79a"
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/hark/-/hark-1.1.6.tgz",
+ "integrity": "sha512-NavBtBszYbDe4AXQc8i8FWEDW34/7ei+ZPYGh6YdNtaWqsQ6ZkDFoYQRlGumMo+43ds+dpUSLSoAYUEgDELCcw==",
+ "requires": {
+ "wildemitter": "1.2.0"
+ }
},
"has": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz",
"integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "function-bind": "1.1.0"
+ }
},
"has-ansi": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "ansi-regex": "2.1.1"
+ }
},
"has-binary": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz",
"integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=",
"dev": true,
+ "requires": {
+ "isarray": "0.0.1"
+ },
"dependencies": {
"isarray": {
"version": "0.0.1",
@@ -3077,35 +4783,61 @@
"integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=",
"dev": true
},
+ "has-flag": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
+ },
"has-gulplog": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
"integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "sparkles": "1.0.0"
+ }
},
"hash-base": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz",
"integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3"
+ }
},
"hash.js": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.1.tgz",
- "integrity": "sha512-I2TYCUjYQMmqmRMCp6jKMC5bvdXxGIZ/heITRR/0F1u0OP920ImEj/cXt3WgcTKBnNYGn7enxUzdai3db829JA==",
- "dev": true
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
+ "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3",
+ "minimalistic-assert": "1.0.0"
+ }
},
"hawk": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
"integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "boom": "2.10.1",
+ "cryptiles": "2.0.5",
+ "hoek": "2.16.3",
+ "sntp": "1.0.9"
+ }
},
"hmac-drbg": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
"integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "hash.js": "1.1.3",
+ "minimalistic-assert": "1.0.0",
+ "minimalistic-crypto-utils": "1.0.1"
+ }
},
"hoek": {
"version": "2.16.3",
@@ -3114,26 +4846,33 @@
"dev": true
},
"hoist-non-react-statics": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz",
- "integrity": "sha1-qkSM8JhtVcxAdzsXF0t90GbLfPs="
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.3.0.tgz",
+ "integrity": "sha1-7eFjGML/H5/joCU5a6Bv1MRGCLs="
},
"home-or-tmp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
"integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "os-homedir": "1.0.2",
+ "os-tmpdir": "1.0.2"
+ }
},
"homedir-polyfill": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz",
"integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "parse-passwd": "1.0.0"
+ }
},
"hosted-git-info": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.4.2.tgz",
- "integrity": "sha1-AHa59GonBQbduq6lZJaJdGBhKmc=",
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",
+ "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==",
"dev": true
},
"htmlescape": {
@@ -3146,19 +4885,33 @@
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.1.tgz",
"integrity": "sha1-eIwNLB3iyBuebowBhDtrl+uSB1A=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3",
+ "setprototypeof": "1.0.2",
+ "statuses": "1.3.1"
+ }
},
"http-proxy": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.15.2.tgz",
"integrity": "sha1-ZC/cr/5S00SNK9o7AHnpQJBk2jE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "eventemitter3": "1.2.0",
+ "requires-port": "1.0.0"
+ }
},
"http-signature": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
"integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "assert-plus": "0.2.0",
+ "jsprim": "1.4.1",
+ "sshpk": "1.13.1"
+ }
},
"https-browserify": {
"version": "1.0.0",
@@ -3166,11 +4919,6 @@
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
"dev": true
},
- "hyphenate-style-name": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz",
- "integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es="
- },
"iconv-lite": {
"version": "0.4.18",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.18.tgz",
@@ -3183,9 +4931,9 @@
"dev": true
},
"ignore": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz",
- "integrity": "sha1-QyNS5XrM2HqzEQ6C0/6g5HgSFW0=",
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.5.tgz",
+ "integrity": "sha512-JLH93mL8amZQhh/p6mfQgVBH3M6epNq3DfsXsTSuSrInVjwyYlFE1nv2AgfRCC8PoOhM0jwQ5v8s9LgbK7yGDw==",
"dev": true
},
"immutable": {
@@ -3216,7 +4964,11 @@
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "once": "1.4.0",
+ "wrappy": "1.0.2"
+ }
},
"inherits": {
"version": "2.0.3",
@@ -3234,18 +4986,32 @@
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz",
"integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=",
- "dev": true
- },
- "inline-style-prefixer": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-3.0.6.tgz",
- "integrity": "sha1-sn/jCbQWijHq84yOjGCrnnwRcx8="
+ "dev": true,
+ "requires": {
+ "source-map": "0.5.6"
+ }
},
"inquirer": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.1.1.tgz",
- "integrity": "sha512-H50sHQwgvvaTBd3HpKMVtL/u6LoHDvYym51gd7bGQe/+9HkCE+J0/3N5FJLfd6O6oz44hHewC2Pc2LodzWVafQ==",
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.2.3.tgz",
+ "integrity": "sha512-Bc3KbimpDTOeQdDj18Ir/rlsGuhBSSNqdOnxaAuKhpkdnMMuKsEGbZD2v5KFF9oso2OU+BPh7+/u5obmFDRmWw==",
"dev": true,
+ "requires": {
+ "ansi-escapes": "2.0.0",
+ "chalk": "2.1.0",
+ "cli-cursor": "2.1.0",
+ "cli-width": "2.2.0",
+ "external-editor": "2.0.4",
+ "figures": "2.0.0",
+ "lodash": "4.17.4",
+ "mute-stream": "0.0.7",
+ "run-async": "2.3.0",
+ "rx-lite": "4.0.8",
+ "rx-lite-aggregates": "4.0.8",
+ "string-width": "2.1.1",
+ "strip-ansi": "4.0.0",
+ "through": "2.3.8"
+ },
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
@@ -3253,6 +5019,26 @@
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
"dev": true
},
+ "ansi-styles": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
+ "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
+ "dev": true,
+ "requires": {
+ "color-convert": "1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz",
+ "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "3.2.0",
+ "escape-string-regexp": "1.0.5",
+ "supports-color": "4.5.0"
+ }
+ },
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
@@ -3260,17 +5046,31 @@
"dev": true
},
"string-width": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz",
- "integrity": "sha1-AwZkVh/BRslCPsfZeP4kV0N/5tA=",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"dev": true,
- "dependencies": {
- "strip-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "dev": true
- }
+ "requires": {
+ "is-fullwidth-code-point": "2.0.0",
+ "strip-ansi": "4.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "3.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
+ "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
+ "dev": true,
+ "requires": {
+ "has-flag": "2.0.0"
}
}
}
@@ -3279,7 +5079,17 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.0.1.tgz",
"integrity": "sha1-wDv04BywhtW15azorQr+eInWOMM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "JSONStream": "1.3.1",
+ "combine-source-map": "0.7.2",
+ "concat-stream": "1.5.2",
+ "is-buffer": "1.1.5",
+ "lexical-scope": "1.2.0",
+ "process": "0.11.10",
+ "through2": "2.0.3",
+ "xtend": "4.0.1"
+ }
},
"interpret": {
"version": "1.0.3",
@@ -3291,7 +5101,9 @@
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",
"integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=",
- "dev": true
+ "requires": {
+ "loose-envify": "1.3.1"
+ }
},
"invert-kv": {
"version": "1.0.0",
@@ -3303,7 +5115,11 @@
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.2.6.tgz",
"integrity": "sha1-IN5p89uULvLYe5wto28XIjWxtes=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-relative": "0.2.1",
+ "is-windows": "0.2.0"
+ }
},
"is-arrayish": {
"version": "0.2.1",
@@ -3315,7 +5131,10 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
"integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "binary-extensions": "1.10.0"
+ }
},
"is-buffer": {
"version": "1.1.5",
@@ -3327,6 +5146,21 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
"integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
+ "dev": true,
+ "requires": {
+ "builtin-modules": "1.1.1"
+ }
+ },
+ "is-callable": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz",
+ "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=",
+ "dev": true
+ },
+ "is-date-object": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
+ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
"dev": true
},
"is-dotfile": {
@@ -3339,7 +5173,10 @@
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
"integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-primitive": "2.0.0"
+ }
},
"is-extendable": {
"version": "0.1.1",
@@ -3357,37 +5194,46 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
"integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "number-is-nan": "1.0.1"
+ }
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "number-is-nan": "1.0.1"
+ }
},
"is-glob": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
- "dev": true
- },
- "is-my-json-valid": {
- "version": "2.16.0",
- "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz",
- "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-extglob": "1.0.0"
+ }
},
"is-number": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
"integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ }
},
"is-number-like": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz",
"integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==",
- "dev": true
+ "dev": true,
+ "requires": {
+ "lodash.isfinite": "3.3.2"
+ }
},
"is-path-cwd": {
"version": "1.0.0",
@@ -3399,24 +5245,33 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz",
"integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-path-inside": "1.0.0"
+ }
},
"is-path-inside": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz",
"integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "path-is-inside": "1.0.2"
+ }
},
"is-plain-object": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.3.tgz",
- "integrity": "sha1-wVvz5LZrYtcu+vKSWEhmPsvGGbY=",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
"dev": true,
+ "requires": {
+ "isobject": "3.0.1"
+ },
"dependencies": {
"isobject": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.0.tgz",
- "integrity": "sha1-OVZSF/NmF4nooKDAgNX35rxG4aA=",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true
}
}
@@ -3439,29 +5294,44 @@
"integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
"dev": true
},
- "is-property": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
- "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=",
- "dev": true
+ "is-regex": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
+ "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=",
+ "dev": true,
+ "requires": {
+ "has": "1.0.1"
+ }
},
"is-relative": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.2.1.tgz",
"integrity": "sha1-0n9MfVFtF1+2ENuEu+7yPDvJeqU=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-unc-path": "0.1.2"
+ }
},
"is-resolvable": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz",
"integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "tryit": "1.0.3"
+ }
},
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
},
+ "is-symbol": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz",
+ "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=",
+ "dev": true
+ },
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
@@ -3471,7 +5341,10 @@
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-0.1.2.tgz",
"integrity": "sha1-arBTpyVzwQJQ/0FqOBTDUXivObk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "unc-path-regex": "0.1.2"
+ }
},
"is-utf8": {
"version": "0.2.1",
@@ -3507,12 +5380,19 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
"integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
},
"isomorphic-fetch": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
- "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk="
+ "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
+ "requires": {
+ "node-fetch": "1.7.2",
+ "whatwg-fetch": "2.0.3"
+ }
},
"isstream": {
"version": "0.1.2",
@@ -3520,16 +5400,25 @@
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
"dev": true
},
+ "js-cookie": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.0.tgz",
+ "integrity": "sha1-Gywnmm7s44ChIWi5JIUmWzWx7/s="
+ },
"js-tokens": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz",
- "integrity": "sha1-COnxMkhKLEWjCQfp3E1VZ7fxFNc="
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+ "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
},
"js-yaml": {
- "version": "3.8.4",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.8.4.tgz",
- "integrity": "sha1-UgtFZPhlc7qWZir4Woyvp7S1pvY=",
- "dev": true
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.9.1.tgz",
+ "integrity": "sha512-CbcG379L1e+mWBnLvHWWeLs8GyV/EMw862uLI3c+GxVyDHWZcjZinwuBd3iW2pgxgIlksW/1vNJa4to+RvDOww==",
+ "dev": true,
+ "requires": {
+ "argparse": "1.0.9",
+ "esprima": "4.0.0"
+ }
},
"jsbn": {
"version": "0.1.1",
@@ -3539,9 +5428,9 @@
"optional": true
},
"jschardet": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.4.2.tgz",
- "integrity": "sha1-KqEH8UKvQSHRRWWdRPUIMJYeaZo=",
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.5.1.tgz",
+ "integrity": "sha512-vE2hT1D0HLZCLLclfBSfkfTTedhVj0fubHpJBHKwwUWX0nSbhPAfk+SG9rTX95BYNmau8rGFfCeaT6T5OW1C2A==",
"dev": true
},
"jsesc": {
@@ -3556,12 +5445,21 @@
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
"dev": true
},
- "json-stable-stringify": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz",
- "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=",
+ "json-schema-traverse": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
+ "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
"dev": true
},
+ "json-stable-stringify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
+ "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
+ "dev": true,
+ "requires": {
+ "jsonify": "0.0.0"
+ }
+ },
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
@@ -3581,10 +5479,13 @@
"dev": true
},
"jsonfile": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.0.tgz",
- "integrity": "sha1-kufHRE5f/V+jLmqa6LhQNN+DR9A=",
- "dev": true
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz",
+ "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11"
+ }
},
"jsonify": {
"version": "0.0.0",
@@ -3598,23 +5499,17 @@
"integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
"dev": true
},
- "jsonpointer": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
- "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
- "dev": true
- },
- "JSONStream": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz",
- "integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=",
- "dev": true
- },
"jsprim": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz",
- "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=",
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"dev": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ },
"dependencies": {
"assert-plus": {
"version": "1.0.0",
@@ -3625,27 +5520,33 @@
}
},
"jsx-ast-utils": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz",
- "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=",
- "dev": true
- },
- "keycode": {
- "version": "2.1.9",
- "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.1.9.tgz",
- "integrity": "sha1-lkojxU5IiUBbSGGlyfBIDUUUHfo="
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.0.tgz",
+ "integrity": "sha1-7Aaj1gzzB+XhGdrHutgeifCW8Pg=",
+ "dev": true,
+ "requires": {
+ "array-includes": "3.0.3"
+ }
},
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-buffer": "1.1.5"
+ }
},
"labeled-stream-splicer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz",
"integrity": "sha1-pS4dE4AkwAuGscDJH2d5GLiuClk=",
"dev": true,
+ "requires": {
+ "inherits": "2.0.3",
+ "isarray": "0.0.1",
+ "stream-splicer": "2.0.0"
+ },
"dependencies": {
"isarray": {
"version": "0.0.1",
@@ -3659,7 +5560,11 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz",
"integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "default-resolution": "2.0.0",
+ "es6-weak-map": "2.0.2"
+ }
},
"lazy-cache": {
"version": "1.0.4",
@@ -3671,31 +5576,55 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
"integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "readable-stream": "2.3.3"
+ }
},
"lcid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
"integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "invert-kv": "1.0.0"
+ }
},
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "prelude-ls": "1.1.2",
+ "type-check": "0.3.2"
+ }
},
"lexical-scope": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz",
"integrity": "sha1-/Ope3HBKSzqHls3KQZw6CvryLfQ=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "astw": "2.2.0"
+ }
},
"liftoff": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.3.0.tgz",
"integrity": "sha1-qY8v9nGD2Lp8+soQVIvX/wVQs4U=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "extend": "3.0.1",
+ "findup-sync": "0.4.3",
+ "fined": "1.1.0",
+ "flagged-respawn": "0.3.2",
+ "lodash.isplainobject": "4.0.6",
+ "lodash.isstring": "4.0.1",
+ "lodash.mapvalues": "4.6.0",
+ "rechoir": "0.6.2",
+ "resolve": "1.4.0"
+ }
},
"limiter": {
"version": "1.1.2",
@@ -3707,31 +5636,49 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
"integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "parse-json": "2.2.0",
+ "pify": "2.3.0",
+ "pinkie-promise": "2.0.1",
+ "strip-bom": "2.0.0"
+ }
},
"localtunnel": {
- "version": "1.8.2",
- "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-1.8.2.tgz",
- "integrity": "sha1-kTBR6DKLUfda2KIq0fXFuMWZo1k=",
+ "version": "1.8.3",
+ "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-1.8.3.tgz",
+ "integrity": "sha1-3MWSL9hWUQN9S94k/ZMkjQsk6wU=",
"dev": true,
+ "requires": {
+ "debug": "2.6.8",
+ "openurl": "1.1.1",
+ "request": "2.81.0",
+ "yargs": "3.29.0"
+ },
"dependencies": {
"debug": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
- "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
- "dev": true
- },
- "ms": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
- "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=",
- "dev": true
+ "version": "2.6.8",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
},
"yargs": {
"version": "3.29.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.29.0.tgz",
"integrity": "sha1-GquWYOrnnYuPZ1vK7qtu40ws9pw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "camelcase": "1.2.1",
+ "cliui": "3.2.0",
+ "decamelize": "1.2.0",
+ "os-locale": "1.4.0",
+ "window-size": "0.1.4",
+ "y18n": "3.2.1"
+ }
}
}
},
@@ -3740,6 +5687,10 @@
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
"integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
"dev": true,
+ "requires": {
+ "p-locate": "2.0.0",
+ "path-exists": "3.0.0"
+ },
"dependencies": {
"path-exists": {
"version": "3.0.0",
@@ -3752,14 +5703,22 @@
"lodash": {
"version": "4.17.4",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
- "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=",
- "dev": true
+ "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
+ },
+ "lodash-es": {
+ "version": "4.17.4",
+ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.4.tgz",
+ "integrity": "sha1-3MHXVS4VCgZABzupyzHXDwMpUOc="
},
"lodash._baseassign": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz",
"integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "lodash._basecopy": "3.0.1",
+ "lodash.keys": "3.1.2"
+ }
},
"lodash._basecopy": {
"version": "3.0.1",
@@ -3789,7 +5748,12 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz",
"integrity": "sha1-g4pbri/aymOsIt7o4Z+k5taXCxE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "lodash._bindcallback": "3.0.1",
+ "lodash._isiterateecall": "3.0.9",
+ "lodash.restparam": "3.6.1"
+ }
},
"lodash._getnative": {
"version": "3.9.1",
@@ -3831,7 +5795,12 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-3.2.0.tgz",
"integrity": "sha1-POnwI0tLIiPilrj6CsH+6OvKZPo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "lodash._baseassign": "3.2.0",
+ "lodash._createassigner": "3.1.1",
+ "lodash.keys": "3.1.2"
+ }
},
"lodash.clone": {
"version": "4.5.0",
@@ -3861,7 +5830,10 @@
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
"integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "lodash._root": "3.0.1"
+ }
},
"lodash.flatten": {
"version": "4.4.0",
@@ -3915,7 +5887,12 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
"integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "lodash._getnative": "3.9.1",
+ "lodash.isarguments": "3.1.0",
+ "lodash.isarray": "3.0.4"
+ }
},
"lodash.mapvalues": {
"version": "4.6.0",
@@ -3932,7 +5909,8 @@
"lodash.merge": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.0.tgz",
- "integrity": "sha1-aYhLoUSsM/5plzemCG3v+t0PicU="
+ "integrity": "sha1-aYhLoUSsM/5plzemCG3v+t0PicU=",
+ "dev": true
},
"lodash.partialright": {
"version": "4.2.1",
@@ -3962,18 +5940,28 @@
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
"integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "lodash._basecopy": "3.0.1",
+ "lodash._basetostring": "3.0.1",
+ "lodash._basevalues": "3.0.0",
+ "lodash._isiterateecall": "3.0.9",
+ "lodash._reinterpolate": "3.0.0",
+ "lodash.escape": "3.2.0",
+ "lodash.keys": "3.1.2",
+ "lodash.restparam": "3.6.1",
+ "lodash.templatesettings": "3.1.1"
+ }
},
"lodash.templatesettings": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz",
"integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=",
- "dev": true
- },
- "lodash.throttle": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
- "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
+ "dev": true,
+ "requires": {
+ "lodash._reinterpolate": "3.0.0",
+ "lodash.escape": "3.2.0"
+ }
},
"lodash.uniq": {
"version": "4.5.0",
@@ -3990,7 +5978,20 @@
"loose-envify": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
- "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg="
+ "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
+ "requires": {
+ "js-tokens": "3.0.2"
+ }
+ },
+ "lru-cache": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
+ "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
+ "dev": true,
+ "requires": {
+ "pseudomap": "1.0.2",
+ "yallist": "2.1.2"
+ }
},
"make-error": {
"version": "1.3.0",
@@ -4002,13 +6003,19 @@
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz",
"integrity": "sha1-3wOI/NCzeBbf8KX7gQiTl3fcvJ0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "make-error": "1.3.0"
+ }
},
"make-iterator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.0.tgz",
"integrity": "sha1-V7713IXSOSO6I3ZzJNjo+PPZaUs=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ }
},
"map-cache": {
"version": "0.2.2",
@@ -4016,29 +6023,39 @@
"integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
"dev": true
},
- "map-stream": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.6.tgz",
- "integrity": "sha1-0u9OuBGihkTHqJiZhcacL91JaCc=",
- "dev": true
- },
"matchdep": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/matchdep/-/matchdep-1.0.1.tgz",
"integrity": "sha1-pXozgESR+64girqPaDgEN6vC3KU=",
"dev": true,
+ "requires": {
+ "findup-sync": "0.3.0",
+ "micromatch": "2.3.11",
+ "resolve": "1.1.7",
+ "stack-trace": "0.0.9"
+ },
"dependencies": {
"findup-sync": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz",
"integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "glob": "5.0.15"
+ }
},
"glob": {
"version": "5.0.15",
"resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
"integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "inflight": "1.0.6",
+ "inherits": "2.0.3",
+ "minimatch": "3.0.4",
+ "once": "1.4.0",
+ "path-is-absolute": "1.0.1"
+ }
},
"resolve": {
"version": "1.1.7",
@@ -4048,28 +6065,68 @@
}
}
},
- "material-ui": {
- "version": "0.18.4",
- "resolved": "https://registry.npmjs.org/material-ui/-/material-ui-0.18.4.tgz",
- "integrity": "sha1-r6DbFljWa0MuwODtuDcn1l5jkKE="
+ "mediasoup-client": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mediasoup-client/-/mediasoup-client-2.0.0.tgz",
+ "integrity": "sha512-67B0N5D0yzvV1I2JGummfRAZqdOymJIAzQs30vPqFTziFMF4qgrDhvoEJALgnhfn4OiAkgAJnzSfKp39kCv8pg==",
+ "requires": {
+ "bowser": "1.8.1",
+ "debug": "3.1.0",
+ "random-number": "0.0.9",
+ "sdp-transform": "2.3.0"
+ },
+ "dependencies": {
+ "bowser": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/bowser/-/bowser-1.8.1.tgz",
+ "integrity": "sha512-NMPaR8ILtdLSWzxQtEs16XbxMcY8ohWGQ5V+TZSJS3fNUt/PBAGkF6YWO9B/4qWE23bK3o0moQKq8UyFEosYkA=="
+ },
+ "random-number": {
+ "version": "0.0.9",
+ "resolved": "https://registry.npmjs.org/random-number/-/random-number-0.0.9.tgz",
+ "integrity": "sha512-ipG3kRCREi/YQpi2A5QGcvDz1KemohovWmH6qGfboVyyGdR2t/7zQz0vFxrfxpbHQgPPdtVlUDaks3aikD1Ljw=="
+ }
+ }
},
"merge-stream": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz",
"integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "readable-stream": "2.3.3"
+ }
},
"micromatch": {
"version": "2.3.11",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
"integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "arr-diff": "2.0.0",
+ "array-unique": "0.2.1",
+ "braces": "1.8.5",
+ "expand-brackets": "0.1.5",
+ "extglob": "0.3.2",
+ "filename-regex": "2.0.1",
+ "is-extglob": "1.0.0",
+ "is-glob": "2.0.1",
+ "kind-of": "3.2.2",
+ "normalize-path": "2.1.1",
+ "object.omit": "2.0.1",
+ "parse-glob": "3.0.4",
+ "regex-cache": "0.4.3"
+ }
},
"miller-rabin": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.0.tgz",
"integrity": "sha1-SmL7HUKTPAVYOYL0xxb2+55sbT0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "bn.js": "4.11.8",
+ "brorand": "1.1.0"
+ }
},
"mime": {
"version": "1.2.4",
@@ -4078,16 +6135,19 @@
"dev": true
},
"mime-db": {
- "version": "1.27.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz",
- "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=",
+ "version": "1.29.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz",
+ "integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg=",
"dev": true
},
"mime-types": {
- "version": "2.1.15",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz",
- "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=",
- "dev": true
+ "version": "2.1.16",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz",
+ "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=",
+ "dev": true,
+ "requires": {
+ "mime-db": "1.29.0"
+ }
},
"mimic-fn": {
"version": "1.1.0",
@@ -4111,7 +6171,10 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "dev": true
+ "dev": true,
+ "requires": {
+ "brace-expansion": "1.1.8"
+ }
},
"minimist": {
"version": "0.0.8",
@@ -4123,13 +6186,33 @@
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
},
"module-deps": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/module-deps/-/module-deps-4.1.1.tgz",
"integrity": "sha1-IyFYM/HaE/1gbMuAh7RIUty4If0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "JSONStream": "1.3.1",
+ "browser-resolve": "1.11.2",
+ "cached-path-relative": "1.0.1",
+ "concat-stream": "1.5.2",
+ "defined": "1.0.0",
+ "detective": "4.5.0",
+ "duplexer2": "0.1.4",
+ "inherits": "2.0.3",
+ "parents": "1.0.1",
+ "readable-stream": "2.3.3",
+ "resolve": "1.4.0",
+ "stream-combiner2": "1.1.1",
+ "subarg": "1.0.0",
+ "through2": "2.0.3",
+ "xtend": "4.0.1"
+ }
},
"ms": {
"version": "2.0.0",
@@ -4141,12 +6224,18 @@
"resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
"integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=",
"dev": true,
+ "requires": {
+ "duplexer2": "0.0.2"
+ },
"dependencies": {
"duplexer2": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
"integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "readable-stream": "1.1.14"
+ }
},
"isarray": {
"version": "0.0.1",
@@ -4158,7 +6247,13 @@
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ }
},
"string_decoder": {
"version": "0.10.31",
@@ -4204,52 +6299,70 @@
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=",
"dev": true
},
- "next-tick": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
- "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
- "dev": true
- },
"nib": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/nib/-/nib-1.1.2.tgz",
"integrity": "sha1-amnt5AgblcDe+L4CSkyK4MLLtsc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "stylus": "0.54.5"
+ }
},
"node-fetch": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.1.tgz",
- "integrity": "sha512-j8XsFGCLw79vWXkZtMSmmLaOk9z5SQ9bV/tkbZVCqvgwzrjAGq66igobLofHtF63NvMTp2WjytpsNTGKa+XRIQ=="
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.2.tgz",
+ "integrity": "sha512-xZZUq2yDhKMIn/UgG5q//IZSNLJIwW2QxS14CNH5spuiXkITM2pUitjdq58yLSaU7m4M0wBNaM2Gh/ggY4YJig==",
+ "requires": {
+ "encoding": "0.1.12",
+ "is-stream": "1.1.0"
+ }
},
- "node-uuid": {
- "version": "1.4.8",
- "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz",
- "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=",
- "dev": true
+ "node-random-name": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/node-random-name/-/node-random-name-1.0.1.tgz",
+ "integrity": "sha1-niQEx6AeCQWi92Fogh7bLc0U91g=",
+ "requires": {
+ "alea": "0.0.9"
+ }
},
"nopt": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
"integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "abbrev": "1.1.0"
+ }
},
"normalize-package-data": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz",
- "integrity": "sha1-2Bntoqne29H/pWPqQHHZNngilbs=",
- "dev": true
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+ "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
+ "dev": true,
+ "requires": {
+ "hosted-git-info": "2.5.0",
+ "is-builtin-module": "1.0.0",
+ "semver": "5.4.1",
+ "validate-npm-package-license": "3.0.1"
+ }
},
"normalize-path": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "remove-trailing-separator": "1.1.0"
+ }
},
"now-and-later": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-1.0.0.tgz",
- "integrity": "sha1-I+eYzKrw6Ky+8Gh/gghidHRuCJM=",
- "dev": true
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.0.tgz",
+ "integrity": "sha1-vGHLtFbXnLMiB85HygUTb/Ln1u4=",
+ "dev": true,
+ "requires": {
+ "once": "1.4.0"
+ }
},
"number-is-nan": {
"version": "1.0.1",
@@ -4274,6 +6387,12 @@
"integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=",
"dev": true
},
+ "object-keys": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz",
+ "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=",
+ "dev": true
+ },
"object-path": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/object-path/-/object-path-0.9.2.tgz",
@@ -4285,17 +6404,26 @@
"resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
"integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=",
"dev": true,
+ "requires": {
+ "array-each": "1.0.1",
+ "array-slice": "1.0.0",
+ "for-own": "1.0.0",
+ "isobject": "3.0.1"
+ },
"dependencies": {
"for-own": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
"integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "for-in": "1.0.2"
+ }
},
"isobject": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.0.tgz",
- "integrity": "sha1-OVZSF/NmF4nooKDAgNX35rxG4aA=",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true
}
}
@@ -4304,55 +6432,106 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
"integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "for-own": "0.1.5",
+ "is-extendable": "0.1.1"
+ }
},
"object.pick": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.2.0.tgz",
- "integrity": "sha1-tTkr7peC2m2ft9avr1OXefEjTCs=",
- "dev": true
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "dev": true,
+ "requires": {
+ "isobject": "3.0.1"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ }
+ }
},
"object.reduce": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-0.1.7.tgz",
- "integrity": "sha1-0YDoT3LSGDSK9FNStVFlJGuVBG0=",
- "dev": true
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz",
+ "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=",
+ "dev": true,
+ "requires": {
+ "for-own": "1.0.0",
+ "make-iterator": "1.0.0"
+ },
+ "dependencies": {
+ "for-own": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+ "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
+ "dev": true,
+ "requires": {
+ "for-in": "1.0.2"
+ }
+ }
+ }
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "ee-first": "1.1.1"
+ }
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "wrappy": "1.0.2"
+ }
},
"onetime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
"integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "mimic-fn": "1.1.0"
+ }
},
"openurl": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.0.tgz",
- "integrity": "sha1-4vIYnZmcBIIyAfCD8PGnzYkDGHo=",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz",
+ "integrity": "sha1-OHW0sO96UsFW8NtB1GCduw+Us4c=",
"dev": true
},
"opn": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz",
"integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "object-assign": "4.1.1",
+ "pinkie-promise": "2.0.1"
+ }
},
"optionator": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
"integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "deep-is": "0.1.3",
+ "fast-levenshtein": "2.0.6",
+ "levn": "0.3.0",
+ "prelude-ls": "1.1.2",
+ "type-check": "0.3.2",
+ "wordwrap": "1.0.0"
+ }
},
"options": {
"version": "0.0.6",
@@ -4364,13 +6543,11 @@
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz",
"integrity": "sha1-cTfmmzKYuzQiR6G77jiByA4v14s=",
- "dev": true
- },
- "os-browserify": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.1.2.tgz",
- "integrity": "sha1-ScoCk+CxlZCl9d4Qx/JlphfY/lQ=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-stream": "1.1.0",
+ "readable-stream": "2.3.3"
+ }
},
"os-homedir": {
"version": "1.0.2",
@@ -4382,7 +6559,10 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
"integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "lcid": "1.0.0"
+ }
},
"os-tmpdir": {
"version": "1.0.2",
@@ -4394,7 +6574,10 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz",
"integrity": "sha1-UM+GFjZeh+Ax4ppeyTOaPaRyX6I=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "shell-quote": "1.6.1"
+ }
},
"p-limit": {
"version": "1.1.0",
@@ -4406,7 +6589,10 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
"integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "p-limit": "1.1.0"
+ }
},
"p-map": {
"version": "1.1.1",
@@ -4414,41 +6600,59 @@
"integrity": "sha1-BfXkrpegaDcbwqXMhr+9vBnErno=",
"dev": true
},
- "pako": {
- "version": "0.2.9",
- "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
- "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=",
- "dev": true
- },
"parents": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
"integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "path-platform": "0.11.15"
+ }
},
"parse-asn1": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz",
"integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "asn1.js": "4.9.1",
+ "browserify-aes": "1.0.6",
+ "create-hash": "1.1.3",
+ "evp_bytestokey": "1.0.0",
+ "pbkdf2": "3.0.13"
+ }
},
"parse-filepath": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.1.tgz",
"integrity": "sha1-FZ1hVdQ5BNFsEO9piRHaHpGWm3M=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-absolute": "0.2.6",
+ "map-cache": "0.2.2",
+ "path-root": "0.1.1"
+ }
},
"parse-glob": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
"integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "glob-base": "0.3.0",
+ "is-dotfile": "1.0.3",
+ "is-extglob": "1.0.0",
+ "is-glob": "2.0.1"
+ }
},
"parse-json": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
"integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "error-ex": "1.3.1"
+ }
},
"parse-passwd": {
"version": "1.0.0",
@@ -4460,19 +6664,28 @@
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz",
"integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "better-assert": "1.0.2"
+ }
},
"parseqs": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
"integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "better-assert": "1.0.2"
+ }
},
"parseuri": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
"integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "better-assert": "1.0.2"
+ }
},
"parseurl": {
"version": "1.3.1",
@@ -4496,7 +6709,10 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "pinkie-promise": "2.0.1"
+ }
},
"path-is-absolute": {
"version": "1.0.1",
@@ -4526,7 +6742,10 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
"integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "path-root-regex": "0.1.2"
+ }
},
"path-root-regex": {
"version": "0.1.2",
@@ -4538,12 +6757,30 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
"integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "pify": "2.3.0",
+ "pinkie-promise": "2.0.1"
+ }
},
"pbkdf2": {
- "version": "3.0.12",
- "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.12.tgz",
- "integrity": "sha1-vjZ4XFBn6kjYBv+SMojF91C2uKI=",
+ "version": "3.0.13",
+ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.13.tgz",
+ "integrity": "sha512-+dCHxDH+djNtjgWmvVC/my3SYBAKpKNqKSjLkp+GtWWYe4XPE+e/PSD2aCanlEZZnqPk2uekTKNC/ccbwd2X2Q==",
+ "dev": true,
+ "requires": {
+ "create-hash": "1.1.3",
+ "create-hmac": "1.1.6",
+ "ripemd160": "2.0.1",
+ "safe-buffer": "5.1.1",
+ "sha.js": "2.4.8"
+ }
+ },
+ "performance-now": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
+ "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=",
"dev": true
},
"pify": {
@@ -4562,25 +6799,29 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "pinkie": "2.0.4"
+ }
},
"pkg-dir": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
"integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=",
- "dev": true
- },
- "pluralize": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-4.0.0.tgz",
- "integrity": "sha1-WbcIwcAZCi9pLxx2GMRGsFL9F2I=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "find-up": "1.1.2"
+ }
},
"portscanner": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.1.1.tgz",
"integrity": "sha1-6rtAnk3iSVD1oqUW01rnaTQ/u5Y=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "async": "1.5.2",
+ "is-number-like": "1.0.8"
+ }
},
"prelude-ls": {
"version": "1.1.2",
@@ -4627,23 +6868,101 @@
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
- "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg=="
+ "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "requires": {
+ "asap": "2.0.6"
+ }
},
"prop-types": {
- "version": "15.5.10",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.5.10.tgz",
- "integrity": "sha1-J5ffwxJhguOpXj37suiT3ddFYVQ="
+ "version": "15.6.0",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.0.tgz",
+ "integrity": "sha1-zq8IMCL8RrSjX2nhPvda7Q1jmFY=",
+ "requires": {
+ "fbjs": "0.8.16",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ },
+ "fbjs": {
+ "version": "0.8.16",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz",
+ "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=",
+ "requires": {
+ "core-js": "1.2.7",
+ "isomorphic-fetch": "2.2.1",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1",
+ "promise": "7.3.1",
+ "setimmediate": "1.0.5",
+ "ua-parser-js": "0.7.14"
+ }
+ }
+ }
},
"protoo-client": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/protoo-client/-/protoo-client-1.1.4.tgz",
- "integrity": "sha1-cX2bStyYQKTacWVdfn8ZXFDK+W4="
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/protoo-client/-/protoo-client-2.0.5.tgz",
+ "integrity": "sha512-oRG7jZUgFBNSU687GG0Du6Gu1hUpv0aZcMh9ClgWJTn6ou0EkRL2wqjI+e8kJd7SERm7h2gdeIbJhocMI9MYRg==",
+ "requires": {
+ "debug": "3.1.0",
+ "random-number": "0.0.9",
+ "retry": "0.10.1",
+ "websocket": "1.0.25"
+ },
+ "dependencies": {
+ "random-number": {
+ "version": "0.0.9",
+ "resolved": "https://registry.npmjs.org/random-number/-/random-number-0.0.9.tgz",
+ "integrity": "sha512-ipG3kRCREi/YQpi2A5QGcvDz1KemohovWmH6qGfboVyyGdR2t/7zQz0vFxrfxpbHQgPPdtVlUDaks3aikD1Ljw=="
+ },
+ "websocket": {
+ "version": "1.0.25",
+ "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.25.tgz",
+ "integrity": "sha512-M58njvi6ZxVb5k7kpnHh2BvNKuBWiwIYvsToErBzWhvBZYwlEiLcyLrG41T1jRcrY9ettqPYEqduLI7ul54CVQ==",
+ "optional": true,
+ "requires": {
+ "debug": "2.6.9",
+ "nan": "2.6.2",
+ "typedarray-to-buffer": "3.1.2",
+ "yaeti": "0.0.6"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "optional": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
+ }
+ }
+ },
+ "pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+ "dev": true
},
"public-encrypt": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz",
"integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "bn.js": "4.11.8",
+ "browserify-rsa": "4.0.1",
+ "create-hash": "1.1.3",
+ "parse-asn1": "5.1.0",
+ "randombytes": "2.0.5"
+ }
},
"punycode": {
"version": "1.4.1",
@@ -4674,11 +6993,6 @@
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-1.0.0.tgz",
"integrity": "sha1-YoYkIRLFtxL6ZU5SZlK/ahP/Bcs="
},
- "random-number": {
- "version": "0.0.7",
- "resolved": "https://registry.npmjs.org/random-number/-/random-number-0.0.7.tgz",
- "integrity": "sha1-fWKxAK3pDxNCNarYwGotLfpc/0g="
- },
"random-string": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/random-string/-/random-string-0.2.0.tgz",
@@ -4689,18 +7003,28 @@
"resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
"integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==",
"dev": true,
+ "requires": {
+ "is-number": "3.0.0",
+ "kind-of": "4.0.0"
+ },
"dependencies": {
"is-number": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
"dev": true,
+ "requires": {
+ "kind-of": "3.2.2"
+ },
"dependencies": {
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-buffer": "1.1.5"
+ }
}
}
},
@@ -4708,7 +7032,10 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
"integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-buffer": "1.1.5"
+ }
}
}
},
@@ -4716,7 +7043,10 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz",
"integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==",
- "dev": true
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.1.1"
+ }
},
"range-parser": {
"version": "1.2.0",
@@ -4725,78 +7055,207 @@
"dev": true
},
"react": {
- "version": "15.6.1",
- "resolved": "https://registry.npmjs.org/react/-/react-15.6.1.tgz",
- "integrity": "sha1-uqhDTsZ4C96ZfNw4C3nNM7ljk98="
+ "version": "16.0.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-16.0.0.tgz",
+ "integrity": "sha1-zn348ZQbA28Cssyp29DLHw6FXi0=",
+ "requires": {
+ "fbjs": "0.8.16",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1",
+ "prop-types": "15.6.0"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ },
+ "fbjs": {
+ "version": "0.8.16",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz",
+ "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=",
+ "requires": {
+ "core-js": "1.2.7",
+ "isomorphic-fetch": "2.2.1",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1",
+ "promise": "7.3.1",
+ "setimmediate": "1.0.5",
+ "ua-parser-js": "0.7.14"
+ }
+ }
+ }
},
"react-clipboard.js": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/react-clipboard.js/-/react-clipboard.js-1.1.2.tgz",
- "integrity": "sha1-lsksko0JhzwUKH/Vx185Xx+RFJA="
+ "integrity": "sha1-lsksko0JhzwUKH/Vx185Xx+RFJA=",
+ "requires": {
+ "clipboard": "1.7.1",
+ "prop-types": "15.6.0"
+ }
},
"react-dom": {
- "version": "15.6.1",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-15.6.1.tgz",
- "integrity": "sha1-LLDtQZEDjlPCCes6eaI+Kkz5lHA="
+ "version": "16.0.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.0.0.tgz",
+ "integrity": "sha1-nMMHnD3NcNTG4BuEqrKn40wwP1g=",
+ "requires": {
+ "fbjs": "0.8.16",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1",
+ "prop-types": "15.6.0"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+ "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+ },
+ "fbjs": {
+ "version": "0.8.16",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz",
+ "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=",
+ "requires": {
+ "core-js": "1.2.7",
+ "isomorphic-fetch": "2.2.1",
+ "loose-envify": "1.3.1",
+ "object-assign": "4.1.1",
+ "promise": "7.3.1",
+ "setimmediate": "1.0.5",
+ "ua-parser-js": "0.7.14"
+ }
+ }
+ }
},
- "react-event-listener": {
- "version": "0.4.5",
- "resolved": "https://registry.npmjs.org/react-event-listener/-/react-event-listener-0.4.5.tgz",
- "integrity": "sha1-4+iVoJcM8U7o+JAROvaBl6vz0LE="
+ "react-redux": {
+ "version": "5.0.6",
+ "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.6.tgz",
+ "integrity": "sha512-8taaaGu+J7PMJQDJrk/xiWEYQmdo3mkXw6wPr3K3LxvXis3Fymiq7c13S+Tpls/AyNUAsoONkU81AP0RA6y6Vw==",
+ "requires": {
+ "hoist-non-react-statics": "2.3.0",
+ "invariant": "2.2.2",
+ "lodash": "4.17.4",
+ "lodash-es": "4.17.4",
+ "loose-envify": "1.3.1",
+ "prop-types": "15.6.0"
+ }
},
- "react-notification-system": {
- "version": "github:ibc/react-notification-system#d6a9c73d028bdbe9f5370f3cea01330baae45d8e"
+ "react-spinner": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/react-spinner/-/react-spinner-0.2.7.tgz",
+ "integrity": "sha1-6jyjN13XpU7btcwB0XSWouL8FNs="
},
- "react-tap-event-plugin": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/react-tap-event-plugin/-/react-tap-event-plugin-2.0.1.tgz",
- "integrity": "sha1-MWvrO8ZVbinshppyk+icgmqQdNI="
+ "react-tooltip": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-3.4.0.tgz",
+ "integrity": "sha1-A38495fD5rG1jSU0zMjCx2r09S0=",
+ "requires": {
+ "classnames": "2.2.5",
+ "prop-types": "15.6.0"
+ }
},
"react-transition-group": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-1.2.0.tgz",
- "integrity": "sha1-tR/JIbDDg1p+98Vxx5/ILHPpIE8="
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.2.1.tgz",
+ "integrity": "sha512-q54UBM22bs/CekG8r3+vi9TugSqh0t7qcEVycaRc9M0p0aCEu+h6rp/RFiW7fHfgd1IKpd9oILFTl5QK+FpiPA==",
+ "requires": {
+ "chain-function": "1.0.0",
+ "classnames": "2.2.5",
+ "dom-helpers": "3.2.1",
+ "loose-envify": "1.3.1",
+ "prop-types": "15.6.0",
+ "warning": "3.0.0"
+ }
},
"read-only-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz",
"integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "readable-stream": "2.3.3"
+ }
},
"read-pkg": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
"integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "load-json-file": "1.1.0",
+ "normalize-package-data": "2.4.0",
+ "path-type": "1.1.0"
+ }
},
"read-pkg-up": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
"integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "find-up": "1.1.2",
+ "read-pkg": "1.1.0"
+ }
},
"readable-stream": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.2.tgz",
- "integrity": "sha1-WgTfBeT1f+Pw3Gj90R3FyXx+b00=",
- "dev": true
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
+ "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "1.0.0",
+ "process-nextick-args": "1.0.7",
+ "safe-buffer": "5.1.1",
+ "string_decoder": "1.0.3",
+ "util-deprecate": "1.0.2"
+ }
},
"readdirp": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
"integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "graceful-fs": "4.1.11",
+ "minimatch": "3.0.4",
+ "readable-stream": "2.3.3",
+ "set-immediate-shim": "1.0.1"
+ }
},
"rechoir": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
"integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "resolve": "1.4.0"
+ }
},
- "recompose": {
- "version": "0.23.4",
- "resolved": "https://registry.npmjs.org/recompose/-/recompose-0.23.4.tgz",
- "integrity": "sha1-rwnk4IQk7/pEnJt5MDcWb3swZEo="
+ "redux": {
+ "version": "3.7.2",
+ "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz",
+ "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==",
+ "requires": {
+ "lodash": "4.17.4",
+ "lodash-es": "4.17.4",
+ "loose-envify": "1.3.1",
+ "symbol-observable": "1.0.4"
+ }
+ },
+ "redux-logger": {
+ "version": "3.0.6",
+ "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz",
+ "integrity": "sha1-91VZZvMJjzyIYExEnPC69XeCdL8=",
+ "requires": {
+ "deep-diff": "0.3.8"
+ }
+ },
+ "redux-thunk": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.2.0.tgz",
+ "integrity": "sha1-5hWhbha0ehmlFXZhM9Hj6Zt4UuU="
},
"regenerate": {
"version": "1.3.2",
@@ -4805,27 +7264,41 @@
"dev": true
},
"regenerator-runtime": {
- "version": "0.10.5",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
- "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
+ "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A=="
},
"regenerator-transform": {
- "version": "0.9.11",
- "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.9.11.tgz",
- "integrity": "sha1-On0GdSDLe3F2dp61/4aGkb7+EoM=",
- "dev": true
+ "version": "0.10.1",
+ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
+ "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "6.26.0",
+ "babel-types": "6.26.0",
+ "private": "0.1.7"
+ }
},
"regex-cache": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz",
"integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-equal-shallow": "0.1.3",
+ "is-primitive": "2.0.0"
+ }
},
"regexpu-core": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz",
"integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "regenerate": "1.3.2",
+ "regjsgen": "0.2.0",
+ "regjsparser": "0.1.5"
+ }
},
"regjsgen": {
"version": "0.2.0",
@@ -4837,12 +7310,15 @@
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
"integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "jsesc": "0.5.0"
+ }
},
"remove-trailing-separator": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz",
- "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
"dev": true
},
"repeat-element": {
@@ -4861,7 +7337,10 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
"integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-finite": "1.0.2"
+ }
},
"replace-ext": {
"version": "0.0.1",
@@ -4870,15 +7349,39 @@
"dev": true
},
"request": {
- "version": "2.78.0",
- "resolved": "https://registry.npmjs.org/request/-/request-2.78.0.tgz",
- "integrity": "sha1-4cjew0bhyBkjskrNszfxHeyr6cw=",
+ "version": "2.81.0",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
+ "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=",
"dev": true,
+ "requires": {
+ "aws-sign2": "0.6.0",
+ "aws4": "1.6.0",
+ "caseless": "0.12.0",
+ "combined-stream": "1.0.5",
+ "extend": "3.0.1",
+ "forever-agent": "0.6.1",
+ "form-data": "2.1.4",
+ "har-validator": "4.2.1",
+ "hawk": "3.1.3",
+ "http-signature": "1.1.1",
+ "is-typedarray": "1.0.0",
+ "isstream": "0.1.2",
+ "json-stringify-safe": "5.0.1",
+ "mime-types": "2.1.16",
+ "oauth-sign": "0.8.2",
+ "performance-now": "0.2.0",
+ "qs": "6.4.0",
+ "safe-buffer": "5.1.1",
+ "stringstream": "0.0.5",
+ "tough-cookie": "2.3.2",
+ "tunnel-agent": "0.6.0",
+ "uuid": "3.1.0"
+ },
"dependencies": {
"qs": {
- "version": "6.3.2",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz",
- "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=",
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
+ "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=",
"dev": true
}
}
@@ -4899,7 +7402,11 @@
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
"integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "caller-path": "0.1.0",
+ "resolve-from": "1.0.1"
+ }
},
"requires-port": {
"version": "1.0.0",
@@ -4907,16 +7414,23 @@
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
},
"resolve": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz",
- "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=",
- "dev": true
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz",
+ "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==",
+ "dev": true,
+ "requires": {
+ "path-parse": "1.0.5"
+ }
},
"resolve-dir": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz",
"integrity": "sha1-shklmlYC+sXFxJatiUpujMQwJh4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "expand-tilde": "1.2.2",
+ "global-modules": "0.2.3"
+ }
},
"resolve-from": {
"version": "1.0.1",
@@ -4928,42 +7442,93 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz",
"integrity": "sha1-sSTeXE+6/LpUH0j/pzlw9KpFa08=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "debug": "2.6.8",
+ "minimatch": "3.0.4"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.8",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
},
"restore-cursor": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
"integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "onetime": "2.0.1",
+ "signal-exit": "3.0.2"
+ }
},
"retry": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz",
"integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q="
},
+ "riek": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/riek/-/riek-1.1.0.tgz",
+ "integrity": "sha1-6oVNtKTtCWIw/wQ4JQjW374pWZQ=",
+ "requires": {
+ "debug": "2.6.8",
+ "prop-types": "15.6.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "2.6.8",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
+ "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
+ },
"right-align": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
"integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "align-text": "0.1.4"
+ }
},
"rimraf": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz",
"integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "glob": "7.1.2"
+ }
},
"ripemd160": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
"integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "hash-base": "2.0.2",
+ "inherits": "2.0.3"
+ }
},
"run-async": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
"integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-promise": "2.1.0"
+ }
},
"rx": {
"version": "4.1.0",
@@ -4981,7 +7546,10 @@
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
"integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "rx-lite": "4.0.8"
+ }
},
"safe-buffer": {
"version": "5.1.1",
@@ -5006,42 +7574,49 @@
"integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0="
},
"semver": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
- "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
+ "version": "5.4.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
+ "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
"dev": true
},
"semver-greatest-satisfied-range": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.0.0.tgz",
- "integrity": "sha1-T7RB4qjSbEC1mDJ1VzGN4nKlWKA=",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz",
+ "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=",
"dev": true,
- "dependencies": {
- "semver": {
- "version": "4.3.6",
- "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
- "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=",
- "dev": true
- }
+ "requires": {
+ "sver-compat": "1.5.0"
}
},
- "semver-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-1.0.0.tgz",
- "integrity": "sha1-kqSWkGX5xwxpR1PVUkj8aPj2Usk=",
- "dev": true
- },
"send": {
"version": "0.15.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.15.2.tgz",
"integrity": "sha1-+R+rRAO8+H5xb3DOtdsvV4vcF9Y=",
"dev": true,
+ "requires": {
+ "debug": "2.6.4",
+ "depd": "1.1.1",
+ "destroy": "1.0.4",
+ "encodeurl": "1.0.1",
+ "escape-html": "1.0.3",
+ "etag": "1.8.0",
+ "fresh": "0.5.0",
+ "http-errors": "1.6.2",
+ "mime": "1.3.4",
+ "ms": "1.0.0",
+ "on-finished": "2.3.0",
+ "range-parser": "1.2.0",
+ "statuses": "1.3.1"
+ },
"dependencies": {
"debug": {
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.4.tgz",
"integrity": "sha1-dYaps8OXQcAoKuM0RcTorHRzT+A=",
"dev": true,
+ "requires": {
+ "ms": "0.7.3"
+ },
"dependencies": {
"ms": {
"version": "0.7.3",
@@ -5058,10 +7633,16 @@
"dev": true
},
"http-errors": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.1.tgz",
- "integrity": "sha1-X4uO2YrKVFZWv1cplzh/kEpyIlc=",
- "dev": true
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
+ "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
+ "dev": true,
+ "requires": {
+ "depd": "1.1.1",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.0.3",
+ "statuses": "1.3.1"
+ }
},
"mime": {
"version": "1.3.4",
@@ -5088,12 +7669,24 @@
"resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.8.0.tgz",
"integrity": "sha1-fF2WwT+xMRAfk8HFd0+FFqHnjTs=",
"dev": true,
+ "requires": {
+ "accepts": "1.3.3",
+ "batch": "0.5.3",
+ "debug": "2.2.0",
+ "escape-html": "1.0.3",
+ "http-errors": "1.5.1",
+ "mime-types": "2.1.16",
+ "parseurl": "1.3.1"
+ },
"dependencies": {
"debug": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
"integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "ms": "0.7.1"
+ }
},
"ms": {
"version": "0.7.1",
@@ -5107,7 +7700,13 @@
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.2.tgz",
"integrity": "sha1-5UbicmCBuBtLzsjpCAjrzdMjr7o=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "encodeurl": "1.0.1",
+ "escape-html": "1.0.3",
+ "parseurl": "1.3.1",
+ "send": "0.15.2"
+ }
},
"server-destroy": {
"version": "1.0.1",
@@ -5142,19 +7741,58 @@
"version": "2.4.8",
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.8.tgz",
"integrity": "sha1-NwaMLEdra69ALRSknGf1l5IfY08=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3"
+ }
},
"shasum": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz",
"integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=",
+ "dev": true,
+ "requires": {
+ "json-stable-stringify": "0.0.1",
+ "sha.js": "2.4.8"
+ },
+ "dependencies": {
+ "json-stable-stringify": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz",
+ "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=",
+ "dev": true,
+ "requires": {
+ "jsonify": "0.0.0"
+ }
+ }
+ }
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true
},
"shell-quote": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
"integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "array-filter": "0.0.1",
+ "array-map": "0.0.0",
+ "array-reduce": "0.0.0",
+ "jsonify": "0.0.0"
+ }
},
"signal-exit": {
"version": "3.0.2",
@@ -5162,11 +7800,6 @@
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true
},
- "simple-assign": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/simple-assign/-/simple-assign-0.1.0.tgz",
- "integrity": "sha1-F/0wZqXz13OPUDIbsPFMooHMS6o="
- },
"slash": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
@@ -5183,19 +7816,34 @@
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
"integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "hoek": "2.16.3"
+ }
},
"socket.io": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.6.0.tgz",
"integrity": "sha1-PkDZMmN+a9kjmBslyvfFPoO24uE=",
"dev": true,
+ "requires": {
+ "debug": "2.3.3",
+ "engine.io": "1.8.0",
+ "has-binary": "0.1.7",
+ "object-assign": "4.1.0",
+ "socket.io-adapter": "0.5.0",
+ "socket.io-client": "1.6.0",
+ "socket.io-parser": "2.3.1"
+ },
"dependencies": {
"debug": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "ms": "0.7.2"
+ }
},
"ms": {
"version": "0.7.2",
@@ -5216,12 +7864,19 @@
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz",
"integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=",
"dev": true,
+ "requires": {
+ "debug": "2.3.3",
+ "socket.io-parser": "2.3.1"
+ },
"dependencies": {
"debug": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "ms": "0.7.2"
+ }
},
"ms": {
"version": "0.7.2",
@@ -5236,6 +7891,19 @@
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.6.0.tgz",
"integrity": "sha1-W2aPT3cTBN/u0XkGRwg4b6ZxeFM=",
"dev": true,
+ "requires": {
+ "backo2": "1.0.2",
+ "component-bind": "1.0.0",
+ "component-emitter": "1.2.1",
+ "debug": "2.3.3",
+ "engine.io-client": "1.8.0",
+ "has-binary": "0.1.7",
+ "indexof": "0.0.1",
+ "object-component": "0.0.3",
+ "parseuri": "0.0.5",
+ "socket.io-parser": "2.3.1",
+ "to-array": "0.1.4"
+ },
"dependencies": {
"component-emitter": {
"version": "1.2.1",
@@ -5247,7 +7915,10 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
"integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "ms": "0.7.2"
+ }
},
"ms": {
"version": "0.7.2",
@@ -5262,12 +7933,21 @@
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz",
"integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=",
"dev": true,
+ "requires": {
+ "component-emitter": "1.1.2",
+ "debug": "2.2.0",
+ "isarray": "0.0.1",
+ "json3": "3.3.2"
+ },
"dependencies": {
"debug": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
"integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "ms": "0.7.1"
+ }
},
"isarray": {
"version": "0.0.1",
@@ -5290,10 +7970,13 @@
"dev": true
},
"source-map-support": {
- "version": "0.4.15",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz",
- "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=",
- "dev": true
+ "version": "0.4.18",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+ "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+ "dev": true,
+ "requires": {
+ "source-map": "0.5.6"
+ }
},
"sparkles": {
"version": "1.0.0",
@@ -5305,7 +7988,10 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz",
"integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "spdx-license-ids": "1.2.2"
+ }
},
"spdx-expression-parse": {
"version": "1.0.4",
@@ -5330,6 +8016,16 @@
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
"integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
"dev": true,
+ "requires": {
+ "asn1": "0.2.3",
+ "assert-plus": "1.0.0",
+ "bcrypt-pbkdf": "1.0.1",
+ "dashdash": "1.14.1",
+ "ecc-jsbn": "0.1.1",
+ "getpass": "0.1.7",
+ "jsbn": "0.1.1",
+ "tweetnacl": "0.14.5"
+ },
"dependencies": {
"assert-plus": {
"version": "1.0.0",
@@ -5355,13 +8051,21 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
"integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3",
+ "readable-stream": "2.3.3"
+ }
},
"stream-combiner2": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz",
"integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "duplexer2": "0.1.4",
+ "readable-stream": "2.3.3"
+ }
},
"stream-exhaust": {
"version": "1.0.1",
@@ -5373,7 +8077,14 @@
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz",
"integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==",
- "dev": true
+ "dev": true,
+ "requires": {
+ "builtin-status-codes": "3.0.0",
+ "inherits": "2.0.3",
+ "readable-stream": "2.3.3",
+ "to-arraybuffer": "1.0.1",
+ "xtend": "4.0.1"
+ }
},
"stream-shift": {
"version": "1.0.0",
@@ -5385,25 +8096,41 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz",
"integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "inherits": "2.0.3",
+ "readable-stream": "2.3.3"
+ }
},
"stream-throttle": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz",
"integrity": "sha1-rdV8jXzHOoFjDTHNVdOWHPr7qcM=",
- "dev": true
- },
- "string_decoder": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
- "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
- "dev": true
+ "dev": true,
+ "requires": {
+ "commander": "2.11.0",
+ "limiter": "1.1.2"
+ }
},
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "code-point-at": "1.1.0",
+ "is-fullwidth-code-point": "1.0.0",
+ "strip-ansi": "3.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.1.1"
+ }
},
"stringstream": {
"version": "0.0.5",
@@ -5415,19 +8142,29 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "ansi-regex": "2.1.1"
+ }
},
"strip-bom": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "is-utf8": "0.2.1"
+ }
},
"strip-bom-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz",
"integrity": "sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "first-chunk-stream": "1.0.0",
+ "strip-bom": "2.0.0"
+ }
},
"strip-json-comments": {
"version": "2.0.1",
@@ -5440,18 +8177,37 @@
"resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz",
"integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=",
"dev": true,
+ "requires": {
+ "css-parse": "1.7.0",
+ "debug": "3.1.0",
+ "glob": "7.0.6",
+ "mkdirp": "0.5.1",
+ "sax": "0.5.8",
+ "source-map": "0.1.43"
+ },
"dependencies": {
"glob": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
"integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "fs.realpath": "1.0.0",
+ "inflight": "1.0.6",
+ "inherits": "2.0.3",
+ "minimatch": "3.0.4",
+ "once": "1.4.0",
+ "path-is-absolute": "1.0.1"
+ }
},
"source-map": {
"version": "0.1.43",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
"integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "amdefine": "1.0.1"
+ }
}
}
},
@@ -5460,6 +8216,9 @@
"resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
"integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=",
"dev": true,
+ "requires": {
+ "minimist": "1.2.0"
+ },
"dependencies": {
"minimist": {
"version": "1.2.0",
@@ -5470,10 +8229,22 @@
}
},
"supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
- "dev": true
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.0.0.tgz",
+ "integrity": "sha1-HbJiKfauAvms21QQkHw2zi42KxM=",
+ "requires": {
+ "has-flag": "2.0.0"
+ }
+ },
+ "sver-compat": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz",
+ "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=",
+ "dev": true,
+ "requires": {
+ "es6-iterator": "2.0.1",
+ "es6-symbol": "3.1.1"
+ }
},
"symbol-observable": {
"version": "1.0.4",
@@ -5484,13 +8255,24 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.3.0.tgz",
"integrity": "sha1-HtkmbE1AvnXcVb+bsct3Biu5bKE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "acorn": "4.0.13"
+ }
},
"table": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/table/-/table-4.0.1.tgz",
"integrity": "sha1-qBFsEz+sLGH0pCCrbN9cTWHw5DU=",
"dev": true,
+ "requires": {
+ "ajv": "4.11.8",
+ "ajv-keywords": "1.5.1",
+ "chalk": "1.1.3",
+ "lodash": "4.17.4",
+ "slice-ansi": "0.0.4",
+ "string-width": "2.1.1"
+ },
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
@@ -5505,16 +8287,23 @@
"dev": true
},
"string-width": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz",
- "integrity": "sha1-AwZkVh/BRslCPsfZeP4kV0N/5tA=",
- "dev": true
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "requires": {
+ "is-fullwidth-code-point": "2.0.0",
+ "strip-ansi": "4.0.0"
+ }
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "ansi-regex": "3.0.0"
+ }
}
}
},
@@ -5522,7 +8311,13 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-2.0.1.tgz",
"integrity": "sha1-Bk5Im0tb9gumpre8fy9cJ07Pgmk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "duplexify": "3.5.1",
+ "fork-stream": "0.0.4",
+ "merge-stream": "1.0.1",
+ "through2": "2.0.3"
+ }
},
"text-table": {
"version": "0.2.0",
@@ -5534,7 +8329,11 @@
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/tfunk/-/tfunk-3.1.0.tgz",
"integrity": "sha1-OORBT8ZJd9h6/apy+sttKfgve1s=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "chalk": "1.1.3",
+ "object-path": "0.9.2"
+ }
},
"through": {
"version": "2.3.8",
@@ -5546,19 +8345,30 @@
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
"integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "readable-stream": "2.3.3",
+ "xtend": "4.0.1"
+ }
},
"through2-filter": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-2.0.0.tgz",
"integrity": "sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "through2": "2.0.3",
+ "xtend": "4.0.1"
+ }
},
"tildify": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz",
"integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "os-homedir": "1.0.2"
+ }
},
"time-stamp": {
"version": "1.1.0",
@@ -5570,24 +8380,33 @@
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz",
"integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "process": "0.11.10"
+ }
},
"tiny-emitter": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.0.0.tgz",
- "integrity": "sha1-utMnrbGAS0KiMa+nQVMr2ITNCa0="
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.0.2.tgz",
+ "integrity": "sha512-2NM0auVBGft5tee/OxP4PI3d8WItkDM+fPnaRAVo6xTDI2knbz9eC5ArWGqtGlYqiH3RU5yMpdyTTO7MguC4ow=="
},
"tmp": {
"version": "0.0.31",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz",
"integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "os-tmpdir": "1.0.2"
+ }
},
"to-absolute-glob": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz",
"integrity": "sha1-HN+kcqnvUMI57maZm2YsoOs5k38=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "extend-shallow": "2.0.1"
+ }
},
"to-array": {
"version": "0.1.4",
@@ -5611,7 +8430,10 @@
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz",
"integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "punycode": "1.4.1"
+ }
},
"trim-right": {
"version": "1.0.1",
@@ -5632,10 +8454,13 @@
"dev": true
},
"tunnel-agent": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz",
- "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=",
- "dev": true
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.1.1"
+ }
},
"tweetnacl": {
"version": "0.14.5",
@@ -5648,7 +8473,10 @@
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "prelude-ls": "1.1.2"
+ }
},
"typedarray": {
"version": "0.0.6",
@@ -5660,24 +8488,37 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.2.tgz",
"integrity": "sha1-EBezLZhP9VbroQD1AViauhrOLgQ=",
- "optional": true
+ "optional": true,
+ "requires": {
+ "is-typedarray": "1.0.0"
+ }
},
"ua-parser-js": {
- "version": "0.7.13",
- "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.13.tgz",
- "integrity": "sha1-zZ3S+GSTs/RNvu7zeA/adMXuFL4="
+ "version": "0.7.14",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.14.tgz",
+ "integrity": "sha1-EQ1T+kw/MmwSEpK76skE0uAzh8o="
},
"uglify-js": {
"version": "2.8.29",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
"integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
"dev": true,
+ "requires": {
+ "source-map": "0.5.6",
+ "uglify-to-browserify": "1.0.2",
+ "yargs": "3.10.0"
+ },
"dependencies": {
"cliui": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
"integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "center-align": "0.1.3",
+ "right-align": "0.1.3",
+ "wordwrap": "0.0.2"
+ }
},
"window-size": {
"version": "0.1.0",
@@ -5695,7 +8536,13 @@
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
"integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "camelcase": "1.2.1",
+ "cliui": "2.1.0",
+ "decamelize": "1.2.0",
+ "window-size": "0.1.0"
+ }
}
}
},
@@ -5731,35 +8578,20 @@
"dev": true
},
"undertaker": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.1.0.tgz",
- "integrity": "sha1-C6AOb7aor+HpKGMVZar226YRGus=",
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.0.tgz",
+ "integrity": "sha1-M52kZGJS0ILcN45wgGcpl1DhG0k=",
"dev": true,
- "dependencies": {
- "array-each": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/array-each/-/array-each-0.1.1.tgz",
- "integrity": "sha1-xdUrqCJfNtcoF4unrsQTrPrd0Pk=",
- "dev": true
- },
- "array-slice": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
- "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=",
- "dev": true
- },
- "isobject": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-1.0.2.tgz",
- "integrity": "sha1-8Pm4zpLdVA+gdAiC44NaLgIux4o=",
- "dev": true
- },
- "object.defaults": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-0.3.0.tgz",
- "integrity": "sha1-seucvHjEx71WysbK496tWnETiCo=",
- "dev": true
- }
+ "requires": {
+ "arr-flatten": "1.1.0",
+ "arr-map": "2.0.2",
+ "bach": "1.2.0",
+ "collection-map": "1.0.0",
+ "es6-weak-map": "2.0.2",
+ "last-run": "1.1.1",
+ "object.defaults": "1.1.0",
+ "object.reduce": "1.0.1",
+ "undertaker-registry": "1.0.0"
}
},
"undertaker-registry": {
@@ -5773,19 +8605,15 @@
"resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.2.1.tgz",
"integrity": "sha1-WqADz76Uxf+GbE59ZouxxNuts2k=",
"dev": true,
- "dependencies": {
- "json-stable-stringify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
- "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
- "dev": true
- }
+ "requires": {
+ "json-stable-stringify": "1.0.1",
+ "through2-filter": "2.0.0"
}
},
"universalify": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.0.tgz",
- "integrity": "sha1-nrHEZR3rzGcMyU8adXYjMruWd3g=",
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",
+ "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=",
"dev": true
},
"unpipe": {
@@ -5799,6 +8627,10 @@
"resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
"integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
"dev": true,
+ "requires": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ },
"dependencies": {
"punycode": {
"version": "1.3.2",
@@ -5811,7 +8643,11 @@
"url-parse": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.1.9.tgz",
- "integrity": "sha1-xn8dd11R8KGJEd17P/rSe7nlvRk="
+ "integrity": "sha1-xn8dd11R8KGJEd17P/rSe7nlvRk=",
+ "requires": {
+ "querystringify": "1.0.0",
+ "requires-port": "1.0.0"
+ }
},
"user-home": {
"version": "1.1.1",
@@ -5824,6 +8660,9 @@
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
"integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
"dev": true,
+ "requires": {
+ "inherits": "2.0.1"
+ },
"dependencies": {
"inherits": {
"version": "2.0.1",
@@ -5845,11 +8684,20 @@
"integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=",
"dev": true
},
+ "uuid": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
+ "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==",
+ "dev": true
+ },
"v8flags": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz",
"integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "user-home": "1.1.1"
+ }
},
"vali-date": {
"version": "1.0.0",
@@ -5861,25 +8709,51 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
"integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "spdx-correct": "1.0.2",
+ "spdx-expression-parse": "1.0.4"
+ }
},
"verror": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz",
- "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=",
- "dev": true
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "1.3.0"
+ },
+ "dependencies": {
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true
+ }
+ }
},
"vinyl": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz",
"integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "clone": "1.0.2",
+ "clone-stats": "0.0.1",
+ "replace-ext": "0.0.1"
+ }
},
"vinyl-buffer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/vinyl-buffer/-/vinyl-buffer-1.0.0.tgz",
"integrity": "sha1-ygZ+oIQx1QdyKx3lCD9gJhbrwjQ=",
"dev": true,
+ "requires": {
+ "bl": "0.9.5",
+ "through2": "0.6.5"
+ },
"dependencies": {
"isarray": {
"version": "0.0.1",
@@ -5891,7 +8765,13 @@
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ }
},
"string_decoder": {
"version": "0.10.31",
@@ -5903,7 +8783,11 @@
"version": "0.6.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
"integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "readable-stream": "1.0.34",
+ "xtend": "4.0.1"
+ }
}
}
},
@@ -5911,13 +8795,36 @@
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-2.4.4.tgz",
"integrity": "sha1-vm/zJwy1Xf19MGNkDegfJddTIjk=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "duplexify": "3.5.1",
+ "glob-stream": "5.3.5",
+ "graceful-fs": "4.1.11",
+ "gulp-sourcemaps": "1.6.0",
+ "is-valid-glob": "0.3.0",
+ "lazystream": "1.0.0",
+ "lodash.isequal": "4.5.0",
+ "merge-stream": "1.0.1",
+ "mkdirp": "0.5.1",
+ "object-assign": "4.1.1",
+ "readable-stream": "2.3.3",
+ "strip-bom": "2.0.0",
+ "strip-bom-stream": "1.0.0",
+ "through2": "2.0.3",
+ "through2-filter": "2.0.0",
+ "vali-date": "1.0.0",
+ "vinyl": "1.2.0"
+ }
},
"vinyl-source-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-1.1.0.tgz",
"integrity": "sha1-RMvlEIIFJ53rDFZTwJSiiHk4sas=",
"dev": true,
+ "requires": {
+ "through2": "0.6.5",
+ "vinyl": "0.4.6"
+ },
"dependencies": {
"clone": {
"version": "0.2.0",
@@ -5935,7 +8842,13 @@
"version": "1.0.34",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "core-util-is": "1.0.2",
+ "inherits": "2.0.3",
+ "isarray": "0.0.1",
+ "string_decoder": "0.10.31"
+ }
},
"string_decoder": {
"version": "0.10.31",
@@ -5947,13 +8860,21 @@
"version": "0.6.5",
"resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
"integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "readable-stream": "1.0.34",
+ "xtend": "4.0.1"
+ }
},
"vinyl": {
"version": "0.4.6",
"resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
"integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "clone": "0.2.0",
+ "clone-stats": "0.0.1"
+ }
}
}
},
@@ -5961,44 +8882,53 @@
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz",
"integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "source-map": "0.5.6"
+ }
},
"vm-browserify": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
"integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "indexof": "0.0.1"
+ }
},
"warning": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
- "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w="
+ "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
+ "requires": {
+ "loose-envify": "1.3.1"
+ }
},
"watchify": {
"version": "3.9.0",
"resolved": "https://registry.npmjs.org/watchify/-/watchify-3.9.0.tgz",
"integrity": "sha1-8HX9LoqGrN6Eztum5cKgvt1SPZ4=",
- "dev": true
- },
- "websocket": {
- "version": "1.0.24",
- "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.24.tgz",
- "integrity": "sha1-dJA+dfJUW2suHeFCW8HJBZF6GJA=",
- "optional": true,
- "dependencies": {
- "yaeti": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
- "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=",
- "optional": true
- }
+ "dev": true,
+ "requires": {
+ "anymatch": "1.3.2",
+ "browserify": "14.5.0",
+ "chokidar": "1.7.0",
+ "defined": "1.0.0",
+ "outpipe": "1.1.1",
+ "through2": "2.0.3",
+ "xtend": "4.0.1"
}
},
"weinre": {
"version": "2.0.0-pre-I0Z7U9OV",
"resolved": "https://registry.npmjs.org/weinre/-/weinre-2.0.0-pre-I0Z7U9OV.tgz",
"integrity": "sha1-/viqIjkh97QLu71MPtQwL2/QqBM=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "express": "2.5.11",
+ "nopt": "3.0.6",
+ "underscore": "1.7.0"
+ }
},
"whatwg-fetch": {
"version": "2.0.3",
@@ -6012,10 +8942,13 @@
"dev": true
},
"which": {
- "version": "1.2.14",
- "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz",
- "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=",
- "dev": true
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
+ "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
+ "dev": true,
+ "requires": {
+ "isexe": "2.0.0"
+ }
},
"which-module": {
"version": "1.0.0",
@@ -6044,7 +8977,11 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "string-width": "1.0.2",
+ "strip-ansi": "3.0.1"
+ }
},
"wrappy": {
"version": "1.0.2",
@@ -6056,19 +8993,30 @@
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/wreck/-/wreck-6.3.0.tgz",
"integrity": "sha1-oTaXafB7u2LWo3gzanhx/Hc8dAs=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "boom": "2.10.1",
+ "hoek": "2.16.3"
+ }
},
"write": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
"integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "mkdirp": "0.5.1"
+ }
},
"ws": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-1.1.1.tgz",
"integrity": "sha1-CC3bbGQehdS7RR8D1S8G6r2x8Bg=",
- "dev": true
+ "dev": true,
+ "requires": {
+ "options": "0.0.6",
+ "ultron": "1.0.2"
+ }
},
"wtf-8": {
"version": "1.0.0",
@@ -6095,15 +9043,38 @@
"dev": true
},
"yaeti": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-1.0.1.tgz",
- "integrity": "sha1-IX0Eu83LvYbMR45GVapMKMST3r8="
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
+ "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=",
+ "optional": true
+ },
+ "yallist": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+ "dev": true
},
"yargs": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-6.4.0.tgz",
"integrity": "sha1-gW4ahm1VmMzzTlWW3c4i2S2kkNQ=",
"dev": true,
+ "requires": {
+ "camelcase": "3.0.0",
+ "cliui": "3.2.0",
+ "decamelize": "1.2.0",
+ "get-caller-file": "1.0.2",
+ "os-locale": "1.4.0",
+ "read-pkg-up": "1.0.1",
+ "require-directory": "2.1.1",
+ "require-main-filename": "1.0.1",
+ "set-blocking": "2.0.0",
+ "string-width": "1.0.2",
+ "which-module": "1.0.0",
+ "window-size": "0.2.0",
+ "y18n": "3.2.1",
+ "yargs-parser": "4.2.1"
+ },
"dependencies": {
"camelcase": {
"version": "3.0.0",
@@ -6124,6 +9095,9 @@
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz",
"integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=",
"dev": true,
+ "requires": {
+ "camelcase": "3.0.0"
+ },
"dependencies": {
"camelcase": {
"version": "3.0.0",
diff --git a/app/package.json b/app/package.json
index 21b5d10..4209900 100644
--- a/app/package.json
+++ b/app/package.json
@@ -1,55 +1,61 @@
{
"name": "mediasoup-demo-app",
- "version": "1.2.0",
+ "version": "2.0.0",
"private": true,
"description": "mediasoup demo app",
"author": "IƱaki Baz Castillo ",
"license": "All Rights Reserved",
"main": "lib/index.jsx",
"dependencies": {
- "babel-runtime": "^6.23.0",
- "bowser": "^1.7.0",
+ "babel-runtime": "^6.26.0",
"classnames": "^2.2.5",
- "debug": "^2.6.8",
+ "debug": "^3.1.0",
"domready": "^1.0.8",
- "hark": "github:ibc/hark#main-with-raf",
- "material-ui": "^0.18.4",
- "prop-types": "^15.5.10",
- "protoo-client": "^1.1.4",
- "random-number": "0.0.7",
+ "hark": "^1.1.6",
+ "js-cookie": "^2.2.0",
+ "mediasoup-client": "^2.0.1",
+ "node-random-name": "^1.0.1",
+ "prop-types": "^15.6.0",
+ "protoo-client": "^2.0.5",
"random-string": "^0.2.0",
- "react": "^15.6.1",
+ "react": "^16.0.0",
"react-clipboard.js": "^1.1.2",
- "react-dom": "^15.6.1",
- "react-notification-system": "github:ibc/react-notification-system#master",
- "react-tap-event-plugin": "^2.0.1",
- "react-transition-group": "^1.2.0",
- "sdp-transform": "^2.3.0",
- "url-parse": "^1.1.9",
- "yaeti": "^1.0.1"
+ "react-dom": "^16.0.0",
+ "react-redux": "^5.0.6",
+ "react-spinner": "^0.2.7",
+ "react-tooltip": "^3.4.0",
+ "react-transition-group": "^2.2.1",
+ "redux": "^3.7.2",
+ "redux-logger": "^3.0.6",
+ "redux-thunk": "^2.2.0",
+ "riek": "^1.1.0",
+ "supports-color": "^5.0.0",
+ "url-parse": "^1.1.9"
},
"devDependencies": {
+ "babel-core": "^6.26.0",
"babel-plugin-transform-object-assign": "^6.22.0",
+ "babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
- "babelify": "^7.3.0",
- "browser-sync": "^2.18.12",
- "browserify": "^14.4.0",
+ "babelify": "^8.0.0",
+ "browser-sync": "^2.18.13",
+ "browserify": "^14.5.0",
"del": "^3.0.0",
- "envify": "^4.0.0",
- "eslint": "^4.1.1",
- "eslint-plugin-import": "^2.6.0",
- "eslint-plugin-react": "^7.1.0",
+ "envify": "^4.1.0",
+ "eslint": "^4.10.0",
+ "eslint-plugin-import": "^2.8.0",
+ "eslint-plugin-react": "^7.4.0",
"gulp": "git://github.com/gulpjs/gulp.git#4.0",
"gulp-css-base64": "^1.3.4",
"gulp-eslint": "^4.0.0",
- "gulp-header": "^1.8.8",
+ "gulp-header": "^1.8.9",
"gulp-if": "^2.0.2",
"gulp-plumber": "^1.1.0",
"gulp-rename": "^1.2.2",
"gulp-stylus": "^2.6.0",
- "gulp-touch": "^1.0.1",
+ "gulp-touch-cmd": "0.0.1",
"gulp-uglify": "^3.0.0",
"gulp-util": "^3.0.8",
"mkdirp": "^0.5.1",
diff --git a/app/resources/images/body-bg-2.jpg b/app/resources/images/body-bg-2.jpg
index 10e59d1..b909ef8 100644
Binary files a/app/resources/images/body-bg-2.jpg and b/app/resources/images/body-bg-2.jpg differ
diff --git a/app/resources/images/body-bg.jpg b/app/resources/images/body-bg.jpg
index 299edb4..10e59d1 100644
Binary files a/app/resources/images/body-bg.jpg and b/app/resources/images/body-bg.jpg differ
diff --git a/app/resources/images/devices/chrome_16x16.png b/app/resources/images/devices/chrome_16x16.png
new file mode 100644
index 0000000..a5ac9d7
Binary files /dev/null and b/app/resources/images/devices/chrome_16x16.png differ
diff --git a/app/resources/images/devices/edge_16x16.png b/app/resources/images/devices/edge_16x16.png
new file mode 100644
index 0000000..c620c60
Binary files /dev/null and b/app/resources/images/devices/edge_16x16.png differ
diff --git a/app/resources/images/devices/firefox_16x16.png b/app/resources/images/devices/firefox_16x16.png
new file mode 100644
index 0000000..b3b50ac
Binary files /dev/null and b/app/resources/images/devices/firefox_16x16.png differ
diff --git a/app/resources/images/devices/opera_16x16.png b/app/resources/images/devices/opera_16x16.png
new file mode 100644
index 0000000..84e6d0f
Binary files /dev/null and b/app/resources/images/devices/opera_16x16.png differ
diff --git a/app/resources/images/devices/safari_16x16.png b/app/resources/images/devices/safari_16x16.png
new file mode 100644
index 0000000..e186f90
Binary files /dev/null and b/app/resources/images/devices/safari_16x16.png differ
diff --git a/app/resources/images/devices/sip_endpoint.svg b/app/resources/images/devices/sip_endpoint.svg
new file mode 100644
index 0000000..8538c6d
--- /dev/null
+++ b/app/resources/images/devices/sip_endpoint.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/app/resources/images/devices/unknown.svg b/app/resources/images/devices/unknown.svg
new file mode 100644
index 0000000..cab67f5
--- /dev/null
+++ b/app/resources/images/devices/unknown.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/resources/images/icon_audio_only_black.svg b/app/resources/images/icon_audio_only_black.svg
new file mode 100644
index 0000000..d79e38b
--- /dev/null
+++ b/app/resources/images/icon_audio_only_black.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/app/resources/images/icon_audio_only_white.svg b/app/resources/images/icon_audio_only_white.svg
new file mode 100644
index 0000000..12a0389
--- /dev/null
+++ b/app/resources/images/icon_audio_only_white.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/resources/images/icon_change_webcam_black.svg b/app/resources/images/icon_change_webcam_black.svg
new file mode 100644
index 0000000..deef458
--- /dev/null
+++ b/app/resources/images/icon_change_webcam_black.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/app/resources/images/icon_change_webcam_white_unsupported.svg b/app/resources/images/icon_change_webcam_white_unsupported.svg
new file mode 100644
index 0000000..3fc69ea
--- /dev/null
+++ b/app/resources/images/icon_change_webcam_white_unsupported.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/resources/images/icon_mic_black_on.svg b/app/resources/images/icon_mic_black_on.svg
new file mode 100644
index 0000000..e5f2bbc
--- /dev/null
+++ b/app/resources/images/icon_mic_black_on.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/app/resources/images/icon_mic_white_off.svg b/app/resources/images/icon_mic_white_off.svg
new file mode 100644
index 0000000..47cc5da
--- /dev/null
+++ b/app/resources/images/icon_mic_white_off.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/resources/images/icon_mic_white_unsupported.svg b/app/resources/images/icon_mic_white_unsupported.svg
new file mode 100644
index 0000000..2a4cbc0
--- /dev/null
+++ b/app/resources/images/icon_mic_white_unsupported.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/resources/images/icon_notification_error_white.svg b/app/resources/images/icon_notification_error_white.svg
new file mode 100644
index 0000000..80fde2e
--- /dev/null
+++ b/app/resources/images/icon_notification_error_white.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/app/resources/images/icon_notification_info_white.svg b/app/resources/images/icon_notification_info_white.svg
new file mode 100644
index 0000000..4838d8e
--- /dev/null
+++ b/app/resources/images/icon_notification_info_white.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/app/resources/images/icon_remote_mic_white_off.svg b/app/resources/images/icon_remote_mic_white_off.svg
new file mode 100644
index 0000000..2a4cbc0
--- /dev/null
+++ b/app/resources/images/icon_remote_mic_white_off.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/resources/images/icon_remote_webcam_white_off.svg b/app/resources/images/icon_remote_webcam_white_off.svg
new file mode 100644
index 0000000..a2379b3
--- /dev/null
+++ b/app/resources/images/icon_remote_webcam_white_off.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/resources/images/icon_restart_ice_white.svg b/app/resources/images/icon_restart_ice_white.svg
new file mode 100644
index 0000000..2190d8c
--- /dev/null
+++ b/app/resources/images/icon_restart_ice_white.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/resources/images/icon_webcam_black_on.svg b/app/resources/images/icon_webcam_black_on.svg
new file mode 100644
index 0000000..9357fe2
--- /dev/null
+++ b/app/resources/images/icon_webcam_black_on.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/app/resources/images/icon_webcam_white_on.svg b/app/resources/images/icon_webcam_white_on.svg
new file mode 100644
index 0000000..beec50b
--- /dev/null
+++ b/app/resources/images/icon_webcam_white_on.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/resources/images/icon_webcam_white_unsupported.svg b/app/resources/images/icon_webcam_white_unsupported.svg
new file mode 100644
index 0000000..a2379b3
--- /dev/null
+++ b/app/resources/images/icon_webcam_white_unsupported.svg
@@ -0,0 +1,4 @@
+
diff --git a/app/resources/images/paint-stains-spots-bright-5K-wallpaper.jpg b/app/resources/images/paint-stains-spots-bright-5K-wallpaper.jpg
new file mode 100644
index 0000000..96f40bf
Binary files /dev/null and b/app/resources/images/paint-stains-spots-bright-5K-wallpaper.jpg differ
diff --git a/app/stylus/components/App.styl b/app/stylus/components/App.styl
deleted file mode 100644
index 68dc0e9..0000000
--- a/app/stylus/components/App.styl
+++ /dev/null
@@ -1,5 +0,0 @@
-[data-component='App'] {
- position: relative;
- min-height: 100vh;
- width: 100%;
-}
diff --git a/app/stylus/components/LocalVideo.styl b/app/stylus/components/LocalVideo.styl
deleted file mode 100644
index 5d5cfcf..0000000
--- a/app/stylus/components/LocalVideo.styl
+++ /dev/null
@@ -1,100 +0,0 @@
-[data-component='LocalVideo'] {
- position: relative;
- flex: 0 0 auto;
-
- TransitionAppear(500ms);
-
- +desktop() {
- height: 220px;
- width: 220px;
- border: 2px solid rgba(#fff, 0.5);
- }
-
- +mobile() {
- height: 180px;
- width: 180px;
- border: 2px solid rgba(#fff, 0.5);
- }
-
- &.state-checking {
- border-color: orange;
- }
-
- &.state-checking {
- animation: LocalVideo-state-checking .5s infinite linear;
- }
-
- &.state-connected,
- &.state-completed {
- border-color: rgba(#49ce3e, 0.9);
- }
-
- &.state-failed,
- &.state-disconnected,
- &.state-closed {
- border-color: rgba(#ff2000, 0.75);
- }
-
- &.active-speaker {
- border-color: rgba(#fff, 0.9);
- }
-
- > .controls {
- pointer-events: none;
- position: absolute;
- z-index: 10;
- top: 0;
- left: 0;
- right: 0;
- display: flex;
- flex-direction: row;
- justify-content: flex-end;
- align-items: center;
- transition-property: opacity;
- transition-duration: 0.25s;
-
- > .control {
- pointer-events: auto;
- flex: 0 0 auto;
- margin: 4px !important;
- margin-left: 0 !important;
- height: 32px !important;
- width: 32px !important;
- padding: 0 !important;
- background-color: rgba(#000, 0.25) !important;
- border-radius: 100%;
- opacity: 0.8;
-
- &:hover {
- background-color: rgba(#000, 0.85) !important;
- opacity: 1;
- }
- }
- }
-
- > .info {
- position: absolute;
- z-index: 10;
- bottom: 4px;
- left: 0;
- right: 0;
- display: flex;
- flex-direction: row;
- justify-content: center;
- align-items: center;
-
- > .peer-id {
- padding: 4px 14px;
- font-size: 14px;
- color: rgba(#fff, 0.75);
- background: rgba(#000, 0.6);
- border-radius: 4px;
- }
- }
-}
-
-@keyframes LocalVideo-state-checking {
- 50% {
- border-color: rgba(orange, 0.9);
- }
-}
diff --git a/app/stylus/components/Me.styl b/app/stylus/components/Me.styl
new file mode 100644
index 0000000..18f95d3
--- /dev/null
+++ b/app/stylus/components/Me.styl
@@ -0,0 +1,98 @@
+[data-component='Me'] {
+ position: relative;
+ height: 100%;
+ width: 100%;
+
+ > .controls {
+ position: absolute;
+ z-index: 10
+ top: 0;
+ left: 0;
+ right: 0;
+ display: flex;
+ flex-direction:; row;
+ justify-content: flex-end;
+ align-items: center;
+
+ > .button {
+ flex: 0 0 auto;
+ margin: 4px;
+ margin-left: 0;
+ border-radius: 2px;
+ background-position: center;
+ background-size: 75%;
+ background-repeat: no-repeat;
+ background-color: rgba(#000, 0.5);
+ cursor: pointer;
+ transition-property: opacity, background-color;
+ transition-duration: 0.15s;
+
+ +desktop() {
+ width: 28px;
+ height: 28px;
+ opacity: 0.85;
+
+ &:hover {
+ opacity: 1;
+ }
+ }
+
+ +mobile() {
+ width: 26px;
+ height: 26px;
+ }
+
+ &.unsupported {
+ pointer-events: none;
+ }
+
+ &.disabled {
+ pointer-events: none;
+ opacity: 0.5;
+ }
+
+ &.on {
+ background-color: rgba(#fff, 0.7);
+ }
+
+ &.mic {
+ &.on {
+ background-image: url('/resources/images/icon_mic_black_on.svg');
+ }
+
+ &.off {
+ background-image: url('/resources/images/icon_mic_white_off.svg');
+ background-color: rgba(#d42241, 0.7);
+ }
+
+ &.unsupported {
+ background-image: url('/resources/images/icon_mic_white_unsupported.svg');
+ }
+ }
+
+ &.webcam {
+ &.on {
+ background-image: url('/resources/images/icon_webcam_black_on.svg');
+ }
+
+ &.off {
+ background-image: url('/resources/images/icon_webcam_white_on.svg');
+ }
+
+ &.unsupported {
+ background-image: url('/resources/images/icon_webcam_white_unsupported.svg');
+ }
+ }
+
+ &.change-webcam {
+ &.on {
+ background-image: url('/resources/images/icon_change_webcam_black.svg');
+ }
+
+ &.unsupported {
+ background-image: url('/resources/images/icon_change_webcam_white_unsupported.svg');
+ }
+ }
+ }
+ }
+}
diff --git a/app/stylus/components/Notifications.styl b/app/stylus/components/Notifications.styl
new file mode 100644
index 0000000..32b2e92
--- /dev/null
+++ b/app/stylus/components/Notifications.styl
@@ -0,0 +1,101 @@
+[data-component='Notifications'] {
+ position: fixed;
+ z-index: 9999;
+ pointer-events: none;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ padding: 20px;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ align-items: flex-end;
+
+ +desktop() {
+ padding: 10px;
+ width: 300px;
+ }
+
+ +mobile() {
+ padding: 4px;
+ width: 65%;
+ max-width: 220px;
+ }
+
+ > .notification {
+ pointer-events: auto;
+ margin-top: 4px;
+ border-radius: 4px;
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+
+ &.Appear-appear {
+ visibility: hidden;
+ opacity: 0;
+ transition: all 0.15s ease-in-out 0s, visibility 0s linear 0.25s;
+ transform: translateX(200px);
+ }
+
+ &.Appear-appear.Appear-appear-active {
+ visibility: visible;
+ pointer-events: auto;
+ opacity: 1;
+ transform: translateY(0%);
+ transition-delay: 0s, 0s;
+ }
+
+ +desktop() {
+ padding: 16px 24px 16px 12px;
+ }
+
+ +mobile() {
+ padding: 6px 16px 6px 12px;
+ }
+
+ > .icon {
+ flex: 0 0 auto;
+ height: 24px;
+ width: 24px;
+ margin-right: 12px;
+ background-position: center;
+ background-size: 100%;
+ background-repeat: no-repeat;
+ }
+
+ > .text {
+ font-size: 13px;
+ user-select: none;
+ cursor: default;
+
+ +desktop() {
+ font-size: 13px;
+ }
+
+ +mobile() {
+ font-size: 11px;
+ }
+ }
+
+ &.info {
+ background-color: rgba(#0a1d26, 0.75);
+ color: rgba(#fff, 0.65);
+
+ >.icon {
+ opacity: 0.65;
+ background-image: url('/resources/images/icon_notification_info_white.svg');
+ }
+ }
+
+ &.error {
+ background-color: rgba(#ff1914, 0.65);
+ color: rgba(#fff, 0.85);
+
+ >.icon {
+ opacity: 0.85;
+ background-image: url('/resources/images/icon_notification_error_white.svg');
+ }
+ }
+ }
+}
diff --git a/app/stylus/components/Peer.styl b/app/stylus/components/Peer.styl
new file mode 100644
index 0000000..8426b0f
--- /dev/null
+++ b/app/stylus/components/Peer.styl
@@ -0,0 +1,72 @@
+[data-component='Peer'] {
+ flex: 100 100 auto;
+ position: relative;
+ height: 100%;
+ width: 100%;
+
+ +mobile() {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ }
+
+ > .indicators {
+ position: absolute;
+ z-index: 10
+ top: 0;
+ left: 0;
+ right: 0;
+ display: flex;
+ flex-direction:; row;
+ justify-content: flex-end;
+ align-items: center;
+
+ > .icon {
+ flex: 0 0 auto;
+ margin: 4px;
+ margin-left: 0;
+ width: 32px;
+ height: 32px;
+ background-position: center;
+ background-size: 75%;
+ background-repeat: no-repeat;
+ transition-property: opacity;
+ transition-duration: 0.15s;
+
+ +desktop() {
+ opacity: 0.85;
+ }
+
+ &.mic-off {
+ background-image: url('/resources/images/icon_remote_mic_white_off.svg');
+ }
+
+ &.webcam-off {
+ background-image: url('/resources/images/icon_remote_webcam_white_off.svg');
+ }
+ }
+ }
+
+ .incompatible-video {
+ position: absolute;
+ z-index: 2
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ > p {
+ padding: 6px 12px;
+ border-radius: 6px;
+ user-select: none;
+ pointer-events: none;
+ font-size: 15px;
+ color: rgba(#fff, 0.55);
+ }
+ }
+}
diff --git a/app/stylus/components/PeerView.styl b/app/stylus/components/PeerView.styl
new file mode 100644
index 0000000..a44610c
--- /dev/null
+++ b/app/stylus/components/PeerView.styl
@@ -0,0 +1,262 @@
+[data-component='PeerView'] {
+ position: relative;
+ flex: 100 100 auto;
+ height: 100%;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ background-color: rgba(#2a4b58, 0.9);
+ background-image: url('/resources/images/buddy.svg');
+ background-position: bottom;
+ background-size: auto 85%;
+ background-repeat: no-repeat;
+
+ > .info {
+ $backgroundTint = #000;
+
+ position: absolute;
+ z-index: 5
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ background: linear-gradient(to bottom,
+ rgba($backgroundTint, 0) 0%,
+ rgba($backgroundTint, 0) 60%,
+ rgba($backgroundTint, 0.1) 70%,
+ rgba($backgroundTint, 0.8) 100%);
+
+ > .media {
+ flex: 0 0 auto;
+ display: flex;
+ flex-direction: row;
+
+ > .box {
+ margin: 4px;
+ padding: 2px 4px;
+ border-radius: 2px;
+ background-color: rgba(#000, 0.25);
+
+ > p {
+ user-select: none;
+ pointer-events: none;
+ margin-bottom: 2px;
+ color: rgba(#fff, 0.7);
+ font-size: 10px;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
+ }
+ }
+
+ > .peer {
+ flex: 0 0 auto;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+
+ +desktop() {
+ &.is-me {
+ padding: 10px;
+ align-items: flex-start;
+ }
+
+ &:not(.is-me) {
+ padding: 20px;
+ align-items: flex-start;
+ }
+ }
+
+ +mobile() {
+ &.is-me {
+ padding: 10px;
+ align-items: flex-start;
+ }
+
+ &:not(.is-me) {
+ padding: 10px;
+ align-items: flex-end;
+ }
+ }
+
+ > .display-name {
+ font-size: 14px;
+ font-weight: 400;
+ color: rgba(#fff, 0.85);
+ }
+
+ > span.display-name {
+ user-select: none;
+ cursor: text;
+
+ &:not(.editable) {
+ cursor: default;
+ }
+
+ &.editable {
+ +desktop() {
+ &:hover {
+ background-color: rgba(#aeff00, 0.25);
+ }
+ }
+ }
+
+ &.loading {
+ opacity: 0.5;
+ }
+ }
+
+ > input.display-name {
+ border: none;
+ border-bottom: 1px solid #aeff00;
+ background-color: transparent;
+ }
+
+ > .row {
+ margin-top: 4px;
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: flex-end;
+
+ > .device-icon {
+ height: 18px;
+ width: 18px;
+ margin-right: 3px;
+ user-select: none;
+ pointer-events: none;
+ background-position: center;
+ background-size: 100%;
+ background-repeat: no-repeat;
+ background-image: url('/resources/images/devices/unknown.svg');
+
+ &.chrome {
+ background-image: url('/resources/images/devices/chrome_16x16.png');
+ }
+
+ &.firefox {
+ background-image: url('/resources/images/devices/firefox_16x16.png');
+ }
+
+ &.safari {
+ background-image: url('/resources/images/devices/safari_16x16.png');
+ }
+
+ &.msedge {
+ background-image: url('/resources/images/devices/edge_16x16.png');
+ }
+
+ &.opera {
+ background-image: url('/resources/images/devices/opera_16x16.png');
+ }
+
+ &.sipendpoint {
+ background-image: url('/resources/images/devices/sip_endpoint.svg');
+ }
+ }
+
+ > .device-version {
+ user-select: none;
+ pointer-events: none;
+ font-size: 11px;
+ color: rgba(#fff, 0.55);
+ }
+ }
+ }
+ }
+
+ > video {
+ flex: 100 100 auto;
+ height: 100%;
+ width: 100%;
+ object-fit: cover;
+ user-select: none;
+ transition-property: opacity;
+ transition-duration: .15s;
+ background-color: rgba(#000, 0.75);
+
+ &.is-me {
+ transform: scaleX(-1);
+ }
+
+ &.hidden {
+ opacity: 0;
+ transition-duration: 0s;
+ }
+
+ &.loading {
+ filter: blur(5px);
+ }
+ }
+
+ > .volume-container {
+ position: absolute;
+ top: 0
+ bottom: 0;
+ right: 2px;
+ width: 10px;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ > .bar {
+ width: 6px;
+ border-radius: 6px;
+ background: rgba(yellow, 0.65);
+ transition-property: height background-color;
+ transition-duration: 0.25s;
+
+ &.level0 { height: 0; background-color: rgba(yellow, 0.65); }
+ &.level1 { height: 10%; background-color: rgba(yellow, 0.65); }
+ &.level2 { height: 20%; background-color: rgba(yellow, 0.65); }
+ &.level3 { height: 30%; background-color: rgba(yellow, 0.65); }
+ &.level4 { height: 40%; background-color: rgba(orange, 0.65); }
+ &.level5 { height: 50%; background-color: rgba(orange, 0.65); }
+ &.level6 { height: 60%; background-color: rgba(red, 0.65); }
+ &.level7 { height: 70%; background-color: rgba(red, 0.65); }
+ &.level8 { height: 80%; background-color: rgba(#000, 0.65); }
+ &.level9 { height: 90%; background-color: rgba(#000, 0.65); }
+ &.level10 { height: 100%; background-color: rgba(#000, 0.65); }
+ }
+ }
+
+ > .spinner-container {
+ position: absolute;
+ top: 0
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background-color: rgba(#000, 0.75);
+
+ .react-spinner {
+ position: relative;
+ width: 48px;
+ height: 48px;
+ top: 50%;
+ left: 50%;
+
+ .react-spinner_bar {
+ position: absolute;
+ width: 20%;
+ height: 7.8%;
+ top: -3.9%;
+ left: -10%;
+ animation: PeerView-spinner 1.2s linear infinite;
+ border-radius: 5px;
+ background-color: rgba(#fff, 0.5);
+ }
+ }
+ }
+}
+
+@keyframes PeerView-spinner {
+ 0% { opacity: 1; }
+ 100% { opacity: 0.15; }
+}
diff --git a/app/stylus/components/Peers.styl b/app/stylus/components/Peers.styl
new file mode 100644
index 0000000..7f72b52
--- /dev/null
+++ b/app/stylus/components/Peers.styl
@@ -0,0 +1,60 @@
+[data-component='Peers'] {
+ min-height: 100%;
+ width: 100%;
+
+ +desktop() {
+ width: 100%;
+ padding: 40px 0 140px 0;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ justify-content: center;
+ align-items: center;
+ align-content: center;
+ }
+
+ +mobile() {
+ min-height: 100vh;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ }
+
+ > .peer-container {
+ overflow: hidden;
+
+ AppearFadeIn(1000ms);
+
+ +desktop() {
+ flex: 0 0 auto;
+ height: 382px;
+ width: 450px;
+ margin: 6px;
+ border: 1px solid rgba(#fff, 0.15);
+ box-shadow: 0px 5px 12px 2px rgba(#111, 0.5);
+ transition-property: border-color;
+ transition-duration: 0.15s;
+
+ &.active-speaker {
+ border-color: #fff;
+ }
+ }
+
+ +mobile() {
+ flex: 100 100 auto;
+ order: 2;
+ min-height: 25vh;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ &.active-speaker {
+ order: 1;
+ }
+ }
+ }
+}
diff --git a/app/stylus/components/RemoteVideo.styl b/app/stylus/components/RemoteVideo.styl
deleted file mode 100644
index 025e5f3..0000000
--- a/app/stylus/components/RemoteVideo.styl
+++ /dev/null
@@ -1,114 +0,0 @@
-[data-component='RemoteVideo'] {
- position: relative;
- flex: 0 0 auto;
- transition-duration: 0.25s;
-
- TransitionAppear(500ms);
-
- &.fullsize {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- margin: 0;
- height: 100vh;
- width: 100%;
-
- > .info {
- justify-content: flex-end;
- right: 4px;
- }
- }
-
- +desktop() {
- height: 350px;
- width: 400px;
- margin: 4px;
- border: 4px solid rgba(#fff, 0.2);
-
- &.fullsize {
- border-width: 0;
- }
- }
-
- +mobile() {
- height: 50vh;
- width: 100%;
- border: 4px solid rgba(#fff, 0.2);
- border-bottom-width: 0;
-
- &:last-child {
- border-bottom-width: 4px;
- }
-
- &.fullsize {
- border-width: 0;
- }
- }
-
- &.active-speaker {
- border-color: rgba(#fff, 0.9);
- }
-
- > .controls {
- pointer-events: none;
- position: absolute;
- z-index: 10;
- top: 0;
- left: 0;
- right: 0;
- display: flex;
- flex-direction: row;
- justify-content: flex-end;
- align-items: center;
- transition-property: opacity;
- transition-duration: 0.25s;
- opacity: 0.8;
-
- > .control {
- pointer-events: auto;
- flex: 0 0 auto;
- margin: 4px !important;
- margin-left: 0 !important;
- height: 32px !important;
- width: 32px !important;
- padding: 0 !important;
- background-color: rgba(#000, 0.25) !important;
- border-radius: 100%;
- opacity: 0.8;
-
- &:hover {
- background-color: rgba(#000, 0.85) !important;
- opacity: 1;
- }
- }
- }
-
- > .info {
- position: absolute;
- z-index: 10;
- bottom: 4px;
- left: 0;
- right: 0;
- display: flex;
- flex-direction: row;
-
- +desktop() {
- justify-content: center;
- }
-
- +mobile() {
- justify-content: flex-end;
- right: 4px;
- }
-
- > .peer-id {
- padding: 6px 16px;
- font-size: 16px;
- color: rgba(#fff, 0.75);
- background: rgba(#000, 0.6);
- border-radius: 4px;
- }
- }
-}
diff --git a/app/stylus/components/Room.styl b/app/stylus/components/Room.styl
index 22cafd2..5e5bc84 100644
--- a/app/stylus/components/Room.styl
+++ b/app/stylus/components/Room.styl
@@ -1,14 +1,91 @@
[data-component='Room'] {
position: relative;
- overflow: auto;
- display: flex;
- flex-direction: row;
- justify-content: center;
- align-items: center;
+ height: 100%;
+ width: 100%;
- +desktop() {
- min-height: 100vh;
- width: 100%;
+ AppearFadeIn(300ms);
+
+ > .state {
+ position: fixed;
+ z-index: 100;
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ border-radius: 25px;
+ background-color: rgba(#fff, 0.2);
+
+ +desktop() {
+ top: 20px;
+ left: 20px;
+ width: 124px;
+ }
+
+ +mobile() {
+ top: 10px;
+ left: 10px;
+ width: 110px;
+ }
+
+ > .icon {
+ flex: 0 0 auto;
+ border-radius: 100%;
+
+ +desktop() {
+ margin: 5px;
+ margin-right: 0;
+ height: 20px;
+ width: 20px;
+ }
+
+ +mobile() {
+ margin: 4px;
+ margin-right: 0;
+ height: 16px;
+ width: 16px;
+ }
+
+ &.new, &.closed {
+ background-color: rgba(#aaa, 0.5);
+ }
+
+ &.connecting {
+ animation: Room-info-state-connecting .75s infinite linear;
+ }
+
+ &.connected {
+ background-color: rgba(#30bd18, 0.75);
+
+ +mobile() {
+ display: none;
+ }
+ }
+ }
+
+ > .text {
+ flex: 100 0 auto;
+ user-select: none;
+ pointer-events: none;
+ text-align: center;
+ text-transform: uppercase;
+ font-family: 'Roboto';
+ font-weight: 400;
+ color: rgba(#fff, 0.75);
+
+ +desktop() {
+ font-size: 12px;
+ }
+
+ +mobile() {
+ font-size: 10px;
+ }
+
+ &.connected {
+ +mobile() {
+ display: none;
+ }
+ }
+ }
}
> .room-link-wrapper {
@@ -24,7 +101,7 @@
> .room-link {
width: auto;
- background-color: rgba(#fff, 0.8);
+ background-color: rgba(#fff, 0.75);
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
box-shadow: 0px 3px 12px 2px rgba(#111, 0.4);
@@ -33,15 +110,24 @@
display: block;;
user-select: none;
pointer-events: auto;
- padding: 10px 20px;
color: #104758;
- font-size: 16px;
+ font-weight: 400;
cursor: pointer;
text-decoration: none;
transition-property: opacity;
transition-duration: 0.25s;
opacity: 0.8;
+ +desktop() {
+ padding: 10px 20px;
+ font-size: 16px;
+ }
+
+ +mobile() {
+ padding: 6px 10px;
+ font-size: 14px;
+ }
+
&:hover {
opacity: 1;
text-decoration: underline;
@@ -50,65 +136,105 @@
}
}
- > .remote-videos {
+ > .me-container {
+ position: fixed;
+ z-index: 100;
+ overflow: hidden;
+ box-shadow: 0px 5px 12px 2px rgba(#111, 0.5);
+ transition-property: border-color;
+ transition-duration: 0.15s;
+
+ &.active-speaker {
+ border-color: #fff;
+ }
+
+desktop() {
- min-height: 100vh;
- width: 100%;
- padding-bottom: 150px;
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: center;
- align-items: center;
- align-content: center;
+ height: 200px;
+ width: 235px;
+ bottom: 20px;
+ left: 20px;
+ border: 1px solid rgba(#fff, 0.15);
}
+mobile() {
- min-height: 100vh;
- width: 100%;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
+ height: 175px;
+ width: 150px;
+ bottom: 10px;
+ left: 10px;
+ border: 1px solid rgba(#fff, 0.25);
}
}
- > .local-video {
+ > .sidebar {
position: fixed;
+ z-index: 101;
+ top: calc(50% - 60px);
+ height: 120px;
display: flex;
- flex-direction: row;
- z-index: 100;
- box-shadow: 0px 5px 12px 2px rgba(#111, 0.5);
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+desktop() {
- bottom: 20px;
left: 20px;
+ width: 36px;
}
+mobile() {
- bottom: 10px;
left: 10px;
+ width: 32px;
}
- > .show-stats {
- position: absolute;
- bottom: 5px;
- right: -40px;
- width: 30px;
- height: 30px;
- background-image: url('/resources/images/stats.svg');
+ > .button {
+ flex: 0 0 auto;
+ margin: 4px 0;
background-position: center;
- background-size: cover;
+ background-size: 75%;
background-repeat: no-repeat;
- background-color: rgba(#000, 0.25);
- border-radius: 4px;
+ background-color: rgba(#fff, 0.15);
cursor: pointer;
- opacity: 0.85;
- transition-duration: 0.25s;
+ transition-property: opacity, background-color;
+ transition-duration: 0.15s;
+ border-radius: 100%;
- &:hover {
- opacity: 1;
+ +desktop() {
+ height: 36px;
+ width: 36px;
+ }
+
+ +mobile() {
+ height: 32px;
+ width: 32px;
+ }
+
+ &.on {
+ background-color: rgba(#fff, 0.7);
+ }
+
+ &.disabled {
+ pointer-events: none;
+ opacity: 0.5;
+ }
+
+ &.audio-only {
+ background-image: url('/resources/images/icon_audio_only_white.svg');
+
+ &.on {
+ background-image: url('/resources/images/icon_audio_only_black.svg');
+ }
+ }
+
+ &.restart-ice {
+ background-image: url('/resources/images/icon_restart_ice_white.svg');
+
+ &.on {
+ background-image: url('/resources/images/icon_restart_ice__black.svg');
+ }
}
}
}
}
+
+@keyframes Room-info-state-connecting {
+ 50% { background-color: rgba(orange, 0.75); }
+}
diff --git a/app/stylus/components/Stats.styl b/app/stylus/components/Stats.styl
deleted file mode 100644
index f715e8f..0000000
--- a/app/stylus/components/Stats.styl
+++ /dev/null
@@ -1,114 +0,0 @@
-[data-component='Stats'] {
- TransitionAppear(500ms);
-
- +desktop() {
- position: relative;
- display: flex;
- flex-direction: row;
- padding: 10px 0;
- min-width: 100px;
- background-color: rgba(#1c446f, 0.75);
- font-size: 0.7rem;
- }
-
- +mobile() {
- position: fixed;
- z-index: 3000;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- background-color: rgba(#1c446f, 0.75);
- padding: 40px 10px;
- font-size: 0.9rem;
- overflow: auto;
- }
-
- > .close {
- background-image: url('/resources/images/close.svg');
- background-position: center;
- background-size: cover;
- background-repeat: no-repeat;
- cursor: pointer;
- opacity: 0.75;
- transition-duration: 0.25s;
-
- +desktop() {
- position: absolute;
- top: 5px;
- right: 5px;
- width: 20px;
- height: 20px;
- }
-
- +mobile() {
- position: fixed;
- top: 10px;
- right: 10px;
- width: 30px;
- height: 30px;
- }
-
- &:hover {
- opacity: 1;
- }
- }
-
- > .block {
- padding: 5px;
-
- +desktop() {
- border-right: 1px solid rgba(#fff, 0.15);
-
- &:last-child {
- border-right: none;
- }
- }
-
- +mobile() {
- width: 100%;
- }
-
- > h1 {
- margin-bottom: 8px;
- text-align: center;
- font-weight: 400;
- color: #fff;
- }
-
- > .item {
- display: flex;
- flex-direction: row;
- margin: 3px 0;
- font-size: 0.95em;
- font-weight: 300;
-
- > .key {
- text-align: right;
- color: rgba(#fff, 0.9);
-
- +desktop() {
- width: 85px;
- }
-
- +mobile() {
- width: 50%;
- }
- }
-
- > .value {
- margin-left: 10px;
- text-align: left;
- color: #aae22b;
-
- +desktop() {
- width: 85px;
- }
-
- +mobile() {
- width: 50%;
- }
- }
- }
- }
-}
diff --git a/app/stylus/components/Video.styl b/app/stylus/components/Video.styl
deleted file mode 100644
index 8127d00..0000000
--- a/app/stylus/components/Video.styl
+++ /dev/null
@@ -1,84 +0,0 @@
-[data-component='Video'] {
- position: relative;
- height: 100%;
- width: 100%;
- object-fit: cover;
- background-color: rgba(#041918, 0.65);
- background-image: url('/resources/images/buddy.svg');
- background-position: bottom;
- background-size: auto 85%;
- background-repeat: no-repeat;
- overflow: hidden;
-
- > .resolution {
- position: absolute;
- z-index: 5;
- top: 0;
- left: 0;
- padding: 4px 8px;
- border-bottom-right-radius: 5px;
- background: rgba(#000, 0.5);
- transition-property: background;
- transition-duration: 0.25s;
-
- &.clickable {
- cursor: pointer;
-
- &:hover {
- background: rgba(#000, 0.85);
- }
- }
-
- > p {
- font-size: 11px;
- color: rgba(#fff, 0.75);
- }
- }
-
- > .volume {
- position: absolute;
- z-index: 5;
- top: 0
- bottom: 0;
- right: 2px;
- width: 10px;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
-
- > .bar {
- width: 6px;
- border-radius: 6px;
- background: rgba(yellow, 0.65);
- transition-property: height background-color;
- transition-duration: 0.25s;
-
- &.level0 { height: 0; background-color: rgba(yellow, 0.65); }
- &.level1 { height: 10%; background-color: rgba(yellow, 0.65); }
- &.level2 { height: 20%; background-color: rgba(yellow, 0.65); }
- &.level3 { height: 30%; background-color: rgba(yellow, 0.65); }
- &.level4 { height: 40%; background-color: rgba(orange, 0.65); }
- &.level5 { height: 50%; background-color: rgba(orange, 0.65); }
- &.level6 { height: 60%; background-color: rgba(red, 0.65); }
- &.level7 { height: 70%; background-color: rgba(red, 0.65); }
- &.level8 { height: 80%; background-color: rgba(#000, 0.65); }
- &.level9 { height: 90%; background-color: rgba(#000, 0.65); }
- &.level10 { height: 100%; background-color: rgba(#000, 0.65); }
- }
- }
-
- > video {
- height: 100%;
- width: 100%;
- object-fit: cover;
-
- &.mirror {
- transform: scaleX(-1);
- }
-
- &.hidden {
- display: none;
- }
- }
-}
diff --git a/app/stylus/index.styl b/app/stylus/index.styl
index 8ad2413..b39337a 100644
--- a/app/stylus/index.styl
+++ b/app/stylus/index.styl
@@ -4,17 +4,18 @@ global-reset();
@import './mixins';
@import './fonts';
+@import './reset';
html {
- font-family: 'Roboto';
+ height: 100%;
+ box-sizing: border-box;
background-image: url('/resources/images/body-bg-2.jpg');
background-attachment: fixed;
background-position: center;
background-size: cover;
background-repeat: no-repeat;
- min-height: 100vh;
- width: 100%;
- font-weight: 400;
+ font-family: 'Roboto';
+ font-weight: 300;
+desktop() {
font-size: 16px;
@@ -26,25 +27,20 @@ html {
}
body {
- background: none;
-}
-
-* {
- box-sizing: border-box;
- outline: none;
+ height: 100%;
}
#mediasoup-demo-app-container {
- min-height: 100vh;
+ height: 100%;
width: 100%;
// Components
- @import './components/App';
@import './components/Room';
- @import './components/LocalVideo';
- @import './components/RemoteVideo';
- @import './components/Video';
- @import './components/Stats';
+ @import './components/Me';
+ @import './components/Peers';
+ @import './components/Peer';
+ @import './components/PeerView';
+ @import './components/Notifications';
}
// Hack to detect in JS the current media query
diff --git a/app/stylus/mixins.styl b/app/stylus/mixins.styl
index 191ebbc..d68557a 100644
--- a/app/stylus/mixins.styl
+++ b/app/stylus/mixins.styl
@@ -21,13 +21,13 @@ desktop()
@media (min-device-width: 721px)
{block}
-TransitionAppear($duration = 1s, $appearOpacity = 0, $activeOpacity = 1)
+AppearFadeIn($duration = 1s, $enterOpacity = 0, $activeOpacity = 1)
will-change: opacity;
- &.transition-appear
- opacity: $appearOpacity;
+ &.Appear-appear
+ opacity: $enterOpacity;
- &.transition-appear.transition-appear-active
+ &.Appear-appear.Appear-appear-active
transition-property: opacity;
transition-duration: $duration;
opacity: $activeOpacity;
diff --git a/app/stylus/reset.styl b/app/stylus/reset.styl
new file mode 100644
index 0000000..7202cb0
--- /dev/null
+++ b/app/stylus/reset.styl
@@ -0,0 +1,14 @@
+* {
+ box-sizing: border-box;
+ outline: none;
+}
+
+body {
+ background: none;
+}
+
+input {
+ padding: 0;
+ font-family: inherit;
+ background-color: transparent;
+}
diff --git a/app/test/DATA.js b/app/test/DATA.js
new file mode 100644
index 0000000..350584c
--- /dev/null
+++ b/app/test/DATA.js
@@ -0,0 +1,401 @@
+/* eslint-disable key-spacing */
+
+exports.ROOM_OPTIONS =
+{
+ requestTimeout: 10000,
+ transportOptions:
+ {
+ tcp: false
+ },
+ __turnServers:
+ [
+ {
+ urls: [ 'turn:worker2.versatica.com:3478?transport=udp' ],
+ username: 'testuser1',
+ credential: 'testpasswd1'
+ }
+ ],
+ hidden: false
+};
+
+exports.ROOM_RTP_CAPABILITIES =
+{
+ codecs:
+ [
+ {
+ name: 'PCMA',
+ mimeType: 'audio/PCMA',
+ kind: 'audio',
+ clockRate: 8000,
+ preferredPayloadType: 8,
+ rtcpFeedback: [],
+ parameters: {}
+ },
+ {
+ name: 'opus',
+ mimeType: 'audio/opus',
+ kind: 'audio',
+ clockRate: 48000,
+ channels: 2,
+ preferredPayloadType: 96,
+ rtcpFeedback: [],
+ parameters: {}
+ },
+ {
+ name: 'SILK',
+ mimeType: 'audio/SILK',
+ kind: 'audio',
+ clockRate: 16000,
+ preferredPayloadType: 97,
+ rtcpFeedback: [],
+ parameters: {}
+ },
+ {
+ name: 'VP9',
+ mimeType: 'video/VP9',
+ kind: 'video',
+ clockRate: 90000,
+ preferredPayloadType: 102,
+ rtcpFeedback:
+ [
+ {
+ parameter: '',
+ type: 'nack'
+ },
+ {
+ parameter: 'pli',
+ type: 'nack'
+ },
+ {
+ parameter: '',
+ type: 'goog-remb'
+ },
+ {
+ parameter: 'bar',
+ type: 'foo'
+ }
+ ],
+ parameters: {}
+ },
+ {
+ name: 'rtx',
+ mimeType: 'video/rtx',
+ kind: 'video',
+ clockRate: 90000,
+ preferredPayloadType: 103,
+ rtcpFeedback: [],
+ parameters: {
+ apt: 102
+ }
+ },
+ {
+ name: 'VP8',
+ mimeType: 'video/VP8',
+ kind: 'video',
+ clockRate: 90000,
+ preferredPayloadType: 100,
+ rtcpFeedback:
+ [
+ {
+ parameter: '',
+ type: 'nack'
+ },
+ {
+ parameter: 'pli',
+ type: 'nack'
+ },
+ {
+ parameter: '',
+ type: 'goog-remb'
+ },
+ {
+ parameter: 'bar',
+ type: 'foo'
+ }
+ ],
+ parameters: {}
+ },
+ {
+ name: 'rtx',
+ mimeType: 'video/rtx',
+ kind: 'video',
+ clockRate: 90000,
+ preferredPayloadType: 101,
+ rtcpFeedback: [],
+ parameters: {
+ apt: 100
+ }
+ }
+ ],
+ headerExtensions: [
+ {
+ kind: 'audio',
+ uri: 'urn:ietf:params:rtp-hdrext:ssrc-audio-level',
+ preferredId: 10
+ },
+ {
+ kind: 'video',
+ uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time',
+ preferredId: 11
+ },
+ {
+ kind: 'video',
+ uri: 'http://foo.bar',
+ preferredId: 12
+ }
+ ],
+ fecMechanisms: []
+};
+
+exports.QUERY_ROOM_RESPONSE =
+{
+ rtpCapabilities: exports.ROOM_RTP_CAPABILITIES
+};
+
+exports.JOIN_ROOM_RESPONSE =
+{
+ peers:
+ [
+ {
+ name: 'alice',
+ appData: 'Alice iPad Pro',
+ consumers:
+ [
+ {
+ id: 3333,
+ kind: 'audio',
+ paused: false,
+ appData: 'ALICE_MIC',
+ rtpParameters:
+ {
+ muxId: null,
+ codecs:
+ [
+ {
+ name: 'PCMA',
+ mimeType: 'audio/PCMA',
+ clockRate: 8000,
+ payloadType: 8,
+ rtcpFeedback: [],
+ parameters: {}
+ }
+ ],
+ headerExtensions:
+ [
+ {
+ uri: 'urn:ietf:params:rtp-hdrext:ssrc-audio-level',
+ id: 1
+ }
+ ],
+ encodings:
+ [
+ {
+ ssrc: 33333333
+ }
+ ],
+ rtcp:
+ {
+ cname: 'ALICECNAME',
+ reducedSize: true,
+ mux: true
+ }
+ }
+ }
+ ]
+ },
+ {
+ name: 'bob',
+ appData: 'Bob HP Laptop',
+ consumers:
+ [
+ {
+ id: 6666,
+ kind: 'audio',
+ paused: false,
+ appData: 'BOB_MIC',
+ rtpParameters:
+ {
+ muxId: null,
+ codecs:
+ [
+ {
+ name: 'opus',
+ mimeType: 'audio/opus',
+ clockRate: 48000,
+ channels: 2,
+ payloadType: 96,
+ rtcpFeedback: [],
+ parameters: {}
+ }
+ ],
+ headerExtensions:
+ [
+ {
+ uri: 'urn:ietf:params:rtp-hdrext:ssrc-audio-level',
+ id: 1
+ }
+ ],
+ encodings:
+ [
+ {
+ ssrc: 66666666
+ }
+ ],
+ rtcp:
+ {
+ cname: 'BOBCNAME',
+ reducedSize: true,
+ mux: true
+ }
+ }
+ }
+ ]
+ }
+ ]
+};
+
+exports.CREATE_TRANSPORT_1_RESPONSE =
+{
+ iceParameters:
+ {
+ usernameFragment: 'server-usernamefragment-12345678',
+ password: 'server-password-xxxxxxxx',
+ iceLite: true
+ },
+ iceCandidates:
+ [
+ {
+ foundation: 'F1',
+ priority: 1234,
+ ip: '1.2.3.4',
+ protocol: 'udp',
+ port: 9999,
+ type: 'host'
+ }
+ ],
+ dtlsParameters:
+ {
+ fingerprints:
+ [
+ {
+ algorithm: 'sha-256',
+ value: 'FF:FF:39:66:A4:E2:66:60:30:18:A7:59:B3:AF:A5:33:58:5E:7F:69:A4:62:A6:D4:EB:9F:B7:42:05:35:FF:FF'
+ }
+ ],
+ role: 'client'
+ }
+};
+
+exports.CREATE_TRANSPORT_2_RESPONSE =
+{
+ iceParameters:
+ {
+ usernameFragment: 'server-usernamefragment-12345678',
+ password: 'server-password-xxxxxxxx',
+ iceLite: true
+ },
+ iceCandidates:
+ [
+ {
+ foundation: 'F1',
+ priority: 1234,
+ ip: '1.2.3.4',
+ protocol: 'udp',
+ port: 9999,
+ type: 'host'
+ }
+ ],
+ dtlsParameters:
+ {
+ fingerprints:
+ [
+ {
+ algorithm: 'sha-256',
+ value: 'FF:FF:39:66:A4:E2:66:60:30:18:A7:59:B3:AF:A5:33:58:5E:7F:69:A4:62:A6:D4:EB:9F:B7:42:05:35:FF:FF'
+ }
+ ],
+ role: 'auto'
+ }
+};
+
+exports.ALICE_WEBCAM_NEW_CONSUMER_NOTIFICATION =
+{
+ method: 'newConsumer',
+ notification: true,
+ id: 4444,
+ peerName: 'alice',
+ kind: 'video',
+ paused: true,
+ appData: 'ALICE_WEBCAM',
+ rtpParameters:
+ {
+ muxId: null,
+ codecs:
+ [
+ {
+ name: 'VP8',
+ mimeType: 'video/VP8',
+ clockRate: 90000,
+ payloadType: 100,
+ rtcpFeedback:
+ [
+ {
+ parameter: '',
+ type: 'nack'
+ },
+ {
+ parameter: 'pli',
+ type: 'nack'
+ },
+ {
+ parameter: '',
+ type: 'goog-remb'
+ },
+ {
+ parameter: 'bar',
+ type: 'foo'
+ }
+ ],
+ parameters: {}
+ },
+ {
+ name: 'rtx',
+ mimeType: 'video/rtx',
+ clockRate: 90000,
+ payloadType: 101,
+ rtcpFeedback: [],
+ parameters: {
+ apt: 100
+ }
+ }
+ ],
+ headerExtensions:
+ [
+ {
+ kind: 'video',
+ uri: 'http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time',
+ id: 11
+ },
+ {
+ kind: 'video',
+ uri: 'http://foo.bar',
+ id: 12
+ }
+ ],
+ encodings:
+ [
+ {
+ ssrc: 444444441,
+ rtx: {
+ ssrc: 444444442
+ }
+ }
+ ],
+ rtcp:
+ {
+ cname: 'ALICECNAME',
+ reducedSize: true,
+ mux: true
+ }
+ }
+};
diff --git a/app/test/gulpfile.js b/app/test/gulpfile.js
new file mode 100644
index 0000000..fdeca18
--- /dev/null
+++ b/app/test/gulpfile.js
@@ -0,0 +1,145 @@
+const path = require('path');
+const gulp = require('gulp');
+const gutil = require('gulp-util');
+const plumber = require('gulp-plumber');
+const rename = require('gulp-rename');
+const browserify = require('browserify');
+const watchify = require('watchify');
+const envify = require('envify/custom');
+const source = require('vinyl-source-stream');
+const buffer = require('vinyl-buffer');
+const eslint = require('gulp-eslint');
+const browserSync = require('browser-sync');
+
+const OUTPUT_DIR = 'output';
+const APP_NAME = 'mediasoup-client-test';
+
+// Node environment.
+process.env.NODE_ENV = 'development';
+
+function logError(error)
+{
+ gutil.log(gutil.colors.red(error.stack));
+}
+
+gulp.task('lint', () =>
+{
+ const src =
+ [
+ 'gulpfile.js',
+ '**/*.js',
+ '**/*.jsx'
+ ];
+
+ return gulp.src(src)
+ .pipe(plumber())
+ .pipe(eslint())
+ .pipe(eslint.format());
+});
+
+gulp.task('html', () =>
+{
+ return gulp.src('index.html')
+ .pipe(gulp.dest(OUTPUT_DIR));
+});
+
+gulp.task('bundle', () =>
+{
+ const watch = true;
+
+ let bundler = browserify(
+ {
+ entries : 'index.jsx',
+ extensions : [ '.js', '.jsx' ],
+ // required for sourcemaps (must be false otherwise).
+ debug : process.env.NODE_ENV === 'development',
+ // required for watchify.
+ cache : {},
+ // required for watchify.
+ packageCache : {},
+ // required to be true only for watchify.
+ fullPaths : watch
+ })
+ .transform('babelify',
+ {
+ presets : [ 'es2015', 'es2017', 'react' ],
+ plugins :
+ [
+ 'transform-runtime',
+ 'transform-object-assign',
+ 'transform-object-rest-spread'
+ ]
+ })
+ .transform(envify(
+ {
+ NODE_ENV : process.env.NODE_ENV,
+ _ : 'purge'
+ }));
+
+ if (watch)
+ {
+ bundler = watchify(bundler);
+
+ bundler.on('update', () =>
+ {
+ const start = Date.now();
+
+ gutil.log('bundling...');
+ rebundle();
+ gutil.log('bundle took %sms', (Date.now() - start));
+ });
+ }
+
+ function rebundle()
+ {
+ return bundler.bundle()
+ .on('error', logError)
+ .pipe(plumber())
+ .pipe(source(`${APP_NAME}.js`))
+ .pipe(buffer())
+ .pipe(rename(`${APP_NAME}.js`))
+ .pipe(gulp.dest(OUTPUT_DIR));
+ }
+
+ return rebundle();
+});
+
+gulp.task('livebrowser', (done) =>
+{
+ browserSync(
+ {
+ server :
+ {
+ baseDir : OUTPUT_DIR
+ },
+ ghostMode : false,
+ files : path.join(OUTPUT_DIR, '**', '*')
+ });
+
+ done();
+});
+
+gulp.task('watch', (done) =>
+{
+ // Watch changes in HTML.
+ gulp.watch([ 'index.html' ], gulp.series(
+ 'html'
+ ));
+
+ // Watch changes in JS files.
+ gulp.watch([ 'gulpfile.js', '**/*.js', '**/*.jsx' ], gulp.series(
+ 'lint'
+ ));
+
+ done();
+});
+
+gulp.task('live', gulp.series(
+ 'lint',
+ 'html',
+ 'bundle',
+ 'watch',
+ 'livebrowser'
+));
+
+gulp.task('default', gulp.series('live'));
diff --git a/app/test/index.html b/app/test/index.html
new file mode 100644
index 0000000..7fba1d4
--- /dev/null
+++ b/app/test/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+ mediasoup-client test
+
+
+
+
+
+
+
+
+ mediasoup-client test
+
+
diff --git a/app/test/index.jsx b/app/test/index.jsx
new file mode 100644
index 0000000..93e46c8
--- /dev/null
+++ b/app/test/index.jsx
@@ -0,0 +1,692 @@
+import * as mediasoupClient from 'mediasoup-client';
+import domready from 'domready';
+import Logger from '../lib/Logger';
+const DATA = require('./DATA');
+
+window.mediasoupClient = mediasoupClient;
+
+const logger = new Logger();
+
+
+const SEND = true;
+const SEND_AUDIO = true;
+const SEND_VIDEO = false;
+const RECV = true;
+
+
+domready(() =>
+{
+ logger.debug('DOM ready');
+
+ run();
+});
+
+function run()
+{
+ logger.debug('run() [environment:%s]', process.env.NODE_ENV);
+
+ let transport1;
+ let transport2;
+ let audioTrack;
+ let videoTrack;
+ let audioProducer1;
+ let audioProducer2;
+ let videoProducer;
+
+ logger.debug('calling room = new mediasoupClient.Room()');
+
+ // const room = new mediasoupClient.Room();
+ const room = new mediasoupClient.Room(DATA.ROOM_OPTIONS);
+
+ window.room = room;
+
+ room.on('closed', (originator, appData) =>
+ {
+ logger.warn(
+ 'room "closed" event [originator:%s, appData:%o]', originator, appData);
+ });
+
+ room.on('request', (request, callback, errback) =>
+ {
+ logger.warn('sending request [method:%s]:%o', request.method, request);
+
+ switch (request.method)
+ {
+ case 'queryRoom':
+ {
+ setTimeout(() =>
+ {
+ callback(DATA.QUERY_ROOM_RESPONSE);
+ errback('upppps');
+ }, 200);
+ break;
+ }
+
+ case 'joinRoom':
+ {
+ setTimeout(() =>
+ {
+ callback(DATA.JOIN_ROOM_RESPONSE);
+ // errback('upppps');
+ }, 200);
+ break;
+ }
+
+ case 'createTransport':
+ {
+ setTimeout(() =>
+ {
+ switch (request.appData)
+ {
+ case 'TRANSPORT_1':
+ callback(DATA.CREATE_TRANSPORT_1_RESPONSE);
+ break;
+ case 'TRANSPORT_2':
+ callback(DATA.CREATE_TRANSPORT_2_RESPONSE);
+ break;
+ default:
+ errback('upppps');
+ }
+ }, 250);
+ break;
+ }
+
+ case 'createProducer':
+ {
+ setTimeout(() =>
+ {
+ callback();
+ }, 250);
+ break;
+ }
+
+ case 'enableConsumer':
+ {
+ setTimeout(() =>
+ {
+ callback();
+ }, 500);
+ break;
+ }
+
+ default:
+ errback(`NO IDEA ABOUT REQUEST METHOD "${request.method}"`);
+ }
+ });
+
+ room.on('notify', (notification) =>
+ {
+ logger.warn(
+ 'sending notification [method:%s]:%o', notification.method, notification);
+
+ switch (notification.method)
+ {
+ case 'leaveRoom':
+ case 'updateTransport':
+ case 'closeTransport':
+ case 'closeProducer':
+ case 'pauseProducer':
+ case 'resumeProducer':
+ case 'pauseConsumer':
+ case 'resumeConsumer':
+ break;
+
+ default:
+ logger.error(`NO IDEA ABOUT NOTIFICATION METHOD "${notification.method}"`);
+ }
+ });
+
+ room.on('newpeer', (peer) =>
+ {
+ logger.warn('room "newpeer" event [name:"%s", peer:%o]', peer.name, peer);
+
+ handlePeer(peer);
+ });
+
+ Promise.resolve()
+ .then(() =>
+ {
+ logger.debug('calling room.join()');
+
+ const deviceInfo = mediasoupClient.getDeviceInfo();
+ const appData =
+ {
+ device : `${deviceInfo.name} ${deviceInfo.version}`
+ };
+
+ return room.join(null, appData);
+ // return room.join(DATA.ROOM_RTP_CAPABILITIES, appData);
+ })
+ .then((peers) =>
+ {
+ if (!RECV)
+ return;
+
+ logger.debug('room.join() succeeded');
+
+ logger.debug('calling transport2 = room.createTransport("recv")');
+
+ transport2 = room.createTransport('recv', 'TRANSPORT_2');
+ window.transport2 = transport2;
+ window.pc2 = transport2._handler._pc;
+
+ handleTransport(transport2);
+
+ for (const peer of peers)
+ {
+ handlePeer(peer);
+ }
+ })
+ .then(() =>
+ {
+ if (!SEND)
+ return;
+
+ if (room.canSend('audio'))
+ logger.debug('can send audio');
+ else
+ logger.warn('cannot send audio');
+
+ if (room.canSend('video'))
+ logger.debug('can send video');
+ else
+ logger.warn('cannot send video');
+
+ logger.debug('calling transport1 = room.createTransport("send")');
+
+ transport1 = room.createTransport('send', 'TRANSPORT_1');
+ window.transport1 = transport1;
+ window.pc1 = transport1._handler._pc;
+
+ handleTransport(transport1);
+
+ logger.debug('calling getUserMedia()');
+
+ return navigator.mediaDevices
+ .getUserMedia({ audio: SEND_AUDIO, video: SEND_VIDEO });
+ })
+ .then((stream) =>
+ {
+ if (!SEND)
+ return;
+
+ audioTrack = stream.getAudioTracks()[0];
+ videoTrack = stream.getVideoTracks()[0];
+ window.audioTrack = audioTrack;
+ window.videoTrack = videoTrack;
+ })
+ // Add Producers.
+ .then(() =>
+ {
+ if (audioTrack)
+ {
+ const deviceId = audioTrack.getSettings().deviceId;
+
+ logger.debug('calling audioProducer1 = room.createProducer(audioTrack)');
+
+ try
+ {
+ audioProducer1 = room.createProducer(audioTrack, `${deviceId}-1`);
+ window.audioProducer1 = audioProducer1;
+
+ handleProducer(audioProducer1);
+ }
+ catch (error)
+ {
+ logger.error(error);
+ }
+
+ logger.debug('calling audioProducer2 = room.createProducer(audioTrack)');
+
+ try
+ {
+ audioProducer2 = room.createProducer(audioTrack, `${deviceId}-2`);
+ window.audioProducer2 = audioProducer2;
+
+ handleProducer(audioProducer2);
+ }
+ catch (error)
+ {
+ logger.error(error);
+ }
+ }
+
+ if (videoTrack)
+ {
+ const deviceId = videoTrack.getSettings().deviceId;
+
+ logger.debug('calling videoProducer = room.createProducer(videoTrack)');
+
+ try
+ {
+ videoProducer = room.createProducer(videoTrack, `${deviceId}-1`);
+ window.videoProducer = videoProducer;
+
+ handleProducer(videoProducer);
+ }
+ catch (error)
+ {
+ logger.error(error);
+ }
+ }
+ })
+ // Receive notifications.
+ .then(() =>
+ {
+ if (!RECV)
+ return;
+
+ setTimeout(() =>
+ {
+ room.receiveNotification(DATA.ALICE_WEBCAM_NEW_CONSUMER_NOTIFICATION);
+ }, 2000);
+ });
+}
+
+function handleTransport(transport)
+{
+ logger.warn(
+ 'handleTransport() [direction:%s, appData:"%s", transport:%o]',
+ transport.direction, transport.appData, transport);
+
+ transport.on('closed', (originator, appData) =>
+ {
+ logger.warn(
+ 'transport "closed" event [originator:%s, appData:%o, transport:%o]',
+ originator, appData, transport);
+ });
+
+ transport.on('connectionstatechange', (state) =>
+ {
+ logger.warn(
+ 'transport "connectionstatechange" event [direction:%s, state:%s, transport:%o]',
+ transport.direction, state, transport);
+ });
+
+ setInterval(() =>
+ {
+ const queue = transport._commandQueue._queue;
+
+ if (queue.length !== 0)
+ logger.error('queue not empty [transport:%o, queue:%o]', transport, queue);
+ }, 15000);
+}
+
+function handlePeer(peer)
+{
+ logger.warn('handlePeer() [name:"%s", peer:%o]', peer.name, peer);
+
+ switch (peer.name)
+ {
+ case 'alice':
+ window.alice = peer;
+ break;
+ case 'bob':
+ window.bob = peer;
+ break;
+ }
+
+ for (const consumer of peer.consumers)
+ {
+ handleConsumer(consumer);
+ }
+
+ peer.on('closed', (originator, appData) =>
+ {
+ logger.warn(
+ 'peer "closed" event [name:"%s", originator:%s, appData:%o]',
+ peer.name, originator, appData);
+ });
+
+ peer.on('newconsumer', (consumer) =>
+ {
+ logger.warn(
+ 'peer "newconsumer" event [name:"%s", id:%s, consumer:%o]',
+ peer.name, consumer.id, consumer);
+
+ handleConsumer(consumer);
+ });
+}
+
+function handleProducer(producer)
+{
+ const transport1 = window.transport1;
+
+ logger.debug(
+ 'handleProducer() [id:"%s", appData:%o, producer:%o]',
+ producer.id, producer.appData, producer);
+
+ logger.debug('handleProducer() | calling transport1.send(producer)');
+
+ transport1.send(producer)
+ .then(() =>
+ {
+ logger.debug('transport1.send(producer) succeeded');
+ })
+ .catch((error) =>
+ {
+ logger.error('transport1.send(producer) failed: %o', error);
+ });
+
+ producer.on('closed', (originator, appData) =>
+ {
+ logger.warn(
+ 'producer "closed" event [id:%s, originator:%s, appData:%o, producer:%o]',
+ producer.id, originator, appData, producer);
+ });
+
+ producer.on('paused', (originator, appData) =>
+ {
+ logger.warn(
+ 'producer "paused" event [id:%s, originator:%s, appData:%o, producer:%o]',
+ producer.id, originator, appData, producer);
+ });
+
+ producer.on('resumed', (originator, appData) =>
+ {
+ logger.warn(
+ 'producer "resumed" event [id:%s, originator:%s, appData:%o, producer:%o]',
+ producer.id, originator, appData, producer);
+ });
+
+ producer.on('unhandled', () =>
+ {
+ logger.warn(
+ 'producer "unhandled" event [id:%s, producer:%o]', producer.id, producer);
+ });
+}
+
+function handleConsumer(consumer)
+{
+ const transport2 = window.transport2;
+
+ logger.debug(
+ 'handleConsumer() [id:"%s", appData:%o, consumer:%o]',
+ consumer.id, consumer.appData, consumer);
+
+ switch (consumer.appData)
+ {
+ case 'ALICE_MIC':
+ window.aliceAudioConsumer = consumer;
+ break;
+ case 'ALICE_WEBCAM':
+ window.aliceVideoConsumer = consumer;
+ break;
+ case 'BOB_MIC':
+ window.bobAudioConsumer = consumer;
+ break;
+ }
+
+ logger.debug('handleConsumer() calling transport2.receive(consumer)');
+
+ transport2.receive(consumer)
+ .then((track) =>
+ {
+ logger.warn(
+ 'transport2.receive(consumer) succeeded [track:%o]', track);
+ })
+ .catch((error) =>
+ {
+ logger.error('transport2.receive() failed:%o', error);
+ });
+
+ consumer.on('closed', (originator, appData) =>
+ {
+ logger.warn(
+ 'consumer "closed" event [id:%s, originator:%s, appData:%o, consumer:%o]',
+ consumer.id, originator, appData, consumer);
+ });
+
+ consumer.on('paused', (originator, appData) =>
+ {
+ logger.warn(
+ 'consumer "paused" event [id:%s, originator:%s, appData:%o, consumer:%o]',
+ consumer.id, originator, appData, consumer);
+ });
+
+ consumer.on('resumed', (originator, appData) =>
+ {
+ logger.warn(
+ 'consumer "resumed" event [id:%s, originator:%s, appData:%o, consumer:%o]',
+ consumer.id, originator, appData, consumer);
+ });
+
+ consumer.on('unhandled', () =>
+ {
+ logger.warn(
+ 'consumer "unhandled" event [id:%s, consumer:%o]', consumer.id, consumer);
+ });
+}
+
+
+// NOTE: Trigger server notifications.
+
+window.notifyRoomClosed = function()
+{
+ const room = window.room;
+ const notification =
+ {
+ method : 'roomClosed',
+ notification : true,
+ appData : 'ha cascao la room remota!!!'
+ };
+
+ room.receiveNotification(notification);
+};
+
+window.notifyTransportClosed = function()
+{
+ const room = window.room;
+ const notification =
+ {
+ method : 'transportClosed',
+ notification : true,
+ id : room.transports[0].id,
+ appData : 'admin closed your transport'
+ };
+
+ room.receiveNotification(notification);
+};
+
+window.notifyAudioProducer1Closed = function()
+{
+ const room = window.room;
+ const notification =
+ {
+ method : 'producerClosed',
+ notification : true,
+ id : window.audioProducer1.id,
+ appData : 'te paro el micro por la fuerza'
+ };
+
+ room.receiveNotification(notification);
+};
+
+window.notifyAudioProducer1Paused = function()
+{
+ const room = window.room;
+ const notification =
+ {
+ method : 'producerPaused',
+ notification : true,
+ id : window.audioProducer1.id,
+ appData : 'te pause el micro por la fuerza'
+ };
+
+ room.receiveNotification(notification);
+};
+
+window.notifyAudioProducer1Resumed = function()
+{
+ const room = window.room;
+ const notification =
+ {
+ method : 'producerResumed',
+ notification : true,
+ id : window.audioProducer1.id,
+ appData : 'te resumo el micro'
+ };
+
+ room.receiveNotification(notification);
+};
+
+window.notifyAlicePeerClosed = function()
+{
+ const room = window.room;
+ const notification =
+ {
+ method : 'peerClosed',
+ notification : true,
+ name : 'alice',
+ appData : 'peer left'
+ };
+
+ room.receiveNotification(notification);
+};
+
+window.notifyAliceAudioConsumerClosed = function()
+{
+ const room = window.room;
+ const notification =
+ {
+ method : 'consumerClosed',
+ notification : true,
+ peerName : 'alice',
+ id : 3333,
+ appData : 'mic broken'
+ };
+
+ room.receiveNotification(notification);
+};
+
+window.notifyAliceVideoConsumerClosed = function()
+{
+ const room = window.room;
+ const notification =
+ {
+ method : 'consumerClosed',
+ notification : true,
+ peerName : 'alice',
+ id : 4444,
+ appData : 'webcam broken'
+ };
+
+ room.receiveNotification(notification);
+};
+
+window.notifyAliceVideoConsumerPaused = function()
+{
+ const room = window.room;
+ const notification =
+ {
+ method : 'consumerPaused',
+ notification : true,
+ peerName : 'alice',
+ id : 4444,
+ appData : 'webcam paused'
+ };
+
+ room.receiveNotification(notification);
+};
+
+window.notifyAliceVideoConsumerResumed = function()
+{
+ const room = window.room;
+ const notification =
+ {
+ method : 'consumerResumed',
+ notification : true,
+ peerName : 'alice',
+ id : 4444,
+ appData : 'webcam resumed'
+ };
+
+ room.receiveNotification(notification);
+};
+
+
+// NOTE: Test pause/resume.
+
+window.testPauseResume = function()
+{
+ logger.debug('testPauseResume() with audioProducer1');
+
+ const producer = window.audioProducer1;
+
+ // producer.once('paused', () =>
+ // {
+ // producer.resume('I RESUME TO FUACK!!!');
+ // });
+
+ logger.debug('testPauseResume() | (1) calling producer.pause()');
+
+ if (producer.pause('I PAUSE (1)'))
+ {
+ logger.warn(
+ 'testPauseResume() | (1) producer.pause() succeeded [locallyPaused:%s]',
+ producer.locallyPaused);
+ }
+ else
+ {
+ logger.error(
+ 'testPauseResume() | (1) producer.pause() failed [locallyPaused:%s]',
+ producer.locallyPaused);
+ }
+
+ logger.debug('testPauseResume() | (2) calling producer.pause()');
+
+ if (producer.pause('I PAUSE (2)'))
+ {
+ logger.warn(
+ 'testPauseResume() | (2) producer.pause() succeeded [locallyPaused:%s]',
+ producer.locallyPaused);
+ }
+ else
+ {
+ logger.error(
+ 'testPauseResume() | (2) producer.pause() failed [locallyPaused:%s]',
+ producer.locallyPaused);
+ }
+
+ logger.debug('testPauseResume() | (3) calling producer.resume()');
+
+ if (producer.resume('I RESUME (3)'))
+ {
+ logger.warn(
+ 'testPauseResume() | (3) producer.resume() succeeded [locallyPaused:%s]',
+ producer.locallyPaused);
+ }
+ else
+ {
+ logger.error(
+ 'testPauseResume() | (3) producer.resume() failed [locallyPaused:%s]',
+ producer.locallyPaused);
+ }
+};
+
+
+// NOTE: For debugging.
+
+window.dump1 = function()
+{
+ const transport1 = window.transport1;
+ const pc1 = transport1._handler._pc;
+
+ if (pc1 && pc1.localDescription)
+ logger.warn('PC1 SEND LOCAL OFFER:\n%s', pc1.localDescription.sdp);
+
+ if (pc1 && pc1.remoteDescription)
+ logger.warn('PC1 SEND REMOTE ANSWER:\n%s', pc1.remoteDescription.sdp);
+};
+
+window.dump2 = function()
+{
+ const transport2 = window.transport2;
+ const pc2 = transport2._handler._pc;
+
+ if (pc2 && pc2.remoteDescription)
+ logger.warn('PC2 RECV REMOTE OFFER:\n%s', pc2.remoteDescription.sdp);
+
+ if (pc2 && pc2.localDescription)
+ logger.warn('PC2 RECV LOCAL ANSWER:\n%s', pc2.localDescription.sdp);
+};
diff --git a/app/test/output/index.html b/app/test/output/index.html
new file mode 100644
index 0000000..7fba1d4
--- /dev/null
+++ b/app/test/output/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+ mediasoup-client test
+
+
+
+
+
+
+
+
+ mediasoup-client test
+
+
diff --git a/app/test/output/mediasoup-client-test.js b/app/test/output/mediasoup-client-test.js
new file mode 100644
index 0000000..d50e1fb
--- /dev/null
+++ b/app/test/output/mediasoup-client-test.js
@@ -0,0 +1,14243 @@
+(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o}
+ _this._queue = [];
+ return _this;
+ }
+
+ (0, _createClass3.default)(CommandQueue, [{
+ key: 'close',
+ value: function close() {
+ this._closed = true;
+ }
+ }, {
+ key: 'push',
+ value: function push(method, data) {
+ var _this2 = this;
+
+ var command = (0, _extends3.default)({ method: method }, data);
+
+ logger.debug('push() [method:%s]', method);
+
+ return new _promise2.default(function (resolve, reject) {
+ var queue = _this2._queue;
+
+ command.resolve = resolve;
+ command.reject = reject;
+
+ // Append command to the queue.
+ queue.push(command);
+ _this2._handlePendingCommands();
+ });
+ }
+ }, {
+ key: '_handlePendingCommands',
+ value: function _handlePendingCommands() {
+ var _this3 = this;
+
+ if (this._busy) return;
+
+ var queue = this._queue;
+
+ // Take the first command.
+ var command = queue[0];
+
+ if (!command) return;
+
+ this._busy = true;
+
+ // Execute it.
+ this._handleCommand(command).then(function () {
+ _this3._busy = false;
+
+ // Remove the first command (the completed one) from the queue.
+ queue.shift();
+
+ // And continue.
+ _this3._handlePendingCommands();
+ });
+ }
+ }, {
+ key: '_handleCommand',
+ value: function _handleCommand(command) {
+ var _this4 = this;
+
+ logger.debug('_handleCommand() [method:%s]', command.method);
+
+ if (this._closed) {
+ command.reject(new _errors.InvalidStateError('closed'));
+
+ return _promise2.default.resolve();
+ }
+
+ var promiseHolder = { promise: null };
+
+ this.emit('exec', command, promiseHolder);
+
+ return _promise2.default.resolve().then(function () {
+ return promiseHolder.promise;
+ }).then(function (result) {
+ logger.debug('_handleCommand() | command succeeded [method:%s]', command.method);
+
+ if (_this4._closed) {
+ command.reject(new _errors.InvalidStateError('closed'));
+
+ return;
+ }
+
+ // Resolve the command with the given result (if any).
+ command.resolve(result);
+ }).catch(function (error) {
+ logger.error('_handleCommand() | command failed [method:%s]: %o', command.method, error);
+
+ // Reject the command with the error.
+ command.reject(error);
+ });
+ }
+ }]);
+ return CommandQueue;
+}(_events.EventEmitter);
+
+exports.default = CommandQueue;
+
+},{"./Logger":"/Users/ibc/src/mediasoup-client/lib/Logger.js","./errors":"/Users/ibc/src/mediasoup-client/lib/errors.js","babel-runtime/core-js/object/get-prototype-of":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/object/get-prototype-of.js","babel-runtime/core-js/promise":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/promise.js","babel-runtime/helpers/classCallCheck":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/classCallCheck.js","babel-runtime/helpers/createClass":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/createClass.js","babel-runtime/helpers/extends":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/extends.js","babel-runtime/helpers/inherits":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/inherits.js","babel-runtime/helpers/possibleConstructorReturn":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/possibleConstructorReturn.js","events":"/Users/ibc/src/mediasoup-demo-2/app/node_modules/events/events.js"}],"/Users/ibc/src/mediasoup-client/lib/Consumer.js":[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
+
+var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
+
+var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _createClass2 = require('babel-runtime/helpers/createClass');
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require('babel-runtime/helpers/inherits');
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _Logger = require('./Logger');
+
+var _Logger2 = _interopRequireDefault(_Logger);
+
+var _EnhancedEventEmitter2 = require('./EnhancedEventEmitter');
+
+var _EnhancedEventEmitter3 = _interopRequireDefault(_EnhancedEventEmitter2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var logger = new _Logger2.default('Consumer');
+
+var Consumer = function (_EnhancedEventEmitter) {
+ (0, _inherits3.default)(Consumer, _EnhancedEventEmitter);
+
+ /**
+ * @private
+ *
+ * @emits {originator: String, [appData]: Any} paused
+ * @emits {originator: String, [appData]: Any} resumed
+ * @emits unhandled
+ * @emits {originator: String, [appData]: Any} closed
+ *
+ * @emits {[appData]: Any} @pause
+ * @emits {[appData]: Any} @resume
+ * @emits {originator: String} @close
+ */
+ function Consumer(id, kind, rtpParameters, peer, appData) {
+ (0, _classCallCheck3.default)(this, Consumer);
+
+ // Id.
+ // @type {Number}
+ var _this = (0, _possibleConstructorReturn3.default)(this, (Consumer.__proto__ || (0, _getPrototypeOf2.default)(Consumer)).call(this));
+
+ _this._id = id;
+
+ // Closed flag.
+ // @type {Boolean}
+ _this._closed = false;
+
+ // Media kind.
+ // @type {String}
+ _this._kind = kind;
+
+ // RTP parameters.
+ // @type {RTCRtpParameters}
+ _this._rtpParameters = rtpParameters;
+
+ // Associated Peer.
+ // @type {Peer}
+ _this._peer = peer;
+
+ // App custom data.
+ // @type {Any}
+ _this._appData = appData;
+
+ // Whether we can receive this Consumer (based on our RTP capabilities).
+ // @type {Boolean}
+ _this._supported = false;
+
+ // Whether this Consumer is being handled by a Transport.
+ // @type {Boolean}
+ _this._handled = false;
+
+ // Remote track.
+ // @type {MediaStreamTrack}
+ _this._track = null;
+
+ // Locally paused flag.
+ // @type {Boolean}
+ _this._locallyPaused = false;
+
+ // Remotely paused flag.
+ // @type {Boolean}
+ _this._remotelyPaused = false;
+ return _this;
+ }
+
+ /**
+ * Class name.
+ *
+ * @return {String}
+ */
+
+
+ (0, _createClass3.default)(Consumer, [{
+ key: 'close',
+
+
+ /**
+ * Closes the Consumer.
+ * This is called when the local Room is closed.
+ *
+ * @private
+ */
+ value: function close() {
+ logger.debug('close()');
+
+ if (this._closed) return;
+
+ this._closed = true;
+
+ this.emit('@close', 'local');
+ this.safeEmit('closed', 'local');
+
+ this._destroy();
+ }
+
+ /**
+ * My remote Consumer was closed.
+ * Invoked via remote notification.
+ *
+ * @private
+ *
+ * @param {Any} [appData] - App custom data.
+ */
+
+ }, {
+ key: 'remoteClose',
+ value: function remoteClose(appData) {
+ logger.debug('remoteClose()');
+
+ if (this._closed) return;
+
+ this._closed = true;
+
+ this.emit('@close', 'remote');
+ this.safeEmit('closed', 'remote', appData);
+
+ this._destroy();
+ }
+ }, {
+ key: '_destroy',
+ value: function _destroy() {
+ this._handled = false;
+
+ try {
+ this._track.stop();
+ } catch (error) {}
+
+ this._track = null;
+ }
+
+ /**
+ * Pauses receiving media.
+ *
+ * @param {Any} [appData] - App custom data.
+ *
+ * @return {Boolean} true if paused.
+ */
+
+ }, {
+ key: 'pause',
+ value: function pause(appData) {
+ logger.debug('pause()');
+
+ if (this._closed) {
+ logger.error('pause() | Consumer closed');
+
+ return false;
+ } else if (!this._handled) {
+ logger.error('pause() | Consumer not handled');
+
+ return false;
+ } else if (this._locallyPaused) {
+ return true;
+ }
+
+ this._locallyPaused = true;
+ this._track.enabled = false;
+
+ this.emit('@pause', appData);
+
+ if (!this._remotelyPaused) this.safeEmit('paused', 'local', appData);
+
+ // Return true if really paused.
+ return this.paused;
+ }
+
+ /**
+ * My remote Consumer was paused.
+ * Invoked via remote notification.
+ *
+ * @private
+ *
+ * @param {Any} [appData] - App custom data.
+ */
+
+ }, {
+ key: 'remotePause',
+ value: function remotePause(appData) {
+ logger.debug('remotePause()');
+
+ if (this._closed || this._remotelyPaused) return;
+
+ this._remotelyPaused = true;
+
+ if (this._track) this._track.enabled = false;
+
+ if (!this._locallyPaused) this.safeEmit('paused', 'remote', appData);
+ }
+
+ /**
+ * Resumes receiving media.
+ *
+ * @param {Any} [appData] - App custom data.
+ *
+ * @return {Boolean} true if not paused.
+ */
+
+ }, {
+ key: 'resume',
+ value: function resume(appData) {
+ logger.debug('resume()');
+
+ if (this._closed) {
+ logger.error('resume() | Consumer closed');
+
+ return false;
+ } else if (!this._handled) {
+ logger.error('pause() | Consumer not handled');
+
+ return false;
+ } else if (!this._locallyPaused) {
+ return true;
+ }
+
+ this._locallyPaused = false;
+
+ this.emit('@resume', appData);
+
+ if (!this._remotelyPaused) {
+ this._track.enabled = true;
+
+ this.safeEmit('resumed', 'local', appData);
+ }
+
+ // Return true if not paused.
+ return !this.paused;
+ }
+
+ /**
+ * My remote Consumer was resumed.
+ * Invoked via remote notification.
+ *
+ * @private
+ *
+ * @param {Any} [appData] - App custom data.
+ */
+
+ }, {
+ key: 'remoteResume',
+ value: function remoteResume(appData) {
+ logger.debug('remoteResume()');
+
+ if (this._closed || !this._remotelyPaused) return;
+
+ this._remotelyPaused = false;
+
+ if (!this._locallyPaused) {
+ if (this._track) this._track.enabled = false;
+
+ this.safeEmit('resumed', 'remote', appData);
+ }
+ }
+
+ /**
+ * Mark this Consumer as suitable for reception or not.
+ *
+ * @private
+ *
+ * @param {Boolean} flag
+ */
+
+ }, {
+ key: 'setSupported',
+ value: function setSupported(flag) {
+ this._supported = flag;
+ }
+
+ /**
+ * Set this Consumer as handled or unhandled by a Transport.
+ *
+ * @private
+ *
+ * @param {Boolean|String} flag - If 'tmp' (String) it's considered as termporal.
+ * @param {track} MediaStreamTrack
+ */
+
+ }, {
+ key: 'setHandled',
+ value: function setHandled(flag, track) {
+ if (this._closed) return;
+
+ var previous = this._handled;
+
+ this._handled = flag;
+ this._track = track || null;
+
+ if (track && this.paused) this._track.enabled = false;
+
+ if (flag === false || flag === 'tmp') {
+ try {
+ this._track.stop();
+ } catch (error) {}
+
+ this._track = null;
+ }
+
+ if (previous === true && flag === false) this.safeEmit('unhandled');
+ }
+ }, {
+ key: 'klass',
+ get: function get() {
+ return 'Consumer';
+ }
+
+ /**
+ * Consumer id.
+ *
+ * @return {Number}
+ */
+
+ }, {
+ key: 'id',
+ get: function get() {
+ return this._id;
+ }
+
+ /**
+ * Whether the Consumer is closed.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'closed',
+ get: function get() {
+ return this._closed;
+ }
+
+ /**
+ * Media kind.
+ *
+ * @return {String}
+ */
+
+ }, {
+ key: 'kind',
+ get: function get() {
+ return this._kind;
+ }
+
+ /**
+ * RTP parameters.
+ *
+ * @return {RTCRtpParameters}
+ */
+
+ }, {
+ key: 'rtpParameters',
+ get: function get() {
+ return this._rtpParameters;
+ }
+
+ /**
+ * Associated Peer.
+ *
+ * @return {Peer}
+ */
+
+ }, {
+ key: 'peer',
+ get: function get() {
+ return this._peer;
+ }
+
+ /**
+ * App custom data.
+ *
+ * @return {Any}
+ */
+
+ }, {
+ key: 'appData',
+ get: function get() {
+ return this._appData;
+ }
+
+ /**
+ * Whether we can receive this Consumer (based on our RTP capabilities).
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'supported',
+ get: function get() {
+ return this._supported;
+ }
+
+ /**
+ * Whether this is being handled by a Transport.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'handled',
+ get: function get() {
+ return Boolean(this._handled);
+ }
+
+ /**
+ * The associated track (if any yet).
+ *
+ * @return {MediaStreamTrack|Null}
+ */
+
+ }, {
+ key: 'track',
+ get: function get() {
+ return this._track;
+ }
+
+ /**
+ * Whether the Consumer is locally paused.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'locallyPaused',
+ get: function get() {
+ return this._locallyPaused;
+ }
+
+ /**
+ * Whether the Consumer is remotely paused.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'remotelyPaused',
+ get: function get() {
+ return this._remotelyPaused;
+ }
+
+ /**
+ * Whether the Consumer is paused.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'paused',
+ get: function get() {
+ return this._locallyPaused || this._remotelyPaused;
+ }
+
+ /**
+ * Whether the Consumer is actually receiving media.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'active',
+ get: function get() {
+ return !this._closed && this.handled === true && !this.paused;
+ }
+ }]);
+ return Consumer;
+}(_EnhancedEventEmitter3.default);
+
+exports.default = Consumer;
+
+},{"./EnhancedEventEmitter":"/Users/ibc/src/mediasoup-client/lib/EnhancedEventEmitter.js","./Logger":"/Users/ibc/src/mediasoup-client/lib/Logger.js","babel-runtime/core-js/object/get-prototype-of":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/object/get-prototype-of.js","babel-runtime/helpers/classCallCheck":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/classCallCheck.js","babel-runtime/helpers/createClass":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/createClass.js","babel-runtime/helpers/inherits":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/inherits.js","babel-runtime/helpers/possibleConstructorReturn":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/possibleConstructorReturn.js"}],"/Users/ibc/src/mediasoup-client/lib/Device.js":[function(require,module,exports){
+(function (global){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _createClass2 = require('babel-runtime/helpers/createClass');
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _bowser = require('bowser');
+
+var _bowser2 = _interopRequireDefault(_bowser);
+
+var _Logger = require('./Logger');
+
+var _Logger2 = _interopRequireDefault(_Logger);
+
+var _Chrome = require('./handlers/Chrome55');
+
+var _Chrome2 = _interopRequireDefault(_Chrome);
+
+var _Safari = require('./handlers/Safari11');
+
+var _Safari2 = _interopRequireDefault(_Safari);
+
+var _Firefox = require('./handlers/Firefox50');
+
+var _Firefox2 = _interopRequireDefault(_Firefox);
+
+var _Edge = require('./handlers/Edge11');
+
+var _Edge2 = _interopRequireDefault(_Edge);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var logger = new _Logger2.default('Device');
+
+/**
+ * Class with static members representing the underlying device or browser.
+ */
+
+var Device = function () {
+ function Device() {
+ (0, _classCallCheck3.default)(this, Device);
+ }
+
+ (0, _createClass3.default)(Device, null, [{
+ key: 'isSupported',
+
+
+ /**
+ * Whether this device is supported.
+ *
+ * @return {Boolean}
+ */
+ value: function isSupported() {
+ if (!Device._detected) Device._detect();
+
+ return Boolean(Device._handlerClass);
+ }
+
+ /**
+ * Returns a suitable WebRTC handler class.
+ *
+ * @type {Class}
+ */
+
+ }, {
+ key: '_detect',
+
+
+ /**
+ * Detects the current device/browser.
+ *
+ * @private
+ */
+ value: function _detect() {
+ var ua = global.navigator.userAgent;
+ var browser = _bowser2.default._detect(ua);
+
+ Device._detected = true;
+ Device._name = browser.name || 'unknown device';
+ Device._version = browser.version || 'unknown vesion';
+ Device._handlerClass = null;
+
+ // Chrome, Chromium, Opera (desktop and mobile).
+ if (_bowser2.default.check({ chrome: '55', chromium: '55', opera: '44' }, true, ua)) {
+ Device._handlerClass = _Chrome2.default;
+ }
+ // Safari (desktop and mobile).
+ else if (_bowser2.default.check({ safari: '11' }, true, ua)) {
+ Device._handlerClass = _Safari2.default;
+ }
+ // Firefox (desktop and mobile).
+ else if (_bowser2.default.check({ firefox: '50' }, true, ua)) {
+ Device._handlerClass = _Firefox2.default;
+ }
+ // Edge (desktop).
+ else if (_bowser2.default.check({ msedge: '11' }, true, ua)) {
+ Device._handlerClass = _Edge2.default;
+ }
+
+ // TODO: More devices.
+
+ if (Device.isSupported()) {
+ logger.debug('device supported [name:%s, version:%s, handler:%s]', Device._name, Device._version, Device._handlerClass.name);
+ } else {
+ logger.warn('device not supported [name:%s, version:%s]', Device._name, Device._version);
+ }
+ }
+ }, {
+ key: 'name',
+
+ /**
+ * Get the device name.
+ *
+ * @return {String}
+ */
+ get: function get() {
+ if (!Device._detected) Device._detect();
+
+ return Device._name;
+ }
+
+ /**
+ * Get the device version.
+ *
+ * @return {String}
+ */
+
+ }, {
+ key: 'version',
+ get: function get() {
+ if (!Device._detected) Device._detect();
+
+ return Device._version;
+ }
+ }, {
+ key: 'Handler',
+ get: function get() {
+ if (!Device._detected) Device._detect();
+
+ return Device._handlerClass;
+ }
+ }]);
+ return Device;
+}();
+
+// Initialized flag.
+// @type {Boolean}
+
+
+exports.default = Device;
+Device._detected = false;
+
+// Device name.
+// @type {String}
+Device._name = undefined;
+
+// Device version.
+// @type {String}
+Device._version = undefined;
+
+// WebRTC hander for this device.
+// @type {Class}
+Device._handlerClass = null;
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{"./Logger":"/Users/ibc/src/mediasoup-client/lib/Logger.js","./handlers/Chrome55":"/Users/ibc/src/mediasoup-client/lib/handlers/Chrome55.js","./handlers/Edge11":"/Users/ibc/src/mediasoup-client/lib/handlers/Edge11.js","./handlers/Firefox50":"/Users/ibc/src/mediasoup-client/lib/handlers/Firefox50.js","./handlers/Safari11":"/Users/ibc/src/mediasoup-client/lib/handlers/Safari11.js","babel-runtime/helpers/classCallCheck":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/classCallCheck.js","babel-runtime/helpers/createClass":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/createClass.js","bowser":"/Users/ibc/src/mediasoup-client/node_modules/bowser/src/bowser.js"}],"/Users/ibc/src/mediasoup-client/lib/EnhancedEventEmitter.js":[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _promise = require('babel-runtime/core-js/promise');
+
+var _promise2 = _interopRequireDefault(_promise);
+
+var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
+
+var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
+
+var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _createClass2 = require('babel-runtime/helpers/createClass');
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require('babel-runtime/helpers/inherits');
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _events = require('events');
+
+var _Logger = require('./Logger');
+
+var _Logger2 = _interopRequireDefault(_Logger);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var logger = new _Logger2.default('EnhancedEventEmitter');
+
+var EnhancedEventEmitter = function (_EventEmitter) {
+ (0, _inherits3.default)(EnhancedEventEmitter, _EventEmitter);
+
+ function EnhancedEventEmitter() {
+ (0, _classCallCheck3.default)(this, EnhancedEventEmitter);
+
+ var _this = (0, _possibleConstructorReturn3.default)(this, (EnhancedEventEmitter.__proto__ || (0, _getPrototypeOf2.default)(EnhancedEventEmitter)).call(this));
+
+ _this.setMaxListeners(Infinity);
+ return _this;
+ }
+
+ (0, _createClass3.default)(EnhancedEventEmitter, [{
+ key: 'safeEmit',
+ value: function safeEmit(event) {
+ try {
+ for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ args[_key - 1] = arguments[_key];
+ }
+
+ this.emit.apply(this, [event].concat(args));
+ } catch (error) {
+ logger.error('event listener threw an error [event:%s]: %o', event, error);
+ }
+ }
+ }, {
+ key: 'safeEmitAsPromise',
+ value: function safeEmitAsPromise() {
+ var _this2 = this;
+
+ for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+ args[_key2] = arguments[_key2];
+ }
+
+ return new _promise2.default(function (resolve, reject) {
+ var callback = function callback(result) {
+ resolve(result);
+ };
+
+ var errback = function errback(error) {
+ reject(error);
+ };
+
+ _this2.safeEmit.apply(_this2, args.concat([callback, errback]));
+ });
+ }
+ }]);
+ return EnhancedEventEmitter;
+}(_events.EventEmitter);
+
+exports.default = EnhancedEventEmitter;
+
+},{"./Logger":"/Users/ibc/src/mediasoup-client/lib/Logger.js","babel-runtime/core-js/object/get-prototype-of":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/object/get-prototype-of.js","babel-runtime/core-js/promise":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/promise.js","babel-runtime/helpers/classCallCheck":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/classCallCheck.js","babel-runtime/helpers/createClass":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/createClass.js","babel-runtime/helpers/inherits":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/inherits.js","babel-runtime/helpers/possibleConstructorReturn":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/possibleConstructorReturn.js","events":"/Users/ibc/src/mediasoup-demo-2/app/node_modules/events/events.js"}],"/Users/ibc/src/mediasoup-client/lib/Logger.js":[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _createClass2 = require('babel-runtime/helpers/createClass');
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _debug = require('debug');
+
+var _debug2 = _interopRequireDefault(_debug);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var APP_NAME = 'mediasoup-client';
+
+var Logger = function () {
+ function Logger(prefix) {
+ (0, _classCallCheck3.default)(this, Logger);
+
+ if (prefix) {
+ this._debug = (0, _debug2.default)(APP_NAME + ':' + prefix);
+ this._warn = (0, _debug2.default)(APP_NAME + ':WARN:' + prefix);
+ this._error = (0, _debug2.default)(APP_NAME + ':ERROR:' + prefix);
+ } else {
+ this._debug = (0, _debug2.default)(APP_NAME);
+ this._warn = (0, _debug2.default)(APP_NAME + ':WARN');
+ this._error = (0, _debug2.default)(APP_NAME + ':ERROR');
+ }
+
+ /* eslint-disable no-console */
+ this._debug.log = console.info.bind(console);
+ this._warn.log = console.warn.bind(console);
+ this._error.log = console.error.bind(console);
+ /* eslint-enable no-console */
+ }
+
+ (0, _createClass3.default)(Logger, [{
+ key: 'debug',
+ get: function get() {
+ return this._debug;
+ }
+ }, {
+ key: 'warn',
+ get: function get() {
+ return this._warn;
+ }
+ }, {
+ key: 'error',
+ get: function get() {
+ return this._error;
+ }
+ }]);
+ return Logger;
+}();
+
+exports.default = Logger;
+
+},{"babel-runtime/helpers/classCallCheck":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/classCallCheck.js","babel-runtime/helpers/createClass":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/createClass.js","debug":"/Users/ibc/src/mediasoup-client/node_modules/debug/src/browser.js"}],"/Users/ibc/src/mediasoup-client/lib/Peer.js":[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _from = require('babel-runtime/core-js/array/from');
+
+var _from2 = _interopRequireDefault(_from);
+
+var _getIterator2 = require('babel-runtime/core-js/get-iterator');
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _map = require('babel-runtime/core-js/map');
+
+var _map2 = _interopRequireDefault(_map);
+
+var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
+
+var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
+
+var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _createClass2 = require('babel-runtime/helpers/createClass');
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require('babel-runtime/helpers/inherits');
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _Logger = require('./Logger');
+
+var _Logger2 = _interopRequireDefault(_Logger);
+
+var _EnhancedEventEmitter2 = require('./EnhancedEventEmitter');
+
+var _EnhancedEventEmitter3 = _interopRequireDefault(_EnhancedEventEmitter2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var logger = new _Logger2.default('Peer');
+
+var Peer = function (_EnhancedEventEmitter) {
+ (0, _inherits3.default)(Peer, _EnhancedEventEmitter);
+
+ /**
+ * @private
+ *
+ * @emits {consumer: Consumer} newconsumer
+ * @emits {originator: String, [appData]: Any} closed
+ * @emits {originator: String} @close
+ */
+ function Peer(name, appData) {
+ (0, _classCallCheck3.default)(this, Peer);
+
+ // Name.
+ // @type {String}
+ var _this = (0, _possibleConstructorReturn3.default)(this, (Peer.__proto__ || (0, _getPrototypeOf2.default)(Peer)).call(this));
+
+ _this._name = name;
+
+ // Closed flag.
+ // @type {Boolean}
+ _this._closed = false;
+
+ // App custom data.
+ // @type {Any}
+ _this._appData = appData;
+
+ // Map of Consumers indexed by id.
+ // @type {map}
+ _this._consumers = new _map2.default();
+ return _this;
+ }
+
+ /**
+ * Peer name.
+ *
+ * @return {String}
+ */
+
+
+ (0, _createClass3.default)(Peer, [{
+ key: 'close',
+
+
+ /**
+ * Closes the Peer.
+ * This is called when the local Room is closed.
+ *
+ * @private
+ */
+ value: function close() {
+ logger.debug('close()');
+
+ if (this._closed) return;
+
+ this._closed = true;
+
+ this.emit('@close', 'local');
+ this.safeEmit('closed', 'local');
+
+ // Close all the Consumers.
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = (0, _getIterator3.default)(this._consumers.values()), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var consumer = _step.value;
+
+ consumer.close();
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+ }
+
+ /**
+ * The remote Peer or Room was closed.
+ * Invoked via remote notification.
+ *
+ * @private
+ *
+ * @param {Any} [appData] - App custom data.
+ */
+
+ }, {
+ key: 'remoteClose',
+ value: function remoteClose(appData) {
+ logger.debug('remoteClose()');
+
+ if (this._closed) return;
+
+ this._closed = true;
+
+ this.emit('@close', 'remote');
+ this.safeEmit('closed', 'remote', appData);
+
+ // Close all the Consumers.
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = (0, _getIterator3.default)(this._consumers.values()), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var consumer = _step2.value;
+
+ consumer.remoteClose();
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+ }
+
+ /**
+ * Get the Consumer with the given id.
+ *
+ * @param {Number} id
+ *
+ * @return {Consumer}
+ */
+
+ }, {
+ key: 'getConsumerById',
+ value: function getConsumerById(id) {
+ return this._consumers.get(id);
+ }
+
+ /**
+ * Add an associated Consumer.
+ *
+ * @private
+ *
+ * @param {Consumer} consumer
+ */
+
+ }, {
+ key: 'addConsumer',
+ value: function addConsumer(consumer) {
+ var _this2 = this;
+
+ if (this._consumers.has(consumer.id)) throw new Error('Consumer already exists [id:' + consumer.id + ']');
+
+ // Store it.
+ this._consumers.set(consumer.id, consumer);
+
+ // Handle it.
+ consumer.on('@close', function () {
+ _this2._consumers.delete(consumer.id);
+ });
+
+ // Emit event.
+ this.safeEmit('newconsumer', consumer);
+ }
+ }, {
+ key: 'name',
+ get: function get() {
+ return this._name;
+ }
+
+ /**
+ * Whether the Peer is closed.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'closed',
+ get: function get() {
+ return this._closed;
+ }
+
+ /**
+ * App custom data.
+ *
+ * @return {Any}
+ */
+
+ }, {
+ key: 'appData',
+ get: function get() {
+ return this._appData;
+ }
+
+ /**
+ * The list of Consumers.
+ *
+ * @return {Array}
+ */
+
+ }, {
+ key: 'consumers',
+ get: function get() {
+ return (0, _from2.default)(this._consumers.values());
+ }
+ }]);
+ return Peer;
+}(_EnhancedEventEmitter3.default);
+
+exports.default = Peer;
+
+},{"./EnhancedEventEmitter":"/Users/ibc/src/mediasoup-client/lib/EnhancedEventEmitter.js","./Logger":"/Users/ibc/src/mediasoup-client/lib/Logger.js","babel-runtime/core-js/array/from":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/array/from.js","babel-runtime/core-js/get-iterator":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/get-iterator.js","babel-runtime/core-js/map":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/map.js","babel-runtime/core-js/object/get-prototype-of":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/object/get-prototype-of.js","babel-runtime/helpers/classCallCheck":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/classCallCheck.js","babel-runtime/helpers/createClass":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/createClass.js","babel-runtime/helpers/inherits":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/inherits.js","babel-runtime/helpers/possibleConstructorReturn":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/possibleConstructorReturn.js"}],"/Users/ibc/src/mediasoup-client/lib/Producer.js":[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
+
+var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
+
+var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _createClass2 = require('babel-runtime/helpers/createClass');
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require('babel-runtime/helpers/inherits');
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _Logger = require('./Logger');
+
+var _Logger2 = _interopRequireDefault(_Logger);
+
+var _EnhancedEventEmitter2 = require('./EnhancedEventEmitter');
+
+var _EnhancedEventEmitter3 = _interopRequireDefault(_EnhancedEventEmitter2);
+
+var _utils = require('./utils');
+
+var utils = _interopRequireWildcard(_utils);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var logger = new _Logger2.default('Producer');
+
+var Producer = function (_EnhancedEventEmitter) {
+ (0, _inherits3.default)(Producer, _EnhancedEventEmitter);
+
+ /**
+ * @private
+ *
+ * @emits {originator: String, [appData]: Any} paused
+ * @emits {originator: String, [appData]: Any} resumed
+ * @emits unhandled
+ * @emits {originator: String, [appData]: Any} closed
+ *
+ * @emits {[appData]: Any} @pause
+ * @emits {[appData]: Any} @resume
+ * @emits {originator: String, [appData]: Any} @close
+ *
+ */
+ function Producer(track, appData) {
+ (0, _classCallCheck3.default)(this, Producer);
+
+ // Id.
+ // @type {Number}
+ var _this = (0, _possibleConstructorReturn3.default)(this, (Producer.__proto__ || (0, _getPrototypeOf2.default)(Producer)).call(this));
+
+ _this._id = utils.randomNumber();
+
+ // Closed flag.
+ // @type {Boolean}
+ _this._closed = false;
+
+ // Original track.
+ // @type {MediaStreamTrack}
+ _this._originalTrack = track;
+
+ // Track cloned from the original one.
+ // @type {MediaStreamTrack}
+ _this._track = track.clone();
+
+ // App custom data.
+ // @type {Any}
+ _this._appData = appData;
+
+ // Whether this Producer is being handled by a Transport.
+ // @type {Boolean}
+ _this._handled = false;
+
+ // RTP parameters.
+ // @type {RTCRtpParameters}
+ _this._rtpParameters = null;
+
+ // Locally paused flag.
+ // @type {Boolean}
+ _this._locallyPaused = !_this._track.enabled;
+
+ // Remotely paused flag.
+ // @type {Boolean}
+ _this._remotelyPaused = false;
+ return _this;
+ }
+
+ /**
+ * Class name.
+ *
+ * @return {String}
+ */
+
+
+ (0, _createClass3.default)(Producer, [{
+ key: 'close',
+
+
+ /**
+ * Closes the Producer.
+ *
+ * @param {Any} [appData] - App custom data.
+ */
+ value: function close(appData) {
+ logger.debug('close()');
+
+ if (this._closed) return;
+
+ this._closed = true;
+
+ this.emit('@close', 'local', appData);
+ this.safeEmit('closed', 'local', appData);
+
+ this._destroy();
+ }
+
+ /**
+ * My remote Producer was closed.
+ * Invoked via remote notification.
+ *
+ * @private
+ *
+ * @param {Any} [appData] - App custom data.
+ */
+
+ }, {
+ key: 'remoteClose',
+ value: function remoteClose(appData) {
+ logger.debug('remoteClose()');
+
+ if (this._closed) return;
+
+ this._closed = true;
+
+ this.emit('@close', 'remote', appData);
+ this.safeEmit('closed', 'remote', appData);
+
+ this._destroy();
+ }
+ }, {
+ key: '_destroy',
+ value: function _destroy() {
+ this._closed = true;
+ this._handled = false;
+ this._rtpParameters = null;
+
+ try {
+ this._track.stop();
+ } catch (error) {}
+ }
+
+ /**
+ * Pauses sending media.
+ *
+ * @param {Any} [appData] - App custom data.
+ *
+ * @return {Boolean} true if paused.
+ */
+
+ }, {
+ key: 'pause',
+ value: function pause(appData) {
+ logger.debug('pause()');
+
+ if (this._closed) {
+ logger.error('pause() | Producer closed');
+
+ return false;
+ } else if (!this._handled) {
+ logger.error('pause() | Producer not handled');
+
+ return false;
+ } else if (this._locallyPaused) {
+ return true;
+ }
+
+ this._locallyPaused = true;
+ this._track.enabled = false;
+
+ this.emit('@pause', appData);
+
+ if (!this._remotelyPaused) this.safeEmit('paused', 'local', appData);
+
+ // Return true if really paused.
+ return this.paused;
+ }
+
+ /**
+ * My remote Producer was paused.
+ * Invoked via remote notification.
+ *
+ * @private
+ *
+ * @param {Any} [appData] - App custom data.
+ */
+
+ }, {
+ key: 'remotePause',
+ value: function remotePause(appData) {
+ logger.debug('remotePause()');
+
+ if (this._closed || !this._handled || this._remotelyPaused) return;
+
+ this._remotelyPaused = true;
+ this._track.enabled = false;
+
+ if (!this._locallyPaused) this.safeEmit('paused', 'remote', appData);
+ }
+
+ /**
+ * Resumes sending media.
+ *
+ * @param {Any} [appData] - App custom data.
+ *
+ * @return {Boolean} true if not paused.
+ */
+
+ }, {
+ key: 'resume',
+ value: function resume(appData) {
+ logger.debug('resume()');
+
+ if (this._closed) {
+ logger.error('resume() | Producer closed');
+
+ return false;
+ } else if (!this._handled) {
+ logger.error('pause() | Producer not handled');
+
+ return false;
+ } else if (!this._locallyPaused) {
+ return true;
+ }
+
+ this._locallyPaused = false;
+
+ this.emit('@resume', appData);
+
+ if (!this._remotelyPaused) {
+ this._track.enabled = true;
+
+ this.safeEmit('resumed', 'local', appData);
+ }
+
+ // Return true if not paused.
+ return !this.paused;
+ }
+
+ /**
+ * My remote Producer was resumed.
+ * Invoked via remote notification.
+ *
+ * @private
+ *
+ * @param {Any} [appData] - App custom data.
+ */
+
+ }, {
+ key: 'remoteResume',
+ value: function remoteResume(appData) {
+ logger.debug('remoteResume()');
+
+ if (this._closed || !this._handled || !this._remotelyPaused) return;
+
+ this._remotelyPaused = false;
+
+ if (!this._locallyPaused) {
+ this._track.enabled = true;
+
+ this.safeEmit('resumed', 'remote', appData);
+ }
+ }
+
+ /**
+ * Set this Producer as handled or unhandled by a Transport.
+ *
+ * @private
+ *
+ * @param {Boolean|String} flag - If 'tmp' (String) it's considered as termporal.
+ * @param {RTCRtpParameters} rtpParameters
+ */
+
+ }, {
+ key: 'setHandled',
+ value: function setHandled(flag, rtpParameters) {
+ if (this._closed) return;
+
+ var previous = this._handled;
+
+ this._handled = flag;
+ this._rtpParameters = rtpParameters;
+
+ if (flag === false || flag === 'tmp') this._rtpParameters = null;
+
+ if (previous === true && flag === false) this.safeEmit('unhandled');
+ }
+ }, {
+ key: 'klass',
+ get: function get() {
+ return 'Producer';
+ }
+
+ /**
+ * Producer id.
+ *
+ * @return {Number}
+ */
+
+ }, {
+ key: 'id',
+ get: function get() {
+ return this._id;
+ }
+
+ /**
+ * Whether the Producer is closed.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'closed',
+ get: function get() {
+ return this._closed;
+ }
+
+ /**
+ * Media kind.
+ *
+ * @return {String}
+ */
+
+ }, {
+ key: 'kind',
+ get: function get() {
+ return this._track.kind;
+ }
+
+ /**
+ * The associated track.
+ *
+ * @return {MediaStreamTrack}
+ */
+
+ }, {
+ key: 'track',
+ get: function get() {
+ return this._track;
+ }
+
+ /**
+ * The associated original track.
+ *
+ * @return {MediaStreamTrack}
+ */
+
+ }, {
+ key: 'originalTrack',
+ get: function get() {
+ return this._originalTrack;
+ }
+
+ /**
+ * App custom data.
+ *
+ * @return {Any}
+ */
+
+ }, {
+ key: 'appData',
+ get: function get() {
+ return this._appData;
+ }
+
+ /**
+ * Whether this is being handled by a Transport.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'handled',
+ get: function get() {
+ return Boolean(this._handled);
+ }
+
+ /**
+ * RTP parameters.
+ *
+ * @return {RTCRtpParameters}
+ */
+
+ }, {
+ key: 'rtpParameters',
+ get: function get() {
+ return this._rtpParameters;
+ }
+
+ /**
+ * Whether the Producer is locally paused.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'locallyPaused',
+ get: function get() {
+ return this._locallyPaused;
+ }
+
+ /**
+ * Whether the Producer is remotely paused.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'remotelyPaused',
+ get: function get() {
+ return this._remotelyPaused;
+ }
+
+ /**
+ * Whether the Producer is paused.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'paused',
+ get: function get() {
+ return this._locallyPaused || this._remotelyPaused;
+ }
+
+ /**
+ * Whether the Producer is actually sending media.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'active',
+ get: function get() {
+ return !this._closed && this.handled === true && !this.paused;
+ }
+ }]);
+ return Producer;
+}(_EnhancedEventEmitter3.default);
+
+exports.default = Producer;
+
+},{"./EnhancedEventEmitter":"/Users/ibc/src/mediasoup-client/lib/EnhancedEventEmitter.js","./Logger":"/Users/ibc/src/mediasoup-client/lib/Logger.js","./utils":"/Users/ibc/src/mediasoup-client/lib/utils.js","babel-runtime/core-js/object/get-prototype-of":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/object/get-prototype-of.js","babel-runtime/helpers/classCallCheck":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/classCallCheck.js","babel-runtime/helpers/createClass":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/createClass.js","babel-runtime/helpers/inherits":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/inherits.js","babel-runtime/helpers/possibleConstructorReturn":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/possibleConstructorReturn.js"}],"/Users/ibc/src/mediasoup-client/lib/Room.js":[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _from = require('babel-runtime/core-js/array/from');
+
+var _from2 = _interopRequireDefault(_from);
+
+var _extends2 = require('babel-runtime/helpers/extends');
+
+var _extends3 = _interopRequireDefault(_extends2);
+
+var _typeof2 = require('babel-runtime/helpers/typeof');
+
+var _typeof3 = _interopRequireDefault(_typeof2);
+
+var _getIterator2 = require('babel-runtime/core-js/get-iterator');
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _promise = require('babel-runtime/core-js/promise');
+
+var _promise2 = _interopRequireDefault(_promise);
+
+var _map = require('babel-runtime/core-js/map');
+
+var _map2 = _interopRequireDefault(_map);
+
+var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
+
+var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
+
+var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _createClass2 = require('babel-runtime/helpers/createClass');
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require('babel-runtime/helpers/inherits');
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _Logger = require('./Logger');
+
+var _Logger2 = _interopRequireDefault(_Logger);
+
+var _EnhancedEventEmitter2 = require('./EnhancedEventEmitter');
+
+var _EnhancedEventEmitter3 = _interopRequireDefault(_EnhancedEventEmitter2);
+
+var _errors = require('./errors');
+
+var _utils = require('./utils');
+
+var utils = _interopRequireWildcard(_utils);
+
+var _Device = require('./Device');
+
+var _Device2 = _interopRequireDefault(_Device);
+
+var _Transport = require('./Transport');
+
+var _Transport2 = _interopRequireDefault(_Transport);
+
+var _Producer = require('./Producer');
+
+var _Producer2 = _interopRequireDefault(_Producer);
+
+var _Peer = require('./Peer');
+
+var _Peer2 = _interopRequireDefault(_Peer);
+
+var _Consumer = require('./Consumer');
+
+var _Consumer2 = _interopRequireDefault(_Consumer);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var logger = new _Logger2.default('Room');
+
+var RoomState = {
+ new: 'new',
+ joining: 'joining',
+ joined: 'joined',
+ closed: 'closed'
+};
+
+/**
+ * An instance of Room represents a remote multi conference and a local
+ * peer that joins it.
+ */
+
+var Room = function (_EnhancedEventEmitter) {
+ (0, _inherits3.default)(Room, _EnhancedEventEmitter);
+
+ /**
+ * Room class.
+ *
+ * @param {Object} [options]
+ * @param {Number} [options.requestTimeout=10000] - Timeout for sent requests
+ * (in milliseconds). Defaults to 10000 (10 seconds).
+ * @param {Object} [options.transportOptions] - Transport options for mediasoup.
+ * @param {Array} [options.turnServers] - Array of TURN servers.
+ * @param {Boolean} [hidden=false] - If true no remote Peers will be notified.
+ *
+ * @throws {Error} if device is not supported.
+ *
+ * @emits {request: Object, callback: Function, errback: Function} request
+ * @emits {notification: Object} notify
+ * @emits {peer: Peer} newpeer
+ * @emits {originator: String, [appData]: Any} closed
+ */
+ function Room(options) {
+ (0, _classCallCheck3.default)(this, Room);
+
+ logger.debug('constructor() [options:%o]', options);
+
+ var _this = (0, _possibleConstructorReturn3.default)(this, (Room.__proto__ || (0, _getPrototypeOf2.default)(Room)).call(this));
+
+ if (!_Device2.default.isSupported()) throw new Error('current browser/device not supported');
+
+ options = options || {};
+
+ // Computed settings.
+ // @type {Object}
+ _this._settings = {
+ requestTimeout: options.requestTimeout || 10000,
+ transportOptions: options.transportOptions || {},
+ turnServers: options.turnServers || [],
+ hidden: Boolean(options.hidden)
+ };
+
+ // Room state.
+ // @type {Boolean}
+ _this._state = RoomState.new;
+
+ // Map of Transports indexed by id.
+ // @type {map}
+ _this._transports = new _map2.default();
+
+ // Map of Producers indexed by id.
+ // @type {map}
+ _this._producers = new _map2.default();
+
+ // Map of Peers indexed by name.
+ // @type {map}
+ _this._peers = new _map2.default();
+
+ // Extended RTP capabilities.
+ // @type {Object}
+ _this._extendedRtpCapabilities = null;
+
+ // Whether we can send audio/video based on computed extended RTP
+ // capabilities.
+ // @type {Object}
+ _this._canSendByKind = {
+ audio: false,
+ video: false
+ };
+ return _this;
+ }
+
+ /**
+ * Whether the Room is joined.
+ *
+ * @return {Boolean}
+ */
+
+
+ (0, _createClass3.default)(Room, [{
+ key: 'join',
+
+
+ /**
+ * Start the procedures to join a remote room.
+ *
+ * @param {RTCRtpCapabilities} [roomRtpCapabilities] Remote room RTP capabilities.
+ * If given, no request is sent to the server to discover them.
+ * @param {Any} [appData] - App custom data.
+ * @return {Promise}
+ */
+ value: function join(roomRtpCapabilities, appData) {
+ var _this2 = this;
+
+ if (!roomRtpCapabilities) logger.debug('join()');else logger.debug('join() [roomRtpCapabilities:%o]', roomRtpCapabilities);
+
+ if (this._state !== RoomState.new) {
+ return _promise2.default.reject(new _errors.InvalidStateError('invalid state "' + this._state + '"'));
+ }
+
+ this._state = RoomState.joining;
+
+ var remoteRtpCapabilities = void 0;
+ var localRtpCapabilities = void 0;
+
+ return _promise2.default.resolve().then(function () {
+ if (roomRtpCapabilities) return roomRtpCapabilities;
+
+ return _this2._sendRequest('queryRoom').then(function (response) {
+ var rtpCapabilities = response.rtpCapabilities;
+
+
+ logger.debug('join() | got Room RTP capabilities:%o', rtpCapabilities);
+
+ return rtpCapabilities;
+ });
+ }).then(function (rtpCapabilities) {
+ remoteRtpCapabilities = rtpCapabilities;
+
+ return _Device2.default.Handler.getLocalRtpCapabilities();
+ }).then(function (rtpCapabilities) {
+ localRtpCapabilities = rtpCapabilities;
+
+ // Get extended RTP capabilities.
+ _this2._extendedRtpCapabilities = utils.getExtendedRtpCapabilities(localRtpCapabilities, remoteRtpCapabilities);
+
+ // Check whether we can send audio/video.
+ _this2._canSendByKind.audio = utils.canSend('audio', _this2._extendedRtpCapabilities);
+ _this2._canSendByKind.video = utils.canSend('video', _this2._extendedRtpCapabilities);
+
+ // Generate our effective RTP capabilities for receiving media.
+ var effectiveLocalRtpCapabilities = utils.getRtpCapabilities(_this2._extendedRtpCapabilities);
+
+ logger.debug('join() | effective local RTP capabilities:%o', effectiveLocalRtpCapabilities);
+
+ var data = {
+ rtpCapabilities: effectiveLocalRtpCapabilities,
+ appData: appData
+ };
+
+ return _this2._sendRequest('joinRoom', data).then(function (response) {
+ return response.peers;
+ });
+ }).then(function (peers) {
+ if (!_this2._settings.hidden) {
+ // Handle Peers already existing in the room.
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = (0, _getIterator3.default)(peers || []), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var peerData = _step.value;
+
+ try {
+ _this2._handlePeerData(peerData);
+ } catch (error) {
+ logger.error('join() | error handling Peer:%o', error);
+ }
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+ } else if (peers.length > 0) {
+ logger.error('join() | should not receive Peer list in hidden mode');
+ }
+
+ _this2._state = RoomState.joined;
+
+ logger.debug('join() | joined the Room');
+
+ // Return the list of already existing Peers.
+ return _this2.peers;
+ }).catch(function (error) {
+ _this2._state = RoomState.new;
+
+ throw error;
+ });
+ }
+
+ /**
+ * Leave the Room.
+ *
+ * @param {Any} [appData] - App custom data.
+ */
+
+ }, {
+ key: 'leave',
+ value: function leave(appData) {
+ logger.debug('leave()');
+
+ if (this.closed) return;
+
+ // Send a notification.
+ this._sendNotification('leaveRoom', { appData: appData });
+
+ // Set closed state after sending the notification (otherwise the
+ // notification won't be sent).
+ this._state = RoomState.closed;
+
+ this.safeEmit('closed', 'local', appData);
+
+ // Close all the Transports.
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = (0, _getIterator3.default)(this._transports.values()), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var transport = _step2.value;
+
+ transport.close();
+ }
+
+ // Close all the Producers.
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = (0, _getIterator3.default)(this._producers.values()), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var producer = _step3.value;
+
+ producer.close();
+ }
+
+ // Close all the Peers.
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3.return) {
+ _iterator3.return();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = (0, _getIterator3.default)(this._peers.values()), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ var peer = _step4.value;
+
+ peer.close();
+ }
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4.return) {
+ _iterator4.return();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+ }
+
+ /**
+ * The remote Room was closed or our remote Peer has been closed.
+ * Invoked via remote notification.
+ *
+ * @private
+ * @param {Any} [appData] - App custom data.
+ */
+
+ }, {
+ key: 'remoteClose',
+ value: function remoteClose(appData) {
+ logger.debug('remoteClose()');
+
+ if (this.closed) return;
+
+ this._state = RoomState.closed;
+
+ this.safeEmit('closed', 'remote', appData);
+
+ // Close all the Transports.
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = (0, _getIterator3.default)(this._transports.values()), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ var transport = _step5.value;
+
+ transport.remoteClose();
+ }
+
+ // Close all the Producers.
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5.return) {
+ _iterator5.return();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion6 = true;
+ var _didIteratorError6 = false;
+ var _iteratorError6 = undefined;
+
+ try {
+ for (var _iterator6 = (0, _getIterator3.default)(this._producers.values()), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+ var producer = _step6.value;
+
+ producer.remoteClose();
+ }
+
+ // Close all the Peers.
+ } catch (err) {
+ _didIteratorError6 = true;
+ _iteratorError6 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion6 && _iterator6.return) {
+ _iterator6.return();
+ }
+ } finally {
+ if (_didIteratorError6) {
+ throw _iteratorError6;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion7 = true;
+ var _didIteratorError7 = false;
+ var _iteratorError7 = undefined;
+
+ try {
+ for (var _iterator7 = (0, _getIterator3.default)(this._peers.values()), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
+ var peer = _step7.value;
+
+ peer.remoteClose();
+ }
+ } catch (err) {
+ _didIteratorError7 = true;
+ _iteratorError7 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion7 && _iterator7.return) {
+ _iterator7.return();
+ }
+ } finally {
+ if (_didIteratorError7) {
+ throw _iteratorError7;
+ }
+ }
+ }
+ }
+
+ /**
+ * Whether we can send audio/video.
+ *
+ * @param {String} kind - 'audio' or 'video'.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'canSend',
+ value: function canSend(kind) {
+ if (!this.joined) throw new _errors.InvalidStateError('invalid state "' + this._state + '"');else if (kind !== 'audio' && kind !== 'video') throw new TypeError('invalid kind "' + kind + '"');
+
+ return this._canSendByKind[kind];
+ }
+
+ /**
+ * Creates a Transport.
+ *
+ * @param {String} direction - Must be 'send' or 'recv'.
+ * @param {Any} [appData] - App custom data.
+ *
+ * @return {Transport}
+ *
+ * @throws {InvalidStateError} if not joined.
+ * @throws {TypeError} if wrong arguments.
+ */
+
+ }, {
+ key: 'createTransport',
+ value: function createTransport(direction, appData) {
+ var _this3 = this;
+
+ logger.debug('createTransport() [direction:%s]', direction);
+
+ if (!this.joined) throw new _errors.InvalidStateError('invalid state "' + this._state + '"');else if (direction !== 'send' && direction !== 'recv') throw new TypeError('invalid direction "' + direction + '"');
+
+ // Create a new Transport.
+ var transport = new _Transport2.default(direction, this._extendedRtpCapabilities, this._settings, appData);
+
+ // Store it.
+ this._transports.set(transport.id, transport);
+
+ transport.on('@request', function (method, data, callback, errback) {
+ _this3._sendRequest(method, data).then(callback || function () {}).catch(errback || function () {});
+ });
+
+ transport.on('@notify', function (method, data) {
+ _this3._sendNotification(method, data);
+ });
+
+ transport.on('@close', function () {
+ _this3._transports.delete(transport.id);
+ });
+
+ return transport;
+ }
+
+ /**
+ * Creates a Producer.
+ *
+ * @param {MediaStreamTrack} track
+ * @param {Any} [appData] - App custom data.
+ *
+ * @return {Producer}
+ *
+ * @throws {InvalidStateError} if not joined.
+ * @throws {TypeError} if wrong arguments.
+ * @throws {Error} if cannot send the given kind.
+ */
+
+ }, {
+ key: 'createProducer',
+ value: function createProducer(track, appData) {
+ var _this4 = this;
+
+ logger.debug('createProducer() [track:%o]', track);
+
+ if (!this.joined) throw new _errors.InvalidStateError('invalid state "' + this._state + '"');else if (!(track instanceof MediaStreamTrack)) throw new TypeError('track is not a MediaStreamTrack');else if (!this._canSendByKind[track.kind]) throw new Error('cannot send ' + track.kind);else if (track.readyState === 'ended') throw new Error('track.readyState is "ended"');
+
+ // Create a new Producer.
+ var producer = new _Producer2.default(track, appData);
+
+ // Store it.
+ this._producers.set(producer.id, producer);
+
+ producer.on('@close', function () {
+ _this4._producers.delete(producer.id);
+ });
+
+ return producer;
+ }
+
+ /**
+ * Get the Transport with the given id.
+ *
+ * @param {Number} id
+ *
+ * @return {Transport}
+ */
+
+ }, {
+ key: 'getTransportById',
+ value: function getTransportById(id) {
+ return this._transports.get(id);
+ }
+
+ /**
+ * Get the Producer with the given id.
+ *
+ * @param {Number} id
+ *
+ * @return {Producer}
+ */
+
+ }, {
+ key: 'getProducerById',
+ value: function getProducerById(id) {
+ return this._producers.get(id);
+ }
+
+ /**
+ * Get the Peer with the given name.
+ *
+ * @param {String} name
+ *
+ * @return {Peer}
+ */
+
+ }, {
+ key: 'getPeerById',
+ value: function getPeerById(name) {
+ return this._peers.get(name);
+ }
+
+ /**
+ * Provide the local Room with a notification generated by mediasoup server.
+ *
+ * @param {Object} notification
+ */
+
+ }, {
+ key: 'receiveNotification',
+ value: function receiveNotification(notification) {
+ try {
+ if (this.closed) throw new _errors.InvalidStateError('Room closed');else if ((typeof notification === 'undefined' ? 'undefined' : (0, _typeof3.default)(notification)) !== 'object') throw new TypeError('wrong notification Object');else if (notification.notification !== true) throw new TypeError('not a notification');else if (typeof notification.method !== 'string') throw new TypeError('wrong/missing notification method');
+
+ var method = notification.method;
+
+ logger.debug('receiveNotification() [method:%s, notification:%o]', method, notification);
+
+ switch (method) {
+ case 'roomClosed':
+ {
+ var appData = notification.appData;
+
+
+ this.remoteClose(appData);
+
+ break;
+ }
+
+ case 'transportClosed':
+ {
+ var id = notification.id,
+ _appData = notification.appData;
+
+ var transport = this._transports.get(id);
+
+ if (!transport) throw new Error('Transport does not exist [id:"' + id + '"]');
+
+ transport.remoteClose(_appData);
+
+ break;
+ }
+
+ case 'newPeer':
+ {
+ this._ensureNotHidden();
+
+ var name = notification.name;
+
+
+ if (this._peers.has(name)) throw new Error('Peer already exists [name:"' + name + '"]');
+
+ var peerData = notification;
+
+ this._handlePeerData(peerData);
+
+ break;
+ }
+
+ case 'peerClosed':
+ {
+ this._ensureNotHidden();
+
+ var peerName = notification.name;
+ var _appData2 = notification.appData;
+
+ var peer = this._peers.get(peerName);
+
+ if (!peer) throw new Error('no Peer found [name:"' + peerName + '"]');
+
+ peer.remoteClose(_appData2);
+
+ break;
+ }
+
+ case 'producerClosed':
+ {
+ var _id = notification.id,
+ _appData3 = notification.appData;
+
+ var producer = this._producers.get(_id);
+
+ if (!producer) throw new Error('Producer not found [id:' + _id + ']');
+
+ producer.remoteClose(_appData3);
+
+ break;
+ }
+
+ case 'producerPaused':
+ {
+ var _id2 = notification.id,
+ _appData4 = notification.appData;
+
+ var _producer = this._producers.get(_id2);
+
+ if (!_producer) throw new Error('Producer not found [id:' + _id2 + ']');
+
+ _producer.remotePause(_appData4);
+
+ break;
+ }
+
+ case 'producerResumed':
+ {
+ var _id3 = notification.id,
+ _appData5 = notification.appData;
+
+ var _producer2 = this._producers.get(_id3);
+
+ if (!_producer2) throw new Error('Producer not found [id:' + _id3 + ']');
+
+ _producer2.remoteResume(_appData5);
+
+ break;
+ }
+
+ case 'newConsumer':
+ {
+ this._ensureNotHidden();
+
+ var _peerName = notification.peerName;
+
+ var _peer = this._peers.get(_peerName);
+
+ if (!_peer) throw new Error('no Peer found [name:"' + _peerName + '"]');
+
+ var consumerData = notification;
+
+ this._handleConsumerData(consumerData, _peer);
+
+ break;
+ }
+
+ case 'consumerClosed':
+ {
+ this._ensureNotHidden();
+
+ var _id4 = notification.id,
+ _peerName2 = notification.peerName,
+ _appData6 = notification.appData;
+
+ var _peer2 = this._peers.get(_peerName2);
+
+ if (!_peer2) throw new Error('no Peer found [name:"' + _peerName2 + '"]');
+
+ var consumer = _peer2.getConsumerById(_id4);
+
+ if (!consumer) throw new Error('Consumer not found [id:' + _id4 + ']');
+
+ consumer.remoteClose(_appData6);
+
+ break;
+ }
+
+ case 'consumerPaused':
+ {
+ this._ensureNotHidden();
+
+ var _id5 = notification.id,
+ _peerName3 = notification.peerName,
+ _appData7 = notification.appData;
+
+ var _peer3 = this._peers.get(_peerName3);
+
+ if (!_peer3) throw new Error('no Peer found [name:"' + _peerName3 + '"]');
+
+ var _consumer = _peer3.getConsumerById(_id5);
+
+ if (!_consumer) throw new Error('Consumer not found [id:' + _id5 + ']');
+
+ _consumer.remotePause(_appData7);
+
+ break;
+ }
+
+ case 'consumerResumed':
+ {
+ this._ensureNotHidden();
+
+ var _id6 = notification.id,
+ _peerName4 = notification.peerName,
+ _appData8 = notification.appData;
+
+ var _peer4 = this._peers.get(_peerName4);
+
+ var _consumer2 = _peer4.getConsumerById(_id6);
+
+ if (!_consumer2) throw new Error('Consumer not found [id:' + _id6 + ']');
+
+ _consumer2.remoteResume(_appData8);
+
+ break;
+ }
+
+ default:
+ throw new Error('unknown notification method "' + method + '"');
+ }
+ } catch (error) {
+ logger.error('receiveNotification() failed [notification:%o]: %s', notification, error.toString());
+ }
+ }
+ }, {
+ key: '_sendRequest',
+ value: function _sendRequest(method, data) {
+ var _this5 = this;
+
+ var request = (0, _extends3.default)({ method: method }, data);
+
+ // Should never happen.
+ // Ignore if closed.
+ if (this.closed) {
+ logger.error('_sendRequest() | Room closed [method:%s, request:%o]', method, request);
+
+ return _promise2.default.reject(new _errors.InvalidStateError('Room closed'));
+ }
+
+ logger.debug('_sendRequest() [method:%s, request:%o]', method, request);
+
+ return new _promise2.default(function (resolve, reject) {
+ var done = false;
+
+ var timer = setTimeout(function () {
+ logger.error('request failed [method:%s]: timeout', method);
+
+ done = true;
+ reject(new _errors.TimeoutError('timeout'));
+ }, _this5._settings.requestTimeout);
+
+ // TODO: We could also handle room 'closed' event here.
+
+ var callback = function callback(response) {
+ if (done) return;
+
+ done = true;
+ clearTimeout(timer);
+
+ if (_this5.closed) {
+ logger.error('request failed [method:%s]: Room closed', method);
+
+ reject(new Error('Room closed'));
+
+ return;
+ }
+
+ logger.debug('request succeeded [method:%s, response:%o]', method, response);
+
+ resolve(response);
+ };
+
+ var errback = function errback(message) {
+ if (done) return;
+
+ done = true;
+ clearTimeout(timer);
+
+ if (_this5.closed) {
+ logger.error('request failed [method:%s]: Room closed', method);
+
+ reject(new Error('Room closed'));
+
+ return;
+ }
+
+ // Make sure message is a String.
+ message = String(message);
+
+ logger.error('request failed [method:%s]: %s', method, message);
+
+ reject(new Error(message));
+ };
+
+ _this5.safeEmit('request', request, callback, errback);
+ });
+ }
+ }, {
+ key: '_sendNotification',
+ value: function _sendNotification(method, data) {
+ // Ignore if closed.
+ if (this.closed) return;
+
+ var notification = (0, _extends3.default)({ method: method, notification: true }, data);
+
+ logger.debug('_sendNotification() [method:%s, notification:%o]', method, notification);
+
+ this.safeEmit('notify', notification);
+ }
+ }, {
+ key: '_ensureNotHidden',
+ value: function _ensureNotHidden() {
+ if (this._settings.hidden) throw new Error('hidden mode set');
+ }
+ }, {
+ key: '_handlePeerData',
+ value: function _handlePeerData(peerData) {
+ var _this6 = this;
+
+ var name = peerData.name,
+ consumers = peerData.consumers,
+ appData = peerData.appData;
+
+ var peer = new _Peer2.default(name, appData);
+
+ // Store it.
+ this._peers.set(peer.name, peer);
+
+ peer.on('@close', function () {
+ _this6._peers.delete(peer.name);
+ });
+
+ // Add consumers.
+ var _iteratorNormalCompletion8 = true;
+ var _didIteratorError8 = false;
+ var _iteratorError8 = undefined;
+
+ try {
+ for (var _iterator8 = (0, _getIterator3.default)(consumers), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
+ var consumerData = _step8.value;
+
+ try {
+ this._handleConsumerData(consumerData, peer);
+ } catch (error) {
+ logger.error('error handling existing Consumer in Peer:%o', error);
+ }
+ }
+
+ // If already joined emit event.
+ } catch (err) {
+ _didIteratorError8 = true;
+ _iteratorError8 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion8 && _iterator8.return) {
+ _iterator8.return();
+ }
+ } finally {
+ if (_didIteratorError8) {
+ throw _iteratorError8;
+ }
+ }
+ }
+
+ if (this.joined) this.safeEmit('newpeer', peer);
+ }
+ }, {
+ key: '_handleConsumerData',
+ value: function _handleConsumerData(producerData, peer) {
+ var id = producerData.id,
+ kind = producerData.kind,
+ rtpParameters = producerData.rtpParameters,
+ paused = producerData.paused,
+ appData = producerData.appData;
+
+ var consumer = new _Consumer2.default(id, kind, rtpParameters, peer, appData);
+ var supported = utils.canReceive(consumer.rtpParameters, this._extendedRtpCapabilities);
+
+ if (supported) consumer.setSupported(true);
+
+ if (paused) consumer.remotePause();
+
+ peer.addConsumer(consumer);
+ }
+ }, {
+ key: 'joined',
+ get: function get() {
+ return this._state === RoomState.joined;
+ }
+
+ /**
+ * Whether the Room is closed.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'closed',
+ get: function get() {
+ return this._state === RoomState.closed;
+ }
+
+ /**
+ * The list of Transports.
+ *
+ * @return {Array}
+ */
+
+ }, {
+ key: 'transports',
+ get: function get() {
+ return (0, _from2.default)(this._transports.values());
+ }
+
+ /**
+ * The list of Producers.
+ *
+ * @return {Array}
+ */
+
+ }, {
+ key: 'producers',
+ get: function get() {
+ return (0, _from2.default)(this._producers.values());
+ }
+
+ /**
+ * The list of Peers.
+ *
+ * @return {Array}
+ */
+
+ }, {
+ key: 'peers',
+ get: function get() {
+ return (0, _from2.default)(this._peers.values());
+ }
+ }]);
+ return Room;
+}(_EnhancedEventEmitter3.default);
+
+exports.default = Room;
+
+},{"./Consumer":"/Users/ibc/src/mediasoup-client/lib/Consumer.js","./Device":"/Users/ibc/src/mediasoup-client/lib/Device.js","./EnhancedEventEmitter":"/Users/ibc/src/mediasoup-client/lib/EnhancedEventEmitter.js","./Logger":"/Users/ibc/src/mediasoup-client/lib/Logger.js","./Peer":"/Users/ibc/src/mediasoup-client/lib/Peer.js","./Producer":"/Users/ibc/src/mediasoup-client/lib/Producer.js","./Transport":"/Users/ibc/src/mediasoup-client/lib/Transport.js","./errors":"/Users/ibc/src/mediasoup-client/lib/errors.js","./utils":"/Users/ibc/src/mediasoup-client/lib/utils.js","babel-runtime/core-js/array/from":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/array/from.js","babel-runtime/core-js/get-iterator":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/get-iterator.js","babel-runtime/core-js/map":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/map.js","babel-runtime/core-js/object/get-prototype-of":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/object/get-prototype-of.js","babel-runtime/core-js/promise":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/promise.js","babel-runtime/helpers/classCallCheck":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/classCallCheck.js","babel-runtime/helpers/createClass":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/createClass.js","babel-runtime/helpers/extends":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/extends.js","babel-runtime/helpers/inherits":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/inherits.js","babel-runtime/helpers/possibleConstructorReturn":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/possibleConstructorReturn.js","babel-runtime/helpers/typeof":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/typeof.js"}],"/Users/ibc/src/mediasoup-client/lib/Transport.js":[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _promise = require('babel-runtime/core-js/promise');
+
+var _promise2 = _interopRequireDefault(_promise);
+
+var _getIterator2 = require('babel-runtime/core-js/get-iterator');
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _map = require('babel-runtime/core-js/map');
+
+var _map2 = _interopRequireDefault(_map);
+
+var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
+
+var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
+
+var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _createClass2 = require('babel-runtime/helpers/createClass');
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require('babel-runtime/helpers/inherits');
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _Logger = require('./Logger');
+
+var _Logger2 = _interopRequireDefault(_Logger);
+
+var _EnhancedEventEmitter2 = require('./EnhancedEventEmitter');
+
+var _EnhancedEventEmitter3 = _interopRequireDefault(_EnhancedEventEmitter2);
+
+var _utils = require('./utils');
+
+var utils = _interopRequireWildcard(_utils);
+
+var _Device = require('./Device');
+
+var _Device2 = _interopRequireDefault(_Device);
+
+var _CommandQueue = require('./CommandQueue');
+
+var _CommandQueue2 = _interopRequireDefault(_CommandQueue);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var logger = new _Logger2.default('Transport');
+
+var Transport = function (_EnhancedEventEmitter) {
+ (0, _inherits3.default)(Transport, _EnhancedEventEmitter);
+
+ /**
+ * @private
+ *
+ * @emits {state: String} connectionstatechange
+ * @emits {originator: String, [appData]: Any} closed
+ * @emits {method: String, [data]: Object, callback: Function, errback: Function} @request
+ * @emits {method: String, [data]: Object} @notify
+ * @emits {originator: String} @close
+ */
+ function Transport(direction, extendedRtpCapabilities, settings, appData) {
+ (0, _classCallCheck3.default)(this, Transport);
+
+ logger.debug('constructor() [direction:%s, extendedRtpCapabilities:%o]', direction, extendedRtpCapabilities);
+
+ // Id.
+ // @type {Number}
+ var _this = (0, _possibleConstructorReturn3.default)(this, (Transport.__proto__ || (0, _getPrototypeOf2.default)(Transport)).call(this));
+
+ _this._id = utils.randomNumber();
+
+ // Closed flag.
+ // @type {Boolean}
+ _this._closed = false;
+
+ // Direction.
+ // @type {String}
+ _this._direction = direction;
+
+ // Room settings.
+ // @type {Object}
+ _this._settings = settings;
+
+ // App custom data.
+ // @type {Any}
+ _this._appData = appData;
+
+ // Map of Producers indexed by id.
+ // @type {map}
+ _this._producers = new _map2.default();
+
+ // Map of Consumers indexed by id.
+ // @type {map}
+ _this._consumers = new _map2.default();
+
+ // Commands handler.
+ // @type {CommandQueue}
+ _this._commandQueue = new _CommandQueue2.default();
+
+ // Device specific handler.
+ _this._handler = new _Device2.default.Handler(direction, extendedRtpCapabilities, settings);
+
+ // Transport state. Values can be:
+ // 'new'/'connecting'/'connected'/'failed'/'disconnected'/'closed'
+ // @type {String}
+ _this._connectionState = 'new';
+
+ _this._commandQueue.on('exec', _this._execCommand.bind(_this));
+ _this._handleHandler();
+ return _this;
+ }
+
+ /**
+ * Transport id.
+ *
+ * @return {Number}
+ */
+
+
+ (0, _createClass3.default)(Transport, [{
+ key: 'close',
+
+
+ /**
+ * Close the Transport.
+ *
+ * @param {Any} [appData] - App custom data.
+ */
+ value: function close(appData) {
+ logger.debug('close()');
+
+ if (this._closed) return;
+
+ this._closed = true;
+
+ this.safeEmit('@notify', 'closeTransport', { id: this._id, appData: appData });
+
+ this.emit('@close', 'local');
+ this.safeEmit('closed', 'local', appData);
+
+ this._destroy();
+ }
+
+ /**
+ * My remote Transport was closed.
+ * Invoked via remote notification.
+ *
+ * @param {Any} [appData] - App custom data.
+ */
+
+ }, {
+ key: 'remoteClose',
+ value: function remoteClose(appData) {
+ logger.debug('remoteClose()');
+
+ if (this._closed) return;
+
+ this._closed = true;
+
+ this.emit('@close', 'remote');
+ this.safeEmit('closed', 'remote', appData);
+
+ this._destroy();
+ }
+ }, {
+ key: '_destroy',
+ value: function _destroy() {
+ // Close the CommandQueue.
+ this._commandQueue.close();
+
+ // Close the handler.
+ this._handler.close();
+
+ // Unhandle all the Producers.
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = (0, _getIterator3.default)(this._producers.values()), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var producer = _step.value;
+
+ producer.setHandled(false);
+ }
+
+ // Unhandle all the Consumers.
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = (0, _getIterator3.default)(this._consumers.values()), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var consumer = _step2.value;
+
+ consumer.setHandled(false);
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+ }
+
+ /**
+ * Send the given Producer over this Transport.
+ *
+ * @param {Producer} producer
+ *
+ * @return {Promise}
+ *
+ * @example
+ * transport.send(videoProducer)
+ * .then(() => {
+ * // Done
+ * });
+ */
+
+ }, {
+ key: 'send',
+ value: function send(producer) {
+ logger.debug('send() [producer:%o]', producer);
+
+ if (this._direction !== 'send') return _promise2.default.reject(new Error('cannot send on a receiving Transport'));else if (!producer || producer.klass !== 'Producer') return _promise2.default.reject(new TypeError('wrong Producer'));
+
+ // Enqueue command.
+ return this._commandQueue.push('addProducer', { producer: producer });
+ }
+
+ /**
+ * Receive the given Consumer over this Transport.
+ *
+ * @param {Consumer} consumer
+ *
+ * @return {Promise}
+ *
+ * @example
+ * transport.receive(aliceVideoConsumer)
+ * .then(() => {
+ * // Done
+ * });
+ */
+
+ }, {
+ key: 'receive',
+ value: function receive(consumer) {
+ logger.debug('receive() [consumer:%o]', consumer);
+
+ if (this._direction !== 'recv') return _promise2.default.reject(new Error('cannot receive on a sending Transport'));else if (!consumer || consumer.klass !== 'Consumer') return _promise2.default.reject(new TypeError('wrong Consumer'));
+
+ // Enqueue command.
+ return this._commandQueue.push('addConsumer', { consumer: consumer });
+ }
+ }, {
+ key: '_handleHandler',
+ value: function _handleHandler() {
+ var _this2 = this;
+
+ var handler = this._handler;
+
+ handler.on('@connectionstatechange', function (state) {
+ if (_this2._connectionState === state) return;
+
+ _this2._connectionState = state;
+
+ if (!_this2._closed) _this2.safeEmit('connectionstatechange', state);
+ });
+
+ handler.on('@needcreatetransport', function (transportLocalParameters, callback, errback) {
+ var data = {
+ id: _this2._id,
+ options: _this2._settings.transportOptions,
+ appData: _this2._appData
+ };
+
+ if (transportLocalParameters) data.dtlsParameters = transportLocalParameters.dtlsParameters;
+
+ _this2.safeEmit('@request', 'createTransport', data, callback, errback);
+ });
+
+ handler.on('@needupdatetransport', function (transportLocalParameters) {
+ var data = {
+ id: _this2._id,
+ dtlsParameters: transportLocalParameters.dtlsParameters
+ };
+
+ _this2.safeEmit('@notify', 'updateTransport', data);
+ });
+ }
+ }, {
+ key: '_execCommand',
+ value: function _execCommand(command, promiseHolder) {
+ var promise = void 0;
+
+ try {
+ switch (command.method) {
+ case 'addProducer':
+ {
+ var producer = command.producer;
+
+
+ promise = this._execAddProducer(producer);
+ break;
+ }
+
+ case 'removeProducer':
+ {
+ var _producer = command.producer;
+
+
+ promise = this._execRemoveProducer(_producer);
+ break;
+ }
+
+ case 'addConsumer':
+ {
+ var consumer = command.consumer;
+
+
+ promise = this._execAddConsumer(consumer);
+ break;
+ }
+
+ case 'removeConsumer':
+ {
+ var _consumer = command.consumer;
+
+
+ promise = this._execRemoveConsumer(_consumer);
+ break;
+ }
+
+ default:
+ {
+ promise = _promise2.default.reject(new Error('unknown command method "' + command.method + '"'));
+ }
+ }
+ } catch (error) {
+ promise = _promise2.default.reject(error);
+ }
+
+ // Fill the given Promise holder.
+ promiseHolder.promise = promise;
+ }
+ }, {
+ key: '_execAddProducer',
+ value: function _execAddProducer(producer) {
+ var _this3 = this;
+
+ logger.debug('_execAddProducer()');
+
+ if (producer.closed) return _promise2.default.reject(new Error('Producer closed'));else if (producer.handled) return _promise2.default.reject(new Error('Producer already handled by a Transport'));
+
+ var producerRtpParameters = void 0;
+
+ producer.setHandled('tmp');
+
+ // Call the handler.
+ return _promise2.default.resolve().then(function () {
+ return _this3._handler.addProducer(producer);
+ }).then(function (rtpParameters) {
+ producerRtpParameters = rtpParameters;
+
+ var data = {
+ id: producer.id,
+ kind: producer.kind,
+ transportId: _this3._id,
+ rtpParameters: rtpParameters,
+ appData: producer.appData
+ };
+
+ return _this3.safeEmitAsPromise('@request', 'createProducer', data);
+ }).then(function () {
+ producer.setHandled(true, producerRtpParameters);
+ _this3._producers.set(producer.id, producer);
+ _this3._handleProducer(producer);
+ }).catch(function (error) {
+ producer.setHandled(false);
+
+ throw error;
+ });
+ }
+ }, {
+ key: '_execRemoveProducer',
+ value: function _execRemoveProducer(producer) {
+ logger.debug('_execRemoveProducer()');
+
+ // Call the handler.
+ return this._handler.removeProducer(producer);
+ }
+ }, {
+ key: '_execAddConsumer',
+ value: function _execAddConsumer(consumer) {
+ var _this4 = this;
+
+ logger.debug('_execAddConsumer()');
+
+ if (consumer.closed) return _promise2.default.reject(new Error('Consumer closed'));else if (consumer.handled) return _promise2.default.reject(new Error('Consumer already handled by a Transport'));
+
+ // Check whether we can receive this Consumer.
+ if (!consumer.supported) {
+ return _promise2.default.reject(new Error('cannot receive this Consumer, unsupported codecs'));
+ }
+
+ var consumerTrack = void 0;
+
+ consumer.setHandled('tmp');
+
+ // Call the handler.
+ return _promise2.default.resolve().then(function () {
+ return _this4._handler.addConsumer(consumer);
+ }).then(function (track) {
+ consumerTrack = track;
+
+ var data = {
+ id: consumer.id
+ };
+
+ return _this4.safeEmitAsPromise('@request', 'enableConsumer', data);
+ }).then(function () {
+ consumer.setHandled(true, consumerTrack);
+ _this4._consumers.set(consumer.id, consumer);
+ _this4._handleConsumer(consumer);
+
+ return consumerTrack;
+ }).catch(function (error) {
+ consumer.setHandled(false);
+
+ throw error;
+ });
+ }
+ }, {
+ key: '_execRemoveConsumer',
+ value: function _execRemoveConsumer(consumer) {
+ logger.debug('_execRemoveConsumer()');
+
+ // Call the handler.
+ return this._handler.removeConsumer(consumer);
+ }
+ }, {
+ key: '_handleProducer',
+ value: function _handleProducer(producer) {
+ var _this5 = this;
+
+ producer.on('@close', function (originator, appData) {
+ _this5._producers.delete(producer.id);
+
+ // Enqueue command.
+ _this5._commandQueue.push('removeProducer', { producer: producer }).catch(function () {});
+
+ if (originator === 'local') {
+ _this5.safeEmit('@notify', 'closeProducer', { id: producer.id, appData: appData });
+ }
+ });
+
+ producer.on('@pause', function (appData) {
+ var data = {
+ id: producer.id,
+ appData: appData
+ };
+
+ _this5.safeEmit('@notify', 'pauseProducer', data);
+ });
+
+ producer.on('@resume', function (appData) {
+ var data = {
+ id: producer.id,
+ appData: appData
+ };
+
+ _this5.safeEmit('@notify', 'resumeProducer', data);
+ });
+ }
+ }, {
+ key: '_handleConsumer',
+ value: function _handleConsumer(consumer) {
+ var _this6 = this;
+
+ consumer.on('@close', function () {
+ _this6._consumers.delete(consumer.id);
+
+ // Enqueue command.
+ _this6._commandQueue.push('removeConsumer', { consumer: consumer }).catch(function () {});
+ });
+
+ consumer.on('@pause', function (appData) {
+ var data = {
+ id: consumer.id,
+ appData: appData
+ };
+
+ _this6.safeEmit('@notify', 'pauseConsumer', data);
+ });
+
+ consumer.on('@resume', function (appData) {
+ var data = {
+ id: consumer.id,
+ appData: appData
+ };
+
+ _this6.safeEmit('@notify', 'resumeConsumer', data);
+ });
+ }
+ }, {
+ key: 'id',
+ get: function get() {
+ return this._id;
+ }
+
+ /**
+ * Whether the Transport is closed.
+ *
+ * @return {Boolean}
+ */
+
+ }, {
+ key: 'closed',
+ get: function get() {
+ return this._closed;
+ }
+
+ /**
+ * Transport direction.
+ *
+ * @return {String}
+ */
+
+ }, {
+ key: 'direction',
+ get: function get() {
+ return this._direction;
+ }
+
+ /**
+ * App custom data.
+ *
+ * @return {Any}
+ */
+
+ }, {
+ key: 'appData',
+ get: function get() {
+ return this._appData;
+ }
+
+ /**
+ * Connection state.
+ *
+ * @return {String}
+ */
+
+ }, {
+ key: 'connectionState',
+ get: function get() {
+ return this._connectionState;
+ }
+ }]);
+ return Transport;
+}(_EnhancedEventEmitter3.default);
+
+exports.default = Transport;
+
+},{"./CommandQueue":"/Users/ibc/src/mediasoup-client/lib/CommandQueue.js","./Device":"/Users/ibc/src/mediasoup-client/lib/Device.js","./EnhancedEventEmitter":"/Users/ibc/src/mediasoup-client/lib/EnhancedEventEmitter.js","./Logger":"/Users/ibc/src/mediasoup-client/lib/Logger.js","./utils":"/Users/ibc/src/mediasoup-client/lib/utils.js","babel-runtime/core-js/get-iterator":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/get-iterator.js","babel-runtime/core-js/map":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/map.js","babel-runtime/core-js/object/get-prototype-of":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/object/get-prototype-of.js","babel-runtime/core-js/promise":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/promise.js","babel-runtime/helpers/classCallCheck":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/classCallCheck.js","babel-runtime/helpers/createClass":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/createClass.js","babel-runtime/helpers/inherits":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/inherits.js","babel-runtime/helpers/possibleConstructorReturn":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/possibleConstructorReturn.js"}],"/Users/ibc/src/mediasoup-client/lib/errors.js":[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.TimeoutError = exports.InvalidStateError = undefined;
+
+var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
+
+var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
+
+var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require('babel-runtime/helpers/inherits');
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+/**
+ * Error produced when calling a method in an invalid state.
+ */
+var InvalidStateError = exports.InvalidStateError = function (_Error) {
+ (0, _inherits3.default)(InvalidStateError, _Error);
+
+ function InvalidStateError(message) {
+ (0, _classCallCheck3.default)(this, InvalidStateError);
+
+ var _this = (0, _possibleConstructorReturn3.default)(this, (InvalidStateError.__proto__ || (0, _getPrototypeOf2.default)(InvalidStateError)).call(this, message));
+
+ Object.defineProperty(_this, 'name', {
+ enumerable: false,
+ writable: false,
+ value: 'InvalidStateError'
+ });
+
+ if (Error.hasOwnProperty('captureStackTrace')) // Just in V8.
+ {
+ Error.captureStackTrace(_this, InvalidStateError);
+ } else {
+ Object.defineProperty(_this, 'stack', {
+ enumerable: false,
+ writable: false,
+ value: new Error(message).stack
+ });
+ }
+ return _this;
+ }
+
+ return InvalidStateError;
+}(Error);
+
+/**
+ * Error produced when a Promise is rejected due to a timeout.
+ */
+
+
+var TimeoutError = exports.TimeoutError = function (_Error2) {
+ (0, _inherits3.default)(TimeoutError, _Error2);
+
+ function TimeoutError(message) {
+ (0, _classCallCheck3.default)(this, TimeoutError);
+
+ var _this2 = (0, _possibleConstructorReturn3.default)(this, (TimeoutError.__proto__ || (0, _getPrototypeOf2.default)(TimeoutError)).call(this, message));
+
+ Object.defineProperty(_this2, 'name', {
+ enumerable: false,
+ writable: false,
+ value: 'TimeoutError'
+ });
+
+ if (Error.hasOwnProperty('captureStackTrace')) // Just in V8.
+ {
+ Error.captureStackTrace(_this2, TimeoutError);
+ } else {
+ Object.defineProperty(_this2, 'stack', {
+ enumerable: false,
+ writable: false,
+ value: new Error(message).stack
+ });
+ }
+ return _this2;
+ }
+
+ return TimeoutError;
+}(Error);
+
+},{"babel-runtime/core-js/object/get-prototype-of":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/object/get-prototype-of.js","babel-runtime/helpers/classCallCheck":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/classCallCheck.js","babel-runtime/helpers/inherits":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/inherits.js","babel-runtime/helpers/possibleConstructorReturn":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/possibleConstructorReturn.js"}],"/Users/ibc/src/mediasoup-client/lib/handlers/Chrome55.js":[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _from = require('babel-runtime/core-js/array/from');
+
+var _from2 = _interopRequireDefault(_from);
+
+var _map = require('babel-runtime/core-js/map');
+
+var _map2 = _interopRequireDefault(_map);
+
+var _set = require('babel-runtime/core-js/set');
+
+var _set2 = _interopRequireDefault(_set);
+
+var _promise = require('babel-runtime/core-js/promise');
+
+var _promise2 = _interopRequireDefault(_promise);
+
+var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
+
+var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
+
+var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _createClass2 = require('babel-runtime/helpers/createClass');
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require('babel-runtime/helpers/inherits');
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _sdpTransform = require('sdp-transform');
+
+var _sdpTransform2 = _interopRequireDefault(_sdpTransform);
+
+var _Logger = require('../Logger');
+
+var _Logger2 = _interopRequireDefault(_Logger);
+
+var _EnhancedEventEmitter2 = require('../EnhancedEventEmitter');
+
+var _EnhancedEventEmitter3 = _interopRequireDefault(_EnhancedEventEmitter2);
+
+var _utils = require('../utils');
+
+var utils = _interopRequireWildcard(_utils);
+
+var _commonUtils = require('./sdp/commonUtils');
+
+var sdpCommonUtils = _interopRequireWildcard(_commonUtils);
+
+var _planBUtils = require('./sdp/planBUtils');
+
+var sdpPlanBUtils = _interopRequireWildcard(_planBUtils);
+
+var _RemotePlanBSdp = require('./sdp/RemotePlanBSdp');
+
+var _RemotePlanBSdp2 = _interopRequireDefault(_RemotePlanBSdp);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var logger = new _Logger2.default('Chrome55');
+
+var Handler = function (_EnhancedEventEmitter) {
+ (0, _inherits3.default)(Handler, _EnhancedEventEmitter);
+
+ function Handler(direction, rtpParametersByKind, settings) {
+ (0, _classCallCheck3.default)(this, Handler);
+
+ // RTCPeerConnection instance.
+ // @type {RTCPeerConnection}
+ var _this = (0, _possibleConstructorReturn3.default)(this, (Handler.__proto__ || (0, _getPrototypeOf2.default)(Handler)).call(this));
+
+ _this._pc = new RTCPeerConnection({
+ iceServers: settings.turnServers || [],
+ iceTransportPolicy: 'relay',
+ bundlePolicy: 'max-bundle',
+ rtcpMuxPolicy: 'require'
+ });
+
+ // Generic sending RTP parameters for audio and video.
+ // @type {Object}
+ _this._rtpParametersByKind = rtpParametersByKind;
+
+ // Remote SDP handler.
+ // @type {RemotePlanBSdp}
+ _this._remoteSdp = new _RemotePlanBSdp2.default(direction, rtpParametersByKind);
+
+ // Handle RTCPeerConnection connection status.
+ _this._pc.addEventListener('iceconnectionstatechange', function () {
+ switch (_this._pc.iceConnectionState) {
+ case 'checking':
+ _this.emit('@connectionstatechange', 'connecting');
+ break;
+ case 'connected':
+ case 'completed':
+ _this.emit('@connectionstatechange', 'connected');
+ break;
+ case 'failed':
+ _this.emit('@connectionstatechange', 'failed');
+ break;
+ case 'disconnected':
+ _this.emit('@connectionstatechange', 'disconnected');
+ break;
+ case 'closed':
+ _this.emit('@connectionstatechange', 'closed');
+ break;
+ }
+ });
+ return _this;
+ }
+
+ (0, _createClass3.default)(Handler, [{
+ key: 'close',
+ value: function close() {
+ logger.debug('close()');
+
+ // Close RTCPeerConnection.
+ try {
+ this._pc.close();
+ } catch (error) {}
+ }
+ }]);
+ return Handler;
+}(_EnhancedEventEmitter3.default);
+
+var SendHandler = function (_Handler) {
+ (0, _inherits3.default)(SendHandler, _Handler);
+
+ function SendHandler(rtpParametersByKind, settings) {
+ (0, _classCallCheck3.default)(this, SendHandler);
+
+ // Got transport local and remote parameters.
+ // @type {Boolean}
+ var _this2 = (0, _possibleConstructorReturn3.default)(this, (SendHandler.__proto__ || (0, _getPrototypeOf2.default)(SendHandler)).call(this, 'send', rtpParametersByKind, settings));
+
+ _this2._transportReady = false;
+
+ // Local stream.
+ // @type {MediaStream}
+ _this2._stream = new MediaStream();
+ return _this2;
+ }
+
+ (0, _createClass3.default)(SendHandler, [{
+ key: 'addProducer',
+ value: function addProducer(producer) {
+ var _this3 = this;
+
+ var track = producer.track;
+
+
+ logger.debug('addProducer() [id:%s, kind:%s, trackId:%s]', producer.id, producer.kind, track.id);
+
+ var localSdpObj = void 0;
+
+ return _promise2.default.resolve().then(function () {
+ // Add the track to the local stream.
+ _this3._stream.addTrack(track);
+
+ // Add the stream to the PeerConnection.
+ _this3._pc.addStream(_this3._stream);
+
+ return _this3._pc.createOffer();
+ }).then(function (offer) {
+ return _this3._pc.setLocalDescription(offer);
+ }).then(function () {
+ if (!_this3._transportReady) return _this3._setupTransport();
+ }).then(function () {
+ localSdpObj = _sdpTransform2.default.parse(_this3._pc.localDescription.sdp);
+
+ var remoteSdp = _this3._remoteSdp.createAnswerSdp(localSdpObj);
+ var answer = { type: 'answer', sdp: remoteSdp };
+
+ return _this3._pc.setRemoteDescription(answer);
+ }).then(function () {
+ var rtpParameters = utils.clone(_this3._rtpParametersByKind[producer.kind]);
+
+ // Fill the RTP parameters for this track.
+ sdpPlanBUtils.fillRtpParametersForTrack(rtpParameters, localSdpObj, track);
+
+ return rtpParameters;
+ }).catch(function (error) {
+ // Panic here. Try to undo things.
+
+ _this3._stream.removeTrack(track);
+ _this3._pc.addStream(_this3._stream);
+
+ throw error;
+ });
+ }
+ }, {
+ key: 'removeProducer',
+ value: function removeProducer(producer) {
+ var _this4 = this;
+
+ var track = producer.track;
+
+
+ logger.debug('removeProducer() [id:%s, kind:%s, trackId:%s]', producer.id, producer.kind, track.id);
+
+ return _promise2.default.resolve().then(function () {
+ // Remove the track from the local stream.
+ _this4._stream.removeTrack(track);
+
+ // Add the stream to the PeerConnection.
+ _this4._pc.addStream(_this4._stream);
+
+ return _this4._pc.createOffer();
+ }).then(function (offer) {
+ return _this4._pc.setLocalDescription(offer);
+ }).catch(function (error) {
+ // NOTE: If there are no sending tracks, setLocalDescription() will fail with
+ // "Failed to create channels". If so, ignore it.
+ if (_this4._stream.getTracks().length === 0) {
+ logger.warn('removeProducer() | ignoring expected error due no sending tracks: %s', error.toString());
+
+ return;
+ }
+
+ throw error;
+ }).then(function () {
+ if (_this4._pc.signalingState === 'stable') return;
+
+ var localSdpObj = _sdpTransform2.default.parse(_this4._pc.localDescription.sdp);
+ var remoteSdp = _this4._remoteSdp.createAnswerSdp(localSdpObj);
+ var answer = { type: 'answer', sdp: remoteSdp };
+
+ return _this4._pc.setRemoteDescription(answer);
+ });
+ }
+ }, {
+ key: '_setupTransport',
+ value: function _setupTransport() {
+ var _this5 = this;
+
+ logger.debug('_setupTransport()');
+
+ return _promise2.default.resolve().then(function () {
+ // Get our local DTLS parameters.
+ var transportLocalParameters = {};
+ var sdp = _this5._pc.localDescription.sdp;
+ var sdpObj = _sdpTransform2.default.parse(sdp);
+ var dtlsParameters = sdpCommonUtils.extractDtlsParameters(sdpObj);
+
+ // Let's decide that we'll be DTLS server (because we can).
+ dtlsParameters.role = 'server';
+
+ transportLocalParameters.dtlsParameters = dtlsParameters;
+
+ // Provide the remote SDP handler with transport local parameters.
+ _this5._remoteSdp.setTransportLocalParameters(transportLocalParameters);
+
+ // We need transport remote parameters.
+ return _this5.safeEmitAsPromise('@needcreatetransport', transportLocalParameters);
+ }).then(function (transportRemoteParameters) {
+ // Provide the remote SDP handler with transport remote parameters.
+ _this5._remoteSdp.setTransportRemoteParameters(transportRemoteParameters);
+
+ _this5._transportReady = true;
+ });
+ }
+ }]);
+ return SendHandler;
+}(Handler);
+
+var RecvHandler = function (_Handler2) {
+ (0, _inherits3.default)(RecvHandler, _Handler2);
+
+ function RecvHandler(rtpParametersByKind, settings) {
+ (0, _classCallCheck3.default)(this, RecvHandler);
+
+ // Got transport remote parameters.
+ // @type {Boolean}
+ var _this6 = (0, _possibleConstructorReturn3.default)(this, (RecvHandler.__proto__ || (0, _getPrototypeOf2.default)(RecvHandler)).call(this, 'recv', rtpParametersByKind, settings));
+
+ _this6._transportCreated = false;
+
+ // Got transport local parameters.
+ // @type {Boolean}
+ _this6._transportUpdated = false;
+
+ // Seen media kinds.
+ // @type {Set}
+ _this6._kinds = new _set2.default();
+
+ // Map of Consumers information indexed by consumer.id.
+ // - kind {String}
+ // - trackId {String}
+ // - ssrc {Number}
+ // - rtxSsrc {Number}
+ // - cname {String}
+ // @type {Map}
+ _this6._consumerInfos = new _map2.default();
+ return _this6;
+ }
+
+ (0, _createClass3.default)(RecvHandler, [{
+ key: 'addConsumer',
+ value: function addConsumer(consumer) {
+ var _this7 = this;
+
+ logger.debug('addConsumer() [id:%s, kind:%s]', consumer.id, consumer.kind);
+
+ if (this._consumerInfos.has(consumer.id)) return _promise2.default.reject('Consumer already added');
+
+ var encoding = consumer.rtpParameters.encodings[0];
+ var cname = consumer.rtpParameters.rtcp.cname;
+ var consumerInfo = {
+ kind: consumer.kind,
+ trackId: 'consumer-' + consumer.kind + '-' + consumer.id,
+ ssrc: encoding.ssrc,
+ cname: cname
+ };
+
+ if (encoding.rtx && encoding.rtx.ssrc) consumerInfo.rtxSsrc = encoding.rtx.ssrc;
+
+ this._consumerInfos.set(consumer.id, consumerInfo);
+ this._kinds.add(consumer.kind);
+
+ return _promise2.default.resolve().then(function () {
+ if (!_this7._transportCreated) return _this7._setupTransport();
+ }).then(function () {
+ var remoteSdp = _this7._remoteSdp.createOfferSdp((0, _from2.default)(_this7._kinds), (0, _from2.default)(_this7._consumerInfos.values()));
+ var offer = { type: 'offer', sdp: remoteSdp };
+
+ return _this7._pc.setRemoteDescription(offer);
+ }).then(function () {
+ return _this7._pc.createAnswer();
+ }).then(function (answer) {
+ return _this7._pc.setLocalDescription(answer);
+ }).then(function () {
+ if (!_this7._transportUpdated) return _this7._updateTransport();
+ }).then(function () {
+ var stream = _this7._pc.getRemoteStreams()[0];
+ var track = stream.getTrackById(consumerInfo.trackId);
+
+ if (!track) throw new Error('remote track not found');
+
+ return track;
+ });
+ }
+ }, {
+ key: 'removeConsumer',
+ value: function removeConsumer(consumer) {
+ var _this8 = this;
+
+ logger.debug('removeConsumer() [id:%s, kind:%s]', consumer.id, consumer.kind);
+
+ if (!this._consumerInfos.has(consumer.id)) return _promise2.default.reject('Consumer not found');
+
+ this._consumerInfos.delete(consumer.id);
+
+ return _promise2.default.resolve().then(function () {
+ var remoteSdp = _this8._remoteSdp.createOfferSdp((0, _from2.default)(_this8._kinds), (0, _from2.default)(_this8._consumerInfos.values()));
+ var offer = { type: 'offer', sdp: remoteSdp };
+
+ return _this8._pc.setRemoteDescription(offer);
+ }).then(function () {
+ return _this8._pc.createAnswer();
+ }).then(function (answer) {
+ return _this8._pc.setLocalDescription(answer);
+ });
+ }
+ }, {
+ key: '_setupTransport',
+ value: function _setupTransport() {
+ var _this9 = this;
+
+ logger.debug('_setupTransport()');
+
+ return _promise2.default.resolve().then(function () {
+ // We need transport remote parameters.
+ return _this9.safeEmitAsPromise('@needcreatetransport', null);
+ }).then(function (transportRemoteParameters) {
+ // Provide the remote SDP handler with transport remote parameters.
+ _this9._remoteSdp.setTransportRemoteParameters(transportRemoteParameters);
+
+ _this9._transportCreated = true;
+ });
+ }
+ }, {
+ key: '_updateTransport',
+ value: function _updateTransport() {
+ logger.debug('_updateTransport()');
+
+ // Get our local DTLS parameters.
+ // const transportLocalParameters = {};
+ var sdp = this._pc.localDescription.sdp;
+ var sdpObj = _sdpTransform2.default.parse(sdp);
+ var dtlsParameters = sdpCommonUtils.extractDtlsParameters(sdpObj);
+ var transportLocalParameters = { dtlsParameters: dtlsParameters };
+
+ // We need to provide transport local parameters.
+ this.safeEmit('@needupdatetransport', transportLocalParameters);
+
+ this._transportUpdated = true;
+ }
+ }]);
+ return RecvHandler;
+}(Handler);
+
+var Chrome55 = function () {
+ (0, _createClass3.default)(Chrome55, null, [{
+ key: 'getLocalRtpCapabilities',
+ value: function getLocalRtpCapabilities() {
+ logger.debug('getLocalRtpCapabilities()');
+
+ var pc = new RTCPeerConnection({
+ iceServers: [],
+ iceTransportPolicy: 'relay',
+ bundlePolicy: 'max-bundle',
+ rtcpMuxPolicy: 'require'
+ });
+
+ return pc.createOffer({
+ offerToReceiveAudio: true,
+ offerToReceiveVideo: true
+ }).then(function (offer) {
+ try {
+ pc.close();
+ } catch (error) {}
+
+ var sdpObj = _sdpTransform2.default.parse(offer.sdp);
+ var localRtpCapabilities = sdpCommonUtils.extractRtpCapabilities(sdpObj);
+
+ return localRtpCapabilities;
+ }).catch(function (error) {
+ try {
+ pc.close();
+ } catch (error2) {}
+
+ throw error;
+ });
+ }
+ }, {
+ key: 'name',
+ get: function get() {
+ return 'Chrome55';
+ }
+ }]);
+
+ function Chrome55(direction, extendedRtpCapabilities, settings) {
+ (0, _classCallCheck3.default)(this, Chrome55);
+
+ logger.debug('constructor() [direction:%s, extendedRtpCapabilities:%o]', direction, extendedRtpCapabilities);
+
+ var rtpParametersByKind = void 0;
+
+ switch (direction) {
+ case 'send':
+ {
+ rtpParametersByKind = {
+ audio: utils.getSendingRtpParameters('audio', extendedRtpCapabilities),
+ video: utils.getSendingRtpParameters('video', extendedRtpCapabilities)
+ };
+
+ return new SendHandler(rtpParametersByKind, settings);
+ }
+ case 'recv':
+ {
+ rtpParametersByKind = {
+ audio: utils.getReceivingFullRtpParameters('audio', extendedRtpCapabilities),
+ video: utils.getReceivingFullRtpParameters('video', extendedRtpCapabilities)
+ };
+
+ return new RecvHandler(rtpParametersByKind, settings);
+ }
+ }
+ }
+
+ return Chrome55;
+}();
+
+exports.default = Chrome55;
+
+},{"../EnhancedEventEmitter":"/Users/ibc/src/mediasoup-client/lib/EnhancedEventEmitter.js","../Logger":"/Users/ibc/src/mediasoup-client/lib/Logger.js","../utils":"/Users/ibc/src/mediasoup-client/lib/utils.js","./sdp/RemotePlanBSdp":"/Users/ibc/src/mediasoup-client/lib/handlers/sdp/RemotePlanBSdp.js","./sdp/commonUtils":"/Users/ibc/src/mediasoup-client/lib/handlers/sdp/commonUtils.js","./sdp/planBUtils":"/Users/ibc/src/mediasoup-client/lib/handlers/sdp/planBUtils.js","babel-runtime/core-js/array/from":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/array/from.js","babel-runtime/core-js/map":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/map.js","babel-runtime/core-js/object/get-prototype-of":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/object/get-prototype-of.js","babel-runtime/core-js/promise":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/promise.js","babel-runtime/core-js/set":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/set.js","babel-runtime/helpers/classCallCheck":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/classCallCheck.js","babel-runtime/helpers/createClass":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/createClass.js","babel-runtime/helpers/inherits":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/inherits.js","babel-runtime/helpers/possibleConstructorReturn":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/possibleConstructorReturn.js","sdp-transform":"/Users/ibc/src/mediasoup-client/node_modules/sdp-transform/lib/index.js"}],"/Users/ibc/src/mediasoup-client/lib/handlers/Edge11.js":[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _promise = require('babel-runtime/core-js/promise');
+
+var _promise2 = _interopRequireDefault(_promise);
+
+var _getIterator2 = require('babel-runtime/core-js/get-iterator');
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _map = require('babel-runtime/core-js/map');
+
+var _map2 = _interopRequireDefault(_map);
+
+var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
+
+var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
+
+var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _createClass2 = require('babel-runtime/helpers/createClass');
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _inherits2 = require('babel-runtime/helpers/inherits');
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _Logger = require('../Logger');
+
+var _Logger2 = _interopRequireDefault(_Logger);
+
+var _EnhancedEventEmitter2 = require('../EnhancedEventEmitter');
+
+var _EnhancedEventEmitter3 = _interopRequireDefault(_EnhancedEventEmitter2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+// import * as utils from '../utils';
+
+/* global RTCIceGatherer, RTCIceTransport, RTCDtlsTransport, RTCRtpReceiver */
+
+var logger = new _Logger2.default('Edge11');
+
+// const CNAME = `cname-${utils.randomNumber()}`;
+
+var Edge11 = function (_EnhancedEventEmitter) {
+ (0, _inherits3.default)(Edge11, _EnhancedEventEmitter);
+ (0, _createClass3.default)(Edge11, null, [{
+ key: 'getLocalRtpCapabilities',
+ value: function getLocalRtpCapabilities() {
+ logger.debug('getLocalRtpCapabilities()');
+
+ // TODO: Not enough since Edge does not set mimeType, etc.
+ return RTCRtpReceiver.getCapabilities();
+ }
+ }, {
+ key: 'name',
+ get: function get() {
+ return 'Edge11';
+ }
+ }]);
+
+ function Edge11(direction, extendedRtpCapabilities, settings) {
+ (0, _classCallCheck3.default)(this, Edge11);
+
+ logger.debug('constructor() [direction:%s, extendedRtpCapabilities:%o]', direction, extendedRtpCapabilities);
+
+ // Got transport local and remote parameters.
+ // @type {Boolean}
+ var _this = (0, _possibleConstructorReturn3.default)(this, (Edge11.__proto__ || (0, _getPrototypeOf2.default)(Edge11)).call(this));
+
+ _this._transportReady = false;
+
+ // ICE gatherer.
+ _this._iceGatherer = null;
+
+ // ICE transport.
+ _this._iceTransport = null;
+
+ // DTLS transport.
+ // @type {RTCDtlsTransport}
+ _this._dtlsTransport = null;
+
+ // Map of RTCRtpSenders indexed by Producer.id.
+ // @type {Map}
+ _this6._consumerInfos = new _map2.default();
+ return _this6;
+ }
+
+ (0, _createClass3.default)(RecvHandler, [{
+ key: 'addConsumer',
+ value: function addConsumer(consumer) {
+ var _this7 = this;
+
+ logger.debug('addConsumer() [id:%s, kind:%s]', consumer.id, consumer.kind);
+
+ if (this._consumerInfos.has(consumer.id)) return _promise2.default.reject('Consumer already added');
+
+ var encoding = consumer.rtpParameters.encodings[0];
+ var cname = consumer.rtpParameters.rtcp.cname;
+ var consumerInfo = {
+ mid: 'consumer-' + consumer.kind + '-' + consumer.id,
+ kind: consumer.kind,
+ closed: consumer.closed,
+ trackId: 'consumer-' + consumer.kind + '-' + consumer.id,
+ ssrc: encoding.ssrc,
+ cname: cname
+ };
+
+ if (encoding.rtx && encoding.rtx.ssrc) consumerInfo.rtxSsrc = encoding.rtx.ssrc;
+
+ this._consumerInfos.set(consumer.id, consumerInfo);
+
+ return _promise2.default.resolve().then(function () {
+ if (!_this7._transportCreated) return _this7._setupTransport();
+ }).then(function () {
+ var remoteSdp = _this7._remoteSdp.createOfferSdp((0, _from2.default)(_this7._consumerInfos.values()));
+ var offer = { type: 'offer', sdp: remoteSdp };
+
+ return _this7._pc.setRemoteDescription(offer);
+ }).then(function () {
+ return _this7._pc.createAnswer();
+ }).then(function (answer) {
+ return _this7._pc.setLocalDescription(answer);
+ }).then(function () {
+ if (!_this7._transportUpdated) return _this7._updateTransport();
+ }).then(function () {
+ var newRtpReceiver = _this7._pc.getReceivers().find(function (rtpReceiver) {
+ var track = rtpReceiver.track;
+
+
+ if (!track) return false;
+
+ return track.id === consumerInfo.trackId;
+ });
+
+ if (!newRtpReceiver) throw new Error('remote track not found');
+
+ return newRtpReceiver.track;
+ });
+ }
+ }, {
+ key: 'removeConsumer',
+ value: function removeConsumer(consumer) {
+ var _this8 = this;
+
+ // TODO: If this is the last active Consumer, Firefox will close the DTLS.
+ // This is noted in the TODO.md file.
+
+ logger.debug('removeConsumer() [id:%s, kind:%s]', consumer.id, consumer.kind);
+
+ var consumerInfo = this._consumerInfos.get(consumer.id);
+
+ if (!consumerInfo) return _promise2.default.reject('Consumer not found');
+
+ consumerInfo.closed = true;
+
+ return _promise2.default.resolve().then(function () {
+ var remoteSdp = _this8._remoteSdp.createOfferSdp((0, _from2.default)(_this8._consumerInfos.values()));
+ var offer = { type: 'offer', sdp: remoteSdp };
+
+ return _this8._pc.setRemoteDescription(offer);
+ }).then(function () {
+ return _this8._pc.createAnswer();
+ }).then(function (answer) {
+ return _this8._pc.setLocalDescription(answer);
+ });
+ }
+ }, {
+ key: '_setupTransport',
+ value: function _setupTransport() {
+ var _this9 = this;
+
+ logger.debug('_setupTransport()');
+
+ return _promise2.default.resolve().then(function () {
+ // We need transport remote parameters.
+ return _this9.safeEmitAsPromise('@needcreatetransport', null);
+ }).then(function (transportRemoteParameters) {
+ // Provide the remote SDP handler with transport remote parameters.
+ _this9._remoteSdp.setTransportRemoteParameters(transportRemoteParameters);
+
+ _this9._transportCreated = true;
+ });
+ }
+ }, {
+ key: '_updateTransport',
+ value: function _updateTransport() {
+ logger.debug('_updateTransport()');
+
+ // Get our local DTLS parameters.
+ // const transportLocalParameters = {};
+ var sdp = this._pc.localDescription.sdp;
+ var sdpObj = _sdpTransform2.default.parse(sdp);
+ var dtlsParameters = sdpCommonUtils.extractDtlsParameters(sdpObj);
+ var transportLocalParameters = { dtlsParameters: dtlsParameters };
+
+ // We need to provide transport local parameters.
+ this.safeEmit('@needupdatetransport', transportLocalParameters);
+
+ this._transportUpdated = true;
+ }
+ }]);
+ return RecvHandler;
+}(Handler);
+
+var Firefox50 = function () {
+ (0, _createClass3.default)(Firefox50, null, [{
+ key: 'getLocalRtpCapabilities',
+ value: function getLocalRtpCapabilities() {
+ logger.debug('getLocalRtpCapabilities()');
+
+ var pc = new RTCPeerConnection({
+ iceServers: [],
+ iceTransportPolicy: 'relay',
+ bundlePolicy: 'max-bundle',
+ rtcpMuxPolicy: 'require'
+ });
+
+ return pc.createOffer({
+ offerToReceiveAudio: true,
+ offerToReceiveVideo: true
+ }).then(function (offer) {
+ try {
+ pc.close();
+ } catch (error) {}
+
+ var sdpObj = _sdpTransform2.default.parse(offer.sdp);
+ var localRtpCapabilities = sdpCommonUtils.extractRtpCapabilities(sdpObj);
+
+ return localRtpCapabilities;
+ }).catch(function (error) {
+ try {
+ pc.close();
+ } catch (error2) {}
+
+ throw error;
+ });
+ }
+ }, {
+ key: 'name',
+ get: function get() {
+ return 'Firefox50';
+ }
+ }]);
+
+ function Firefox50(direction, extendedRtpCapabilities, settings) {
+ (0, _classCallCheck3.default)(this, Firefox50);
+
+ logger.debug('constructor() [direction:%s, extendedRtpCapabilities:%o]', direction, extendedRtpCapabilities);
+
+ var rtpParametersByKind = void 0;
+
+ switch (direction) {
+ case 'send':
+ {
+ rtpParametersByKind = {
+ audio: utils.getSendingRtpParameters('audio', extendedRtpCapabilities),
+ video: utils.getSendingRtpParameters('video', extendedRtpCapabilities)
+ };
+
+ return new SendHandler(rtpParametersByKind, settings);
+ }
+ case 'recv':
+ {
+ rtpParametersByKind = {
+ audio: utils.getReceivingFullRtpParameters('audio', extendedRtpCapabilities),
+ video: utils.getReceivingFullRtpParameters('video', extendedRtpCapabilities)
+ };
+
+ return new RecvHandler(rtpParametersByKind, settings);
+ }
+ }
+ }
+
+ return Firefox50;
+}();
+
+exports.default = Firefox50;
+
+},{"../EnhancedEventEmitter":"/Users/ibc/src/mediasoup-client/lib/EnhancedEventEmitter.js","../Logger":"/Users/ibc/src/mediasoup-client/lib/Logger.js","../utils":"/Users/ibc/src/mediasoup-client/lib/utils.js","./sdp/RemoteUnifiedPlanSdp":"/Users/ibc/src/mediasoup-client/lib/handlers/sdp/RemoteUnifiedPlanSdp.js","./sdp/commonUtils":"/Users/ibc/src/mediasoup-client/lib/handlers/sdp/commonUtils.js","./sdp/unifiedPlanUtils":"/Users/ibc/src/mediasoup-client/lib/handlers/sdp/unifiedPlanUtils.js","babel-runtime/core-js/array/from":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/array/from.js","babel-runtime/core-js/map":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/map.js","babel-runtime/core-js/object/get-prototype-of":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/object/get-prototype-of.js","babel-runtime/core-js/promise":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/promise.js","babel-runtime/helpers/classCallCheck":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/classCallCheck.js","babel-runtime/helpers/createClass":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/createClass.js","babel-runtime/helpers/inherits":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/inherits.js","babel-runtime/helpers/possibleConstructorReturn":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/possibleConstructorReturn.js","sdp-transform":"/Users/ibc/src/mediasoup-client/node_modules/sdp-transform/lib/index.js"}],"/Users/ibc/src/mediasoup-client/lib/handlers/Safari11.js":[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _from = require('babel-runtime/core-js/array/from');
+
+var _from2 = _interopRequireDefault(_from);
+
+var _map = require('babel-runtime/core-js/map');
+
+var _map2 = _interopRequireDefault(_map);
+
+var _set = require('babel-runtime/core-js/set');
+
+var _set2 = _interopRequireDefault(_set);
+
+var _promise = require('babel-runtime/core-js/promise');
+
+var _promise2 = _interopRequireDefault(_promise);
+
+var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
+
+var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
+
+var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _createClass2 = require('babel-runtime/helpers/createClass');
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require('babel-runtime/helpers/inherits');
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _sdpTransform = require('sdp-transform');
+
+var _sdpTransform2 = _interopRequireDefault(_sdpTransform);
+
+var _Logger = require('../Logger');
+
+var _Logger2 = _interopRequireDefault(_Logger);
+
+var _EnhancedEventEmitter2 = require('../EnhancedEventEmitter');
+
+var _EnhancedEventEmitter3 = _interopRequireDefault(_EnhancedEventEmitter2);
+
+var _utils = require('../utils');
+
+var utils = _interopRequireWildcard(_utils);
+
+var _commonUtils = require('./sdp/commonUtils');
+
+var sdpCommonUtils = _interopRequireWildcard(_commonUtils);
+
+var _planBUtils = require('./sdp/planBUtils');
+
+var sdpPlanBUtils = _interopRequireWildcard(_planBUtils);
+
+var _RemotePlanBSdp = require('./sdp/RemotePlanBSdp');
+
+var _RemotePlanBSdp2 = _interopRequireDefault(_RemotePlanBSdp);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var logger = new _Logger2.default('Safari11');
+
+var Handler = function (_EnhancedEventEmitter) {
+ (0, _inherits3.default)(Handler, _EnhancedEventEmitter);
+
+ function Handler(direction, rtpParametersByKind, settings) {
+ (0, _classCallCheck3.default)(this, Handler);
+
+ // RTCPeerConnection instance.
+ // @type {RTCPeerConnection}
+ var _this = (0, _possibleConstructorReturn3.default)(this, (Handler.__proto__ || (0, _getPrototypeOf2.default)(Handler)).call(this));
+
+ _this._pc = new RTCPeerConnection({
+ iceServers: settings.turnServers || [],
+ iceTransportPolicy: 'relay',
+ bundlePolicy: 'max-bundle',
+ rtcpMuxPolicy: 'require'
+ });
+
+ // Generic sending RTP parameters for audio and video.
+ // @type {Object}
+ _this._rtpParametersByKind = rtpParametersByKind;
+
+ // Remote SDP handler.
+ // @type {RemotePlanBSdp}
+ _this._remoteSdp = new _RemotePlanBSdp2.default(direction, rtpParametersByKind);
+
+ // Handle RTCPeerConnection connection status.
+ _this._pc.addEventListener('iceconnectionstatechange', function () {
+ switch (_this._pc.iceConnectionState) {
+ case 'checking':
+ _this.emit('@connectionstatechange', 'connecting');
+ break;
+ case 'connected':
+ case 'completed':
+ _this.emit('@connectionstatechange', 'connected');
+ break;
+ case 'failed':
+ _this.emit('@connectionstatechange', 'failed');
+ break;
+ case 'disconnected':
+ _this.emit('@connectionstatechange', 'disconnected');
+ break;
+ case 'closed':
+ _this.emit('@connectionstatechange', 'closed');
+ break;
+ }
+ });
+ return _this;
+ }
+
+ (0, _createClass3.default)(Handler, [{
+ key: 'close',
+ value: function close() {
+ logger.debug('close()');
+
+ // Close RTCPeerConnection.
+ try {
+ this._pc.close();
+ } catch (error) {}
+ }
+ }]);
+ return Handler;
+}(_EnhancedEventEmitter3.default);
+
+var SendHandler = function (_Handler) {
+ (0, _inherits3.default)(SendHandler, _Handler);
+
+ function SendHandler(rtpParametersByKind, settings) {
+ (0, _classCallCheck3.default)(this, SendHandler);
+
+ // Got transport local and remote parameters.
+ // @type {Boolean}
+ var _this2 = (0, _possibleConstructorReturn3.default)(this, (SendHandler.__proto__ || (0, _getPrototypeOf2.default)(SendHandler)).call(this, 'send', rtpParametersByKind, settings));
+
+ _this2._transportReady = false;
+
+ // Local stream.
+ // @type {MediaStream}
+ _this2._stream = new MediaStream();
+ return _this2;
+ }
+
+ (0, _createClass3.default)(SendHandler, [{
+ key: 'addProducer',
+ value: function addProducer(producer) {
+ var _this3 = this;
+
+ var track = producer.track;
+
+
+ logger.debug('addProducer() [id:%s, kind:%s, trackId:%s]', producer.id, producer.kind, track.id);
+
+ var rtpSender = void 0;
+ var localSdpObj = void 0;
+
+ return _promise2.default.resolve().then(function () {
+ _this3._stream.addTrack(track);
+
+ // Add the stream to the PeerConnection.
+ rtpSender = _this3._pc.addTrack(track, _this3._stream);
+
+ return _this3._pc.createOffer();
+ }).then(function (offer) {
+ return _this3._pc.setLocalDescription(offer);
+ }).then(function () {
+ if (!_this3._transportReady) return _this3._setupTransport();
+ }).then(function () {
+ localSdpObj = _sdpTransform2.default.parse(_this3._pc.localDescription.sdp);
+
+ var remoteSdp = _this3._remoteSdp.createAnswerSdp(localSdpObj);
+ var answer = { type: 'answer', sdp: remoteSdp };
+
+ return _this3._pc.setRemoteDescription(answer);
+ }).then(function () {
+ var rtpParameters = utils.clone(_this3._rtpParametersByKind[producer.kind]);
+
+ // Fill the RTP parameters for this track.
+ sdpPlanBUtils.fillRtpParametersForTrack(rtpParameters, localSdpObj, track);
+
+ return rtpParameters;
+ }).catch(function (error) {
+ // Panic here. Try to undo things.
+
+ try {
+ _this3._pc.removeTrack(rtpSender);
+ } catch (error2) {}
+
+ _this3._stream.removeTrack(track);
+
+ throw error;
+ });
+ }
+ }, {
+ key: 'removeProducer',
+ value: function removeProducer(producer) {
+ var _this4 = this;
+
+ var track = producer.track;
+
+
+ logger.debug('removeProducer() [id:%s, kind:%s, trackId:%s]', producer.id, producer.kind, track.id);
+
+ return _promise2.default.resolve().then(function () {
+ // Get the associated RTCRtpSender.
+ var rtpSender = _this4._pc.getSenders().find(function (s) {
+ return s.track === track;
+ });
+
+ if (!rtpSender) throw new Error('local track not found');
+
+ // Remove the associated RtpSender.
+ _this4._pc.removeTrack(rtpSender);
+
+ // Remove the track from the local stream.
+ _this4._stream.removeTrack(track);
+
+ return _this4._pc.createOffer();
+ }).then(function (offer) {
+ return _this4._pc.setLocalDescription(offer);
+ }).catch(function (error) {
+ // NOTE: If there are no sending tracks, setLocalDescription() will fail with
+ // "Failed to create channels". If so, ignore it.
+ if (_this4._stream.getTracks().length === 0) {
+ logger.warn('removeLocalTrack() | ignoring expected error due no sending tracks: %s', error.toString());
+
+ return;
+ }
+
+ throw error;
+ }).then(function () {
+ if (_this4._pc.signalingState === 'stable') return;
+
+ var localSdpObj = _sdpTransform2.default.parse(_this4._pc.localDescription.sdp);
+ var remoteSdp = _this4._remoteSdp.createAnswerSdp(localSdpObj);
+ var answer = { type: 'answer', sdp: remoteSdp };
+
+ return _this4._pc.setRemoteDescription(answer);
+ });
+ }
+ }, {
+ key: '_setupTransport',
+ value: function _setupTransport() {
+ var _this5 = this;
+
+ logger.debug('_setupTransport()');
+
+ return _promise2.default.resolve().then(function () {
+ // Get our local DTLS parameters.
+ var transportLocalParameters = {};
+ var sdp = _this5._pc.localDescription.sdp;
+ var sdpObj = _sdpTransform2.default.parse(sdp);
+ var dtlsParameters = sdpCommonUtils.extractDtlsParameters(sdpObj);
+
+ // Let's decide that we'll be DTLS server (because we can).
+ dtlsParameters.role = 'server';
+
+ transportLocalParameters.dtlsParameters = dtlsParameters;
+
+ // Provide the remote SDP handler with transport local parameters.
+ _this5._remoteSdp.setTransportLocalParameters(transportLocalParameters);
+
+ // We need transport remote parameters.
+ return _this5.safeEmitAsPromise('@needcreatetransport', transportLocalParameters);
+ }).then(function (transportRemoteParameters) {
+ // Provide the remote SDP handler with transport remote parameters.
+ _this5._remoteSdp.setTransportRemoteParameters(transportRemoteParameters);
+
+ _this5._transportReady = true;
+ });
+ }
+ }]);
+ return SendHandler;
+}(Handler);
+
+var RecvHandler = function (_Handler2) {
+ (0, _inherits3.default)(RecvHandler, _Handler2);
+
+ function RecvHandler(rtpParametersByKind, settings) {
+ (0, _classCallCheck3.default)(this, RecvHandler);
+
+ // Got transport remote parameters.
+ // @type {Boolean}
+ var _this6 = (0, _possibleConstructorReturn3.default)(this, (RecvHandler.__proto__ || (0, _getPrototypeOf2.default)(RecvHandler)).call(this, 'recv', rtpParametersByKind, settings));
+
+ _this6._transportCreated = false;
+
+ // Got transport local parameters.
+ // @type {Boolean}
+ _this6._transportUpdated = false;
+
+ // Seen media kinds.
+ // @type {Set}
+ _this6._kinds = new _set2.default();
+
+ // Map of Consumers information indexed by consumer.id.
+ // - kind {String}
+ // - trackId {String}
+ // - ssrc {Number}
+ // - rtxSsrc {Number}
+ // - cname {String}
+ // @type {Map}
+ _this6._consumerInfos = new _map2.default();
+ return _this6;
+ }
+
+ (0, _createClass3.default)(RecvHandler, [{
+ key: 'addConsumer',
+ value: function addConsumer(consumer) {
+ var _this7 = this;
+
+ logger.debug('addConsumer() [id:%s, kind:%s]', consumer.id, consumer.kind);
+
+ if (this._consumerInfos.has(consumer.id)) return _promise2.default.reject('Consumer already added');
+
+ var encoding = consumer.rtpParameters.encodings[0];
+ var cname = consumer.rtpParameters.rtcp.cname;
+ var consumerInfo = {
+ kind: consumer.kind,
+ trackId: 'consumer-' + consumer.kind + '-' + consumer.id,
+ ssrc: encoding.ssrc,
+ cname: cname
+ };
+
+ if (encoding.rtx && encoding.rtx.ssrc) consumerInfo.rtxSsrc = encoding.rtx.ssrc;
+
+ this._consumerInfos.set(consumer.id, consumerInfo);
+ this._kinds.add(consumer.kind);
+
+ return _promise2.default.resolve().then(function () {
+ if (!_this7._transportCreated) return _this7._setupTransport();
+ }).then(function () {
+ var remoteSdp = _this7._remoteSdp.createOfferSdp((0, _from2.default)(_this7._kinds), (0, _from2.default)(_this7._consumerInfos.values()));
+ var offer = { type: 'offer', sdp: remoteSdp };
+
+ return _this7._pc.setRemoteDescription(offer);
+ }).then(function () {
+ return _this7._pc.createAnswer();
+ }).then(function (answer) {
+ return _this7._pc.setLocalDescription(answer);
+ }).then(function () {
+ if (!_this7._transportUpdated) return _this7._updateTransport();
+ }).then(function () {
+ var newRtpReceiver = _this7._pc.getReceivers().find(function (rtpReceiver) {
+ var track = rtpReceiver.track;
+
+
+ if (!track) return false;
+
+ return track.id === consumerInfo.trackId;
+ });
+
+ if (!newRtpReceiver) throw new Error('remote track not found');
+
+ return newRtpReceiver.track;
+ });
+ }
+ }, {
+ key: 'removeConsumer',
+ value: function removeConsumer(consumer) {
+ var _this8 = this;
+
+ logger.debug('removeConsumer() [id:%s, kind:%s]', consumer.id, consumer.kind);
+
+ if (!this._consumerInfos.has(consumer.id)) return _promise2.default.reject('Consumer not found');
+
+ this._consumerInfos.delete(consumer.id);
+
+ return _promise2.default.resolve().then(function () {
+ var remoteSdp = _this8._remoteSdp.createOfferSdp((0, _from2.default)(_this8._kinds), (0, _from2.default)(_this8._consumerInfos.values()));
+ var offer = { type: 'offer', sdp: remoteSdp };
+
+ return _this8._pc.setRemoteDescription(offer);
+ }).then(function () {
+ return _this8._pc.createAnswer();
+ }).then(function (answer) {
+ return _this8._pc.setLocalDescription(answer);
+ });
+ }
+ }, {
+ key: '_setupTransport',
+ value: function _setupTransport() {
+ var _this9 = this;
+
+ logger.debug('_setupTransport()');
+
+ return _promise2.default.resolve().then(function () {
+ // We need transport remote parameters.
+ return _this9.safeEmitAsPromise('@needcreatetransport', null);
+ }).then(function (transportRemoteParameters) {
+ // Provide the remote SDP handler with transport remote parameters.
+ _this9._remoteSdp.setTransportRemoteParameters(transportRemoteParameters);
+
+ _this9._transportCreated = true;
+ });
+ }
+ }, {
+ key: '_updateTransport',
+ value: function _updateTransport() {
+ logger.debug('_updateTransport()');
+
+ // Get our local DTLS parameters.
+ // const transportLocalParameters = {};
+ var sdp = this._pc.localDescription.sdp;
+ var sdpObj = _sdpTransform2.default.parse(sdp);
+ var dtlsParameters = sdpCommonUtils.extractDtlsParameters(sdpObj);
+ var transportLocalParameters = { dtlsParameters: dtlsParameters };
+
+ // We need to provide transport local parameters.
+ this.safeEmit('@needupdatetransport', transportLocalParameters);
+
+ this._transportUpdated = true;
+ }
+ }]);
+ return RecvHandler;
+}(Handler);
+
+var Safari11 = function () {
+ (0, _createClass3.default)(Safari11, null, [{
+ key: 'getLocalRtpCapabilities',
+ value: function getLocalRtpCapabilities() {
+ logger.debug('getLocalRtpCapabilities()');
+
+ var pc = new RTCPeerConnection({
+ iceServers: [],
+ iceTransportPolicy: 'relay',
+ bundlePolicy: 'max-bundle',
+ rtcpMuxPolicy: 'require'
+ });
+
+ pc.addTransceiver('audio');
+ pc.addTransceiver('video');
+
+ return pc.createOffer().then(function (offer) {
+ try {
+ pc.close();
+ } catch (error) {}
+
+ var sdpObj = _sdpTransform2.default.parse(offer.sdp);
+ var localRtpCapabilities = sdpCommonUtils.extractRtpCapabilities(sdpObj);
+
+ return localRtpCapabilities;
+ }).catch(function (error) {
+ try {
+ pc.close();
+ } catch (error2) {}
+
+ throw error;
+ });
+ }
+ }, {
+ key: 'name',
+ get: function get() {
+ return 'Safari11';
+ }
+ }]);
+
+ function Safari11(direction, extendedRtpCapabilities, settings) {
+ (0, _classCallCheck3.default)(this, Safari11);
+
+ logger.debug('constructor() [direction:%s, extendedRtpCapabilities:%o]', direction, extendedRtpCapabilities);
+
+ var rtpParametersByKind = void 0;
+
+ switch (direction) {
+ case 'send':
+ {
+ rtpParametersByKind = {
+ audio: utils.getSendingRtpParameters('audio', extendedRtpCapabilities),
+ video: utils.getSendingRtpParameters('video', extendedRtpCapabilities)
+ };
+
+ return new SendHandler(rtpParametersByKind, settings);
+ }
+ case 'recv':
+ {
+ rtpParametersByKind = {
+ audio: utils.getReceivingFullRtpParameters('audio', extendedRtpCapabilities),
+ video: utils.getReceivingFullRtpParameters('video', extendedRtpCapabilities)
+ };
+
+ return new RecvHandler(rtpParametersByKind, settings);
+ }
+ }
+ }
+
+ return Safari11;
+}();
+
+exports.default = Safari11;
+
+},{"../EnhancedEventEmitter":"/Users/ibc/src/mediasoup-client/lib/EnhancedEventEmitter.js","../Logger":"/Users/ibc/src/mediasoup-client/lib/Logger.js","../utils":"/Users/ibc/src/mediasoup-client/lib/utils.js","./sdp/RemotePlanBSdp":"/Users/ibc/src/mediasoup-client/lib/handlers/sdp/RemotePlanBSdp.js","./sdp/commonUtils":"/Users/ibc/src/mediasoup-client/lib/handlers/sdp/commonUtils.js","./sdp/planBUtils":"/Users/ibc/src/mediasoup-client/lib/handlers/sdp/planBUtils.js","babel-runtime/core-js/array/from":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/array/from.js","babel-runtime/core-js/map":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/map.js","babel-runtime/core-js/object/get-prototype-of":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/object/get-prototype-of.js","babel-runtime/core-js/promise":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/promise.js","babel-runtime/core-js/set":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/core-js/set.js","babel-runtime/helpers/classCallCheck":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/classCallCheck.js","babel-runtime/helpers/createClass":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/createClass.js","babel-runtime/helpers/inherits":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/inherits.js","babel-runtime/helpers/possibleConstructorReturn":"/Users/ibc/src/mediasoup-client/node_modules/babel-runtime/helpers/possibleConstructorReturn.js","sdp-transform":"/Users/ibc/src/mediasoup-client/node_modules/sdp-transform/lib/index.js"}],"/Users/ibc/src/mediasoup-client/lib/handlers/sdp/RemotePlanBSdp.js":[function(require,module,exports){
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+
+var _keys = require('babel-runtime/core-js/object/keys');
+
+var _keys2 = _interopRequireDefault(_keys);
+
+var _getIterator2 = require('babel-runtime/core-js/get-iterator');
+
+var _getIterator3 = _interopRequireDefault(_getIterator2);
+
+var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
+
+var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
+
+var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
+
+var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
+
+var _inherits2 = require('babel-runtime/helpers/inherits');
+
+var _inherits3 = _interopRequireDefault(_inherits2);
+
+var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
+
+var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
+
+var _createClass2 = require('babel-runtime/helpers/createClass');
+
+var _createClass3 = _interopRequireDefault(_createClass2);
+
+var _sdpTransform = require('sdp-transform');
+
+var _sdpTransform2 = _interopRequireDefault(_sdpTransform);
+
+var _Logger = require('../../Logger');
+
+var _Logger2 = _interopRequireDefault(_Logger);
+
+var _utils = require('../../utils');
+
+var utils = _interopRequireWildcard(_utils);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+var logger = new _Logger2.default('RemotePlanBSdp');
+
+var RemoteSdp = function () {
+ function RemoteSdp(rtpParametersByKind) {
+ (0, _classCallCheck3.default)(this, RemoteSdp);
+
+ // Generic sending RTP parameters for audio and video.
+ // @type {Object}
+ this._rtpParametersByKind = rtpParametersByKind;
+
+ // Transport local parameters, including DTLS parameteres.
+ // @type {Object}
+ this._transportLocalParameters = null;
+
+ // Transport remote parameters, including ICE parameters, ICE candidates
+ // and DTLS parameteres.
+ // @type {Object}
+ this._transportRemoteParameters = null;
+
+ // SDP global fields.
+ // @type {Object}
+ this._sdpGlobalFields = {
+ id: utils.randomNumber(),
+ version: 0
+ };
+ }
+
+ (0, _createClass3.default)(RemoteSdp, [{
+ key: 'setTransportLocalParameters',
+ value: function setTransportLocalParameters(transportLocalParameters) {
+ logger.debug('setTransportLocalParameters() [transportLocalParameters:%o]', transportLocalParameters);
+
+ this._transportLocalParameters = transportLocalParameters;
+ }
+ }, {
+ key: 'setTransportRemoteParameters',
+ value: function setTransportRemoteParameters(transportRemoteParameters) {
+ logger.debug('setTransportRemoteParameters() [transportRemoteParameters:%o]', transportRemoteParameters);
+
+ this._transportRemoteParameters = transportRemoteParameters;
+ }
+ }]);
+ return RemoteSdp;
+}();
+
+var SendRemoteSdp = function (_RemoteSdp) {
+ (0, _inherits3.default)(SendRemoteSdp, _RemoteSdp);
+
+ function SendRemoteSdp(rtpParametersByKind) {
+ (0, _classCallCheck3.default)(this, SendRemoteSdp);
+ return (0, _possibleConstructorReturn3.default)(this, (SendRemoteSdp.__proto__ || (0, _getPrototypeOf2.default)(SendRemoteSdp)).call(this, rtpParametersByKind));
+ }
+
+ (0, _createClass3.default)(SendRemoteSdp, [{
+ key: 'createAnswerSdp',
+ value: function createAnswerSdp(localSdpObj) {
+ logger.debug('createAnswerSdp()');
+
+ if (!this._transportLocalParameters) throw new Error('no transport local parameters');else if (!this._transportRemoteParameters) throw new Error('no transport remote parameters');
+
+ var localDtlsParameters = this._transportLocalParameters.dtlsParameters;
+ var remoteIceParameters = this._transportRemoteParameters.iceParameters;
+ var remoteIceCandidates = this._transportRemoteParameters.iceCandidates;
+ var remoteDtlsParameters = this._transportRemoteParameters.dtlsParameters;
+ var sdpObj = {};
+ var mids = (localSdpObj.media || []).map(function (m) {
+ return m.mid;
+ });
+
+ // Increase our SDP version.
+ this._sdpGlobalFields.version++;
+
+ sdpObj.version = 0;
+ sdpObj.origin = {
+ address: '0.0.0.0',
+ ipVer: 4,
+ netType: 'IN',
+ sessionId: this._sdpGlobalFields.id,
+ sessionVersion: this._sdpGlobalFields.version,
+ username: 'mediasoup-client'
+ };
+ sdpObj.name = '-';
+ sdpObj.timing = { start: 0, stop: 0 };
+ sdpObj.icelite = remoteIceParameters.iceLite ? 'ice-lite' : null;
+ sdpObj.msidSemantic = {
+ semantic: 'WMS',
+ token: '*'
+ };
+ sdpObj.groups = [{
+ type: 'BUNDLE',
+ mids: mids.join(' ')
+ }];
+ sdpObj.media = [];
+
+ sdpObj.fingerprint = {
+ type: remoteDtlsParameters.fingerprints[0].algorithm,
+ hash: remoteDtlsParameters.fingerprints[0].value
+ };
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = (0, _getIterator3.default)(localSdpObj.media || []), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var localMediaObj = _step.value;
+
+ var kind = localMediaObj.type;
+ var codecs = this._rtpParametersByKind[kind].codecs;
+ var headerExtensions = this._rtpParametersByKind[kind].headerExtensions;
+ var remoteMediaObj = {};
+
+ remoteMediaObj.type = localMediaObj.type;
+ remoteMediaObj.port = 7;
+ remoteMediaObj.protocol = 'RTP/SAVPF';
+ remoteMediaObj.connection = { ip: '127.0.0.1', version: 4 };
+ remoteMediaObj.mid = localMediaObj.mid;
+
+ remoteMediaObj.iceUfrag = remoteIceParameters.usernameFragment;
+ remoteMediaObj.icePwd = remoteIceParameters.password;
+ remoteMediaObj.candidates = [];
+
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+ for (var _iterator2 = (0, _getIterator3.default)(remoteIceCandidates), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var candidate = _step2.value;
+
+ var candidateObj = {};
+
+ // mediasoup does not support non rtcp-mux so candidates component is
+ // always RTP (1).
+ candidateObj.component = 1;
+ candidateObj.foundation = candidate.foundation;
+ candidateObj.ip = candidate.ip;
+ candidateObj.port = candidate.port;
+ candidateObj.priority = candidate.priority;
+ candidateObj.transport = candidate.protocol;
+ candidateObj.type = candidate.type;
+ if (candidate.tcpType) candidateObj.tcptype = candidate.tcpType;
+
+ remoteMediaObj.candidates.push(candidateObj);
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ remoteMediaObj.endOfCandidates = 'end-of-candidates';
+
+ // Announce support for ICE renomination.
+ // https://tools.ietf.org/html/draft-thatcher-ice-renomination
+ remoteMediaObj.iceOptions = 'renomination';
+
+ switch (localDtlsParameters.role) {
+ case 'client':
+ remoteMediaObj.setup = 'active';
+ break;
+ case 'server':
+ remoteMediaObj.setup = 'passive';
+ break;
+ }
+
+ switch (localMediaObj.direction) {
+ case 'sendrecv':
+ case 'sendonly':
+ remoteMediaObj.direction = 'recvonly';
+ break;
+ case 'recvonly':
+ case 'inactive':
+ remoteMediaObj.direction = 'inactive';
+ break;
+ }
+
+ remoteMediaObj.rtp = [];
+ remoteMediaObj.rtcpFb = [];
+ remoteMediaObj.fmtp = [];
+
+ var _iteratorNormalCompletion3 = true;
+ var _didIteratorError3 = false;
+ var _iteratorError3 = undefined;
+
+ try {
+ for (var _iterator3 = (0, _getIterator3.default)(codecs), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
+ var codec = _step3.value;
+
+ var rtp = {
+ payload: codec.payloadType,
+ codec: codec.name,
+ rate: codec.clockRate
+ };
+
+ if (codec.channels > 1) rtp.encoding = codec.channels;
+
+ remoteMediaObj.rtp.push(rtp);
+
+ if (codec.parameters) {
+ var paramFmtp = {
+ payload: codec.payloadType,
+ config: ''
+ };
+
+ var _iteratorNormalCompletion5 = true;
+ var _didIteratorError5 = false;
+ var _iteratorError5 = undefined;
+
+ try {
+ for (var _iterator5 = (0, _getIterator3.default)((0, _keys2.default)(codec.parameters)), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
+ var key = _step5.value;
+
+ if (paramFmtp.config) paramFmtp.config += ';';
+
+ paramFmtp.config += key + '=' + codec.parameters[key];
+ }
+ } catch (err) {
+ _didIteratorError5 = true;
+ _iteratorError5 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion5 && _iterator5.return) {
+ _iterator5.return();
+ }
+ } finally {
+ if (_didIteratorError5) {
+ throw _iteratorError5;
+ }
+ }
+ }
+
+ if (paramFmtp.config) remoteMediaObj.fmtp.push(paramFmtp);
+ }
+
+ if (codec.rtcpFeedback) {
+ var _iteratorNormalCompletion6 = true;
+ var _didIteratorError6 = false;
+ var _iteratorError6 = undefined;
+
+ try {
+ for (var _iterator6 = (0, _getIterator3.default)(codec.rtcpFeedback), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
+ var fb = _step6.value;
+
+ remoteMediaObj.rtcpFb.push({
+ payload: codec.payloadType,
+ type: fb.type,
+ subtype: fb.parameter
+ });
+ }
+ } catch (err) {
+ _didIteratorError6 = true;
+ _iteratorError6 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion6 && _iterator6.return) {
+ _iterator6.return();
+ }
+ } finally {
+ if (_didIteratorError6) {
+ throw _iteratorError6;
+ }
+ }
+ }
+ }
+ }
+ } catch (err) {
+ _didIteratorError3 = true;
+ _iteratorError3 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion3 && _iterator3.return) {
+ _iterator3.return();
+ }
+ } finally {
+ if (_didIteratorError3) {
+ throw _iteratorError3;
+ }
+ }
+ }
+
+ remoteMediaObj.payloads = codecs.map(function (codec) {
+ return codec.payloadType;
+ }).join(' ');
+
+ remoteMediaObj.ext = [];
+
+ var _iteratorNormalCompletion4 = true;
+ var _didIteratorError4 = false;
+ var _iteratorError4 = undefined;
+
+ try {
+ for (var _iterator4 = (0, _getIterator3.default)(headerExtensions), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
+ var ext = _step4.value;
+
+ remoteMediaObj.ext.push({
+ uri: ext.uri,
+ value: ext.id
+ });
+ }
+ } catch (err) {
+ _didIteratorError4 = true;
+ _iteratorError4 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion4 && _iterator4.return) {
+ _iterator4.return();
+ }
+ } finally {
+ if (_didIteratorError4) {
+ throw _iteratorError4;
+ }
+ }
+ }
+
+ remoteMediaObj.rtcpMux = 'rtcp-mux';
+ remoteMediaObj.rtcpRsize = 'rtcp-rsize';
+
+ // Push it.
+ sdpObj.media.push(remoteMediaObj);
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ var sdp = _sdpTransform2.default.write(sdpObj);
+
+ return sdp;
+ }
+ }]);
+ return SendRemoteSdp;
+}(RemoteSdp);
+
+var RecvRemoteSdp = function (_RemoteSdp2) {
+ (0, _inherits3.default)(RecvRemoteSdp, _RemoteSdp2);
+
+ function RecvRemoteSdp(rtpParametersByKind) {
+ (0, _classCallCheck3.default)(this, RecvRemoteSdp);
+
+ // Id of the unique MediaStream for all the remote tracks.
+ var _this2 = (0, _possibleConstructorReturn3.default)(this, (RecvRemoteSdp.__proto__ || (0, _getPrototypeOf2.default)(RecvRemoteSdp)).call(this, rtpParametersByKind));
+
+ _this2._streamId = 'recv-stream-' + utils.randomNumber();
+ return _this2;
+ }
+
+ /**
+ * @param {Array} kinds - Media kinds.
+ * @param {Array