@kelnishi/satmouse-client 0.15.2 → 0.16.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.
@@ -254,133 +254,57 @@ var WebSocketAdapter = class {
254
254
  }
255
255
  };
256
256
 
257
- // src/core/transports/webrtc.ts
258
- var WebRTCAdapter = class {
259
- protocol = "webrtc";
257
+ // src/core/transports/extension.ts
258
+ var ExtensionAdapter = class {
259
+ protocol = "extension";
260
260
  onSpatialData = null;
261
261
  onButtonEvent = null;
262
262
  onDeviceStatus = null;
263
263
  onClose = null;
264
264
  onError = null;
265
- pc = null;
266
- signalingUrl;
267
- constructor(signalingUrl) {
268
- this.signalingUrl = signalingUrl;
265
+ messageHandler = null;
266
+ static isAvailable() {
267
+ return !!globalThis.__satmouseExtensionAvailable;
269
268
  }
270
269
  async connect() {
271
- if (typeof globalThis.RTCPeerConnection === "undefined") {
272
- throw new Error("RTCPeerConnection not available");
270
+ if (typeof globalThis.postMessage !== "function") {
271
+ throw new Error("postMessage not available");
273
272
  }
274
- this.pc = new RTCPeerConnection({ iceServers: [] });
275
- this.pc.ondatachannel = (event) => {
276
- const channel = event.channel;
277
- if (channel.label === "spatial") {
278
- channel.binaryType = "arraybuffer";
279
- channel.onmessage = (e) => {
280
- if (e.data instanceof ArrayBuffer && e.data.byteLength >= 20) {
281
- this.onSpatialData?.(decodeBinaryFrame(e.data));
282
- }
283
- };
284
- } else if (channel.label === "reliable") {
285
- channel.onmessage = (e) => {
286
- try {
287
- const text = typeof e.data === "string" ? e.data : new TextDecoder().decode(e.data);
288
- const msg = JSON.parse(text);
289
- if (msg.type === "buttonEvent") this.onButtonEvent?.(msg.data);
290
- else if (msg.type === "deviceStatus") this.onDeviceStatus?.(msg.data.event, msg.data.device);
291
- } catch {
292
- }
293
- };
294
- }
295
- };
296
- this.pc.onconnectionstatechange = () => {
297
- const state = this.pc?.connectionState;
298
- if (state === "disconnected" || state === "failed" || state === "closed") {
299
- this.onClose?.();
300
- }
301
- };
302
- const offer = await this.pc.createOffer();
303
- await this.pc.setLocalDescription(offer);
304
- await this.waitForICE();
305
- const answerSdp = await this.exchangeSDP(this.pc.localDescription.sdp);
306
- await this.pc.setRemoteDescription({ type: "answer", sdp: answerSdp });
307
- await new Promise((resolve, reject) => {
308
- const timeout = setTimeout(() => reject(new Error("WebRTC connection timeout")), 1e4);
309
- const check = () => {
310
- const state = this.pc?.connectionState;
311
- if (state === "connected") {
273
+ return new Promise((resolve, reject) => {
274
+ const timeout = setTimeout(() => {
275
+ this.close();
276
+ reject(new Error("Extension connection timeout"));
277
+ }, 5e3);
278
+ this.messageHandler = (event) => {
279
+ if (event.data?.source !== "satmouse-extension") return;
280
+ const msg = event.data;
281
+ if ((msg.type === "connected" || msg.type === "bridgeConnected") && timeout) {
312
282
  clearTimeout(timeout);
313
283
  resolve();
314
- } else if (state === "failed") {
315
- clearTimeout(timeout);
316
- reject(new Error("WebRTC connection failed"));
284
+ }
285
+ if (msg.type === "disconnected") {
286
+ this.onClose?.();
287
+ }
288
+ if (msg.type === "spatialData" && msg.data) {
289
+ this.onSpatialData?.(msg.data);
290
+ }
291
+ if (msg.type === "buttonEvent" && msg.data) {
292
+ this.onButtonEvent?.(msg.data);
293
+ }
294
+ if (msg.type === "deviceStatus" && msg.data) {
295
+ this.onDeviceStatus?.(msg.data.event, msg.data.device);
317
296
  }
318
297
  };
319
- this.pc.onconnectionstatechange = () => {
320
- check();
321
- const state = this.pc?.connectionState;
322
- if (state === "disconnected" || state === "failed" || state === "closed") this.onClose?.();
323
- };
324
- check();
298
+ globalThis.addEventListener("message", this.messageHandler);
299
+ globalThis.postMessage({ target: "satmouse-extension", action: "connect" }, "*");
325
300
  });
326
301
  }
327
302
  close() {
328
- try {
329
- this.pc?.close();
330
- } catch {
331
- }
332
- this.pc = null;
333
- }
334
- /** Exchange SDP: try fetch POST, fall back to popup window */
335
- async exchangeSDP(offerSdp) {
336
- try {
337
- const res = await fetch(this.signalingUrl, {
338
- method: "POST",
339
- body: offerSdp,
340
- headers: { "Content-Type": "application/sdp" }
341
- });
342
- if (res.ok) return await res.text();
343
- } catch {
303
+ if (this.messageHandler) {
304
+ globalThis.removeEventListener("message", this.messageHandler);
305
+ this.messageHandler = null;
344
306
  }
345
- return this.exchangeSDPViaPopup(offerSdp);
346
- }
347
- exchangeSDPViaPopup(offerSdp) {
348
- return new Promise((resolve, reject) => {
349
- const offerB64 = btoa(offerSdp);
350
- const baseUrl = this.signalingUrl.replace("/rtc/offer", "/rtc/connect-popup");
351
- const url = `${baseUrl}?offer=${encodeURIComponent(offerB64)}`;
352
- const popup = globalThis.open(url, "satmouse-rtc", "width=1,height=1,left=-100,top=-100");
353
- if (!popup) {
354
- reject(new Error("Popup blocked \u2014 user interaction required"));
355
- return;
356
- }
357
- const timeout = setTimeout(() => {
358
- popup.close();
359
- reject(new Error("WebRTC signaling timeout"));
360
- }, 1e4);
361
- const onMessage = (event) => {
362
- if (event.data?.type === "satmouse-rtc-answer") {
363
- clearTimeout(timeout);
364
- globalThis.removeEventListener("message", onMessage);
365
- popup.close();
366
- resolve(event.data.answer);
367
- }
368
- };
369
- globalThis.addEventListener("message", onMessage);
370
- });
371
- }
372
- waitForICE() {
373
- return new Promise((resolve) => {
374
- if (!this.pc) return resolve();
375
- if (this.pc.iceGatheringState === "complete") return resolve();
376
- const timeout = setTimeout(resolve, 2e3);
377
- this.pc.onicegatheringstatechange = () => {
378
- if (this.pc?.iceGatheringState === "complete") {
379
- clearTimeout(timeout);
380
- resolve();
381
- }
382
- };
383
- });
307
+ globalThis.postMessage({ target: "satmouse-extension", action: "disconnect" }, "*");
384
308
  }
385
309
  };
386
310
 
@@ -397,7 +321,7 @@ function parseSatMouseUri(uri) {
397
321
  };
398
322
  }
399
323
  var DEFAULT_OPTIONS = {
400
- transports: ["webtransport", "webrtc", "websocket"],
324
+ transports: ["webtransport", "extension", "websocket"],
401
325
  reconnectDelay: 2e3,
402
326
  maxRetries: 3,
403
327
  wsSubprotocol: "satmouse-json"
@@ -469,11 +393,10 @@ var SatMouseConnection = class extends TypedEmitter {
469
393
  continue;
470
394
  }
471
395
  }
472
- if (proto === "webrtc") {
396
+ if (proto === "extension") {
473
397
  try {
474
- if (typeof globalThis.RTCPeerConnection === "undefined") continue;
475
- const rtcUrl = this.options.rtcUrl ?? `http://127.0.0.1:18945/rtc/offer`;
476
- const adapter = new WebRTCAdapter(rtcUrl);
398
+ if (!ExtensionAdapter.isAvailable()) continue;
399
+ const adapter = new ExtensionAdapter();
477
400
  if (await this.tryTransport(adapter)) return;
478
401
  } catch {
479
402
  continue;