@3dsource/angular-unreal-module 0.0.146-dev.8 → 0.0.148-dev.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3dsource/angular-unreal-module",
3
- "version": "0.0.146-dev.8",
3
+ "version": "0.0.148-dev.0",
4
4
  "description": "Unreal module for connect with unreal engine stream",
5
5
  "keywords": [
6
6
  "3dsource",
@@ -11,7 +11,7 @@ import { Store } from '@ngrx/store';
11
11
  import { Actions } from '@ngrx/effects';
12
12
  import { IKeyCode, ImageOutputValues, Area } from '@3dsource/utils';
13
13
  import { SafeHtml, SafeStyle, SafeScript, SafeUrl, SafeResourceUrl } from '@angular/platform-browser';
14
- import { MetaBoxCommandPacket, MetaBoxCommandList, FSceneState, FProductPayload, FCameraChangedPayload, FTransformJson } from '@3dsource/types-unreal';
14
+ import { MetaBoxCommandPacket, MetaBoxCommandList, MetaBoxCallbackList, FOnSceneStateCallback, FOnFocusObjectCallback, FCameraChangedCallback, FOnObjectTransformChangedCallback, FOnChangeSequenceChangedCallback, FOnFinishSequenceChangedCallback } from '@3dsource/types-unreal';
15
15
  import * as node_modules__ngrx_effects_types_ngrx_effects from 'node_modules/@ngrx/effects/types/ngrx-effects';
16
16
 
17
17
  declare class AfkTimeoutModalComponent {
@@ -231,6 +231,18 @@ interface FreezeFrameMessage {
231
231
  progress: number | null;
232
232
  }
233
233
 
234
+ interface ReconnectConfig {
235
+ /** Enable auto-reconnection when WebRTC or DataChannel connection is lost. Default: true */
236
+ enabled?: boolean;
237
+ /** Maximum number of reconnection attempts before giving up. Default: 3 */
238
+ maxAttempts?: number;
239
+ /** Delay in milliseconds between reconnection attempts. Default: 1000 */
240
+ delayMs?: number;
241
+ /** Reconnect on ICE connection failure (disconnected/failed state). Default: true */
242
+ onIceFailure?: boolean;
243
+ /** Reconnect on DataChannel close. Default: true */
244
+ onDataChannelClose?: boolean;
245
+ }
234
246
  interface UnrealInitialConfig {
235
247
  playwright?: boolean;
236
248
  customErrorsEndpoint?: string;
@@ -241,57 +253,8 @@ interface UnrealInitialConfig {
241
253
  streamTelemetryV2Url?: string;
242
254
  fpsMonitor?: boolean;
243
255
  autoHighResolution?: boolean;
244
- }
245
-
246
- interface SignalingData {
247
- instanceType: string;
248
- branchInfo: string;
249
- cirrusVersion: string;
250
- streamerVersion: string;
251
- streamPath: string;
252
- streamApp: string;
253
- connectionId: string;
254
- }
255
-
256
- /**
257
- * Live WebRTC connection parked on `window.__stream` by the `stream-prefetch.js`
258
- * head-script, ready for the Angular services to ADOPT instead of building a
259
- * connection from scratch. The shape is the handoff contract between that
260
- * framework-free script and {@link StreamAdoptionService} — keep the two in sync.
261
- */
262
- interface ParkedStream {
263
- state: 'connecting' | 'ready' | 'failed' | 'adopted';
264
- pc?: RTCPeerConnection;
265
- dc?: RTCDataChannel;
266
- /** video(+audio) MediaStream from the `track` event */
267
- stream?: MediaStream;
268
- /** live signalling socket (handshake already done, `requestStream` sent) */
269
- ws?: WebSocket;
270
- /** `data` from the streamer's `ssInfo` message — received before adoption */
271
- ssData?: SignalingData;
272
- /** = resolved wsUrl of the winning machine */
273
- machineId?: string;
274
- /** `peerConnectionOptions` the machine sent in its `config` message */
275
- config?: RTCConfiguration;
276
- /** ids the script generated; Angular reuses them (no regeneration) */
277
- ids: {
278
- clientId: string;
279
- viewId: string;
280
- correlationId: string;
281
- };
282
- /** DataChannel messages received before adoption, replayed on adopt */
283
- dcBuffer: ArrayBuffer[];
284
- /** `performance.now()` marks for the prefetch waterfall (telemetry) */
285
- timings: Record<string, number>;
286
- failReason?: string;
287
- failError?: string;
288
- /** Stops the script's watchdog and flips state to `adopted`. */
289
- adopt: () => ParkedStream;
290
- }
291
- declare global {
292
- interface Window {
293
- __stream?: ParkedStream;
294
- }
256
+ /** Configuration for auto-reconnection behavior */
257
+ reconnect?: ReconnectConfig;
295
258
  }
296
259
 
297
260
  declare const SpecialKeyCodes: {
@@ -383,9 +346,6 @@ declare const MIN_CONTAINER_SIZE = 2;
383
346
  declare const MINIMAL_FPS = 6;
384
347
  declare const STREAMING_VIDEO_ID = "streamingVideo";
385
348
  declare const STREAMING_AUDIO_ID = "streamingAudio";
386
- declare const CONSOLE_COMMAND_ENABLE_MESSAGES = "EnableAllScreenMessages";
387
- declare const CONSOLE_COMMAND_DISABLE_MESSAGES = "DisableAllScreenMessages";
388
- declare const CONSOLE_COMMAND_PIXEL_QUALITY = "PixelStreaming.FreezeFrameQuality 95";
389
349
  declare const FULL_HD_WIDTH = 1920;
390
350
  declare const FULL_HD_HEIGHT = 1080;
391
351
  declare const WS_TIMEOUT = 6000;
@@ -404,29 +364,16 @@ declare const REGION_PING_CACHE_TTL_MS: number;
404
364
  declare const REGION_PING_ACCURATE_SAMPLES = 3;
405
365
  declare const REGION_PING_WARMUP_DEADLINE_MS = 1500;
406
366
  declare const REGION_PING_BACKGROUND_REFRESH_DELAY_MS = 5000;
407
- declare const RECONNECT_CONFIG: {
408
- readonly enabled: true;
409
- readonly maxAttempts: 3;
410
- readonly delayMs: 1000;
411
- };
367
+ declare const DEFAULT_RECONNECT_ENABLED = true;
368
+ declare const DEFAULT_RECONNECT_MAX_ATTEMPTS = 3;
369
+ declare const DEFAULT_RECONNECT_DELAY_MS = 1000;
370
+ declare const DEFAULT_RECONNECT_ON_ICE_FAILURE = true;
371
+ declare const DEFAULT_RECONNECT_ON_DATACHANNEL_CLOSE = true;
412
372
  declare const UnrealStatusMessage: {
413
373
  readonly CONNECTING_TO_SESSION: "Connecting to session.";
414
374
  readonly STARTING_YOUR_SESSION: "Starting your session";
415
375
  };
416
376
 
417
- interface NormalizeAndQuantizeUnsignedValue {
418
- inRange: boolean;
419
- x: number;
420
- y: number;
421
- }
422
- interface UnquantizeAndDenormalizeUnsignedValue {
423
- x: number;
424
- y: number;
425
- }
426
- interface NormalizeAndQuantizeSignedValue {
427
- x: number;
428
- y: number;
429
- }
430
377
  interface InputProps {
431
378
  controlScheme: ControlSchemeValues;
432
379
  suppressBrowserKeys: boolean;
@@ -434,6 +381,16 @@ interface InputProps {
434
381
 
435
382
  type Quality = 'lime' | 'red' | 'orange';
436
383
 
384
+ interface SignalingData {
385
+ instanceType: string;
386
+ branchInfo: string;
387
+ cirrusVersion: string;
388
+ streamerVersion: string;
389
+ streamPath: string;
390
+ streamApp: string;
391
+ connectionId: string;
392
+ }
393
+
437
394
  declare const OrchestrationMessageTypes: {
438
395
  readonly ping: "ping";
439
396
  readonly error: "error";
@@ -898,7 +855,6 @@ declare class InputService extends SubService {
898
855
  private isKeyCodeBrowserKey;
899
856
  private getKeyCode;
900
857
  private registerKeyboardEvents;
901
- private isIgnoredViewportKey;
902
858
  private startListenKeys;
903
859
  static ɵfac: i0.ɵɵFactoryDeclaration<InputService, never>;
904
860
  static ɵprov: i0.ɵɵInjectableDeclaration<InputService>;
@@ -923,15 +879,8 @@ declare class RegionsPingService {
923
879
  * entry is well-formed and still within {@link REGION_PING_CACHE_TTL_MS}.
924
880
  * All access is guarded — `localStorage` can throw (private mode, disabled
925
881
  * storage) or be absent (non-browser).
926
- *
927
- * Public so adopted connections (which skip `getFastest`) can replay the
928
- * region-resolving telemetry phase from the same cached winner — see
929
- * `UnrealEffects.regionTelemetryOnAdopt$`.
930
882
  */
931
- readCachedWinner(): {
932
- region_code: string;
933
- result: number[];
934
- } | null;
883
+ private readCachedWinner;
935
884
  private writeCachedWinner;
936
885
  /**
937
886
  * Accurate, OFF-critical-path refresh of the region cache. Mirrors the
@@ -1053,15 +1002,6 @@ declare class SignallingService extends SubService {
1053
1002
  private pollLoop;
1054
1003
  private connectToCirrus;
1055
1004
  private addWsHandlers;
1056
- /**
1057
- * Adopt a live signalling socket opened by the `stream-prefetch.js`
1058
- * head-script. The socket is already OPEN and `requestStream` was already
1059
- * sent, so — unlike {@link addWsHandlers} — we attach message/close/error
1060
- * handlers but deliberately skip {@link OnOpenHandler} (which would
1061
- * `setCirrusConnected` + re-`sendRequestStream`). Reuses the head-script's
1062
- * `correlationId` so subsequent correlated messages line up.
1063
- */
1064
- adoptSocket(ws: WebSocket, correlationId: string): void;
1065
1005
  private showStatusMessage;
1066
1006
  /**
1067
1007
  * Close the connection with the signaling server
@@ -1081,52 +1021,6 @@ declare class SignallingService extends SubService {
1081
1021
  static ɵprov: i0.ɵɵInjectableDeclaration<SignallingService>;
1082
1022
  }
1083
1023
 
1084
- /**
1085
- * Adopts a WebRTC connection prefetched by the `stream-prefetch.js` head-script
1086
- * and parked on `window.__stream`, instead of running `connectToSignaling` from
1087
- * scratch. Called from the same seam where signalling normally starts
1088
- * (`connectToSignaling$` effect); if there is nothing ready to adopt it returns
1089
- * `false` and the caller falls back to the normal connect — strictly additive.
1090
- */
1091
- declare class StreamAdoptionService {
1092
- private readonly store;
1093
- private readonly signalling;
1094
- private readonly webRtc;
1095
- /**
1096
- * Decide adoption, WAITING for an in-flight prefetch instead of racing it.
1097
- *
1098
- * - nothing parked → emit `false` at once (caller connects normally).
1099
- * - already settled (`ready`/`failed`/`adopted`) → adopt-if-ready at once.
1100
- * - still `connecting` → poll until the script settles it, then adopt-if-ready.
1101
- *
1102
- * Deliberately NO time budget: for DIRECT orchestration the prefetch holds
1103
- * the socket open while the orchestrator provisions a machine, which can take
1104
- * minutes (150–200s+). A fixed deadline would make Angular give up and open a
1105
- * second connection mid-provisioning — exactly the race/orphan this avoids.
1106
- * The wait is bounded by liveness instead: the script flips the parked state
1107
- * to `failed` on a dead socket (`ws.onclose`/`onerror`), and the caller wraps
1108
- * this in `takeUntil(abortEstablishingConnection)`, so a route change / teardown
1109
- * cancels it. Emits exactly once. Cancelling runs no adoption — which is what
1110
- * stops a fast route-switch from starting overlapping connections.
1111
- *
1112
- * Wrapped in `defer` so the `tryAdopt()` side effect (which dispatches
1113
- * `streamAdopted`) runs at SUBSCRIPTION time, not when the observable is
1114
- * built. The effect prepends `startWith(setEstablishingConnection(true))`,
1115
- * which starts the telemetry session and subscribes its phase catalog; that
1116
- * must happen BEFORE `streamAdopted` → `regionTelemetryOnAdopt$` replays
1117
- * `regionResolved`, or the region phase fires into a session that doesn't
1118
- * exist yet and is lost. `defer` guarantees that ordering.
1119
- */
1120
- awaitAndAdopt$(): Observable<boolean>;
1121
- /**
1122
- * @returns `true` if a ready parked stream was adopted (caller must NOT
1123
- * start a fresh connection), `false` otherwise.
1124
- */
1125
- tryAdopt(): boolean;
1126
- static ɵfac: i0.ɵɵFactoryDeclaration<StreamAdoptionService, never>;
1127
- static ɵprov: i0.ɵɵInjectableDeclaration<StreamAdoptionService>;
1128
- }
1129
-
1130
1024
  declare class StreamStatusTelemetryService extends SubService {
1131
1025
  private readonly videoService;
1132
1026
  private readonly unrealConfig;
@@ -1214,17 +1108,6 @@ declare class StreamStatusTelemetryService2 {
1214
1108
  private readonly disconnectReason$;
1215
1109
  private readonly errorMessage$;
1216
1110
  private readonly viewPortReady$;
1217
- /**
1218
- * Synchronous adoption flag. The `streamAdopted` reducer sets it BEFORE any
1219
- * action subscriber runs, so the connection-phase closers (which fire inside
1220
- * the same dispatch, e.g. `ssinfo-received` off the `ssData` state change)
1221
- * can read it and defer to the prefetch-timed attribution emitted by
1222
- * {@link emitAdoptedConnection} instead of recording the live wall-clock.
1223
- */
1224
- private readonly adopted$;
1225
- /** Streamer identity for the adopted signaling phase params. */
1226
- private readonly ssData$;
1227
- private readonly awsInstance$;
1228
1111
  private session;
1229
1112
  /**
1230
1113
  * Whether a session has already started during the current page lifetime.
@@ -1288,36 +1171,6 @@ declare class StreamStatusTelemetryService2 {
1288
1171
  * are derived from neighbor phases.
1289
1172
  */
1290
1173
  private emitPhaseEnded;
1291
- /**
1292
- * Emit the region / signaling / webrtc phases for an ADOPTED connection.
1293
- *
1294
- * The prefetch script established the connection in PARALLEL with page load,
1295
- * so the phases are positioned at their real (anchor-relative) spans — shifted
1296
- * LEFT to overlap the HTML-loading / route-idle rows — rather than sequentially
1297
- * after them. That's the whole point of the prefetch: the handshake already
1298
- * happened while the page was loading. Each phase ships:
1299
- * - `duration` — the real sub-step time the prefetch spent.
1300
- * - `spanStartMs` — anchor-relative start, so the viewer left-shifts the bar.
1301
- * - `adoptionAtMs` — where Angular took over (the next phase, Unreal
1302
- * communication, resumes here on the sequential timeline).
1303
- * - savings params: `prefetchConnectMs` (full handshake), `prefetchSavedMs`
1304
- * (done before Angular was ready), `adoptionWaitMs` (real connect→adopted
1305
- * wait), `adoptionOverheadMs` (prefetch-ready → adopted gap).
1306
- */
1307
- private emitAdoptedConnection;
1308
- /**
1309
- * Emit one adopted phase positioned at its real `spanStartMs` (left-shifted
1310
- * to overlap page load) with its real prefetch `duration`. `prefetched`,
1311
- * `spanStartMs` and `adoptionAtMs` ride as top-level wire fields the viewer
1312
- * uses to lay the bar out; the rest become display params.
1313
- */
1314
- private emitAdoptedPhase;
1315
- /** Streamer identity params for the adopted signaling phase — mirrors the
1316
- * `ssinfo-received` closer's shape (client / instanceName / …ssData). */
1317
- private adoptedSignalingParams;
1318
- /** Read the region-ping cache the prefetch reused (localStorage), so the
1319
- * adopted region phase can still report the winning region + samples. */
1320
- private readRegionCache;
1321
1174
  private handleWindow;
1322
1175
  private evaluateAnomalies;
1323
1176
  private updateMaxFpsTarget;
@@ -1546,16 +1399,6 @@ declare class WebRtcPlayerService extends SubService {
1546
1399
  * @returns true if reconnection was initiated, false if signaling is not connected
1547
1400
  */
1548
1401
  reconnectPeer(): boolean;
1549
- /**
1550
- * Adopt a fully-negotiated connection prefetched by `stream-prefetch.js`:
1551
- * take ownership of its PeerConnection, DataChannel and media stream instead
1552
- * of running the handshake. The head-script attached property-based handlers
1553
- * (`pc.onicecandidate`, `dc.onmessage`, …) and buffered inbound DC messages;
1554
- * here we detach those, wire our own (addEventListener-based) handlers, replay
1555
- * the buffer in order, then drive `onDataChannelConnected` manually because the
1556
- * DataChannel is already open (its `open` event won't fire again).
1557
- */
1558
- adopt(pc: RTCPeerConnection, dc: RTCDataChannel, stream: MediaStream, config: RTCConfiguration, dcBuffer: ArrayBuffer[]): void;
1559
1402
  private setConfig;
1560
1403
  private handlePeerConnectionEvents;
1561
1404
  private setupTransceiversAsync;
@@ -1821,44 +1664,45 @@ declare class FpsMonitorService extends SubService {
1821
1664
  static ɵprov: i0.ɵɵInjectableDeclaration<FpsMonitorService>;
1822
1665
  }
1823
1666
 
1667
+ /**
1668
+ * `MetaBoxCommandList` / `MetaBoxCallbackList` are keyed by string-**enum**
1669
+ * members, which are nominal: a plain string literal like
1670
+ * `'loadProductCommandCallback'` is NOT assignable to the enum key
1671
+ * `MetaBoxCallback.FLoadProductCommandCallback`. So template-literal lookups
1672
+ * against `keyof MetaBoxCallbackList` always miss. We first re-key the callback
1673
+ * list by its plain string values, then bridge command→callback by string.
1674
+ */
1675
+ type CallbackByString = {
1676
+ [C in keyof MetaBoxCallbackList as `${C & string}`]: MetaBoxCallbackList[C];
1677
+ };
1678
+ /**
1679
+ * Resolves a command key to its matching callback type via the
1680
+ * `F*Command` → `F*CommandCallback` naming convention
1681
+ * (e.g. command `'loadProduct'` → callback `'loadProductCommandCallback'`).
1682
+ */
1683
+ type CommandCallbackFor<K extends keyof MetaBoxCommandList> = `${K & string}CommandCallback` extends keyof CallbackByString ? CallbackByString[`${K & string}CommandCallback`] : never;
1684
+ /** Every command keyed to its real callback type. */
1685
+ type UnrealCommandCallbackMap = {
1686
+ [K in keyof MetaBoxCommandList]: CommandCallbackFor<K>;
1687
+ };
1824
1688
  /**
1825
1689
  * Custom Unreal callback events that are not part of MetaBoxCommandList.
1826
1690
  * These events are pushed from Unreal to the frontend via the data channel.
1691
+ * Keys are the runtime `command` values used for filtering.
1827
1692
  */
1828
1693
  interface UnrealCallbackEventMap {
1829
- onSceneState: {
1830
- command: 'onSceneState';
1831
- payload: FSceneState;
1832
- };
1833
- onFocusObject: {
1834
- command: 'onFocusObject';
1835
- payload: FProductPayload;
1836
- };
1837
- cameraChanged: {
1838
- command: 'cameraChanged';
1839
- payload: FCameraChangedPayload;
1840
- };
1841
- onObjectTransformChanged: {
1842
- command: 'onObjectTransformChanged';
1843
- payload: {
1844
- objectName: string;
1845
- transform: FTransformJson;
1846
- };
1847
- };
1848
- onChangeSequence: {
1849
- command: 'onChangeSequence';
1850
- payload: unknown;
1851
- };
1852
- onFinishedSequence: {
1853
- command: 'onFinishedSequence';
1854
- payload: unknown;
1855
- };
1694
+ onSceneState: FOnSceneStateCallback;
1695
+ onFocusObject: FOnFocusObjectCallback;
1696
+ cameraChanged: FCameraChangedCallback;
1697
+ onObjectTransformChanged: FOnObjectTransformChangedCallback;
1698
+ onChangeSequence: FOnChangeSequenceChangedCallback;
1699
+ onFinishedSequence: FOnFinishSequenceChangedCallback;
1856
1700
  }
1857
1701
  /**
1858
- * Combined map of all known callback event types:
1859
- * MetaBoxCommandList (command responses) + UnrealCallbackEventMap (custom events).
1702
+ * Combined map of all known callback types: every command mapped to its real
1703
+ * callback (`MetaBoxCallbackList`) + the custom event callbacks.
1860
1704
  */
1861
- type UnrealCallbackDescriptor = MetaBoxCommandList & UnrealCallbackEventMap;
1705
+ type UnrealCallbackDescriptor = UnrealCommandCallbackMap & UnrealCallbackEventMap;
1862
1706
  declare class UnrealCallbackService {
1863
1707
  private readonly actions$;
1864
1708
  /**
@@ -1903,7 +1747,7 @@ declare class UnrealCallbackService {
1903
1747
  * .subscribe();
1904
1748
  * ```
1905
1749
  */
1906
- observeCommandResponse<K extends keyof MetaBoxCommandList, T extends MetaBoxCommandList[K] = MetaBoxCommandList[K]>(data: T, sender: (data: T) => void, timeOut?: number, dispatchOnTimeout?: boolean): node_modules_rxjs_dist_types.Observable<MetaBoxCommandList[K]>;
1750
+ observeCommandResponse<K extends keyof MetaBoxCommandList, T extends MetaBoxCommandList[K] = MetaBoxCommandList[K]>(data: T, sender: (data: T) => void, timeOut?: number, dispatchOnTimeout?: boolean): node_modules_rxjs_dist_types.Observable<CommandCallbackFor<K>>;
1907
1751
  static ɵfac: i0.ɵɵFactoryDeclaration<UnrealCallbackService, never>;
1908
1752
  static ɵprov: i0.ɵɵInjectableDeclaration<UnrealCallbackService>;
1909
1753
  }
@@ -2616,44 +2460,6 @@ declare const showUnrealErrorMessage: node_modules__ngrx_store_types_ngrx_store.
2616
2460
  error?: string;
2617
2461
  } & node_modules__ngrx_store_types_ngrx_store.Action<string>>;
2618
2462
  declare const initSignalling: node_modules__ngrx_store_types_ngrx_store.ActionCreator<string, () => node_modules__ngrx_store_types_ngrx_store.Action<string>>;
2619
- /**
2620
- * Dispatched when a prefetched connection parked on `window.__stream` by the
2621
- * `stream-prefetch.js` head-script is adopted instead of opening a fresh
2622
- * `connectToSignaling`. Marks cirrus connected and records the adopted machine
2623
- * in one transaction; the data channel / app-init chain then proceeds via
2624
- * `dataChannelConnected` dispatched from `WebRtcPlayerService`.
2625
- *
2626
- * Deliberately does NOT touch `streamClientCompanyId` / `streamViewId`: the host
2627
- * app (e.g. metabox) sets those authoritatively from its own data before
2628
- * `initSignalling`, and the prefetch script's ids are connection-internal only.
2629
- */
2630
- declare const streamAdopted: node_modules__ngrx_store_types_ngrx_store.ActionCreator<string, (props: {
2631
- machineId: string | null;
2632
- ssData: SignalingData | null;
2633
- /**
2634
- * `performance.now()` marks the prefetch script recorded while it
2635
- * established the connection (`prefetch_start` / `ws_open` / `dc_open` /
2636
- * `ready`), on the page navigation timeline. The telemetry service uses
2637
- * them to attribute the signaling / webrtc phase durations to the time the
2638
- * prefetch actually spent — instead of dumping the whole pre-adoption wait
2639
- * onto whichever phase closer happens to fire first. `null` when adopting a
2640
- * stream that carried no timings.
2641
- */
2642
- timings: Record<string, number> | null;
2643
- }) => {
2644
- machineId: string | null;
2645
- ssData: SignalingData | null;
2646
- /**
2647
- * `performance.now()` marks the prefetch script recorded while it
2648
- * established the connection (`prefetch_start` / `ws_open` / `dc_open` /
2649
- * `ready`), on the page navigation timeline. The telemetry service uses
2650
- * them to attribute the signaling / webrtc phase durations to the time the
2651
- * prefetch actually spent — instead of dumping the whole pre-adoption wait
2652
- * onto whichever phase closer happens to fire first. `null` when adopting a
2653
- * stream that carried no timings.
2654
- */
2655
- timings: Record<string, number> | null;
2656
- } & node_modules__ngrx_store_types_ngrx_store.Action<string>>;
2657
2463
  declare const startStream: node_modules__ngrx_store_types_ngrx_store.ActionCreator<string, (props: {
2658
2464
  config: Partial<StreamConfig>;
2659
2465
  }) => {
@@ -2750,11 +2556,11 @@ declare class UnrealEffects {
2750
2556
  private readonly commandTelemetryService;
2751
2557
  private readonly regionsPingService;
2752
2558
  private readonly signallingService;
2753
- private readonly streamAdoptionService;
2754
2559
  private readonly videoService;
2755
2560
  private readonly unrealCallbackService;
2756
2561
  private dataChannelConnectionTimeout;
2757
2562
  private connectionCompleted$;
2563
+ private reconnectConfig;
2758
2564
  destroyConnections$: node_modules_rxjs_dist_types.Observable<{
2759
2565
  reason: _3dsource_angular_unreal_module.DisconnectReasonType;
2760
2566
  } & node_modules__ngrx_store_types_ngrx_store.Action<string>> & node_modules__ngrx_effects_types_ngrx_effects.CreateEffectMetadata;
@@ -2822,8 +2628,8 @@ declare class UnrealEffects {
2822
2628
  * Effect: `handleDataChannelClosed$`
2823
2629
  *
2824
2630
  * Triggers peer reconnection when DataChannel closes unexpectedly.
2825
- * Only triggers if reconnection is enabled and the signaling WebSocket
2826
- * is still connected.
2631
+ * Only triggers if reconnection is enabled, onDataChannelClose is true,
2632
+ * and the signaling WebSocket is still connected.
2827
2633
  */
2828
2634
  handleDataChannelClosed$: node_modules_rxjs_dist_types.Observable<{
2829
2635
  attempt: number;
@@ -2868,9 +2674,7 @@ declare class UnrealEffects {
2868
2674
  id: string;
2869
2675
  now: number;
2870
2676
  } & node_modules__ngrx_store_types_ngrx_store.Action<string>> & node_modules__ngrx_effects_types_ngrx_effects.CreateEffectMetadata;
2871
- connectToSignaling$: node_modules_rxjs_dist_types.Observable<{
2872
- value: boolean;
2873
- } & node_modules__ngrx_store_types_ngrx_store.Action<string>> & node_modules__ngrx_effects_types_ngrx_effects.CreateEffectMetadata;
2677
+ connectToSignaling$: node_modules_rxjs_dist_types.Observable<WebSocket> & node_modules__ngrx_effects_types_ngrx_effects.CreateEffectMetadata;
2874
2678
  private canPeerReconnect;
2875
2679
  /**
2876
2680
  * Either schedules the next peer-reconnect attempt or gives up with the
@@ -2887,7 +2691,6 @@ declare const unrealFeature: {
2887
2691
  name: "unrealFeature";
2888
2692
  reducer: node_modules__ngrx_store_types_ngrx_store.ActionReducer<_3dsource_angular_unreal_module.UnrealState, node_modules__ngrx_store_types_ngrx_store.Action<string>>;
2889
2693
  selectUnrealFeatureState: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, _3dsource_angular_unreal_module.UnrealState, (featureState: _3dsource_angular_unreal_module.UnrealState) => _3dsource_angular_unreal_module.UnrealState>;
2890
- selectAdopted: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, boolean, (featureState: _3dsource_angular_unreal_module.UnrealState) => boolean>;
2891
2694
  selectFreezeFrame: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, _3dsource_angular_unreal_module.FreezeFrameMessage, (featureState: _3dsource_angular_unreal_module.UnrealState) => _3dsource_angular_unreal_module.FreezeFrameMessage>;
2892
2695
  selectIsVideoPlaying: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, boolean, (featureState: _3dsource_angular_unreal_module.UnrealState) => boolean>;
2893
2696
  selectStatusMessage: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, string | null, (featureState: _3dsource_angular_unreal_module.UnrealState) => string | null>;
@@ -2944,13 +2747,6 @@ interface UnrealState {
2944
2747
  isAfkTimerVisible: boolean;
2945
2748
  afkCountdown: number;
2946
2749
  cirrusConnected: boolean;
2947
- /**
2948
- * True once a prefetched connection has been adopted (`streamAdopted`).
2949
- * Read synchronously by the telemetry service so the connection-phase
2950
- * closers know to defer to the prefetch-timed attribution instead of the
2951
- * live-event one. Reset on every fresh attempt / disconnect.
2952
- */
2953
- adopted: boolean;
2954
2750
  viewportReady: boolean;
2955
2751
  freezeFrameFromVideo: FreezeFrameMessage;
2956
2752
  freezeFrame: FreezeFrameMessage;
@@ -3036,5 +2832,5 @@ declare const selectUserInactivityDetected: node_modules__ngrx_store_types_ngrx_
3036
2832
  /** Used by external consumers (e.g., metabox). Do not remove. */
3037
2833
  declare const selectIsVideoPlayingAndDataChannelConnected: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, boolean, (s1: boolean, s2: boolean) => boolean>;
3038
2834
 
3039
- export { AFKService, AUTO_HIGH_RESOLUTION_IDLE_MS, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler, CONSOLE_COMMAND_DISABLE_MESSAGES, CONSOLE_COMMAND_ENABLE_MESSAGES, CONSOLE_COMMAND_PIXEL_QUALITY, CommandTelemetryService, ConfigHandler, ConsoleExtensionsService, ControlScheme, DATA_CHANNEL_CONNECTION_TIMEOUT, DEBOUNCE_TO_MANY_RESIZE_CALLS, DEFAULT_AFK_TIMEOUT, DEFAULT_AFK_TIMEOUT_PERIOD, DESTROY_DISCONNECT_REASONS, DataFlowMonitor, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FilterSettingsComponent, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, KalmanFilter1D, LatencyTimings, LoadingProgressService, LowBandwidthDetectorComponent, LowBandwidthModalComponent, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PingHandler, PlayerCountHandler, RECONNECT_CONFIG, REGION_PING_ACCURATE_SAMPLES, REGION_PING_BACKGROUND_REFRESH_DELAY_MS, REGION_PING_CACHE_KEY, REGION_PING_CACHE_TTL_MS, REGION_PING_WARMUP_DEADLINE_MS, RegionsPingService, SAME_SIZE_THRESHOLD, SCREEN_LOCKER_CONTAINER_ID, SIGNALLING_PERCENT_VALUE, SSInfoHandler, STREAMING_AUDIO_ID, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamAdoptionService, StreamStatusTelemetryService, StreamStatusTelemetryService2, SubService, ToClientMessage, UNREAL_CONFIG, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealSceneComponent, UnrealStatusMessage, VideoService, VideoStatsComponent, WSCloseCode_CIRRUS_ABNORMAL_CLOSURE, WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR, WSCloseCode_CIRRUS_PLAYER_DISCONNECTED, WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER, WSCloseCode_FORCE_CIRRUS_CLOSE, WSCloseCode_NORMAL_AFK_TIMEOUT, WSCloseCode_NORMAL_CLOSURE, WSCloseCode_NORMAL_MANUAL_DISCONNECT, WSCloseCode_UNKNOWN, WSCloseCodes, WS_OPEN_STATE, WS_RETRY_PER_INSTANCE, WS_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, answerSent, changeStatusMainVideoOnScene, changeStreamResolutionAction, commandCompleted, commandStarted, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToPercents, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues, getResizeValuesUniversal, getRtcErrorMessage, iceConnectionFailed, initSignalling, instanceReady, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, provideUnrealState, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, saveAnalyticsEvent, selectCirrusConnectionId, selectClientAndViewIds, selectCommandProgress, selectFreezeFrameCombinedDataUrl, selectFreezeFrameDataUrl, selectFreezeFrameDataUrlFromVideo, selectFreezeFrameProgressMessageFromVideo, selectIsAutostart, selectIsExistMatchUrls, selectIsFreezeFrameLoading, selectIsFullyConnected, selectIsLoaderScreenVisible, selectIsVideoPlayingAndDataChannelConnected, selectShowLoader, selectShowReconnectPopup, selectSignalingParameters, selectStreamConfig, selectTotalProgress, selectUserInactivityDetected, selectWarnTimeout, setAfkTimerCountdown, setAfkTimerHide, setAfkTimerVisible, setAwsInstance, setCirrusConnected, setCirrusDisconnected, setConfig, setEstablishingConnection, setFreezeFrame, setFreezeFrameFromVideo, setIntroImageSrc, setIntroVideoSrc, setLoadingImageSrc, setLoopBackCommandIsCompleted, setMaxFps, setOrchestrationContext, setOrchestrationMessage, setOrchestrationParameters, setOrchestrationProgress, setSignalingName, setStatusMessage, setStatusPercentSignallingServer, setStreamClientCompanyId, setStreamViewId, setUnrealPlaywrightConfig, setUserInactivityTimeout, setViewportNotReady, setViewportReady, showLoadingProgress, showResumeStreamPopup, showUnrealErrorMessage, showUserInactivityTimeoutPopup, signalingRetryAttempted, smoothTransition, startStream, streamAdopted, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
3040
- export type { AggregatedStat, AnySignalingMessage, AwsInstance, CandidateMessage, CloseReason, CommandInProgress, ConfigMessage, ConnectionError, ControlSchemeValues, DataFlowCheckResult, DisconnectReasonType, EmittedMilestone, EventId, ForceClientDisconnect, FreezeFrameMessage, InboundVideoStats, InputProps, InstanceReady, InstanceReserved, InterruptClientStream, ListStreamersMessage, MessageBase, MessageTypeValues, NormalizeAndQuantizeSignedValue, NormalizeAndQuantizeUnsignedValue, OrchestrationErrorMessage, OrchestrationMessageType, P2PEstablishedMessage, ParkedStream, PhaseOverlay, PhaseParam, PingMessage, PlayerCountMessage, PollingOrchestrationMessage, Quality, ReceivedFile, RequestStream, SSInfo, SelectedIceCandidatePair, SignalingData, SignalingMessageHandler, SignalingMessageMap, StreamConfig, StreamRequestContext, StreamResolutionProps, StreamerListMessage, TelemetryType, UnknownFields, UnquantizeAndDenormalizeUnsignedValue, UnrealCallbackDescriptor, UnrealCallbackEventMap, UnrealCallbackJson, UnrealCallbackJsonWrapped, UnrealInitialConfig, UnrealState, WSCloseCodesValues, streamPreparedForUserInteractionMessage };
2835
+ export { AFKService, AUTO_HIGH_RESOLUTION_IDLE_MS, AfkTimeoutModalComponent, AggregatorService, AnalyticsService, AnswerHandler, CommandTelemetryService, ConfigHandler, ConsoleExtensionsService, ControlScheme, DATA_CHANNEL_CONNECTION_TIMEOUT, DEBOUNCE_TO_MANY_RESIZE_CALLS, DEFAULT_AFK_TIMEOUT, DEFAULT_AFK_TIMEOUT_PERIOD, DEFAULT_RECONNECT_DELAY_MS, DEFAULT_RECONNECT_ENABLED, DEFAULT_RECONNECT_MAX_ATTEMPTS, DEFAULT_RECONNECT_ON_DATACHANNEL_CLOSE, DEFAULT_RECONNECT_ON_ICE_FAILURE, DESTROY_DISCONNECT_REASONS, DataFlowMonitor, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FilterSettingsComponent, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, KalmanFilter1D, LatencyTimings, LoadingProgressService, LowBandwidthDetectorComponent, LowBandwidthModalComponent, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, PingHandler, PlayerCountHandler, REGION_PING_ACCURATE_SAMPLES, REGION_PING_BACKGROUND_REFRESH_DELAY_MS, REGION_PING_CACHE_KEY, REGION_PING_CACHE_TTL_MS, REGION_PING_WARMUP_DEADLINE_MS, RegionsPingService, SAME_SIZE_THRESHOLD, SCREEN_LOCKER_CONTAINER_ID, SIGNALLING_PERCENT_VALUE, SSInfoHandler, STREAMING_AUDIO_ID, STREAMING_VIDEO_ID, SafePipe, SignallingService, SpecialKeyCodes, StatGraphComponent, StreamStatusTelemetryService, StreamStatusTelemetryService2, SubService, ToClientMessage, UNREAL_CONFIG, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealSceneComponent, UnrealStatusMessage, VideoService, VideoStatsComponent, WSCloseCode_CIRRUS_ABNORMAL_CLOSURE, WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR, WSCloseCode_CIRRUS_PLAYER_DISCONNECTED, WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER, WSCloseCode_FORCE_CIRRUS_CLOSE, WSCloseCode_NORMAL_AFK_TIMEOUT, WSCloseCode_NORMAL_CLOSURE, WSCloseCode_NORMAL_MANUAL_DISCONNECT, WSCloseCode_UNKNOWN, WSCloseCodes, WS_OPEN_STATE, WS_RETRY_PER_INSTANCE, WS_TIMEOUT, WebRtcPlayerService, WebrtcErrorModalComponent, abortEstablishingConnection, answerSent, changeStatusMainVideoOnScene, changeStreamResolutionAction, commandCompleted, commandStarted, dataChannelConnected, dataChannelReady, decodeData, destroyRemoteConnections, destroyUnrealScene, disconnectStream, dispatchResize, dropConnection, dropDC, dropPC, floatToPercents, floatToSmoothPercents, forceResizeViewport, fromResizeObserver, getActiveUrl, getImageFromVideoStream, getResizeStudioValues, getResizeValuesUniversal, getRtcErrorMessage, iceConnectionFailed, initSignalling, instanceReady, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, provideUnrealState, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, saveAnalyticsEvent, selectCirrusConnectionId, selectClientAndViewIds, selectCommandProgress, selectFreezeFrameCombinedDataUrl, selectFreezeFrameDataUrl, selectFreezeFrameDataUrlFromVideo, selectFreezeFrameProgressMessageFromVideo, selectIsAutostart, selectIsExistMatchUrls, selectIsFreezeFrameLoading, selectIsFullyConnected, selectIsLoaderScreenVisible, selectIsVideoPlayingAndDataChannelConnected, selectShowLoader, selectShowReconnectPopup, selectSignalingParameters, selectStreamConfig, selectTotalProgress, selectUserInactivityDetected, selectWarnTimeout, setAfkTimerCountdown, setAfkTimerHide, setAfkTimerVisible, setAwsInstance, setCirrusConnected, setCirrusDisconnected, setConfig, setEstablishingConnection, setFreezeFrame, setFreezeFrameFromVideo, setIntroImageSrc, setIntroVideoSrc, setLoadingImageSrc, setLoopBackCommandIsCompleted, setMaxFps, setOrchestrationContext, setOrchestrationMessage, setOrchestrationParameters, setOrchestrationProgress, setSignalingName, setStatusMessage, setStatusPercentSignallingServer, setStreamClientCompanyId, setStreamViewId, setUnrealPlaywrightConfig, setUserInactivityTimeout, setViewportNotReady, setViewportReady, showLoadingProgress, showResumeStreamPopup, showUnrealErrorMessage, showUserInactivityTimeoutPopup, signalingRetryAttempted, smoothTransition, startStream, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
2836
+ export type { AggregatedStat, AnySignalingMessage, AwsInstance, CandidateMessage, CloseReason, CommandInProgress, ConfigMessage, ConnectionError, ControlSchemeValues, DataFlowCheckResult, DisconnectReasonType, EmittedMilestone, EventId, ForceClientDisconnect, FreezeFrameMessage, InboundVideoStats, InputProps, InstanceReady, InstanceReserved, InterruptClientStream, ListStreamersMessage, MessageBase, MessageTypeValues, OrchestrationErrorMessage, OrchestrationMessageType, P2PEstablishedMessage, PhaseOverlay, PhaseParam, PingMessage, PlayerCountMessage, PollingOrchestrationMessage, Quality, ReceivedFile, ReconnectConfig, RequestStream, SSInfo, SelectedIceCandidatePair, SignalingData, SignalingMessageHandler, SignalingMessageMap, StreamConfig, StreamRequestContext, StreamResolutionProps, StreamerListMessage, TelemetryType, UnknownFields, UnrealCallbackDescriptor, UnrealCallbackEventMap, UnrealCallbackJson, UnrealCallbackJsonWrapped, UnrealInitialConfig, UnrealState, WSCloseCodesValues, streamPreparedForUserInteractionMessage };
@@ -1,4 +0,0 @@
1
- "use strict";(()=>{"use strict";const f="metabox-configurator",m=/metabox-configurator\/(modular|basic)\/([^/?#]+)/i,g="3dsource:region-ping",k="assets/config.json",w="42e01f";function l(){return typeof crypto!="undefined"&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,o=>{const t=Math.random()*16|0;return(o==="x"?t:t&3|8).toString(16)})}function I(o){return o.replace("http://","ws://").replace("https://","wss://")}const h="[stream-prefetch]",s=(...o)=>console.log(h,...o),c=(...o)=>console.warn(h,...o),u=(...o)=>console.error(h,...o);class y{constructor(){const t=document.currentScript||(()=>{const n=document.getElementsByTagName("script");return n[n.length-1]})(),e=t&&t.dataset||{};this.configUrl=e.configUrl||k,this.fallbackPollingUrl=e.fallbackUrl||"",this.skipRouteCheck=this.boolOr(e.skipRouteCheck,!1),this.config={ws_timeout:this.numberOr(e.wsTimeout,6e3),poll_timeout:this.numberOr(e.pollTimeout,4e3)};const i=new URLSearchParams(window.location.search);this.forceTURN=i.has("ForceTURN"),this.forceMaxBundle=i.has("ForceMaxBundle"),this.forceMonoAudio=i.has("forceMono"),this.ids={clientId:l(),viewId:l(),correlationId:l()},this.context=null,this.environmentId=void 0,this.orchestrationType="",this.region="",this.requireEnvironmentId=!0,this.pc=null,this.dc=null,this.stream=null,this.ws=null,this.remoteDescriptionSet=!1,this.iceBuffer=[],this.wsTimeoutId=null,this.settled=!1}run(){if(typeof window=="undefined"||!("WebSocket"in window)||!("RTCPeerConnection"in window))return;if(this.skipRouteCheck){this.context={},this.requireEnvironmentId=!1,c("skipRouteCheck=true \u2014 ignoring URL gate, route, context and environmentId; using fallback polling"),this.publishParked("connecting"),this.connect().catch(e=>this.fail("exception",e));return}if(window.location.href.indexOf(f)===-1){s("skip \u2014 URL does not contain gate",`"${f}"`);return}const t=this.parseConfiguratorUrl();t?(this.context={id:t.contextId,data:{configuratorId:t.configuratorId}},this.requireEnvironmentId=!0,s("start",{contextId:t.contextId,configuratorId:t.configuratorId,ids:this.ids})):(this.context={},this.requireEnvironmentId=!1,c("URL is not a configurator route \u2014 prefetching with empty context {} and no required environmentId",window.location.pathname)),this.publishParked("connecting"),this.connect().catch(e=>this.fail("exception",e))}parseConfiguratorUrl(){const t=window.location.pathname.match(m);return t?{contextId:t[1].toLowerCase()==="modular"?"metaboxModularConfigurator":"metaboxBasicConfigurator",configuratorId:decodeURIComponent(t[2])}:null}connect(){return this.mark("prefetch_start"),this.region=this.readRegion()||"",s("region from cache:",this.region||"(none)"),(this.skipRouteCheck?Promise.resolve(null):this.fetchConfig()).then(e=>{let i;if(e)i=this.chooseEndpoint(e);else if(this.fallbackPollingUrl)c("no app config \u2014 falling back to polling",this.fallbackPollingUrl),i={type:"polling",url:this.fallbackPollingUrl,environmentId:""},this.requireEnvironmentId=!1;else{this.fail("no-config");return}if(!i){this.fail("no-endpoint");return}if(s("endpoint chosen",{type:i.type,url:i.url,environmentId:i.environmentId}),this.requireEnvironmentId&&!i.environmentId){this.fail("no-environment-id");return}this.orchestrationType=i.type,this.environmentId=i.environmentId||void 0;const n=this.adaptUrlToRegion(i.url);return(i.type==="polling"?this.pollOrchestration(n):Promise.resolve(n)).then(a=>{if(!a){this.fail("no-ws-url");return}return this.parked.machineId=a,s("opening socket",a),this.openSocket(a)})})}fetchConfig(){const t=new URL(this.configUrl,window.location.origin).href;return this.fetchWithTimeout(t,{credentials:"omit"},this.config.poll_timeout).then(e=>e.ok?e.json().catch(()=>null):null).catch(()=>null)}chooseEndpoint(t){const e=t.newSignalling,i=this.firstVersionUrl(e&&e.versions);if(i&&/^wss?:\/\//i.test(i))return{type:"direct",url:i,environmentId:e&&e.environmentId||""};const n=t.signalling,r=this.firstVersionUrl(n&&n.versions);return r?(this.requireEnvironmentId=!1,{type:"polling",url:r,environmentId:n&&n.environmentId||""}):null}firstVersionUrl(t){if(!t||typeof t!="object")return"";for(const e of Object.keys(t))if(t[e])return t[e];return""}pollOrchestration(t){const e=`${t}${this.ids.clientId}/${this.ids.viewId}`;return this.fetchWithTimeout(e,{credentials:"omit"},this.config.poll_timeout).then(i=>i.ok?i.json().catch(()=>({})):null).then(i=>i&&i.signallingServer?I(`${window.location.protocol}//${i.signallingServer}`):null).catch(()=>null)}adaptUrlToRegion(t){return this.region&&t.indexOf(":region")===-1?t.replace(/signallingserver/gi,`signallingserver/region:${this.region}`):t}openSocket(t){const e=new WebSocket(t);e.binaryType="arraybuffer",this.ws=e,this.parked.ws=e,this.wsTimeoutId=setTimeout(()=>{e.readyState!==WebSocket.OPEN&&this.fail("ws-timeout")},this.config.ws_timeout),e.onopen=()=>{clearTimeout(this.wsTimeoutId),this.mark("ws_open"),s("WS open \u2192 sending requestStream",{environmentId:this.environmentId,region:this.region,context:this.context}),this.sendRequestStream()},e.onmessage=i=>this.onWsMessage(i),e.onerror=i=>{u("WS error",i),this.fail("ws-error")},e.onclose=i=>{!this.settled&&this.parked.state!=="ready"&&(c("WS closed before ready",{code:i&&i.code}),this.fail("ws-closed"))}}sendRequestStream(){this.send({type:"requestStream",correlationId:this.ids.correlationId,payload:{region:this.region,environmentId:this.environmentId,context:this.context}})}onWsMessage(t){let e;try{const i=typeof t.data=="string"?t.data:null;if(i===null)return;e=JSON.parse(i)}catch{return}switch(s("WS \u2190",e.type),e.type){case"ssInfo":this.parked.ssData=e.data;break;case"config":this.onConfig(e);break;case"offer":this.onOffer(e);break;case"answer":this.onAnswer(e);break;case"iceCandidate":this.onIceCandidate(e.candidate);break;case"ping":this.send({type:"pong",source:"front"});break;case"streamerDisconnected":case"playerDisconnected":this.fail("streamer-disconnected");break;case"error":this.fail("orchestration-error");break;default:break}}onConfig(t){if(this.pc)return;const e=Object.assign({},t.peerConnectionOptions);this.forceTURN&&(e.iceTransportPolicy="relay"),e.bundlePolicy=this.forceMaxBundle?"max-bundle":"balanced",e.iceCandidatePoolSize=1,this.parked.config=e;const i=new RTCPeerConnection(e);this.pc=i,this.parked.pc=i,s("PeerConnection created from config"),i.onicecandidate=n=>{n.candidate&&this.send({type:"iceCandidate",candidate:n.candidate})},i.ondatachannel=n=>this.wireDataChannel(n.channel),i.ontrack=n=>{n.track&&n.track.kind==="video"&&n.streams[0]&&(s("video track received"),this.stream=n.streams[0],this.parked.stream=this.stream,this.maybeReady())}}onOffer(t){return this.pc?(this.remoteDescriptionSet=!1,this.iceBuffer.length=0,this.pc.setRemoteDescription(t).then(()=>(this.remoteDescriptionSet=!0,this.flushIce(),this.pc.createAnswer())).then(e=>(e.sdp=this.mungeSDP(e.sdp||""),this.pc.setLocalDescription(e).then(()=>{s("WS \u2192 answer sent"),this.send(e)}))).catch(e=>this.fail("offer-failed",e))):Promise.resolve()}onAnswer(t){return this.pc?this.pc.setRemoteDescription(t).then(()=>{this.remoteDescriptionSet=!0,this.flushIce()}).catch(e=>this.fail("answer-failed",e)):Promise.resolve()}onIceCandidate(t){t&&(this.forceTURN&&String(t.candidate).indexOf("relay")<0||(this.remoteDescriptionSet&&this.pc?this.pc.addIceCandidate(t).catch(()=>{}):this.iceBuffer.push(t)))}flushIce(){for(const t of this.iceBuffer)this.pc.addIceCandidate(t).catch(()=>{});this.iceBuffer.length=0}wireDataChannel(t){t.binaryType="arraybuffer",this.dc=t,this.parked.dc=t,t.onmessage=e=>{this.parked.dcBuffer.push(e.data)},t.onopen=()=>{s("DataChannel open"),this.mark("dc_open"),this.maybeReady()},t.onclose=()=>{!this.settled&&this.parked.state!=="ready"&&(c("DataChannel closed before ready"),this.fail("dc-closed"))},t.readyState==="open"&&this.maybeReady()}maybeReady(){this.settled||!this.dc||this.dc.readyState!=="open"||this.stream&&(this.settled=!0,this.mark("ready"),this.parked.state="ready",s("READY \u2014 parked on window.__stream",this.parked.timings))}publishParked(t){const e=this;this.parked={state:t,pc:null,dc:null,stream:null,ws:null,ssData:void 0,machineId:void 0,config:void 0,ids:this.ids,dcBuffer:[],timings:{},adopt(){return e.clearTimers(),this.state="adopted",this}},window.__stream=this.parked}clearTimers(){this.wsTimeoutId&&(clearTimeout(this.wsTimeoutId),this.wsTimeoutId=null)}fail(t,e){if(!(this.parked&&(this.parked.state==="adopted"||this.parked.state==="failed"))){u("FAILED:",t,e||""),this.settled=!0,this.clearTimers();try{this.dc&&this.dc.close()}catch{}try{this.pc&&this.pc.close()}catch{}try{this.ws&&this.ws.close()}catch{}this.parked&&(this.parked.state="failed",this.parked.failReason=t,e&&(this.parked.failError=String(e&&e.message||e)))}}mungeSDP(t){let e=this.prioritizeH264Profile(t,w);e=e.replace(/(a=fmtp:\d+ .*level-asymmetry-allowed=.*)\r\n/gm,`$1;x-google-start-bitrate=10000;x-google-max-bitrate=100000\r
2
- `);let i="maxaveragebitrate=510000;";return i+=this.forceMonoAudio?"stereo=0;":"stereo=1;",i+="useinbandfec=1",e=e.replace("useinbandfec=1",i),e}prioritizeH264Profile(t,e){const i=t.split(`\r
3
- `),n=[];for(const r of i)if(r.startsWith("a=fmtp:")&&r.toLowerCase().includes(`profile-level-id=${e}`)){const a=r.split(":")[1]&&r.split(":")[1].split(" ")[0];a&&n.push(a)}return n.length===0?t:i.map(r=>{if(!r.startsWith("m=video"))return r;const a=r.split(" "),x=a.slice(0,3),p=a.slice(3),b=[...n.filter(d=>p.includes(d)),...p.filter(d=>!n.includes(d))];return[...x,...b].join(" ")}).join(`\r
4
- `)}send(t){const e=typeof t=="string"?t:JSON.stringify(t);if(this.ws&&this.ws.readyState===WebSocket.OPEN)try{this.ws.send(e)}catch{}}mark(t){this.parked&&(this.parked.timings[t]=performance.now())}readRegion(){try{const t=localStorage.getItem(g);if(!t)return null;const e=JSON.parse(t);return!e||typeof e.region_code!="string"||typeof e.ts!="number"||Date.now()-e.ts>=2592e6?null:e.region_code}catch{return null}}fetchWithTimeout(t,e,i){const n=new AbortController;e.signal=n.signal;const r=setTimeout(()=>n.abort(),i);return fetch(t,e).finally(()=>clearTimeout(r))}numberOr(t,e){const i=Number(t);return t!=null&&t!==""&&!Number.isNaN(i)?i:e}boolOr(t,e){return t==="true"||t===""?!0:t==="false"?!1:e}}new y().run()})();