├── .gitignore ├── LICENSE ├── README.md ├── backend ├── .gitignore ├── package-lock.json ├── package.json ├── server.ts └── tsconfig.json └── frontend ├── .editorconfig ├── .gitignore ├── README.md ├── angular-cli.json ├── e2e ├── app.e2e-spec.ts ├── app.po.ts └── tsconfig.json ├── karma.conf.js ├── package-lock.json ├── package.json ├── protractor.conf.js ├── src ├── app │ ├── app.component.css │ ├── app.component.html │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── index.ts │ ├── shared │ │ ├── immutable-model.ts │ │ ├── index.ts │ │ ├── mediastream.service.ts │ │ └── shared.module.ts │ └── webrtc-chat │ │ ├── index.ts │ │ ├── shared │ │ ├── index.ts │ │ ├── webrtc-client-connection.service.ts │ │ ├── webrtc-client.model.ts │ │ ├── webrtc-client.store.service.ts │ │ ├── webrtc-custom.d.ts │ │ ├── webrtc-event-messages.ts │ │ └── webrtc-shared.module.ts │ │ ├── webrtc-chat.component.html │ │ ├── webrtc-chat.component.ts │ │ └── webrtc-chat.module.ts ├── assets │ └── .gitkeep ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.css ├── test.ts ├── tsconfig.json └── typings.d.ts ├── tsconfig.json ├── tslint.json └── typings.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WebRTC Video Chat Example with Angular 2 and TypeScript 2 | 3 | Small example on how to use WebRTC with TypeScript and Angular 2 to build a small video chat. 4 | Only runs in a local network due to missing configured ICE server. 5 | 6 | ## Start Server 7 | 1. Navigate to `./backend` 8 | 2. Install dependencies 9 | 10 | `$ npm install` 11 | 12 | 3. Build server 13 | 14 | `$ npm run build` 15 | 16 | 4. Start server on port 3000 17 | 18 | `$ npm start` 19 | 20 | ## Serve frontend 21 | 1. Install [Angular-CLI](https://github.com/angular/angular-cli) 22 | 23 | 2. Navigate to `./frontend` 24 | 25 | 3. Serve with Angular-CLI 26 | 27 | `$ ng serve` 28 | 29 | ## Notes 30 | - Currently no ICE servers are configured 31 | - Therefor the project only runs on a local network. 32 | - To use it from different devices inside your network, 33 | you have to change the address, that the socket is using to connect to the backend. 34 | The address can be found in the file `./frontend/src/app/webrtc-chat/shared/webrtc-client-connection.service.ts` 35 | - Angular-CLI can listen to all interfaces by using `ng serve --host 0.0.0.0` 36 | - Chrome uses deprecated API's of WebRTC due to the problem in [webrtc/adapter #361](https://github.com/webrtc/adapter/issues/361) 37 | 38 | ## ToDo's 39 | - Add ICE config 40 | - Pretty up the whole thing :-) -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | ### Node ### 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | *.pid.lock 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # nyc test coverage 20 | .nyc_output 21 | 22 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 23 | .grunt 24 | 25 | # node-waf configuration 26 | .lock-wscript 27 | 28 | # Compiled binary addons (http://nodejs.org/api/addons.html) 29 | build/Release 30 | 31 | # Dependency directories 32 | node_modules 33 | jspm_packages 34 | 35 | # Optional npm cache directory 36 | .npm 37 | 38 | # Optional eslint cache 39 | .eslintcache 40 | 41 | # Optional REPL history 42 | .node_repl_history 43 | 44 | # Output of 'npm pack' 45 | *.tgz 46 | 47 | # Yarn Integrity file 48 | .yarn-integrity 49 | 50 | /dist -------------------------------------------------------------------------------- /backend/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/body-parser": { 8 | "version": "0.0.33", 9 | "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-0.0.33.tgz", 10 | "integrity": "sha1-M8oUmPw35Rxd8MgcrjRWnnBB4CU=", 11 | "dev": true, 12 | "requires": { 13 | "@types/express": "*" 14 | } 15 | }, 16 | "@types/express": { 17 | "version": "4.11.1", 18 | "resolved": "https://registry.npmjs.org/@types/express/-/express-4.11.1.tgz", 19 | "integrity": "sha512-ttWle8cnPA5rAelauSWeWJimtY2RsUf2aspYZs7xPHiWgOlPn6nnUfBMtrkcnjFJuIHJF4gNOdVvpLK2Zmvh6g==", 20 | "dev": true, 21 | "requires": { 22 | "@types/body-parser": "*", 23 | "@types/express-serve-static-core": "*", 24 | "@types/serve-static": "*" 25 | } 26 | }, 27 | "@types/express-serve-static-core": { 28 | "version": "4.0.49", 29 | "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.0.49.tgz", 30 | "integrity": "sha512-b7mVHoURu1xaP/V6xw1sYwyv9V0EZ7euyi+sdnbnTZxEkAh4/hzPsI6Eflq+ZzHQ/Tgl7l16Jz+0oz8F46MLnA==", 31 | "dev": true, 32 | "requires": { 33 | "@types/node": "*" 34 | } 35 | }, 36 | "@types/mime": { 37 | "version": "2.0.1", 38 | "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", 39 | "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==", 40 | "dev": true 41 | }, 42 | "@types/morgan": { 43 | "version": "1.7.32", 44 | "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.7.32.tgz", 45 | "integrity": "sha1-+rHs5NrhcuGjd9Vj0z42NPoEkn0=", 46 | "dev": true, 47 | "requires": { 48 | "@types/express": "*" 49 | } 50 | }, 51 | "@types/node": { 52 | "version": "0.0.2", 53 | "resolved": "https://registry.npmjs.org/@types/node/-/node-0.0.2.tgz", 54 | "integrity": "sha1-DaSTSQL79oqXoPUyBKNa0iJJF7w=", 55 | "dev": true 56 | }, 57 | "@types/serve-static": { 58 | "version": "1.13.3", 59 | "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", 60 | "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==", 61 | "dev": true, 62 | "requires": { 63 | "@types/express-serve-static-core": "*", 64 | "@types/mime": "*" 65 | } 66 | }, 67 | "@types/socket.io": { 68 | "version": "1.4.27", 69 | "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-1.4.27.tgz", 70 | "integrity": "sha1-xqnz/60h46CZkDiBOgatIKvcbpU=", 71 | "dev": true, 72 | "requires": { 73 | "@types/node": "*" 74 | } 75 | }, 76 | "accepts": { 77 | "version": "1.3.7", 78 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", 79 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", 80 | "requires": { 81 | "mime-types": "~2.1.24", 82 | "negotiator": "0.6.2" 83 | } 84 | }, 85 | "after": { 86 | "version": "0.8.1", 87 | "resolved": "https://registry.npmjs.org/after/-/after-0.8.1.tgz", 88 | "integrity": "sha1-q11PuIP1loFtNRX495HAr0ht1ic=" 89 | }, 90 | "array-flatten": { 91 | "version": "1.1.1", 92 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 93 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 94 | }, 95 | "arraybuffer.slice": { 96 | "version": "0.0.6", 97 | "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz", 98 | "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=" 99 | }, 100 | "backo2": { 101 | "version": "1.0.2", 102 | "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", 103 | "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" 104 | }, 105 | "base64-arraybuffer": { 106 | "version": "0.1.5", 107 | "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", 108 | "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" 109 | }, 110 | "base64id": { 111 | "version": "0.1.0", 112 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz", 113 | "integrity": "sha1-As4P3u4M709ACA4ec+g08LG/zj8=" 114 | }, 115 | "basic-auth": { 116 | "version": "1.0.4", 117 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.4.tgz", 118 | "integrity": "sha1-Awk1sB3nyblKgksp8/zLdQ06UpA=" 119 | }, 120 | "better-assert": { 121 | "version": "1.0.2", 122 | "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", 123 | "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", 124 | "requires": { 125 | "callsite": "1.0.0" 126 | } 127 | }, 128 | "blob": { 129 | "version": "0.0.4", 130 | "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", 131 | "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" 132 | }, 133 | "body-parser": { 134 | "version": "1.15.2", 135 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.15.2.tgz", 136 | "integrity": "sha1-11eM9PHRHV9uqATO813Hp/9trmc=", 137 | "requires": { 138 | "bytes": "2.4.0", 139 | "content-type": "~1.0.2", 140 | "debug": "~2.2.0", 141 | "depd": "~1.1.0", 142 | "http-errors": "~1.5.0", 143 | "iconv-lite": "0.4.13", 144 | "on-finished": "~2.3.0", 145 | "qs": "6.2.0", 146 | "raw-body": "~2.1.7", 147 | "type-is": "~1.6.13" 148 | } 149 | }, 150 | "bytes": { 151 | "version": "2.4.0", 152 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", 153 | "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" 154 | }, 155 | "callsite": { 156 | "version": "1.0.0", 157 | "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", 158 | "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" 159 | }, 160 | "component-bind": { 161 | "version": "1.0.0", 162 | "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", 163 | "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" 164 | }, 165 | "component-emitter": { 166 | "version": "1.1.2", 167 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz", 168 | "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=" 169 | }, 170 | "component-inherit": { 171 | "version": "0.0.3", 172 | "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", 173 | "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" 174 | }, 175 | "content-disposition": { 176 | "version": "0.5.1", 177 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.1.tgz", 178 | "integrity": "sha1-h0dsamfI2qh+Muh2Ft+IO6f7Bxs=" 179 | }, 180 | "content-type": { 181 | "version": "1.0.4", 182 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 183 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 184 | }, 185 | "cookie": { 186 | "version": "0.3.1", 187 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 188 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 189 | }, 190 | "cookie-signature": { 191 | "version": "1.0.6", 192 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 193 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 194 | }, 195 | "debug": { 196 | "version": "2.2.0", 197 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", 198 | "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", 199 | "requires": { 200 | "ms": "0.7.1" 201 | } 202 | }, 203 | "depd": { 204 | "version": "1.1.2", 205 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 206 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 207 | }, 208 | "destroy": { 209 | "version": "1.0.4", 210 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 211 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 212 | }, 213 | "ee-first": { 214 | "version": "1.1.1", 215 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 216 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 217 | }, 218 | "encodeurl": { 219 | "version": "1.0.2", 220 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 221 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 222 | }, 223 | "engine.io": { 224 | "version": "1.8.1", 225 | "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.1.tgz", 226 | "integrity": "sha1-IAZuqQMwTxPuN/EPqv9rR4T2Q3M=", 227 | "requires": { 228 | "accepts": "1.3.3", 229 | "base64id": "0.1.0", 230 | "cookie": "0.3.1", 231 | "debug": "2.3.3", 232 | "engine.io-parser": "1.3.1", 233 | "ws": "1.1.1" 234 | }, 235 | "dependencies": { 236 | "accepts": { 237 | "version": "1.3.3", 238 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz", 239 | "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=", 240 | "requires": { 241 | "mime-types": "~2.1.11", 242 | "negotiator": "0.6.1" 243 | } 244 | }, 245 | "debug": { 246 | "version": "2.3.3", 247 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 248 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 249 | "requires": { 250 | "ms": "0.7.2" 251 | } 252 | }, 253 | "ms": { 254 | "version": "0.7.2", 255 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 256 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" 257 | }, 258 | "negotiator": { 259 | "version": "0.6.1", 260 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 261 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 262 | } 263 | } 264 | }, 265 | "engine.io-client": { 266 | "version": "1.8.1", 267 | "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.1.tgz", 268 | "integrity": "sha1-cSN+m7zgSGJnXU1r++81HItqNaM=", 269 | "requires": { 270 | "component-emitter": "1.2.1", 271 | "component-inherit": "0.0.3", 272 | "debug": "2.3.3", 273 | "engine.io-parser": "1.3.1", 274 | "has-cors": "1.1.0", 275 | "indexof": "0.0.1", 276 | "parsejson": "0.0.3", 277 | "parseqs": "0.0.5", 278 | "parseuri": "0.0.5", 279 | "ws": "1.1.1", 280 | "xmlhttprequest-ssl": "1.5.3", 281 | "yeast": "0.1.2" 282 | }, 283 | "dependencies": { 284 | "component-emitter": { 285 | "version": "1.2.1", 286 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 287 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 288 | }, 289 | "debug": { 290 | "version": "2.3.3", 291 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 292 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 293 | "requires": { 294 | "ms": "0.7.2" 295 | } 296 | }, 297 | "ms": { 298 | "version": "0.7.2", 299 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 300 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" 301 | } 302 | } 303 | }, 304 | "engine.io-parser": { 305 | "version": "1.3.1", 306 | "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.1.tgz", 307 | "integrity": "sha1-lVTxrjMQfW+9FwylRm0vgz9qB88=", 308 | "requires": { 309 | "after": "0.8.1", 310 | "arraybuffer.slice": "0.0.6", 311 | "base64-arraybuffer": "0.1.5", 312 | "blob": "0.0.4", 313 | "has-binary": "0.1.6", 314 | "wtf-8": "1.0.0" 315 | }, 316 | "dependencies": { 317 | "has-binary": { 318 | "version": "0.1.6", 319 | "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz", 320 | "integrity": "sha1-JTJvOc+k9hath4eJTjryz7x7bhA=", 321 | "requires": { 322 | "isarray": "0.0.1" 323 | } 324 | } 325 | } 326 | }, 327 | "escape-html": { 328 | "version": "1.0.3", 329 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 330 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 331 | }, 332 | "etag": { 333 | "version": "1.7.0", 334 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz", 335 | "integrity": "sha1-A9MLX2fdbmMtKUXTDWZScxo01dg=" 336 | }, 337 | "express": { 338 | "version": "4.14.0", 339 | "resolved": "https://registry.npmjs.org/express/-/express-4.14.0.tgz", 340 | "integrity": "sha1-we4/Qs3Ikfs9xlCoki1R7IR9DWY=", 341 | "requires": { 342 | "accepts": "~1.3.3", 343 | "array-flatten": "1.1.1", 344 | "content-disposition": "0.5.1", 345 | "content-type": "~1.0.2", 346 | "cookie": "0.3.1", 347 | "cookie-signature": "1.0.6", 348 | "debug": "~2.2.0", 349 | "depd": "~1.1.0", 350 | "encodeurl": "~1.0.1", 351 | "escape-html": "~1.0.3", 352 | "etag": "~1.7.0", 353 | "finalhandler": "0.5.0", 354 | "fresh": "0.3.0", 355 | "merge-descriptors": "1.0.1", 356 | "methods": "~1.1.2", 357 | "on-finished": "~2.3.0", 358 | "parseurl": "~1.3.1", 359 | "path-to-regexp": "0.1.7", 360 | "proxy-addr": "~1.1.2", 361 | "qs": "6.2.0", 362 | "range-parser": "~1.2.0", 363 | "send": "0.14.1", 364 | "serve-static": "~1.11.1", 365 | "type-is": "~1.6.13", 366 | "utils-merge": "1.0.0", 367 | "vary": "~1.1.0" 368 | } 369 | }, 370 | "finalhandler": { 371 | "version": "0.5.0", 372 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.0.tgz", 373 | "integrity": "sha1-6VCKvs6bbbqHGmlCodeRG5GRGsc=", 374 | "requires": { 375 | "debug": "~2.2.0", 376 | "escape-html": "~1.0.3", 377 | "on-finished": "~2.3.0", 378 | "statuses": "~1.3.0", 379 | "unpipe": "~1.0.0" 380 | }, 381 | "dependencies": { 382 | "statuses": { 383 | "version": "1.3.1", 384 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 385 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" 386 | } 387 | } 388 | }, 389 | "forwarded": { 390 | "version": "0.1.2", 391 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 392 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 393 | }, 394 | "fresh": { 395 | "version": "0.3.0", 396 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz", 397 | "integrity": "sha1-ZR+DjiJCTnVm3hYdg1jKoZn4PU8=" 398 | }, 399 | "has-binary": { 400 | "version": "0.1.7", 401 | "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz", 402 | "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=", 403 | "requires": { 404 | "isarray": "0.0.1" 405 | } 406 | }, 407 | "has-cors": { 408 | "version": "1.1.0", 409 | "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", 410 | "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" 411 | }, 412 | "http-errors": { 413 | "version": "1.5.1", 414 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.1.tgz", 415 | "integrity": "sha1-eIwNLB3iyBuebowBhDtrl+uSB1A=", 416 | "requires": { 417 | "inherits": "2.0.3", 418 | "setprototypeof": "1.0.2", 419 | "statuses": ">= 1.3.1 < 2" 420 | } 421 | }, 422 | "iconv-lite": { 423 | "version": "0.4.13", 424 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz", 425 | "integrity": "sha1-H4irpKsLFQjoMSrMOTRfNumS4vI=" 426 | }, 427 | "indexof": { 428 | "version": "0.0.1", 429 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", 430 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" 431 | }, 432 | "inherits": { 433 | "version": "2.0.3", 434 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 435 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 436 | }, 437 | "ipaddr.js": { 438 | "version": "1.4.0", 439 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz", 440 | "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA=" 441 | }, 442 | "isarray": { 443 | "version": "0.0.1", 444 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 445 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 446 | }, 447 | "json3": { 448 | "version": "3.3.2", 449 | "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", 450 | "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=" 451 | }, 452 | "media-typer": { 453 | "version": "0.3.0", 454 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 455 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 456 | }, 457 | "merge-descriptors": { 458 | "version": "1.0.1", 459 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 460 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 461 | }, 462 | "methods": { 463 | "version": "1.1.2", 464 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 465 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 466 | }, 467 | "mime": { 468 | "version": "1.3.4", 469 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", 470 | "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" 471 | }, 472 | "mime-db": { 473 | "version": "1.44.0", 474 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", 475 | "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" 476 | }, 477 | "mime-types": { 478 | "version": "2.1.27", 479 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", 480 | "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", 481 | "requires": { 482 | "mime-db": "1.44.0" 483 | } 484 | }, 485 | "morgan": { 486 | "version": "1.7.0", 487 | "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.7.0.tgz", 488 | "integrity": "sha1-6xDKjlDRq+D409rVwCAdBS2YHGI=", 489 | "requires": { 490 | "basic-auth": "~1.0.3", 491 | "debug": "~2.2.0", 492 | "depd": "~1.1.0", 493 | "on-finished": "~2.3.0", 494 | "on-headers": "~1.0.1" 495 | } 496 | }, 497 | "ms": { 498 | "version": "0.7.1", 499 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", 500 | "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=" 501 | }, 502 | "negotiator": { 503 | "version": "0.6.2", 504 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", 505 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" 506 | }, 507 | "object-assign": { 508 | "version": "4.1.0", 509 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz", 510 | "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=" 511 | }, 512 | "object-component": { 513 | "version": "0.0.3", 514 | "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", 515 | "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" 516 | }, 517 | "on-finished": { 518 | "version": "2.3.0", 519 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 520 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 521 | "requires": { 522 | "ee-first": "1.1.1" 523 | } 524 | }, 525 | "on-headers": { 526 | "version": "1.0.2", 527 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", 528 | "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" 529 | }, 530 | "options": { 531 | "version": "0.0.6", 532 | "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", 533 | "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" 534 | }, 535 | "parsejson": { 536 | "version": "0.0.3", 537 | "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz", 538 | "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=", 539 | "requires": { 540 | "better-assert": "~1.0.0" 541 | } 542 | }, 543 | "parseqs": { 544 | "version": "0.0.5", 545 | "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", 546 | "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", 547 | "requires": { 548 | "better-assert": "~1.0.0" 549 | } 550 | }, 551 | "parseuri": { 552 | "version": "0.0.5", 553 | "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", 554 | "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", 555 | "requires": { 556 | "better-assert": "~1.0.0" 557 | } 558 | }, 559 | "parseurl": { 560 | "version": "1.3.3", 561 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", 562 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" 563 | }, 564 | "path-to-regexp": { 565 | "version": "0.1.7", 566 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 567 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 568 | }, 569 | "proxy-addr": { 570 | "version": "1.1.5", 571 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz", 572 | "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=", 573 | "requires": { 574 | "forwarded": "~0.1.0", 575 | "ipaddr.js": "1.4.0" 576 | } 577 | }, 578 | "qs": { 579 | "version": "6.2.0", 580 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.0.tgz", 581 | "integrity": "sha1-O3hIwDwt7OaalSKw+ujEEm10Xzs=" 582 | }, 583 | "range-parser": { 584 | "version": "1.2.1", 585 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", 586 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" 587 | }, 588 | "raw-body": { 589 | "version": "2.1.7", 590 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz", 591 | "integrity": "sha1-rf6s4uT7MJgFgBTQjActzFl1h3Q=", 592 | "requires": { 593 | "bytes": "2.4.0", 594 | "iconv-lite": "0.4.13", 595 | "unpipe": "1.0.0" 596 | } 597 | }, 598 | "send": { 599 | "version": "0.14.1", 600 | "resolved": "https://registry.npmjs.org/send/-/send-0.14.1.tgz", 601 | "integrity": "sha1-qVSYQyU5L1FTKndgdg5FlZjIn3o=", 602 | "requires": { 603 | "debug": "~2.2.0", 604 | "depd": "~1.1.0", 605 | "destroy": "~1.0.4", 606 | "encodeurl": "~1.0.1", 607 | "escape-html": "~1.0.3", 608 | "etag": "~1.7.0", 609 | "fresh": "0.3.0", 610 | "http-errors": "~1.5.0", 611 | "mime": "1.3.4", 612 | "ms": "0.7.1", 613 | "on-finished": "~2.3.0", 614 | "range-parser": "~1.2.0", 615 | "statuses": "~1.3.0" 616 | }, 617 | "dependencies": { 618 | "statuses": { 619 | "version": "1.3.1", 620 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 621 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" 622 | } 623 | } 624 | }, 625 | "serve-static": { 626 | "version": "1.11.2", 627 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.11.2.tgz", 628 | "integrity": "sha1-LPmIm9RDWjIMw2iVyapXvWYuasc=", 629 | "requires": { 630 | "encodeurl": "~1.0.1", 631 | "escape-html": "~1.0.3", 632 | "parseurl": "~1.3.1", 633 | "send": "0.14.2" 634 | }, 635 | "dependencies": { 636 | "ms": { 637 | "version": "0.7.2", 638 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 639 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" 640 | }, 641 | "send": { 642 | "version": "0.14.2", 643 | "resolved": "https://registry.npmjs.org/send/-/send-0.14.2.tgz", 644 | "integrity": "sha1-ObBDiz9RC+Xcb2Z6EfcWiTaM3u8=", 645 | "requires": { 646 | "debug": "~2.2.0", 647 | "depd": "~1.1.0", 648 | "destroy": "~1.0.4", 649 | "encodeurl": "~1.0.1", 650 | "escape-html": "~1.0.3", 651 | "etag": "~1.7.0", 652 | "fresh": "0.3.0", 653 | "http-errors": "~1.5.1", 654 | "mime": "1.3.4", 655 | "ms": "0.7.2", 656 | "on-finished": "~2.3.0", 657 | "range-parser": "~1.2.0", 658 | "statuses": "~1.3.1" 659 | } 660 | }, 661 | "statuses": { 662 | "version": "1.3.1", 663 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 664 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" 665 | } 666 | } 667 | }, 668 | "setprototypeof": { 669 | "version": "1.0.2", 670 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.2.tgz", 671 | "integrity": "sha1-gaVSFB7BBLiOic44MQOtXGZWTQg=" 672 | }, 673 | "socket.io": { 674 | "version": "1.7.1", 675 | "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.1.tgz", 676 | "integrity": "sha1-o012P9Is2XVkPC8MfF8Uum2oCq8=", 677 | "requires": { 678 | "debug": "2.3.3", 679 | "engine.io": "1.8.1", 680 | "has-binary": "0.1.7", 681 | "object-assign": "4.1.0", 682 | "socket.io-adapter": "0.5.0", 683 | "socket.io-client": "1.7.1", 684 | "socket.io-parser": "2.3.1" 685 | }, 686 | "dependencies": { 687 | "debug": { 688 | "version": "2.3.3", 689 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 690 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 691 | "requires": { 692 | "ms": "0.7.2" 693 | } 694 | }, 695 | "ms": { 696 | "version": "0.7.2", 697 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 698 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" 699 | } 700 | } 701 | }, 702 | "socket.io-adapter": { 703 | "version": "0.5.0", 704 | "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz", 705 | "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=", 706 | "requires": { 707 | "debug": "2.3.3", 708 | "socket.io-parser": "2.3.1" 709 | }, 710 | "dependencies": { 711 | "debug": { 712 | "version": "2.3.3", 713 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 714 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 715 | "requires": { 716 | "ms": "0.7.2" 717 | } 718 | }, 719 | "ms": { 720 | "version": "0.7.2", 721 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 722 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" 723 | } 724 | } 725 | }, 726 | "socket.io-client": { 727 | "version": "1.7.1", 728 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.1.tgz", 729 | "integrity": "sha1-bCNyXt/4BPORnBzk67JeWRxuYdc=", 730 | "requires": { 731 | "backo2": "1.0.2", 732 | "component-bind": "1.0.0", 733 | "component-emitter": "1.2.1", 734 | "debug": "2.3.3", 735 | "engine.io-client": "1.8.1", 736 | "has-binary": "0.1.7", 737 | "indexof": "0.0.1", 738 | "object-component": "0.0.3", 739 | "parseuri": "0.0.5", 740 | "socket.io-parser": "2.3.1", 741 | "to-array": "0.1.4" 742 | }, 743 | "dependencies": { 744 | "component-emitter": { 745 | "version": "1.2.1", 746 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", 747 | "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" 748 | }, 749 | "debug": { 750 | "version": "2.3.3", 751 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz", 752 | "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=", 753 | "requires": { 754 | "ms": "0.7.2" 755 | } 756 | }, 757 | "ms": { 758 | "version": "0.7.2", 759 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", 760 | "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" 761 | } 762 | } 763 | }, 764 | "socket.io-parser": { 765 | "version": "2.3.1", 766 | "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz", 767 | "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=", 768 | "requires": { 769 | "component-emitter": "1.1.2", 770 | "debug": "2.2.0", 771 | "isarray": "0.0.1", 772 | "json3": "3.3.2" 773 | } 774 | }, 775 | "statuses": { 776 | "version": "1.5.0", 777 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 778 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 779 | }, 780 | "to-array": { 781 | "version": "0.1.4", 782 | "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", 783 | "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" 784 | }, 785 | "type-is": { 786 | "version": "1.6.18", 787 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", 788 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", 789 | "requires": { 790 | "media-typer": "0.3.0", 791 | "mime-types": "~2.1.24" 792 | } 793 | }, 794 | "typescript": { 795 | "version": "2.1.6", 796 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.1.6.tgz", 797 | "integrity": "sha1-QMfm6eXaeWG3cYtVUF+crJSHpgc=", 798 | "dev": true 799 | }, 800 | "ultron": { 801 | "version": "1.0.2", 802 | "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz", 803 | "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=" 804 | }, 805 | "unpipe": { 806 | "version": "1.0.0", 807 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 808 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 809 | }, 810 | "utils-merge": { 811 | "version": "1.0.0", 812 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", 813 | "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" 814 | }, 815 | "vary": { 816 | "version": "1.1.2", 817 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 818 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 819 | }, 820 | "ws": { 821 | "version": "1.1.1", 822 | "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.1.tgz", 823 | "integrity": "sha1-CC3bbGQehdS7RR8D1S8G6r2x8Bg=", 824 | "requires": { 825 | "options": ">=0.0.5", 826 | "ultron": "1.0.x" 827 | } 828 | }, 829 | "wtf-8": { 830 | "version": "1.0.0", 831 | "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz", 832 | "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=" 833 | }, 834 | "xmlhttprequest-ssl": { 835 | "version": "1.5.3", 836 | "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz", 837 | "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=" 838 | }, 839 | "yeast": { 840 | "version": "0.1.2", 841 | "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", 842 | "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" 843 | } 844 | } 845 | } 846 | -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "./dist/server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "tsc -p .", 9 | "start": "node ./dist/server.js" 10 | }, 11 | "keywords": [], 12 | "author": "Philipp Jäcks", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "@types/body-parser": "0.0.33", 16 | "@types/express": "4.11.1", 17 | "@types/express-serve-static-core": "4.0.49", 18 | "@types/morgan": "1.7.32", 19 | "@types/node": "0.0.2", 20 | "@types/socket.io": "1.4.27", 21 | "typescript": "2.1.6" 22 | }, 23 | "dependencies": { 24 | "body-parser": "1.15.2", 25 | "express": "4.14.0", 26 | "morgan": "1.7.0", 27 | "socket.io": "1.7.1" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /backend/server.ts: -------------------------------------------------------------------------------- 1 | import * as express from 'express'; 2 | import * as morgan from 'morgan'; 3 | import * as bodyParser from 'body-parser'; 4 | import * as socketio from 'socket.io'; 5 | import * as http from 'http'; 6 | 7 | class Server { 8 | public app: express.Application; 9 | private server: http.Server; 10 | public io: SocketIO.Server; 11 | private allowedOrigins = [ 'http://localhost:4200' ]; 12 | 13 | 14 | public static bootstrap(): Server { 15 | return new Server(); 16 | } 17 | 18 | constructor() { 19 | this.app = express(); 20 | this.server = http.createServer(this.app); 21 | this.io = socketio().listen(this.server); 22 | this.config(); 23 | this.setupSocket(); 24 | } 25 | 26 | private config() { 27 | this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => { 28 | const origin = req.header('Origin'); 29 | 30 | for (let o of this.allowedOrigins) { 31 | if (o === origin) { 32 | res.header('Access-Control-Allow-Origin', origin); 33 | break; 34 | } 35 | } 36 | }); 37 | 38 | this.app.use(bodyParser.json()); 39 | this.app.use(bodyParser.urlencoded({ extended: true })); 40 | 41 | this.app.use(morgan('dev')); 42 | 43 | this.app.get('/', (req, res) => { 44 | res.send('Hello!'); 45 | }); 46 | 47 | this.server.listen(3000, () => { 48 | console.log('Server is listening on port 3000'); 49 | }); 50 | } 51 | 52 | private setupSocket() { 53 | this.io.on('connection', (socket: SocketIO.Socket) => { 54 | console.log(`Socket ${socket.id} connected`); 55 | // forward WebRTC messages 56 | socket.on('api/v1/webrtc/peermessage', (data: any) => { 57 | console.log('Forward WebRTC peer message:', JSON.stringify(data)); 58 | socket.broadcast.emit('api/v1/webrtc/peermessage', data); 59 | }); 60 | 61 | socket.on('api/v1/webrtc/connect-to-chat', (data: any) => { 62 | console.log(`Client ${socket.id} connected to room`); 63 | socket.broadcast.emit('api/v1/webrtc/peer-connected', { 64 | id: socket.id 65 | }); 66 | }); 67 | 68 | }); 69 | } 70 | } 71 | 72 | Server.bootstrap(); -------------------------------------------------------------------------------- /backend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "outDir": "dist", 6 | "noImplicitAny": true, 7 | "removeComments": true, 8 | "preserveConstEnums": true, 9 | "sourceMap": true, 10 | "typeRoots": [ 11 | "node_modules/@types" 12 | ] 13 | }, 14 | "exclude": [ 15 | "node_modules" 16 | ] 17 | } -------------------------------------------------------------------------------- /frontend/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | /bower_components 10 | 11 | # IDEs and editors 12 | /.idea 13 | /.vscode 14 | .project 15 | .classpath 16 | .c9/ 17 | *.launch 18 | .settings/ 19 | 20 | # misc 21 | /.sass-cache 22 | /connect.lock 23 | /coverage/* 24 | /libpeerconnection.log 25 | npm-debug.log 26 | testem.log 27 | /typings 28 | 29 | # e2e 30 | /e2e/*.js 31 | /e2e/*.map 32 | 33 | #System Files 34 | .DS_Store 35 | Thumbs.db 36 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # Frontend 2 | 3 | This project was generated with [angular-cli](https://github.com/angular/angular-cli) version 1.0.0-beta.22-1. 4 | 5 | ## Development server 6 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 7 | 8 | ## Code scaffolding 9 | 10 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class`. 11 | 12 | ## Build 13 | 14 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. 15 | 16 | ## Running unit tests 17 | 18 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 19 | 20 | ## Running end-to-end tests 21 | 22 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 23 | Before running the tests make sure you are serving the app via `ng serve`. 24 | 25 | ## Deploying to Github Pages 26 | 27 | Run `ng github-pages:deploy` to deploy to Github Pages. 28 | 29 | ## Further help 30 | 31 | To get more help on the `angular-cli` use `ng --help` or go check out the [Angular-CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 32 | -------------------------------------------------------------------------------- /frontend/angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "project": { 3 | "version": "1.0.0-beta.22-1", 4 | "name": "frontend" 5 | }, 6 | "apps": [ 7 | { 8 | "root": "src", 9 | "outDir": "dist", 10 | "assets": [ 11 | "assets", 12 | "favicon.ico" 13 | ], 14 | "index": "index.html", 15 | "main": "main.ts", 16 | "test": "test.ts", 17 | "tsconfig": "tsconfig.json", 18 | "prefix": "app", 19 | "mobile": false, 20 | "styles": [ 21 | "styles.css" 22 | ], 23 | "scripts": [], 24 | "environments": { 25 | "source": "environments/environment.ts", 26 | "dev": "environments/environment.ts", 27 | "prod": "environments/environment.prod.ts" 28 | } 29 | } 30 | ], 31 | "addons": [], 32 | "packages": [], 33 | "e2e": { 34 | "protractor": { 35 | "config": "./protractor.conf.js" 36 | } 37 | }, 38 | "test": { 39 | "karma": { 40 | "config": "./karma.conf.js" 41 | } 42 | }, 43 | "defaults": { 44 | "styleExt": "css", 45 | "prefixInterfaces": false, 46 | "inline": { 47 | "style": false, 48 | "template": false 49 | }, 50 | "spec": { 51 | "class": false, 52 | "component": true, 53 | "directive": true, 54 | "module": false, 55 | "pipe": true, 56 | "service": true 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /frontend/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { FrontendPage } from './app.po'; 2 | 3 | describe('frontend App', function() { 4 | let page: FrontendPage; 5 | 6 | beforeEach(() => { 7 | page = new FrontendPage(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('app works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /frontend/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class FrontendPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /frontend/e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "declaration": false, 5 | "emitDecoratorMetadata": true, 6 | "experimentalDecorators": true, 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "outDir": "../dist/out-tsc-e2e", 10 | "sourceMap": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "../node_modules/@types" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/0.13/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', 'angular-cli'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-remap-istanbul'), 12 | require('angular-cli/plugins/karma') 13 | ], 14 | files: [ 15 | { pattern: './src/test.ts', watched: false } 16 | ], 17 | preprocessors: { 18 | './src/test.ts': ['angular-cli'] 19 | }, 20 | mime: { 21 | 'text/x-typescript': ['ts','tsx'] 22 | }, 23 | remapIstanbulReporter: { 24 | reports: { 25 | html: 'coverage', 26 | lcovonly: './coverage/coverage.lcov' 27 | } 28 | }, 29 | angularCli: { 30 | config: './angular-cli.json', 31 | environment: 'dev' 32 | }, 33 | reporters: config.angularCli && config.angularCli.codeCoverage 34 | ? ['progress', 'karma-remap-istanbul'] 35 | : ['progress'], 36 | port: 9876, 37 | colors: true, 38 | logLevel: config.LOG_INFO, 39 | autoWatch: true, 40 | browsers: ['Chrome'], 41 | singleRun: false 42 | }); 43 | }; 44 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "author": "Philipp Jäcks", 6 | "angular-cli": {}, 7 | "scripts": { 8 | "start": "ng serve", 9 | "lint": "tslint \"src/**/*.ts\"", 10 | "test": "ng test", 11 | "pree2e": "webdriver-manager update", 12 | "e2e": "protractor", 13 | "postinstall": "typings install" 14 | }, 15 | "private": true, 16 | "dependencies": { 17 | "@angular/common": "2.3.1", 18 | "@angular/compiler": "2.3.1", 19 | "@angular/core": "2.3.1", 20 | "@angular/forms": "2.3.1", 21 | "@angular/http": "2.3.1", 22 | "@angular/material": "2.0.0-alpha.10", 23 | "@angular/platform-browser": "2.3.1", 24 | "@angular/platform-browser-dynamic": "2.3.1", 25 | "@angular/router": "3.2.3", 26 | "core-js": "^2.4.1", 27 | "immutable": "3.8.1", 28 | "rxjs": "5.0.0-beta.12", 29 | "socket.io": "1.7.1", 30 | "socket.io-client": "1.7.1", 31 | "ts-helpers": "^1.1.1", 32 | "webrtc-adapter": "2.0.8", 33 | "zone.js": "^0.6.23" 34 | }, 35 | "devDependencies": { 36 | "@angular/compiler-cli": "2.3.1", 37 | "@types/jasmine": "2.5.38", 38 | "@types/node": "^6.0.42", 39 | "@types/socket.io": "1.4.27", 40 | "@types/socket.io-client": "1.4.29", 41 | "@types/webrtc": "0.0.21", 42 | "angular-cli": "1.0.0-beta.28.3", 43 | "codelyzer": "~2.0.0-beta.1", 44 | "jasmine-core": "2.5.2", 45 | "jasmine-spec-reporter": "2.5.0", 46 | "karma": "1.2.0", 47 | "karma-chrome-launcher": "^2.0.0", 48 | "karma-cli": "^1.0.1", 49 | "karma-jasmine": "^1.0.2", 50 | "karma-remap-istanbul": "^0.2.1", 51 | "protractor": "4.0.9", 52 | "ts-node": "1.2.1", 53 | "tslint": "^4.0.2", 54 | "typescript": "~2.0.3", 55 | "typings": "2.0.0", 56 | "webdriver-manager": "10.2.5" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /frontend/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/docs/referenceConf.js 3 | 4 | /*global jasmine */ 5 | var SpecReporter = require('jasmine-spec-reporter'); 6 | 7 | exports.config = { 8 | allScriptsTimeout: 11000, 9 | specs: [ 10 | './e2e/**/*.e2e-spec.ts' 11 | ], 12 | capabilities: { 13 | 'browserName': 'chrome' 14 | }, 15 | directConnect: true, 16 | baseUrl: 'http://localhost:4200/', 17 | framework: 'jasmine', 18 | jasmineNodeOpts: { 19 | showColors: true, 20 | defaultTimeoutInterval: 30000, 21 | print: function() {} 22 | }, 23 | useAllAngular2AppRoots: true, 24 | beforeLaunch: function() { 25 | require('ts-node').register({ 26 | project: 'e2e' 27 | }); 28 | }, 29 | onPrepare: function() { 30 | jasmine.getEnv().addReporter(new SpecReporter()); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /frontend/src/app/app.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pj035/angular2-webrtc-video-example/b7d76503de9cf20f844ec7143a76e300585a1ee3/frontend/src/app/app.component.css -------------------------------------------------------------------------------- /frontend/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |