@reactoo/watchtogether-sdk-js 2.5.32 → 2.5.38

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.
@@ -0,0 +1,57 @@
1
+ .app-wrapper {
2
+ display: flex;
3
+ gap: 50px;
4
+ }
5
+
6
+ .settings,
7
+ .participants-constrols{
8
+ display: flex;
9
+ flex-direction: column;
10
+ gap: 15px;
11
+ }
12
+
13
+ .heading {
14
+ font-size: 20px;
15
+ font-weight: bold;
16
+ }
17
+
18
+ .form-group {
19
+ display: flex;
20
+ flex-direction: column;
21
+ gap: 2px;
22
+ width: 280px;
23
+ max-width: 100%;
24
+ }
25
+
26
+ .form-group input,
27
+ .form-group button,
28
+ .form-group textarea {
29
+ width: 100%;
30
+ box-sizing: border-box;
31
+ resize: vertical;
32
+ margin: unset;
33
+ }
34
+
35
+ .form-group input[type="checkbox"] {
36
+ width: 14px;
37
+ }
38
+
39
+ #participants-list {
40
+ display: flex;
41
+ flex-direction: row;
42
+ flex-wrap: wrap;
43
+ gap: 50px;
44
+ margin-top: 10px;
45
+ }
46
+
47
+ .participant-container {
48
+ display: flex;
49
+ flex-direction: column;
50
+ border: 1px solid black;
51
+ width: 190px;
52
+ gap: 0;
53
+ }
54
+
55
+ .participant-container canvas {
56
+ aspect-ratio: calc(16/9);
57
+ }
@@ -0,0 +1,528 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <title>The Bulk Join 2</title>
7
+ <script src="../../dist/watchtogether-sdk.js"></script>
8
+ <link rel="stylesheet" href="bulk_join_room_2.css">
9
+ </head>
10
+
11
+ <body>
12
+ <div class="app-wrapper">
13
+ <div class="settings">
14
+ <div class="heading">Settings</div>
15
+
16
+ <div class="form-group">
17
+ <label for="participants-count">Participants count</label>
18
+ <input type="number" id="participants-count" onchange="applySettingsFromForm()">
19
+ </div>
20
+
21
+ <div class="form-group">
22
+ <label for="participants-order-randomization">Participants order randomization</label>
23
+ <input type="checkbox" id="participants-order-randomization" onchange="applySettingsFromForm()">
24
+ </div>
25
+
26
+ <div class="form-group">
27
+ <label for="room-id">Room ID</label>
28
+ <input type="text" id="room-id" onchange="applySettingsFromForm()">
29
+ </div>
30
+
31
+ <div class="form-group">
32
+ <label for="pin-hash">Pin hash</label>
33
+ <input type="text" id="pin-hash" placeholder="Not required" onchange="applySettingsFromForm()">
34
+ </div>
35
+
36
+ <div class="form-group">
37
+ <label for="room-id">Connection delay (seconds)</label>
38
+ <input type="number" id="connection-delay" min="0" step="0.25" onchange="applySettingsFromForm()">
39
+ </div>
40
+
41
+ <div class="form-group">
42
+ <label for="parallel-queues">Parallel connection queues</label>
43
+ <input type="number" id="parallel-queues" min="1" step="4" onchange="applySettingsFromForm()">
44
+ </div>
45
+
46
+ <div class="form-group">
47
+ <label for="instance-type">Instance type</label>
48
+ <input type="text" id="instance-type" onchange="applySettingsFromForm()">
49
+ </div>
50
+
51
+ <div class="form-group">
52
+ <label for="fetch-names">Fetch participants names</label>
53
+ <input type="checkbox" id="fetch-names" onchange="applySettingsFromForm()">
54
+ </div>
55
+
56
+ <div class="form-group">
57
+ <button type="button" onclick="resetSettings()">Reset settings</button>
58
+ </div>
59
+ </div>
60
+
61
+ <div class="participants-constrols">
62
+ <div class="heading">Participants controls</div>
63
+ <div class="form-group">
64
+ <button type="button" onclick="createParticipants()">Create participants (without connect)</button>
65
+ <button type="button" onclick="destroyParticipants()">Destroy participants</button>
66
+ <br>
67
+ <button type="button" onclick="createSingleParticipant()">Create single participant (without connect)</button>
68
+ <br>
69
+ <button type="button" onclick="joinParticipantsToRoom()">Join all participants to room</button>
70
+ <button type="button" onclick="disconnectParticipantsFromRoom()">Disconnect all participants from room</button>
71
+ <br>
72
+ <div class="form-group">
73
+ <label for="participants-names">Participants names (one name per line)</label>
74
+ <textarea id="participants-names" rows="5" onchange="applySettingsFromForm()"></textarea>
75
+ </div>
76
+ <button type="button" onclick="setParticipantsNames()">Set Participants Names</button>
77
+ </div>
78
+ </div>
79
+
80
+ <div class="participants-list-container">
81
+ <div class="heading">Participants</div>
82
+ <div id="participants-list"></div>
83
+ </div>
84
+ </div>
85
+
86
+ <script>
87
+ // https://github.com/w3c/webcodecs/blob/f73dd2ccea32c0652ef94d48b87d728e4f709569/samples/image-decoder/animated-gif-renderer.html
88
+
89
+ // ====================== Configuration ===================================
90
+
91
+ const settingsUrlParameterName = 'settings';
92
+
93
+ const defaultSettings = {
94
+ participantsCount: 5,
95
+ participantsOrderRandomization: false,
96
+ minParticipantsCount: 1,
97
+ maxParticipantsCount: 32,
98
+ instanceType: "reactooDemo",
99
+ roomId: "",
100
+ pinHash: "",
101
+ connectionDelay: 1,
102
+ parallelQueues: 1, // number of parallel queues for joining participants - only applied when connectionDelay is 0
103
+ fetchNames: false,
104
+ participantsNames: [],
105
+ };
106
+
107
+ const gifsCount = 32; // Number of gifs in ./persons_gifs folder
108
+
109
+ // ====================== General Variables ===============================
110
+
111
+ let settings;
112
+
113
+ const elements = {
114
+ form: {
115
+ participantsCount: document.getElementById("participants-count"),
116
+ participantsOrderRandomization: document.getElementById("participants-order-randomization"),
117
+ roomId: document.getElementById("room-id"),
118
+ pinHash: document.getElementById("pin-hash"),
119
+ connectionDelay: document.getElementById("connection-delay"),
120
+ parallelQueues: document.getElementById("parallel-queues"),
121
+ instanceType: document.getElementById("instance-type"),
122
+ fetchNames: document.getElementById("fetch-names"),
123
+ participantsNames: document.getElementById("participants-names"),
124
+ },
125
+ participantsList: document.getElementById("participants-list"),
126
+ };
127
+
128
+ const participants = new Array(gifsCount).fill(undefined);
129
+
130
+ const usedGifsIds = [];
131
+
132
+ const audioContext = new (window.AudioContext || window.webkitAudioContext)();
133
+
134
+ // ====================== Helper Functions ================================
135
+
136
+ function getUrlParameter(varName){
137
+ const queryStr = decodeURI(window.location.search) + '&';
138
+ const regex = new RegExp('.*?[&\\?]' + varName + '=(.*?)&.*');
139
+ const val = queryStr.replace(regex, "$1");
140
+ return val === queryStr ? false : val;
141
+ }
142
+
143
+ // ====================== Settings Functions ==============================
144
+
145
+ function applySettingsFromForm() {
146
+ settings = {
147
+ participantsCount: parseInt(elements.form.participantsCount.value) || 0,
148
+ participantsOrderRandomization: elements.form.participantsOrderRandomization.checked,
149
+ minParticipantsCount: parseInt(settings.minParticipantsCount) || 1,
150
+ maxParticipantsCount: parseInt(settings.maxParticipantsCount) || 32,
151
+ roomId: elements.form.roomId.value || "",
152
+ pinHash: elements.form.pinHash.value || "",
153
+ connectionDelay: parseFloat(elements.form.connectionDelay.value) || 0,
154
+ parallelQueues: parseInt(elements.form.parallelQueues.value) || 1,
155
+ instanceType: elements.form.instanceType.value || "reactooDemo",
156
+ fetchNames: elements.form.fetchNames.checked,
157
+ participantsNames: elements.form.participantsNames.value.split("\n"),
158
+ };
159
+
160
+ setSettingsToUrl(false);
161
+ fillSettingsForm();
162
+ }
163
+
164
+ function setSettingsToUrl(deleteInstead = false) {
165
+ const url = new URL(location.href);
166
+ if (deleteInstead) {
167
+ url.searchParams.delete(settingsUrlParameterName);
168
+ } else {
169
+ url.searchParams.set(settingsUrlParameterName, JSON.stringify(settings));
170
+ }
171
+ history.replaceState (null, '', url);
172
+ }
173
+
174
+ function getSettingsFromUrl() {
175
+ let settingsFromUrl = getUrlParameter(settingsUrlParameterName);
176
+
177
+ if (settingsFromUrl && typeof settingsFromUrl === 'string') {
178
+ settingsFromUrl = JSON.parse(decodeURIComponent(settingsFromUrl.replace(/\+/g, ' ')));
179
+
180
+ if (settingsFromUrl && typeof settingsFromUrl === 'object' && !Array.isArray(settingsFromUrl)) {
181
+ settings = {...settings, ...settingsFromUrl};
182
+ }
183
+ }
184
+ }
185
+
186
+ function initializeSettings() {
187
+ settings = {...defaultSettings};
188
+ }
189
+
190
+ function resetSettings() {
191
+ initializeSettings();
192
+ setSettingsToUrl(true);
193
+ fillSettingsForm();
194
+ }
195
+
196
+ function fillSettingsForm() {
197
+ elements.form.participantsCount.value = settings.participantsCount;
198
+ elements.form.participantsOrderRandomization.checked = settings.participantsOrderRandomization;
199
+ elements.form.roomId.value = settings.roomId;
200
+ elements.form.pinHash.value = settings.pinHash;
201
+ elements.form.connectionDelay.value = settings.connectionDelay;
202
+ elements.form.parallelQueues.value = settings.parallelQueues;
203
+ elements.form.instanceType.value = settings.instanceType;
204
+ elements.form.fetchNames.checked = settings.fetchNames;
205
+ elements.form.participantsNames.value = settings.participantsNames.join("\n");
206
+ }
207
+
208
+ // ====================== Main Logic ==================================
209
+
210
+ function getRandomNotUsedGifId() {
211
+ const availableGifsIds = new Array(gifsCount).fill().map((_, index) => index+1).filter(e => !usedGifsIds.includes(e));
212
+ let randomNotUsedGifId;
213
+
214
+ if (settings.participantsOrderRandomization) {
215
+ randomNotUsedGifId = availableGifsIds[Math.floor(Math.random() * availableGifsIds.length)];
216
+ } else {
217
+ randomNotUsedGifId = Math.min(...availableGifsIds);
218
+ }
219
+
220
+ if (randomNotUsedGifId) {
221
+ usedGifsIds.push(randomNotUsedGifId);
222
+ return randomNotUsedGifId;
223
+ } else {
224
+ return null;
225
+ }
226
+ }
227
+
228
+ function createParticipant(participantOrder) {
229
+ const gifId = getRandomNotUsedGifId();
230
+
231
+ if (gifId === null) {
232
+ return Promise.reject();
233
+ }
234
+
235
+ const gifUrl = `./persons_gifs/${gifId}.gif`;
236
+ const frameIndex = 0;
237
+ const sdkInstance = WatchTogetherSDK({debug:true, storagePrefix: `participant_${gifId}`})({instanceType: settings.instanceType});
238
+
239
+ const containerElement = document.createElement('div');
240
+ containerElement.classList.add('participant-container');
241
+ containerElement.setAttribute('data-participant-id', gifId);
242
+ containerElement.style.order = participantOrder;
243
+
244
+ const canvasElement = document.createElement('canvas');
245
+ canvasElement.setAttribute('title', `Gif ID - ` + gifId);
246
+ const canvasContext = canvasElement.getContext('2d');
247
+ containerElement.appendChild(canvasElement);
248
+
249
+ let participantNameElement;
250
+ participantNameElement = document.createElement('input');
251
+ participantNameElement.setAttribute('type', 'text');
252
+ participantNameElement.setAttribute('placeholder', 'Name');
253
+ containerElement.appendChild(participantNameElement);
254
+
255
+ const setNameButtonElement = document.createElement('button');
256
+ setNameButtonElement.innerText = 'Save name';
257
+ setNameButtonElement.addEventListener('click', () => sdkInstance.user.updateUserSelf({lastRoomId: settings.roomId, displayname: participantNameElement.value}));
258
+ containerElement.appendChild(setNameButtonElement);
259
+
260
+ const destroyButtonElement = document.createElement('button');
261
+ destroyButtonElement.innerText = 'Destroy';
262
+ destroyButtonElement.addEventListener('click', () => destroyParticipant(participants[gifId]));
263
+ containerElement.appendChild(destroyButtonElement);
264
+
265
+ const joinButtonElement = document.createElement('button');
266
+ joinButtonElement.innerText = 'Join';
267
+ joinButtonElement.addEventListener('click', () => joinParticipantToRoom(participants[gifId]));
268
+ containerElement.appendChild(joinButtonElement);
269
+
270
+ const leaveButtonElement = document.createElement('button');
271
+ leaveButtonElement.innerText = 'Leave';
272
+ leaveButtonElement.addEventListener('click', () => disconnectParticipantFromRoom(participants[gifId]));
273
+ containerElement.appendChild(leaveButtonElement);
274
+
275
+ const toggleCameraButtonElement = document.createElement('button');
276
+ toggleCameraButtonElement.innerText = 'Toggle camera';
277
+ toggleCameraButtonElement.addEventListener('click', () => participants[gifId].session.toggleVideo());
278
+ containerElement.appendChild(toggleCameraButtonElement);
279
+
280
+ const toggleAudioButtonElement = document.createElement('button');
281
+ toggleAudioButtonElement.innerText = 'Toggle audio';
282
+ toggleAudioButtonElement.addEventListener('click', () => participants[gifId].session.toggleAudio());
283
+ containerElement.appendChild(toggleAudioButtonElement);
284
+
285
+ return fetch(gifUrl)
286
+ .then(response => {
287
+ const imageDecoder = new ImageDecoder({data: response.body, type: 'image/gif'});
288
+
289
+ const participant = {
290
+ gifId,
291
+ gifUrl,
292
+ imageDecoder,
293
+ frameIndex,
294
+ reverseOrder: false, // boomerang animation
295
+ width: null, // Will be set after first frame is decoded
296
+ height: null, // Will be set after first frame is decoded
297
+ canvas: canvasElement,
298
+ canvasContext,
299
+ sdkInstance,
300
+ loginPromise: sdkInstance.auth.deviceLogin(gifId),
301
+ session: null, // Will be set after room join
302
+ };
303
+
304
+ if (settings.fetchNames) {
305
+ participant.loginPromise.then(() => sdkInstance.user.getUserSelf())
306
+ .then(response => {
307
+ participant.displayname = response.data.displayname;
308
+ participantNameElement.value = response.data.displayname;
309
+ });
310
+ }
311
+
312
+ return imageDecoder
313
+ .decode({frameIndex})
314
+ .then(decodeResult => {
315
+ participant.width = decodeResult.image.displayWidth;
316
+ participant.canvas.width = decodeResult.image.displayWidth;
317
+
318
+ participant.height = decodeResult.image.displayHeight;
319
+ participant.canvas.height = decodeResult.image.displayHeight;
320
+
321
+ participant.canvas.id = `canvas-${participant.gifId}`;
322
+
323
+ // Start render loop
324
+ renderGif(decodeResult, participant);
325
+
326
+ elements.participantsList.appendChild(containerElement);
327
+
328
+ return participant;
329
+ });
330
+ });
331
+ }
332
+
333
+ function createParticipants(participantsCount = settings.participantsCount) {
334
+ destroyParticipants()
335
+ .then(() => {
336
+ for (let i = 0; i < participantsCount; i++) {
337
+ createParticipant(i).then(participant => participants[participant.gifId] = participant);
338
+ }
339
+ })
340
+ }
341
+
342
+ function createSingleParticipant() {
343
+ const participantOrder = participants.filter(p => p).length;
344
+
345
+ console.log(participantOrder);
346
+
347
+ createParticipant(participantOrder)
348
+ .then(participant => participants[participant.gifId] = participant);
349
+ }
350
+
351
+ function destroyParticipant(participant) {
352
+ disconnectParticipantFromRoom(participant)
353
+ .then(() => {
354
+ participant.imageDecoder.close();
355
+ participant.sdkInstance.auth.logout();
356
+ usedGifsIds.splice(usedGifsIds.indexOf(participant.gifId), 1);
357
+ document.querySelector('.participant-container[data-participant-id="' + participant.gifId + '"]').remove();
358
+
359
+ participants[participant.gifId] = undefined;
360
+ });
361
+ }
362
+
363
+ function destroyParticipants() {
364
+ return disconnectParticipantsFromRoom()
365
+ .then(() => {
366
+ participants.filter(p => p).forEach(participant => {
367
+ participant.imageDecoder.close();
368
+ participant.sdkInstance.auth.logout();
369
+ usedGifsIds.splice(usedGifsIds.indexOf(participant.gifId), 1);
370
+ document.querySelector('.participant-container[data-participant-id="' + participant.gifId + '"]').remove();
371
+ });
372
+
373
+ for (let i = 0 ; i < participants.length ; i++) {
374
+ if (participants[i]) {
375
+ participants[i] = undefined;
376
+ }
377
+ }
378
+ });
379
+ }
380
+
381
+ function joinParticipantToRoom(participant) {
382
+ return participant.loginPromise.then(() => {
383
+ participant.sdkInstance.room.createSession({roomId: settings.roomId, pinHash: settings.pinHash})
384
+ .then(session => {
385
+ participant.session = session;
386
+ return Promise.all([session, session.connect()])
387
+ })
388
+ .then(([session, _]) => {
389
+ return getAudioStream()
390
+ .then(audioStream => {
391
+ participant.stream = participant.canvas.captureStream();
392
+ participant.stream.addTrack(audioStream.getAudioTracks()[0]);
393
+ return session.publishLocal(participant.stream, {getStreamIfEmpty: false});
394
+ });
395
+ });
396
+ });
397
+ }
398
+
399
+ function joinParticipantsToRoom () {
400
+ if (settings.connectionDelay === 0 && settings.parallelQueues > 0) {
401
+ // Parallel join
402
+
403
+ const parallelQueues = new Array(participants.filter(p => p).length).fill().map(() => Promise.resolve());
404
+
405
+ for (let i = 0 ; i < participants.filter(p => p).length ; i++) {
406
+ const parallelQueueIndex = i % settings.parallelQueues;
407
+ parallelQueues[parallelQueueIndex] = parallelQueues[parallelQueueIndex]
408
+ .then(() => joinParticipantToRoom(participants.filter(p => p)[i]))
409
+ .then(() => new Promise(resolve => setTimeout(resolve, settings.connectionDelay * 1000)));
410
+ }
411
+ } else {
412
+ // Serial join
413
+
414
+ return participants.filter(p => p).reduce((promiseChain, participant) => {
415
+ return promiseChain.then(() => joinParticipantToRoom(participant))
416
+ .then(() => new Promise(resolve => setTimeout(resolve, settings.connectionDelay * 1000)));
417
+ }, Promise.resolve());
418
+ }
419
+ }
420
+
421
+ function disconnectParticipantFromRoom(participant) {
422
+ if (participant && participant.loginPromise) {
423
+ return participant.loginPromise
424
+ .then(() => {
425
+ if (participant.session && participant.session.disconnect) {
426
+ return participant.session.disconnect();
427
+ }
428
+ })
429
+ .then(() => participant.session = null);
430
+ }
431
+ }
432
+
433
+ function disconnectParticipantsFromRoom() {
434
+ return Promise.all(participants.filter(p => p).map(participant => disconnectParticipantFromRoom(participant)));
435
+ }
436
+
437
+ function renderGif(decodeResult, participant) {
438
+ participant.canvasContext.drawImage(decodeResult.image, 0, 0);
439
+
440
+ const track = participant.imageDecoder.tracks.selectedTrack;
441
+
442
+ if (!track) {
443
+ return;
444
+ }
445
+
446
+ // We check complete here since `frameCount` won't be stable until all data
447
+ // has been received. This may cause us to receive a RangeError during the
448
+ // decode() call below which needs to be handled.
449
+ if (participant.imageDecoder.complete) {
450
+ if (track.frameCount == 1) {
451
+ return;
452
+ }
453
+
454
+ if ((participant.reverseOrder && participant.frameIndex - 1 <= 0) || (!participant.reverseOrder && participant.frameIndex + 1 >= track.frameCount)) {
455
+ participant.reverseOrder = !participant.reverseOrder;
456
+ }
457
+ }
458
+
459
+ if (participant.reverseOrder) {
460
+ --participant.frameIndex;
461
+ } else {
462
+ ++participant.frameIndex;
463
+ }
464
+
465
+ // Decode the next frame ahead of display so it's ready in time.
466
+ participant.imageDecoder.decode({frameIndex: participant.frameIndex})
467
+ .then( nextDecodeResult => setTimeout(_ => {
468
+ renderGif(nextDecodeResult, participant);
469
+ }, decodeResult.image.duration / 1000.0))
470
+ .catch(e => {
471
+ // We can end up requesting an imageIndex past the end since we're using
472
+ // a ReadableStrem from fetch(), when this happens just wrap around.
473
+ if (e instanceof RangeError) {
474
+ participant.frameIndex = 0;
475
+ participant.imageDecoder.decode({frameIndex: imageIndex}).then(decodeResult => renderGif(decodeResult, participant));
476
+ } else {
477
+ throw e;
478
+ }
479
+ });
480
+ }
481
+
482
+ function setParticipantsNames() {
483
+ participants.filter(p => p).forEach((participant, participantOrder) => {
484
+ if (settings.participantsNames[participantOrder]) {
485
+ participant.sdkInstance.user.updateUserSelf({lastRoomId: settings.roomId, displayname: settings.participantsNames[participantOrder]});
486
+ } else {
487
+ console.log('Not enough names');
488
+ }
489
+ });
490
+ }
491
+
492
+ function getAudioStream() {
493
+ return new Promise(resolve => {
494
+ const request = new XMLHttpRequest();
495
+ // https://ttsmp3.com/
496
+ request.open('GET', './sound_2.mp3', true);
497
+ request.responseType = 'arraybuffer';
498
+ request.onload = function() {
499
+ audioContext.decodeAudioData(request.response)
500
+ .then(buffer => {
501
+ const streamDestination = audioContext.createMediaStreamDestination();
502
+ const source = audioContext.createBufferSource();
503
+ source.buffer = buffer;
504
+ source.connect(streamDestination);
505
+ source.loop = true;
506
+ source.start();
507
+
508
+ new Audio().srcObject = streamDestination.stream;
509
+
510
+ resolve(streamDestination.stream);
511
+ });
512
+ }
513
+ request.send();
514
+ });
515
+ }
516
+
517
+ // ====================== Initialization ==============================
518
+
519
+ document.addEventListener("DOMContentLoaded", function() {
520
+ initializeSettings();
521
+ getSettingsFromUrl();
522
+ fillSettingsForm();
523
+ });
524
+
525
+ </script>
526
+
527
+ </body>
528
+ </html>
@@ -97,13 +97,13 @@
97
97
  Instance.room.getSessionByConstructId(constructId).toggleAudio()
98
98
  }
99
99
 
100
- let Instance = WatchTogetherSDK({debug:true})({instanceType:'reactooDemo'});
100
+ let Instance = WatchTogetherSDK({debug:true, apiUrl: 'https://api.reactoo.com/dev3/swagger.json'})({instanceType:'reactooDemo'});
101
101
 
102
102
  Instance.auth.$on('login', () => {
103
103
  console.log('We are in');
104
104
  });
105
105
 
106
- Instance.iot.$on('connected', () => {
106
+ Instance.iot.$on('connect', () => {
107
107
  console.log('Iot connected');
108
108
  });
109
109
 
@@ -111,7 +111,7 @@
111
111
  console.log('Iot error' ,e);
112
112
  });
113
113
 
114
- Instance.iot.$on('disconnected', () => {
114
+ Instance.iot.$on('close', () => {
115
115
  console.log('Iot disconnected');
116
116
  });
117
117
 
@@ -125,7 +125,10 @@
125
125
 
126
126
  if(roomId) {
127
127
  console.log(roomId);
128
- return Promise.resolve({roomId, pinHash});
128
+ return Instance.room.getRoomById(roomId, pinHash).then((r) => {
129
+ Instance.iot?.subscribe(r.data.iotTopic);
130
+ return {roomId, pinHash}
131
+ })
129
132
  }
130
133
 
131
134
  // get our room or create one if it doesn't exist yet
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reactoo/watchtogether-sdk-js",
3
- "version": "2.5.32",
3
+ "version": "2.5.38",
4
4
  "description": "Javascript SDK for Reactoo",
5
5
  "main": "src/index.js",
6
6
  "unpkg": "dist/watchtogether-sdk.min.js",