@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
|
@@ -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
|
-
|
|
8914
|
-
|
|
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,
|
|
@@ -9980,7 +9992,7 @@ var AbracadabraWebRTC = class AbracadabraWebRTC extends EventEmitter {
|
|
|
9980
9992
|
channel = pc.router.createChannel(channelName, { ordered: true });
|
|
9981
9993
|
channel.onopen = () => {
|
|
9982
9994
|
const data = new TextEncoder().encode(payload);
|
|
9983
|
-
pc.router.send(channelName, data);
|
|
9995
|
+
pc.router.send(channelName, data).catch(() => {});
|
|
9984
9996
|
};
|
|
9985
9997
|
return;
|
|
9986
9998
|
}
|
|
@@ -10066,9 +10078,14 @@ var AbracadabraWebRTC = class AbracadabraWebRTC extends EventEmitter {
|
|
|
10066
10078
|
this.e2eeChannels.set(peerId, e2ee);
|
|
10067
10079
|
pc.router.setEncryptor(e2ee);
|
|
10068
10080
|
pc.router.on("channelMessage", async ({ name, data }) => {
|
|
10069
|
-
if (name === KEY_EXCHANGE_CHANNEL) {
|
|
10081
|
+
if (name === KEY_EXCHANGE_CHANNEL) try {
|
|
10070
10082
|
const buf = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
|
|
10071
10083
|
await e2ee.handleKeyExchange(buf);
|
|
10084
|
+
} catch (err) {
|
|
10085
|
+
this.emit("e2eeFailed", {
|
|
10086
|
+
peerId,
|
|
10087
|
+
error: err
|
|
10088
|
+
});
|
|
10072
10089
|
}
|
|
10073
10090
|
});
|
|
10074
10091
|
pc.router.on("channelOpen", ({ name, channel }) => {
|
|
@@ -10139,7 +10156,12 @@ var AbracadabraWebRTC = class AbracadabraWebRTC extends EventEmitter {
|
|
|
10139
10156
|
try {
|
|
10140
10157
|
const sdp = await pc.createOffer();
|
|
10141
10158
|
this.signaling?.sendOffer(peerId, sdp);
|
|
10142
|
-
} catch {
|
|
10159
|
+
} catch (err) {
|
|
10160
|
+
this.emit("error", {
|
|
10161
|
+
type: "offer-failed",
|
|
10162
|
+
peerId,
|
|
10163
|
+
error: err
|
|
10164
|
+
});
|
|
10143
10165
|
this.removePeer(peerId);
|
|
10144
10166
|
}
|
|
10145
10167
|
}
|
|
@@ -10157,7 +10179,12 @@ var AbracadabraWebRTC = class AbracadabraWebRTC extends EventEmitter {
|
|
|
10157
10179
|
try {
|
|
10158
10180
|
const answerSdp = await pc.setRemoteOffer(sdp);
|
|
10159
10181
|
this.signaling?.sendAnswer(from, answerSdp);
|
|
10160
|
-
} catch {
|
|
10182
|
+
} catch (err) {
|
|
10183
|
+
this.emit("error", {
|
|
10184
|
+
type: "answer-failed",
|
|
10185
|
+
peerId: from,
|
|
10186
|
+
error: err
|
|
10187
|
+
});
|
|
10161
10188
|
this.removePeer(from);
|
|
10162
10189
|
}
|
|
10163
10190
|
}
|
|
@@ -10349,6 +10376,7 @@ var ManualSignaling = class extends EventEmitter {
|
|
|
10349
10376
|
const CODE_CHARSET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
10350
10377
|
const CODE_LENGTH = 6;
|
|
10351
10378
|
const PAIRING_TIMEOUT_MS = 300 * 1e3;
|
|
10379
|
+
const SIGNALING_CONNECT_TIMEOUT_MS = 5e3;
|
|
10352
10380
|
function generatePairingCode() {
|
|
10353
10381
|
const bytes = crypto.getRandomValues(new Uint8Array(CODE_LENGTH));
|
|
10354
10382
|
return Array.from(bytes).map((b) => CODE_CHARSET[b % 32]).join("");
|
|
@@ -10366,6 +10394,7 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
10366
10394
|
this._destroyed = false;
|
|
10367
10395
|
this._pendingRequest = null;
|
|
10368
10396
|
this._connectedPeerId = null;
|
|
10397
|
+
this._usingFallback = false;
|
|
10369
10398
|
this.role = role;
|
|
10370
10399
|
this.pairingCode = pairingCode;
|
|
10371
10400
|
}
|
|
@@ -10520,12 +10549,41 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
10520
10549
|
}
|
|
10521
10550
|
this.removeAllListeners();
|
|
10522
10551
|
}
|
|
10552
|
+
async resolveToken(serverUrl) {
|
|
10553
|
+
if (this.config.token && serverUrl === this.config.serverUrl) return this.config.token;
|
|
10554
|
+
let base = serverUrl ?? this.config.serverUrl;
|
|
10555
|
+
while (base.endsWith("/")) base = base.slice(0, -1);
|
|
10556
|
+
const resp = await fetch(`${base}/auth/pairing-token`, { method: "POST" });
|
|
10557
|
+
if (!resp.ok) throw new Error(`Failed to fetch pairing token: ${resp.status} ${resp.statusText}`);
|
|
10558
|
+
const { token } = await resp.json();
|
|
10559
|
+
return token;
|
|
10560
|
+
}
|
|
10523
10561
|
start() {
|
|
10562
|
+
this.connectToServer(this.config.serverUrl);
|
|
10563
|
+
this.timeoutHandle = setTimeout(() => {
|
|
10564
|
+
if (!this._destroyed) {
|
|
10565
|
+
this.emit("error", /* @__PURE__ */ new Error("Pairing timed out"));
|
|
10566
|
+
this.destroy();
|
|
10567
|
+
}
|
|
10568
|
+
}, PAIRING_TIMEOUT_MS);
|
|
10569
|
+
}
|
|
10570
|
+
connectToServer(serverUrl, signalingUrl) {
|
|
10571
|
+
const roomId = codeToRoomId(this.pairingCode);
|
|
10572
|
+
const tokenPromise = this.resolveToken(serverUrl);
|
|
10573
|
+
const tokenFactory = async () => {
|
|
10574
|
+
const t = await tokenPromise;
|
|
10575
|
+
if (typeof t === "function") return await t();
|
|
10576
|
+
return t;
|
|
10577
|
+
};
|
|
10578
|
+
if (!this.config.iceServers) new AbracadabraClient({ url: serverUrl }).getIceServers().then((servers) => {
|
|
10579
|
+
if (servers.length > 0) this._resolvedIceServers = servers;
|
|
10580
|
+
});
|
|
10524
10581
|
this.webrtc = new AbracadabraWebRTC({
|
|
10525
|
-
docId:
|
|
10526
|
-
url:
|
|
10527
|
-
|
|
10528
|
-
|
|
10582
|
+
docId: roomId,
|
|
10583
|
+
url: serverUrl,
|
|
10584
|
+
signalingUrl: signalingUrl ?? void 0,
|
|
10585
|
+
token: tokenFactory,
|
|
10586
|
+
iceServers: this.config.iceServers ?? this._resolvedIceServers,
|
|
10529
10587
|
e2ee: this.config.e2ee,
|
|
10530
10588
|
enableDocSync: false,
|
|
10531
10589
|
enableAwarenessSync: false,
|
|
@@ -10533,6 +10591,10 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
10533
10591
|
autoConnect: false,
|
|
10534
10592
|
WebSocketPolyfill: this.config.WebSocketPolyfill
|
|
10535
10593
|
});
|
|
10594
|
+
let connected = false;
|
|
10595
|
+
this.webrtc.on("connected", () => {
|
|
10596
|
+
connected = true;
|
|
10597
|
+
});
|
|
10536
10598
|
this.webrtc.on("e2eeEstablished", ({ peerId }) => {
|
|
10537
10599
|
this._connectedPeerId = peerId;
|
|
10538
10600
|
this.emit("connected");
|
|
@@ -10540,20 +10602,37 @@ var DevicePairingChannel = class DevicePairingChannel extends EventEmitter {
|
|
|
10540
10602
|
this.webrtc.on("customMessage", ({ peerId, payload }) => {
|
|
10541
10603
|
this.handleMessage(peerId, payload);
|
|
10542
10604
|
});
|
|
10605
|
+
this.webrtc.on("e2eeFailed", ({ peerId, error }) => {
|
|
10606
|
+
if (!this._destroyed) this.emit("error", /* @__PURE__ */ new Error(`E2EE failed: ${error?.message ?? error}`));
|
|
10607
|
+
});
|
|
10608
|
+
this.webrtc.on("error", (err) => {
|
|
10609
|
+
if (!this._destroyed) this.emit("error", /* @__PURE__ */ new Error(`WebRTC: ${err?.type ?? err?.message ?? "unknown"}`));
|
|
10610
|
+
});
|
|
10543
10611
|
this.webrtc.on("peerLeft", () => {
|
|
10544
10612
|
if (!this._destroyed) this.emit("error", /* @__PURE__ */ new Error("Peer disconnected"));
|
|
10545
10613
|
});
|
|
10546
10614
|
this.webrtc.on("signalingError", (err) => {
|
|
10547
10615
|
this.emit("error", /* @__PURE__ */ new Error(`Signaling: ${err.message}`));
|
|
10548
10616
|
});
|
|
10549
|
-
this.
|
|
10550
|
-
|
|
10551
|
-
this.
|
|
10552
|
-
this.
|
|
10553
|
-
|
|
10554
|
-
|
|
10617
|
+
if (this.config.fallbackSignalingUrl && !signalingUrl) {
|
|
10618
|
+
const fallbackTimer = setTimeout(() => {
|
|
10619
|
+
if (this._destroyed || connected) return;
|
|
10620
|
+
if (this.webrtc) {
|
|
10621
|
+
this.webrtc.destroy();
|
|
10622
|
+
this.webrtc = null;
|
|
10623
|
+
}
|
|
10624
|
+
this._usingFallback = true;
|
|
10625
|
+
this.emit("fallback", { url: this.config.fallbackSignalingUrl });
|
|
10626
|
+
this.connectToServer(this.config.fallbackSignalingUrl);
|
|
10627
|
+
}, SIGNALING_CONNECT_TIMEOUT_MS);
|
|
10628
|
+
this.webrtc.on("connected", () => clearTimeout(fallbackTimer));
|
|
10629
|
+
}
|
|
10555
10630
|
this.webrtc.connect();
|
|
10556
10631
|
}
|
|
10632
|
+
/** Whether the connection fell back to the fallback signaling server. */
|
|
10633
|
+
get usingFallback() {
|
|
10634
|
+
return this._usingFallback;
|
|
10635
|
+
}
|
|
10557
10636
|
sendMessage(msg) {
|
|
10558
10637
|
if (!this.webrtc || !this._connectedPeerId) return;
|
|
10559
10638
|
this.webrtc.sendCustomMessage(this._connectedPeerId, JSON.stringify(msg));
|
|
@@ -10801,26 +10880,41 @@ var IdentityDocProvider = class extends EventEmitter {
|
|
|
10801
10880
|
});
|
|
10802
10881
|
for (const { url, key } of targets) {
|
|
10803
10882
|
if (this.providers.has(key)) continue;
|
|
10804
|
-
this.
|
|
10883
|
+
this.connectToServer(key, url);
|
|
10805
10884
|
}
|
|
10806
10885
|
if (this.config.webrtc && !this.webrtc) this._connectWebRTC();
|
|
10807
10886
|
}
|
|
10808
|
-
|
|
10887
|
+
connectToServer(key, serverUrl) {
|
|
10888
|
+
if (this._destroyed) return;
|
|
10889
|
+
const existingProvider = this.providers.get(key);
|
|
10890
|
+
if (existingProvider) {
|
|
10891
|
+
existingProvider.destroy();
|
|
10892
|
+
this.providers.delete(key);
|
|
10893
|
+
}
|
|
10894
|
+
const existingWs = this.websockets.get(key);
|
|
10895
|
+
if (existingWs) {
|
|
10896
|
+
existingWs.destroy();
|
|
10897
|
+
this.websockets.delete(key);
|
|
10898
|
+
}
|
|
10809
10899
|
const token = this.config.tokens?.[serverUrl] ?? this.config.token ?? "";
|
|
10810
10900
|
const ws = new AbracadabraWS({
|
|
10811
10901
|
url: serverUrl.replace(/^http/, "ws").replace(/\/$/, "").concat("/ws"),
|
|
10812
10902
|
WebSocketPolyfill: void 0
|
|
10813
10903
|
});
|
|
10814
10904
|
this.websockets.set(key, ws);
|
|
10815
|
-
const
|
|
10905
|
+
const providerConfig = {
|
|
10816
10906
|
name: this.docId,
|
|
10817
10907
|
document: this.document,
|
|
10818
10908
|
websocketProvider: ws,
|
|
10819
|
-
token,
|
|
10820
10909
|
serverAgnostic: true,
|
|
10821
10910
|
disableOfflineStore: key !== "local" && key !== "sync" ? true : this.config.disableOfflineStore ?? false,
|
|
10822
10911
|
...this.config.providerDefaults
|
|
10823
|
-
}
|
|
10912
|
+
};
|
|
10913
|
+
if (this.config.cryptoIdentity && this.config.signChallenge) {
|
|
10914
|
+
providerConfig.cryptoIdentity = this.config.cryptoIdentity;
|
|
10915
|
+
providerConfig.signChallenge = this.config.signChallenge;
|
|
10916
|
+
} else providerConfig.token = token;
|
|
10917
|
+
const provider = new AbracadabraProvider(providerConfig);
|
|
10824
10918
|
provider.on("synced", () => this.emit("synced", { server: key }));
|
|
10825
10919
|
provider.on("status", (data) => this.emit("status", {
|
|
10826
10920
|
server: key,
|
|
@@ -11027,7 +11121,7 @@ var IdentityDocProvider = class extends EventEmitter {
|
|
|
11027
11121
|
...this.config,
|
|
11028
11122
|
syncServerUrl: url
|
|
11029
11123
|
};
|
|
11030
|
-
this.
|
|
11124
|
+
this.connectToServer("sync", url);
|
|
11031
11125
|
}
|
|
11032
11126
|
}
|
|
11033
11127
|
getProvider(key) {
|