@kelnishi/satmouse-client 0.14.3 → 0.15.0
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/{connection-iUlge6Er.d.cts → connection-B6DpQdAG.d.cts} +3 -1
- package/dist/{connection-iUlge6Er.d.ts → connection-B6DpQdAG.d.ts} +3 -1
- package/dist/core/index.cjs +119 -1
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +2 -2
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +119 -1
- package/dist/core/index.js.map +1 -1
- package/dist/elements/index.d.cts +1 -1
- package/dist/elements/index.d.ts +1 -1
- package/dist/react/index.cjs +119 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +3 -1
- package/dist/react/index.d.ts +3 -1
- package/dist/react/index.js +119 -1
- package/dist/react/index.js.map +1 -1
- package/dist/utils/index.d.cts +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/package.json +1 -1
package/dist/react/index.js
CHANGED
|
@@ -252,6 +252,114 @@ var WebSocketAdapter = class {
|
|
|
252
252
|
}
|
|
253
253
|
};
|
|
254
254
|
|
|
255
|
+
// src/core/transports/webrtc.ts
|
|
256
|
+
var WebRTCAdapter = class {
|
|
257
|
+
protocol = "webrtc";
|
|
258
|
+
onSpatialData = null;
|
|
259
|
+
onButtonEvent = null;
|
|
260
|
+
onDeviceStatus = null;
|
|
261
|
+
onClose = null;
|
|
262
|
+
onError = null;
|
|
263
|
+
pc = null;
|
|
264
|
+
signalingUrl;
|
|
265
|
+
/**
|
|
266
|
+
* @param signalingUrl — HTTP endpoint for SDP exchange (e.g., "http://127.0.0.1:18945/rtc/offer")
|
|
267
|
+
*/
|
|
268
|
+
constructor(signalingUrl) {
|
|
269
|
+
this.signalingUrl = signalingUrl;
|
|
270
|
+
}
|
|
271
|
+
async connect() {
|
|
272
|
+
if (typeof globalThis.RTCPeerConnection === "undefined") {
|
|
273
|
+
throw new Error("RTCPeerConnection not available");
|
|
274
|
+
}
|
|
275
|
+
this.pc = new RTCPeerConnection({
|
|
276
|
+
iceServers: []
|
|
277
|
+
// Local network, no STUN/TURN
|
|
278
|
+
});
|
|
279
|
+
this.pc.ondatachannel = (event) => {
|
|
280
|
+
const channel = event.channel;
|
|
281
|
+
if (channel.label === "spatial") {
|
|
282
|
+
channel.binaryType = "arraybuffer";
|
|
283
|
+
channel.onmessage = (e) => {
|
|
284
|
+
if (e.data instanceof ArrayBuffer && e.data.byteLength >= 20) {
|
|
285
|
+
const decoded = decodeBinaryFrame(e.data);
|
|
286
|
+
this.onSpatialData?.(decoded);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
} else if (channel.label === "reliable") {
|
|
290
|
+
channel.onmessage = (e) => {
|
|
291
|
+
try {
|
|
292
|
+
const text = typeof e.data === "string" ? e.data : new TextDecoder().decode(e.data);
|
|
293
|
+
const msg = JSON.parse(text);
|
|
294
|
+
if (msg.type === "buttonEvent") this.onButtonEvent?.(msg.data);
|
|
295
|
+
else if (msg.type === "deviceStatus") this.onDeviceStatus?.(msg.data.event, msg.data.device);
|
|
296
|
+
} catch {
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
this.pc.onconnectionstatechange = () => {
|
|
302
|
+
const state = this.pc?.connectionState;
|
|
303
|
+
if (state === "disconnected" || state === "failed" || state === "closed") {
|
|
304
|
+
this.onClose?.();
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
const offer = await this.pc.createOffer();
|
|
308
|
+
await this.pc.setLocalDescription(offer);
|
|
309
|
+
await this.waitForICE();
|
|
310
|
+
const response = await fetch(this.signalingUrl, {
|
|
311
|
+
method: "POST",
|
|
312
|
+
body: this.pc.localDescription.sdp,
|
|
313
|
+
headers: { "Content-Type": "application/sdp" }
|
|
314
|
+
});
|
|
315
|
+
if (!response.ok) {
|
|
316
|
+
throw new Error(`Signaling failed: ${response.status}`);
|
|
317
|
+
}
|
|
318
|
+
const answerSdp = await response.text();
|
|
319
|
+
await this.pc.setRemoteDescription({ type: "answer", sdp: answerSdp });
|
|
320
|
+
await new Promise((resolve, reject) => {
|
|
321
|
+
const timeout = setTimeout(() => reject(new Error("WebRTC connection timeout")), 1e4);
|
|
322
|
+
const check = () => {
|
|
323
|
+
if (this.pc?.connectionState === "connected") {
|
|
324
|
+
clearTimeout(timeout);
|
|
325
|
+
resolve();
|
|
326
|
+
} else if (this.pc?.connectionState === "failed") {
|
|
327
|
+
clearTimeout(timeout);
|
|
328
|
+
reject(new Error("WebRTC connection failed"));
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
this.pc.onconnectionstatechange = () => {
|
|
332
|
+
check();
|
|
333
|
+
const state = this.pc?.connectionState;
|
|
334
|
+
if (state === "disconnected" || state === "failed" || state === "closed") {
|
|
335
|
+
this.onClose?.();
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
check();
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
close() {
|
|
342
|
+
try {
|
|
343
|
+
this.pc?.close();
|
|
344
|
+
} catch {
|
|
345
|
+
}
|
|
346
|
+
this.pc = null;
|
|
347
|
+
}
|
|
348
|
+
waitForICE() {
|
|
349
|
+
return new Promise((resolve) => {
|
|
350
|
+
if (!this.pc) return resolve();
|
|
351
|
+
if (this.pc.iceGatheringState === "complete") return resolve();
|
|
352
|
+
const timeout = setTimeout(resolve, 2e3);
|
|
353
|
+
this.pc.onicegatheringstatechange = () => {
|
|
354
|
+
if (this.pc?.iceGatheringState === "complete") {
|
|
355
|
+
clearTimeout(timeout);
|
|
356
|
+
resolve();
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
|
|
255
363
|
// src/core/connection.ts
|
|
256
364
|
function parseSatMouseUri(uri) {
|
|
257
365
|
const url = new URL(uri);
|
|
@@ -265,7 +373,7 @@ function parseSatMouseUri(uri) {
|
|
|
265
373
|
};
|
|
266
374
|
}
|
|
267
375
|
var DEFAULT_OPTIONS = {
|
|
268
|
-
transports: ["webtransport", "websocket"],
|
|
376
|
+
transports: ["webtransport", "webrtc", "websocket"],
|
|
269
377
|
reconnectDelay: 2e3,
|
|
270
378
|
maxRetries: 3,
|
|
271
379
|
wsSubprotocol: "satmouse-json"
|
|
@@ -337,6 +445,16 @@ var SatMouseConnection = class extends TypedEmitter {
|
|
|
337
445
|
continue;
|
|
338
446
|
}
|
|
339
447
|
}
|
|
448
|
+
if (proto === "webrtc") {
|
|
449
|
+
try {
|
|
450
|
+
if (typeof globalThis.RTCPeerConnection === "undefined") continue;
|
|
451
|
+
const rtcUrl = this.options.rtcUrl ?? `http://127.0.0.1:18945/rtc/offer`;
|
|
452
|
+
const adapter = new WebRTCAdapter(rtcUrl);
|
|
453
|
+
if (await this.tryTransport(adapter)) return;
|
|
454
|
+
} catch {
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
340
458
|
if (proto === "websocket" && wsUrl) {
|
|
341
459
|
try {
|
|
342
460
|
const adapter = new WebSocketAdapter(wsUrl, this.options.wsSubprotocol);
|