@abraca/dabra 1.0.22 → 1.0.24
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/dist/abracadabra-provider.cjs +116 -22
- package/dist/abracadabra-provider.cjs.map +1 -1
- package/dist/abracadabra-provider.esm.js +116 -22
- package/dist/abracadabra-provider.esm.js.map +1 -1
- package/dist/index.d.ts +34 -3
- package/package.json +1 -1
- package/src/AbracadabraClient.ts +17 -0
- package/src/IdentityDoc.ts +42 -6
- package/src/webrtc/AbracadabraWebRTC.ts +11 -5
- package/src/webrtc/DevicePairingChannel.ts +113 -13
- package/src/webrtc/SignalingSocket.ts +2 -2
|
@@ -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
|
-
|
|
8862
|
-
|
|
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,
|
|
@@ -9928,7 +9940,7 @@ var AbracadabraWebRTC = class AbracadabraWebRTC extends EventEmitter {
|
|
|
9928
9940
|
channel = pc.router.createChannel(channelName, { ordered: true });
|
|
9929
9941
|
channel.onopen = () => {
|
|
9930
9942
|
const data = new TextEncoder().encode(payload);
|
|
9931
|
-
pc.router.send(channelName, data);
|
|
9943
|
+
pc.router.send(channelName, data).catch(() => {});
|
|
9932
9944
|
};
|
|
9933
9945
|
return;
|
|
9934
9946
|
}
|
|
@@ -10014,9 +10026,14 @@ var AbracadabraWebRTC = class AbracadabraWebRTC extends EventEmitter {
|
|
|
10014
10026
|
this.e2eeChannels.set(peerId, e2ee);
|
|
10015
10027
|
pc.router.setEncryptor(e2ee);
|
|
10016
10028
|
pc.router.on("channelMessage", async ({ name, data }) => {
|
|
10017
|
-
if (name === KEY_EXCHANGE_CHANNEL) {
|
|
10029
|
+
if (name === KEY_EXCHANGE_CHANNEL) try {
|
|
10018
10030
|
const buf = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
|
|
10019
10031
|
await e2ee.handleKeyExchange(buf);
|
|
10032
|
+
} catch (err) {
|
|
10033
|
+
this.emit("e2eeFailed", {
|
|
10034
|
+
peerId,
|
|
10035
|
+
error: err
|
|
10036
|
+
});
|
|
10020
10037
|
}
|
|
10021
10038
|
});
|
|
10022
10039
|
pc.router.on("channelOpen", ({ name, channel }) => {
|
|
@@ -10087,7 +10104,12 @@ var AbracadabraWebRTC = class AbracadabraWebRTC extends EventEmitter {
|
|
|
10087
10104
|
try {
|
|
10088
10105
|
const sdp = await pc.createOffer();
|
|
10089
10106
|
this.signaling?.sendOffer(peerId, sdp);
|
|
10090
|
-
} catch {
|
|
10107
|
+
} catch (err) {
|
|
10108
|
+
this.emit("error", {
|
|
10109
|
+
type: "offer-failed",
|
|
10110
|
+
peerId,
|
|
10111
|
+
error: err
|
|
10112
|
+
});
|
|
10091
10113
|
this.removePeer(peerId);
|
|
10092
10114
|
}
|
|
10093
10115
|
}
|
|
@@ -10105,7 +10127,12 @@ var AbracadabraWebRTC = class AbracadabraWebRTC extends EventEmitter {
|
|
|
10105
10127
|
try {
|
|
10106
10128
|
const answerSdp = await pc.setRemoteOffer(sdp);
|
|
10107
10129
|
this.signaling?.sendAnswer(from, answerSdp);
|
|
10108
|
-
} catch {
|
|
10130
|
+
} catch (err) {
|
|
10131
|
+
this.emit("error", {
|
|
10132
|
+
type: "answer-failed",
|
|
10133
|
+
peerId: from,
|
|
10134
|
+
error: err
|
|
10135
|
+
});
|
|
10109
10136
|
this.removePeer(from);
|
|
10110
10137
|
}
|
|
10111
10138
|
}
|
|
@@ -10297,6 +10324,7 @@ var ManualSignaling = class extends EventEmitter {
|
|
|
10297
10324
|
const CODE_CHARSET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
10298
10325
|
const CODE_LENGTH = 6;
|
|
10299
10326
|
const PAIRING_TIMEOUT_MS = 300 * 1e3;
|
|
10327
|
+
const SIGNALING_CONNECT_TIMEOUT_MS = 5e3;
|
|
10300
10328
|
function generatePairingCode() {
|
|
10301
10329
|
const bytes = crypto.getRandomValues(new Uint8Array(CODE_LENGTH));
|
|
10302
10330
|
return Array.from(bytes).map((b) => CODE_CHARSET[b % 32]).join("");
|
|
@@ -10314,6 +10342,7 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
10314
10342
|
this._destroyed = false;
|
|
10315
10343
|
this._pendingRequest = null;
|
|
10316
10344
|
this._connectedPeerId = null;
|
|
10345
|
+
this._usingFallback = false;
|
|
10317
10346
|
this.role = role;
|
|
10318
10347
|
this.pairingCode = pairingCode;
|
|
10319
10348
|
}
|
|
@@ -10468,12 +10497,41 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
10468
10497
|
}
|
|
10469
10498
|
this.removeAllListeners();
|
|
10470
10499
|
}
|
|
10500
|
+
async resolveToken(serverUrl) {
|
|
10501
|
+
if (this.config.token && serverUrl === this.config.serverUrl) return this.config.token;
|
|
10502
|
+
let base = serverUrl ?? this.config.serverUrl;
|
|
10503
|
+
while (base.endsWith("/")) base = base.slice(0, -1);
|
|
10504
|
+
const resp = await fetch(`${base}/auth/pairing-token`, { method: "POST" });
|
|
10505
|
+
if (!resp.ok) throw new Error(`Failed to fetch pairing token: ${resp.status} ${resp.statusText}`);
|
|
10506
|
+
const { token } = await resp.json();
|
|
10507
|
+
return token;
|
|
10508
|
+
}
|
|
10471
10509
|
start() {
|
|
10510
|
+
this.connectToServer(this.config.serverUrl);
|
|
10511
|
+
this.timeoutHandle = setTimeout(() => {
|
|
10512
|
+
if (!this._destroyed) {
|
|
10513
|
+
this.emit("error", /* @__PURE__ */ new Error("Pairing timed out"));
|
|
10514
|
+
this.destroy();
|
|
10515
|
+
}
|
|
10516
|
+
}, PAIRING_TIMEOUT_MS);
|
|
10517
|
+
}
|
|
10518
|
+
connectToServer(serverUrl, signalingUrl) {
|
|
10519
|
+
const roomId = codeToRoomId(this.pairingCode);
|
|
10520
|
+
const tokenPromise = this.resolveToken(serverUrl);
|
|
10521
|
+
const tokenFactory = async () => {
|
|
10522
|
+
const t = await tokenPromise;
|
|
10523
|
+
if (typeof t === "function") return await t();
|
|
10524
|
+
return t;
|
|
10525
|
+
};
|
|
10526
|
+
if (!this.config.iceServers) new AbracadabraClient({ url: serverUrl }).getIceServers().then((servers) => {
|
|
10527
|
+
if (servers.length > 0) this._resolvedIceServers = servers;
|
|
10528
|
+
});
|
|
10472
10529
|
this.webrtc = new AbracadabraWebRTC({
|
|
10473
|
-
docId:
|
|
10474
|
-
url:
|
|
10475
|
-
|
|
10476
|
-
|
|
10530
|
+
docId: roomId,
|
|
10531
|
+
url: serverUrl,
|
|
10532
|
+
signalingUrl: signalingUrl ?? void 0,
|
|
10533
|
+
token: tokenFactory,
|
|
10534
|
+
iceServers: this.config.iceServers ?? this._resolvedIceServers,
|
|
10477
10535
|
e2ee: this.config.e2ee,
|
|
10478
10536
|
enableDocSync: false,
|
|
10479
10537
|
enableAwarenessSync: false,
|
|
@@ -10481,6 +10539,10 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
10481
10539
|
autoConnect: false,
|
|
10482
10540
|
WebSocketPolyfill: this.config.WebSocketPolyfill
|
|
10483
10541
|
});
|
|
10542
|
+
let connected = false;
|
|
10543
|
+
this.webrtc.on("connected", () => {
|
|
10544
|
+
connected = true;
|
|
10545
|
+
});
|
|
10484
10546
|
this.webrtc.on("e2eeEstablished", ({ peerId }) => {
|
|
10485
10547
|
this._connectedPeerId = peerId;
|
|
10486
10548
|
this.emit("connected");
|
|
@@ -10488,20 +10550,37 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
10488
10550
|
this.webrtc.on("customMessage", ({ peerId, payload }) => {
|
|
10489
10551
|
this.handleMessage(peerId, payload);
|
|
10490
10552
|
});
|
|
10553
|
+
this.webrtc.on("e2eeFailed", ({ peerId, error }) => {
|
|
10554
|
+
if (!this._destroyed) this.emit("error", /* @__PURE__ */ new Error(`E2EE failed: ${error?.message ?? error}`));
|
|
10555
|
+
});
|
|
10556
|
+
this.webrtc.on("error", (err) => {
|
|
10557
|
+
if (!this._destroyed) this.emit("error", /* @__PURE__ */ new Error(`WebRTC: ${err?.type ?? err?.message ?? "unknown"}`));
|
|
10558
|
+
});
|
|
10491
10559
|
this.webrtc.on("peerLeft", () => {
|
|
10492
10560
|
if (!this._destroyed) this.emit("error", /* @__PURE__ */ new Error("Peer disconnected"));
|
|
10493
10561
|
});
|
|
10494
10562
|
this.webrtc.on("signalingError", (err) => {
|
|
10495
10563
|
this.emit("error", /* @__PURE__ */ new Error(`Signaling: ${err.message}`));
|
|
10496
10564
|
});
|
|
10497
|
-
this.
|
|
10498
|
-
|
|
10499
|
-
this.
|
|
10500
|
-
this.
|
|
10501
|
-
|
|
10502
|
-
|
|
10565
|
+
if (this.config.fallbackSignalingUrl && !signalingUrl) {
|
|
10566
|
+
const fallbackTimer = setTimeout(() => {
|
|
10567
|
+
if (this._destroyed || connected) return;
|
|
10568
|
+
if (this.webrtc) {
|
|
10569
|
+
this.webrtc.destroy();
|
|
10570
|
+
this.webrtc = null;
|
|
10571
|
+
}
|
|
10572
|
+
this._usingFallback = true;
|
|
10573
|
+
this.emit("fallback", { url: this.config.fallbackSignalingUrl });
|
|
10574
|
+
this.connectToServer(this.config.fallbackSignalingUrl);
|
|
10575
|
+
}, SIGNALING_CONNECT_TIMEOUT_MS);
|
|
10576
|
+
this.webrtc.on("connected", () => clearTimeout(fallbackTimer));
|
|
10577
|
+
}
|
|
10503
10578
|
this.webrtc.connect();
|
|
10504
10579
|
}
|
|
10580
|
+
/** Whether the connection fell back to the fallback signaling server. */
|
|
10581
|
+
get usingFallback() {
|
|
10582
|
+
return this._usingFallback;
|
|
10583
|
+
}
|
|
10505
10584
|
sendMessage(msg) {
|
|
10506
10585
|
if (!this.webrtc || !this._connectedPeerId) return;
|
|
10507
10586
|
this.webrtc.sendCustomMessage(this._connectedPeerId, JSON.stringify(msg));
|
|
@@ -10749,26 +10828,41 @@ var IdentityDocProvider = class extends EventEmitter {
|
|
|
10749
10828
|
});
|
|
10750
10829
|
for (const { url, key } of targets) {
|
|
10751
10830
|
if (this.providers.has(key)) continue;
|
|
10752
|
-
this.
|
|
10831
|
+
this.connectToServer(key, url);
|
|
10753
10832
|
}
|
|
10754
10833
|
if (this.config.webrtc && !this.webrtc) this._connectWebRTC();
|
|
10755
10834
|
}
|
|
10756
|
-
|
|
10835
|
+
connectToServer(key, serverUrl) {
|
|
10836
|
+
if (this._destroyed) return;
|
|
10837
|
+
const existingProvider = this.providers.get(key);
|
|
10838
|
+
if (existingProvider) {
|
|
10839
|
+
existingProvider.destroy();
|
|
10840
|
+
this.providers.delete(key);
|
|
10841
|
+
}
|
|
10842
|
+
const existingWs = this.websockets.get(key);
|
|
10843
|
+
if (existingWs) {
|
|
10844
|
+
existingWs.destroy();
|
|
10845
|
+
this.websockets.delete(key);
|
|
10846
|
+
}
|
|
10757
10847
|
const token = this.config.tokens?.[serverUrl] ?? this.config.token ?? "";
|
|
10758
10848
|
const ws = new AbracadabraWS({
|
|
10759
10849
|
url: serverUrl.replace(/^http/, "ws").replace(/\/$/, "").concat("/ws"),
|
|
10760
10850
|
WebSocketPolyfill: void 0
|
|
10761
10851
|
});
|
|
10762
10852
|
this.websockets.set(key, ws);
|
|
10763
|
-
const
|
|
10853
|
+
const providerConfig = {
|
|
10764
10854
|
name: this.docId,
|
|
10765
10855
|
document: this.document,
|
|
10766
10856
|
websocketProvider: ws,
|
|
10767
|
-
token,
|
|
10768
10857
|
serverAgnostic: true,
|
|
10769
10858
|
disableOfflineStore: key !== "local" && key !== "sync" ? true : this.config.disableOfflineStore ?? false,
|
|
10770
10859
|
...this.config.providerDefaults
|
|
10771
|
-
}
|
|
10860
|
+
};
|
|
10861
|
+
if (this.config.cryptoIdentity && this.config.signChallenge) {
|
|
10862
|
+
providerConfig.cryptoIdentity = this.config.cryptoIdentity;
|
|
10863
|
+
providerConfig.signChallenge = this.config.signChallenge;
|
|
10864
|
+
} else providerConfig.token = token;
|
|
10865
|
+
const provider = new AbracadabraProvider(providerConfig);
|
|
10772
10866
|
provider.on("synced", () => this.emit("synced", { server: key }));
|
|
10773
10867
|
provider.on("status", (data) => this.emit("status", {
|
|
10774
10868
|
server: key,
|
|
@@ -10975,7 +11069,7 @@ var IdentityDocProvider = class extends EventEmitter {
|
|
|
10975
11069
|
...this.config,
|
|
10976
11070
|
syncServerUrl: url
|
|
10977
11071
|
};
|
|
10978
|
-
this.
|
|
11072
|
+
this.connectToServer("sync", url);
|
|
10979
11073
|
}
|
|
10980
11074
|
}
|
|
10981
11075
|
getProvider(key) {
|