From 246834c0f1b700ad76d44509e800ba9301cc7eaf Mon Sep 17 00:00:00 2001 From: charliesantos Date: Wed, 24 May 2023 12:18:39 -0700 Subject: [PATCH 01/12] VBLOCKS-1716 | Convert JS pipeline to TS --- .babelrc | 4 - .circleci/config.yml | 2 +- .eslintrc | 108 --------- .gitignore | 2 +- .npmignore | 2 + .release.json | 6 +- karma.conf.ts | 4 +- lib/browser.js | 1 - lib/twilio/audiohelper.ts | 7 +- lib/twilio/call.ts | 8 +- lib/twilio/device.ts | 13 +- .../{eventpublisher.js => eventpublisher.ts} | 83 ++++--- lib/twilio/preflight/preflight.ts | 2 +- lib/twilio/{pstream.js => pstream.ts} | 59 ++--- lib/twilio/{request.js => request.ts} | 14 +- .../rtc/{getusermedia.js => getusermedia.ts} | 12 +- lib/twilio/rtc/index.js | 16 -- lib/twilio/rtc/index.ts | 22 ++ ...tcstatsreport.js => mockrtcstatsreport.ts} | 219 +++++++++--------- .../{peerconnection.js => peerconnection.ts} | 51 ++-- lib/twilio/rtc/{rtcpc.js => rtcpc.ts} | 28 ++- lib/twilio/rtc/{sdp.js => sdp.ts} | 14 +- lib/twilio/rtc/{stats.js => stats.ts} | 21 +- .../shims/{eventtarget.js => eventtarget.ts} | 21 +- ...{mediadeviceinfo.js => mediadeviceinfo.ts} | 9 +- .../{mediadevices.js => mediadevices.ts} | 29 +-- lib/twilio/{sound.js => sound.ts} | 57 +++-- lib/twilio/statsMonitor.ts | 5 +- lib/twilio/{util.js => util.ts} | 39 ++-- package-lock.json | 27 +-- package.json | 10 +- scripts/constants.js | 6 +- scripts/errors.js | 22 +- templates/constants.js | 33 --- templates/constants.ts | 19 ++ tests/docker/proxy/fetchRequest.js | 1 - tests/docker/proxy/server.js | 1 - tests/env.js | 1 - tests/eventpublisher.js | 2 +- tests/framework/index.js | 2 - tests/framework/webdriver.js | 4 - tests/getusermedia.js | 2 +- tests/peerconnection.js | 2 +- tests/pstream.js | 2 +- tests/shims/mediadevices.js | 2 +- tests/sound.js | 2 +- tests/stats.js | 2 +- tests/unit/call.ts | 6 +- tests/unit/device.ts | 6 +- tsconfig.json | 3 +- 50 files changed, 467 insertions(+), 546 deletions(-) delete mode 100644 .babelrc delete mode 100644 .eslintrc rename lib/twilio/{eventpublisher.js => eventpublisher.ts} (91%) rename lib/twilio/{pstream.js => pstream.ts} (91%) rename lib/twilio/{request.js => request.ts} (89%) rename lib/twilio/rtc/{getusermedia.js => getusermedia.ts} (88%) delete mode 100644 lib/twilio/rtc/index.js create mode 100644 lib/twilio/rtc/index.ts rename lib/twilio/rtc/{mockrtcstatsreport.js => mockrtcstatsreport.ts} (95%) rename lib/twilio/rtc/{peerconnection.js => peerconnection.ts} (98%) rename lib/twilio/rtc/{rtcpc.js => rtcpc.ts} (94%) rename lib/twilio/rtc/{sdp.js => sdp.ts} (97%) rename lib/twilio/rtc/{stats.js => stats.ts} (96%) rename lib/twilio/shims/{eventtarget.js => eventtarget.ts} (83%) rename lib/twilio/shims/{mediadeviceinfo.js => mediadeviceinfo.ts} (72%) rename lib/twilio/shims/{mediadevices.js => mediadevices.ts} (93%) rename lib/twilio/{sound.js => sound.ts} (90%) rename lib/twilio/{util.js => util.ts} (88%) delete mode 100644 templates/constants.js create mode 100644 templates/constants.ts diff --git a/.babelrc b/.babelrc deleted file mode 100644 index b30d23db..00000000 --- a/.babelrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "presets": ["es2015"], - "plugins": ["transform-class-properties"] -} diff --git a/.circleci/config.yml b/.circleci/config.yml index 92e06c5a..c58e4fef 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -83,7 +83,7 @@ commands: - build - run: name: Running build checks - command: npm run test:typecheck && npm run lint && npm run test:unit + command: npm run test:es5 && npm run test:typecheck && npm run lint && npm run test:unit - store_artifacts: path: coverage destination: coverage diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 71ef078f..00000000 --- a/.eslintrc +++ /dev/null @@ -1,108 +0,0 @@ -root: true - -env: - es6: true - node: true - browser: true - -extends: - 'eslint:recommended' - -parser: - babel-eslint - -plugins: - - babel - -globals: - Map: true - Set: true - Promise: true - Uint8Array: true - Symbol: true - webkitAudioContext: true - -rules: - array-bracket-spacing: 2 - babel/new-cap: 2 - babel/object-curly-spacing: [2, always] - babel/no-invalid-this: 2 - babel/semi: 2 - block-spacing: 2 - callback-return: 2 - camelcase: 2 - comma-spacing: 2 - comma-style: [2, last] - computed-property-spacing: 2 - consistent-return: 2 - consistent-this: [2, self] - dot-location: [2, property] - dot-notation: 2 - eol-last: 2 - eqeqeq: 2 - func-style: [2, declaration] - handle-callback-err: 2 - key-spacing: 2 - linebreak-style: [2, unix] - new-cap: 0 - new-parens: 2 - no-alert: 2 - no-caller: 2 - no-case-declarations: 0 - no-console: 2 - no-const-assign: 2 - no-else-return: 2 - no-eval: 2 - no-extend-native: 2 - no-extra-bind: 2 - no-implicit-coercion: 0 - no-implied-eval: 2 - no-invalid-this: 0 - no-iterator: 2 - no-labels: 2 - no-lone-blocks: 2 - no-lonely-if: 2 - no-loop-func: 2 - no-multiple-empty-lines: 2 - no-nested-ternary: 0 - no-new-object: 2 - no-new-require: 2 - no-path-concat: 2 - no-process-env: 2 - no-process-exit: 2 - no-proto: 2 - no-return-assign: 2 - no-shadow: 2 - no-shadow-restricted-names: 2 - no-script-url: 2 - no-self-compare: 2 - no-sequences: 2 - no-spaced-func: 2 - no-throw-literal: 2 - no-trailing-spaces: 2 - no-undef-init: 2 - no-undefined: 2 - no-unneeded-ternary: 2 - no-unused-expressions: 2 - no-use-before-define: [2, nofunc] - no-useless-call: 2 - no-useless-concat: 2 - no-warning-comments: 1 - no-with: 1 - object-curly-spacing: 0 - one-var: [2, never] - operator-assignment: [2, always] - quote-props: [2, as-needed] - quotes: [2, single] - semi: 0 - keyword-spacing: 2 - space-before-blocks: [2, always] - space-before-function-paren: [2, { - anonymous: 'never', - named: 'never', - asyncArrow: 'always' - }] - space-infix-ops: 2 - space-unary-ops: 2 - spaced-comment: 1 - strict: [2, global] diff --git a/.gitignore b/.gitignore index 21cdddb8..2efd7454 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,6 @@ es5 extension/token.js node_modules docs -lib/twilio/constants.js +lib/twilio/constants.ts nodemon.json tests/webpack/package-lock.json diff --git a/.npmignore b/.npmignore index daa365da..9d7f4d43 100644 --- a/.npmignore +++ b/.npmignore @@ -1,3 +1,4 @@ +.env .idea .nyc_output BUILD.md @@ -9,6 +10,7 @@ docs extension lib node_modules +nodemon.json scripts server.js tests diff --git a/.release.json b/.release.json index 42d58c80..8eba65a7 100644 --- a/.release.json +++ b/.release.json @@ -15,10 +15,10 @@ "node ./node_modules/.bin/release --bump ${CURRENT_VERSION} ${RELEASE_VERSION}", "git config user.name \"${GIT_USER_NAME}\"", "git config user.email \"${GIT_USER_EMAIL}\"", - "git rm -rf --ignore-unmatch dist es5 docs lib/twilio/constants.js", + "git rm -rf --ignore-unmatch dist es5 docs lib/twilio/constants.ts", "npm run build:release", "git add package.json", - "git add -f dist es5 docs lib/twilio/constants.js", + "git add -f dist es5 docs lib/twilio/constants.ts", "git commit -nm \"${RELEASE_VERSION}\"", "git tag ${RELEASE_VERSION}", "git remote set-url origin \"https://${GH_TOKEN}@${GH_REF}\"", @@ -40,7 +40,7 @@ "development": { "commands": [ "node ./node_modules/.bin/release --bump ${RELEASE_VERSION} ${DEVELOPMENT_VERSION}", - "git rm -rf dist es5 docs lib/twilio/constants.js", + "git rm -rf dist es5 docs lib/twilio/constants.ts", "npm run clean", "npm run docs:clean", "git add package.json", diff --git a/karma.conf.ts b/karma.conf.ts index 50162636..79e36178 100644 --- a/karma.conf.ts +++ b/karma.conf.ts @@ -74,7 +74,7 @@ module.exports = function(config: any) { }, files: [ 'lib/twilio.ts', - 'lib/twilio/**/*.+(ts|js)', + 'lib/twilio/**/*.ts', 'tests/integration/*.ts', ], frameworks: ['mocha', 'karma-typescript'], @@ -102,7 +102,7 @@ module.exports = function(config: any) { logLevel: config.LOG_INFO, port: 9876, preprocessors: { - 'lib/**/*.+(ts|js)': 'karma-typescript', + 'lib/**/*.ts': 'karma-typescript', 'tests/integration/*.ts': 'karma-typescript', }, reporters: ['spec', 'karma-typescript'], diff --git a/lib/browser.js b/lib/browser.js index 42bd1119..ea6199d6 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -2,7 +2,6 @@ $license */ -/* eslint-disable */ (function(root) { var bundle = $bundle; var Voice = bundle($entry); diff --git a/lib/twilio/audiohelper.ts b/lib/twilio/audiohelper.ts index f64b3886..ea353423 100644 --- a/lib/twilio/audiohelper.ts +++ b/lib/twilio/audiohelper.ts @@ -7,11 +7,10 @@ import Device from './device'; import { InvalidArgumentError, NotSupportedError } from './errors'; import Log from './log'; import OutputDeviceCollection from './outputdevicecollection'; -import * as getMediaDevicesInstance from './shims/mediadevices'; +import MediaDeviceInfoShim from './shims/mediadeviceinfo'; +import getMediaDevicesInstance from './shims/mediadevices'; import { average, difference, isFirefox } from './util'; -const MediaDeviceInfoShim = require('./shims/mediadeviceinfo'); - /** * Aliases for audio kinds, used for labelling. * @private @@ -177,7 +176,7 @@ class AudioHelper extends EventEmitter { }, options); this._getUserMedia = getUserMedia; - this._mediaDevices = options.mediaDevices || getMediaDevicesInstance(); + this._mediaDevices = options.mediaDevices || getMediaDevicesInstance() as AudioHelper.MediaDevicesLike; this._onActiveInputChanged = onActiveInputChanged; this._enumerateDevices = typeof options.enumerateDevices === 'function' ? options.enumerateDevices diff --git a/lib/twilio/call.ts b/lib/twilio/call.ts index b375a459..578c757d 100644 --- a/lib/twilio/call.ts +++ b/lib/twilio/call.ts @@ -17,17 +17,17 @@ import { UserMediaErrors, } from './errors'; import Log from './log'; +import { PeerConnection } from './rtc'; import { IceCandidate, RTCIceCandidate } from './rtc/icecandidate'; import RTCSample from './rtc/sample'; +import { getPreferredCodecInfo } from './rtc/sdp'; import RTCWarning from './rtc/warning'; import StatsMonitor from './statsMonitor'; import { isChrome } from './util'; import { generateVoiceEventSid } from './uuid'; const Backoff = require('backoff'); -const C = require('./constants'); -const { PeerConnection } = require('./rtc'); -const { getPreferredCodecInfo } = require('./rtc/sdp'); +const { RELEASE_VERSION } = require('./constants'); // Placeholders until we convert the respective files to TypeScript. /** @@ -1005,7 +1005,7 @@ class Call extends EventEmitter { const payload: Partial> = { call_sid: this.parameters.CallSid, dscp: !!this._options.dscp, - sdk_version: C.RELEASE_VERSION, + sdk_version: RELEASE_VERSION, }; if (this._options.gateway) { diff --git a/lib/twilio/device.ts b/lib/twilio/device.ts index 8122f3fb..068d0853 100644 --- a/lib/twilio/device.ts +++ b/lib/twilio/device.ts @@ -8,6 +8,7 @@ import { EventEmitter } from 'events'; import { levels as LogLevels, LogLevelDesc } from 'loglevel'; import AudioHelper from './audiohelper'; import Call from './call'; +import * as C from './constants'; import DialtonePlayer from './dialtonePlayer'; import { AuthorizationErrors, @@ -20,8 +21,10 @@ import { NotSupportedError, TwilioError, } from './errors'; +import Publisher from './eventpublisher'; import Log from './log'; import { PreflightTest } from './preflight/preflight'; +import PStream from './pstream'; import { createEventGatewayURI, createSignalingEndpointURL, @@ -31,6 +34,9 @@ import { Region, regionToEdge, } from './regions'; +import * as rtc from './rtc'; +import getUserMedia from './rtc/getusermedia'; +import Sound from './sound'; import { isLegacyEdge, isUnifiedPlanDefault, @@ -38,13 +44,6 @@ import { } from './util'; import { generateVoiceEventSid } from './uuid'; -const C = require('./constants'); -const Publisher = require('./eventpublisher'); -const PStream = require('./pstream'); -const rtc = require('./rtc'); -const getUserMedia = require('./rtc/getusermedia'); -const Sound = require('./sound'); - // Placeholders until we convert the respective files to TypeScript. /** * @private diff --git a/lib/twilio/eventpublisher.js b/lib/twilio/eventpublisher.ts similarity index 91% rename from lib/twilio/eventpublisher.js rename to lib/twilio/eventpublisher.ts index 5223150d..bdee0446 100644 --- a/lib/twilio/eventpublisher.js +++ b/lib/twilio/eventpublisher.ts @@ -1,5 +1,11 @@ -const EventEmitter = require('events').EventEmitter; -const request = require('./request'); +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck +import { EventEmitter } from 'events'; +import request from './request'; /** * Builds Endpoint Analytics (EA) event payloads and sends them to @@ -12,7 +18,8 @@ const request = require('./request'); * @property {Boolean} isEnabled - Whether or not this publisher is publishing * to the server. Currently ignores the request altogether, in the future this * may store them in case publishing is re-enabled later. Defaults to true. - *//** + */ +/** * @typedef {Object} EventPublisher.Options * @property {Object} [metadata=undefined] - A publisher_metadata object to send * with each payload. @@ -33,9 +40,7 @@ class EventPublisher extends EventEmitter { } // Apply default options - options = Object.assign({ - defaultPayload() { return { }; } - }, options); + options = Object.assign({ defaultPayload() { return { }; } }, options); let defaultPayload = options.defaultPayload; @@ -44,32 +49,31 @@ class EventPublisher extends EventEmitter { } let isEnabled = true; - // eslint-disable-next-line camelcase,no-undefined const metadata = Object.assign({ app_name: undefined, app_version: undefined }, options.metadata); Object.defineProperties(this, { _defaultPayload: { value: defaultPayload }, + _host: { value: options.host, writable: true }, _isEnabled: { get() { return isEnabled; }, - set(_isEnabled) { isEnabled = _isEnabled; } + set(_isEnabled) { isEnabled = _isEnabled; }, }, - _host: { value: options.host, writable: true }, _log: { value: options.log }, _request: { value: options.request || request, writable: true }, _token: { value: token, writable: true }, isEnabled: { enumerable: true, - get() { return isEnabled; } + get() { return isEnabled; }, }, metadata: { enumerable: true, - get() { return metadata; } + get() { return metadata; }, }, productName: { enumerable: true, value: productName }, token: { enumerable: true, - get() { return this._token; } - } + get() { return this._token; }, + }, }); } } @@ -98,31 +102,28 @@ EventPublisher.prototype._post = function _post(endpointName, level, group, name } const event = { - /* eslint-disable camelcase */ - publisher: this.productName, group, - name, - timestamp: (new Date()).toISOString(), level: level.toUpperCase(), - payload_type: 'application/json', - private: false, + name, payload: (payload && payload.forEach) ? - payload.slice(0) : Object.assign(this._defaultPayload(connection), payload) - /* eslint-enable camelcase */ + payload.slice(0) : Object.assign(this._defaultPayload(connection), payload), + payload_type: 'application/json', + private: false, + publisher: this.productName, + timestamp: (new Date()).toISOString(), }; if (this.metadata) { - // eslint-disable-next-line camelcase event.publisher_metadata = this.metadata; } const requestParams = { - url: `https://${this._host}/v4/${endpointName}`, body: event, headers: { 'Content-Type': 'application/json', - 'X-Twilio-Token': this.token - } + 'X-Twilio-Token': this.token, + }, + url: `https://${this._host}/v4/${endpointName}`, }; return new Promise((resolve, reject) => { @@ -229,7 +230,7 @@ EventPublisher.prototype.postMetrics = function postMetrics(group, name, metrics * Update the host address of the insights server to publish to. * @param {String} host - The new host address of the insights server. */ - EventPublisher.prototype.setHost = function setHost(host) { +EventPublisher.prototype.setHost = function setHost(host) { this._host = host; }; @@ -258,29 +259,27 @@ EventPublisher.prototype.disable = function disable() { function formatMetric(sample) { return { - /* eslint-disable camelcase */ - timestamp: (new Date(sample.timestamp)).toISOString(), - total_packets_received: sample.totals.packetsReceived, - total_packets_lost: sample.totals.packetsLost, - total_packets_sent: sample.totals.packetsSent, - total_bytes_received: sample.totals.bytesReceived, - total_bytes_sent: sample.totals.bytesSent, - packets_received: sample.packetsReceived, - packets_lost: sample.packetsLost, - packets_lost_fraction: sample.packetsLostFraction && - (Math.round(sample.packetsLostFraction * 100) / 100), - bytes_received: sample.bytesReceived, - bytes_sent: sample.bytesSent, audio_codec: sample.codecName, audio_level_in: sample.audioInputLevel, audio_level_out: sample.audioOutputLevel, + bytes_received: sample.bytesReceived, + bytes_sent: sample.bytesSent, call_volume_input: sample.inputVolume, call_volume_output: sample.outputVolume, jitter: sample.jitter, + mos: sample.mos && (Math.round(sample.mos * 100) / 100), + packets_lost: sample.packetsLost, + packets_lost_fraction: sample.packetsLostFraction && + (Math.round(sample.packetsLostFraction * 100) / 100), + packets_received: sample.packetsReceived, rtt: sample.rtt, - mos: sample.mos && (Math.round(sample.mos * 100) / 100) - /* eslint-enable camelcase */ + timestamp: (new Date(sample.timestamp)).toISOString(), + total_bytes_received: sample.totals.bytesReceived, + total_bytes_sent: sample.totals.bytesSent, + total_packets_lost: sample.totals.packetsLost, + total_packets_received: sample.totals.packetsReceived, + total_packets_sent: sample.totals.packetsSent, }; } -module.exports = EventPublisher; +export default EventPublisher; diff --git a/lib/twilio/preflight/preflight.ts b/lib/twilio/preflight/preflight.ts index 537d96c0..1f982c33 100644 --- a/lib/twilio/preflight/preflight.ts +++ b/lib/twilio/preflight/preflight.ts @@ -20,7 +20,7 @@ import RTCWarning from '../rtc/warning'; import StatsMonitor from '../statsMonitor'; import { NetworkTiming, TimeMeasurement } from './timing'; -const { COWBELL_AUDIO_URL, ECHO_TEST_DURATION } = require('../constants'); +import { COWBELL_AUDIO_URL, ECHO_TEST_DURATION } from '../constants'; /** * Placeholder until we convert peerconnection.js to TypeScript. diff --git a/lib/twilio/pstream.js b/lib/twilio/pstream.ts similarity index 91% rename from lib/twilio/pstream.js rename to lib/twilio/pstream.ts index 045deb27..677dad5a 100644 --- a/lib/twilio/pstream.js +++ b/lib/twilio/pstream.ts @@ -1,9 +1,14 @@ -const C = require('./constants'); -const EventEmitter = require('events').EventEmitter; -const Log = require('./log').default; - -const WSTransport = require('./wstransport').default; -const { GeneralErrors, SignalingErrors } = require('./errors'); +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck +import { EventEmitter } from 'events'; +import * as C from './constants'; +import { GeneralErrors, SignalingErrors } from './errors'; +import Log from './log'; +import WSTransport from './wstransport'; const PSTREAM_VERSION = '1.6'; @@ -34,7 +39,9 @@ class PStream extends EventEmitter { }; options = options || {}; for (const prop in defaults) { - if (prop in options) continue; + if (prop in options) { + continue; + } options[prop] = defaults[prop]; } this.options = options; @@ -54,7 +61,9 @@ class PStream extends EventEmitter { this._log = Log.getInstance(); // NOTE(mroberts): EventEmitter requires that we catch all errors. - this.on('error', () => { }); + this.on('error', () => { + this._log.warn('Unexpected error handled in pstream'); + }); /* *events used by device @@ -96,8 +105,8 @@ class PStream extends EventEmitter { enumerable: true, get() { return this.transport.uri; - } - } + }, + }, }); this.transport.on('close', this._handleTransportClose); @@ -171,8 +180,8 @@ PStream.prototype.setToken = function(token) { this._log.info('Setting token and publishing listen'); this.token = token; const payload = { + browserinfo: getBrowserInfo(), token, - browserinfo: getBrowserInfo() }; this._publish('listen', payload); }; @@ -182,7 +191,7 @@ PStream.prototype.sendMessage = function( content, contenttype = 'application/json', messagetype, - voiceeventsid + voiceeventsid, ) { const payload = { callsid, @@ -195,18 +204,16 @@ PStream.prototype.sendMessage = function( }; PStream.prototype.register = function(mediaCapabilities) { - const regPayload = { - media: mediaCapabilities - }; + const regPayload = { media: mediaCapabilities }; this._publish('register', regPayload, true); }; PStream.prototype.invite = function(sdp, callsid, preflight, params) { const payload = { callsid, - sdp, preflight: !!preflight, - twilio: params ? { params } : {} + sdp, + twilio: params ? { params } : {}, }; this._publish('invite', payload, true); }; @@ -214,10 +221,10 @@ PStream.prototype.invite = function(sdp, callsid, preflight, params) { PStream.prototype.reconnect = function(sdp, callsid, reconnect, params) { const payload = { callsid, - sdp, - reconnect, preflight: false, - twilio: params ? { params } : {} + reconnect, + sdp, + twilio: params ? { params } : {}, }; this._publish('invite', payload, true); }; @@ -275,9 +282,9 @@ PStream.prototype.publish = function(type, payload) { PStream.prototype._publish = function(type, payload, shouldRetry) { const msg = JSON.stringify({ + payload, type, version: PSTREAM_VERSION, - payload }); const isSent = !!this.transport.send(msg); @@ -298,16 +305,16 @@ function getBrowserInfo() { const nav = typeof navigator !== 'undefined' ? navigator : {}; const info = { - p: 'browser', - v: C.RELEASE_VERSION, browser: { + platform: nav.platform || 'unknown', userAgent: nav.userAgent || 'unknown', - platform: nav.platform || 'unknown' }, - plugin: 'rtc' + p: 'browser', + plugin: 'rtc', + v: C.RELEASE_VERSION, }; return info; } -module.exports = PStream; +export default PStream; diff --git a/lib/twilio/request.js b/lib/twilio/request.ts similarity index 89% rename from lib/twilio/request.js rename to lib/twilio/request.ts index c4f099b7..074d62ec 100644 --- a/lib/twilio/request.js +++ b/lib/twilio/request.ts @@ -1,4 +1,10 @@ -const XHR = require('xmlhttprequest').XMLHttpRequest; +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck +import { XMLHttpRequest as XHR } from 'xmlhttprequest'; function request(method, params, callback) { const options = {}; @@ -16,7 +22,7 @@ function request(method, params, callback) { callback(new Error(xhr.responseText)); }; - + // tslint:disable-next-line for (const headerName in params.headers) { xhr.setRequestHeader(headerName, params.headers[headerName]); } @@ -31,7 +37,7 @@ function request(method, params, callback) { * @param {Array} params.headers - An array of headers to pass [{ headerName : headerBody }] * @param {Object} params.body - A JSON body to send to the resource * @returns {response} - **/ + */ const Request = request; /** @@ -52,4 +58,4 @@ Request.post = function post(params, callback) { return new this('POST', params, callback); }; -module.exports = Request; +export default Request; diff --git a/lib/twilio/rtc/getusermedia.js b/lib/twilio/rtc/getusermedia.ts similarity index 88% rename from lib/twilio/rtc/getusermedia.js rename to lib/twilio/rtc/getusermedia.ts index 63f03864..a5f4f639 100644 --- a/lib/twilio/rtc/getusermedia.js +++ b/lib/twilio/rtc/getusermedia.ts @@ -1,5 +1,11 @@ -const NotSupportedError = require('../errors').NotSupportedError; -const util = require('../util'); +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck +import { NotSupportedError } from '../errors'; +import * as util from '../util'; function getUserMedia(constraints, options) { options = options || {}; @@ -33,4 +39,4 @@ function getUserMedia(constraints, options) { }); } -module.exports = getUserMedia; +export default getUserMedia; diff --git a/lib/twilio/rtc/index.js b/lib/twilio/rtc/index.js deleted file mode 100644 index bac21d97..00000000 --- a/lib/twilio/rtc/index.js +++ /dev/null @@ -1,16 +0,0 @@ -const PeerConnection = require('./peerconnection'); -const { test } = require('./rtcpc'); - -function enabled() { - return test(); -} - -function getMediaEngine() { - return typeof RTCIceGatherer !== 'undefined' ? 'ORTC' : 'WebRTC'; -} - -module.exports = { - enabled, - getMediaEngine, - PeerConnection -}; diff --git a/lib/twilio/rtc/index.ts b/lib/twilio/rtc/index.ts new file mode 100644 index 00000000..113e3eef --- /dev/null +++ b/lib/twilio/rtc/index.ts @@ -0,0 +1,22 @@ +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck +import PeerConnection from './peerconnection'; +import RTCPC from './rtcpc'; + +function enabled() { + return RTCPC.test(); +} + +function getMediaEngine() { + return typeof RTCIceGatherer !== 'undefined' ? 'ORTC' : 'WebRTC'; +} + +export { + enabled, + getMediaEngine, + PeerConnection, +}; diff --git a/lib/twilio/rtc/mockrtcstatsreport.js b/lib/twilio/rtc/mockrtcstatsreport.ts similarity index 95% rename from lib/twilio/rtc/mockrtcstatsreport.js rename to lib/twilio/rtc/mockrtcstatsreport.ts index 0d591574..c31afb9f 100644 --- a/lib/twilio/rtc/mockrtcstatsreport.js +++ b/lib/twilio/rtc/mockrtcstatsreport.ts @@ -1,11 +1,16 @@ +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck + /** * This file was imported from another project. If making changes to this file, please don't * make them here. Make them on the linked repo below, then copy back: * https://code.hq.twilio.com/client/MockRTCStatsReport */ -/* eslint-disable no-undefined */ - // The legacy max volume, which is the positive half of a signed short integer. const OLD_MAX_VOLUME = 32767; @@ -27,13 +32,13 @@ function MockRTCStatsReport(statsMap) { const self = this; Object.defineProperties(this, { + _map: { value: statsMap }, size: { enumerable: true, get() { return self._map.size; - } + }, }, - _map: { value: statsMap } }); this[Symbol.iterator] = statsMap[Symbol.iterator]; @@ -132,16 +137,16 @@ MockRTCStatsReport.fromRTCStatsResponse = function fromRTCStatsResponse(statsRes */ function createRTCTransportStats(report) { return { - type: 'transport', - id: report.id, - timestamp: Date.parse(report.timestamp), - bytesSent: undefined, bytesReceived: undefined, - rtcpTransportStatsId: undefined, + bytesSent: undefined, dtlsState: undefined, - selectedCandidatePairId: report.stat('selectedCandidatePairId'), + id: report.id, localCertificateId: report.stat('localCertificateId'), - remoteCertificateId: report.stat('remoteCertificateId') + remoteCertificateId: report.stat('remoteCertificateId'), + rtcpTransportStatsId: undefined, + selectedCandidatePairId: report.stat('selectedCandidatePairId'), + timestamp: Date.parse(report.timestamp), + type: 'transport', }; } @@ -151,15 +156,15 @@ function createRTCTransportStats(report) { */ function createRTCCodecStats(report) { return { - type: 'codec', + channels: undefined, + clockRate: undefined, id: report.id, - timestamp: Date.parse(report.timestamp), - payloadType: undefined, + implementation: undefined, mimeType: `${report.stat('mediaType')}/${report.stat('googCodecName')}`, - clockRate: undefined, - channels: undefined, + payloadType: undefined, sdpFmtpLine: undefined, - implementation: undefined + timestamp: Date.parse(report.timestamp), + type: 'codec', }; } @@ -169,34 +174,34 @@ function createRTCCodecStats(report) { */ function createRTCMediaStreamTrackStats(report) { return { - type: 'track', - id: report.id, - timestamp: Date.parse(report.timestamp), - trackIdentifier: report.stat('googTrackId'), - remoteSource: undefined, - ended: undefined, - kind: report.stat('mediaType'), + audioLevel: isPresent(report, 'audioOutputLevel') + ? getInt(report, 'audioOutputLevel') / OLD_MAX_VOLUME + : (getInt(report, 'audioInputLevel') || 0) / OLD_MAX_VOLUME, detached: undefined, - ssrcIds: undefined, - frameWidth: isPresent(report, 'googFrameWidthReceived') - ? getInt(report, 'googFrameWidthReceived') - : getInt(report, 'googFrameWidthSent'), + echoReturnLoss: getFloat(report, 'googEchoCancellationReturnLoss'), + echoReturnLossEnhancement: getFloat(report, 'googEchoCancellationReturnLossEnhancement'), + ended: undefined, frameHeight: isPresent(report, 'googFrameHeightReceived') ? getInt(report, 'googFrameHeightReceived') : getInt(report, 'googFrameHeightSent'), - framesPerSecond: undefined, - framesSent: getInt(report, 'framesEncoded'), - framesReceived: undefined, + frameWidth: isPresent(report, 'googFrameWidthReceived') + ? getInt(report, 'googFrameWidthReceived') + : getInt(report, 'googFrameWidthSent'), + framesCorrupted: undefined, framesDecoded: getInt(report, 'framesDecoded'), framesDropped: undefined, - framesCorrupted: undefined, - partialFramesLost: undefined, + framesPerSecond: undefined, + framesReceived: undefined, + framesSent: getInt(report, 'framesEncoded'), fullFramesLost: undefined, - audioLevel: isPresent(report, 'audioOutputLevel') - ? getInt(report, 'audioOutputLevel') / OLD_MAX_VOLUME - : (getInt(report, 'audioInputLevel') || 0) / OLD_MAX_VOLUME, - echoReturnLoss: getFloat(report, 'googEchoCancellationReturnLoss'), - echoReturnLossEnhancement: getFloat(report, 'googEchoCancellationReturnLossEnhancement') + id: report.id, + kind: report.stat('mediaType'), + partialFramesLost: undefined, + remoteSource: undefined, + ssrcIds: undefined, + timestamp: Date.parse(report.timestamp), + trackIdentifier: report.stat('googTrackId'), + type: 'track', }; } @@ -207,26 +212,26 @@ function createRTCMediaStreamTrackStats(report) { */ function createRTCRTPStreamStats(report, isInbound) { return { - id: report.id, - timestamp: Date.parse(report.timestamp), - ssrc: report.stat('ssrc'), associateStatsId: undefined, - isRemote: undefined, - mediaType: report.stat('mediaType'), - trackId: `track-${report.id}`, - transportId: report.stat('transportId'), codecId: `codec-${report.id}`, firCount: isInbound ? getInt(report, 'googFirsSent') : undefined, - pliCount: isInbound - ? getInt(report, 'googPlisSent') - : getInt(report, 'googPlisReceived'), + id: report.id, + isRemote: undefined, + mediaType: report.stat('mediaType'), nackCount: isInbound ? getInt(report, 'googNacksSent') : getInt(report, 'googNacksReceived'), + pliCount: isInbound + ? getInt(report, 'googPlisSent') + : getInt(report, 'googPlisReceived'), + qpSum: getInt(report, 'qpSum'), sliCount: undefined, - qpSum: getInt(report, 'qpSum') + ssrc: report.stat('ssrc'), + timestamp: Date.parse(report.timestamp), + trackId: `track-${report.id}`, + transportId: report.stat('transportId'), }; } @@ -238,24 +243,24 @@ function createRTCInboundRTPStreamStats(report) { const rtp = createRTCRTPStreamStats(report, true); Object.assign(rtp, { - type: 'inbound-rtp', - packetsReceived: getInt(report, 'packetsReceived'), + burstDiscardCount: undefined, + burstDiscardRate: undefined, + burstLossCount: undefined, + burstLossRate: undefined, + burstPacketsDiscarded: undefined, + burstPacketsLost: undefined, bytesReceived: getInt(report, 'bytesReceived'), - packetsLost: getInt(report, 'packetsLost'), - jitter: convertMsToSeconds(report.stat('googJitterReceived')), fractionLost: undefined, - roundTripTime: convertMsToSeconds(report.stat('googRtt')), + framesDecoded: getInt(report, 'framesDecoded'), + gapDiscardRate: undefined, + gapLossRate: undefined, + jitter: convertMsToSeconds(report.stat('googJitterReceived')), packetsDiscarded: undefined, + packetsLost: getInt(report, 'packetsLost'), + packetsReceived: getInt(report, 'packetsReceived'), packetsRepaired: undefined, - burstPacketsLost: undefined, - burstPacketsDiscarded: undefined, - burstLossCount: undefined, - burstDiscardCount: undefined, - burstLossRate: undefined, - burstDiscardRate: undefined, - gapLossRate: undefined, - gapDiscardRate: undefined, - framesDecoded: getInt(report, 'framesDecoded') + roundTripTime: convertMsToSeconds(report.stat('googRtt')), + type: 'inbound-rtp', }); return rtp; @@ -269,12 +274,12 @@ function createRTCOutboundRTPStreamStats(report) { const rtp = createRTCRTPStreamStats(report, false); Object.assign(rtp, { - type: 'outbound-rtp', - remoteTimestamp: undefined, - packetsSent: getInt(report, 'packetsSent'), bytesSent: getInt(report, 'bytesSent'), + framesEncoded: getInt(report, 'framesEncoded'), + packetsSent: getInt(report, 'packetsSent'), + remoteTimestamp: undefined, targetBitrate: undefined, - framesEncoded: getInt(report, 'framesEncoded') + type: 'outbound-rtp', }); return rtp; @@ -287,21 +292,21 @@ function createRTCOutboundRTPStreamStats(report) { */ function createRTCIceCandidateStats(report, isRemote) { return { - type: isRemote - ? 'remote-candidate' - : 'local-candidate', + candidateType: translateCandidateType(report.stat('candidateType')), + deleted: undefined, id: report.id, - timestamp: Date.parse(report.timestamp), - transportId: undefined, - isRemote, ip: report.stat('ipAddress'), + isRemote, port: getInt(report, 'portNumber'), - protocol: report.stat('transport'), - candidateType: translateCandidateType(report.stat('candidateType')), priority: getFloat(report, 'priority'), - url: undefined, + protocol: report.stat('transport'), relayProtocol: undefined, - deleted: undefined + timestamp: Date.parse(report.timestamp), + transportId: undefined, + type: isRemote + ? 'remote-candidate' + : 'local-candidate', + url: undefined, }; } @@ -311,32 +316,32 @@ function createRTCIceCandidateStats(report, isRemote) { */ function createRTCIceCandidatePairStats(report) { return { - type: 'candidate-pair', + availableIncomingBitrate: undefined, + availableOutgoingBitrate: undefined, + bytesReceived: getInt(report, 'bytesReceived'), + bytesSent: getInt(report, 'bytesSent'), + consentRequestsSent: getInt(report, 'consentRequestsSent'), + currentRoundTripTime: convertMsToSeconds(report.stat('googRtt')), id: report.id, - timestamp: Date.parse(report.timestamp), - transportId: report.stat('googChannelId'), + lastPacketReceivedTimestamp: undefined, + lastPacketSentTimestamp: undefined, localCandidateId: report.stat('localCandidateId'), - remoteCandidateId: report.stat('remoteCandidateId'), - state: undefined, - priority: undefined, nominated: undefined, - writable: getBoolean(report, 'googWritable'), + priority: undefined, readable: undefined, - bytesSent: getInt(report, 'bytesSent'), - bytesReceived: getInt(report, 'bytesReceived'), - lastPacketSentTimestamp: undefined, - lastPacketReceivedTimestamp: undefined, - totalRoundTripTime: undefined, - currentRoundTripTime: convertMsToSeconds(report.stat('googRtt')), - availableOutgoingBitrate: undefined, - availableIncomingBitrate: undefined, + remoteCandidateId: report.stat('remoteCandidateId'), requestsReceived: getInt(report, 'requestsReceived'), requestsSent: getInt(report, 'requestsSent'), responsesReceived: getInt(report, 'responsesReceived'), responsesSent: getInt(report, 'responsesSent'), retransmissionsReceived: undefined, retransmissionsSent: undefined, - consentRequestsSent: getInt(report, 'consentRequestsSent') + state: undefined, + timestamp: Date.parse(report.timestamp), + totalRoundTripTime: undefined, + transportId: report.stat('googChannelId'), + type: 'candidate-pair', + writable: getBoolean(report, 'googWritable'), }; } @@ -346,13 +351,13 @@ function createRTCIceCandidatePairStats(report) { */ function createRTCCertificateStats(report) { return { - type: 'certificate', - id: report.id, - timestamp: Date.parse(report.timestamp), + base64Certificate: report.stat('googDerBase64'), fingerprint: report.stat('googFingerprint'), fingerprintAlgorithm: report.stat('googFingerprintAlgorithm'), - base64Certificate: report.stat('googDerBase64'), - issuerCertificateId: report.stat('googIssuerId') + id: report.id, + issuerCertificateId: report.stat('googIssuerId'), + timestamp: Date.parse(report.timestamp), + type: 'certificate', }; } @@ -362,18 +367,18 @@ function createRTCCertificateStats(report) { */ function createRTCDataChannelStats(report) { return { - type: 'data-channel', + bytesReceived: undefined, + bytesSent: undefined, + datachannelid: report.stat('datachannelid'), id: report.id, - timestamp: Date.parse(report.timestamp), label: report.stat('label'), + messagesReceived: undefined, + messagesSent: undefined, protocol: report.stat('protocol'), - datachannelid: report.stat('datachannelid'), - transportId: report.stat('transportId'), state: report.stat('state'), - messagesSent: undefined, - bytesSent: undefined, - messagesReceived: undefined, - bytesReceived: undefined + timestamp: Date.parse(report.timestamp), + transportId: report.stat('transportId'), + type: 'data-channel', }; } @@ -430,4 +435,4 @@ function isPresent(report, statName) { return typeof stat !== 'undefined' && stat !== ''; } -module.exports = MockRTCStatsReport; +export default MockRTCStatsReport; diff --git a/lib/twilio/rtc/peerconnection.js b/lib/twilio/rtc/peerconnection.ts similarity index 98% rename from lib/twilio/rtc/peerconnection.js rename to lib/twilio/rtc/peerconnection.ts index 3028a836..6b7aa19e 100644 --- a/lib/twilio/rtc/peerconnection.js +++ b/lib/twilio/rtc/peerconnection.ts @@ -1,13 +1,19 @@ -const { +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck +import { InvalidArgumentError, MediaErrors, NotSupportedError, SignalingErrors, -} = require('../errors'); -const Log = require('../log').default; -const util = require('../util'); -const RTCPC = require('./rtcpc'); -const { setIceAggressiveNomination } = require('./sdp'); +} from '../errors'; +import Log from '../log'; +import * as util from '../util'; +import RTCPC from './rtcpc'; +import { setIceAggressiveNomination } from './sdp'; const ICE_GATHERING_TIMEOUT = 15000; const ICE_GATHERING_FAIL_NONE = 'none'; @@ -32,7 +38,11 @@ function PeerConnection(audioHelper, pstream, getUserMedia, options) { return new PeerConnection(audioHelper, pstream, getUserMedia, options); } - function noop() { } + this._log = Log.getInstance(); + + function noop() { + this._log.warn('Unexpected noop call in peerconnection'); + } this.onaudio = noop; this.onopen = noop; this.onerror = noop; @@ -91,8 +101,6 @@ function PeerConnection(audioHelper, pstream, getUserMedia, options) { this.util = options.util || util; this.codecPreferences = options.codecPreferences; - this._log = Log.getInstance(); - return this; } @@ -131,6 +139,7 @@ PeerConnection.prototype._createAnalyser = (audioContext, options) => { }, options); const analyser = audioContext.createAnalyser(); + // tslint:disable-next-line for (const field in options) { analyser[field] = options[field]; } @@ -152,8 +161,8 @@ PeerConnection.prototype._startPollingVolume = function() { const inputBufferLength = inputAnalyser.frequencyBinCount; const inputDataArray = new Uint8Array(inputBufferLength); this._inputAnalyser2 = this._createAnalyser(audioContext, { - minDecibels: -127, maxDecibels: 0, + minDecibels: -127, smoothingTimeConstant: 0, }); @@ -161,8 +170,8 @@ PeerConnection.prototype._startPollingVolume = function() { const outputBufferLength = outputAnalyser.frequencyBinCount; const outputDataArray = new Uint8Array(outputBufferLength); this._outputAnalyser2 = this._createAnalyser(audioContext, { - minDecibels: -127, maxDecibels: 0, + minDecibels: -127, smoothingTimeConstant: 0, }); @@ -211,10 +220,9 @@ PeerConnection.prototype._stopStream = function _stopStream(stream) { audioTracks.forEach(track => { track.stop(); }); - } - // NOTE(mroberts): This is just a fallback to any ancient browsers that may - // not implement MediaStreamTrack.stop. - else { + } else { + // NOTE(mroberts): This is just a fallback to any ancient browsers that may + // not implement MediaStreamTrack.stop. stream.stop(); } }; @@ -497,7 +505,7 @@ PeerConnection.prototype._createAudioOutput = function createAudioOutput(id) { return audio.setSinkId(id).then(() => audio.play()).then(() => { self.outputs.set(id, { audio, - dest + dest, }); }); }; @@ -589,9 +597,7 @@ PeerConnection.prototype._onAddTrack = function onAddTrack(pc, stream) { // Assign the initial master audio element to a random active output device const deviceId = Array.from(pc.outputs.keys())[0] || 'default'; pc._masterAudioDeviceId = deviceId; - pc.outputs.set(deviceId, { - audio - }); + pc.outputs.set(deviceId, { audio }); try { pc._mediaStreamSource = pc._audioContext.createMediaStreamSource(stream); @@ -617,9 +623,7 @@ PeerConnection.prototype._fallbackOnAddTrack = function fallbackOnAddTrack(pc, s pc._log.info('Error attaching stream to element.'); } - pc.outputs.set('default', { - audio - }); + pc.outputs.set('default', { audio }); }; PeerConnection.prototype._setEncodingParameters = function(enableDscp) { @@ -1121,7 +1125,6 @@ function addStream(pc, stream) { function cloneStream(oldStream) { const newStream = typeof MediaStream !== 'undefined' ? new MediaStream() - // eslint-disable-next-line : new webkitMediaStream(); oldStream.getAudioTracks().forEach(newStream.addTrack, newStream); @@ -1159,4 +1162,4 @@ function setAudioSource(audio, stream) { PeerConnection.enabled = RTCPC.test(); -module.exports = PeerConnection; +export default PeerConnection; diff --git a/lib/twilio/rtc/rtcpc.js b/lib/twilio/rtc/rtcpc.ts similarity index 94% rename from lib/twilio/rtc/rtcpc.js rename to lib/twilio/rtc/rtcpc.ts index d9fe1483..2e2212ec 100644 --- a/lib/twilio/rtc/rtcpc.js +++ b/lib/twilio/rtc/rtcpc.ts @@ -1,8 +1,17 @@ +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck +// tslint:disable only-arrow-functions /* global webkitRTCPeerConnection, mozRTCPeerConnection, mozRTCSessionDescription, mozRTCIceCandidate */ + +import Log from '../log'; +import * as util from '../util'; +import { setCodecPreferences, setMaxAverageBitrate } from './sdp'; + const RTCPeerConnectionShim = require('rtcpeerconnection-shim'); -const Log = require('../log').default; -const { setCodecPreferences, setMaxAverageBitrate } = require('./sdp'); -const util = require('../util'); function RTCPC(options) { if (typeof window === 'undefined') { @@ -76,8 +85,8 @@ RTCPC.prototype.createOffer = function(maxAverageBitrate, codecPreferences, cons const sdp = setMaxAverageBitrate(offer.sdp, maxAverageBitrate); return promisifySet(this.pc.setLocalDescription, this.pc)(new RTCSessionDescription({ - type: 'offer', sdp: setCodecPreferences(sdp, codecPreferences), + type: 'offer', })); }).then(onSuccess, onError); }; @@ -88,8 +97,8 @@ RTCPC.prototype.createAnswer = function(maxAverageBitrate, codecPreferences, con const sdp = setMaxAverageBitrate(answer.sdp, maxAverageBitrate); return promisifySet(this.pc.setLocalDescription, this.pc)(new RTCSessionDescription({ - type: 'answer', sdp: setCodecPreferences(sdp, codecPreferences), + type: 'answer', })); }).then(onSuccess, onError); }; @@ -108,7 +117,7 @@ RTCPC.prototype.processAnswer = function(codecPreferences, sdp, onSuccess, onErr sdp = setCodecPreferences(sdp, codecPreferences); return promisifySet(this.pc.setRemoteDescription, this.pc)( - new RTCSessionDescription({ sdp, type: 'answer' }) + new RTCSessionDescription({ sdp, type: 'answer' }), ).then(onSuccess, onError); }; /* NOTE(mroberts): Firefox 18 through 21 include a `mozRTCPeerConnection` @@ -123,7 +132,6 @@ RTCPC.prototype.processAnswer = function(codecPreferences, sdp, onSuccess, onErr typeof (new mozRTCPeerConnection()).getLocalStreams === 'function' - NOTE(rrowland): We no longer support Legacy Edge as of Sep 1, 2020. */ RTCPC.test = () => { @@ -143,10 +151,10 @@ RTCPC.test = () => { return true; } else if (getUserMedia && typeof window.mozRTCPeerConnection === 'function') { try { - // eslint-disable-next-line babel/new-cap const test = new window.mozRTCPeerConnection(); - if (typeof test.getLocalStreams !== 'function') + if (typeof test.getLocalStreams !== 'function') { return false; + } } catch (e) { return false; } @@ -190,4 +198,4 @@ function promisifySet(fn, ctx) { return promisify(fn, ctx, false, false); } -module.exports = RTCPC; +export default RTCPC; diff --git a/lib/twilio/rtc/sdp.js b/lib/twilio/rtc/sdp.ts similarity index 97% rename from lib/twilio/rtc/sdp.js rename to lib/twilio/rtc/sdp.ts index 56f97502..3c7c5b50 100644 --- a/lib/twilio/rtc/sdp.js +++ b/lib/twilio/rtc/sdp.ts @@ -1,8 +1,14 @@ -const util = require('../util'); +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck +import * as util from '../util'; const ptToFixedBitrateAudioCodecName = { 0: 'PCMU', - 8: 'PCMA' + 8: 'PCMA', }; const defaultOpusId = 111; @@ -178,9 +184,9 @@ function getPayloadTypesInMediaSection(section) { return matches.slice(1).map(match => parseInt(match, 10)); } -module.exports = { +export { getPreferredCodecInfo, setCodecPreferences, setIceAggressiveNomination, - setMaxAverageBitrate + setMaxAverageBitrate, }; diff --git a/lib/twilio/rtc/stats.js b/lib/twilio/rtc/stats.ts similarity index 96% rename from lib/twilio/rtc/stats.js rename to lib/twilio/rtc/stats.ts index c477955c..27e50e97 100644 --- a/lib/twilio/rtc/stats.js +++ b/lib/twilio/rtc/stats.ts @@ -1,6 +1,12 @@ -/* eslint-disable no-fallthrough */ -const { NotSupportedError, InvalidArgumentError } = require('../errors'); -const MockRTCStatsReport = require('./mockrtcstatsreport'); +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck +// tslint:disable no-empty +import { InvalidArgumentError, NotSupportedError } from '../errors'; +import MockRTCStatsReport from './mockrtcstatsreport'; const ERROR_PEER_CONNECTION_NULL = 'PeerConnection is null'; const ERROR_WEB_RTC_UNSUPPORTED = 'WebRTC statistics are unsupported'; @@ -54,9 +60,7 @@ function getRTCStatsReport(peerConnection) { * @return {Promise} Universally-formatted version of RTC stats. */ function getRTCStats(peerConnection, options) { - options = Object.assign({ - createRTCSample - }, options); + options = Object.assign({ createRTCSample }, options); return getRTCStatsReport(peerConnection).then(options.createRTCSample); } @@ -105,8 +109,7 @@ function getRTCIceCandidateStatsReport(peerConnection) { // Firefox pair.selected || // Spec-compliant way - (transport && pair.id === transport.selectedCandidatePairId) - ); + (transport && pair.id === transport.selectedCandidatePairId)); let selectedIceCandidatePairStats; if (selectedCandidatePairReport) { @@ -225,7 +228,7 @@ function createRTCSample(statsReport) { return sample; } -module.exports = { +export { getRTCStats, getRTCIceCandidateStatsReport, }; diff --git a/lib/twilio/shims/eventtarget.js b/lib/twilio/shims/eventtarget.ts similarity index 83% rename from lib/twilio/shims/eventtarget.js rename to lib/twilio/shims/eventtarget.ts index d1bf210a..9410bda5 100644 --- a/lib/twilio/shims/eventtarget.js +++ b/lib/twilio/shims/eventtarget.ts @@ -1,13 +1,16 @@ -const EventEmitter = require('events').EventEmitter; +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck + +import { EventEmitter } from 'events'; function EventTarget() { Object.defineProperties(this, { - _eventEmitter: { - value: new EventEmitter() - }, - _handlers: { - value: { } - }, + _eventEmitter: { value: new EventEmitter() }, + _handlers: { value: { } }, }); } @@ -44,8 +47,8 @@ EventTarget.prototype._defineEventHandler = function _defineEventHandler(eventNa self._handlers[eventName] = newHandler; self.addEventListener(eventName, newHandler); } - } + }, }); }; -module.exports = EventTarget; +export default EventTarget; diff --git a/lib/twilio/shims/mediadeviceinfo.js b/lib/twilio/shims/mediadeviceinfo.ts similarity index 72% rename from lib/twilio/shims/mediadeviceinfo.js rename to lib/twilio/shims/mediadeviceinfo.ts index 28c82d1c..e72bbe35 100644 --- a/lib/twilio/shims/mediadeviceinfo.js +++ b/lib/twilio/shims/mediadeviceinfo.ts @@ -1,3 +1,9 @@ +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck class MediaDeviceInfoShim { constructor(options) { Object.defineProperties(this, { @@ -9,5 +15,4 @@ class MediaDeviceInfoShim { } } -module.exports = MediaDeviceInfoShim; - +export default MediaDeviceInfoShim; diff --git a/lib/twilio/shims/mediadevices.js b/lib/twilio/shims/mediadevices.ts similarity index 93% rename from lib/twilio/shims/mediadevices.js rename to lib/twilio/shims/mediadevices.ts index ecf61b56..212836ad 100644 --- a/lib/twilio/shims/mediadevices.js +++ b/lib/twilio/shims/mediadevices.ts @@ -1,4 +1,11 @@ -const EventTarget = require('./eventtarget'); +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck + +import EventTarget from './eventtarget'; const POLL_INTERVAL_MS = 500; @@ -23,19 +30,13 @@ class MediaDevicesShim extends EventTarget { const knownDevices = []; Object.defineProperties(this, { - _deviceChangeIsNative: { - value: reemitNativeEvent(this, 'devicechange') - }, - _deviceInfoChangeIsNative: { - value: reemitNativeEvent(this, 'deviceinfochange') - }, - _knownDevices: { - value: knownDevices - }, + _deviceChangeIsNative: { value: reemitNativeEvent(this, 'devicechange') }, + _deviceInfoChangeIsNative: { value: reemitNativeEvent(this, 'deviceinfochange') }, + _knownDevices: { value: knownDevices }, _pollInterval: { value: null, - writable: true - } + writable: true, + }, }); if (typeof nativeMediaDevices.enumerateDevices === 'function') { @@ -181,7 +182,9 @@ function sortDevicesById(a, b) { return a.deviceId < b.deviceId; } -module.exports = () => { +const getMediaDevicesInstance = () => { nativeMediaDevices = typeof navigator !== 'undefined' ? navigator.mediaDevices : null; return nativeMediaDevices ? new MediaDevicesShim() : null; }; + +export default getMediaDevicesInstance; diff --git a/lib/twilio/sound.js b/lib/twilio/sound.ts similarity index 90% rename from lib/twilio/sound.js rename to lib/twilio/sound.ts index 54263930..31409a85 100644 --- a/lib/twilio/sound.js +++ b/lib/twilio/sound.ts @@ -1,6 +1,12 @@ -const AsyncQueue = require('./asyncQueue').AsyncQueue; -const AudioPlayer = require('@twilio/audioplayer'); -const InvalidArgumentError = require('./errors').InvalidArgumentError; +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck +import * as AudioPlayer from '@twilio/audioplayer'; +import { AsyncQueue } from './asyncQueue'; +import { InvalidArgumentError } from './errors'; /** * @class @@ -11,7 +17,8 @@ const InvalidArgumentError = require('./errors').InvalidArgumentError; * @property {string} name - Name of the sound * @property {string} url - URL of the sound * @property {AudioContext} audioContext - The AudioContext to use if available for AudioPlayer. - *//** + */ +/** * @typedef {Object} Sound#ConstructorOptions * @property {number} [maxDuration=0] - The maximum length of time to play the sound * before stopping it. @@ -29,7 +36,7 @@ function Sound(name, url, options) { options = Object.assign({ AudioFactory: typeof Audio !== 'undefined' ? Audio : null, maxDuration: 0, - shouldLoop: false + shouldLoop: false, }, options); options.AudioPlayer = options.audioContext @@ -37,50 +44,38 @@ function Sound(name, url, options) { : options.AudioFactory; Object.defineProperties(this, { - _activeEls: { - value: new Map() - }, - _Audio: { - value: options.AudioPlayer - }, + _Audio: { value: options.AudioPlayer }, + _activeEls: { value: new Map() }, _isSinkSupported: { value: options.AudioFactory !== null - && typeof options.AudioFactory.prototype.setSinkId === 'function' - }, - _maxDuration: { - value: options.maxDuration + && typeof options.AudioFactory.prototype.setSinkId === 'function', }, + _maxDuration: { value: options.maxDuration }, _maxDurationTimeout: { value: null, - writable: true - }, - _operations: { - value: new AsyncQueue() + writable: true, }, + _operations: { value: new AsyncQueue() }, _playPromise: { value: null, - writable: true - }, - _shouldLoop: { - value: options.shouldLoop - }, - _sinkIds: { - value: ['default'] + writable: true, }, + _shouldLoop: { value: options.shouldLoop }, + _sinkIds: { value: ['default'] }, isPlaying: { enumerable: true, get() { return !!this._playPromise; - } + }, }, name: { enumerable: true, - value: name + value: name, }, url: { enumerable: true, - value: url - } + value: url, + }, }); if (this._Audio) { @@ -231,4 +226,4 @@ Sound.prototype.play = function play() { return this._operations.enqueue(() => this._play()); }; -module.exports = Sound; +export default Sound; diff --git a/lib/twilio/statsMonitor.ts b/lib/twilio/statsMonitor.ts index fbcbefe1..32181ab5 100644 --- a/lib/twilio/statsMonitor.ts +++ b/lib/twilio/statsMonitor.ts @@ -8,11 +8,10 @@ import { EventEmitter } from 'events'; import { InvalidArgumentError } from './errors'; import Mos from './rtc/mos'; import RTCSample from './rtc/sample'; +import { getRTCStats } from './rtc/stats'; import RTCWarning from './rtc/warning'; import { average } from './util'; -const { getRTCStats } = require('./rtc/stats'); - // How many samples we use when testing metric thresholds const SAMPLE_COUNT_METRICS = 5; @@ -136,7 +135,7 @@ class StatsMonitor extends EventEmitter { /** * Method to get stats from a PeerConnection object. Overrides getRTCStats library */ - private _getRTCStats: (peerConnection: IPeerConnection) => IRTCStats; + private _getRTCStats: (peerConnection: IPeerConnection, options?: any) => IRTCStats; /** * Keeps track of input volumes in the last second diff --git a/lib/twilio/util.js b/lib/twilio/util.ts similarity index 88% rename from lib/twilio/util.js rename to lib/twilio/util.ts index 71f5558b..0daa8284 100644 --- a/lib/twilio/util.js +++ b/lib/twilio/util.ts @@ -1,3 +1,10 @@ +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck + /** * Exception class. * @class @@ -26,7 +33,7 @@ function average(values) { return values && values.length ? values.reduce((t, v) => t + v) / values.length : 0; } -function difference(lefts, rights, getKey) { +function difference(lefts, rights, getKey?) { getKey = getKey || (a => a); const rightKeys = new Set(rights.map(getKey)); return lefts.filter(left => !rightKeys.has(getKey(left))); @@ -47,7 +54,7 @@ function isChrome(window, navigator) { return isCriOS || isElectron(navigator) || isGoogle || isHeadlessChrome; } -function isFirefox(navigator) { +function isFirefox(navigator?) { navigator = navigator || (typeof window === 'undefined' ? global.navigator : window.navigator); @@ -55,7 +62,7 @@ function isFirefox(navigator) { && /firefox|fxios/i.test(navigator.userAgent); } -function isLegacyEdge(navigator) { +function isLegacyEdge(navigator?) { navigator = navigator || (typeof window === 'undefined' ? global.navigator : window.navigator); @@ -137,14 +144,18 @@ function flatMap(list, mapFn) { }, []); } -exports.Exception = TwilioException; -exports.average = average; -exports.difference = difference; -exports.isElectron = isElectron; -exports.isChrome = isChrome; -exports.isFirefox = isFirefox; -exports.isLegacyEdge = isLegacyEdge; -exports.isSafari = isSafari; -exports.isUnifiedPlanDefault = isUnifiedPlanDefault; -exports.queryToJson = queryToJson; -exports.flatMap = flatMap; +const Exception = TwilioException; + +export { + Exception, + average, + difference, + isElectron, + isChrome, + isFirefox, + isLegacyEdge, + isSafari, + isUnifiedPlanDefault, + queryToJson, + flatMap, +}; diff --git a/package-lock.json b/package-lock.json index eeef94c5..9416fd82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@twilio/voice-sdk", - "version": "2.5.0-dev", + "version": "2.5.1-dev", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@twilio/voice-sdk", - "version": "2.5.0-dev", + "version": "2.5.1-dev", "license": "Apache-2.0", "dependencies": { "@twilio/audioplayer": "1.0.6", @@ -27,7 +27,6 @@ "@types/ws": "7.2.0", "babel-cli": "6.26.0", "babel-eslint": "10.0.3", - "babel-plugin-envify": "1.2.1", "babel-plugin-transform-class-properties": "6.24.1", "babel-plugin-transform-inline-environment-variables": "0.4.3", "babel-preset-es2015": "6.24.1", @@ -1637,17 +1636,6 @@ "babel-runtime": "^6.22.0" } }, - "node_modules/babel-plugin-envify": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/babel-plugin-envify/-/babel-plugin-envify-1.2.1.tgz", - "integrity": "sha512-jIyeB9pnq4moHUs/+lqTbMDAkpm1Pk9D/s96TPTRMrEXq6wAT205anVwqKqgUd3PQqZxg6reTIooM9UxYQyKRA==", - "dev": true, - "dependencies": { - "babel-core": "^6.18.2", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0" - } - }, "node_modules/babel-plugin-syntax-async-functions": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", @@ -16397,17 +16385,6 @@ "babel-runtime": "^6.22.0" } }, - "babel-plugin-envify": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/babel-plugin-envify/-/babel-plugin-envify-1.2.1.tgz", - "integrity": "sha512-jIyeB9pnq4moHUs/+lqTbMDAkpm1Pk9D/s96TPTRMrEXq6wAT205anVwqKqgUd3PQqZxg6reTIooM9UxYQyKRA==", - "dev": true, - "requires": { - "babel-core": "^6.18.2", - "babel-traverse": "^6.18.0", - "babel-types": "^6.18.0" - } - }, "babel-plugin-syntax-async-functions": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", diff --git a/package.json b/package.json index 78dbfe31..67e12aa9 100644 --- a/package.json +++ b/package.json @@ -20,9 +20,8 @@ "url": "git@github.com:twilio/twilio-voice.js.git" }, "scripts": { - "build": "npm-run-all clean build:constants build:errors docs:ts build:es5 build:ts build:dist build:dist-min", + "build": "npm-run-all clean build:constants build:errors docs:ts build:ts build:dist build:dist-min", "build:errors": "node ./scripts/errors.js", - "build:es5": "rimraf ./es5 && babel lib -d es5", "build:dev": "ENV=dev npm run build", "build:dist": "node ./scripts/build.js ./lib/browser.js ./LICENSE.md ./dist/twilio.js", "build:dist-min": "uglifyjs ./dist/twilio.js -o ./dist/twilio.min.js --comments \"/^! twilio-voice.js/\" -b beautify=false,ascii_only=true", @@ -37,9 +36,7 @@ "docs:json": "typedoc --json dist/docs/raw.json --internal-aliases internal,publicapi --external-aliases external,internalapi --excludePrivate --excludeProtected", "docs:ts": "typedoc --out docs --internal-aliases internal,publicapi --external-aliases external,internalapi --excludePrivate --excludeProtected --theme ./node_modules/typedoc-twilio-theme/bin/default", "extension": "browserify -t brfs extension/token/index.js > extension/token.js", - "lint": "npm-run-all lint:js lint:ts", - "lint:js": "eslint lib", - "lint:ts": "tslint -c tslint.json --project tsconfig.json -t stylish", + "lint": "tslint -c tslint.json --project tsconfig.json -t stylish", "release": "release", "start": "node server.js", "status": "git status", @@ -52,7 +49,7 @@ "test:framework:react:run": "mocha ./tests/framework/react.js", "test:framework:react": "npm-run-all test:framework:react:*", "test:frameworks": "npm-run-all test:framework:no-framework test:framework:react", - "test:integration": "karma start $PWD/karma.conf.ts", + "test:integration": "karma start $PWD/karma.conf.ts --log-level debug", "test:network": "node ./scripts/karma.js $PWD/karma.network.conf.ts", "test:selenium": "mocha tests/browser/index.js", "test:typecheck": "./node_modules/typescript/bin/tsc tests/typecheck/index.ts --noEmit", @@ -73,7 +70,6 @@ "@types/ws": "7.2.0", "babel-cli": "6.26.0", "babel-eslint": "10.0.3", - "babel-plugin-envify": "1.2.1", "babel-plugin-transform-class-properties": "6.24.1", "babel-plugin-transform-inline-environment-variables": "0.4.3", "babel-preset-es2015": "6.24.1", diff --git a/scripts/constants.js b/scripts/constants.js index 91d31216..11ce9975 100644 --- a/scripts/constants.js +++ b/scripts/constants.js @@ -2,10 +2,10 @@ const fs = require('fs'); const pkg = require('../package.json'); -const twilioFileString = fs.readFileSync('./templates/constants.js', 'utf8'); -fs.writeFileSync('./lib/twilio/constants.js', `\ +const twilioFileString = fs.readFileSync('./templates/constants.ts', 'utf8'); +fs.writeFileSync('./lib/twilio/constants.ts', `\ /** - * This file is generated on build. To make changes, see /templates/constants.js + * This file is generated on build. To make changes, see /templates/constants.ts */ ${twilioFileString .replace('$packageName', pkg.name) diff --git a/scripts/errors.js b/scripts/errors.js index 97787c5d..5e16331a 100644 --- a/scripts/errors.js +++ b/scripts/errors.js @@ -1,6 +1,26 @@ const fs = require('fs'); const VoiceErrors = require('@twilio/voice-errors'); -const { USED_ERRORS } = require('../lib/twilio/constants'); + +const USED_ERRORS = [ + 'AuthorizationErrors.AccessTokenExpired', + 'AuthorizationErrors.AccessTokenInvalid', + 'AuthorizationErrors.AuthenticationFailed', + 'AuthorizationErrors.PayloadSizeExceededError', + 'AuthorizationErrors.RateExceededError', + 'ClientErrors.BadRequest', + 'GeneralErrors.CallCancelledError', + 'GeneralErrors.ConnectionError', + 'GeneralErrors.TransportError', + 'GeneralErrors.UnknownError', + 'MalformedRequestErrors.MalformedRequestError', + 'MediaErrors.ClientLocalDescFailed', + 'MediaErrors.ClientRemoteDescFailed', + 'MediaErrors.ConnectionError', + 'SignalingErrors.ConnectionDisconnected', + 'SignalingErrors.ConnectionError', + 'UserMediaErrors.PermissionDeniedError', + 'UserMediaErrors.AcquisitionFailedError', +]; let output = `/* tslint:disable max-classes-per-file max-line-length */ /** diff --git a/templates/constants.js b/templates/constants.js deleted file mode 100644 index b4f2e204..00000000 --- a/templates/constants.js +++ /dev/null @@ -1,33 +0,0 @@ -const PACKAGE_NAME = '$packageName'; -const RELEASE_VERSION = '$version'; -const SOUNDS_BASE_URL = 'https://sdk.twilio.com/js/client/sounds/releases/1.0.0'; - -module.exports.COWBELL_AUDIO_URL = `${SOUNDS_BASE_URL}/cowbell.mp3?cache=${RELEASE_VERSION}`; -module.exports.ECHO_TEST_DURATION = 20000; -module.exports.PACKAGE_NAME = PACKAGE_NAME; -module.exports.RELEASE_VERSION = RELEASE_VERSION; -module.exports.SOUNDS_BASE_URL = SOUNDS_BASE_URL; - -/** - * All errors we plan to use need to be defined here. - */ -module.exports.USED_ERRORS = [ - 'AuthorizationErrors.AccessTokenExpired', - 'AuthorizationErrors.AccessTokenInvalid', - 'AuthorizationErrors.AuthenticationFailed', - 'AuthorizationErrors.PayloadSizeExceededError', - 'AuthorizationErrors.RateExceededError', - 'ClientErrors.BadRequest', - 'GeneralErrors.CallCancelledError', - 'GeneralErrors.ConnectionError', - 'GeneralErrors.TransportError', - 'GeneralErrors.UnknownError', - 'MalformedRequestErrors.MalformedRequestError', - 'MediaErrors.ClientLocalDescFailed', - 'MediaErrors.ClientRemoteDescFailed', - 'MediaErrors.ConnectionError', - 'SignalingErrors.ConnectionDisconnected', - 'SignalingErrors.ConnectionError', - 'UserMediaErrors.PermissionDeniedError', - 'UserMediaErrors.AcquisitionFailedError', -]; diff --git a/templates/constants.ts b/templates/constants.ts new file mode 100644 index 00000000..fc316768 --- /dev/null +++ b/templates/constants.ts @@ -0,0 +1,19 @@ +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ + +const PACKAGE_NAME = '$packageName'; +const RELEASE_VERSION = '$version'; +const SOUNDS_BASE_URL = 'https://sdk.twilio.com/js/client/sounds/releases/1.0.0'; +const COWBELL_AUDIO_URL = `${SOUNDS_BASE_URL}/cowbell.mp3?cache=${RELEASE_VERSION}`; +const ECHO_TEST_DURATION = 20000; + +export { + COWBELL_AUDIO_URL, + ECHO_TEST_DURATION, + PACKAGE_NAME, + RELEASE_VERSION, + SOUNDS_BASE_URL, +}; diff --git a/tests/docker/proxy/fetchRequest.js b/tests/docker/proxy/fetchRequest.js index b72304be..2e49c453 100644 --- a/tests/docker/proxy/fetchRequest.js +++ b/tests/docker/proxy/fetchRequest.js @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ 'use strict'; const http = require('http'); diff --git a/tests/docker/proxy/server.js b/tests/docker/proxy/server.js index 27d051eb..98433017 100644 --- a/tests/docker/proxy/server.js +++ b/tests/docker/proxy/server.js @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ 'use strict'; const env = require('../../env.js'); const fetchRequest = require('./fetchRequest'); diff --git a/tests/env.js b/tests/env.js index d82143eb..d4b52986 100644 --- a/tests/env.js +++ b/tests/env.js @@ -1,7 +1,6 @@ 'use strict'; // NOTE(mroberts): We need to do this for envify. -/* eslint no-process-env:0 */ const processEnv = { ACCOUNT_SID: process.env.ACCOUNT_SID, APPLICATION_SID: process.env.APPLICATION_SID, diff --git a/tests/eventpublisher.js b/tests/eventpublisher.js index 026ca523..7d8de615 100644 --- a/tests/eventpublisher.js +++ b/tests/eventpublisher.js @@ -1,6 +1,6 @@ const assert = require('assert'); const sinon = require('sinon'); -const EventPublisher = require('../lib/twilio/eventpublisher'); +const EventPublisher = require('../lib/twilio/eventpublisher').default; describe('EventPublisher', () => { let publisher; diff --git a/tests/framework/index.js b/tests/framework/index.js index e11b3aa0..34a3d93b 100644 --- a/tests/framework/index.js +++ b/tests/framework/index.js @@ -23,7 +23,6 @@ function runFrameworkTest(options) { const timeout = options.timeout; describe(name, function() { - // eslint-disable-next-line no-invalid-this this.timeout(timeout); let server; @@ -34,7 +33,6 @@ function runFrameworkTest(options) { server = spawn(start.command, start.args, { cwd: path, detached: true, - // eslint-disable-next-line no-process-env env: Object.assign({}, start.env, process.env), stdio: 'inherit' }); diff --git a/tests/framework/webdriver.js b/tests/framework/webdriver.js index 409b29bd..2f6fb75b 100644 --- a/tests/framework/webdriver.js +++ b/tests/framework/webdriver.js @@ -17,9 +17,7 @@ function buildWebDriverForChrome() { .addArguments('use-fake-device-for-media-stream') .addArguments('use-fake-ui-for-media-stream'); - // eslint-disable-next-line no-process-env if (process.env.CHROME_BIN) { - // eslint-disable-next-line no-process-env chromeOptions.setChromeBinaryPath(process.env.CHROME_BIN); } @@ -41,9 +39,7 @@ function buildWebDriverForFirefox() { const firefoxOptions = new firefox.Options().setProfile(firefoxProfile); - // eslint-disable-next-line no-process-env if (process.env.FIREFOX_BIN) { - // eslint-disable-next-line no-process-env firefoxOptions.setBinary(process.env.FIREFOX_BIN); } diff --git a/tests/getusermedia.js b/tests/getusermedia.js index 14a63fd7..f4ca0fe5 100644 --- a/tests/getusermedia.js +++ b/tests/getusermedia.js @@ -1,6 +1,6 @@ const sinon = require('sinon'); const assert = require('assert'); -const getUserMedia = require('../lib/twilio/rtc/getusermedia'); +const getUserMedia = require('../lib/twilio/rtc/getusermedia').default; context('navigatorhelper', () => { context('getUserMedia', () => { diff --git a/tests/peerconnection.js b/tests/peerconnection.js index a8531354..8387a28b 100644 --- a/tests/peerconnection.js +++ b/tests/peerconnection.js @@ -1,6 +1,6 @@ const sinon = require('sinon'); const assert = require('assert'); -const PeerConnection = require('./../lib/twilio/rtc/peerconnection'); +const PeerConnection = require('./../lib/twilio/rtc/peerconnection').default; const root = global; diff --git a/tests/pstream.js b/tests/pstream.js index 41d883a2..7936885c 100644 --- a/tests/pstream.js +++ b/tests/pstream.js @@ -1,7 +1,7 @@ const assert = require('assert'); const sinon = require('sinon'); -const PStream = require('../lib/twilio/pstream'); +const PStream = require('../lib/twilio/pstream').default; const { RELEASE_VERSION } = require('../lib/twilio/constants'); const TransportFactory = require('./mock/WSTransport'); diff --git a/tests/shims/mediadevices.js b/tests/shims/mediadevices.js index 61c85616..4fd7d372 100644 --- a/tests/shims/mediadevices.js +++ b/tests/shims/mediadevices.js @@ -1,6 +1,6 @@ const assert = require('assert'); const sinon = require('sinon'); -const getMediaDevicesInstance = require('../../lib/twilio/shims/mediadevices'); +const getMediaDevicesInstance = require('../../lib/twilio/shims/mediadevices').default; describe('MediaDevicesShim', () => { const userMediaStream = 'USER-STREAM'; diff --git a/tests/sound.js b/tests/sound.js index 28a5bdeb..59c634cd 100644 --- a/tests/sound.js +++ b/tests/sound.js @@ -1,7 +1,7 @@ const assert = require('assert'); const sinon = require('sinon'); -const Sound = require('../lib/twilio/sound'); +const Sound = require('../lib/twilio/sound').default; describe('Sound', () => { const root = global; diff --git a/tests/stats.js b/tests/stats.js index eebc045d..779e777c 100644 --- a/tests/stats.js +++ b/tests/stats.js @@ -9,7 +9,7 @@ const withTransportPayload = require('./payloads/rtcstatsreport-with-transport.j const withoutTransportPayload = require('./payloads/rtcstatsreport-without-transport.json'); const withTransportSpec = require('./spec/rtcicecandidates-with-transport.json'); const withoutTransportSpec = require('./spec/rtcicecandidates-without-transport.json'); -const MockRTCStatsReport = require('../lib/twilio/rtc/mockrtcstatsreport'); +const MockRTCStatsReport = require('../lib/twilio/rtc/mockrtcstatsreport').default; describe('Stats Report', () => { describe('getRTCIceCandidateStatsReport', () => { diff --git a/tests/unit/call.ts b/tests/unit/call.ts index 823a7811..a6aaf2ee 100644 --- a/tests/unit/call.ts +++ b/tests/unit/call.ts @@ -29,7 +29,7 @@ describe('Call', function() { const wait = (timeout?: number) => new Promise(r => setTimeout(r, timeout || 0)); const MediaHandler = () => { - mediaHandler = createEmitterStub(require('../../lib/twilio/rtc/peerconnection')); + mediaHandler = createEmitterStub(require('../../lib/twilio/rtc/peerconnection').default); mediaHandler.setInputTracksFromStream = sinon.spy((rejectCode?: number) => { return rejectCode ? Promise.reject({ code: rejectCode }) : Promise.resolve(); }); @@ -59,8 +59,8 @@ describe('Call', function() { audioHelper = createEmitterStub(require('../../lib/twilio/audiohelper').default); getUserMedia = sinon.spy(() => Promise.resolve(new MediaStream())); onIgnore = sinon.spy(); - pstream = createEmitterStub(require('../../lib/twilio/pstream')); - publisher = createEmitterStub(require('../../lib/twilio/eventpublisher')); + pstream = createEmitterStub(require('../../lib/twilio/pstream').default); + publisher = createEmitterStub(require('../../lib/twilio/eventpublisher').default); publisher.postMetrics = sinon.spy(() => Promise.resolve()); pstream.transport = { diff --git a/tests/unit/device.ts b/tests/unit/device.ts index 56d38451..a9cd25b0 100644 --- a/tests/unit/device.ts +++ b/tests/unit/device.ts @@ -52,11 +52,11 @@ describe('Device', function() { return activeCall = createEmitterStub(require('../../lib/twilio/call').default); }; const PStream = sinon.spy((...args: any[]) => - pstream = createEmitterStub(require('../../lib/twilio/pstream'))); + pstream = createEmitterStub(require('../../lib/twilio/pstream').default)); const Publisher = sinon.spy((...args: any[]) => - publisher = createEmitterStub(require('../../lib/twilio/eventpublisher'))); + publisher = createEmitterStub(require('../../lib/twilio/eventpublisher').default)); const Sound = (name: Device.SoundName) => - sounds[name] = sinon.createStubInstance(require('../../lib/twilio/sound')); + sounds[name] = sinon.createStubInstance(require('../../lib/twilio/sound').default); const setupOptions: any = { AudioHelper, Call, PStream, Publisher, Sound }; afterEach(() => { diff --git a/tsconfig.json b/tsconfig.json index 44677ba6..d6abf46e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,8 +11,7 @@ "noImplicitThis": true, "rootDir": "lib", "outDir": "es5", - "sourceMap": true, - "inlineSources": true, + "inlineSourceMap": true, "strictNullChecks": true }, "include": [ From a8ff6dcbc94625d3c6b6c3ea70d70667f393a1d5 Mon Sep 17 00:00:00 2001 From: charliesantos Date: Thu, 25 May 2023 09:06:02 -0700 Subject: [PATCH 02/12] Update npmignore --- .npmignore | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.npmignore b/.npmignore index 9d7f4d43..e68fb4bb 100644 --- a/.npmignore +++ b/.npmignore @@ -1,6 +1,11 @@ +.circleci +.deepsource.toml .env +.github .idea .nyc_output +.nycrc +.release.json BUILD.md build.yaml config.example.yaml @@ -8,9 +13,13 @@ config.yaml coverage docs extension -lib +karma.conf.ts +karma.network.conf.ts node_modules nodemon.json +PREFLIGHT.md scripts server.js +templates tests +tslint.json From 8a2a25788c24032b2289e7561da8c05eccf3b663 Mon Sep 17 00:00:00 2001 From: charliesantos Date: Thu, 25 May 2023 12:50:29 -0700 Subject: [PATCH 03/12] adding browser events and removing backoff --- package-lock.json | 82 +++++++++++++++-------------------------------- package.json | 2 +- 2 files changed, 26 insertions(+), 58 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9416fd82..94a614eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@twilio/audioplayer": "1.0.6", "@twilio/voice-errors": "1.3.1", "@types/md5": "2.3.2", - "backoff": "2.5.0", + "events": "3.3.0", "loglevel": "1.6.7", "md5": "2.3.0", "rtcpeerconnection-shim": "1.2.8", @@ -2157,17 +2157,6 @@ "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==", "dev": true }, - "node_modules/backoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", - "integrity": "sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA==", - "dependencies": { - "precond": "0.2" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2539,6 +2528,15 @@ "pako": "~1.0.5" } }, + "node_modules/browserify/node_modules/events": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", + "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/browserslist": { "version": "3.2.8", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", @@ -4603,12 +4601,11 @@ "dev": true }, "node_modules/events": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", - "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==", - "dev": true, + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "engines": { - "node": ">=0.4.x" + "node": ">=0.8.x" } }, "node_modules/evp_bytestokey": { @@ -7910,15 +7907,6 @@ "util": "^0.12.0" } }, - "node_modules/karma-typescript/node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, "node_modules/karma-typescript/node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -10662,14 +10650,6 @@ "which": "bin/which" } }, - "node_modules/precond": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", - "integrity": "sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -16901,14 +16881,6 @@ "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==", "dev": true }, - "backoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/backoff/-/backoff-2.5.0.tgz", - "integrity": "sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA==", - "requires": { - "precond": "0.2" - } - }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -17148,6 +17120,14 @@ "util": "~0.10.1", "vm-browserify": "^1.0.0", "xtend": "^4.0.0" + }, + "dependencies": { + "events": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", + "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==", + "dev": true + } } }, "browserify-aes": { @@ -18940,10 +18920,9 @@ "dev": true }, "events": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz", - "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==", - "dev": true + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" }, "evp_bytestokey": { "version": "1.0.3", @@ -21585,12 +21564,6 @@ "util": "^0.12.0" } }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true - }, "path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -23729,11 +23702,6 @@ } } }, - "precond": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/precond/-/precond-0.2.3.tgz", - "integrity": "sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ==" - }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", diff --git a/package.json b/package.json index 67e12aa9..f56d7f0e 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,7 @@ "@twilio/audioplayer": "1.0.6", "@twilio/voice-errors": "1.3.1", "@types/md5": "2.3.2", - "backoff": "2.5.0", + "events": "3.3.0", "loglevel": "1.6.7", "md5": "2.3.0", "rtcpeerconnection-shim": "1.2.8", From 03c7fade22a35800a55a46645ca2a4f77553886c Mon Sep 17 00:00:00 2001 From: charliesantos Date: Tue, 30 May 2023 10:47:55 -0700 Subject: [PATCH 04/12] Adding backoff module --- lib/twilio/backoff.ts | 81 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 lib/twilio/backoff.ts diff --git a/lib/twilio/backoff.ts b/lib/twilio/backoff.ts new file mode 100644 index 00000000..88583f22 --- /dev/null +++ b/lib/twilio/backoff.ts @@ -0,0 +1,81 @@ +/** + * @packageDocumentation + * @module Voice + * @internalapi + */ +// @ts-nocheck +// NOTE (csantos): This file was taken directly from twilio-video and has been renamed from JS to TS only. +// It needs to be re-written as part of the overall updating of the files to TS. +import { EventEmitter } from 'events'; + +class Backoff extends EventEmitter { + /** + * Construct a {@link Backoff}. + * @param {object} options + * @property {number} min - Initial timeout in milliseconds [100] + * @property {number} max - Max timeout [10000] + * @property {boolean} jitter - Apply jitter [0] + * @property {number} factor - Multiplication factor for Backoff operation [2] + */ + constructor(options) { + super(); + Object.defineProperties(this, { + _min: { + value: options.min || 100 + }, + _max: { + value: options.max || 10000 + }, + _jitter: { + value: options.jitter > 0 && options.jitter <= 1 ? options.jitter : 0 + }, + _factor: { + value: options.factor || 2 + }, + _attempts: { + value: 0, + writable: true + }, + _duration: { + enumerable: false, + get() { + let ms = this._min * Math.pow(this._factor, this._attempts); + if (this._jitter) { + const rand = Math.random(); + const deviation = Math.floor(rand * this._jitter * ms); + ms = (Math.floor(rand * 10) & 1) === 0 ? ms - deviation : ms + deviation; + } + return Math.min(ms, this._max) | 0; + } + }, + _timeoutID: { + value: null, + writable: true + } + }); + } + + backoff() { + let duration = this._duration; + if (this._timeoutID) { + clearTimeout(this._timeoutID); + this._timeoutID = null; + } + + this.emit('backoff', this._attempts, duration); + this._timeoutID = setTimeout(() => { + this.emit('ready', this._attempts, duration); + this._attempts++; + }, duration); + } + + reset() { + this._attempts = 0; + if (this._timeoutID) { + clearTimeout(this._timeoutID); + this._timeoutID = null; + } + } +} + +export default Backoff; From 8c2a803c2c1850cab581e1e6a5cf9ad61c3872e7 Mon Sep 17 00:00:00 2001 From: charliesantos Date: Wed, 31 May 2023 09:44:15 -0700 Subject: [PATCH 05/12] Use new backoff in call class --- lib/twilio/call.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/twilio/call.ts b/lib/twilio/call.ts index 578c757d..f16139ba 100644 --- a/lib/twilio/call.ts +++ b/lib/twilio/call.ts @@ -5,6 +5,7 @@ * @internal */ import { EventEmitter } from 'events'; +import Backoff from './backoff'; import Device from './device'; import DialtonePlayer from './dialtonePlayer'; import { @@ -26,7 +27,6 @@ import StatsMonitor from './statsMonitor'; import { isChrome } from './util'; import { generateVoiceEventSid } from './uuid'; -const Backoff = require('backoff'); const { RELEASE_VERSION } = require('./constants'); // Placeholders until we convert the respective files to TypeScript. @@ -53,9 +53,9 @@ export type ISound = any; const BACKOFF_CONFIG = { factor: 1.1, - initialDelay: 1, - maxDelay: 30000, - randomisationFactor: 0.5, + jitter: 0.5, + max: 30000, + min: 1, }; const DTMF_INTER_TONE_GAP: number = 70; @@ -345,7 +345,7 @@ class Call extends EventEmitter { this.callerInfo = null; } - this._mediaReconnectBackoff = Backoff.exponential(BACKOFF_CONFIG); + this._mediaReconnectBackoff = new Backoff(BACKOFF_CONFIG); this._mediaReconnectBackoff.on('ready', () => this._mediaHandler.iceRestart()); // temporary call sid to be used for outgoing calls @@ -1242,7 +1242,7 @@ class Call extends EventEmitter { if (isEndOfIceCycle) { // We already exceeded max retry time. - if (Date.now() - this._mediaReconnectStartTime > BACKOFF_CONFIG.maxDelay) { + if (Date.now() - this._mediaReconnectStartTime > BACKOFF_CONFIG.max) { this._log.info('Exceeded max ICE retries'); return this._mediaHandler.onerror(MEDIA_DISCONNECT_ERROR); } From 34f86ff982f715fff7e9c82178b83808c1a35794 Mon Sep 17 00:00:00 2001 From: charliesantos Date: Wed, 31 May 2023 10:05:36 -0700 Subject: [PATCH 06/12] Use new backoff in wstransport --- lib/twilio/wstransport.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/twilio/wstransport.ts b/lib/twilio/wstransport.ts index aa8b0832..2b6b5fe3 100644 --- a/lib/twilio/wstransport.ts +++ b/lib/twilio/wstransport.ts @@ -6,12 +6,10 @@ import { EventEmitter } from 'events'; import * as WebSocket from 'ws'; +import Backoff from './backoff'; import { SignalingErrors } from './errors'; import Log from './log'; -// tslint:disable-next-line -const Backoff = require('backoff'); - const CONNECT_SUCCESS_TIMEOUT = 10000; const CONNECT_TIMEOUT = 5000; const HEARTBEAT_TIMEOUT = 15000; @@ -521,11 +519,12 @@ export default class WSTransport extends EventEmitter { private _setupBackoffs(): typeof WSTransport.prototype._backoff { const preferredBackoffConfig = { factor: 2.0, - maxDelay: this._options.maxPreferredDelayMs, - randomisationFactor: 0.40, + jitter: 0.40, + max: this._options.maxPreferredDelayMs, + min: 100, }; this._log.info('Initializing preferred transport backoff using config: ', preferredBackoffConfig); - const preferredBackoff = Backoff.exponential(preferredBackoffConfig); + const preferredBackoff = new Backoff(preferredBackoffConfig); preferredBackoff.on('backoff', (attempt: number, delay: number) => { if (this.state === WSTransportState.Closed) { @@ -565,16 +564,16 @@ export default class WSTransport extends EventEmitter { const primaryBackoffConfig = { factor: 2.0, + jitter: 0.40, + max: this._options.maxPrimaryDelayMs, // We only want a random initial delay if there are any fallback edges // Initial delay between 1s and 5s both inclusive - initialDelay: this._uris && this._uris.length > 1 + min: this._uris && this._uris.length > 1 ? Math.floor(Math.random() * (5000 - 1000 + 1)) + 1000 : 100, - maxDelay: this._options.maxPrimaryDelayMs, - randomisationFactor: 0.40, }; this._log.info('Initializing primary transport backoff using config: ', primaryBackoffConfig); - const primaryBackoff = Backoff.exponential(primaryBackoffConfig); + const primaryBackoff = new Backoff(primaryBackoffConfig); primaryBackoff.on('backoff', (attempt: number, delay: number) => { if (this.state === WSTransportState.Closed) { From cf7d12a7100df9bffbc638d44d1d58f7f43b6221 Mon Sep 17 00:00:00 2001 From: charliesantos Date: Wed, 31 May 2023 10:10:52 -0700 Subject: [PATCH 07/12] lint --- lib/twilio/backoff.ts | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/lib/twilio/backoff.ts b/lib/twilio/backoff.ts index 88583f22..5c10ac8e 100644 --- a/lib/twilio/backoff.ts +++ b/lib/twilio/backoff.ts @@ -20,21 +20,9 @@ class Backoff extends EventEmitter { constructor(options) { super(); Object.defineProperties(this, { - _min: { - value: options.min || 100 - }, - _max: { - value: options.max || 10000 - }, - _jitter: { - value: options.jitter > 0 && options.jitter <= 1 ? options.jitter : 0 - }, - _factor: { - value: options.factor || 2 - }, _attempts: { value: 0, - writable: true + writable: true, }, _duration: { enumerable: false, @@ -43,20 +31,26 @@ class Backoff extends EventEmitter { if (this._jitter) { const rand = Math.random(); const deviation = Math.floor(rand * this._jitter * ms); + // tslint:disable-next-line ms = (Math.floor(rand * 10) & 1) === 0 ? ms - deviation : ms + deviation; } + // tslint:disable-next-line return Math.min(ms, this._max) | 0; - } + }, }, + _factor: { value: options.factor || 2 }, + _jitter: { value: options.jitter > 0 && options.jitter <= 1 ? options.jitter : 0 }, + _max: { value: options.max || 10000 }, + _min: { value: options.min || 100 }, _timeoutID: { value: null, - writable: true - } + writable: true, + }, }); } backoff() { - let duration = this._duration; + const duration = this._duration; if (this._timeoutID) { clearTimeout(this._timeoutID); this._timeoutID = null; From e51d42e9005a47d0711891eb16397235b91cca0b Mon Sep 17 00:00:00 2001 From: charliesantos Date: Wed, 31 May 2023 12:41:14 -0700 Subject: [PATCH 08/12] fix tsdocs --- lib/twilio/backoff.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/twilio/backoff.ts b/lib/twilio/backoff.ts index 5c10ac8e..d5329b70 100644 --- a/lib/twilio/backoff.ts +++ b/lib/twilio/backoff.ts @@ -1,6 +1,5 @@ /** * @packageDocumentation - * @module Voice * @internalapi */ // @ts-nocheck From f0dc1c6db9bc70ba4fd28ea555f48f7f52537427 Mon Sep 17 00:00:00 2001 From: charliesantos Date: Wed, 31 May 2023 12:51:17 -0700 Subject: [PATCH 09/12] Adding changelog --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 69eadbba..c5984ee4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,13 @@ 2.6.0 (In Progress) =================== -Changes (TODO) +Changes ------- +- Removed usage of NodeJS modules from the SDK and some dependencies. With this change, the SDK should now work with some of the latest frameworks that use the latest versions of bundlers such as Vite and Webpack. +- Links to source maps are now included in the generated npm package. +- Removing unnecessary files from the generated npm package. + 2.5.0 (May 9, 2023) =================== From f3fb3abf74cf12d0ef4f6d355e07e9774d8fd260 Mon Sep 17 00:00:00 2001 From: charliesantos Date: Wed, 31 May 2023 13:38:24 -0700 Subject: [PATCH 10/12] Adding tests --- tests/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/index.ts b/tests/index.ts index 486714c9..825360d5 100644 --- a/tests/index.ts +++ b/tests/index.ts @@ -85,6 +85,7 @@ require('./sound'); require('./sdp'); require('./unit/asyncQueue'); +require('./unit/backoff'); require('./unit/icecandidate'); require('./unit/call'); require('./unit/device'); From 14c0530f6536ebf522ab0fc9791037ed2f08e849 Mon Sep 17 00:00:00 2001 From: charliesantos Date: Wed, 31 May 2023 13:42:27 -0700 Subject: [PATCH 11/12] adding test file --- tests/unit/backoff.ts | 143 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 tests/unit/backoff.ts diff --git a/tests/unit/backoff.ts b/tests/unit/backoff.ts new file mode 100644 index 00000000..bbc094a9 --- /dev/null +++ b/tests/unit/backoff.ts @@ -0,0 +1,143 @@ +//@ts-nocheck +import * as assert from 'assert'; +import * as sinon from 'sinon'; +import Backoff from '../../lib/twilio/backoff'; + +describe('Backoff', () => { + let clock; + beforeEach(() => { + clock = sinon.useFakeTimers(); + }); + + afterEach(() => { + clock.restore(); + }); + + describe('Default Options', () => { + let options = {}; + let backoff; + let onBackoff; + let onReady; + + beforeEach(() => { + onBackoff = sinon.stub(); + onReady = sinon.stub(); + backoff = new Backoff(options); + backoff.on('backoff', onBackoff); + backoff.on('ready', onReady); + }); + + it('should raise backoff and ready events on start', () => { + backoff.backoff(); + clock.tick(100); + backoff.reset(); + sinon.assert.calledOnce(onBackoff); + sinon.assert.calledOnce(onReady); + sinon.assert.callOrder(onBackoff, onReady); + }); + + it('should increase the duration exponentially', () => { + backoff.backoff(); + clock.tick(110); + sinon.assert.calledOnce(onReady); + backoff.backoff(); + clock.tick(210); + sinon.assert.calledTwice(onReady); + backoff.backoff(); + clock.tick(410); + sinon.assert.calledThrice(onReady); + }); + + it('should reset the duration', () => { + backoff.backoff(); + clock.tick(110); + sinon.assert.calledOnce(onReady); + backoff.reset(); + clock.tick(210); + clock.tick(410); + sinon.assert.calledOnce(onReady); + }); + + it('should reset the duration once', () => { + backoff.backoff(); + clock.tick(110); + sinon.assert.calledOnce(onReady); + backoff.reset(); + backoff.reset(); + clock.tick(210); + clock.tick(410); + sinon.assert.calledOnce(onReady); + }); + + it('should provide number of attempts and duration in the backoff and ready event', () => { + const attempts = []; + const durations = []; + backoff = new Backoff({ max: 5000 }); + backoff.on('ready', (a, d) => { + attempts.push(a); + durations.push(d); + backoff.backoff(); + }); + backoff.backoff(); + clock.tick(2000); + assert.deepStrictEqual(attempts, [0,1,2,3,4]); + assert.deepStrictEqual(durations, [100,100,200,400,800]); + }); + }); + + describe('Custom Options', () => { + [ + { + tickCount: 1550, + testName: 'with max 400', + options: { max: 400 }, + numberCallbackExpected: 5 + }, + { + tickCount: 1550, + testName: 'with max 400', + options: { max: 400, jitter: 0.1 }, + numberCallbackExpected: 5 + }, + { + tickCount: 10000, + testName: 'with min 600', + options: { min: 600 }, + numberCallbackExpected: 5 + }, + { + tickCount: 10000, + testName: 'with factor 3', + options: { factor: 3 }, + numberCallbackExpected: 5 + }, + { + tickCount: 25000, + testName: 'with min 200, max 20000', + options: { min: 200, max: 20000 }, + numberCallbackExpected: 7 + }, + { + tickCount: 25000, + testName: 'with min 200, max 20000, factor 3', + options: { min: 200, max: 20000, factor: 3 }, + numberCallbackExpected: 6 + }, + ].forEach(testCase => { + it(testCase.testName, () => { + const backoff = new Backoff(testCase.options); + + let callbacks = 0; + backoff.on('ready', () => { + backoff.backoff(); + callbacks++; + }); + + backoff.backoff(); + clock.tick(testCase.tickCount); + + assert.strictEqual(callbacks, testCase.numberCallbackExpected); + }); + }); + }); +}); From 57a2d902ad3ca1aa992c1557d2caae22f80af557 Mon Sep 17 00:00:00 2001 From: charliesantos Date: Wed, 31 May 2023 13:52:19 -0700 Subject: [PATCH 12/12] Updating changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5984ee4..9ad9c888 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,8 @@ Changes ------- - Removed usage of NodeJS modules from the SDK and some dependencies. With this change, the SDK should now work with some of the latest frameworks that use the latest versions of bundlers such as Vite and Webpack. +- Removed unnecessary files from the generated npm package. - Links to source maps are now included in the generated npm package. -- Removing unnecessary files from the generated npm package. 2.5.0 (May 9, 2023) ===================