@abraca/dabra 1.0.22 → 1.0.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.
@@ -3222,6 +3222,18 @@ var AbracadabraClient = class {
3222
3222
  auth: false
3223
3223
  });
3224
3224
  }
3225
+ /**
3226
+ * Fetch a short-lived anonymous pairing token for WebRTC signaling.
3227
+ * No authentication required. The token only grants access to `__pairing_*` rooms.
3228
+ */
3229
+ static async getPairingToken(serverUrl) {
3230
+ let base = serverUrl;
3231
+ while (base.endsWith("/")) base = base.slice(0, -1);
3232
+ const resp = await fetch(`${base}/auth/pairing-token`, { method: "POST" });
3233
+ if (!resp.ok) throw new Error(`Failed to fetch pairing token: ${resp.status}`);
3234
+ const { token } = await resp.json();
3235
+ return token;
3236
+ }
3225
3237
  /** Get encryption info for a document. */
3226
3238
  async getDocEncryption(docId) {
3227
3239
  return this.request("GET", `/docs/${encodeURIComponent(docId)}/encryption`);
@@ -8858,8 +8870,8 @@ var SignalingSocket = class extends EventEmitter {
8858
8870
  break;
8859
8871
  case "joined":
8860
8872
  this.emit("joined", {
8861
- peerId: msg.peer_id,
8862
- userId: msg.user_id,
8873
+ peer_id: msg.peer_id,
8874
+ user_id: msg.user_id,
8863
8875
  muted: msg.muted,
8864
8876
  video: msg.video,
8865
8877
  screen: msg.screen,
@@ -10297,6 +10309,7 @@ var ManualSignaling = class extends EventEmitter {
10297
10309
  const CODE_CHARSET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
10298
10310
  const CODE_LENGTH = 6;
10299
10311
  const PAIRING_TIMEOUT_MS = 300 * 1e3;
10312
+ const SIGNALING_CONNECT_TIMEOUT_MS = 5e3;
10300
10313
  function generatePairingCode() {
10301
10314
  const bytes = crypto.getRandomValues(new Uint8Array(CODE_LENGTH));
10302
10315
  return Array.from(bytes).map((b) => CODE_CHARSET[b % 32]).join("");
@@ -10314,6 +10327,7 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
10314
10327
  this._destroyed = false;
10315
10328
  this._pendingRequest = null;
10316
10329
  this._connectedPeerId = null;
10330
+ this._usingFallback = false;
10317
10331
  this.role = role;
10318
10332
  this.pairingCode = pairingCode;
10319
10333
  }
@@ -10468,12 +10482,41 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
10468
10482
  }
10469
10483
  this.removeAllListeners();
10470
10484
  }
10485
+ async resolveToken(serverUrl) {
10486
+ if (this.config.token && serverUrl === this.config.serverUrl) return this.config.token;
10487
+ let base = serverUrl ?? this.config.serverUrl;
10488
+ while (base.endsWith("/")) base = base.slice(0, -1);
10489
+ const resp = await fetch(`${base}/auth/pairing-token`, { method: "POST" });
10490
+ if (!resp.ok) throw new Error(`Failed to fetch pairing token: ${resp.status} ${resp.statusText}`);
10491
+ const { token } = await resp.json();
10492
+ return token;
10493
+ }
10471
10494
  start() {
10495
+ this.connectToServer(this.config.serverUrl);
10496
+ this.timeoutHandle = setTimeout(() => {
10497
+ if (!this._destroyed) {
10498
+ this.emit("error", /* @__PURE__ */ new Error("Pairing timed out"));
10499
+ this.destroy();
10500
+ }
10501
+ }, PAIRING_TIMEOUT_MS);
10502
+ }
10503
+ connectToServer(serverUrl, signalingUrl) {
10504
+ const roomId = codeToRoomId(this.pairingCode);
10505
+ const tokenPromise = this.resolveToken(serverUrl);
10506
+ const tokenFactory = async () => {
10507
+ const t = await tokenPromise;
10508
+ if (typeof t === "function") return await t();
10509
+ return t;
10510
+ };
10511
+ if (!this.config.iceServers) new AbracadabraClient({ url: serverUrl }).getIceServers().then((servers) => {
10512
+ if (servers.length > 0) this._resolvedIceServers = servers;
10513
+ });
10472
10514
  this.webrtc = new AbracadabraWebRTC({
10473
- docId: codeToRoomId(this.pairingCode),
10474
- url: this.config.serverUrl,
10475
- token: this.config.token,
10476
- iceServers: this.config.iceServers,
10515
+ docId: roomId,
10516
+ url: serverUrl,
10517
+ signalingUrl: signalingUrl ?? void 0,
10518
+ token: tokenFactory,
10519
+ iceServers: this.config.iceServers ?? this._resolvedIceServers,
10477
10520
  e2ee: this.config.e2ee,
10478
10521
  enableDocSync: false,
10479
10522
  enableAwarenessSync: false,
@@ -10481,6 +10524,10 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
10481
10524
  autoConnect: false,
10482
10525
  WebSocketPolyfill: this.config.WebSocketPolyfill
10483
10526
  });
10527
+ let connected = false;
10528
+ this.webrtc.on("connected", () => {
10529
+ connected = true;
10530
+ });
10484
10531
  this.webrtc.on("e2eeEstablished", ({ peerId }) => {
10485
10532
  this._connectedPeerId = peerId;
10486
10533
  this.emit("connected");
@@ -10494,14 +10541,25 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
10494
10541
  this.webrtc.on("signalingError", (err) => {
10495
10542
  this.emit("error", /* @__PURE__ */ new Error(`Signaling: ${err.message}`));
10496
10543
  });
10497
- this.timeoutHandle = setTimeout(() => {
10498
- if (!this._destroyed) {
10499
- this.emit("error", /* @__PURE__ */ new Error("Pairing timed out"));
10500
- this.destroy();
10501
- }
10502
- }, PAIRING_TIMEOUT_MS);
10544
+ if (this.config.fallbackSignalingUrl && !signalingUrl) {
10545
+ const fallbackTimer = setTimeout(() => {
10546
+ if (this._destroyed || connected) return;
10547
+ if (this.webrtc) {
10548
+ this.webrtc.destroy();
10549
+ this.webrtc = null;
10550
+ }
10551
+ this._usingFallback = true;
10552
+ this.emit("fallback", { url: this.config.fallbackSignalingUrl });
10553
+ this.connectToServer(this.config.fallbackSignalingUrl);
10554
+ }, SIGNALING_CONNECT_TIMEOUT_MS);
10555
+ this.webrtc.on("connected", () => clearTimeout(fallbackTimer));
10556
+ }
10503
10557
  this.webrtc.connect();
10504
10558
  }
10559
+ /** Whether the connection fell back to the fallback signaling server. */
10560
+ get usingFallback() {
10561
+ return this._usingFallback;
10562
+ }
10505
10563
  sendMessage(msg) {
10506
10564
  if (!this.webrtc || !this._connectedPeerId) return;
10507
10565
  this.webrtc.sendCustomMessage(this._connectedPeerId, JSON.stringify(msg));
@@ -10749,26 +10807,41 @@ var IdentityDocProvider = class extends EventEmitter {
10749
10807
  });
10750
10808
  for (const { url, key } of targets) {
10751
10809
  if (this.providers.has(key)) continue;
10752
- this._connectToServer(key, url);
10810
+ this.connectToServer(key, url);
10753
10811
  }
10754
10812
  if (this.config.webrtc && !this.webrtc) this._connectWebRTC();
10755
10813
  }
10756
- _connectToServer(key, serverUrl) {
10814
+ connectToServer(key, serverUrl) {
10815
+ if (this._destroyed) return;
10816
+ const existingProvider = this.providers.get(key);
10817
+ if (existingProvider) {
10818
+ existingProvider.destroy();
10819
+ this.providers.delete(key);
10820
+ }
10821
+ const existingWs = this.websockets.get(key);
10822
+ if (existingWs) {
10823
+ existingWs.destroy();
10824
+ this.websockets.delete(key);
10825
+ }
10757
10826
  const token = this.config.tokens?.[serverUrl] ?? this.config.token ?? "";
10758
10827
  const ws = new AbracadabraWS({
10759
10828
  url: serverUrl.replace(/^http/, "ws").replace(/\/$/, "").concat("/ws"),
10760
10829
  WebSocketPolyfill: void 0
10761
10830
  });
10762
10831
  this.websockets.set(key, ws);
10763
- const provider = new AbracadabraProvider({
10832
+ const providerConfig = {
10764
10833
  name: this.docId,
10765
10834
  document: this.document,
10766
10835
  websocketProvider: ws,
10767
- token,
10768
10836
  serverAgnostic: true,
10769
10837
  disableOfflineStore: key !== "local" && key !== "sync" ? true : this.config.disableOfflineStore ?? false,
10770
10838
  ...this.config.providerDefaults
10771
- });
10839
+ };
10840
+ if (this.config.cryptoIdentity && this.config.signChallenge) {
10841
+ providerConfig.cryptoIdentity = this.config.cryptoIdentity;
10842
+ providerConfig.signChallenge = this.config.signChallenge;
10843
+ } else providerConfig.token = token;
10844
+ const provider = new AbracadabraProvider(providerConfig);
10772
10845
  provider.on("synced", () => this.emit("synced", { server: key }));
10773
10846
  provider.on("status", (data) => this.emit("status", {
10774
10847
  server: key,
@@ -10975,7 +11048,7 @@ var IdentityDocProvider = class extends EventEmitter {
10975
11048
  ...this.config,
10976
11049
  syncServerUrl: url
10977
11050
  };
10978
- this._connectToServer("sync", url);
11051
+ this.connectToServer("sync", url);
10979
11052
  }
10980
11053
  }
10981
11054
  getProvider(key) {