@kelnishi/satmouse-client 0.14.0 → 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 +121 -2
- 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 +121 -2
- 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 +121 -2
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +294 -0
- package/dist/react/index.d.ts +294 -0
- package/dist/react/index.js +121 -2
- 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"
|
|
@@ -323,7 +431,8 @@ var SatMouseConnection = class extends TypedEmitter {
|
|
|
323
431
|
}
|
|
324
432
|
if (!resolved) {
|
|
325
433
|
this.emit("error", new Error("Failed to fetch Thing Description"));
|
|
326
|
-
|
|
434
|
+
const isSecurePage = typeof globalThis.location !== "undefined" && globalThis.location.protocol === "https:";
|
|
435
|
+
wsUrl = isSecurePage ? "wss://127.0.0.1:18947/spatial" : "ws://127.0.0.1:18945/spatial";
|
|
327
436
|
}
|
|
328
437
|
}
|
|
329
438
|
for (const proto of this.options.transports) {
|
|
@@ -336,6 +445,16 @@ var SatMouseConnection = class extends TypedEmitter {
|
|
|
336
445
|
continue;
|
|
337
446
|
}
|
|
338
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
|
+
}
|
|
339
458
|
if (proto === "websocket" && wsUrl) {
|
|
340
459
|
try {
|
|
341
460
|
const adapter = new WebSocketAdapter(wsUrl, this.options.wsSubprotocol);
|