palava-client 2.2.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/room.js ADDED
@@ -0,0 +1,213 @@
1
+ // Generated by CoffeeScript 2.7.0
2
+ var boundMethodCheck = function(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new Error('Bound instance method accessed before binding'); } };
3
+
4
+ import EventEmitter from 'wolfy87-eventemitter';
5
+
6
+ import * as browser from './browser.js';
7
+
8
+ import {
9
+ Distributor
10
+ } from './distributor.js';
11
+
12
+ import {
13
+ LocalPeer
14
+ } from './local_peer.js';
15
+
16
+ import {
17
+ RemotePeer
18
+ } from './remote_peer.js';
19
+
20
+ // A room connecting multiple participants
21
+
22
+ export var Room = class Room extends EventEmitter {
23
+ // @param roomId [String] ID of the room
24
+ // @param channel [Channel] Channel used for communication
25
+ // @param userMedia [UserMedia] UserMedia used for local user
26
+ // @param options [Object] Further objects for the room
27
+ // @option options joinTimeout [Integer] Timeout for joining
28
+ // @option options ownStatus [Object] The status of the local user
29
+
30
+ constructor(roomId, channel, userMedia, options = {}) {
31
+ super();
32
+ // Bind UserMedia events to room events
33
+
34
+ // @nodoc
35
+
36
+ this.setupUserMedia = this.setupUserMedia.bind(this);
37
+ // Set default options
38
+
39
+ // @nodoc
40
+
41
+ this.setupOptions = this.setupOptions.bind(this);
42
+ // Initialize global distributor and messaging
43
+
44
+ // @nodoc
45
+
46
+ this.setupDistributor = this.setupDistributor.bind(this);
47
+ // Join the room
48
+
49
+ // @param status [Object] Status of the local user
50
+
51
+ this.join = this.join.bind(this);
52
+ // Send leave room event to server
53
+
54
+ this.leave = this.leave.bind(this);
55
+ // Makes sure room is closed by disconnecting all peer connections and clearing all timeouts
56
+
57
+ this.destroy = this.destroy.bind(this);
58
+ // Find peer with the given id
59
+
60
+ // @param id [String] id of the searched peer
61
+
62
+ // @return [Peer] The peer with the given id or `undefined`
63
+
64
+ this.getPeerById = this.getPeerById.bind(this);
65
+ // Get local peer
66
+
67
+ // @return [Peer] The local peer
68
+
69
+ this.getLocalPeer = this.getLocalPeer.bind(this);
70
+ // Get remote peers
71
+
72
+ // @return [Array] All peers except the local peer
73
+
74
+ this.getRemotePeers = this.getRemotePeers.bind(this);
75
+ // Get all peers
76
+
77
+ // @return [Array] All peers including the local peer
78
+
79
+ this.getAllPeers = this.getAllPeers.bind(this);
80
+ this.id = roomId;
81
+ this.userMedia = userMedia;
82
+ this.channel = channel;
83
+ this.peers = {};
84
+ this.options = options;
85
+ this.setupUserMedia();
86
+ this.setupDistributor();
87
+ this.setupOptions();
88
+ }
89
+
90
+ setupUserMedia() {
91
+ boundMethodCheck(this, Room);
92
+ this.userMedia.on('stream_ready', (stream) => {
93
+ return this.emit('local_stream_ready', stream);
94
+ });
95
+ this.userMedia.on('stream_error', (error) => {
96
+ return this.emit('local_stream_error', error);
97
+ });
98
+ return this.userMedia.on('stream_released', () => {
99
+ return this.emit('local_stream_removed');
100
+ });
101
+ }
102
+
103
+ setupOptions() {
104
+ var base, base1, base2;
105
+ boundMethodCheck(this, Room);
106
+ (base = this.options).joinTimeout || (base.joinTimeout = 1000);
107
+ (base1 = this.options).ownStatus || (base1.ownStatus = {});
108
+ return (base2 = this.options).filterIceCandidateTypes || (base2.filterIceCandidateTypes = []);
109
+ }
110
+
111
+ setupDistributor() {
112
+ boundMethodCheck(this, Room);
113
+ this.distributor = new Distributor(this.channel);
114
+ this.distributor.on('joined_room', (msg) => {
115
+ var i, len, newPeer, offers, peer, ref, turnCredentials;
116
+ clearTimeout(this.joinCheckTimeout);
117
+ if (msg.turn_user) {
118
+ turnCredentials = {
119
+ user: msg.turn_user,
120
+ password: msg.turn_password
121
+ };
122
+ } else {
123
+ turnCredentials = null;
124
+ }
125
+ new LocalPeer(msg.own_id, this.options.ownStatus, this);
126
+ ref = msg.peers;
127
+ for (i = 0, len = ref.length; i < len; i++) {
128
+ peer = ref[i];
129
+ offers = !browser.isChrome();
130
+ newPeer = new RemotePeer(peer.peer_id, peer.status, this, offers, turnCredentials);
131
+ }
132
+ return this.emit("joined");
133
+ });
134
+ this.distributor.on('new_peer', (msg) => {
135
+ var newPeer, offers;
136
+ offers = msg.status.user_agent === 'chrome';
137
+ newPeer = new RemotePeer(msg.peer_id, msg.status, this, offers);
138
+ return this.emit('peer_joined', newPeer);
139
+ });
140
+ this.distributor.on('error', (msg) => {
141
+ return this.emit('signaling_error', 'server', msg.description);
142
+ });
143
+ return this.distributor.on('shutdown', (msg) => {
144
+ return this.emit('signaling_shutdown', msg.seconds);
145
+ });
146
+ }
147
+
148
+ join(status = {}) {
149
+ var base, i, key, len;
150
+ boundMethodCheck(this, Room);
151
+ this.joinCheckTimeout = setTimeout((() => {
152
+ return this.emit('join_error');
153
+ }), this.options.joinTimeout);
154
+ for (i = 0, len = status.length; i < len; i++) {
155
+ key = status[i];
156
+ this.options.ownStatus[key] = status[key];
157
+ }
158
+ (base = this.options.ownStatus).user_agent || (base.user_agent = browser.getUserAgent());
159
+ return this.distributor.send({
160
+ event: 'join_room',
161
+ room_id: this.id,
162
+ status: this.options.ownStatus
163
+ });
164
+ }
165
+
166
+ leave() {
167
+ boundMethodCheck(this, Room);
168
+ if (this.channel) {
169
+ this.distributor.send({
170
+ event: 'leave_room'
171
+ });
172
+ }
173
+ return this.emit('left');
174
+ }
175
+
176
+ destroy() {
177
+ boundMethodCheck(this, Room);
178
+ this.getRemotePeers().forEach((peer) => {
179
+ return peer.closePeerConnection();
180
+ });
181
+ return clearTimeout(this.joinCheckTimeout);
182
+ }
183
+
184
+ getPeerById(id) {
185
+ boundMethodCheck(this, Room);
186
+ return this.peers[id];
187
+ }
188
+
189
+ getLocalPeer() {
190
+ boundMethodCheck(this, Room);
191
+ return this.localPeer;
192
+ }
193
+
194
+ getRemotePeers() {
195
+ boundMethodCheck(this, Room);
196
+ return this.getAllPeers(false);
197
+ }
198
+
199
+ getAllPeers(allowLocal = true) {
200
+ var id, peer, peers, ref;
201
+ boundMethodCheck(this, Room);
202
+ peers = [];
203
+ ref = this.peers;
204
+ for (id in ref) {
205
+ peer = ref[id];
206
+ if (allowLocal || !peer.local) {
207
+ peers.push(peer);
208
+ }
209
+ }
210
+ return peers;
211
+ }
212
+
213
+ };
@@ -0,0 +1,319 @@
1
+ // Generated by CoffeeScript 2.7.0
2
+ var boundMethodCheck = function(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new Error('Bound instance method accessed before binding'); } };
3
+
4
+ import EventEmitter from 'wolfy87-eventemitter';
5
+
6
+ import * as browser from './browser.js';
7
+
8
+ import {
9
+ Gum
10
+ } from './gum.js';
11
+
12
+ import {
13
+ Room
14
+ } from './room.js';
15
+
16
+ import {
17
+ WebSocketChannel
18
+ } from './web_socket_channel.js';
19
+
20
+ // Session is a wrapper around a concrete room, channel and userMedia
21
+ export var Session = class Session extends EventEmitter {
22
+ // Creates the session object
23
+
24
+ // @param o [Object] See Session#connect for available options
25
+
26
+ constructor(o = {}) {
27
+ super();
28
+ // Initializes the websocket channel, retrieves user media and joins room when stream ready
29
+
30
+ // @param o [Object] Options for the session
31
+ // @option o webSocketAddress [WebSocket] The websocket endpoint to connect to
32
+ // @option o userMediaConfig [Object] getUserMedia constraints
33
+ // @option o stun [String] Address of stun server
34
+ // @option o turn [String] Turn address and credentials
35
+ // @option o joinTimeout [Integer] Milliseconds till joining is canceled by throwing
36
+ // the "join_error" event
37
+
38
+ this.connect = this.connect.bind(this);
39
+ // Reconnect the session
40
+
41
+ this.reconnect = this.reconnect.bind(this);
42
+ // Reset channel and room
43
+
44
+ // @param o [Object] Also release user media
45
+
46
+ this.tearDown = this.tearDown.bind(this);
47
+ // Moves options into inner state
48
+
49
+ // @nodoc
50
+
51
+ this.assignOptions = this.assignOptions.bind(this);
52
+ // Checks whether the inner state of the session is valid. Emits events otherwise
53
+
54
+ // @return [Boolean] `true` if options are correct and webrtc support is given
55
+
56
+ this.checkRequirements = this.checkRequirements.bind(this);
57
+ // Get the channel of the session
58
+
59
+ // @return [Channel] The channel of the session
60
+
61
+ this.getChannel = this.getChannel.bind(this);
62
+ // Get the UserMedia of the session
63
+
64
+ // @return [UserMedia] UserMedia of the session
65
+
66
+ this.getUserMedia = this.getUserMedia.bind(this);
67
+ // Get the room of the session
68
+
69
+ // @return [Room] Room of the session
70
+
71
+ this.getRoom = this.getRoom.bind(this);
72
+ // Build connection to websocket endpont
73
+
74
+ // @return [Room] Room of the session
75
+
76
+ this.createChannel = this.createChannel.bind(this);
77
+ // Maps signals from room to session signals
78
+
79
+ // @nodoc
80
+
81
+ this.createRoom = this.createRoom.bind(this);
82
+ // Destroys the session
83
+ this.destroy = this.destroy.bind(this);
84
+ this.roomOptions = {};
85
+ this.assignOptions(o);
86
+ }
87
+
88
+ connect(o) {
89
+ boundMethodCheck(this, Session);
90
+ this.assignOptions(o);
91
+ if (!this.checkRequirements()) {
92
+ return;
93
+ }
94
+ this.createChannel();
95
+ this.createRoom();
96
+ if (this.userMedia.stream) {
97
+ return this.room.join();
98
+ } else {
99
+ return this.userMedia.requestStream().then(() => {
100
+ return this.room.join();
101
+ });
102
+ }
103
+ }
104
+
105
+ reconnect() {
106
+ boundMethodCheck(this, Session);
107
+ this.emit('session_reconnect');
108
+ this.tearDown();
109
+ this.createChannel();
110
+ this.createRoom();
111
+ return this.room.join();
112
+ }
113
+
114
+ tearDown(resetUserMedia = false) {
115
+ var ref, ref1, ref2, ref3, ref4, ref5;
116
+ boundMethodCheck(this, Session);
117
+ if ((ref = this.room) != null) {
118
+ ref.removeAllListeners();
119
+ }
120
+ if ((ref1 = this.channel) != null) {
121
+ ref1.removeAllListeners();
122
+ }
123
+ if ((ref2 = this.channel) != null ? ref2.isConnected() : void 0) {
124
+ if ((ref3 = this.room) != null) {
125
+ ref3.leave();
126
+ }
127
+ }
128
+ if ((ref4 = this.channel) != null) {
129
+ ref4.close();
130
+ }
131
+ this.channel = null;
132
+ if ((ref5 = this.room) != null) {
133
+ ref5.destroy();
134
+ }
135
+ this.room = null;
136
+ if (resetUserMedia && this.userMedia) {
137
+ return this.userMedia.releaseStream();
138
+ }
139
+ }
140
+
141
+ assignOptions(o) {
142
+ boundMethodCheck(this, Session);
143
+ if (o.roomId) {
144
+ this.roomId = o.roomId;
145
+ }
146
+ if (o.webSocketAddress) {
147
+ this.webSocketAddress = o.webSocketAddress;
148
+ }
149
+ if (o.identity) {
150
+ this.userMedia = o.identity.newUserMedia();
151
+ this.roomOptions.ownStatus = o.identity.getStatus();
152
+ }
153
+ if (o.userMediaConfig) {
154
+ this.userMedia = new Gum(o.userMediaConfig);
155
+ }
156
+ if (o.dataChannels) {
157
+ this.roomOptions.dataChannels = o.dataChannels;
158
+ }
159
+ if (o.stun) {
160
+ this.roomOptions.stun = o.stun;
161
+ }
162
+ if (o.turnUrls) {
163
+ this.roomOptions.turnUrls = o.turnUrls;
164
+ }
165
+ if (o.joinTimeout) {
166
+ this.roomOptions.joinTimeout = o.joinTimeout;
167
+ }
168
+ if (o.filterIceCandidateTypes) {
169
+ return this.roomOptions.filterIceCandidateTypes = o.filterIceCandidateTypes;
170
+ }
171
+ }
172
+
173
+ checkRequirements() {
174
+ var e;
175
+ boundMethodCheck(this, Session);
176
+ if (!this.webSocketAddress) {
177
+ this.emit('argument_error', 'no web socket address given');
178
+ return false;
179
+ }
180
+ if (!this.userMedia) {
181
+ this.emit('argument_error', 'no user media given');
182
+ return false;
183
+ }
184
+ if (!this.roomId) {
185
+ this.emit('argument_error', 'no room id given');
186
+ return false;
187
+ }
188
+ if (!this.roomOptions.stun) {
189
+ this.emit('argument_error', 'no stun server given');
190
+ return false;
191
+ }
192
+ if (this.roomOptions.turnUrls && !Array.isArray(this.roomOptions.turnUrls)) {
193
+ this.emit('argument_error', 'turnUrls must be an array');
194
+ return false;
195
+ }
196
+ if (!navigator.onLine) {
197
+ this.emit('signaling_not_reachable');
198
+ return false;
199
+ }
200
+ if (e = browser.checkForWebrtcError()) {
201
+ this.emit('webrtc_no_support', 'WebRTC is not supported by your browser', e);
202
+ return false;
203
+ }
204
+ return true;
205
+ }
206
+
207
+ getChannel() {
208
+ boundMethodCheck(this, Session);
209
+ return this.channel;
210
+ }
211
+
212
+ getUserMedia() {
213
+ boundMethodCheck(this, Session);
214
+ return this.userMedia;
215
+ }
216
+
217
+ getRoom() {
218
+ boundMethodCheck(this, Session);
219
+ return this.room;
220
+ }
221
+
222
+ createChannel() {
223
+ boundMethodCheck(this, Session);
224
+ this.channel = new WebSocketChannel(this.webSocketAddress);
225
+ this.channel.on('open', () => {
226
+ return this.emit('signaling_open');
227
+ });
228
+ this.channel.on('error', (t, e) => {
229
+ return this.emit('signaling_error', t, e);
230
+ });
231
+ this.channel.on('close', (e) => {
232
+ return this.emit('signaling_close', e);
233
+ });
234
+ return this.channel.on('not_reachable', () => {
235
+ return this.emit('signaling_not_reachable');
236
+ });
237
+ }
238
+
239
+ createRoom() { // TODO move some more stuff away from the room? eg signaling
240
+ boundMethodCheck(this, Session);
241
+ this.room = new Room(this.roomId, this.channel, this.userMedia, this.roomOptions);
242
+ this.room.on('local_stream_ready', (s) => {
243
+ return this.emit('local_stream_ready', s);
244
+ });
245
+ this.room.on('local_stream_error', (e) => {
246
+ return this.emit('local_stream_error', e);
247
+ });
248
+ this.room.on('local_stream_removed', () => {
249
+ return this.emit('local_stream_removed');
250
+ });
251
+ this.room.on('join_error', () => {
252
+ this.tearDown(true);
253
+ return this.emit('room_join_error', this.room);
254
+ });
255
+ this.room.on('full', () => {
256
+ return this.emit('room_full', this.room);
257
+ });
258
+ this.room.on('joined', () => {
259
+ return this.emit('room_joined', this.room);
260
+ });
261
+ this.room.on('left', () => {
262
+ return this.emit('room_left', this.room);
263
+ });
264
+ this.room.on('peer_joined', (p) => {
265
+ return this.emit('peer_joined', p);
266
+ });
267
+ this.room.on('peer_offer', (p) => {
268
+ return this.emit('peer_offer', p);
269
+ });
270
+ this.room.on('peer_answer', (p) => {
271
+ return this.emit('peer_answer', p);
272
+ });
273
+ this.room.on('peer_update', (p) => {
274
+ return this.emit('peer_update', p);
275
+ });
276
+ this.room.on('peer_stream_ready', (p) => {
277
+ return this.emit('peer_stream_ready', p);
278
+ });
279
+ this.room.on('peer_stream_removed', (p) => {
280
+ return this.emit('peer_stream_removed', p);
281
+ });
282
+ this.room.on('peer_connection_pending', (p) => {
283
+ return this.emit('peer_connection_pending', p);
284
+ });
285
+ this.room.on('peer_connection_established', (p) => {
286
+ return this.emit('peer_connection_established', p);
287
+ });
288
+ this.room.on('peer_connection_failed', (p) => {
289
+ return this.emit('peer_connection_failed', p);
290
+ });
291
+ this.room.on('peer_connection_disconnected', (p) => {
292
+ return this.emit('peer_connection_disconnected', p);
293
+ });
294
+ this.room.on('peer_connection_closed', (p) => {
295
+ return this.emit('peer_connection_closed', p);
296
+ });
297
+ this.room.on('peer_left', (p) => {
298
+ return this.emit('peer_left', p);
299
+ });
300
+ this.room.on('peer_channel_ready', (p, n, c) => {
301
+ return this.emit('peer_channel_ready', p, n, c);
302
+ });
303
+ this.room.on('signaling_shutdown', (p) => {
304
+ return this.emit('signaling_shutdown', p);
305
+ });
306
+ this.room.on('signaling_error', (t, e) => {
307
+ return this.emit('signaling_error', t, e);
308
+ });
309
+ return true;
310
+ }
311
+
312
+ destroy() {
313
+ boundMethodCheck(this, Session);
314
+ this.emit('session_before_destroy');
315
+ this.tearDown(true);
316
+ return this.emit('session_after_destroy');
317
+ }
318
+
319
+ };
@@ -0,0 +1,132 @@
1
+ // Generated by CoffeeScript 2.7.0
2
+ var boundMethodCheck = function(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new Error('Bound instance method accessed before binding'); } };
3
+
4
+ import EventEmitter from 'wolfy87-eventemitter';
5
+
6
+ // Channel implementation using websockets
7
+
8
+ // Events: open -> (), message -> (msg), error -> (), close -> ()
9
+
10
+ export var WebSocketChannel = class WebSocketChannel extends EventEmitter {
11
+ // @param address [String] Address of the websocket. Should start with `ws://` for web sockets or `wss://` for secure web sockets.
12
+ constructor(address, retries = 2) {
13
+ super();
14
+ // Returns true if socket is in a good state
15
+ this.isConnected = this.isConnected.bind(this);
16
+ this.sendDeliverOnConnectMessages = this.sendDeliverOnConnectMessages.bind(this);
17
+ // Connects websocket events with the events of this object
18
+
19
+ // @nodoc
20
+
21
+ this.setupWebsocket = this.setupWebsocket.bind(this);
22
+ this.startClientPings = this.startClientPings.bind(this);
23
+ // Sends the given data through the websocket
24
+
25
+ // @param data [Object] Object to send through the channel
26
+
27
+ this.send = this.send.bind(this);
28
+ // Closes the websocket
29
+
30
+ this.close = this.close.bind(this);
31
+ this.address = address;
32
+ this.retries = retries;
33
+ this.messagesToDeliverOnConnect = [];
34
+ this.setupWebsocket();
35
+ this.startClientPings();
36
+ }
37
+
38
+ isConnected() {
39
+ var ref;
40
+ boundMethodCheck(this, WebSocketChannel);
41
+ return ((ref = this.socket) != null ? ref.readyState : void 0) === 1;
42
+ }
43
+
44
+ sendDeliverOnConnectMessages() {
45
+ var i, len, msg, ref;
46
+ boundMethodCheck(this, WebSocketChannel);
47
+ ref = this.messagesToDeliverOnConnect;
48
+ for (i = 0, len = ref.length; i < len; i++) {
49
+ msg = ref[i];
50
+ this.socket.send(msg);
51
+ }
52
+ return this.messagesToDeliverOnConnect = [];
53
+ }
54
+
55
+ setupWebsocket() {
56
+ boundMethodCheck(this, WebSocketChannel);
57
+ this.socket = new WebSocket(this.address);
58
+ this.socket.onopen = (handshake) => {
59
+ this.retries = 0;
60
+ this.sendDeliverOnConnectMessages();
61
+ return this.emit('open', handshake);
62
+ };
63
+ this.socket.onmessage = (msg) => {
64
+ var error, parsedMsg;
65
+ try {
66
+ parsedMsg = JSON.parse(msg.data);
67
+ } catch (error1) {
68
+ error = error1;
69
+ this.emit('error', 'invalid_format', {
70
+ error: error,
71
+ data: msg.data
72
+ });
73
+ return;
74
+ }
75
+ if (parsedMsg.event === "pong") {
76
+ return this.outstandingPongs = 0;
77
+ } else {
78
+ return this.emit('message', parsedMsg);
79
+ }
80
+ };
81
+ this.socket.onerror = (msg) => {
82
+ clearInterval(this.pingInterval);
83
+ if (this.retries > 0) {
84
+ this.retries -= 1;
85
+ this.setupWebsocket();
86
+ return this.startClientPings();
87
+ } else {
88
+ return this.emit('error', 'socket', msg);
89
+ }
90
+ };
91
+ return this.socket.onclose = () => {
92
+ clearInterval(this.pingInterval);
93
+ return this.emit('close');
94
+ };
95
+ }
96
+
97
+ startClientPings() {
98
+ boundMethodCheck(this, WebSocketChannel);
99
+ this.outstandingPongs = 0;
100
+ return this.pingInterval = setInterval(() => {
101
+ if (this.outstandingPongs >= 6) {
102
+ clearInterval(this.pingInterval);
103
+ this.socket.close();
104
+ this.emit('error', "missing_pongs");
105
+ }
106
+ this.socket.send(JSON.stringify({
107
+ event: "ping"
108
+ }));
109
+ return this.outstandingPongs += 1;
110
+ }, 5000);
111
+ }
112
+
113
+ send(data) {
114
+ boundMethodCheck(this, WebSocketChannel);
115
+ if (this.socket.readyState === 1) { // successful connection
116
+ if (this.messagesToDeliverOnConnect.length !== 0) {
117
+ this.sendDeliverOnConnectMessages();
118
+ }
119
+ return this.socket.send(JSON.stringify(data));
120
+ } else if (this.socket.readyState > 1) { // connection closing or closed
121
+ return this.emit('not_reachable'); // connection still to be established
122
+ } else {
123
+ return this.messagesToDeliverOnConnect.push(JSON.stringify(data));
124
+ }
125
+ }
126
+
127
+ close() {
128
+ boundMethodCheck(this, WebSocketChannel);
129
+ return this.socket.close();
130
+ }
131
+
132
+ };
package/package.json CHANGED
@@ -1,18 +1,26 @@
1
1
  {
2
2
  "name": "palava-client",
3
3
  "description": "Signaling client for WebRTC video-/audio conferencing using the palava protocol",
4
- "version": "2.2.1",
4
+ "version": "3.0.0",
5
5
  "author": {
6
6
  "name": "palava e. V.",
7
7
  "email": "contact@palava.tv",
8
8
  "homepage": "https://palava.tv"
9
9
  },
10
10
  "license": "LGPL-3.0",
11
+ "type": "module",
12
+ "exports": "./dist/index.js",
13
+ "scripts": {
14
+ "build": "coffee -c -o dist/ coffee/",
15
+ "watch": "coffee -c -w -o dist/ coffee/"
16
+ },
11
17
  "dependencies": {
12
18
  "webrtc-adapter": "^7.7.0",
13
- "wolfy87-eventemitter": "~5.2.9"
19
+ "wolfy87-eventemitter": "^5.2.9"
20
+ },
21
+ "devDependencies": {
22
+ "coffeescript": "^2.7.0"
14
23
  },
15
- "browser": "./palava.js",
16
24
  "keywords": [
17
25
  "webrtc",
18
26
  "websocket",
@@ -22,6 +30,6 @@
22
30
  ],
23
31
  "repository": {
24
32
  "type": "git",
25
- "url": "https://github.com/palavatv/palava-client.git"
33
+ "url": "git+https://github.com/palavatv/palava-client.git"
26
34
  }
27
35
  }
package/Gemfile DELETED
@@ -1,8 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'sprockets'
4
- gem 'coffee-script'
5
- gem 'rake'
6
- gem 'paint'
7
- gem 'json'
8
- gem 'uglifier'