├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── messages.d.ts ├── package.json ├── public ├── index.html └── web.js ├── server.ts ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 2 7 | indent_style = space 8 | insert_final_newline = true 9 | tab_width = 2 10 | trim_trailing_whitespace = true 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 michaelneu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Howto WebRTC 2 | 3 | This repository contains the code to my post about WebRTC on dev.to. 4 | 5 | See [server.ts](server.ts) and [public/web.js](public/web.js) for both the server and web implementation. 6 | 7 | ## Usage 8 | 9 | Install all dependencies and start the server: 10 | 11 | ```bash 12 | $ yarn install 13 | $ yarn start 14 | ``` 15 | 16 | ## License 17 | 18 | This project is released under the [MIT License](LICENSE). 19 | -------------------------------------------------------------------------------- /messages.d.ts: -------------------------------------------------------------------------------- 1 | interface LoginWebSocketMessage { 2 | channel: "login"; 3 | name: string; 4 | } 5 | 6 | interface StartCallWebSocketMessage { 7 | channel: "start_call"; 8 | otherPerson: string; 9 | } 10 | 11 | interface WebRTCIceCandidateWebSocketMessage { 12 | channel: "webrtc_ice_candidate"; 13 | candidate: RTCIceCandidate; 14 | otherPerson: string; 15 | } 16 | 17 | interface WebRTCOfferWebSocketMessage { 18 | channel: "webrtc_offer"; 19 | offer: RTCSessionDescription; 20 | otherPerson: string; 21 | } 22 | 23 | interface WebRTCAnswerWebSocketMessage { 24 | channel: "webrtc_answer"; 25 | answer: RTCSessionDescription; 26 | otherPerson: string; 27 | } 28 | 29 | type WebSocketCallMessage = 30 | StartCallWebSocketMessage 31 | | WebRTCIceCandidateWebSocketMessage 32 | | WebRTCOfferWebSocketMessage 33 | | WebRTCAnswerWebSocketMessage; 34 | 35 | type WebSocketMessage = LoginWebSocketMessage | WebSocketCallMessage; 36 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "howto-webrtc", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "ts-node server.ts" 8 | }, 9 | "devDependencies": { 10 | "@types/express": "^4.17.0", 11 | "@types/express-ws": "^3.0.0", 12 | "ts-node": "^8.3.0" 13 | }, 14 | "dependencies": { 15 | "express": "^4.17.1", 16 | "express-ws": "^4.0.0", 17 | "tslib": "^1.10.0", 18 | "typescript": "^3.5.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 58 | 59 | 60 | 61 | 62 |
63 |
64 | 65 | 66 |
67 |
68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /public/web.js: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /** 4 | * Hides the given element by setting `display: none`. 5 | * @param {HTMLElement} element The element to hide 6 | */ 7 | function hideElement(element) { 8 | element.style.display = "none"; 9 | } 10 | 11 | /** 12 | * Shows the given element by resetting the display CSS property. 13 | * @param {HTMLElement} element The element to show 14 | */ 15 | function showElement(element) { 16 | element.style.display = ""; 17 | } 18 | 19 | const callButton = document.getElementById("call-button"); 20 | const videoContainer = document.getElementById("video-container"); 21 | 22 | /** 23 | * Hides both local and remote video, but shows the "call" button. 24 | */ 25 | function hideVideoCall() { 26 | hideElement(videoContainer); 27 | showElement(callButton); 28 | } 29 | 30 | /** 31 | * Shows both local and remote video, and hides the "call" button. 32 | */ 33 | function showVideoCall() { 34 | hideElement(callButton); 35 | showElement(videoContainer); 36 | } 37 | 38 | /** @type {string} */ 39 | let otherPerson; 40 | 41 | const username = prompt("What's your name?", `user${Math.floor(Math.random() * 100)}`); 42 | const socketUrl = `ws://${location.host}/ws`; 43 | const socket = new WebSocket(socketUrl); 44 | 45 | /** 46 | * Sends the message over the socket. 47 | * @param {WebSocketMessage} message The message to send 48 | */ 49 | function sendMessageToSignallingServer(message) { 50 | const json = JSON.stringify(message); 51 | socket.send(json); 52 | } 53 | 54 | // log in directly after the socket was opened 55 | socket.addEventListener("open", () => { 56 | console.log("websocket connected"); 57 | sendMessageToSignallingServer({ 58 | channel: "login", 59 | name: username, 60 | }); 61 | }); 62 | 63 | socket.addEventListener("message", (event) => { 64 | const message = JSON.parse(event.data.toString()); 65 | handleMessage(message); 66 | }); 67 | 68 | /** 69 | * Processes the incoming message. 70 | * @param {WebSocketMessage} message The incoming message 71 | */ 72 | async function handleMessage(message) { 73 | switch (message.channel) { 74 | case "start_call": 75 | console.log(`receiving call from ${message.with}`); 76 | otherPerson = message.otherPerson; 77 | showVideoCall(); 78 | 79 | const offer = await webrtc.createOffer(); 80 | await webrtc.setLocalDescription(offer); 81 | sendMessageToSignallingServer({ 82 | channel: "webrtc_offer", 83 | offer, 84 | otherPerson, 85 | }); 86 | break; 87 | 88 | case "webrtc_ice_candidate": 89 | console.log("received ice candidate"); 90 | await webrtc.addIceCandidate(message.candidate); 91 | break; 92 | 93 | case "webrtc_offer": 94 | console.log("received webrtc offer"); 95 | await webrtc.setRemoteDescription(message.offer); 96 | 97 | const answer = await webrtc.createAnswer(); 98 | await webrtc.setLocalDescription(answer); 99 | 100 | sendMessageToSignallingServer({ 101 | channel: "webrtc_answer", 102 | answer, 103 | otherPerson, 104 | }); 105 | break; 106 | 107 | case "webrtc_answer": 108 | console.log("received webrtc answer"); 109 | await webrtc.setRemoteDescription(message.answer); 110 | break; 111 | 112 | default: 113 | console.log("unknown message", message); 114 | break; 115 | } 116 | } 117 | 118 | const webrtc = new RTCPeerConnection({ 119 | iceServers: [ 120 | { 121 | urls: [ 122 | "stun:stun.stunprotocol.org", 123 | ], 124 | }, 125 | ], 126 | }); 127 | 128 | webrtc.addEventListener("icecandidate", (event) => { 129 | if (!event.candidate) { 130 | return; 131 | } 132 | 133 | sendMessageToSignallingServer({ 134 | channel: "webrtc_ice_candidate", 135 | candidate: event.candidate, 136 | otherPerson, 137 | }); 138 | }); 139 | 140 | webrtc.addEventListener("track", (event) => { 141 | /** @type {HTMLVideoElement} */ 142 | const remoteVideo = document.getElementById("remote-video"); 143 | remoteVideo.srcObject = event.streams[0]; 144 | }); 145 | 146 | navigator 147 | .mediaDevices 148 | .getUserMedia({ video: true }) 149 | .then((localStream) => { 150 | /** @type {HTMLVideoElement} */ 151 | const localVideo = document.getElementById("local-video"); 152 | localVideo.srcObject = localStream; 153 | 154 | for (const track of localStream.getTracks()) { 155 | webrtc.addTrack(track, localStream); 156 | } 157 | }); 158 | 159 | callButton.addEventListener("click", async () => { 160 | otherPerson = prompt("Who you gonna call?"); 161 | 162 | showVideoCall(); 163 | sendMessageToSignallingServer({ 164 | channel: "start_call", 165 | otherPerson, 166 | }); 167 | }); 168 | 169 | hideVideoCall(); 170 | -------------------------------------------------------------------------------- /server.ts: -------------------------------------------------------------------------------- 1 | // it's easiest to share typedefs as an ambient declaration file 2 | /// 3 | 4 | import * as express from "express"; 5 | import * as expressWs from "express-ws"; 6 | import * as WebSocket from "ws"; 7 | import { createServer } from "http"; 8 | 9 | interface User { 10 | socket: WebSocket; 11 | name: string; 12 | } 13 | 14 | // we'll keep a list of our connected users, as we need to send them messages later 15 | let connectedUsers: User[] = []; 16 | 17 | /** 18 | * Searches the currently connected users and returns the first one connected to the provided socket. 19 | * @param socket The socket to search for 20 | */ 21 | function findUserBySocket(socket: WebSocket): User | undefined { 22 | return connectedUsers.find((user) => user.socket === socket); 23 | } 24 | 25 | /** 26 | * Searches the currently connected users and returns the first one with the provided name. 27 | * @param name The name to search for 28 | */ 29 | function findUserByName(name: string): User | undefined { 30 | return connectedUsers.find((user) => user.name === name); 31 | } 32 | 33 | /** 34 | * Forwards this message to the person 35 | * @param sender The person originally sending this message 36 | * @param message The received message 37 | */ 38 | function forwardMessageToOtherPerson(sender: User, message: WebSocketCallMessage): void { 39 | const receiver = findUserByName(message.otherPerson); 40 | if (!receiver) { 41 | // in case this user doesn't exist, don't do anything 42 | return; 43 | } 44 | 45 | const json = JSON.stringify({ 46 | ...message, 47 | otherPerson: sender.name, 48 | }); 49 | 50 | receiver.socket.send(json); 51 | } 52 | 53 | /** 54 | * Processes the incoming message. 55 | * @param socket The socket that sent the message 56 | * @param message The message itself 57 | */ 58 | function handleMessage(socket: WebSocket, message: WebSocketMessage): void { 59 | const sender = findUserBySocket(socket) || { 60 | name: "[unknown]", 61 | socket, 62 | }; 63 | 64 | switch (message.channel) { 65 | case "login": 66 | console.log(`${message.name} joined`); 67 | connectedUsers.push({ socket, name: message.name }); 68 | break; 69 | 70 | case "start_call": 71 | console.log(`${sender.name} started a call with ${message.otherPerson}`); 72 | forwardMessageToOtherPerson(sender, message); 73 | break; 74 | 75 | case "webrtc_ice_candidate": 76 | console.log(`received ice candidate from ${sender.name}`); 77 | forwardMessageToOtherPerson(sender, message); 78 | break; 79 | 80 | case "webrtc_offer": 81 | console.log(`received offer from ${sender.name}`); 82 | forwardMessageToOtherPerson(sender, message); 83 | break; 84 | 85 | case "webrtc_answer": 86 | console.log(`received answer from ${sender.name}`); 87 | forwardMessageToOtherPerson(sender, message); 88 | break; 89 | 90 | default: 91 | console.log("unknown message", message); 92 | break; 93 | } 94 | } 95 | 96 | /** 97 | * Adds event listeners to the incoming socket. 98 | * @param socket The incoming WebSocket 99 | */ 100 | function handleSocketConnection(socket: WebSocket): void { 101 | socket.addEventListener("message", (event) => { 102 | // incoming messages are strings of buffers. we need to convert them 103 | // to objects first using JSON.parse() 104 | // it's safe to assume we'll only receive valid json here though 105 | const json = JSON.parse(event.data.toString()); 106 | handleMessage(socket, json); 107 | }); 108 | 109 | socket.addEventListener("close", () => { 110 | // remove the user from our user list 111 | connectedUsers = connectedUsers.filter((user) => { 112 | if (user.socket === socket) { 113 | console.log(`${user.name} disconnected`); 114 | return false; 115 | } 116 | 117 | return true; 118 | }); 119 | }); 120 | } 121 | 122 | // create an express app, using http `createServer` 123 | const app = express(); 124 | const server = createServer(app); 125 | 126 | // we'll serve our public directory under / 127 | app.use("/", express.static("public")); 128 | 129 | // add a websocket listener under /ws 130 | const wsApp = expressWs(app, server).app; 131 | wsApp.ws("/ws", handleSocketConnection); 132 | 133 | // start the server 134 | const port = process.env.PORT || 3000; 135 | server.listen(port, () => { 136 | console.log(`server started on http://localhost:${port}`); 137 | }); 138 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "importHelpers": true, 4 | "module": "commonjs", 5 | "noUnusedLocals": true, 6 | "noUnusedParameters": true, 7 | "strict": true, 8 | "target": "es2017" 9 | }, 10 | "include": [ 11 | "server.ts", 12 | "public/**/*.js" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/body-parser@*": 6 | version "1.17.0" 7 | resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.0.tgz#9f5c9d9bd04bb54be32d5eb9fc0d8c974e6cf58c" 8 | integrity sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w== 9 | dependencies: 10 | "@types/connect" "*" 11 | "@types/node" "*" 12 | 13 | "@types/connect@*": 14 | version "3.4.32" 15 | resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28" 16 | integrity sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg== 17 | dependencies: 18 | "@types/node" "*" 19 | 20 | "@types/events@*": 21 | version "3.0.0" 22 | resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" 23 | integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== 24 | 25 | "@types/express-serve-static-core@*": 26 | version "4.16.7" 27 | resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.7.tgz#50ba6f8a691c08a3dd9fa7fba25ef3133d298049" 28 | integrity sha512-847KvL8Q1y3TtFLRTXcVakErLJQgdpFSaq+k043xefz9raEf0C7HalpSY7OW5PyjCnY8P7bPW5t/Co9qqp+USg== 29 | dependencies: 30 | "@types/node" "*" 31 | "@types/range-parser" "*" 32 | 33 | "@types/express-ws@^3.0.0": 34 | version "3.0.0" 35 | resolved "https://registry.yarnpkg.com/@types/express-ws/-/express-ws-3.0.0.tgz#89674edba2e9141916fc4d4d30fbd4f810e6b80b" 36 | integrity sha512-GxsWec7Vp6h7sJuK0PwnZHeXNZnOwQn8kHAbCfvii66it5jXHTWzSg5cgHVtESwJfBLOe9SJ5wmM7C6gsDoyQw== 37 | dependencies: 38 | "@types/express" "*" 39 | "@types/express-serve-static-core" "*" 40 | "@types/ws" "*" 41 | 42 | "@types/express@*", "@types/express@^4.17.0": 43 | version "4.17.0" 44 | resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.0.tgz#49eaedb209582a86f12ed9b725160f12d04ef287" 45 | integrity sha512-CjaMu57cjgjuZbh9DpkloeGxV45CnMGlVd+XpG7Gm9QgVrd7KFq+X4HY0vM+2v0bczS48Wg7bvnMY5TN+Xmcfw== 46 | dependencies: 47 | "@types/body-parser" "*" 48 | "@types/express-serve-static-core" "*" 49 | "@types/serve-static" "*" 50 | 51 | "@types/mime@*": 52 | version "2.0.1" 53 | resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" 54 | integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw== 55 | 56 | "@types/node@*": 57 | version "12.6.2" 58 | resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.2.tgz#a5ccec6abb6060d5f20d256fb03ed743e9774999" 59 | integrity sha512-gojym4tX0FWeV2gsW4Xmzo5wxGjXGm550oVUII7f7G5o4BV6c7DBdiG1RRQd+y1bvqRyYtPfMK85UM95vsapqQ== 60 | 61 | "@types/range-parser@*": 62 | version "1.2.3" 63 | resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" 64 | integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== 65 | 66 | "@types/serve-static@*": 67 | version "1.13.2" 68 | resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.2.tgz#f5ac4d7a6420a99a6a45af4719f4dcd8cd907a48" 69 | integrity sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q== 70 | dependencies: 71 | "@types/express-serve-static-core" "*" 72 | "@types/mime" "*" 73 | 74 | "@types/ws@*": 75 | version "6.0.1" 76 | resolved "https://registry.yarnpkg.com/@types/ws/-/ws-6.0.1.tgz#ca7a3f3756aa12f62a0a62145ed14c6db25d5a28" 77 | integrity sha512-EzH8k1gyZ4xih/MaZTXwT2xOkPiIMSrhQ9b8wrlX88L0T02eYsddatQlwVFlEPyEqV0ChpdpNnE51QPH6NVT4Q== 78 | dependencies: 79 | "@types/events" "*" 80 | "@types/node" "*" 81 | 82 | accepts@~1.3.7: 83 | version "1.3.7" 84 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" 85 | integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== 86 | dependencies: 87 | mime-types "~2.1.24" 88 | negotiator "0.6.2" 89 | 90 | arg@^4.1.0: 91 | version "4.1.0" 92 | resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.0.tgz#583c518199419e0037abb74062c37f8519e575f0" 93 | integrity sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg== 94 | 95 | array-flatten@1.1.1: 96 | version "1.1.1" 97 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 98 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= 99 | 100 | async-limiter@~1.0.0: 101 | version "1.0.0" 102 | resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" 103 | integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== 104 | 105 | body-parser@1.19.0: 106 | version "1.19.0" 107 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" 108 | integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== 109 | dependencies: 110 | bytes "3.1.0" 111 | content-type "~1.0.4" 112 | debug "2.6.9" 113 | depd "~1.1.2" 114 | http-errors "1.7.2" 115 | iconv-lite "0.4.24" 116 | on-finished "~2.3.0" 117 | qs "6.7.0" 118 | raw-body "2.4.0" 119 | type-is "~1.6.17" 120 | 121 | buffer-from@^1.0.0: 122 | version "1.1.1" 123 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" 124 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== 125 | 126 | bytes@3.1.0: 127 | version "3.1.0" 128 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" 129 | integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== 130 | 131 | content-disposition@0.5.3: 132 | version "0.5.3" 133 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" 134 | integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== 135 | dependencies: 136 | safe-buffer "5.1.2" 137 | 138 | content-type@~1.0.4: 139 | version "1.0.4" 140 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 141 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== 142 | 143 | cookie-signature@1.0.6: 144 | version "1.0.6" 145 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 146 | integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= 147 | 148 | cookie@0.4.0: 149 | version "0.4.0" 150 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" 151 | integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== 152 | 153 | debug@2.6.9: 154 | version "2.6.9" 155 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 156 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 157 | dependencies: 158 | ms "2.0.0" 159 | 160 | depd@~1.1.2: 161 | version "1.1.2" 162 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 163 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= 164 | 165 | destroy@~1.0.4: 166 | version "1.0.4" 167 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 168 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= 169 | 170 | diff@^4.0.1: 171 | version "4.0.1" 172 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff" 173 | integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q== 174 | 175 | ee-first@1.1.1: 176 | version "1.1.1" 177 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 178 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 179 | 180 | encodeurl@~1.0.2: 181 | version "1.0.2" 182 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 183 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 184 | 185 | escape-html@~1.0.3: 186 | version "1.0.3" 187 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 188 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= 189 | 190 | etag@~1.8.1: 191 | version "1.8.1" 192 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 193 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= 194 | 195 | express-ws@^4.0.0: 196 | version "4.0.0" 197 | resolved "https://registry.yarnpkg.com/express-ws/-/express-ws-4.0.0.tgz#dabd8dc974516418902a41fe6e30ed949b4d36c4" 198 | integrity sha512-KEyUw8AwRET2iFjFsI1EJQrJ/fHeGiJtgpYgEWG3yDv4l/To/m3a2GaYfeGyB3lsWdvbesjF5XCMx+SVBgAAYw== 199 | dependencies: 200 | ws "^5.2.0" 201 | 202 | express@^4.17.1: 203 | version "4.17.1" 204 | resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" 205 | integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== 206 | dependencies: 207 | accepts "~1.3.7" 208 | array-flatten "1.1.1" 209 | body-parser "1.19.0" 210 | content-disposition "0.5.3" 211 | content-type "~1.0.4" 212 | cookie "0.4.0" 213 | cookie-signature "1.0.6" 214 | debug "2.6.9" 215 | depd "~1.1.2" 216 | encodeurl "~1.0.2" 217 | escape-html "~1.0.3" 218 | etag "~1.8.1" 219 | finalhandler "~1.1.2" 220 | fresh "0.5.2" 221 | merge-descriptors "1.0.1" 222 | methods "~1.1.2" 223 | on-finished "~2.3.0" 224 | parseurl "~1.3.3" 225 | path-to-regexp "0.1.7" 226 | proxy-addr "~2.0.5" 227 | qs "6.7.0" 228 | range-parser "~1.2.1" 229 | safe-buffer "5.1.2" 230 | send "0.17.1" 231 | serve-static "1.14.1" 232 | setprototypeof "1.1.1" 233 | statuses "~1.5.0" 234 | type-is "~1.6.18" 235 | utils-merge "1.0.1" 236 | vary "~1.1.2" 237 | 238 | finalhandler@~1.1.2: 239 | version "1.1.2" 240 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" 241 | integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== 242 | dependencies: 243 | debug "2.6.9" 244 | encodeurl "~1.0.2" 245 | escape-html "~1.0.3" 246 | on-finished "~2.3.0" 247 | parseurl "~1.3.3" 248 | statuses "~1.5.0" 249 | unpipe "~1.0.0" 250 | 251 | forwarded@~0.1.2: 252 | version "0.1.2" 253 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" 254 | integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= 255 | 256 | fresh@0.5.2: 257 | version "0.5.2" 258 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 259 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 260 | 261 | http-errors@1.7.2: 262 | version "1.7.2" 263 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" 264 | integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== 265 | dependencies: 266 | depd "~1.1.2" 267 | inherits "2.0.3" 268 | setprototypeof "1.1.1" 269 | statuses ">= 1.5.0 < 2" 270 | toidentifier "1.0.0" 271 | 272 | http-errors@~1.7.2: 273 | version "1.7.3" 274 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" 275 | integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== 276 | dependencies: 277 | depd "~1.1.2" 278 | inherits "2.0.4" 279 | setprototypeof "1.1.1" 280 | statuses ">= 1.5.0 < 2" 281 | toidentifier "1.0.0" 282 | 283 | iconv-lite@0.4.24: 284 | version "0.4.24" 285 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 286 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 287 | dependencies: 288 | safer-buffer ">= 2.1.2 < 3" 289 | 290 | inherits@2.0.3: 291 | version "2.0.3" 292 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 293 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 294 | 295 | inherits@2.0.4: 296 | version "2.0.4" 297 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 298 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 299 | 300 | ipaddr.js@1.9.0: 301 | version "1.9.0" 302 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" 303 | integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== 304 | 305 | make-error@^1.1.1: 306 | version "1.3.5" 307 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" 308 | integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== 309 | 310 | media-typer@0.3.0: 311 | version "0.3.0" 312 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 313 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= 314 | 315 | merge-descriptors@1.0.1: 316 | version "1.0.1" 317 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 318 | integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= 319 | 320 | methods@~1.1.2: 321 | version "1.1.2" 322 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 323 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 324 | 325 | mime-db@1.40.0: 326 | version "1.40.0" 327 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" 328 | integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== 329 | 330 | mime-types@~2.1.24: 331 | version "2.1.24" 332 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" 333 | integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== 334 | dependencies: 335 | mime-db "1.40.0" 336 | 337 | mime@1.6.0: 338 | version "1.6.0" 339 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 340 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 341 | 342 | ms@2.0.0: 343 | version "2.0.0" 344 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 345 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 346 | 347 | ms@2.1.1: 348 | version "2.1.1" 349 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 350 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== 351 | 352 | negotiator@0.6.2: 353 | version "0.6.2" 354 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" 355 | integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== 356 | 357 | on-finished@~2.3.0: 358 | version "2.3.0" 359 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 360 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= 361 | dependencies: 362 | ee-first "1.1.1" 363 | 364 | parseurl@~1.3.3: 365 | version "1.3.3" 366 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 367 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 368 | 369 | path-to-regexp@0.1.7: 370 | version "0.1.7" 371 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 372 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= 373 | 374 | proxy-addr@~2.0.5: 375 | version "2.0.5" 376 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" 377 | integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== 378 | dependencies: 379 | forwarded "~0.1.2" 380 | ipaddr.js "1.9.0" 381 | 382 | qs@6.7.0: 383 | version "6.7.0" 384 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" 385 | integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== 386 | 387 | range-parser@~1.2.1: 388 | version "1.2.1" 389 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" 390 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 391 | 392 | raw-body@2.4.0: 393 | version "2.4.0" 394 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" 395 | integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== 396 | dependencies: 397 | bytes "3.1.0" 398 | http-errors "1.7.2" 399 | iconv-lite "0.4.24" 400 | unpipe "1.0.0" 401 | 402 | safe-buffer@5.1.2: 403 | version "5.1.2" 404 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 405 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 406 | 407 | "safer-buffer@>= 2.1.2 < 3": 408 | version "2.1.2" 409 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 410 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 411 | 412 | send@0.17.1: 413 | version "0.17.1" 414 | resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" 415 | integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== 416 | dependencies: 417 | debug "2.6.9" 418 | depd "~1.1.2" 419 | destroy "~1.0.4" 420 | encodeurl "~1.0.2" 421 | escape-html "~1.0.3" 422 | etag "~1.8.1" 423 | fresh "0.5.2" 424 | http-errors "~1.7.2" 425 | mime "1.6.0" 426 | ms "2.1.1" 427 | on-finished "~2.3.0" 428 | range-parser "~1.2.1" 429 | statuses "~1.5.0" 430 | 431 | serve-static@1.14.1: 432 | version "1.14.1" 433 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" 434 | integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== 435 | dependencies: 436 | encodeurl "~1.0.2" 437 | escape-html "~1.0.3" 438 | parseurl "~1.3.3" 439 | send "0.17.1" 440 | 441 | setprototypeof@1.1.1: 442 | version "1.1.1" 443 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" 444 | integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== 445 | 446 | source-map-support@^0.5.6: 447 | version "0.5.12" 448 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" 449 | integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== 450 | dependencies: 451 | buffer-from "^1.0.0" 452 | source-map "^0.6.0" 453 | 454 | source-map@^0.6.0: 455 | version "0.6.1" 456 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 457 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 458 | 459 | "statuses@>= 1.5.0 < 2", statuses@~1.5.0: 460 | version "1.5.0" 461 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 462 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= 463 | 464 | toidentifier@1.0.0: 465 | version "1.0.0" 466 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" 467 | integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== 468 | 469 | ts-node@^8.3.0: 470 | version "8.3.0" 471 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.3.0.tgz#e4059618411371924a1fb5f3b125915f324efb57" 472 | integrity sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ== 473 | dependencies: 474 | arg "^4.1.0" 475 | diff "^4.0.1" 476 | make-error "^1.1.1" 477 | source-map-support "^0.5.6" 478 | yn "^3.0.0" 479 | 480 | tslib@^1.10.0: 481 | version "1.10.0" 482 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" 483 | integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== 484 | 485 | type-is@~1.6.17, type-is@~1.6.18: 486 | version "1.6.18" 487 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 488 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 489 | dependencies: 490 | media-typer "0.3.0" 491 | mime-types "~2.1.24" 492 | 493 | typescript@^3.5.3: 494 | version "3.5.3" 495 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" 496 | integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== 497 | 498 | unpipe@1.0.0, unpipe@~1.0.0: 499 | version "1.0.0" 500 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 501 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= 502 | 503 | utils-merge@1.0.1: 504 | version "1.0.1" 505 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 506 | integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= 507 | 508 | vary@~1.1.2: 509 | version "1.1.2" 510 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 511 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 512 | 513 | ws@^5.2.0: 514 | version "5.2.2" 515 | resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" 516 | integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== 517 | dependencies: 518 | async-limiter "~1.0.0" 519 | 520 | yn@^3.0.0: 521 | version "3.1.0" 522 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.0.tgz#fcbe2db63610361afcc5eb9e0ac91e976d046114" 523 | integrity sha512-kKfnnYkbTfrAdd0xICNFw7Atm8nKpLcLv9AZGEt+kczL/WQVai4e2V6ZN8U/O+iI6WrNuJjNNOyu4zfhl9D3Hg== 524 | --------------------------------------------------------------------------------