@arcware-cloud/pixelstreaming-websdk 1.3.0 → 1.3.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/index.cjs.js CHANGED
@@ -22843,7 +22843,7 @@ function UrlBuilder(input, urlFlags) {
22843
22843
  flags.split("&").forEach((val) => {
22844
22844
  const [key, value] = val.split("=");
22845
22845
  // Ensure the value is encoded
22846
- params.append(key, value);
22846
+ params.set(key, value);
22847
22847
  });
22848
22848
  }
22849
22849
  return url.toString();
@@ -23419,7 +23419,7 @@ class ArcwareConfig extends lib_pixelstreamingfrontend_ue5_5_1.Config {
23419
23419
  if (!config.initialSettings.ss)
23420
23420
  config.initialSettings.ss = exports.DefaultUrl;
23421
23421
  super(config);
23422
- this.VERSION = "1.3.0";
23422
+ this.VERSION = "1.3.2";
23423
23423
  this.settings = settings;
23424
23424
  this.session = new Session_1.Session();
23425
23425
  this._initialSettings = config.initialSettings;
@@ -23573,6 +23573,73 @@ const MicrophoneOverlay_1 = __webpack_require__(3613);
23573
23573
  const ConnectionIdentifier_1 = __webpack_require__(5999);
23574
23574
  const DiagnosticsCollector_1 = __webpack_require__(8429);
23575
23575
  class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStreaming {
23576
+ bindTransportEvents() {
23577
+ var _a, _b, _c, _d, _e, _f, _g;
23578
+ const current = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23579
+ if (!current || current === this._boundTransport)
23580
+ return;
23581
+ // Unbind from previous
23582
+ if (this._boundTransport) {
23583
+ if (this._onWsOpen)
23584
+ (_c = (_b = this._boundTransport).removeEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, "open", this._onWsOpen);
23585
+ if (this._onWsClose)
23586
+ (_e = (_d = this._boundTransport).removeEventListener) === null || _e === void 0 ? void 0 : _e.call(_d, "close", this._onWsClose);
23587
+ }
23588
+ // Define (or reuse) callbacks
23589
+ if (!this._onWsOpen) {
23590
+ this._onWsOpen = () => {
23591
+ this.flushOutbox();
23592
+ // fallback nudge for videoInitialized
23593
+ if (!this.videoInitializedSent)
23594
+ setTimeout(() => this.sendVideoInitializedOnce(), 150);
23595
+ };
23596
+ }
23597
+ if (!this._onWsClose) {
23598
+ this._onWsClose = (evt) => {
23599
+ // Bubble to your public close handler
23600
+ EventHandler_1.EventHandler.Emit(this.websocketOnCloseHandler, evt);
23601
+ };
23602
+ }
23603
+ // Bind to current
23604
+ (_f = current.addEventListener) === null || _f === void 0 ? void 0 : _f.call(current, "open", this._onWsOpen);
23605
+ (_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "close", this._onWsClose);
23606
+ this._boundTransport = current;
23607
+ }
23608
+ startTransportWatcher() {
23609
+ // Rebind if the transport object reference changes (cheap safety net)
23610
+ if (this._transportWatchTimer)
23611
+ return;
23612
+ this._transportWatchTimer = window.setInterval(() => {
23613
+ var _a;
23614
+ const cur = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23615
+ if (cur && cur !== this._boundTransport)
23616
+ this.bindTransportEvents();
23617
+ }, 3000); // light-touch; adjust if you like
23618
+ }
23619
+ stopTransportWatcher() {
23620
+ if (this._transportWatchTimer) {
23621
+ window.clearInterval(this._transportWatchTimer);
23622
+ this._transportWatchTimer = undefined;
23623
+ }
23624
+ }
23625
+ bindVideoElPlayingOnce() {
23626
+ var _a, _b, _c;
23627
+ const videoEl = (_c = (_b = (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement) === null || _c === void 0 ? void 0 : _c.call(_b);
23628
+ if (!videoEl || videoEl === this._boundVideoEl)
23629
+ return;
23630
+ // Unbind older one if replaced
23631
+ if (this._boundVideoEl && this._onVideoPlaying) {
23632
+ this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
23633
+ }
23634
+ this._onVideoPlaying = () => this.sendVideoInitializedOnce();
23635
+ videoEl.addEventListener("playing", this._onVideoPlaying, { once: true });
23636
+ this._boundVideoEl = videoEl;
23637
+ }
23638
+ get isWsOpen() {
23639
+ var _a, _b;
23640
+ const ws = (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport) === null || _b === void 0 ? void 0 : _b.webSocket;
23641
+ return !!ws && ws.readyState === WebSocket.OPEN;
23642
+ }
23576
23643
  /** Returns a list of WebSocketStates of all PixelStreaming Instances generated. */
23577
23644
  get WebsocketStates() {
23578
23645
  return ConnectionIdentifier_1.ConnectionIdentifier.Instance.GetWebSocketStates();
@@ -23588,11 +23655,18 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23588
23655
  return state !== undefined ? state : WebSocket.CLOSED;
23589
23656
  }
23590
23657
  constructor(config, overrides) {
23658
+ var _a, _b, _c;
23591
23659
  /** As soon as upstream is fixed, we got to adjust the url building process. */
23592
23660
  (0, ApplyUrlHack_1.ApplyUrlHack)();
23593
23661
  super(config, overrides);
23594
23662
  this.loveLettersQueue = [];
23595
23663
  this.isProcessingQueue = false;
23664
+ // --- reliable send / idempotence ---
23665
+ this.outbox = [];
23666
+ this.retryTimers = new Map(); // reserved if you later add ACKs
23667
+ this.videoInitializedSent = false;
23668
+ this.versionReplyInFlight = false;
23669
+ this.nextMsgId = 1;
23596
23670
  // Externalized
23597
23671
  /** On ping the session creation timestamp will be updated. */
23598
23672
  this.queueHandler = new EventHandler_1.EventHandler();
@@ -23615,6 +23689,17 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23615
23689
  // const signallingServerUrl = this.config.getTextSettingValue(TextParameters.SignallingServerUrl);
23616
23690
  // return signallingServerUrl + "?" + this.config.urlFlags;
23617
23691
  // });
23692
+ const transport = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23693
+ (_b = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _b === void 0 ? void 0 : _b.call(transport, "open", () => {
23694
+ this.flushOutbox();
23695
+ });
23696
+ (_c = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _c === void 0 ? void 0 : _c.call(transport, "close", (evt) => {
23697
+ // Bubble to your public close handler if you expose one
23698
+ if (this.websocketOnCloseHandler) {
23699
+ EventHandler_1.EventHandler.Emit(this.websocketOnCloseHandler, evt);
23700
+ }
23701
+ });
23702
+ this.setupVideoInitFallbacks();
23618
23703
  // Set override config.
23619
23704
  this.config = config;
23620
23705
  this.loveLettersList = [];
@@ -23622,6 +23707,11 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23622
23707
  this.diagnosticsCollector = new DiagnosticsCollector_1.DiagnosticsCollector({
23623
23708
  enableBandwidthProbe: false
23624
23709
  });
23710
+ // after super(...) and once webRtcController is available
23711
+ this.bindTransportEvents();
23712
+ this.startTransportWatcher();
23713
+ // ensure video 'playing' fallback is attached to the current element
23714
+ this.bindVideoElPlayingOnce();
23625
23715
  // this.loveLettersContainer = null;
23626
23716
  this.wrapWebSocketOnCloseHandler();
23627
23717
  // Bind the event listener function to the class instance
@@ -23679,10 +23769,26 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23679
23769
  * * * * * * *
23680
23770
  */
23681
23771
  /** On version requested, the version of the WebSDK would be returned. */
23682
- onVersion(message) {
23772
+ onVersion(_msg) {
23773
+ var _a, _b;
23683
23774
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
23684
- const diagnostics = yield this.diagnosticsCollector.collect();
23685
- this.send({ type: "version", version: this.config.VERSION, diagnostics });
23775
+ let diagnostics;
23776
+ try {
23777
+ diagnostics = yield this.diagnosticsCollector.collect();
23778
+ }
23779
+ catch (e) {
23780
+ (_a = lib_pixelstreamingfrontend_ue5_5_1.Logger.Warning) === null || _a === void 0 ? void 0 : _a.call(lib_pixelstreamingfrontend_ue5_5_1.Logger, `Diagnostics collection failed: ${(_b = e === null || e === void 0 ? void 0 : e.message) !== null && _b !== void 0 ? _b : e}`);
23781
+ }
23782
+ finally {
23783
+ // Build payload with required fields only; append diagnostics if available
23784
+ const payload = {
23785
+ type: "version",
23786
+ version: this.config.VERSION
23787
+ };
23788
+ if (diagnostics !== undefined)
23789
+ payload.diagnostics = diagnostics;
23790
+ this.send(payload); // uses your buffered send
23791
+ }
23686
23792
  });
23687
23793
  }
23688
23794
  /** On ping the session creation timestamp will be updated. */
@@ -23749,16 +23855,67 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23749
23855
  this.session.set(message.sessionId);
23750
23856
  EventHandler_1.EventHandler.Emit(this.sessionIdHandler, message.sessionId);
23751
23857
  }
23858
+ sendVideoInitializedOnce() {
23859
+ if (this.videoInitializedSent)
23860
+ return;
23861
+ this.videoInitializedSent = true;
23862
+ // Use withId if you plan to support idempotence on the server
23863
+ this.send(/* this.withId( */ { type: "onVideoInitialized" } /* ) */);
23864
+ if (this.videoInitializedHandler) {
23865
+ EventHandler_1.EventHandler.Emit(this.videoInitializedHandler, undefined);
23866
+ }
23867
+ }
23868
+ // Attach fallbacks once (call this in constructor after transport wiring)
23869
+ setupVideoInitFallbacks() {
23870
+ var _a, _b, _c, _d, _e, _f, _g;
23871
+ // Fallback #1: HTMLVideoElement 'playing'
23872
+ const videoEl = (_c = (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement) === null || _c === void 0 ? void 0 : _c.call(_b);
23873
+ (_d = videoEl === null || videoEl === void 0 ? void 0 : videoEl.addEventListener) === null || _d === void 0 ? void 0 : _d.call(videoEl, "playing", () => this.sendVideoInitializedOnce(), { once: true });
23874
+ // Fallback #2: stats hook (if you emit one)
23875
+ (_e = this.addEventListener) === null || _e === void 0 ? void 0 : _e.call(this, "statsReceived", (e) => {
23876
+ var _a, _b;
23877
+ const stats = e === null || e === void 0 ? void 0 : e.detail;
23878
+ if (!this.videoInitializedSent && ((_b = (_a = stats === null || stats === void 0 ? void 0 : stats.video) === null || _a === void 0 ? void 0 : _a.framesDecoded) !== null && _b !== void 0 ? _b : 0) > 0) {
23879
+ this.sendVideoInitializedOnce();
23880
+ }
23881
+ });
23882
+ // Fallback #3: after socket opens, give it a tick
23883
+ const transport = (_f = this.webRtcController) === null || _f === void 0 ? void 0 : _f.transport;
23884
+ (_g = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _g === void 0 ? void 0 : _g.call(transport, "open", () => {
23885
+ if (!this.videoInitializedSent) {
23886
+ setTimeout(() => this.sendVideoInitializedOnce(), 150);
23887
+ }
23888
+ });
23889
+ }
23752
23890
  onVideoInitialized() {
23753
- /** The videoInitialized event is important for the Arcware Cloud Backend, since without that event the instance will be cleaned up (killed). */
23754
- this.handleMouseLock();
23755
- this.send({ type: "onVideoInitialized" });
23756
- EventHandler_1.EventHandler.Emit(this.videoInitializedHandler, undefined);
23757
- this.handleResolutionChange();
23758
- this.handleRemoveLoveLetters();
23759
- this.microphoneOverlay.toggleVisibility(false);
23760
- this.applyResolutionIfPlaying();
23761
- this.removeXRIconIfDisabled();
23891
+ var _a, _b, _c, _d, _e, _f, _g;
23892
+ // send early and once
23893
+ this.sendVideoInitializedOnce();
23894
+ // keep side-effects guarded so they can't break the send
23895
+ try {
23896
+ (_a = this.handleMouseLock) === null || _a === void 0 ? void 0 : _a.call(this);
23897
+ }
23898
+ catch (_h) { }
23899
+ try {
23900
+ (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23901
+ }
23902
+ catch (_j) { }
23903
+ try {
23904
+ (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23905
+ }
23906
+ catch (_k) { }
23907
+ try {
23908
+ (_e = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _e === void 0 ? void 0 : _e.call(_d, false);
23909
+ }
23910
+ catch (_l) { }
23911
+ try {
23912
+ (_f = this.applyResolutionIfPlaying) === null || _f === void 0 ? void 0 : _f.call(this);
23913
+ }
23914
+ catch (_m) { }
23915
+ try {
23916
+ (_g = this.removeXRIconIfDisabled) === null || _g === void 0 ? void 0 : _g.call(this);
23917
+ }
23918
+ catch (_o) { }
23762
23919
  }
23763
23920
  /** Adding a zod-safe handler. */
23764
23921
  addMessageHandler(type, zod, boundMethod) {
@@ -23773,7 +23930,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23773
23930
  lib_pixelstreamingfrontend_ue5_5_1.Logger.Error(error.message);
23774
23931
  }
23775
23932
  if (type === "error") {
23776
- this.disconnect();
23933
+ //this.disconnect();
23777
23934
  }
23778
23935
  });
23779
23936
  }
@@ -23787,19 +23944,48 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23787
23944
  // This cast has to be done, since Frontend does not use typescript-strict setting.
23788
23945
  this.send(message);
23789
23946
  }
23790
- send(message) {
23791
- if (shared_pixelstreaming_websdk_1.Messages.Send[message.type]) {
23792
- const result = shared_pixelstreaming_websdk_1.Messages.Send[message.type].safeParse(message);
23793
- if (result.success)
23794
- this.signallingProtocol.sendMessage(result.data);
23795
- else {
23796
- // This cast has to be done, since Frontend does not use typescript-strict setting.
23797
- const parsedError = result;
23798
- lib_pixelstreamingfrontend_ue5_5_1.Logger.Error(`Failed to send. ${parsedError.error}`);
23947
+ send(a, b) {
23948
+ var _a, _b;
23949
+ const msg = typeof a === "string" ? Object.assign({ type: a }, (b !== null && b !== void 0 ? b : {})) : a;
23950
+ // Optional zod validation if you have schemas for this type
23951
+ const schema = (_a = shared_pixelstreaming_websdk_1.Messages.Send) === null || _a === void 0 ? void 0 : _a[msg.type];
23952
+ if (schema) {
23953
+ const result = schema.safeParse(msg);
23954
+ if (!result.success) {
23955
+ (_b = lib_pixelstreamingfrontend_ue5_5_1.Logger.Error) === null || _b === void 0 ? void 0 : _b.call(lib_pixelstreamingfrontend_ue5_5_1.Logger, `Send validation failed for ${msg.type}: ${result.error}`);
23956
+ return;
23799
23957
  }
23958
+ this._dispatchOrBuffer(result.data);
23800
23959
  }
23801
23960
  else {
23802
- this.signallingProtocol.sendMessage(message);
23961
+ this._dispatchOrBuffer(msg);
23962
+ }
23963
+ }
23964
+ _dispatchOrBuffer(message) {
23965
+ if (this.isWsOpen) {
23966
+ try {
23967
+ this.signallingProtocol.sendMessage(message);
23968
+ return;
23969
+ }
23970
+ catch (_a) {
23971
+ // fallthrough to buffer
23972
+ }
23973
+ }
23974
+ this.outbox.push(message);
23975
+ }
23976
+ flushOutbox() {
23977
+ if (!this.isWsOpen || this.outbox.length === 0)
23978
+ return;
23979
+ const batch = this.outbox.splice(0, this.outbox.length);
23980
+ for (const m of batch) {
23981
+ try {
23982
+ this.signallingProtocol.sendMessage(m);
23983
+ }
23984
+ catch (_a) {
23985
+ // if we fail mid-flush, put remaining back and bail
23986
+ this.outbox.unshift(m, ...batch.slice(batch.indexOf(m) + 1));
23987
+ break;
23988
+ }
23803
23989
  }
23804
23990
  }
23805
23991
  handleResolutionChange() {
@@ -23863,7 +24049,18 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23863
24049
  }
23864
24050
  }
23865
24051
  removePlayer() {
23866
- //this.signallingProtocol.disconnect();
24052
+ var _a, _b, _c, _d;
24053
+ this.stopTransportWatcher();
24054
+ // Optional: unbind handlers
24055
+ if (this._boundTransport) {
24056
+ if (this._onWsOpen)
24057
+ (_b = (_a = this._boundTransport).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, "open", this._onWsOpen);
24058
+ if (this._onWsClose)
24059
+ (_d = (_c = this._boundTransport).removeEventListener) === null || _d === void 0 ? void 0 : _d.call(_c, "close", this._onWsClose);
24060
+ }
24061
+ if (this._boundVideoEl && this._onVideoPlaying) {
24062
+ this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
24063
+ }
23867
24064
  this.disconnect();
23868
24065
  }
23869
24066
  handleMouseLock() {
@@ -23961,11 +24158,11 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23961
24158
  (_a = this === null || this === void 0 ? void 0 : this.config) === null || _a === void 0 ? void 0 : _a.setFlagEnabled(lib_pixelstreamingfrontend_ue5_5_1.Flags.UseMic, enable);
23962
24159
  if (!isDefault) {
23963
24160
  (_b = this === null || this === void 0 ? void 0 : this.microphoneOverlay) === null || _b === void 0 ? void 0 : _b.toggleMessage(enable);
24161
+ setTimeout(() => { var _a; return (_a = this === null || this === void 0 ? void 0 : this.microphoneOverlay) === null || _a === void 0 ? void 0 : _a.toggleVisibility(true); }, 200);
23964
24162
  setTimeout(() => {
23965
- var _a;
23966
- (_a = this === null || this === void 0 ? void 0 : this.microphoneOverlay) === null || _a === void 0 ? void 0 : _a.toggleVisibility(true);
23967
- }, 200);
23968
- setTimeout(() => {
24163
+ this.videoInitializedSent = false; // <-- reset before a real media restart
24164
+ this.bindVideoElPlayingOnce(); // in case a new element will appear
24165
+ this.bindTransportEvents(); // cheap rebind now
23969
24166
  this.reconnect();
23970
24167
  }, 1000);
23971
24168
  }
package/index.esm.js CHANGED
@@ -22831,7 +22831,7 @@ function UrlBuilder(input, urlFlags) {
22831
22831
  flags.split("&").forEach((val) => {
22832
22832
  const [key, value] = val.split("=");
22833
22833
  // Ensure the value is encoded
22834
- params.append(key, value);
22834
+ params.set(key, value);
22835
22835
  });
22836
22836
  }
22837
22837
  return url.toString();
@@ -23427,7 +23427,7 @@ class ArcwareConfig extends _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBP
23427
23427
  if (!config.initialSettings.ss)
23428
23428
  config.initialSettings.ss = DefaultUrl;
23429
23429
  super(config);
23430
- this.VERSION = "1.3.0";
23430
+ this.VERSION = "1.3.2";
23431
23431
  this.settings = settings;
23432
23432
  this.session = new _domain_Session__WEBPACK_IMPORTED_MODULE_0__.Session();
23433
23433
  this._initialSettings = config.initialSettings;
@@ -23576,8 +23576,8 @@ __webpack_require__.r(__webpack_exports__);
23576
23576
  /* harmony import */ var _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(516);
23577
23577
  /* harmony import */ var _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(7800);
23578
23578
  /* harmony import */ var _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(7463);
23579
- /* harmony import */ var _ApplyUrlHack__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(4790);
23580
- /* harmony import */ var _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(3379);
23579
+ /* harmony import */ var _ApplyUrlHack__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(4790);
23580
+ /* harmony import */ var _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(3379);
23581
23581
  /* harmony import */ var _domain_Stats__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9764);
23582
23582
  /* harmony import */ var _domain_debounce__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(9580);
23583
23583
  /* harmony import */ var _ui_LoveLetters__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(4572);
@@ -23598,6 +23598,73 @@ __webpack_require__.r(__webpack_exports__);
23598
23598
 
23599
23599
 
23600
23600
  class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_4__.PixelStreaming {
23601
+ bindTransportEvents() {
23602
+ var _a, _b, _c, _d, _e, _f, _g;
23603
+ const current = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23604
+ if (!current || current === this._boundTransport)
23605
+ return;
23606
+ // Unbind from previous
23607
+ if (this._boundTransport) {
23608
+ if (this._onWsOpen)
23609
+ (_c = (_b = this._boundTransport).removeEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, "open", this._onWsOpen);
23610
+ if (this._onWsClose)
23611
+ (_e = (_d = this._boundTransport).removeEventListener) === null || _e === void 0 ? void 0 : _e.call(_d, "close", this._onWsClose);
23612
+ }
23613
+ // Define (or reuse) callbacks
23614
+ if (!this._onWsOpen) {
23615
+ this._onWsOpen = () => {
23616
+ this.flushOutbox();
23617
+ // fallback nudge for videoInitialized
23618
+ if (!this.videoInitializedSent)
23619
+ setTimeout(() => this.sendVideoInitializedOnce(), 150);
23620
+ };
23621
+ }
23622
+ if (!this._onWsClose) {
23623
+ this._onWsClose = (evt) => {
23624
+ // Bubble to your public close handler
23625
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(this.websocketOnCloseHandler, evt);
23626
+ };
23627
+ }
23628
+ // Bind to current
23629
+ (_f = current.addEventListener) === null || _f === void 0 ? void 0 : _f.call(current, "open", this._onWsOpen);
23630
+ (_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "close", this._onWsClose);
23631
+ this._boundTransport = current;
23632
+ }
23633
+ startTransportWatcher() {
23634
+ // Rebind if the transport object reference changes (cheap safety net)
23635
+ if (this._transportWatchTimer)
23636
+ return;
23637
+ this._transportWatchTimer = window.setInterval(() => {
23638
+ var _a;
23639
+ const cur = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23640
+ if (cur && cur !== this._boundTransport)
23641
+ this.bindTransportEvents();
23642
+ }, 3000); // light-touch; adjust if you like
23643
+ }
23644
+ stopTransportWatcher() {
23645
+ if (this._transportWatchTimer) {
23646
+ window.clearInterval(this._transportWatchTimer);
23647
+ this._transportWatchTimer = undefined;
23648
+ }
23649
+ }
23650
+ bindVideoElPlayingOnce() {
23651
+ var _a, _b, _c;
23652
+ const videoEl = (_c = (_b = (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement) === null || _c === void 0 ? void 0 : _c.call(_b);
23653
+ if (!videoEl || videoEl === this._boundVideoEl)
23654
+ return;
23655
+ // Unbind older one if replaced
23656
+ if (this._boundVideoEl && this._onVideoPlaying) {
23657
+ this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
23658
+ }
23659
+ this._onVideoPlaying = () => this.sendVideoInitializedOnce();
23660
+ videoEl.addEventListener("playing", this._onVideoPlaying, { once: true });
23661
+ this._boundVideoEl = videoEl;
23662
+ }
23663
+ get isWsOpen() {
23664
+ var _a, _b;
23665
+ const ws = (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport) === null || _b === void 0 ? void 0 : _b.webSocket;
23666
+ return !!ws && ws.readyState === WebSocket.OPEN;
23667
+ }
23601
23668
  /** Returns a list of WebSocketStates of all PixelStreaming Instances generated. */
23602
23669
  get WebsocketStates() {
23603
23670
  return _domain_ConnectionIdentifier__WEBPACK_IMPORTED_MODULE_2__.ConnectionIdentifier.Instance.GetWebSocketStates();
@@ -23613,25 +23680,32 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23613
23680
  return state !== undefined ? state : WebSocket.CLOSED;
23614
23681
  }
23615
23682
  constructor(config, overrides) {
23683
+ var _a, _b, _c;
23616
23684
  /** As soon as upstream is fixed, we got to adjust the url building process. */
23617
- (0,_ApplyUrlHack__WEBPACK_IMPORTED_MODULE_5__.ApplyUrlHack)();
23685
+ (0,_ApplyUrlHack__WEBPACK_IMPORTED_MODULE_6__.ApplyUrlHack)();
23618
23686
  super(config, overrides);
23619
23687
  this.loveLettersQueue = [];
23620
23688
  this.isProcessingQueue = false;
23689
+ // --- reliable send / idempotence ---
23690
+ this.outbox = [];
23691
+ this.retryTimers = new Map(); // reserved if you later add ACKs
23692
+ this.videoInitializedSent = false;
23693
+ this.versionReplyInFlight = false;
23694
+ this.nextMsgId = 1;
23621
23695
  // Externalized
23622
23696
  /** On ping the session creation timestamp will be updated. */
23623
- this.queueHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler();
23697
+ this.queueHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
23624
23698
  /** Error receiver. */
23625
- this.errorHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler();
23699
+ this.errorHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
23626
23700
  /** LoveLetter */
23627
- this.loveLetterHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler();
23701
+ this.loveLetterHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
23628
23702
  /** SessionId */
23629
- this.sessionIdHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler();
23703
+ this.sessionIdHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
23630
23704
  /** VideoInitialized */
23631
- this.videoInitializedHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler();
23705
+ this.videoInitializedHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
23632
23706
  // Internal
23633
23707
  /** WebSocket Close */
23634
- this.websocketOnCloseHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler();
23708
+ this.websocketOnCloseHandler = new _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler();
23635
23709
  /** Theoretically this call should be used to implement the signalling url, but this would not work at all, if config is setup for "AutoConnect=true"
23636
23710
  * Instead we use ApplyUrlHack();
23637
23711
  */
@@ -23640,6 +23714,17 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23640
23714
  // const signallingServerUrl = this.config.getTextSettingValue(TextParameters.SignallingServerUrl);
23641
23715
  // return signallingServerUrl + "?" + this.config.urlFlags;
23642
23716
  // });
23717
+ const transport = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23718
+ (_b = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _b === void 0 ? void 0 : _b.call(transport, "open", () => {
23719
+ this.flushOutbox();
23720
+ });
23721
+ (_c = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _c === void 0 ? void 0 : _c.call(transport, "close", (evt) => {
23722
+ // Bubble to your public close handler if you expose one
23723
+ if (this.websocketOnCloseHandler) {
23724
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(this.websocketOnCloseHandler, evt);
23725
+ }
23726
+ });
23727
+ this.setupVideoInitFallbacks();
23643
23728
  // Set override config.
23644
23729
  this.config = config;
23645
23730
  this.loveLettersList = [];
@@ -23647,6 +23732,11 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23647
23732
  this.diagnosticsCollector = new _features_DiagnosticsCollector__WEBPACK_IMPORTED_MODULE_3__.DiagnosticsCollector({
23648
23733
  enableBandwidthProbe: false
23649
23734
  });
23735
+ // after super(...) and once webRtcController is available
23736
+ this.bindTransportEvents();
23737
+ this.startTransportWatcher();
23738
+ // ensure video 'playing' fallback is attached to the current element
23739
+ this.bindVideoElPlayingOnce();
23650
23740
  // this.loveLettersContainer = null;
23651
23741
  this.wrapWebSocketOnCloseHandler();
23652
23742
  // Bind the event listener function to the class instance
@@ -23704,10 +23794,26 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23704
23794
  * * * * * * *
23705
23795
  */
23706
23796
  /** On version requested, the version of the WebSDK would be returned. */
23707
- onVersion(message) {
23797
+ onVersion(_msg) {
23798
+ var _a, _b;
23708
23799
  return (0,tslib__WEBPACK_IMPORTED_MODULE_9__.__awaiter)(this, void 0, void 0, function* () {
23709
- const diagnostics = yield this.diagnosticsCollector.collect();
23710
- this.send({ type: "version", version: this.config.VERSION, diagnostics });
23800
+ let diagnostics;
23801
+ try {
23802
+ diagnostics = yield this.diagnosticsCollector.collect();
23803
+ }
23804
+ catch (e) {
23805
+ (_a = _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__.Logger.Warning) === null || _a === void 0 ? void 0 : _a.call(_epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__.Logger, `Diagnostics collection failed: ${(_b = e === null || e === void 0 ? void 0 : e.message) !== null && _b !== void 0 ? _b : e}`);
23806
+ }
23807
+ finally {
23808
+ // Build payload with required fields only; append diagnostics if available
23809
+ const payload = {
23810
+ type: "version",
23811
+ version: this.config.VERSION
23812
+ };
23813
+ if (diagnostics !== undefined)
23814
+ payload.diagnostics = diagnostics;
23815
+ this.send(payload); // uses your buffered send
23816
+ }
23711
23817
  });
23712
23818
  }
23713
23819
  /** On ping the session creation timestamp will be updated. */
@@ -23755,35 +23861,86 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23755
23861
  }
23756
23862
  onQueue(message) {
23757
23863
  _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__.Logger.Info(`QueueInfo received.`);
23758
- _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler.Emit(this.queueHandler, message);
23864
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(this.queueHandler, message);
23759
23865
  }
23760
23866
  onError(error) {
23761
23867
  _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__.Logger.Error(error.type);
23762
- _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler.Emit(this.errorHandler, error);
23868
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(this.errorHandler, error);
23763
23869
  }
23764
23870
  onLoveLetter(loveLetter) {
23765
23871
  // Logger.Info(Logger.GetStackTrace(), loveLetter.reason);
23766
23872
  if (this.config.settings.loveLetterLogging)
23767
23873
  console.info(loveLetter.reason);
23768
- _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler.Emit(this.loveLetterHandler, loveLetter);
23874
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(this.loveLetterHandler, loveLetter);
23769
23875
  this.pushLetter(loveLetter.reason);
23770
23876
  }
23771
23877
  onSessionId(message) {
23772
23878
  _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__.Logger.Info(message.sessionId);
23773
23879
  // console.info(`Session: ${message.sessionId}`);
23774
23880
  this.session.set(message.sessionId);
23775
- _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler.Emit(this.sessionIdHandler, message.sessionId);
23881
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(this.sessionIdHandler, message.sessionId);
23882
+ }
23883
+ sendVideoInitializedOnce() {
23884
+ if (this.videoInitializedSent)
23885
+ return;
23886
+ this.videoInitializedSent = true;
23887
+ // Use withId if you plan to support idempotence on the server
23888
+ this.send(/* this.withId( */ { type: "onVideoInitialized" } /* ) */);
23889
+ if (this.videoInitializedHandler) {
23890
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(this.videoInitializedHandler, undefined);
23891
+ }
23892
+ }
23893
+ // Attach fallbacks once (call this in constructor after transport wiring)
23894
+ setupVideoInitFallbacks() {
23895
+ var _a, _b, _c, _d, _e, _f, _g;
23896
+ // Fallback #1: HTMLVideoElement 'playing'
23897
+ const videoEl = (_c = (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement) === null || _c === void 0 ? void 0 : _c.call(_b);
23898
+ (_d = videoEl === null || videoEl === void 0 ? void 0 : videoEl.addEventListener) === null || _d === void 0 ? void 0 : _d.call(videoEl, "playing", () => this.sendVideoInitializedOnce(), { once: true });
23899
+ // Fallback #2: stats hook (if you emit one)
23900
+ (_e = this.addEventListener) === null || _e === void 0 ? void 0 : _e.call(this, "statsReceived", (e) => {
23901
+ var _a, _b;
23902
+ const stats = e === null || e === void 0 ? void 0 : e.detail;
23903
+ if (!this.videoInitializedSent && ((_b = (_a = stats === null || stats === void 0 ? void 0 : stats.video) === null || _a === void 0 ? void 0 : _a.framesDecoded) !== null && _b !== void 0 ? _b : 0) > 0) {
23904
+ this.sendVideoInitializedOnce();
23905
+ }
23906
+ });
23907
+ // Fallback #3: after socket opens, give it a tick
23908
+ const transport = (_f = this.webRtcController) === null || _f === void 0 ? void 0 : _f.transport;
23909
+ (_g = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _g === void 0 ? void 0 : _g.call(transport, "open", () => {
23910
+ if (!this.videoInitializedSent) {
23911
+ setTimeout(() => this.sendVideoInitializedOnce(), 150);
23912
+ }
23913
+ });
23776
23914
  }
23777
23915
  onVideoInitialized() {
23778
- /** The videoInitialized event is important for the Arcware Cloud Backend, since without that event the instance will be cleaned up (killed). */
23779
- this.handleMouseLock();
23780
- this.send({ type: "onVideoInitialized" });
23781
- _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler.Emit(this.videoInitializedHandler, undefined);
23782
- this.handleResolutionChange();
23783
- this.handleRemoveLoveLetters();
23784
- this.microphoneOverlay.toggleVisibility(false);
23785
- this.applyResolutionIfPlaying();
23786
- this.removeXRIconIfDisabled();
23916
+ var _a, _b, _c, _d, _e, _f, _g;
23917
+ // send early and once
23918
+ this.sendVideoInitializedOnce();
23919
+ // keep side-effects guarded so they can't break the send
23920
+ try {
23921
+ (_a = this.handleMouseLock) === null || _a === void 0 ? void 0 : _a.call(this);
23922
+ }
23923
+ catch (_h) { }
23924
+ try {
23925
+ (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23926
+ }
23927
+ catch (_j) { }
23928
+ try {
23929
+ (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23930
+ }
23931
+ catch (_k) { }
23932
+ try {
23933
+ (_e = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _e === void 0 ? void 0 : _e.call(_d, false);
23934
+ }
23935
+ catch (_l) { }
23936
+ try {
23937
+ (_f = this.applyResolutionIfPlaying) === null || _f === void 0 ? void 0 : _f.call(this);
23938
+ }
23939
+ catch (_m) { }
23940
+ try {
23941
+ (_g = this.removeXRIconIfDisabled) === null || _g === void 0 ? void 0 : _g.call(this);
23942
+ }
23943
+ catch (_o) { }
23787
23944
  }
23788
23945
  /** Adding a zod-safe handler. */
23789
23946
  addMessageHandler(type, zod, boundMethod) {
@@ -23798,7 +23955,7 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23798
23955
  _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__.Logger.Error(error.message);
23799
23956
  }
23800
23957
  if (type === "error") {
23801
- this.disconnect();
23958
+ //this.disconnect();
23802
23959
  }
23803
23960
  });
23804
23961
  }
@@ -23812,19 +23969,48 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23812
23969
  // This cast has to be done, since Frontend does not use typescript-strict setting.
23813
23970
  this.send(message);
23814
23971
  }
23815
- send(message) {
23816
- if (_arcware_cloud_shared_pixelstreaming_websdk__WEBPACK_IMPORTED_MODULE_0__.Messages.Send[message.type]) {
23817
- const result = _arcware_cloud_shared_pixelstreaming_websdk__WEBPACK_IMPORTED_MODULE_0__.Messages.Send[message.type].safeParse(message);
23818
- if (result.success)
23819
- this.signallingProtocol.sendMessage(result.data);
23820
- else {
23821
- // This cast has to be done, since Frontend does not use typescript-strict setting.
23822
- const parsedError = result;
23823
- _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__.Logger.Error(`Failed to send. ${parsedError.error}`);
23972
+ send(a, b) {
23973
+ var _a, _b;
23974
+ const msg = typeof a === "string" ? Object.assign({ type: a }, (b !== null && b !== void 0 ? b : {})) : a;
23975
+ // Optional zod validation if you have schemas for this type
23976
+ const schema = (_a = _arcware_cloud_shared_pixelstreaming_websdk__WEBPACK_IMPORTED_MODULE_0__.Messages.Send) === null || _a === void 0 ? void 0 : _a[msg.type];
23977
+ if (schema) {
23978
+ const result = schema.safeParse(msg);
23979
+ if (!result.success) {
23980
+ (_b = _epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__.Logger.Error) === null || _b === void 0 ? void 0 : _b.call(_epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_10__.Logger, `Send validation failed for ${msg.type}: ${result.error}`);
23981
+ return;
23824
23982
  }
23983
+ this._dispatchOrBuffer(result.data);
23825
23984
  }
23826
23985
  else {
23827
- this.signallingProtocol.sendMessage(message);
23986
+ this._dispatchOrBuffer(msg);
23987
+ }
23988
+ }
23989
+ _dispatchOrBuffer(message) {
23990
+ if (this.isWsOpen) {
23991
+ try {
23992
+ this.signallingProtocol.sendMessage(message);
23993
+ return;
23994
+ }
23995
+ catch (_a) {
23996
+ // fallthrough to buffer
23997
+ }
23998
+ }
23999
+ this.outbox.push(message);
24000
+ }
24001
+ flushOutbox() {
24002
+ if (!this.isWsOpen || this.outbox.length === 0)
24003
+ return;
24004
+ const batch = this.outbox.splice(0, this.outbox.length);
24005
+ for (const m of batch) {
24006
+ try {
24007
+ this.signallingProtocol.sendMessage(m);
24008
+ }
24009
+ catch (_a) {
24010
+ // if we fail mid-flush, put remaining back and bail
24011
+ this.outbox.unshift(m, ...batch.slice(batch.indexOf(m) + 1));
24012
+ break;
24013
+ }
23828
24014
  }
23829
24015
  }
23830
24016
  handleResolutionChange() {
@@ -23888,7 +24074,18 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23888
24074
  }
23889
24075
  }
23890
24076
  removePlayer() {
23891
- //this.signallingProtocol.disconnect();
24077
+ var _a, _b, _c, _d;
24078
+ this.stopTransportWatcher();
24079
+ // Optional: unbind handlers
24080
+ if (this._boundTransport) {
24081
+ if (this._onWsOpen)
24082
+ (_b = (_a = this._boundTransport).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, "open", this._onWsOpen);
24083
+ if (this._onWsClose)
24084
+ (_d = (_c = this._boundTransport).removeEventListener) === null || _d === void 0 ? void 0 : _d.call(_c, "close", this._onWsClose);
24085
+ }
24086
+ if (this._boundVideoEl && this._onVideoPlaying) {
24087
+ this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
24088
+ }
23892
24089
  this.disconnect();
23893
24090
  }
23894
24091
  handleMouseLock() {
@@ -23986,11 +24183,11 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23986
24183
  (_a = this === null || this === void 0 ? void 0 : this.config) === null || _a === void 0 ? void 0 : _a.setFlagEnabled(_epicgames_ps_lib_pixelstreamingfrontend_ue5_5__WEBPACK_IMPORTED_MODULE_11__.Flags.UseMic, enable);
23987
24184
  if (!isDefault) {
23988
24185
  (_b = this === null || this === void 0 ? void 0 : this.microphoneOverlay) === null || _b === void 0 ? void 0 : _b.toggleMessage(enable);
24186
+ setTimeout(() => { var _a; return (_a = this === null || this === void 0 ? void 0 : this.microphoneOverlay) === null || _a === void 0 ? void 0 : _a.toggleVisibility(true); }, 200);
23989
24187
  setTimeout(() => {
23990
- var _a;
23991
- (_a = this === null || this === void 0 ? void 0 : this.microphoneOverlay) === null || _a === void 0 ? void 0 : _a.toggleVisibility(true);
23992
- }, 200);
23993
- setTimeout(() => {
24188
+ this.videoInitializedSent = false; // <-- reset before a real media restart
24189
+ this.bindVideoElPlayingOnce(); // in case a new element will appear
24190
+ this.bindTransportEvents(); // cheap rebind now
23994
24191
  this.reconnect();
23995
24192
  }, 1000);
23996
24193
  }
@@ -23999,7 +24196,7 @@ class ArcwarePixelStreaming extends _epicgames_ps_lib_pixelstreamingfrontend_ue5
23999
24196
  var _a, _b;
24000
24197
  let self = this;
24001
24198
  (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport) === null || _b === void 0 ? void 0 : _b.addEventListener("close", (event) => {
24002
- _domain_EventHandler__WEBPACK_IMPORTED_MODULE_6__.EventHandler.Emit(self.websocketOnCloseHandler, event);
24199
+ _domain_EventHandler__WEBPACK_IMPORTED_MODULE_5__.EventHandler.Emit(self.websocketOnCloseHandler, event);
24003
24200
  });
24004
24201
  }
24005
24202
  onStreamingStateChange(callback) {
package/index.umd.js CHANGED
@@ -22853,7 +22853,7 @@ function UrlBuilder(input, urlFlags) {
22853
22853
  flags.split("&").forEach((val) => {
22854
22854
  const [key, value] = val.split("=");
22855
22855
  // Ensure the value is encoded
22856
- params.append(key, value);
22856
+ params.set(key, value);
22857
22857
  });
22858
22858
  }
22859
22859
  return url.toString();
@@ -23429,7 +23429,7 @@ class ArcwareConfig extends lib_pixelstreamingfrontend_ue5_5_1.Config {
23429
23429
  if (!config.initialSettings.ss)
23430
23430
  config.initialSettings.ss = exports.DefaultUrl;
23431
23431
  super(config);
23432
- this.VERSION = "1.3.0";
23432
+ this.VERSION = "1.3.2";
23433
23433
  this.settings = settings;
23434
23434
  this.session = new Session_1.Session();
23435
23435
  this._initialSettings = config.initialSettings;
@@ -23583,6 +23583,73 @@ const MicrophoneOverlay_1 = __webpack_require__(3613);
23583
23583
  const ConnectionIdentifier_1 = __webpack_require__(5999);
23584
23584
  const DiagnosticsCollector_1 = __webpack_require__(8429);
23585
23585
  class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStreaming {
23586
+ bindTransportEvents() {
23587
+ var _a, _b, _c, _d, _e, _f, _g;
23588
+ const current = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23589
+ if (!current || current === this._boundTransport)
23590
+ return;
23591
+ // Unbind from previous
23592
+ if (this._boundTransport) {
23593
+ if (this._onWsOpen)
23594
+ (_c = (_b = this._boundTransport).removeEventListener) === null || _c === void 0 ? void 0 : _c.call(_b, "open", this._onWsOpen);
23595
+ if (this._onWsClose)
23596
+ (_e = (_d = this._boundTransport).removeEventListener) === null || _e === void 0 ? void 0 : _e.call(_d, "close", this._onWsClose);
23597
+ }
23598
+ // Define (or reuse) callbacks
23599
+ if (!this._onWsOpen) {
23600
+ this._onWsOpen = () => {
23601
+ this.flushOutbox();
23602
+ // fallback nudge for videoInitialized
23603
+ if (!this.videoInitializedSent)
23604
+ setTimeout(() => this.sendVideoInitializedOnce(), 150);
23605
+ };
23606
+ }
23607
+ if (!this._onWsClose) {
23608
+ this._onWsClose = (evt) => {
23609
+ // Bubble to your public close handler
23610
+ EventHandler_1.EventHandler.Emit(this.websocketOnCloseHandler, evt);
23611
+ };
23612
+ }
23613
+ // Bind to current
23614
+ (_f = current.addEventListener) === null || _f === void 0 ? void 0 : _f.call(current, "open", this._onWsOpen);
23615
+ (_g = current.addEventListener) === null || _g === void 0 ? void 0 : _g.call(current, "close", this._onWsClose);
23616
+ this._boundTransport = current;
23617
+ }
23618
+ startTransportWatcher() {
23619
+ // Rebind if the transport object reference changes (cheap safety net)
23620
+ if (this._transportWatchTimer)
23621
+ return;
23622
+ this._transportWatchTimer = window.setInterval(() => {
23623
+ var _a;
23624
+ const cur = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23625
+ if (cur && cur !== this._boundTransport)
23626
+ this.bindTransportEvents();
23627
+ }, 3000); // light-touch; adjust if you like
23628
+ }
23629
+ stopTransportWatcher() {
23630
+ if (this._transportWatchTimer) {
23631
+ window.clearInterval(this._transportWatchTimer);
23632
+ this._transportWatchTimer = undefined;
23633
+ }
23634
+ }
23635
+ bindVideoElPlayingOnce() {
23636
+ var _a, _b, _c;
23637
+ const videoEl = (_c = (_b = (_a = this === null || this === void 0 ? void 0 : this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement) === null || _c === void 0 ? void 0 : _c.call(_b);
23638
+ if (!videoEl || videoEl === this._boundVideoEl)
23639
+ return;
23640
+ // Unbind older one if replaced
23641
+ if (this._boundVideoEl && this._onVideoPlaying) {
23642
+ this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
23643
+ }
23644
+ this._onVideoPlaying = () => this.sendVideoInitializedOnce();
23645
+ videoEl.addEventListener("playing", this._onVideoPlaying, { once: true });
23646
+ this._boundVideoEl = videoEl;
23647
+ }
23648
+ get isWsOpen() {
23649
+ var _a, _b;
23650
+ const ws = (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport) === null || _b === void 0 ? void 0 : _b.webSocket;
23651
+ return !!ws && ws.readyState === WebSocket.OPEN;
23652
+ }
23586
23653
  /** Returns a list of WebSocketStates of all PixelStreaming Instances generated. */
23587
23654
  get WebsocketStates() {
23588
23655
  return ConnectionIdentifier_1.ConnectionIdentifier.Instance.GetWebSocketStates();
@@ -23598,11 +23665,18 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23598
23665
  return state !== undefined ? state : WebSocket.CLOSED;
23599
23666
  }
23600
23667
  constructor(config, overrides) {
23668
+ var _a, _b, _c;
23601
23669
  /** As soon as upstream is fixed, we got to adjust the url building process. */
23602
23670
  (0, ApplyUrlHack_1.ApplyUrlHack)();
23603
23671
  super(config, overrides);
23604
23672
  this.loveLettersQueue = [];
23605
23673
  this.isProcessingQueue = false;
23674
+ // --- reliable send / idempotence ---
23675
+ this.outbox = [];
23676
+ this.retryTimers = new Map(); // reserved if you later add ACKs
23677
+ this.videoInitializedSent = false;
23678
+ this.versionReplyInFlight = false;
23679
+ this.nextMsgId = 1;
23606
23680
  // Externalized
23607
23681
  /** On ping the session creation timestamp will be updated. */
23608
23682
  this.queueHandler = new EventHandler_1.EventHandler();
@@ -23625,6 +23699,17 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23625
23699
  // const signallingServerUrl = this.config.getTextSettingValue(TextParameters.SignallingServerUrl);
23626
23700
  // return signallingServerUrl + "?" + this.config.urlFlags;
23627
23701
  // });
23702
+ const transport = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.transport;
23703
+ (_b = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _b === void 0 ? void 0 : _b.call(transport, "open", () => {
23704
+ this.flushOutbox();
23705
+ });
23706
+ (_c = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _c === void 0 ? void 0 : _c.call(transport, "close", (evt) => {
23707
+ // Bubble to your public close handler if you expose one
23708
+ if (this.websocketOnCloseHandler) {
23709
+ EventHandler_1.EventHandler.Emit(this.websocketOnCloseHandler, evt);
23710
+ }
23711
+ });
23712
+ this.setupVideoInitFallbacks();
23628
23713
  // Set override config.
23629
23714
  this.config = config;
23630
23715
  this.loveLettersList = [];
@@ -23632,6 +23717,11 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23632
23717
  this.diagnosticsCollector = new DiagnosticsCollector_1.DiagnosticsCollector({
23633
23718
  enableBandwidthProbe: false
23634
23719
  });
23720
+ // after super(...) and once webRtcController is available
23721
+ this.bindTransportEvents();
23722
+ this.startTransportWatcher();
23723
+ // ensure video 'playing' fallback is attached to the current element
23724
+ this.bindVideoElPlayingOnce();
23635
23725
  // this.loveLettersContainer = null;
23636
23726
  this.wrapWebSocketOnCloseHandler();
23637
23727
  // Bind the event listener function to the class instance
@@ -23689,10 +23779,26 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23689
23779
  * * * * * * *
23690
23780
  */
23691
23781
  /** On version requested, the version of the WebSDK would be returned. */
23692
- onVersion(message) {
23782
+ onVersion(_msg) {
23783
+ var _a, _b;
23693
23784
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
23694
- const diagnostics = yield this.diagnosticsCollector.collect();
23695
- this.send({ type: "version", version: this.config.VERSION, diagnostics });
23785
+ let diagnostics;
23786
+ try {
23787
+ diagnostics = yield this.diagnosticsCollector.collect();
23788
+ }
23789
+ catch (e) {
23790
+ (_a = lib_pixelstreamingfrontend_ue5_5_1.Logger.Warning) === null || _a === void 0 ? void 0 : _a.call(lib_pixelstreamingfrontend_ue5_5_1.Logger, `Diagnostics collection failed: ${(_b = e === null || e === void 0 ? void 0 : e.message) !== null && _b !== void 0 ? _b : e}`);
23791
+ }
23792
+ finally {
23793
+ // Build payload with required fields only; append diagnostics if available
23794
+ const payload = {
23795
+ type: "version",
23796
+ version: this.config.VERSION
23797
+ };
23798
+ if (diagnostics !== undefined)
23799
+ payload.diagnostics = diagnostics;
23800
+ this.send(payload); // uses your buffered send
23801
+ }
23696
23802
  });
23697
23803
  }
23698
23804
  /** On ping the session creation timestamp will be updated. */
@@ -23759,16 +23865,67 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23759
23865
  this.session.set(message.sessionId);
23760
23866
  EventHandler_1.EventHandler.Emit(this.sessionIdHandler, message.sessionId);
23761
23867
  }
23868
+ sendVideoInitializedOnce() {
23869
+ if (this.videoInitializedSent)
23870
+ return;
23871
+ this.videoInitializedSent = true;
23872
+ // Use withId if you plan to support idempotence on the server
23873
+ this.send(/* this.withId( */ { type: "onVideoInitialized" } /* ) */);
23874
+ if (this.videoInitializedHandler) {
23875
+ EventHandler_1.EventHandler.Emit(this.videoInitializedHandler, undefined);
23876
+ }
23877
+ }
23878
+ // Attach fallbacks once (call this in constructor after transport wiring)
23879
+ setupVideoInitFallbacks() {
23880
+ var _a, _b, _c, _d, _e, _f, _g;
23881
+ // Fallback #1: HTMLVideoElement 'playing'
23882
+ const videoEl = (_c = (_b = (_a = this.webRtcController) === null || _a === void 0 ? void 0 : _a.videoPlayer) === null || _b === void 0 ? void 0 : _b.getVideoElement) === null || _c === void 0 ? void 0 : _c.call(_b);
23883
+ (_d = videoEl === null || videoEl === void 0 ? void 0 : videoEl.addEventListener) === null || _d === void 0 ? void 0 : _d.call(videoEl, "playing", () => this.sendVideoInitializedOnce(), { once: true });
23884
+ // Fallback #2: stats hook (if you emit one)
23885
+ (_e = this.addEventListener) === null || _e === void 0 ? void 0 : _e.call(this, "statsReceived", (e) => {
23886
+ var _a, _b;
23887
+ const stats = e === null || e === void 0 ? void 0 : e.detail;
23888
+ if (!this.videoInitializedSent && ((_b = (_a = stats === null || stats === void 0 ? void 0 : stats.video) === null || _a === void 0 ? void 0 : _a.framesDecoded) !== null && _b !== void 0 ? _b : 0) > 0) {
23889
+ this.sendVideoInitializedOnce();
23890
+ }
23891
+ });
23892
+ // Fallback #3: after socket opens, give it a tick
23893
+ const transport = (_f = this.webRtcController) === null || _f === void 0 ? void 0 : _f.transport;
23894
+ (_g = transport === null || transport === void 0 ? void 0 : transport.addEventListener) === null || _g === void 0 ? void 0 : _g.call(transport, "open", () => {
23895
+ if (!this.videoInitializedSent) {
23896
+ setTimeout(() => this.sendVideoInitializedOnce(), 150);
23897
+ }
23898
+ });
23899
+ }
23762
23900
  onVideoInitialized() {
23763
- /** The videoInitialized event is important for the Arcware Cloud Backend, since without that event the instance will be cleaned up (killed). */
23764
- this.handleMouseLock();
23765
- this.send({ type: "onVideoInitialized" });
23766
- EventHandler_1.EventHandler.Emit(this.videoInitializedHandler, undefined);
23767
- this.handleResolutionChange();
23768
- this.handleRemoveLoveLetters();
23769
- this.microphoneOverlay.toggleVisibility(false);
23770
- this.applyResolutionIfPlaying();
23771
- this.removeXRIconIfDisabled();
23901
+ var _a, _b, _c, _d, _e, _f, _g;
23902
+ // send early and once
23903
+ this.sendVideoInitializedOnce();
23904
+ // keep side-effects guarded so they can't break the send
23905
+ try {
23906
+ (_a = this.handleMouseLock) === null || _a === void 0 ? void 0 : _a.call(this);
23907
+ }
23908
+ catch (_h) { }
23909
+ try {
23910
+ (_b = this.handleResolutionChange) === null || _b === void 0 ? void 0 : _b.call(this);
23911
+ }
23912
+ catch (_j) { }
23913
+ try {
23914
+ (_c = this.handleRemoveLoveLetters) === null || _c === void 0 ? void 0 : _c.call(this);
23915
+ }
23916
+ catch (_k) { }
23917
+ try {
23918
+ (_e = (_d = this.microphoneOverlay) === null || _d === void 0 ? void 0 : _d.toggleVisibility) === null || _e === void 0 ? void 0 : _e.call(_d, false);
23919
+ }
23920
+ catch (_l) { }
23921
+ try {
23922
+ (_f = this.applyResolutionIfPlaying) === null || _f === void 0 ? void 0 : _f.call(this);
23923
+ }
23924
+ catch (_m) { }
23925
+ try {
23926
+ (_g = this.removeXRIconIfDisabled) === null || _g === void 0 ? void 0 : _g.call(this);
23927
+ }
23928
+ catch (_o) { }
23772
23929
  }
23773
23930
  /** Adding a zod-safe handler. */
23774
23931
  addMessageHandler(type, zod, boundMethod) {
@@ -23783,7 +23940,7 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23783
23940
  lib_pixelstreamingfrontend_ue5_5_1.Logger.Error(error.message);
23784
23941
  }
23785
23942
  if (type === "error") {
23786
- this.disconnect();
23943
+ //this.disconnect();
23787
23944
  }
23788
23945
  });
23789
23946
  }
@@ -23797,19 +23954,48 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23797
23954
  // This cast has to be done, since Frontend does not use typescript-strict setting.
23798
23955
  this.send(message);
23799
23956
  }
23800
- send(message) {
23801
- if (shared_pixelstreaming_websdk_1.Messages.Send[message.type]) {
23802
- const result = shared_pixelstreaming_websdk_1.Messages.Send[message.type].safeParse(message);
23803
- if (result.success)
23804
- this.signallingProtocol.sendMessage(result.data);
23805
- else {
23806
- // This cast has to be done, since Frontend does not use typescript-strict setting.
23807
- const parsedError = result;
23808
- lib_pixelstreamingfrontend_ue5_5_1.Logger.Error(`Failed to send. ${parsedError.error}`);
23957
+ send(a, b) {
23958
+ var _a, _b;
23959
+ const msg = typeof a === "string" ? Object.assign({ type: a }, (b !== null && b !== void 0 ? b : {})) : a;
23960
+ // Optional zod validation if you have schemas for this type
23961
+ const schema = (_a = shared_pixelstreaming_websdk_1.Messages.Send) === null || _a === void 0 ? void 0 : _a[msg.type];
23962
+ if (schema) {
23963
+ const result = schema.safeParse(msg);
23964
+ if (!result.success) {
23965
+ (_b = lib_pixelstreamingfrontend_ue5_5_1.Logger.Error) === null || _b === void 0 ? void 0 : _b.call(lib_pixelstreamingfrontend_ue5_5_1.Logger, `Send validation failed for ${msg.type}: ${result.error}`);
23966
+ return;
23809
23967
  }
23968
+ this._dispatchOrBuffer(result.data);
23810
23969
  }
23811
23970
  else {
23812
- this.signallingProtocol.sendMessage(message);
23971
+ this._dispatchOrBuffer(msg);
23972
+ }
23973
+ }
23974
+ _dispatchOrBuffer(message) {
23975
+ if (this.isWsOpen) {
23976
+ try {
23977
+ this.signallingProtocol.sendMessage(message);
23978
+ return;
23979
+ }
23980
+ catch (_a) {
23981
+ // fallthrough to buffer
23982
+ }
23983
+ }
23984
+ this.outbox.push(message);
23985
+ }
23986
+ flushOutbox() {
23987
+ if (!this.isWsOpen || this.outbox.length === 0)
23988
+ return;
23989
+ const batch = this.outbox.splice(0, this.outbox.length);
23990
+ for (const m of batch) {
23991
+ try {
23992
+ this.signallingProtocol.sendMessage(m);
23993
+ }
23994
+ catch (_a) {
23995
+ // if we fail mid-flush, put remaining back and bail
23996
+ this.outbox.unshift(m, ...batch.slice(batch.indexOf(m) + 1));
23997
+ break;
23998
+ }
23813
23999
  }
23814
24000
  }
23815
24001
  handleResolutionChange() {
@@ -23873,7 +24059,18 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23873
24059
  }
23874
24060
  }
23875
24061
  removePlayer() {
23876
- //this.signallingProtocol.disconnect();
24062
+ var _a, _b, _c, _d;
24063
+ this.stopTransportWatcher();
24064
+ // Optional: unbind handlers
24065
+ if (this._boundTransport) {
24066
+ if (this._onWsOpen)
24067
+ (_b = (_a = this._boundTransport).removeEventListener) === null || _b === void 0 ? void 0 : _b.call(_a, "open", this._onWsOpen);
24068
+ if (this._onWsClose)
24069
+ (_d = (_c = this._boundTransport).removeEventListener) === null || _d === void 0 ? void 0 : _d.call(_c, "close", this._onWsClose);
24070
+ }
24071
+ if (this._boundVideoEl && this._onVideoPlaying) {
24072
+ this._boundVideoEl.removeEventListener("playing", this._onVideoPlaying);
24073
+ }
23877
24074
  this.disconnect();
23878
24075
  }
23879
24076
  handleMouseLock() {
@@ -23971,11 +24168,11 @@ class ArcwarePixelStreaming extends lib_pixelstreamingfrontend_ue5_5_1.PixelStre
23971
24168
  (_a = this === null || this === void 0 ? void 0 : this.config) === null || _a === void 0 ? void 0 : _a.setFlagEnabled(lib_pixelstreamingfrontend_ue5_5_1.Flags.UseMic, enable);
23972
24169
  if (!isDefault) {
23973
24170
  (_b = this === null || this === void 0 ? void 0 : this.microphoneOverlay) === null || _b === void 0 ? void 0 : _b.toggleMessage(enable);
24171
+ setTimeout(() => { var _a; return (_a = this === null || this === void 0 ? void 0 : this.microphoneOverlay) === null || _a === void 0 ? void 0 : _a.toggleVisibility(true); }, 200);
23974
24172
  setTimeout(() => {
23975
- var _a;
23976
- (_a = this === null || this === void 0 ? void 0 : this.microphoneOverlay) === null || _a === void 0 ? void 0 : _a.toggleVisibility(true);
23977
- }, 200);
23978
- setTimeout(() => {
24173
+ this.videoInitializedSent = false; // <-- reset before a real media restart
24174
+ this.bindVideoElPlayingOnce(); // in case a new element will appear
24175
+ this.bindTransportEvents(); // cheap rebind now
23979
24176
  this.reconnect();
23980
24177
  }, 1000);
23981
24178
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@arcware-cloud/pixelstreaming-websdk",
3
3
  "description": "WebSDK for easy implementation of pixel streaming with Arcware Cloud Services. Heavily based on the '@epicgames-ps' library.",
4
- "version": "1.3.0",
4
+ "version": "1.3.2",
5
5
  "type": "commonjs",
6
6
  "main": "./index.umd.js",
7
7
  "module": "./index.umd.js",
@@ -26,7 +26,7 @@ export declare class ArcwareConfig extends Config {
26
26
  readonly session: Session;
27
27
  readonly settings: Settings;
28
28
  private _initialSettings;
29
- readonly VERSION = "1.3.0";
29
+ readonly VERSION = "1.3.2";
30
30
  constructor(config: ArcwareConfigParams);
31
31
  /** Setup connection string. */
32
32
  get urlFlags(): string;
@@ -5,6 +5,9 @@ import { ArcwareConfig } from "./ArcwareConfig";
5
5
  import { EventHandler } from "./domain/EventHandler";
6
6
  import { Session } from "./domain/Session";
7
7
  import { WebsocketState } from "./domain/ConnectionIdentifier";
8
+ type OutboundByKey<K extends keyof typeof Messages.Send> = z.input<(typeof Messages.Send)[K]> & {
9
+ type: K;
10
+ };
8
11
  export declare class ArcwarePixelStreaming extends PixelStreaming {
9
12
  /** Override default config with ArcwareConfig. */
10
13
  config: ArcwareConfig;
@@ -15,6 +18,22 @@ export declare class ArcwarePixelStreaming extends PixelStreaming {
15
18
  private isProcessingQueue;
16
19
  private microphoneOverlay;
17
20
  private diagnosticsCollector;
21
+ private outbox;
22
+ private retryTimers;
23
+ private videoInitializedSent;
24
+ private versionReplyInFlight;
25
+ private nextMsgId;
26
+ private _boundTransport?;
27
+ private _onWsOpen?;
28
+ private _onWsClose?;
29
+ private _transportWatchTimer?;
30
+ private _boundVideoEl?;
31
+ private _onVideoPlaying?;
32
+ private bindTransportEvents;
33
+ private startTransportWatcher;
34
+ private stopTransportWatcher;
35
+ private bindVideoElPlayingOnce;
36
+ private get isWsOpen();
18
37
  /** Returns a list of WebSocketStates of all PixelStreaming Instances generated. */
19
38
  get WebsocketStates(): WebsocketState[];
20
39
  /** Counts all active PixelStreaming Instances generated. (CONNECTING & CONNECTED) */
@@ -67,6 +86,8 @@ export declare class ArcwarePixelStreaming extends PixelStreaming {
67
86
  /** SessionId */
68
87
  readonly sessionIdHandler: EventHandler<string>;
69
88
  private onSessionId;
89
+ private sendVideoInitializedOnce;
90
+ private setupVideoInitFallbacks;
70
91
  /** VideoInitialized */
71
92
  readonly videoInitializedHandler: EventHandler<never>;
72
93
  private onVideoInitialized;
@@ -80,12 +101,13 @@ export declare class ArcwarePixelStreaming extends PixelStreaming {
80
101
  * * * * * *
81
102
  */
82
103
  private sendStats;
83
- send<T extends {
104
+ send<K extends keyof typeof Messages.Send>(message: OutboundByKey<K>): void;
105
+ send(type: string, payload?: Record<string, unknown>): void;
106
+ send(message: {
84
107
  type: string;
85
- }>(message: T): void;
86
- send<K extends keyof typeof Messages.Send>(message: {
87
- type: K;
88
- } & z.infer<(typeof Messages.Send)[K]>): void;
108
+ } & Record<string, unknown>): void;
109
+ private _dispatchOrBuffer;
110
+ private flushOutbox;
89
111
  private handleResolutionChange;
90
112
  private applyResolutionIfPlaying;
91
113
  removePlayer(): void;
@@ -102,3 +124,4 @@ export declare class ArcwarePixelStreaming extends PixelStreaming {
102
124
  private removeXRIconIfDisabled;
103
125
  private injectCustomUI;
104
126
  }
127
+ export {};