peer-term 1.2.9 → 1.2.11

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +59 -20
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "peer-term",
3
- "version": "1.2.9",
3
+ "version": "1.2.11",
4
4
  "license": "MIT",
5
5
  "description": "Share your terminal instantly using a 6-digit code. Encrypted. No config.",
6
6
  "keywords": [
package/src/index.js CHANGED
@@ -326,6 +326,7 @@ class Session {
326
326
  this.awaitingRejoin = false;
327
327
  this.destroyed = false;
328
328
  this.intentionalClose = false;
329
+ this.ptyOutputQueue = Promise.resolve();
329
330
  this.reconnectTimer = null;
330
331
  this.createdAt = Date.now();
331
332
  this.relayUrl = null; // Track which relay URL we connected to
@@ -647,13 +648,10 @@ class Session {
647
648
  try {
648
649
  const resizeJson = JSON.stringify({ type: 'resize', cols, rows });
649
650
  const payload = await encrypt(this.sharedKey, resizeJson);
650
- // Phase 4: Route through DataChannel if active, else relay
651
- if (this.useDataChannel && this.webrtc && this.webrtc.isActive()) {
652
- // Send resize as a tagged message so client can distinguish
653
- this.webrtc.send(JSON.stringify({ _meta: 'resize', payload }));
654
- } else if (this.ws && this.ws.readyState === WebSocket.OPEN) {
655
- this.ws.send(JSON.stringify({ type: 'data', payload, meta: 'resize' }));
656
- }
651
+ this._sendEncryptedToClient(payload, {
652
+ directPayload: JSON.stringify({ _meta: 'resize', payload }),
653
+ meta: 'resize',
654
+ });
657
655
  } catch {}
658
656
  }
659
657
 
@@ -708,25 +706,14 @@ class Session {
708
706
  env: process.env,
709
707
  });
710
708
 
711
- this.ptyProcess.onData(async (data) => {
709
+ this.ptyProcess.onData((data) => {
712
710
  // Mirror PTY output to local viewer terminal
713
711
  if (this.viewerSocket) {
714
712
  try { this.viewerSocket.write(data); } catch {}
715
713
  }
716
714
 
717
715
  if (!this.sharedKey) return;
718
- try {
719
- const payload = await encrypt(this.sharedKey, data);
720
- // Phase 4: Route through DataChannel if active, else relay
721
- if (this.useDataChannel && this.webrtc && this.webrtc.isActive()) {
722
- this.webrtc.send(payload);
723
- } else if (this.ws && this.ws.readyState === WebSocket.OPEN) {
724
- // Backpressure: drop chunk if relay can't keep up (1.25 MB buffer limit)
725
- if (this.ws.bufferedAmount < 1.25 * 1024 * 1024) {
726
- this.ws.send(JSON.stringify({ type: 'data', payload }));
727
- }
728
- }
729
- } catch {}
716
+ this._queuePtyOutput(data, this.sharedKey);
730
717
  });
731
718
 
732
719
  this.ptyProcess.onExit(({ exitCode }) => {
@@ -742,6 +729,58 @@ class Session {
742
729
  }
743
730
 
744
731
  // ─── Local TCP viewer for host terminal ─────────────────────────────
732
+ _queuePtyOutput(data, sharedKey) {
733
+ this.ptyOutputQueue = this.ptyOutputQueue
734
+ .then(() => this._sendPtyOutput(data, sharedKey))
735
+ .catch((err) => {
736
+ this.logDebug(`Failed to send PTY output: ${err.message}`);
737
+ });
738
+ }
739
+
740
+ async _sendPtyOutput(data, sharedKey) {
741
+ if (this.destroyed || !sharedKey || sharedKey !== this.sharedKey) return;
742
+
743
+ const payload = await encrypt(sharedKey, data);
744
+ if (this.destroyed || sharedKey !== this.sharedKey) return;
745
+
746
+ this._sendEncryptedToClient(payload, { enforceBackpressure: true });
747
+ }
748
+
749
+ _sendEncryptedToClient(payload, options = {}) {
750
+ const directPayload = options.directPayload || payload;
751
+
752
+ if (this.useDataChannel) {
753
+ if (this.webrtc && this.webrtc.isActive()) {
754
+ let sentDirect = false;
755
+ try {
756
+ sentDirect = this.webrtc.send(directPayload);
757
+ } catch {}
758
+
759
+ if (sentDirect) return true;
760
+ }
761
+
762
+ this.useDataChannel = false;
763
+ this.log('DataChannel send failed — falling back to relay');
764
+ }
765
+
766
+ return this._sendViaRelay(payload, options);
767
+ }
768
+
769
+ _sendViaRelay(payload, { meta, enforceBackpressure = false } = {}) {
770
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN) return false;
771
+ if (enforceBackpressure && this.ws.bufferedAmount >= 1.25 * 1024 * 1024) return false;
772
+
773
+ const msg = { type: 'data', payload };
774
+ if (meta) msg.meta = meta;
775
+
776
+ try {
777
+ this.ws.send(JSON.stringify(msg));
778
+ return true;
779
+ } catch {
780
+ return false;
781
+ }
782
+ }
783
+
745
784
  _startViewerServer() {
746
785
  this.viewerServer = net.createServer((socket) => {
747
786
  // Close any existing viewer connection before accepting a new one