@3dsource/angular-unreal-module 0.0.146-dev.9 → 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.9",
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,65 +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
- * Register a one-shot callback fired the instant the stream settles
292
- * (`ready`/`failed`); fires on the next microtask if already settled. Lets
293
- * {@link StreamAdoptionService} adopt event-driven instead of polling.
294
- * Optional — absent on head-script versions predating the hook, where the
295
- * service falls back to polling.
296
- */
297
- onSettled?: (cb: (state: ParkedStream['state']) => void) => void;
298
- }
299
- declare global {
300
- interface Window {
301
- __stream?: ParkedStream;
302
- }
256
+ /** Configuration for auto-reconnection behavior */
257
+ reconnect?: ReconnectConfig;
303
258
  }
304
259
 
305
260
  declare const SpecialKeyCodes: {
@@ -391,9 +346,6 @@ declare const MIN_CONTAINER_SIZE = 2;
391
346
  declare const MINIMAL_FPS = 6;
392
347
  declare const STREAMING_VIDEO_ID = "streamingVideo";
393
348
  declare const STREAMING_AUDIO_ID = "streamingAudio";
394
- declare const CONSOLE_COMMAND_ENABLE_MESSAGES = "EnableAllScreenMessages";
395
- declare const CONSOLE_COMMAND_DISABLE_MESSAGES = "DisableAllScreenMessages";
396
- declare const CONSOLE_COMMAND_PIXEL_QUALITY = "PixelStreaming.FreezeFrameQuality 95";
397
349
  declare const FULL_HD_WIDTH = 1920;
398
350
  declare const FULL_HD_HEIGHT = 1080;
399
351
  declare const WS_TIMEOUT = 6000;
@@ -412,29 +364,16 @@ declare const REGION_PING_CACHE_TTL_MS: number;
412
364
  declare const REGION_PING_ACCURATE_SAMPLES = 3;
413
365
  declare const REGION_PING_WARMUP_DEADLINE_MS = 1500;
414
366
  declare const REGION_PING_BACKGROUND_REFRESH_DELAY_MS = 5000;
415
- declare const RECONNECT_CONFIG: {
416
- readonly enabled: true;
417
- readonly maxAttempts: 3;
418
- readonly delayMs: 1000;
419
- };
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;
420
372
  declare const UnrealStatusMessage: {
421
373
  readonly CONNECTING_TO_SESSION: "Connecting to session.";
422
374
  readonly STARTING_YOUR_SESSION: "Starting your session";
423
375
  };
424
376
 
425
- interface NormalizeAndQuantizeUnsignedValue {
426
- inRange: boolean;
427
- x: number;
428
- y: number;
429
- }
430
- interface UnquantizeAndDenormalizeUnsignedValue {
431
- x: number;
432
- y: number;
433
- }
434
- interface NormalizeAndQuantizeSignedValue {
435
- x: number;
436
- y: number;
437
- }
438
377
  interface InputProps {
439
378
  controlScheme: ControlSchemeValues;
440
379
  suppressBrowserKeys: boolean;
@@ -442,6 +381,16 @@ interface InputProps {
442
381
 
443
382
  type Quality = 'lime' | 'red' | 'orange';
444
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
+
445
394
  declare const OrchestrationMessageTypes: {
446
395
  readonly ping: "ping";
447
396
  readonly error: "error";
@@ -906,7 +855,6 @@ declare class InputService extends SubService {
906
855
  private isKeyCodeBrowserKey;
907
856
  private getKeyCode;
908
857
  private registerKeyboardEvents;
909
- private isIgnoredViewportKey;
910
858
  private startListenKeys;
911
859
  static ɵfac: i0.ɵɵFactoryDeclaration<InputService, never>;
912
860
  static ɵprov: i0.ɵɵInjectableDeclaration<InputService>;
@@ -931,15 +879,8 @@ declare class RegionsPingService {
931
879
  * entry is well-formed and still within {@link REGION_PING_CACHE_TTL_MS}.
932
880
  * All access is guarded — `localStorage` can throw (private mode, disabled
933
881
  * storage) or be absent (non-browser).
934
- *
935
- * Public so adopted connections (which skip `getFastest`) can replay the
936
- * region-resolving telemetry phase from the same cached winner — see
937
- * `UnrealEffects.regionTelemetryOnAdopt$`.
938
882
  */
939
- readCachedWinner(): {
940
- region_code: string;
941
- result: number[];
942
- } | null;
883
+ private readCachedWinner;
943
884
  private writeCachedWinner;
944
885
  /**
945
886
  * Accurate, OFF-critical-path refresh of the region cache. Mirrors the
@@ -1061,15 +1002,6 @@ declare class SignallingService extends SubService {
1061
1002
  private pollLoop;
1062
1003
  private connectToCirrus;
1063
1004
  private addWsHandlers;
1064
- /**
1065
- * Adopt a live signalling socket opened by the `stream-prefetch.js`
1066
- * head-script. The socket is already OPEN and `requestStream` was already
1067
- * sent, so — unlike {@link addWsHandlers} — we attach message/close/error
1068
- * handlers but deliberately skip {@link OnOpenHandler} (which would
1069
- * `setCirrusConnected` + re-`sendRequestStream`). Reuses the head-script's
1070
- * `correlationId` so subsequent correlated messages line up.
1071
- */
1072
- adoptSocket(ws: WebSocket, correlationId: string): void;
1073
1005
  private showStatusMessage;
1074
1006
  /**
1075
1007
  * Close the connection with the signaling server
@@ -1089,64 +1021,6 @@ declare class SignallingService extends SubService {
1089
1021
  static ɵprov: i0.ɵɵInjectableDeclaration<SignallingService>;
1090
1022
  }
1091
1023
 
1092
- /**
1093
- * Adopts a WebRTC connection prefetched by the `stream-prefetch.js` head-script
1094
- * and parked on `window.__stream`, instead of running `connectToSignaling` from
1095
- * scratch. Called from the same seam where signalling normally starts
1096
- * (`connectToSignaling$` effect); if there is nothing ready to adopt it returns
1097
- * `false` and the caller falls back to the normal connect — strictly additive.
1098
- */
1099
- declare class StreamAdoptionService {
1100
- private readonly store;
1101
- private readonly signalling;
1102
- private readonly webRtc;
1103
- /**
1104
- * Decide adoption, WAITING for an in-flight prefetch instead of racing it.
1105
- *
1106
- * - nothing parked → emit `false` at once (caller connects normally).
1107
- * - already settled (`ready`/`failed`/`adopted`) → adopt-if-ready at once.
1108
- * - still `connecting` → wait for the script's `onSettled` callback (no
1109
- * polling latency) and adopt-if-ready the instant it fires; on older
1110
- * scripts without the hook, fall back to a `timer` poll.
1111
- *
1112
- * Deliberately NO time budget: for DIRECT orchestration the prefetch holds
1113
- * the socket open while the orchestrator provisions a machine, which can take
1114
- * minutes (150–200s+). A fixed deadline would make Angular give up and open a
1115
- * second connection mid-provisioning — exactly the race/orphan this avoids.
1116
- * The wait is bounded by liveness instead: the script flips the parked state
1117
- * to `failed` on a dead socket (`ws.onclose`/`onerror`), and the caller wraps
1118
- * this in `takeUntil(abortEstablishingConnection)`, so a route change / teardown
1119
- * cancels it. Emits exactly once. Cancelling runs no adoption — which is what
1120
- * stops a fast route-switch from starting overlapping connections.
1121
- *
1122
- * Wrapped in `defer` so the `tryAdopt()` side effect (which dispatches
1123
- * `streamAdopted`) runs at SUBSCRIPTION time, not when the observable is
1124
- * built. The effect prepends `startWith(setEstablishingConnection(true))`,
1125
- * which starts the telemetry session and subscribes its phase catalog; that
1126
- * must happen BEFORE `streamAdopted` → `regionTelemetryOnAdopt$` replays
1127
- * `regionResolved`, or the region phase fires into a session that doesn't
1128
- * exist yet and is lost. `defer` guarantees that ordering.
1129
- */
1130
- awaitAndAdopt$(): Observable<boolean>;
1131
- /**
1132
- * Event-driven wait: resolve the instant the script's `onSettled` callback
1133
- * fires (ready/failed), then adopt-if-ready. Emits exactly once.
1134
- *
1135
- * A coarse {@link ADOPT_EVENT_SAFETY_MS} interval is a backstop only — if
1136
- * `onSettled` somehow never fires it still settles, without adding latency to
1137
- * the normal case. Teardown (route change → unsubscribe) sets `done`, so a
1138
- * late callback after cancel can't trigger a stray adoption.
1139
- */
1140
- private awaitSettled$;
1141
- /**
1142
- * @returns `true` if a ready parked stream was adopted (caller must NOT
1143
- * start a fresh connection), `false` otherwise.
1144
- */
1145
- tryAdopt(): boolean;
1146
- static ɵfac: i0.ɵɵFactoryDeclaration<StreamAdoptionService, never>;
1147
- static ɵprov: i0.ɵɵInjectableDeclaration<StreamAdoptionService>;
1148
- }
1149
-
1150
1024
  declare class StreamStatusTelemetryService extends SubService {
1151
1025
  private readonly videoService;
1152
1026
  private readonly unrealConfig;
@@ -1234,17 +1108,6 @@ declare class StreamStatusTelemetryService2 {
1234
1108
  private readonly disconnectReason$;
1235
1109
  private readonly errorMessage$;
1236
1110
  private readonly viewPortReady$;
1237
- /**
1238
- * Synchronous adoption flag. The `streamAdopted` reducer sets it BEFORE any
1239
- * action subscriber runs, so the connection-phase closers (which fire inside
1240
- * the same dispatch, e.g. `ssinfo-received` off the `ssData` state change)
1241
- * can read it and defer to the prefetch-timed attribution emitted by
1242
- * {@link emitAdoptedConnection} instead of recording the live wall-clock.
1243
- */
1244
- private readonly adopted$;
1245
- /** Streamer identity for the adopted signaling phase params. */
1246
- private readonly ssData$;
1247
- private readonly awsInstance$;
1248
1111
  private session;
1249
1112
  /**
1250
1113
  * Whether a session has already started during the current page lifetime.
@@ -1308,36 +1171,6 @@ declare class StreamStatusTelemetryService2 {
1308
1171
  * are derived from neighbor phases.
1309
1172
  */
1310
1173
  private emitPhaseEnded;
1311
- /**
1312
- * Emit the region / signaling / webrtc phases for an ADOPTED connection.
1313
- *
1314
- * The prefetch script established the connection in PARALLEL with page load,
1315
- * so the phases are positioned at their real (anchor-relative) spans — shifted
1316
- * LEFT to overlap the HTML-loading / route-idle rows — rather than sequentially
1317
- * after them. That's the whole point of the prefetch: the handshake already
1318
- * happened while the page was loading. Each phase ships:
1319
- * - `duration` — the real sub-step time the prefetch spent.
1320
- * - `spanStartMs` — anchor-relative start, so the viewer left-shifts the bar.
1321
- * - `adoptionAtMs` — where Angular took over (the next phase, Unreal
1322
- * communication, resumes here on the sequential timeline).
1323
- * - savings params: `prefetchConnectMs` (full handshake), `prefetchSavedMs`
1324
- * (done before Angular was ready), `adoptionWaitMs` (real connect→adopted
1325
- * wait), `adoptionOverheadMs` (prefetch-ready → adopted gap).
1326
- */
1327
- private emitAdoptedConnection;
1328
- /**
1329
- * Emit one adopted phase positioned at its real `spanStartMs` (left-shifted
1330
- * to overlap page load) with its real prefetch `duration`. `prefetched`,
1331
- * `spanStartMs` and `adoptionAtMs` ride as top-level wire fields the viewer
1332
- * uses to lay the bar out; the rest become display params.
1333
- */
1334
- private emitAdoptedPhase;
1335
- /** Streamer identity params for the adopted signaling phase — mirrors the
1336
- * `ssinfo-received` closer's shape (client / instanceName / …ssData). */
1337
- private adoptedSignalingParams;
1338
- /** Read the region-ping cache the prefetch reused (localStorage), so the
1339
- * adopted region phase can still report the winning region + samples. */
1340
- private readRegionCache;
1341
1174
  private handleWindow;
1342
1175
  private evaluateAnomalies;
1343
1176
  private updateMaxFpsTarget;
@@ -1566,16 +1399,6 @@ declare class WebRtcPlayerService extends SubService {
1566
1399
  * @returns true if reconnection was initiated, false if signaling is not connected
1567
1400
  */
1568
1401
  reconnectPeer(): boolean;
1569
- /**
1570
- * Adopt a fully-negotiated connection prefetched by `stream-prefetch.js`:
1571
- * take ownership of its PeerConnection, DataChannel and media stream instead
1572
- * of running the handshake. The head-script attached property-based handlers
1573
- * (`pc.onicecandidate`, `dc.onmessage`, …) and buffered inbound DC messages;
1574
- * here we detach those, wire our own (addEventListener-based) handlers, replay
1575
- * the buffer in order, then drive `onDataChannelConnected` manually because the
1576
- * DataChannel is already open (its `open` event won't fire again).
1577
- */
1578
- adopt(pc: RTCPeerConnection, dc: RTCDataChannel, stream: MediaStream, config: RTCConfiguration, dcBuffer: ArrayBuffer[]): void;
1579
1402
  private setConfig;
1580
1403
  private handlePeerConnectionEvents;
1581
1404
  private setupTransceiversAsync;
@@ -1841,44 +1664,45 @@ declare class FpsMonitorService extends SubService {
1841
1664
  static ɵprov: i0.ɵɵInjectableDeclaration<FpsMonitorService>;
1842
1665
  }
1843
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
+ };
1844
1688
  /**
1845
1689
  * Custom Unreal callback events that are not part of MetaBoxCommandList.
1846
1690
  * These events are pushed from Unreal to the frontend via the data channel.
1691
+ * Keys are the runtime `command` values used for filtering.
1847
1692
  */
1848
1693
  interface UnrealCallbackEventMap {
1849
- onSceneState: {
1850
- command: 'onSceneState';
1851
- payload: FSceneState;
1852
- };
1853
- onFocusObject: {
1854
- command: 'onFocusObject';
1855
- payload: FProductPayload;
1856
- };
1857
- cameraChanged: {
1858
- command: 'cameraChanged';
1859
- payload: FCameraChangedPayload;
1860
- };
1861
- onObjectTransformChanged: {
1862
- command: 'onObjectTransformChanged';
1863
- payload: {
1864
- objectName: string;
1865
- transform: FTransformJson;
1866
- };
1867
- };
1868
- onChangeSequence: {
1869
- command: 'onChangeSequence';
1870
- payload: unknown;
1871
- };
1872
- onFinishedSequence: {
1873
- command: 'onFinishedSequence';
1874
- payload: unknown;
1875
- };
1694
+ onSceneState: FOnSceneStateCallback;
1695
+ onFocusObject: FOnFocusObjectCallback;
1696
+ cameraChanged: FCameraChangedCallback;
1697
+ onObjectTransformChanged: FOnObjectTransformChangedCallback;
1698
+ onChangeSequence: FOnChangeSequenceChangedCallback;
1699
+ onFinishedSequence: FOnFinishSequenceChangedCallback;
1876
1700
  }
1877
1701
  /**
1878
- * Combined map of all known callback event types:
1879
- * 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.
1880
1704
  */
1881
- type UnrealCallbackDescriptor = MetaBoxCommandList & UnrealCallbackEventMap;
1705
+ type UnrealCallbackDescriptor = UnrealCommandCallbackMap & UnrealCallbackEventMap;
1882
1706
  declare class UnrealCallbackService {
1883
1707
  private readonly actions$;
1884
1708
  /**
@@ -1923,7 +1747,7 @@ declare class UnrealCallbackService {
1923
1747
  * .subscribe();
1924
1748
  * ```
1925
1749
  */
1926
- 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>>;
1927
1751
  static ɵfac: i0.ɵɵFactoryDeclaration<UnrealCallbackService, never>;
1928
1752
  static ɵprov: i0.ɵɵInjectableDeclaration<UnrealCallbackService>;
1929
1753
  }
@@ -2636,44 +2460,6 @@ declare const showUnrealErrorMessage: node_modules__ngrx_store_types_ngrx_store.
2636
2460
  error?: string;
2637
2461
  } & node_modules__ngrx_store_types_ngrx_store.Action<string>>;
2638
2462
  declare const initSignalling: node_modules__ngrx_store_types_ngrx_store.ActionCreator<string, () => node_modules__ngrx_store_types_ngrx_store.Action<string>>;
2639
- /**
2640
- * Dispatched when a prefetched connection parked on `window.__stream` by the
2641
- * `stream-prefetch.js` head-script is adopted instead of opening a fresh
2642
- * `connectToSignaling`. Marks cirrus connected and records the adopted machine
2643
- * in one transaction; the data channel / app-init chain then proceeds via
2644
- * `dataChannelConnected` dispatched from `WebRtcPlayerService`.
2645
- *
2646
- * Deliberately does NOT touch `streamClientCompanyId` / `streamViewId`: the host
2647
- * app (e.g. metabox) sets those authoritatively from its own data before
2648
- * `initSignalling`, and the prefetch script's ids are connection-internal only.
2649
- */
2650
- declare const streamAdopted: node_modules__ngrx_store_types_ngrx_store.ActionCreator<string, (props: {
2651
- machineId: string | null;
2652
- ssData: SignalingData | null;
2653
- /**
2654
- * `performance.now()` marks the prefetch script recorded while it
2655
- * established the connection (`prefetch_start` / `ws_open` / `dc_open` /
2656
- * `ready`), on the page navigation timeline. The telemetry service uses
2657
- * them to attribute the signaling / webrtc phase durations to the time the
2658
- * prefetch actually spent — instead of dumping the whole pre-adoption wait
2659
- * onto whichever phase closer happens to fire first. `null` when adopting a
2660
- * stream that carried no timings.
2661
- */
2662
- timings: Record<string, number> | null;
2663
- }) => {
2664
- machineId: string | null;
2665
- ssData: SignalingData | null;
2666
- /**
2667
- * `performance.now()` marks the prefetch script recorded while it
2668
- * established the connection (`prefetch_start` / `ws_open` / `dc_open` /
2669
- * `ready`), on the page navigation timeline. The telemetry service uses
2670
- * them to attribute the signaling / webrtc phase durations to the time the
2671
- * prefetch actually spent — instead of dumping the whole pre-adoption wait
2672
- * onto whichever phase closer happens to fire first. `null` when adopting a
2673
- * stream that carried no timings.
2674
- */
2675
- timings: Record<string, number> | null;
2676
- } & node_modules__ngrx_store_types_ngrx_store.Action<string>>;
2677
2463
  declare const startStream: node_modules__ngrx_store_types_ngrx_store.ActionCreator<string, (props: {
2678
2464
  config: Partial<StreamConfig>;
2679
2465
  }) => {
@@ -2770,11 +2556,11 @@ declare class UnrealEffects {
2770
2556
  private readonly commandTelemetryService;
2771
2557
  private readonly regionsPingService;
2772
2558
  private readonly signallingService;
2773
- private readonly streamAdoptionService;
2774
2559
  private readonly videoService;
2775
2560
  private readonly unrealCallbackService;
2776
2561
  private dataChannelConnectionTimeout;
2777
2562
  private connectionCompleted$;
2563
+ private reconnectConfig;
2778
2564
  destroyConnections$: node_modules_rxjs_dist_types.Observable<{
2779
2565
  reason: _3dsource_angular_unreal_module.DisconnectReasonType;
2780
2566
  } & node_modules__ngrx_store_types_ngrx_store.Action<string>> & node_modules__ngrx_effects_types_ngrx_effects.CreateEffectMetadata;
@@ -2842,8 +2628,8 @@ declare class UnrealEffects {
2842
2628
  * Effect: `handleDataChannelClosed$`
2843
2629
  *
2844
2630
  * Triggers peer reconnection when DataChannel closes unexpectedly.
2845
- * Only triggers if reconnection is enabled and the signaling WebSocket
2846
- * is still connected.
2631
+ * Only triggers if reconnection is enabled, onDataChannelClose is true,
2632
+ * and the signaling WebSocket is still connected.
2847
2633
  */
2848
2634
  handleDataChannelClosed$: node_modules_rxjs_dist_types.Observable<{
2849
2635
  attempt: number;
@@ -2888,9 +2674,7 @@ declare class UnrealEffects {
2888
2674
  id: string;
2889
2675
  now: number;
2890
2676
  } & node_modules__ngrx_store_types_ngrx_store.Action<string>> & node_modules__ngrx_effects_types_ngrx_effects.CreateEffectMetadata;
2891
- connectToSignaling$: node_modules_rxjs_dist_types.Observable<{
2892
- value: boolean;
2893
- } & 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;
2894
2678
  private canPeerReconnect;
2895
2679
  /**
2896
2680
  * Either schedules the next peer-reconnect attempt or gives up with the
@@ -2907,7 +2691,6 @@ declare const unrealFeature: {
2907
2691
  name: "unrealFeature";
2908
2692
  reducer: node_modules__ngrx_store_types_ngrx_store.ActionReducer<_3dsource_angular_unreal_module.UnrealState, node_modules__ngrx_store_types_ngrx_store.Action<string>>;
2909
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>;
2910
- selectAdopted: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, boolean, (featureState: _3dsource_angular_unreal_module.UnrealState) => boolean>;
2911
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>;
2912
2695
  selectIsVideoPlaying: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, boolean, (featureState: _3dsource_angular_unreal_module.UnrealState) => boolean>;
2913
2696
  selectStatusMessage: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, string | null, (featureState: _3dsource_angular_unreal_module.UnrealState) => string | null>;
@@ -2964,13 +2747,6 @@ interface UnrealState {
2964
2747
  isAfkTimerVisible: boolean;
2965
2748
  afkCountdown: number;
2966
2749
  cirrusConnected: boolean;
2967
- /**
2968
- * True once a prefetched connection has been adopted (`streamAdopted`).
2969
- * Read synchronously by the telemetry service so the connection-phase
2970
- * closers know to defer to the prefetch-timed attribution instead of the
2971
- * live-event one. Reset on every fresh attempt / disconnect.
2972
- */
2973
- adopted: boolean;
2974
2750
  viewportReady: boolean;
2975
2751
  freezeFrameFromVideo: FreezeFrameMessage;
2976
2752
  freezeFrame: FreezeFrameMessage;
@@ -3056,5 +2832,5 @@ declare const selectUserInactivityDetected: node_modules__ngrx_store_types_ngrx_
3056
2832
  /** Used by external consumers (e.g., metabox). Do not remove. */
3057
2833
  declare const selectIsVideoPlayingAndDataChannelConnected: node_modules__ngrx_store_types_ngrx_store.MemoizedSelector<Record<string, any>, boolean, (s1: boolean, s2: boolean) => boolean>;
3058
2834
 
3059
- 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 };
3060
- 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),this.fireSettled())}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},onSettled(i){if(typeof i=="function"){if(this.state!=="connecting"){const n=this.state;Promise.resolve().then(()=>i(n));return}e.settledCb=i}}},window.__stream=this.parked}fireSettled(){const t=this.settledCb;if(t){this.settledCb=null;try{t(this.parked.state)}catch{}}}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)),this.fireSettled())}}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()})();