diff --git a/jest.config.js b/jest.config.js index 216adfd..31e2e42 100644 --- a/jest.config.js +++ b/jest.config.js @@ -15,6 +15,6 @@ module.exports = { transform: { '^.+\\.ts$': 'ts-jest', }, - testEnvironment: "jsdom", + testEnvironment: 'jsdom', clearMocks: true, }; diff --git a/package-lock.json b/package-lock.json index 0b598cd..7c1c1fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,12 +9,14 @@ "version": "2.1.0", "license": "Apache-2.0", "dependencies": { + "Buffer": "^0.0.0", "isomorphic-webcrypto": "^2.3.6", "jsdom": "^20.0.0", "json-schema": "^0.4.0", "json5": "^2.2.3", "tslib": "^1.10.0", "ua-parser-js": "^1.0.35", + "ws": "^8.14.2", "xml2js": "^0.5.0" }, "devDependencies": { @@ -7555,6 +7557,31 @@ "readable-stream": "^3.4.0" } }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "peer": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/bl/node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -7767,29 +7794,12 @@ "node-int64": "^0.4.0" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true, - "peer": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "node_modules/Buffer": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/Buffer/-/Buffer-0.0.0.tgz", + "integrity": "sha512-+zdncl8lI5TCkARStn9F1BwcuJYofYmD0oEHe5FNfCvGfeDJwf6+dSikCdQN6BMXXmHMhNNUagBN367WST1AIQ==", + "engines": { + "node": ">= 0.2.0" } }, "node_modules/buffer-alloc": { @@ -22239,9 +22249,9 @@ } }, "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "engines": { "node": ">=10.0.0" }, diff --git a/package.json b/package.json index bf1ddff..ace7de5 100644 --- a/package.json +++ b/package.json @@ -55,12 +55,14 @@ "webpack-merge": "^4.2.2" }, "dependencies": { + "Buffer": "^0.0.0", "isomorphic-webcrypto": "^2.3.6", "jsdom": "^20.0.0", "json-schema": "^0.4.0", "json5": "^2.2.3", "tslib": "^1.10.0", "ua-parser-js": "^1.0.35", + "ws": "^8.14.2", "xml2js": "^0.5.0" }, "overrides": { diff --git a/src/SignalingClient.spec.ts b/src/SignalingClient.spec.ts index 20012a5..ef4b783 100644 --- a/src/SignalingClient.spec.ts +++ b/src/SignalingClient.spec.ts @@ -572,4 +572,30 @@ describe('SignalingClient', () => { }); }); }); + + describe('outsideBrowser', () => { + it('parseJSONObjectFromBase64String', done => { + global.atob = undefined; + const client = new SignalingClient(config as SignalingClientConfig); + client.once('sdpAnswer', (sdpAnswer, _) => { + expect(sdpAnswer).toEqual(SDP_ANSWER_OBJECT); + done(); + }); + client.once('open', () => { + MockWebSocket.instance.emit('message', { data: SDP_ANSWER_MASTER_MESSAGE }); + }); + client.open(); + }); + + it('serializeJSONObjectAsBase64String', done => { + global.btoa = undefined; + const client = new SignalingClient(config as SignalingClientConfig); + client.open(); + client.on('open', () => { + client.sendSdpOffer(SDP_OFFER); + expect(MockWebSocket.instance.send).toHaveBeenCalledWith(SDP_OFFER_VIEWER_STRING); + done(); + }); + }); + }); }); diff --git a/src/SignalingClient.ts b/src/SignalingClient.ts index 280af01..8ee0173 100644 --- a/src/SignalingClient.ts +++ b/src/SignalingClient.ts @@ -137,7 +137,8 @@ export class SignalingClient extends EventEmitter { return; } - this.websocket = new WebSocket(signedURL); + /* istanbul ignore next */ + this.websocket = new (global.WebSocket || require('ws'))(signedURL); this.websocket.addEventListener('open', this.onOpen); this.websocket.addEventListener('message', this.onMessage); @@ -166,7 +167,7 @@ export class SignalingClient extends EventEmitter { * @param {string} [recipientClientId] - ID of the client to send the message to. Required for 'MASTER' role. Should not be present for 'VIEWER' role. */ public sendSdpOffer(sdpOffer: RTCSessionDescription, recipientClientId?: string): void { - this.sendMessage(MessageType.SDP_OFFER, sdpOffer.toJSON(), recipientClientId); + this.sendMessage(MessageType.SDP_OFFER, sdpOffer, recipientClientId); } /** @@ -177,7 +178,7 @@ export class SignalingClient extends EventEmitter { * @param {string} [recipientClientId] - ID of the client to send the message to. Required for 'MASTER' role. Should not be present for 'VIEWER' role. */ public sendSdpAnswer(sdpAnswer: RTCSessionDescription, recipientClientId?: string): void { - this.sendMessage(MessageType.SDP_ANSWER, sdpAnswer.toJSON(), recipientClientId); + this.sendMessage(MessageType.SDP_ANSWER, sdpAnswer, recipientClientId); } /** @@ -188,7 +189,7 @@ export class SignalingClient extends EventEmitter { * @param {string} [recipientClientId] - ID of the client to send the message to. Required for 'MASTER' role. Should not be present for 'VIEWER' role. */ public sendIceCandidate(iceCandidate: RTCIceCandidate, recipientClientId?: string): void { - this.sendMessage(MessageType.ICE_CANDIDATE, iceCandidate.toJSON(), recipientClientId); + this.sendMessage(MessageType.ICE_CANDIDATE, iceCandidate, recipientClientId); } /** @@ -266,14 +267,22 @@ export class SignalingClient extends EventEmitter { * Takes the given base64 encoded string and decodes it into a JSON object. */ private static parseJSONObjectFromBase64String(base64EncodedString: string): object { - return JSON.parse(atob(base64EncodedString)); + try { + return JSON.parse(atob(base64EncodedString)); + } catch (e) { + return JSON.parse(Buffer.from(base64EncodedString, 'base64').toString()); + } } /** * Takes the given JSON object and encodes it into a base64 string. */ private static serializeJSONObjectAsBase64String(object: object): string { - return btoa(JSON.stringify(object)); + try { + return btoa(JSON.stringify(object)); + } catch (e) { + return Buffer.from(JSON.stringify(object)).toString('base64'); + } } /** diff --git a/webpack.dev.config.js b/webpack.dev.config.js index f4af1d8..423ec93 100644 --- a/webpack.dev.config.js +++ b/webpack.dev.config.js @@ -1,5 +1,6 @@ const path = require('path'); const merge = require('webpack-merge'); +const webpack = require('webpack'); module.exports = merge.smart(require('./webpack.config'), { mode: 'development', @@ -11,7 +12,7 @@ module.exports = merge.smart(require('./webpack.config'), { devServer: { static: { - directory: path.join(__dirname, "examples") + directory: path.join(__dirname, 'examples'), }, devMiddleware: { publicPath: '/',