@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.
@@ -3252,6 +3252,18 @@ var AbracadabraClient = class {
3252
3252
  auth: false
3253
3253
  });
3254
3254
  }
3255
+ /**
3256
+ * Fetch a short-lived anonymous pairing token for WebRTC signaling.
3257
+ * No authentication required. The token only grants access to `__pairing_*` rooms.
3258
+ */
3259
+ static async getPairingToken(serverUrl) {
3260
+ let base = serverUrl;
3261
+ while (base.endsWith("/")) base = base.slice(0, -1);
3262
+ const resp = await fetch(`${base}/auth/pairing-token`, { method: "POST" });
3263
+ if (!resp.ok) throw new Error(`Failed to fetch pairing token: ${resp.status}`);
3264
+ const { token } = await resp.json();
3265
+ return token;
3266
+ }
3255
3267
  /** Get encryption info for a document. */
3256
3268
  async getDocEncryption(docId) {
3257
3269
  return this.request("GET", `/docs/${encodeURIComponent(docId)}/encryption`);
@@ -8910,8 +8922,8 @@ var SignalingSocket = class extends EventEmitter {
8910
8922
  break;
8911
8923
  case "joined":
8912
8924
  this.emit("joined", {
8913
- peerId: msg.peer_id,
8914
- userId: msg.user_id,
8925
+ peer_id: msg.peer_id,
8926
+ user_id: msg.user_id,
8915
8927
  muted: msg.muted,
8916
8928
  video: msg.video,
8917
8929
  screen: msg.screen,
@@ -10349,6 +10361,7 @@ var ManualSignaling = class extends EventEmitter {
10349
10361
  const CODE_CHARSET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
10350
10362
  const CODE_LENGTH = 6;
10351
10363
  const PAIRING_TIMEOUT_MS = 300 * 1e3;
10364
+ const SIGNALING_CONNECT_TIMEOUT_MS = 5e3;
10352
10365
  function generatePairingCode() {
10353
10366
  const bytes = crypto.getRandomValues(new Uint8Array(CODE_LENGTH));
10354
10367
  return Array.from(bytes).map((b) => CODE_CHARSET[b % 32]).join("");
@@ -10366,6 +10379,7 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
10366
10379
  this._destroyed = false;
10367
10380
  this._pendingRequest = null;
10368
10381
  this._connectedPeerId = null;
10382
+ this._usingFallback = false;
10369
10383
  this.role = role;
10370
10384
  this.pairingCode = pairingCode;
10371
10385
  }
@@ -10520,12 +10534,41 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
10520
10534
  }
10521
10535
  this.removeAllListeners();
10522
10536
  }
10537
+ async resolveToken(serverUrl) {
10538
+ if (this.config.token && serverUrl === this.config.serverUrl) return this.config.token;
10539
+ let base = serverUrl ?? this.config.serverUrl;
10540
+ while (base.endsWith("/")) base = base.slice(0, -1);
10541
+ const resp = await fetch(`${base}/auth/pairing-token`, { method: "POST" });
10542
+ if (!resp.ok) throw new Error(`Failed to fetch pairing token: ${resp.status} ${resp.statusText}`);
10543
+ const { token } = await resp.json();
10544
+ return token;
10545
+ }
10523
10546
  start() {
10547
+ this.connectToServer(this.config.serverUrl);
10548
+ this.timeoutHandle = setTimeout(() => {
10549
+ if (!this._destroyed) {
10550
+ this.emit("error", /* @__PURE__ */ new Error("Pairing timed out"));
10551
+ this.destroy();
10552
+ }
10553
+ }, PAIRING_TIMEOUT_MS);
10554
+ }
10555
+ connectToServer(serverUrl, signalingUrl) {
10556
+ const roomId = codeToRoomId(this.pairingCode);
10557
+ const tokenPromise = this.resolveToken(serverUrl);
10558
+ const tokenFactory = async () => {
10559
+ const t = await tokenPromise;
10560
+ if (typeof t === "function") return await t();
10561
+ return t;
10562
+ };
10563
+ if (!this.config.iceServers) new AbracadabraClient({ url: serverUrl }).getIceServers().then((servers) => {
10564
+ if (servers.length > 0) this._resolvedIceServers = servers;
10565
+ });
10524
10566
  this.webrtc = new AbracadabraWebRTC({
10525
- docId: codeToRoomId(this.pairingCode),
10526
- url: this.config.serverUrl,
10527
- token: this.config.token,
10528
- iceServers: this.config.iceServers,
10567
+ docId: roomId,
10568
+ url: serverUrl,
10569
+ signalingUrl: signalingUrl ?? void 0,
10570
+ token: tokenFactory,
10571
+ iceServers: this.config.iceServers ?? this._resolvedIceServers,
10529
10572
  e2ee: this.config.e2ee,
10530
10573
  enableDocSync: false,
10531
10574
  enableAwarenessSync: false,
@@ -10533,6 +10576,10 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
10533
10576
  autoConnect: false,
10534
10577
  WebSocketPolyfill: this.config.WebSocketPolyfill
10535
10578
  });
10579
+ let connected = false;
10580
+ this.webrtc.on("connected", () => {
10581
+ connected = true;
10582
+ });
10536
10583
  this.webrtc.on("e2eeEstablished", ({ peerId }) => {
10537
10584
  this._connectedPeerId = peerId;
10538
10585
  this.emit("connected");
@@ -10546,14 +10593,25 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
10546
10593
  this.webrtc.on("signalingError", (err) => {
10547
10594
  this.emit("error", /* @__PURE__ */ new Error(`Signaling: ${err.message}`));
10548
10595
  });
10549
- this.timeoutHandle = setTimeout(() => {
10550
- if (!this._destroyed) {
10551
- this.emit("error", /* @__PURE__ */ new Error("Pairing timed out"));
10552
- this.destroy();
10553
- }
10554
- }, PAIRING_TIMEOUT_MS);
10596
+ if (this.config.fallbackSignalingUrl && !signalingUrl) {
10597
+ const fallbackTimer = setTimeout(() => {
10598
+ if (this._destroyed || connected) return;
10599
+ if (this.webrtc) {
10600
+ this.webrtc.destroy();
10601
+ this.webrtc = null;
10602
+ }
10603
+ this._usingFallback = true;
10604
+ this.emit("fallback", { url: this.config.fallbackSignalingUrl });
10605
+ this.connectToServer(this.config.fallbackSignalingUrl);
10606
+ }, SIGNALING_CONNECT_TIMEOUT_MS);
10607
+ this.webrtc.on("connected", () => clearTimeout(fallbackTimer));
10608
+ }
10555
10609
  this.webrtc.connect();
10556
10610
  }
10611
+ /** Whether the connection fell back to the fallback signaling server. */
10612
+ get usingFallback() {
10613
+ return this._usingFallback;
10614
+ }
10557
10615
  sendMessage(msg) {
10558
10616
  if (!this.webrtc || !this._connectedPeerId) return;
10559
10617
  this.webrtc.sendCustomMessage(this._connectedPeerId, JSON.stringify(msg));
@@ -10801,26 +10859,41 @@ var IdentityDocProvider = class extends EventEmitter {
10801
10859
  });
10802
10860
  for (const { url, key } of targets) {
10803
10861
  if (this.providers.has(key)) continue;
10804
- this._connectToServer(key, url);
10862
+ this.connectToServer(key, url);
10805
10863
  }
10806
10864
  if (this.config.webrtc && !this.webrtc) this._connectWebRTC();
10807
10865
  }
10808
- _connectToServer(key, serverUrl) {
10866
+ connectToServer(key, serverUrl) {
10867
+ if (this._destroyed) return;
10868
+ const existingProvider = this.providers.get(key);
10869
+ if (existingProvider) {
10870
+ existingProvider.destroy();
10871
+ this.providers.delete(key);
10872
+ }
10873
+ const existingWs = this.websockets.get(key);
10874
+ if (existingWs) {
10875
+ existingWs.destroy();
10876
+ this.websockets.delete(key);
10877
+ }
10809
10878
  const token = this.config.tokens?.[serverUrl] ?? this.config.token ?? "";
10810
10879
  const ws = new AbracadabraWS({
10811
10880
  url: serverUrl.replace(/^http/, "ws").replace(/\/$/, "").concat("/ws"),
10812
10881
  WebSocketPolyfill: void 0
10813
10882
  });
10814
10883
  this.websockets.set(key, ws);
10815
- const provider = new AbracadabraProvider({
10884
+ const providerConfig = {
10816
10885
  name: this.docId,
10817
10886
  document: this.document,
10818
10887
  websocketProvider: ws,
10819
- token,
10820
10888
  serverAgnostic: true,
10821
10889
  disableOfflineStore: key !== "local" && key !== "sync" ? true : this.config.disableOfflineStore ?? false,
10822
10890
  ...this.config.providerDefaults
10823
- });
10891
+ };
10892
+ if (this.config.cryptoIdentity && this.config.signChallenge) {
10893
+ providerConfig.cryptoIdentity = this.config.cryptoIdentity;
10894
+ providerConfig.signChallenge = this.config.signChallenge;
10895
+ } else providerConfig.token = token;
10896
+ const provider = new AbracadabraProvider(providerConfig);
10824
10897
  provider.on("synced", () => this.emit("synced", { server: key }));
10825
10898
  provider.on("status", (data) => this.emit("status", {
10826
10899
  server: key,
@@ -11027,7 +11100,7 @@ var IdentityDocProvider = class extends EventEmitter {
11027
11100
  ...this.config,
11028
11101
  syncServerUrl: url
11029
11102
  };
11030
- this._connectToServer("sync", url);
11103
+ this.connectToServer("sync", url);
11031
11104
  }
11032
11105
  }
11033
11106
  getProvider(key) {