@uzuhq/code-sdk 0.9.0 → 0.9.2

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/README.md CHANGED
@@ -604,6 +604,7 @@ type Other = {
604
604
  | { status: 'here'; mic: Mic; speaking: boolean; quality: 'good' | 'poor' } // 自分と同じ部屋で聞こえている
605
605
  | { status: 'elsewhere'; room: string | null } // 別の部屋にいる
606
606
  | { status: 'lost'; since: number } // 声が届かない (通話が切れた / 同じ部屋のはずなのに聞こえなくなった)
607
+ | { status: 'left'; since: number } // 本人が退出した (一時退出を含む)。戻ってきたらほかの値に戻る
607
608
  | { status: 'unknown'; reason: 'me-not-connected' | 'no-report' }; // 自分が通話にいない / 申告が届かず聞こえてもいない
608
609
  };
609
610
 
package/dist/index.d.ts CHANGED
@@ -150,6 +150,14 @@ type Other = {
150
150
  status: 'lost';
151
151
  since: number;
152
152
  } |
153
+ /**
154
+ * 本人が退出した (一時退出を含む)。戻ってきたら、ほかの値に戻る。
155
+ * 声が届かないのはこのためなので、`lost` とは分けて出す。since は端末の時刻 (ms)。
156
+ */
157
+ {
158
+ status: 'left';
159
+ since: number;
160
+ } |
153
161
  /**
154
162
  * 自分が通話にいない / 本人の申告が届かず、自分にも聞こえていない
155
163
  * (まだ一度も入っていない人もここ)。
@@ -240,6 +248,14 @@ declare class ReconnectableWebSocket {
240
248
  private heartbeatTimeoutTimer;
241
249
  private reconnectTimer;
242
250
  private disposed;
251
+ /**
252
+ * 画面・回線が戻ったら、backoff の予約を待たずにつなぎ直す。
253
+ *
254
+ * 画面が隠れている間 (macOS の WKWebView でウィンドウが覆われた等) は JS のタイマーが
255
+ * 止められ、再接続の予約も止まる。試行回数を使い切って disconnected になった後も
256
+ * ここから戻れるよう、回数も数え直す。
257
+ */
258
+ private readonly onResume;
243
259
  constructor(url: string, options?: ReconnectableWSOptions);
244
260
  get connectionState(): ConnectionState$1;
245
261
  /** WebSocket.readyState 互換 (既存コードとの互換用) */
package/dist/index.js CHANGED
@@ -434,6 +434,11 @@ const heardOf = (value) => {
434
434
  };
435
435
  };
436
436
  const otherVoice = (seatId, seat, me, input) => {
437
+ const left = input.voice?.left?.[seatId];
438
+ if (left !== void 0) return {
439
+ status: "left",
440
+ since: numberOr(isRecord$2(left) ? left.since : void 0, Date.now())
441
+ };
437
442
  const voice = isRecord$2(seat) && isRecord$2(seat.voice) ? seat.voice : {};
438
443
  const status = typeof voice.status === "string" ? voice.status : "unknown";
439
444
  if (status === "lost") return {
@@ -545,7 +550,7 @@ const SESSIONS = [
545
550
  * 捨てると聞こえている相手 (heard) まで止まってしまう。
546
551
  */
547
552
  const parseVoiceChanged = (payload) => {
548
- const { self, heard, missing } = payload;
553
+ const { self, heard, missing, left } = payload;
549
554
  if (!isRecord$2(self) || typeof self.session !== "string") return null;
550
555
  const session = SESSIONS.includes(self.session) ? self.session : "connecting";
551
556
  const room = typeof self.room === "string" ? self.room : null;
@@ -560,7 +565,8 @@ const parseVoiceChanged = (payload) => {
560
565
  quality: self.quality === "poor" ? "poor" : "good"
561
566
  },
562
567
  heard: isRecord$2(heard) ? heard : {},
563
- missing: isRecord$2(missing) ? missing : {}
568
+ missing: isRecord$2(missing) ? missing : {},
569
+ left: isRecord$2(left) ? left : {}
564
570
  };
565
571
  };
566
572
  const initialInput = () => ({
@@ -758,6 +764,20 @@ var ReconnectableWebSocket = class {
758
764
  this.heartbeatTimeoutTimer = null;
759
765
  this.reconnectTimer = null;
760
766
  this.disposed = false;
767
+ this.onResume = () => {
768
+ if (this.disposed || document.visibilityState === "hidden") return;
769
+ const readyState = this.ws?.readyState;
770
+ if (readyState === WebSocket.CONNECTING || readyState === WebSocket.OPEN) return;
771
+ console.log(`[ReconnectableWS] ⏰ Resumed: reconnecting now (state=${this._state})`);
772
+ this.stopHeartbeat();
773
+ if (this.reconnectTimer) {
774
+ clearTimeout(this.reconnectTimer);
775
+ this.reconnectTimer = null;
776
+ }
777
+ this.reconnectAttempt = 0;
778
+ this.setState("reconnecting");
779
+ this.connect();
780
+ };
761
781
  this.url = url;
762
782
  this.opts = {
763
783
  maxReconnectAttempts: options.maxReconnectAttempts ?? DEFAULTS.maxReconnectAttempts,
@@ -770,6 +790,11 @@ var ReconnectableWebSocket = class {
770
790
  shouldBuffer: options.shouldBuffer,
771
791
  onConnectionStateChange: options.onConnectionStateChange
772
792
  };
793
+ if (typeof window !== "undefined") {
794
+ window.addEventListener("online", this.onResume);
795
+ window.addEventListener("focus", this.onResume);
796
+ document.addEventListener("visibilitychange", this.onResume);
797
+ }
773
798
  this.connect();
774
799
  }
775
800
  get connectionState() {
@@ -800,6 +825,11 @@ var ReconnectableWebSocket = class {
800
825
  /** 全リソース解放 */
801
826
  dispose() {
802
827
  this.disposed = true;
828
+ if (typeof window !== "undefined") {
829
+ window.removeEventListener("online", this.onResume);
830
+ window.removeEventListener("focus", this.onResume);
831
+ document.removeEventListener("visibilitychange", this.onResume);
832
+ }
803
833
  this.stopHeartbeat();
804
834
  if (this.reconnectTimer) {
805
835
  clearTimeout(this.reconnectTimer);
@@ -831,7 +861,7 @@ var ReconnectableWebSocket = class {
831
861
  this.flushBuffer();
832
862
  };
833
863
  ws.onclose = (ev) => {
834
- if (this.disposed) return;
864
+ if (this.disposed || ws !== this.ws) return;
835
865
  if (ev.code === 1e3) {
836
866
  console.log(`[ReconnectableWS] 🔒 Closed cleanly (code=${ev.code})`);
837
867
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uzuhq/code-sdk",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "UZU PlayScreen SDK - Flutter ↔ JS ゲーム通信ライブラリ",
5
5
  "type": "module",
6
6
  "exports": {