topazcube 0.1.21 → 0.1.23

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/README.md CHANGED
@@ -23,7 +23,9 @@ const server = new TopazCubeServer({
23
23
 
24
24
  ### WebRTC Support (Optional)
25
25
 
26
- WebRTC functionality is optional and requires platform-specific binary packages. If you want to use WebRTC features:
26
+ WebRTC functionality is optional and requires platform-specific binary packages. **Note: WebRTC is only available when using the CommonJS build due to native module limitations.**
27
+
28
+ If you want to use WebRTC features:
27
29
 
28
30
  ```bash
29
31
  # Install the appropriate platform package
@@ -32,15 +34,30 @@ npm install @roamhq/wrtc-linux-x64 # for Linux x64
32
34
  npm install @roamhq/wrtc-win32-x64 # for Windows x64
33
35
  ```
34
36
 
35
- Then enable WebRTC in your server:
37
+ Then use the CommonJS build and enable WebRTC:
38
+
39
+ ```javascript
40
+ // Use require() and .cjs build for WebRTC support
41
+ const TopazCubeServer = require('topazcube/server').default;
36
42
 
37
- ```typescript
38
43
  const server = new TopazCubeServer({
39
44
  port: 8799,
40
45
  allowWebRTC: true // Enable WebRTC functionality
41
46
  })
42
47
  ```
43
48
 
49
+ For ESM imports without WebRTC:
50
+
51
+ ```typescript
52
+ // ESM import works fine without WebRTC
53
+ import TopazCubeServer from 'topazcube/server'
54
+
55
+ const server = new TopazCubeServer({
56
+ port: 8799,
57
+ allowWebRTC: false // WebRTC not available in ESM mode
58
+ })
59
+ ```
60
+
44
61
  ### Client Setup
45
62
 
46
63
  ```typescript
package/dist/client.cjs CHANGED
@@ -174,7 +174,7 @@ async function decompress(buffer) {
174
174
  // src/client.ts
175
175
  var import_gl_matrix = require("gl-matrix");
176
176
  var TopazCubeClient = class {
177
- debug = false;
177
+ DEBUG = false;
178
178
  CYCLE = 200;
179
179
  // update/patch rate in ms
180
180
  url = "";
@@ -205,6 +205,9 @@ var TopazCubeClient = class {
205
205
  ID = 0;
206
206
  socket = null;
207
207
  _peerConnection = null;
208
+ _candidates = [];
209
+ _remoteCandidates = [];
210
+ _offerSent = false;
208
211
  _dataChannel = null;
209
212
  // our data channel
210
213
  _serverDataChannel = null;
@@ -228,15 +231,30 @@ var TopazCubeClient = class {
228
231
  // auto reconnect on disconnect
229
232
  allowSync = true,
230
233
  // allow sync on connect
231
- allowWebRTC = false
234
+ allowWebRTC = false,
235
+ DEBUG = false
232
236
  }) {
233
237
  this.url = url;
234
238
  this.autoReconnect = autoReconnect;
235
239
  this.allowSync = allowSync;
236
240
  this.allowWebRTC = allowWebRTC;
237
241
  this.socket = null;
242
+ this.DEBUG = DEBUG;
238
243
  this._startLoop();
239
- console.log("Client initialized");
244
+ this.log("Client initialized");
245
+ }
246
+ log(...args) {
247
+ if (this.DEBUG) {
248
+ console.log(...args);
249
+ }
250
+ }
251
+ warn(...args) {
252
+ if (this.DEBUG) {
253
+ console.warn(...args);
254
+ }
255
+ }
256
+ error(...args) {
257
+ console.error(...args);
240
258
  }
241
259
  /*= UPDATE ===================================================================*/
242
260
  _startLoop() {
@@ -307,20 +325,32 @@ var TopazCubeClient = class {
307
325
  let t2 = e._lpostime2;
308
326
  const interval = t2 - t1;
309
327
  const elapsed = now - t1;
310
- const alpha = Math.max(0, elapsed / interval);
311
- import_gl_matrix.vec3.lerp(this._dpos, e._lpos1, e._lpos2, alpha);
312
- import_gl_matrix.vec3.lerp(e.position, e.position, this._dpos, 0.07);
313
- e._changed_position = now;
328
+ e.pelapsed = elapsed;
329
+ if (elapsed > 1e3) {
330
+ import_gl_matrix.vec3.copy(e.position, e._lpos2);
331
+ e._changed_position = now;
332
+ } else {
333
+ const alpha = Math.max(0, elapsed / interval);
334
+ import_gl_matrix.vec3.lerp(this._dpos, e._lpos1, e._lpos2, alpha);
335
+ import_gl_matrix.vec3.lerp(e.position, e.position, this._dpos, 0.07);
336
+ e._changed_position = now;
337
+ }
314
338
  }
315
339
  if (e._lrottime1 && e._lrottime2) {
316
340
  let t1 = e._lrottime1;
317
341
  let t2 = e._lrottime2;
318
342
  const interval = t2 - t1;
319
343
  const elapsed = now - t1;
320
- const alpha = Math.max(0, elapsed / interval);
321
- import_gl_matrix.quat.slerp(this._drot, e._lrot1, e._lrot2, alpha);
322
- import_gl_matrix.quat.slerp(e.rotation, e.rotation, this._drot, 0.07);
323
- e._changed_rotation = now;
344
+ e.relapsed = elapsed;
345
+ if (elapsed > 1e3) {
346
+ import_gl_matrix.quat.copy(e.rotation, e._lrot2);
347
+ e._changed_rotation = now;
348
+ } else {
349
+ const alpha = Math.max(0, elapsed / interval);
350
+ import_gl_matrix.quat.slerp(this._drot, e._lrot1, e._lrot2, alpha);
351
+ import_gl_matrix.quat.slerp(e.rotation, e.rotation, this._drot, 0.07);
352
+ e._changed_rotation = now;
353
+ }
324
354
  }
325
355
  }
326
356
  }
@@ -341,7 +371,7 @@ var TopazCubeClient = class {
341
371
  }
342
372
  this.isConnecting = true;
343
373
  this._clear();
344
- console.log("connecting...");
374
+ this.log("connecting...");
345
375
  this.socket = new WebSocket(this.url);
346
376
  this.socket.onmessage = async (event) => {
347
377
  let buffer = await event.data.arrayBuffer();
@@ -448,7 +478,7 @@ var TopazCubeClient = class {
448
478
  this.socket.send(enc);
449
479
  }
450
480
  } catch (e) {
451
- console.error("send failed", e);
481
+ this.error("send failed", e);
452
482
  }
453
483
  }
454
484
  get document() {
@@ -486,7 +516,7 @@ var TopazCubeClient = class {
486
516
  try {
487
517
  (0, import_fast_json_patch.applyOperation)(this.documents[name], dop);
488
518
  } catch (e) {
489
- console.error("applyOperation failed for", name, "with op", dop, e);
519
+ this.error("applyOperation failed for", name, "with op", dop, e);
490
520
  }
491
521
  }
492
522
  this.isPatched = false;
@@ -517,10 +547,10 @@ var TopazCubeClient = class {
517
547
  let nmessage = decode(cdecu);
518
548
  this._onMessage(nmessage);
519
549
  } catch (error) {
520
- console.error("Error decoding chunks:", error);
550
+ this.error("Error decoding chunks:", error);
521
551
  }
522
552
  } else {
523
- console.warn("missing chunks", cfound, "of", message.seq + 1);
553
+ this.warn("missing chunks", cfound, "of", message.seq + 1);
524
554
  }
525
555
  }
526
556
  } else if (message.c == "fpatch") {
@@ -533,11 +563,11 @@ var TopazCubeClient = class {
533
563
  if (this._lastUpdateId[name] < message.u) {
534
564
  let lp = message.u - this._lastUpdateId[name] - 1;
535
565
  if (lp > 0) {
536
- console.warn("Lost " + lp + " updates");
566
+ this.warn("Lost " + lp + " updates");
537
567
  }
538
568
  this._lastUpdateId[name] = message.u;
539
569
  } else if (this._lastUpdateId[name] > message.u) {
540
- console.warn(`Received outdated update ID for document ${name}: ${message.u} < ${this._lastUpdateId[name]}`);
570
+ this.warn(`Received outdated update ID for document ${name}: ${message.u} < ${this._lastUpdateId[name]}`);
541
571
  doPatch = false;
542
572
  }
543
573
  }
@@ -553,9 +583,11 @@ var TopazCubeClient = class {
553
583
  this.send({ c: "peng", ct: Date.now(), st: stime });
554
584
  this.stats.stdiff = stime + ping / 2 - time;
555
585
  this.stats.ping = ping;
556
- console.log("ping", ping, "ms", "stdiff", this.stats.stdiff, "ms");
586
+ this.log("ping", ping, "ms", "stdiff", this.stats.stdiff, "ms");
557
587
  } else if (message.c == "rtc-offer") {
588
+ this.log("RTC: offer received:", message);
558
589
  } else if (message.c == "rtc-answer") {
590
+ this.log("RTC: answer received:", message);
559
591
  try {
560
592
  const sessionDesc = new RTCSessionDescription({
561
593
  type: message.type,
@@ -564,30 +596,30 @@ var TopazCubeClient = class {
564
596
  if (this._peerConnection) {
565
597
  await this._peerConnection.setRemoteDescription(sessionDesc);
566
598
  }
599
+ this.log("RTC: Remote description set successfully");
600
+ for (let candidate of this._remoteCandidates) {
601
+ try {
602
+ await this._peerConnection?.addIceCandidate(candidate);
603
+ this.log("RTC: Added remote ICE candidate:", candidate);
604
+ } catch (error) {
605
+ this.error("RTC: Error adding remote ICE candidate:", error);
606
+ }
607
+ }
567
608
  } catch (error) {
568
- console.error("RTC: Error setting remote description:", error);
609
+ this.error("RTC: Error setting remote description:", error);
569
610
  }
570
611
  } else if (message.c == "rtc-candidate") {
571
- try {
572
- if (this._peerConnection && message.candidate) {
573
- await this._peerConnection.addIceCandidate(
574
- //new RTCIceCandidate(message.candidate)
575
- message.candidate
576
- );
577
- } else {
578
- console.warn(
579
- "RTC: Received candidate but peerConnection not ready or candidate missing"
580
- );
581
- }
582
- } catch (error) {
612
+ this.log("RTC: candidate received", message);
613
+ if (this._peerConnection && message.candidate) {
614
+ this._remoteCandidates.push(message.candidate);
583
615
  }
584
616
  } else {
585
617
  this.onMessage(message);
586
618
  }
587
619
  }
588
620
  _onDocumentChange(name, op, target, path, value) {
589
- if (this.debug) {
590
- console.log("Document change:", name, op, target, path, value);
621
+ if (this.DEBUG) {
622
+ this.log("Document change:", name, op, target, path, value);
591
623
  }
592
624
  if (this.isPatched || !this.allowSync) {
593
625
  return;
@@ -770,12 +802,12 @@ var TopazCubeClient = class {
770
802
  }
771
803
  }
772
804
  _onRTCConnect() {
773
- console.log("RTC: Connected");
805
+ this.log("RTC: Connected");
774
806
  this.send({ c: "test", message: "Hello RTC from client" });
775
807
  }
776
808
  _onRTCDisconnect() {
777
809
  this._webRTCConnected = false;
778
- console.log("RTC: Disconnected");
810
+ this.log("RTC: Disconnected");
779
811
  }
780
812
  async _onRTCMessage(data) {
781
813
  this.stats.recRTC += data.byteLength;
@@ -787,6 +819,9 @@ var TopazCubeClient = class {
787
819
  }
788
820
  async _initializeWebRTC() {
789
821
  this._peerConnection = null;
822
+ this._candidates = [];
823
+ this._remoteCandidates = [];
824
+ this._offerSent = false;
790
825
  try {
791
826
  this._peerConnection = new RTCPeerConnection({
792
827
  iceServers: [
@@ -798,22 +833,31 @@ var TopazCubeClient = class {
798
833
  });
799
834
  this._peerConnection.onicecandidate = (event) => {
800
835
  if (event.candidate) {
801
- this.send({
802
- c: "rtc-candidate",
803
- type: "ice-candidate",
804
- candidate: event.candidate
805
- });
836
+ this._candidates.push(event.candidate);
806
837
  } else {
838
+ this.log("RTC: ICE candidate gathering complete");
807
839
  }
808
840
  };
809
841
  this._peerConnection.onconnectionstatechange = () => {
810
842
  if (this._peerConnection && this._peerConnection.connectionState === "connected") {
811
843
  this._webRTCConnected = true;
844
+ this.log("RTC: Peer connection established!");
812
845
  } else if (this._peerConnection && (this._peerConnection.connectionState === "failed" || this._peerConnection.connectionState === "disconnected" || this._peerConnection.connectionState === "closed")) {
813
846
  this._webRTCConnected = false;
847
+ this.log("RTC: Peer connection closed or failed");
814
848
  }
815
849
  };
816
850
  this._peerConnection.onicegatheringstatechange = () => {
851
+ this.log(`RTC: ICE gathering state. _candidates:`, this._candidates.length, this._peerConnection?.iceGatheringState);
852
+ if (this._peerConnection?.iceGatheringState == "complete" && this._offerSent) {
853
+ for (let candidate of this._candidates) {
854
+ this.send({
855
+ c: "rtc-candidate",
856
+ type: "ice-candidate",
857
+ candidate
858
+ });
859
+ }
860
+ }
817
861
  };
818
862
  this._peerConnection.oniceconnectionstatechange = () => {
819
863
  if (this._peerConnection && (this._peerConnection.iceConnectionState === "connected" || this._peerConnection.iceConnectionState === "completed")) {
@@ -833,7 +877,7 @@ var TopazCubeClient = class {
833
877
  this._onRTCDisconnect();
834
878
  };
835
879
  this._dataChannel.onerror = (_error) => {
836
- console.error("RTC: Client data channel error", _error);
880
+ this.error("RTC: Client data channel error", _error);
837
881
  };
838
882
  this._peerConnection.ondatachannel = (event) => {
839
883
  const dataChannel = event.channel;
@@ -864,17 +908,18 @@ var TopazCubeClient = class {
864
908
  sdp: ld.sdp
865
909
  };
866
910
  this.send(offerPayload);
911
+ this._offerSent = true;
867
912
  }
868
913
  setTimeout(() => {
869
914
  if (!this._webRTCConnected && this._peerConnection) {
870
915
  if (this._peerConnection.iceConnectionState === "failed") {
871
- console.log("RTC: Attempting ICE restart");
916
+ this.log("RTC: Attempting ICE restart");
872
917
  this._restartIce();
873
918
  }
874
919
  }
875
920
  }, 5e3);
876
921
  } catch (error) {
877
- console.error("RTC: error:", error);
922
+ this.error("RTC: error:", error);
878
923
  }
879
924
  }
880
925
  // Add this method to restart ICE if needed