@3dsource/angular-unreal-module 0.0.171 → 0.0.173

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.
@@ -1,16 +1,16 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, output, ChangeDetectionStrategy, Component, InjectionToken, inject, DestroyRef, Injectable, signal, effect, untracked, computed, ElementRef, viewChild, afterNextRender, HostListener, SecurityContext, Pipe, makeEnvironmentProviders, provideEnvironmentInitializer } from '@angular/core';
3
- import { Subject, skip, share, merge, map, scan, timestamp, startWith, pairwise, concatMap, of, animationFrameScheduler, interval, Observable, timer, take, defer, switchMap, from, throwError, EMPTY, retry, timeout as timeout$1, repeat, BehaviorSubject, takeUntil as takeUntil$1, fromEvent, tap as tap$1, throttleTime, delay, concat, debounceTime, mergeMap, NEVER, ignoreElements, shareReplay, firstValueFrom, asyncScheduler, filter as filter$1, withLatestFrom as withLatestFrom$1, Subscription, bufferTime, combineLatestWith } from 'rxjs';
4
- import { createAction, props, createReducer, on, createFeature, Store, createSelector, provideState } from '@ngrx/store';
5
- import { whereNot, Falsy, Logger, clampf, lerp, getCanvasCached, getSnapshot, fitIntoRectangle, generateUuid, Truthy, tapLog, Semaphore, COLOR_CODES, where, KeyboardNumericCode, InvertedKeyMap, HEXtoRGB, RGBtoHSV, inverseLerp, HSVtoRGB, RGBtoHEX, fpIsASameAsB } from '@3dsource/utils';
6
- import { filter, map as map$1, distinctUntilChanged, takeWhile, takeUntil, catchError, tap, timeout, finalize, first, switchMap as switchMap$1, withLatestFrom, exhaustMap, debounceTime as debounceTime$1, take as take$1, startWith as startWith$1 } from 'rxjs/operators';
2
+ import { input, output, ChangeDetectionStrategy, Component, InjectionToken, inject, DestroyRef, Injectable, signal, effect, untracked, computed, ElementRef, viewChild, afterNextRender, HostListener, TemplateRef, Directive, SecurityContext, Pipe, contentChild, makeEnvironmentProviders, provideEnvironmentInitializer } from '@angular/core';
3
+ import { NgTemplateOutlet, NgOptimizedImage, JsonPipe } from '@angular/common';
4
+ import { createAction, props, createReducer, on, createFeature, createSelector, Store, provideState } from '@ngrx/store';
7
5
  import { Actions, ofType, createEffect, provideEffects } from '@ngrx/effects';
6
+ import { Subject, skip, share, timer, of, take, defer, switchMap, from, throwError, Observable, EMPTY, retry, merge, timeout as timeout$1, repeat, BehaviorSubject, interval, map as map$1, takeUntil as takeUntil$1, fromEvent, tap as tap$1, throttleTime, delay, concat, debounceTime, mergeMap, NEVER, ignoreElements, startWith, scan, timestamp, pairwise, concatMap, animationFrameScheduler, shareReplay, firstValueFrom, asyncScheduler, filter as filter$1, withLatestFrom as withLatestFrom$1, Subscription, bufferTime, combineLatestWith } from 'rxjs';
7
+ import { whereNot, lerp, clampf, Falsy, generateUuid, Truthy, Logger, tapLog, Semaphore, COLOR_CODES, getCanvasCached, getSnapshot, fitIntoRectangle, where, KeyboardNumericCode, InvertedKeyMap, HEXtoRGB, RGBtoHSV, inverseLerp, HSVtoRGB, RGBtoHEX, fpIsASameAsB } from '@3dsource/utils';
8
+ import { filter, takeUntil, catchError, tap, map, timeout, finalize, first, switchMap as switchMap$1, distinctUntilChanged, withLatestFrom, exhaustMap, takeWhile, debounceTime as debounceTime$1, take as take$1, startWith as startWith$1 } from 'rxjs/operators';
8
9
  import { DialogRef, DIALOG_DATA, Dialog } from '@angular/cdk/dialog';
9
10
  import { HttpClient } from '@angular/common/http';
10
11
  import { ScrollStrategyOptions } from '@angular/cdk/overlay';
11
12
  import { MetaBoxCommand, EPayloadVersion } from '@3dsource/types-unreal';
12
13
  import { toSignal, toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
13
- import { NgOptimizedImage, JsonPipe } from '@angular/common';
14
14
  import { DomSanitizer } from '@angular/platform-browser';
15
15
 
16
16
  class UnrealButtonComponent {
@@ -34,14 +34,246 @@ class UnrealButtonComponent {
34
34
  event.preventDefault();
35
35
  this.clicked.emit(event);
36
36
  }
37
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
38
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.0", type: UnrealButtonComponent, isStandalone: true, selector: "app-unreal-button", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, weight: { classPropertyName: "weight", publicName: "weight", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null }, testID: { classPropertyName: "testID", publicName: "data-testid", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\r\n (click)=\"handleClick($event)\"\r\n [attr.data-testid]=\"testID() || null\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n [class.unreal-button--primary]=\"weight() === 'primary'\"\r\n [class.unreal-button--lg]=\"size() === 'lg'\"\r\n [class.unreal-button--full-width]=\"fullWidth()\"\r\n [disabled]=\"isDisabled()\"\r\n [type]=\"type()\"\r\n class=\"unreal-button\"\r\n>\r\n <span><ng-content></ng-content></span>\r\n</button>\r\n", styles: [".unreal-button{--unrealButtonHeight: 36px;--unrealButtonPaddings: 0 12px;--unrealButtonBorderRadius: 6px;--unrealButtonFontSize: var(--src-font-size-sm, 14px);--unrealButtonLineHeight: var(--src-font-line-sm, 20px);--unrealButtonWidth: auto;--unrealButtonBgColor: transparent;--unrealButtonBorderColor: var(--src-border-button-basic, #e5e7eb);--unrealButtonBorder: 1px solid var(--unrealButtonBorderColor);--unrealButtonFontColor: var(--src-text-ui-secondary-main, #111827);--unrealButtonFontWeight: var(--src-font-weight-medium, 500);--unrealButtonFocusRingSize: 4px;--unrealButtonFocusRingColor: var( --src-shadow-light, rgba(148, 163, 184, .16) );--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 1px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16));position:relative;display:flex;justify-content:center;align-items:center;width:var(--unrealButtonWidth);height:var(--unrealButtonHeight);padding:var(--unrealButtonPaddings);font-weight:var(--unrealButtonFontWeight);font-size:var(--unrealButtonFontSize);font-style:normal;line-height:var(--unrealButtonLineHeight);text-align:center;color:var(--unrealButtonFontColor);letter-spacing:0;white-space:nowrap;border:none;background-color:var(--unrealButtonBgColor);border-radius:var(--unrealButtonBorderRadius);box-shadow:var(--unrealButtonBoxShadow);cursor:pointer}.unreal-button:after{content:\"\";position:absolute;inset:0;border-radius:var(--unrealButtonBorderRadius);border:var(--unrealButtonBorder)}.unreal-button>span{display:flex;justify-content:center;align-items:center;gap:var(--src-gap-md, 6px);width:auto;font-size:inherit;line-height:inherit;color:inherit;font-weight:inherit}.unreal-button:disabled{--unrealButtonBgColor: var( --src-ui-accent-disabled, rgba(148, 163, 184, .24) );--unrealButtonFontColor: var(--src-text-ui-secondary-disabled, #9ca3af);--unrealButtonBoxShadow: none;--unrealButtonBorder: none;--unrealButtonBorderColor: transparent;cursor:default;pointer-events:none}.unreal-button:focus-visible{--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af);outline:none;box-shadow:0 0 0 var(--unrealButtonFocusRingSize) var(--unrealButtonFocusRingColor)}@media(pointer:fine){.unreal-button:hover{--unrealButtonBgColor: var( --src-ui-secondary-default-hover, rgba(148, 163, 184, .08) );--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af)}}.unreal-button--primary{--unrealButtonBgColor: var(--src-ui-accent-default, #017bff);--unrealButtonBorder: none;--unrealButtonFontColor: var(--src-text-ui-primary-main, #fff);--unrealButtonFocusRingColor: var( --src-shadow-accent-light, rgba(1, 123, 255, .16) )}@media(pointer:fine){.unreal-button--primary:hover{--unrealButtonBgColor: var(--src-ui-accent-default-hover, #016fe6);--unrealButtonFontColor: var(--src-text-ui-primary-main, #fff)}}.unreal-button--lg{--unrealButtonHeight: 44px;--unrealButtonPaddings: 0 16px;--unrealButtonBorderRadius: 8px;--unrealButtonFontSize: var(--src-font-size-base, 16px);--unrealButtonLineHeight: var(--src-font-line-base, 24px);--unrealButtonFocusRingSize: 6px;--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 2px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16))}.unreal-button--lg>span{gap:var(--src-gap-md, 8px)}.unreal-button--full-width{--unrealButtonWidth: 100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
37
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
38
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: UnrealButtonComponent, isStandalone: true, selector: "app-unreal-button", inputs: { type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, weight: { classPropertyName: "weight", publicName: "weight", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, isDisabled: { classPropertyName: "isDisabled", publicName: "isDisabled", isSignal: true, isRequired: false, transformFunction: null }, testID: { classPropertyName: "testID", publicName: "data-testid", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<button\n (click)=\"handleClick($event)\"\n [attr.data-testid]=\"testID() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n [class.unreal-button--primary]=\"weight() === 'primary'\"\n [class.unreal-button--lg]=\"size() === 'lg'\"\n [class.unreal-button--full-width]=\"fullWidth()\"\n [disabled]=\"isDisabled()\"\n [type]=\"type()\"\n class=\"unreal-button\"\n>\n <span><ng-content></ng-content></span>\n</button>\n", styles: [".unreal-button{--unrealButtonHeight: 36px;--unrealButtonPaddings: 0 12px;--unrealButtonBorderRadius: 6px;--unrealButtonFontSize: var(--src-font-size-sm, 14px);--unrealButtonLineHeight: var(--src-font-line-sm, 20px);--unrealButtonWidth: auto;--unrealButtonBgColor: transparent;--unrealButtonBorderColor: var(--src-border-button-basic, #e5e7eb);--unrealButtonBorder: 1px solid var(--unrealButtonBorderColor);--unrealButtonFontColor: var(--src-text-ui-secondary-main, #111827);--unrealButtonFontWeight: var(--src-font-weight-medium, 500);--unrealButtonFocusRingSize: 4px;--unrealButtonFocusRingColor: var( --src-shadow-light, rgba(148, 163, 184, .16) );--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 1px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16));position:relative;display:flex;justify-content:center;align-items:center;width:var(--unrealButtonWidth);height:var(--unrealButtonHeight);padding:var(--unrealButtonPaddings);font-weight:var(--unrealButtonFontWeight);font-size:var(--unrealButtonFontSize);font-style:normal;line-height:var(--unrealButtonLineHeight);text-align:center;color:var(--unrealButtonFontColor);letter-spacing:0;white-space:nowrap;border:none;background-color:var(--unrealButtonBgColor);border-radius:var(--unrealButtonBorderRadius);box-shadow:var(--unrealButtonBoxShadow);cursor:pointer}.unreal-button:after{content:\"\";position:absolute;inset:0;border-radius:var(--unrealButtonBorderRadius);border:var(--unrealButtonBorder)}.unreal-button>span{display:flex;justify-content:center;align-items:center;gap:var(--src-gap-md, 6px);width:auto;font-size:inherit;line-height:inherit;color:inherit;font-weight:inherit}.unreal-button:disabled{--unrealButtonBgColor: var( --src-ui-accent-disabled, rgba(148, 163, 184, .24) );--unrealButtonFontColor: var(--src-text-ui-secondary-disabled, #9ca3af);--unrealButtonBoxShadow: none;--unrealButtonBorder: none;--unrealButtonBorderColor: transparent;cursor:default;pointer-events:none}.unreal-button:focus-visible{--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af);outline:none;box-shadow:0 0 0 var(--unrealButtonFocusRingSize) var(--unrealButtonFocusRingColor)}@media(pointer:fine){.unreal-button:hover{--unrealButtonBgColor: var( --src-ui-secondary-default-hover, rgba(148, 163, 184, .08) );--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af)}}.unreal-button--primary{--unrealButtonBgColor: var(--unreal-accent, var(--src-ui-accent-default, #017bff));--unrealButtonBorder: none;--unrealButtonFontColor: var(--unreal-accent-text, var(--src-text-ui-primary-main, #fff));--unrealButtonFocusRingColor: var( --src-shadow-accent-light, rgba(1, 123, 255, .16) )}@media(pointer:fine){.unreal-button--primary:hover{--unrealButtonBgColor: var(--unreal-accent-hover, var(--src-ui-accent-default-hover, #016fe6));--unrealButtonFontColor: var(--unreal-accent-text, var(--src-text-ui-primary-main, #fff))}}.unreal-button--lg{--unrealButtonHeight: 44px;--unrealButtonPaddings: 0 16px;--unrealButtonBorderRadius: 8px;--unrealButtonFontSize: var(--src-font-size-base, 16px);--unrealButtonLineHeight: var(--src-font-line-base, 24px);--unrealButtonFocusRingSize: 6px;--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 2px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16))}.unreal-button--lg>span{gap:var(--src-gap-md, 8px)}.unreal-button--full-width{--unrealButtonWidth: 100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
39
39
  }
40
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealButtonComponent, decorators: [{
40
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealButtonComponent, decorators: [{
41
41
  type: Component,
42
- args: [{ selector: 'app-unreal-button', changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\r\n (click)=\"handleClick($event)\"\r\n [attr.data-testid]=\"testID() || null\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n [class.unreal-button--primary]=\"weight() === 'primary'\"\r\n [class.unreal-button--lg]=\"size() === 'lg'\"\r\n [class.unreal-button--full-width]=\"fullWidth()\"\r\n [disabled]=\"isDisabled()\"\r\n [type]=\"type()\"\r\n class=\"unreal-button\"\r\n>\r\n <span><ng-content></ng-content></span>\r\n</button>\r\n", styles: [".unreal-button{--unrealButtonHeight: 36px;--unrealButtonPaddings: 0 12px;--unrealButtonBorderRadius: 6px;--unrealButtonFontSize: var(--src-font-size-sm, 14px);--unrealButtonLineHeight: var(--src-font-line-sm, 20px);--unrealButtonWidth: auto;--unrealButtonBgColor: transparent;--unrealButtonBorderColor: var(--src-border-button-basic, #e5e7eb);--unrealButtonBorder: 1px solid var(--unrealButtonBorderColor);--unrealButtonFontColor: var(--src-text-ui-secondary-main, #111827);--unrealButtonFontWeight: var(--src-font-weight-medium, 500);--unrealButtonFocusRingSize: 4px;--unrealButtonFocusRingColor: var( --src-shadow-light, rgba(148, 163, 184, .16) );--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 1px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16));position:relative;display:flex;justify-content:center;align-items:center;width:var(--unrealButtonWidth);height:var(--unrealButtonHeight);padding:var(--unrealButtonPaddings);font-weight:var(--unrealButtonFontWeight);font-size:var(--unrealButtonFontSize);font-style:normal;line-height:var(--unrealButtonLineHeight);text-align:center;color:var(--unrealButtonFontColor);letter-spacing:0;white-space:nowrap;border:none;background-color:var(--unrealButtonBgColor);border-radius:var(--unrealButtonBorderRadius);box-shadow:var(--unrealButtonBoxShadow);cursor:pointer}.unreal-button:after{content:\"\";position:absolute;inset:0;border-radius:var(--unrealButtonBorderRadius);border:var(--unrealButtonBorder)}.unreal-button>span{display:flex;justify-content:center;align-items:center;gap:var(--src-gap-md, 6px);width:auto;font-size:inherit;line-height:inherit;color:inherit;font-weight:inherit}.unreal-button:disabled{--unrealButtonBgColor: var( --src-ui-accent-disabled, rgba(148, 163, 184, .24) );--unrealButtonFontColor: var(--src-text-ui-secondary-disabled, #9ca3af);--unrealButtonBoxShadow: none;--unrealButtonBorder: none;--unrealButtonBorderColor: transparent;cursor:default;pointer-events:none}.unreal-button:focus-visible{--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af);outline:none;box-shadow:0 0 0 var(--unrealButtonFocusRingSize) var(--unrealButtonFocusRingColor)}@media(pointer:fine){.unreal-button:hover{--unrealButtonBgColor: var( --src-ui-secondary-default-hover, rgba(148, 163, 184, .08) );--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af)}}.unreal-button--primary{--unrealButtonBgColor: var(--src-ui-accent-default, #017bff);--unrealButtonBorder: none;--unrealButtonFontColor: var(--src-text-ui-primary-main, #fff);--unrealButtonFocusRingColor: var( --src-shadow-accent-light, rgba(1, 123, 255, .16) )}@media(pointer:fine){.unreal-button--primary:hover{--unrealButtonBgColor: var(--src-ui-accent-default-hover, #016fe6);--unrealButtonFontColor: var(--src-text-ui-primary-main, #fff)}}.unreal-button--lg{--unrealButtonHeight: 44px;--unrealButtonPaddings: 0 16px;--unrealButtonBorderRadius: 8px;--unrealButtonFontSize: var(--src-font-size-base, 16px);--unrealButtonLineHeight: var(--src-font-line-base, 24px);--unrealButtonFocusRingSize: 6px;--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 2px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16))}.unreal-button--lg>span{gap:var(--src-gap-md, 8px)}.unreal-button--full-width{--unrealButtonWidth: 100%}\n"] }]
42
+ args: [{ selector: 'app-unreal-button', changeDetection: ChangeDetectionStrategy.OnPush, template: "<button\n (click)=\"handleClick($event)\"\n [attr.data-testid]=\"testID() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n [class.unreal-button--primary]=\"weight() === 'primary'\"\n [class.unreal-button--lg]=\"size() === 'lg'\"\n [class.unreal-button--full-width]=\"fullWidth()\"\n [disabled]=\"isDisabled()\"\n [type]=\"type()\"\n class=\"unreal-button\"\n>\n <span><ng-content></ng-content></span>\n</button>\n", styles: [".unreal-button{--unrealButtonHeight: 36px;--unrealButtonPaddings: 0 12px;--unrealButtonBorderRadius: 6px;--unrealButtonFontSize: var(--src-font-size-sm, 14px);--unrealButtonLineHeight: var(--src-font-line-sm, 20px);--unrealButtonWidth: auto;--unrealButtonBgColor: transparent;--unrealButtonBorderColor: var(--src-border-button-basic, #e5e7eb);--unrealButtonBorder: 1px solid var(--unrealButtonBorderColor);--unrealButtonFontColor: var(--src-text-ui-secondary-main, #111827);--unrealButtonFontWeight: var(--src-font-weight-medium, 500);--unrealButtonFocusRingSize: 4px;--unrealButtonFocusRingColor: var( --src-shadow-light, rgba(148, 163, 184, .16) );--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 1px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16));position:relative;display:flex;justify-content:center;align-items:center;width:var(--unrealButtonWidth);height:var(--unrealButtonHeight);padding:var(--unrealButtonPaddings);font-weight:var(--unrealButtonFontWeight);font-size:var(--unrealButtonFontSize);font-style:normal;line-height:var(--unrealButtonLineHeight);text-align:center;color:var(--unrealButtonFontColor);letter-spacing:0;white-space:nowrap;border:none;background-color:var(--unrealButtonBgColor);border-radius:var(--unrealButtonBorderRadius);box-shadow:var(--unrealButtonBoxShadow);cursor:pointer}.unreal-button:after{content:\"\";position:absolute;inset:0;border-radius:var(--unrealButtonBorderRadius);border:var(--unrealButtonBorder)}.unreal-button>span{display:flex;justify-content:center;align-items:center;gap:var(--src-gap-md, 6px);width:auto;font-size:inherit;line-height:inherit;color:inherit;font-weight:inherit}.unreal-button:disabled{--unrealButtonBgColor: var( --src-ui-accent-disabled, rgba(148, 163, 184, .24) );--unrealButtonFontColor: var(--src-text-ui-secondary-disabled, #9ca3af);--unrealButtonBoxShadow: none;--unrealButtonBorder: none;--unrealButtonBorderColor: transparent;cursor:default;pointer-events:none}.unreal-button:focus-visible{--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af);outline:none;box-shadow:0 0 0 var(--unrealButtonFocusRingSize) var(--unrealButtonFocusRingColor)}@media(pointer:fine){.unreal-button:hover{--unrealButtonBgColor: var( --src-ui-secondary-default-hover, rgba(148, 163, 184, .08) );--unrealButtonBorderColor: var(--src-border-button-basic-hover, #9ca3af)}}.unreal-button--primary{--unrealButtonBgColor: var(--unreal-accent, var(--src-ui-accent-default, #017bff));--unrealButtonBorder: none;--unrealButtonFontColor: var(--unreal-accent-text, var(--src-text-ui-primary-main, #fff));--unrealButtonFocusRingColor: var( --src-shadow-accent-light, rgba(1, 123, 255, .16) )}@media(pointer:fine){.unreal-button--primary:hover{--unrealButtonBgColor: var(--unreal-accent-hover, var(--src-ui-accent-default-hover, #016fe6));--unrealButtonFontColor: var(--unreal-accent-text, var(--src-text-ui-primary-main, #fff))}}.unreal-button--lg{--unrealButtonHeight: 44px;--unrealButtonPaddings: 0 16px;--unrealButtonBorderRadius: 8px;--unrealButtonFontSize: var(--src-font-size-base, 16px);--unrealButtonLineHeight: var(--src-font-line-base, 24px);--unrealButtonFocusRingSize: 6px;--unrealButtonBoxShadow: 0 -1px 0 0 var(--src-shadow-hard, rgba(71, 85, 105, .24)) inset, 0 2px 0 0 var(--src-shadow-light, rgba(148, 163, 184, .16))}.unreal-button--lg>span{gap:var(--src-gap-md, 8px)}.unreal-button--full-width{--unrealButtonWidth: 100%}\n"] }]
43
43
  }], propDecorators: { type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], weight: [{ type: i0.Input, args: [{ isSignal: true, alias: "weight", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], isDisabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "isDisabled", required: false }] }], testID: [{ type: i0.Input, args: [{ isSignal: true, alias: "data-testid", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], clicked: [{ type: i0.Output, args: ["clicked"] }] } });
44
44
 
45
+ function AnswerHandler(msg) {
46
+ this.onWebRtcAnswer$.next(msg);
47
+ }
48
+
49
+ function ConfigHandler(msg) {
50
+ this.onConfig$.next(msg);
51
+ //DO NOT REMOVE. Possible required in future for SFU
52
+ /*this.send({
53
+ type: OrchestrationMessageTypes.listStreamers,
54
+ correlationId: this.correlationId,
55
+ });*/
56
+ }
57
+
58
+ function IceCandidateHandler(msg) {
59
+ this.onWebRtcIce$.next(msg.candidate);
60
+ }
61
+
62
+ const scoped = (templateString) => `[UNREAL] ${templateString[0]}`;
63
+ const unrealCommandCallback = createAction(scoped `unreal command callback`, props());
64
+ const commandStarted = createAction(scoped `command started`, props());
65
+ const commandCompleted = createAction(scoped `command completed`, props());
66
+ const trackMixpanelEvent = createAction(scoped `track Mixpanel event`, props());
67
+ const trackTelemetryData = createAction(scoped `track telemetry data`, props());
68
+ const setMaxFps = createAction(scoped `change fps`, props());
69
+ const destroyRemoteConnections = createAction(scoped `destroyRemoteConnections`, props());
70
+ const destroyUnrealScene = createAction(scoped `destroyUnrealScene`);
71
+ const setCirrusConnected = createAction(scoped `cirrusConnected`);
72
+ const setCirrusDisconnected = createAction(scoped `cirrusDisconnected`);
73
+ const changeStatusMainVideoOnScene = createAction(scoped `change status main video on scene`, props());
74
+ const setAwsInstance = createAction(scoped `set aws instance`, props());
75
+ const setStatusMessage = createAction(scoped `set status message`, props());
76
+ const setStatusPercentSignallingServer = createAction(scoped `change status percent signalling server`, props());
77
+ const setFreezeFrame = createAction(scoped `set freeze frame`, props());
78
+ const setStreamClientCompanyId = createAction(scoped `set stream client company id`, props());
79
+ const setStreamViewId = createAction(scoped `set stream view id`, props());
80
+ const setIntroImageSrc = createAction(scoped `set intro image src`, props());
81
+ const setLoadingImageSrc = createAction(scoped `set loading image src`, props());
82
+ const setIntroVideoSrc = createAction(scoped `set intro video src`, props());
83
+ const resetIntroSrc = createAction(scoped `reset intro src`);
84
+ const setFreezeFrameFromVideo = createAction(scoped `set freeze frame from video`, props());
85
+ const setEstablishingConnection = createAction(scoped `set establishing connection`, props());
86
+ const dataChannelConnected = createAction(scoped `data channel connected`, props());
87
+ const dataChannelReady = createAction(scoped `dataChannelReady`);
88
+ const setConfig = createAction(scoped `set config`, props());
89
+ const disconnectStream = createAction(scoped `disconnectStream`, props());
90
+ const dropConnection = createAction(scoped `dropConnection`);
91
+ const setViewportReady = createAction(scoped `set viewport ready`);
92
+ const setViewportNotReady = createAction(scoped `set viewport not ready`);
93
+ const changeStreamResolutionAction = createAction(scoped `change stream resolution`, props());
94
+ const setSignalingName = createAction(scoped `set aws instanceName`, props());
95
+ const setOrchestrationParameters = createAction(scoped `set orchestration parameters`, props());
96
+ /**
97
+ * Dispatched when the orchestration server signals that the reserved
98
+ * instance is ready to serve the stream (`instanceReady` WS message).
99
+ * Carries the stream-machine coordinates — `originInstanceUri` is used to
100
+ * open the second (stream-machine) signalling socket. Also consumed by
101
+ * telemetry as a phase marker.
102
+ */
103
+ const instanceReady = createAction(scoped `instance ready`, props());
104
+ /**
105
+ * Dispatched when `RegionsPingService.getFastest()` begins — right
106
+ * before the region-list HTTP request goes out. Bookends the entire
107
+ * region-discovery flow together with {@link regionResolved}.
108
+ * Observability-only — no state change.
109
+ */
110
+ const regionPingFetchStart = createAction(scoped `region ping fetch start`);
111
+ /**
112
+ * Dispatched once `RegionsPingService.getProviders()` returns the region
113
+ * list — i.e., the fetch step is done and the actual per-region ping
114
+ * sweep is about to start. Splits the region-discovery waterfall into
115
+ * two legs: config fetch vs. ping sweep. Observability-only.
116
+ */
117
+ const regionPingFetchEnd = createAction(scoped `region ping fetch end`);
118
+ /**
119
+ * Dispatched once the closest region has been resolved by the
120
+ * regions-ping service. Carries every sampled ping RTT to the winning
121
+ * region (one entry per probe — `checkLatency` issues `ping_count`
122
+ * sequential pings per region) so consumers can inspect variance /
123
+ * jitter, not just the mean. Observability-only — no state change.
124
+ */
125
+ const regionResolved = createAction(scoped `region resolved`, props());
126
+ /**
127
+ * Dispatched around the HTTP polling roundup inside `getAwsInstance`
128
+ * (old orchestration flow). Only fires when polling is actually used
129
+ * (i.e., signaling URL is not a direct `ws://` / `wss://` endpoint).
130
+ * Observability-only — no state change.
131
+ */
132
+ const pollingStarted = createAction(scoped `polling started`);
133
+ const pollingEnded = createAction(scoped `polling ended`);
134
+ /**
135
+ * Dispatched once for every `retry()` attempt inside the signalling
136
+ * connect pipeline. Two kinds:
137
+ *
138
+ * - `'connect'` — outer retry around the whole connect pipeline
139
+ * (region ping → AWS instance → WebSocket). Fires when the WS
140
+ * errors (e.g. "WebSocket closed before open") and the entire
141
+ * pipeline is re-subscribed. See `SIGNALLING.md` — every one of
142
+ * these currently triggers a fresh region-ping storm.
143
+ * - `'orchestration'` — inner retry inside `getAwsInstance`,
144
+ * advancing `urlGen` to the next candidate signalling URL when
145
+ * polling fails or returns an error payload.
146
+ *
147
+ * Observability-only — no state change. Surfaces in the viewer's
148
+ * Anomalies table as `signaling_retry` rows so a session that
149
+ * needed N tries shows N entries with their reasons.
150
+ */
151
+ const signalingRetryAttempted = createAction(scoped `signaling retry attempted`, props());
152
+ /**
153
+ * Dispatched when the client has just sent an SDP answer back to Cirrus
154
+ * after receiving the server-initiated offer. Observability-only.
155
+ */
156
+ const answerSent = createAction(scoped `answer sent`);
157
+ const setOrchestrationMessage = createAction(scoped `set orchestration message`, props());
158
+ const setOrchestrationProgress = createAction(scoped `set orchestration progress`, props());
159
+ const setOrchestrationContext = createAction(scoped `set orchestration params`, props());
160
+ const updateCirrusInfo = createAction(scoped `set unrealInfo`, props());
161
+ const setLoopBackCommandIsCompleted = createAction(scoped `set loopBack command is completed`);
162
+ const setAfkTimerVisible = createAction(scoped `set afk timer visible`);
163
+ const setAfkTimerHide = createAction(scoped `set afk timer hide`);
164
+ const setAfkTimerCountdown = createAction(scoped `set afk timer count down`, props());
165
+ const showUnrealErrorMessage = createAction(scoped `show unreal error message`, props());
166
+ const initSignalling = createAction(scoped `init signalling`);
167
+ /**
168
+ * Dispatched when a prefetched connection parked on `window.__stream` by the
169
+ * `stream-prefetch.js` head-script is adopted instead of opening a fresh
170
+ * `connectToSignaling`. Marks cirrus connected and records the adopted machine
171
+ * in one transaction; the data channel / app-init chain then proceeds via
172
+ * `dataChannelConnected` dispatched from `WebRtcPlayerService`.
173
+ *
174
+ * Deliberately does NOT touch `streamClientCompanyId` / `streamViewId`: the host
175
+ * app (e.g. metabox) sets those authoritatively from its own data before
176
+ * `initSignalling`, and the prefetch script's ids are connection-internal only.
177
+ */
178
+ const streamAdopted = createAction(scoped `stream adopted`, props());
179
+ const startStream = createAction(scoped `startStream`, props());
180
+ const resetConfig = createAction(scoped `reset config`);
181
+ const resetAfk = createAction(scoped `reset afk action`);
182
+ const resetWarnTimeout = createAction(scoped `reset config warn timeout`);
183
+ /**
184
+ * Fan-in for "cancel an in-flight signalling attempt". Dispatched by the
185
+ * abortEstablishingConnection$ effect whenever any of these source actions
186
+ * fire: `setCirrusDisconnected` (cirrus dropped), `dropConnection` (user
187
+ * called drop), `destroyUnrealScene` (component teardown). Consumers
188
+ * (`SignallingService.abort$`, `setDataChannelTimeoutCheck$.abort$`) listen
189
+ * to this one action instead of the trio so the "abort" intent has a single
190
+ * named entry in Redux DevTools and one subscription site to update.
191
+ */
192
+ const abortEstablishingConnection = createAction(scoped `abortEstablishingConnection`);
193
+ const setUnrealPlaywrightConfig = createAction(scoped `set unreal playwright config`);
194
+ const saveAnalyticsEvent = createAction(scoped `save analytics event`, props());
195
+ /** Action to trigger WebRTC peer reconnection (keeps signaling connection) */
196
+ const reconnectPeer = createAction(scoped `reconnect peer`, props());
197
+ /** Action to reset the data channel state before reconnection */
198
+ const resetDataChannelForReconnect = createAction(scoped `reset data channel for reconnect`);
199
+ /** Action dispatched when peer reconnection succeeds */
200
+ const reconnectPeerSuccess = createAction(scoped `reconnect peer success`);
201
+ /** Action dispatched when all peer reconnection attempts are exhausted */
202
+ const reconnectPeerFailed = createAction(scoped `reconnect peer failed`, props());
203
+ /** Action dispatched when ICE connection state changes to failed/disconnected */
204
+ const iceConnectionFailed = createAction(scoped `ice connection failed`, props());
205
+ const forceResizeViewport = createAction(scoped `force resize viewport`);
206
+ const videoAdaptedToContainer = createAction(scoped `video adapted to container`);
207
+ const videoStreamInitialized = createAction(scoped `video stream initialized`);
208
+ const dropDC = createAction(scoped `drop data channel`);
209
+ const dropPC = createAction(scoped `drop peer connection`);
210
+ const showLoadingProgress = createAction(scoped `show loading progress`, props());
211
+ const showResumeStreamPopup = createAction(scoped `show resume stream popup`, props());
212
+ const showUserInactivityTimeoutPopup = createAction(scoped `show user inactivity timeout popup`, props());
213
+ const setUserInactivityTimeout = createAction(scoped `set user inactivity timeout`, props());
214
+ const resetUserInactivityTimeout = createAction(scoped `reset user inactivity timeout`);
215
+
216
+ const WSCloseCode_NORMAL_CLOSURE = 3000;
217
+ const WSCloseCode_NORMAL_AFK_TIMEOUT = 3001;
218
+ const WSCloseCode_NORMAL_MANUAL_DISCONNECT = 3002;
219
+ const WSCloseCode_FORCE_CIRRUS_CLOSE = 3003;
220
+ const WSCloseCode_UNKNOWN = 1000;
221
+ const WSCloseCode_CIRRUS_PLAYER_DISCONNECTED = 1001;
222
+ const WSCloseCode_CIRRUS_ABNORMAL_CLOSURE = 1006;
223
+ const WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR = 1013;
224
+ const WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER = 1011;
225
+ const WSCloseCodes = [
226
+ WSCloseCode_NORMAL_CLOSURE,
227
+ WSCloseCode_NORMAL_AFK_TIMEOUT,
228
+ WSCloseCode_NORMAL_MANUAL_DISCONNECT,
229
+ WSCloseCode_FORCE_CIRRUS_CLOSE,
230
+ WSCloseCode_UNKNOWN,
231
+ WSCloseCode_CIRRUS_PLAYER_DISCONNECTED,
232
+ WSCloseCode_CIRRUS_ABNORMAL_CLOSURE,
233
+ WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR,
234
+ WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER,
235
+ ];
236
+
237
+ const DisconnectReason = {
238
+ Afk: 'Afk',
239
+ None: 'None',
240
+ Destroy: 'Destroy',
241
+ DataChannelClosed: 'DataChannelClosed',
242
+ DataChannelTimeout: 'DataChannelTimeout',
243
+ WebRTCError: 'WebRTCError',
244
+ WebSocketError: 'WebSocketError',
245
+ WebSocketClose: 'WebSocketClose',
246
+ DropConnection: 'DropConnection',
247
+ OrchestrationPlayerDisconnected: 'OrchestrationPlayerDisconnected',
248
+ OrchestrationStreamerDisconnected: 'OrchestrationStreamerDisconnected',
249
+ IceConnectionFailed: 'IceConnectionFailed',
250
+ ReconnectFailed: 'ReconnectFailed',
251
+ NewConnectionAttempt: 'NewConnectionAttempt',
252
+ AbortEstablishingConnection: 'AbortEstablishingConnection',
253
+ };
254
+
255
+ /*
256
+ export interface RequestReservation extends InstanceMessageBase {
257
+ type: 'requestReservation';
258
+ }
259
+ */
260
+ const OrchestrationMessageTypes = {
261
+ error: 'error',
262
+ offer: 'offer',
263
+ answer: 'answer',
264
+ ssInfo: 'ssInfo',
265
+ config: 'config',
266
+ playerCount: 'playerCount',
267
+ iceCandidate: 'iceCandidate',
268
+ streamerList: 'streamerList',
269
+ requestStream: 'requestStream',
270
+ listStreamers: 'listStreamers',
271
+ instanceReady: 'instanceReady',
272
+ p2pEstablished: 'p2pEstablished',
273
+ instanceReserved: 'instanceReserved',
274
+ interruptClientStream: 'interruptClientStream',
275
+ };
276
+
45
277
  const SpecialKeyCodes = {
46
278
  BackSpace: 8,
47
279
  Shift: 16,
@@ -140,67 +372,6 @@ const InputOptions = {
140
372
  suppressBrowserKeys: true,
141
373
  };
142
374
 
143
- const WSCloseCode_NORMAL_CLOSURE = 3000;
144
- const WSCloseCode_NORMAL_AFK_TIMEOUT = 3001;
145
- const WSCloseCode_NORMAL_MANUAL_DISCONNECT = 3002;
146
- const WSCloseCode_FORCE_CIRRUS_CLOSE = 3003;
147
- const WSCloseCode_UNKNOWN = 1000;
148
- const WSCloseCode_CIRRUS_PLAYER_DISCONNECTED = 1001;
149
- const WSCloseCode_CIRRUS_ABNORMAL_CLOSURE = 1006;
150
- const WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR = 1013;
151
- const WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER = 1011;
152
- const WSCloseCodes = [
153
- WSCloseCode_NORMAL_CLOSURE,
154
- WSCloseCode_NORMAL_AFK_TIMEOUT,
155
- WSCloseCode_NORMAL_MANUAL_DISCONNECT,
156
- WSCloseCode_FORCE_CIRRUS_CLOSE,
157
- WSCloseCode_UNKNOWN,
158
- WSCloseCode_CIRRUS_PLAYER_DISCONNECTED,
159
- WSCloseCode_CIRRUS_ABNORMAL_CLOSURE,
160
- WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR,
161
- WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER,
162
- ];
163
-
164
- const DisconnectReason = {
165
- Afk: 'Afk',
166
- None: 'None',
167
- Destroy: 'Destroy',
168
- DataChannelClosed: 'DataChannelClosed',
169
- DataChannelTimeout: 'DataChannelTimeout',
170
- WebRTCError: 'WebRTCError',
171
- WebSocketError: 'WebSocketError',
172
- WebSocketClose: 'WebSocketClose',
173
- DropConnection: 'DropConnection',
174
- OrchestrationPlayerDisconnected: 'OrchestrationPlayerDisconnected',
175
- OrchestrationStreamerDisconnected: 'OrchestrationStreamerDisconnected',
176
- IceConnectionFailed: 'IceConnectionFailed',
177
- ReconnectFailed: 'ReconnectFailed',
178
- NewConnectionAttempt: 'NewConnectionAttempt',
179
- AbortEstablishingConnection: 'AbortEstablishingConnection',
180
- };
181
-
182
- /*
183
- export interface RequestReservation extends InstanceMessageBase {
184
- type: 'requestReservation';
185
- }
186
- */
187
- const OrchestrationMessageTypes = {
188
- error: 'error',
189
- offer: 'offer',
190
- answer: 'answer',
191
- ssInfo: 'ssInfo',
192
- config: 'config',
193
- playerCount: 'playerCount',
194
- iceCandidate: 'iceCandidate',
195
- streamerList: 'streamerList',
196
- requestStream: 'requestStream',
197
- listStreamers: 'listStreamers',
198
- instanceReady: 'instanceReady',
199
- p2pEstablished: 'p2pEstablished',
200
- instanceReserved: 'instanceReserved',
201
- interruptClientStream: 'interruptClientStream',
202
- };
203
-
204
375
  /** Disconnect reasons that should trigger remote connection cleanup. */
205
376
  const DESTROY_DISCONNECT_REASONS = [
206
377
  DisconnectReason.Afk,
@@ -300,160 +471,6 @@ const UnrealStatusMessage = {
300
471
  STARTING_YOUR_SESSION: 'Starting your session',
301
472
  };
302
473
 
303
- const scoped = (templateString) => `[UNREAL] ${templateString[0]}`;
304
- const unrealCommandCallback = createAction(scoped `unreal command callback`, props());
305
- const commandStarted = createAction(scoped `command started`, props());
306
- const commandCompleted = createAction(scoped `command completed`, props());
307
- const trackMixpanelEvent = createAction(scoped `track Mixpanel event`, props());
308
- const trackTelemetryData = createAction(scoped `track telemetry data`, props());
309
- const setMaxFps = createAction(scoped `change fps`, props());
310
- const destroyRemoteConnections = createAction(scoped `destroyRemoteConnections`, props());
311
- const destroyUnrealScene = createAction(scoped `destroyUnrealScene`);
312
- const setCirrusConnected = createAction(scoped `cirrusConnected`);
313
- const setCirrusDisconnected = createAction(scoped `cirrusDisconnected`);
314
- const changeStatusMainVideoOnScene = createAction(scoped `change status main video on scene`, props());
315
- const setAwsInstance = createAction(scoped `set aws instance`, props());
316
- const setStatusMessage = createAction(scoped `set status message`, props());
317
- const setStatusPercentSignallingServer = createAction(scoped `change status percent signalling server`, props());
318
- const setFreezeFrame = createAction(scoped `set freeze frame`, props());
319
- const setStreamClientCompanyId = createAction(scoped `set stream client company id`, props());
320
- const setStreamViewId = createAction(scoped `set stream view id`, props());
321
- const setIntroImageSrc = createAction(scoped `set intro image src`, props());
322
- const setLoadingImageSrc = createAction(scoped `set loading image src`, props());
323
- const setIntroVideoSrc = createAction(scoped `set intro video src`, props());
324
- const resetIntroSrc = createAction(scoped `reset intro src`);
325
- const setFreezeFrameFromVideo = createAction(scoped `set freeze frame from video`, props());
326
- const setEstablishingConnection = createAction(scoped `set establishing connection`, props());
327
- const dataChannelConnected = createAction(scoped `data channel connected`, props());
328
- const dataChannelReady = createAction(scoped `dataChannelReady`);
329
- const setConfig = createAction(scoped `set config`, props());
330
- const disconnectStream = createAction(scoped `disconnectStream`, props());
331
- const dropConnection = createAction(scoped `dropConnection`);
332
- const setViewportReady = createAction(scoped `set viewport ready`);
333
- const setViewportNotReady = createAction(scoped `set viewport not ready`);
334
- const changeStreamResolutionAction = createAction(scoped `change stream resolution`, props());
335
- const setSignalingName = createAction(scoped `set aws instanceName`, props());
336
- const setOrchestrationParameters = createAction(scoped `set orchestration parameters`, props());
337
- /**
338
- * Dispatched when the orchestration server signals that the reserved
339
- * instance is ready to serve the stream (`instanceReady` WS message).
340
- * Carries the stream-machine coordinates — `originInstanceUri` is used to
341
- * open the second (stream-machine) signalling socket. Also consumed by
342
- * telemetry as a phase marker.
343
- */
344
- const instanceReady = createAction(scoped `instance ready`, props());
345
- /**
346
- * Dispatched when `RegionsPingService.getFastest()` begins — right
347
- * before the region-list HTTP request goes out. Bookends the entire
348
- * region-discovery flow together with {@link regionResolved}.
349
- * Observability-only — no state change.
350
- */
351
- const regionPingFetchStart = createAction(scoped `region ping fetch start`);
352
- /**
353
- * Dispatched once `RegionsPingService.getProviders()` returns the region
354
- * list — i.e., the fetch step is done and the actual per-region ping
355
- * sweep is about to start. Splits the region-discovery waterfall into
356
- * two legs: config fetch vs. ping sweep. Observability-only.
357
- */
358
- const regionPingFetchEnd = createAction(scoped `region ping fetch end`);
359
- /**
360
- * Dispatched once the closest region has been resolved by the
361
- * regions-ping service. Carries every sampled ping RTT to the winning
362
- * region (one entry per probe — `checkLatency` issues `ping_count`
363
- * sequential pings per region) so consumers can inspect variance /
364
- * jitter, not just the mean. Observability-only — no state change.
365
- */
366
- const regionResolved = createAction(scoped `region resolved`, props());
367
- /**
368
- * Dispatched around the HTTP polling roundup inside `getAwsInstance`
369
- * (old orchestration flow). Only fires when polling is actually used
370
- * (i.e., signaling URL is not a direct `ws://` / `wss://` endpoint).
371
- * Observability-only — no state change.
372
- */
373
- const pollingStarted = createAction(scoped `polling started`);
374
- const pollingEnded = createAction(scoped `polling ended`);
375
- /**
376
- * Dispatched once for every `retry()` attempt inside the signalling
377
- * connect pipeline. Two kinds:
378
- *
379
- * - `'connect'` — outer retry around the whole connect pipeline
380
- * (region ping → AWS instance → WebSocket). Fires when the WS
381
- * errors (e.g. "WebSocket closed before open") and the entire
382
- * pipeline is re-subscribed. See `SIGNALLING.md` — every one of
383
- * these currently triggers a fresh region-ping storm.
384
- * - `'orchestration'` — inner retry inside `getAwsInstance`,
385
- * advancing `urlGen` to the next candidate signalling URL when
386
- * polling fails or returns an error payload.
387
- *
388
- * Observability-only — no state change. Surfaces in the viewer's
389
- * Anomalies table as `signaling_retry` rows so a session that
390
- * needed N tries shows N entries with their reasons.
391
- */
392
- const signalingRetryAttempted = createAction(scoped `signaling retry attempted`, props());
393
- /**
394
- * Dispatched when the client has just sent an SDP answer back to Cirrus
395
- * after receiving the server-initiated offer. Observability-only.
396
- */
397
- const answerSent = createAction(scoped `answer sent`);
398
- const setOrchestrationMessage = createAction(scoped `set orchestration message`, props());
399
- const setOrchestrationProgress = createAction(scoped `set orchestration progress`, props());
400
- const setOrchestrationContext = createAction(scoped `set orchestration params`, props());
401
- const updateCirrusInfo = createAction(scoped `set unrealInfo`, props());
402
- const setLoopBackCommandIsCompleted = createAction(scoped `set loopBack command is completed`);
403
- const setAfkTimerVisible = createAction(scoped `set afk timer visible`);
404
- const setAfkTimerHide = createAction(scoped `set afk timer hide`);
405
- const setAfkTimerCountdown = createAction(scoped `set afk timer count down`, props());
406
- const showUnrealErrorMessage = createAction(scoped `show unreal error message`, props());
407
- const initSignalling = createAction(scoped `init signalling`);
408
- /**
409
- * Dispatched when a prefetched connection parked on `window.__stream` by the
410
- * `stream-prefetch.js` head-script is adopted instead of opening a fresh
411
- * `connectToSignaling`. Marks cirrus connected and records the adopted machine
412
- * in one transaction; the data channel / app-init chain then proceeds via
413
- * `dataChannelConnected` dispatched from `WebRtcPlayerService`.
414
- *
415
- * Deliberately does NOT touch `streamClientCompanyId` / `streamViewId`: the host
416
- * app (e.g. metabox) sets those authoritatively from its own data before
417
- * `initSignalling`, and the prefetch script's ids are connection-internal only.
418
- */
419
- const streamAdopted = createAction(scoped `stream adopted`, props());
420
- const startStream = createAction(scoped `startStream`, props());
421
- const resetConfig = createAction(scoped `reset config`);
422
- const resetAfk = createAction(scoped `reset afk action`);
423
- const resetWarnTimeout = createAction(scoped `reset config warn timeout`);
424
- /**
425
- * Fan-in for "cancel an in-flight signalling attempt". Dispatched by the
426
- * abortEstablishingConnection$ effect whenever any of these source actions
427
- * fire: `setCirrusDisconnected` (cirrus dropped), `dropConnection` (user
428
- * called drop), `destroyUnrealScene` (component teardown). Consumers
429
- * (`SignallingService.abort$`, `setDataChannelTimeoutCheck$.abort$`) listen
430
- * to this one action instead of the trio so the "abort" intent has a single
431
- * named entry in Redux DevTools and one subscription site to update.
432
- */
433
- const abortEstablishingConnection = createAction(scoped `abortEstablishingConnection`);
434
- const setUnrealPlaywrightConfig = createAction(scoped `set unreal playwright config`);
435
- const saveAnalyticsEvent = createAction(scoped `save analytics event`, props());
436
- /** Action to trigger WebRTC peer reconnection (keeps signaling connection) */
437
- const reconnectPeer = createAction(scoped `reconnect peer`, props());
438
- /** Action to reset the data channel state before reconnection */
439
- const resetDataChannelForReconnect = createAction(scoped `reset data channel for reconnect`);
440
- /** Action dispatched when peer reconnection succeeds */
441
- const reconnectPeerSuccess = createAction(scoped `reconnect peer success`);
442
- /** Action dispatched when all peer reconnection attempts are exhausted */
443
- const reconnectPeerFailed = createAction(scoped `reconnect peer failed`, props());
444
- /** Action dispatched when ICE connection state changes to failed/disconnected */
445
- const iceConnectionFailed = createAction(scoped `ice connection failed`, props());
446
- const forceResizeViewport = createAction(scoped `force resize viewport`);
447
- const videoAdaptedToContainer = createAction(scoped `video adapted to container`);
448
- const videoStreamInitialized = createAction(scoped `video stream initialized`);
449
- const dropDC = createAction(scoped `drop data channel`);
450
- const dropPC = createAction(scoped `drop peer connection`);
451
- const showLoadingProgress = createAction(scoped `show loading progress`, props());
452
- const showResumeStreamPopup = createAction(scoped `show resume stream popup`, props());
453
- const showUserInactivityTimeoutPopup = createAction(scoped `show user inactivity timeout popup`, props());
454
- const setUserInactivityTimeout = createAction(scoped `set user inactivity timeout`, props());
455
- const resetUserInactivityTimeout = createAction(scoped `reset user inactivity timeout`);
456
-
457
474
  const COMMAND_EXILE_TIMEOUT_MS = 10_000;
458
475
  function exileExpiredCommands(commandsInProgress, idToRemove, now) {
459
476
  let remaining = commandsInProgress.filter(whereNot({ id: idToRemove }));
@@ -785,613 +802,210 @@ const unrealFeature = createFeature({
785
802
  reducer: unrealReducer,
786
803
  });
787
804
 
788
- class SubService {
789
- constructor() {
790
- this.destroyRef = inject(DestroyRef);
791
- this.destroy$ = new Subject();
792
- this.actions$ = inject(Actions);
793
- this.store = inject(Store);
794
- this.disconnect$ = this.store
795
- .select(unrealFeature.selectCirrusConnected)
796
- .pipe(skip(1), filter(Falsy), share());
797
- this.destroyRef.onDestroy(() => {
798
- this.destroy$.next();
799
- this.destroy$.complete();
800
- });
801
- }
802
- }
803
-
804
- function AnswerHandler(msg) {
805
- this.onWebRtcAnswer$.next(msg);
806
- }
807
-
808
- function ConfigHandler(msg) {
809
- this.onConfig$.next(msg);
810
- //DO NOT REMOVE. Possible required in future for SFU
811
- /*this.send({
812
- type: OrchestrationMessageTypes.listStreamers,
813
- correlationId: this.correlationId,
814
- });*/
815
- }
816
-
817
- function IceCandidateHandler(msg) {
818
- this.onWebRtcIce$.next(msg.candidate);
819
- }
820
-
821
- function InstanceReadyHandler(msg) {
822
- const payload = msg?.payload;
823
- if (!payload) {
824
- Logger.warn('instanceReady received without payload — ignoring');
825
- return;
826
- }
827
- if (!payload.originInstanceUri) {
828
- Logger.warn('instanceReady without originInstanceUri — ignoring');
829
- return;
830
- }
831
- // Emit for observability (telemetry) and store the stream-machine coords.
832
- this.store.dispatch(instanceReady(payload));
833
- // This is the answer `requestCirrusViaSocket` is waiting for: the Cirrus
834
- // address (`originInstanceUri`) plus the connection id to hand it. The socket
835
- // itself is opened by the shared `connectToCirrus`, not here.
836
- this.onInstanceReady$.next(payload);
837
- }
838
-
839
- function InstanceReservedHandler(msg) {
840
- this.store.dispatch(setOrchestrationParameters({
841
- instanceName: msg.payload.instanceId,
842
- streamRequestId: msg.payload.streamRequestId,
843
- eta: msg.payload.eta ?? 150,
844
- }));
805
+ /**
806
+ * `'metabox'` — the default when `UNREAL_CONFIG` omits `mode` — speaks the full
807
+ * Metabox command protocol. `'default'` targets a stock Pixel Streaming
808
+ * application, which understands no `MetaBoxCommand` packet, so the module
809
+ * sends none of its own.
810
+ */
811
+ function isMetaboxMode(config) {
812
+ return (config?.mode ?? 'metabox') === 'metabox';
845
813
  }
846
814
 
847
- function PlayerCountHandler(msg) {
848
- Logger.log(msg);
849
- }
850
-
851
- function SSInfoHandler(msg) {
852
- this.store.dispatch(updateCirrusInfo({ ssData: msg.data }));
853
- return null;
854
- }
855
-
856
- const dropCodes = [
857
- WSCloseCode_UNKNOWN,
858
- WSCloseCode_CIRRUS_PLAYER_DISCONNECTED,
859
- WSCloseCode_CIRRUS_ABNORMAL_CLOSURE,
860
- WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER,
861
- WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR,
862
- ];
863
- function OnCloseHandler(e) {
864
- const message = `WebSocket closed: ${JSON.stringify(e.code)} - ${e.reason}`;
865
- Logger.warn(message);
866
- this.store.dispatch(setCirrusDisconnected());
867
- if (dropCodes.includes(e.code)) {
868
- this.store.dispatch(dropConnection());
869
- }
870
- }
871
-
872
- function OnErrorHandler(e) {
873
- Logger.warn(`WS error: ${JSON.stringify(e)}`);
874
- this.store.dispatch(disconnectStream({
875
- reason: DisconnectReason.WebSocketError,
876
- message: 'WebSocket Error',
877
- }));
878
- }
879
-
880
- function OnMessageHandler(e) {
881
- const handleData = (data) => {
882
- //Logger.colored(...COLOR_CODES.FROM_SIGNALING, data);
883
- const msg = JSON.parse(data);
884
- this.handleMessage(msg);
885
- };
886
- if (typeof e.data === 'string') {
887
- try {
888
- handleData(e.data);
889
- }
890
- catch (err) {
891
- Logger.warn('OnMessageHandler: failed to parse string message', err);
892
- }
893
- }
894
- else if (e.data instanceof Blob) {
895
- e.data
896
- .text()
897
- .then(handleData)
898
- .catch((err) => Logger.warn('OnMessageHandler: failed to parse Blob message', err));
899
- }
900
- }
901
-
902
- /**
903
- * Open handler of the CIRRUS socket only (`addWsHandlers`), so
904
- * `setCirrusConnected` now means what it says. It used to also send
905
- * `requestStream` here, which made the flag fire on the orchestration control
906
- * socket — a whole provisioning wait (`eta`, ~150 s) before any Cirrus existed.
907
- * `requestStream` belongs to the control socket and is sent by
908
- * `requestCirrusViaSocket`.
909
- */
910
- function OnOpenHandler() {
911
- this.store.dispatch(setCirrusConnected());
912
- }
913
-
914
- /**
915
- * Keeps the max of numbers seen so far; resets to 0 whenever `reset$` emits.
916
- */
917
- const keepMaxUntilReset = (reset$) => (source$) => merge(source$, reset$.pipe(map(() => null))).pipe(scan((max, value) => (value === null ? 0 : Math.max(max, value)), 0));
918
-
919
- // Reused across every inbound data-channel message — instantiating a
920
- // TextDecoder per call adds needless GC churn on a hot path.
921
- const utf16Decoder = new TextDecoder('utf-16');
922
- function decodeData(anyData) {
923
- try {
924
- return utf16Decoder.decode(anyData);
925
- }
926
- catch {
927
- return '';
928
- }
929
- }
930
-
931
- const dispatchResize = () => {
932
- window.dispatchEvent(new Event('resize'));
933
- };
934
-
935
- const errorCodes = {
936
- code404: 'Your asset is being synced on Metabox servers and is not yet available in Metabox Studio or Metabox Configurator. Please check again later after syncing is complete. ',
937
- };
938
- function getRtcErrorMessage(code) {
939
- if (code === null) {
940
- return undefined;
941
- }
942
- return errorCodes[`code${code}`];
943
- }
944
-
945
- const JUMP_THRESHOLD = 0.95;
946
- const MAX_TRANSITION_DURATION_MS = 200;
947
815
  /**
948
- * Maps a 0..1 stream directly to a 0..100 integer percent stream.
949
- * No animation — emits whatever the source emits, rounded and clamped.
816
+ * Fraction of commands completed (0–1). Drives the second half of the
817
+ * loading bar, after signaling reaches `SIGNALLING_PERCENT_VALUE`.
950
818
  */
951
- const floatToPercents = () => (source) => source.pipe(map$1((value) => clampf(0, 100, Math.round(value * 100))));
819
+ const selectCommandProgress = createSelector(unrealFeature.selectTotalCommandsStarted, unrealFeature.selectTotalCommandsCompleted, (started, completed) => (started ? completed / started : 0));
820
+ const selectFreezeFrameDataUrlFromVideo = createSelector(unrealFeature.selectFreezeFrameFromVideo, (freezeFrameFromVideo) => freezeFrameFromVideo?.dataUrl || null);
821
+ const selectFreezeFrameProgressMessageFromVideo = createSelector(unrealFeature.selectFreezeFrameFromVideo, (freezeFrameFromVideo) => freezeFrameFromVideo?.progress || null);
822
+ const selectFreezeFrameDataUrl = createSelector(unrealFeature.selectFreezeFrame, (freezeFrame) => (freezeFrame?.dataUrl ? freezeFrame?.dataUrl : null));
823
+ const selectIsFreezeFrameLoading = createSelector(unrealFeature.selectFreezeFrame, (freezeFrame) => freezeFrame?.progress
824
+ ? freezeFrame.progress > 0 && freezeFrame.progress < 1
825
+ : false);
826
+ const selectFreezeFrameCombinedDataUrl = createSelector(selectFreezeFrameDataUrlFromVideo, selectFreezeFrameDataUrl, (dataUrlFromVideo, remoteDataUrl) => dataUrlFromVideo || remoteDataUrl || null);
827
+ const selectStreamConfig = createSelector(unrealFeature.selectStreamConfig, (config) => config);
828
+ const selectWarnTimeout = createSelector(selectStreamConfig, (config) => config?.warnTimeout || DEFAULT_AFK_TIMEOUT);
829
+ const selectIsExistMatchUrls = createSelector(unrealFeature.selectMatchUrls, (urls) => urls?.length > 0);
830
+ const selectIsAutostart = createSelector(selectStreamConfig, (config) => config?.autoStart);
831
+ const selectShowReconnectPopup = createSelector(unrealFeature.selectCirrusConnected, unrealFeature.selectEstablishingConnection, (cirrusConnected, establishingConnection) => !cirrusConnected && !establishingConnection);
832
+ const selectShowLoader = createSelector(selectShowReconnectPopup, unrealFeature.selectViewportReady, (showPopup, viewportReady) => !showPopup && !viewportReady);
952
833
  /**
953
- * Maps a 0..1 progress stream to a smoothed 0..100 integer percent stream.
954
- * Animates between consecutive values over up to 200ms; jumps directly when
955
- * the delta exceeds 0.95 (treated as a reset, not a real progression).
834
+ * The connection id of the current stream session.
835
+ *
836
+ * The id is issued on the Cirrus side and reaches us either as the
837
+ * orchestration's `streamRequestId` (polling response / `instanceReserved` /
838
+ * `instanceReady`) or, when the backend issues none, in the `ssInfo` message
839
+ * once Cirrus generated it itself. Inside the player it is ONE value —
840
+ * `connectionId` — and this selector is where the two arrival paths collapse
841
+ * into it. It names the session everywhere: the debug overlay ("Connection Id")
842
+ * and the stream telemetry's `sessionId`.
843
+ *
844
+ * Also used by external consumers (e.g., metabox). Do not remove.
956
845
  */
957
- const floatToSmoothPercents = () => (source) => source.pipe(timestamp(), startWith({ value: 0, timestamp: 0 }), pairwise(), concatMap(([prev, curr]) => {
958
- const isJump = Math.abs(curr.value - prev.value) > JUMP_THRESHOLD;
959
- const dt = prev.timestamp ? curr.timestamp - prev.timestamp : 0;
960
- if (isJump || dt === 0) {
961
- return of(curr.value);
846
+ const selectCirrusConnectionId = createSelector(unrealFeature.selectAwsInstance, unrealFeature.selectSsData, (awsInstance, ssData) => awsInstance?.streamRequestId ?? ssData?.connectionId);
847
+ const selectSignalingParameters = createSelector(unrealFeature.selectSsData, unrealFeature.selectAwsInstance, selectCirrusConnectionId, (data, instance, connectionId) => {
848
+ const info = [];
849
+ if (data) {
850
+ info.push(`${data.cirrusVersion}, ${data.branchInfo}, ${data.instanceType}`);
851
+ info.push(`Unreal App Version: ${data.streamerVersion}`);
852
+ info.push(`APP: ${data.streamPath}${data.streamApp}`);
962
853
  }
963
- return smoothTransition(prev.value, curr.value, Math.min(dt, MAX_TRANSITION_DURATION_MS));
964
- }), floatToPercents());
854
+ // The endpoint that handed us the Cirrus address: an HTTP polling URL in one
855
+ // flow, a `wss://` orchestration URL in the other.
856
+ info.push(`Orchestration: ${instance.pollingUrl}`);
857
+ info.push(`WS: ${instance.wsUrl}`);
858
+ // The stream's `connectionId` — the telemetry ships it as its `sessionId`
859
+ // (a file name on the collector), and the viewer labels it `Connection Id`
860
+ // too, so the same value is named the same thing everywhere.
861
+ info.push(`Connection Id: ${connectionId ?? '—'}`);
862
+ return info.join('<br>');
863
+ });
864
+ const selectClientAndViewIds = createSelector(unrealFeature.selectStreamClientCompanyId, unrealFeature.selectStreamViewId, (clientId, viewId) => ({ clientId, viewId }));
865
+ const selectIsFullyConnected = createSelector(unrealFeature.selectViewportReady, unrealFeature.selectDataChannelConnected, unrealFeature.selectCirrusConnected, (viewportReady, dataChannelConnected, cirrusConnected) => viewportReady && dataChannelConnected && cirrusConnected);
866
+ const selectIsLoaderScreenVisible = createSelector(selectIsFullyConnected, (fullyConnected) => !fullyConnected);
965
867
  /**
966
- * Smoothly interpolates from `start` to `end` over `duration`ms using the
967
- * animation frame scheduler. Completes when the transition finishes.
868
+ * Returns Scene load progress as a float value between 0 and 1.
968
869
  *
969
- * NOTE: duplicates `smoothTransition` from `@3dsource/utils`. The utils version
970
- * is missing `takeWhile(... < 1, true)` and never completes — which would
971
- * deadlock the `concatMap` above. Keep this local copy until utils is fixed.
972
- * Not exported: internal to `floatToSmoothPercents`.
870
+ * Progress is split into two phases:
871
+ * 1. **Signaling** (0 → ~56%): connection polling or orchestration progress.
872
+ * Starts at 0.1%, so the bar is never visually empty while connecting.
873
+ * 2. **Commands** (~56% → 100%): Unreal command progress after the data channel connects.
874
+ *
875
+ * The split point bumps by +1% once the WebSocket URL is known,
876
+ * producing a small visual step that indicates the WS handshake succeeded.
973
877
  */
974
- const smoothTransition = (start, end, duration) => {
975
- const startTime = animationFrameScheduler.now();
976
- return interval(0, animationFrameScheduler).pipe(map$1(() => clampf(0, 1, (animationFrameScheduler.now() - startTime) / duration)), distinctUntilChanged(), takeWhile((fraction) => fraction < 1, true), map$1((fraction) => lerp(start, end, fraction)));
977
- };
878
+ const selectTotalProgress = createSelector(unrealFeature.selectStatusPercentSignallingServer, selectCommandProgress, unrealFeature.selectAwsInstance, unrealFeature.selectDataChannelConnected, (statusPercentSignallingServer, commandProgress, awsInstance, dataChannelConnected) => {
879
+ const SIGNALLING_MAX = SIGNALLING_PERCENT_VALUE / 100;
880
+ // Stated by the service (`AwsInstance.kind`), not sniffed from the hostname.
881
+ // In the socket flow it is set by `instanceReserved` — i.e. before
882
+ // `setAwsInstance` — so the eta-driven bar is picked up from the start of
883
+ // the provisioning wait.
884
+ const isNewOrchestration = awsInstance?.kind === 'socket';
885
+ // Once the data channel is connected, signaling is fully complete (1.0) —
886
+ // regardless of orchestration type. This is what makes an ADOPTED stream
887
+ // (which never set `statusPercentSignallingServer`) correctly show the whole
888
+ // first phase done instead of stalling near the command-only value.
889
+ // Otherwise: new orchestration reports 0–1 progress; legacy uses the
890
+ // polling percent.
891
+ const signalingProgress = dataChannelConnected
892
+ ? 1
893
+ : isNewOrchestration
894
+ ? (awsInstance?.progressComplete ?? 0)
895
+ : (statusPercentSignallingServer ?? 0) / 100;
896
+ // +1% bump once WS URL is known (visual step for WS handshake)
897
+ const splitPoint = awsInstance?.wsUrl
898
+ ? SIGNALLING_MAX + 0.01
899
+ : SIGNALLING_MAX;
900
+ // 0.001 minimum so the bar is never completely empty while loading
901
+ const progressSignaling = lerp(0.001, splitPoint, signalingProgress);
902
+ const progressRest = lerp(0, 1 - splitPoint, commandProgress);
903
+ return clampf(0, 1, progressSignaling + progressRest);
904
+ });
905
+ /** Used by external consumers (e.g., metabox). Do not remove. */
906
+ const selectUserInactivityDetected = createSelector(unrealFeature.selectAfkCountdown, unrealFeature.selectIsAfkTimerVisible, (remainingSecondsToDisconnect, countdownVisible) => ({
907
+ remainingSecondsToDisconnect,
908
+ countdownVisible,
909
+ }));
910
+ /** Used by external consumers (e.g., metabox). Do not remove. */
911
+ const selectIsVideoPlayingAndDataChannelConnected = createSelector(unrealFeature.selectIsVideoPlaying, unrealFeature.selectDataChannelConnected, (isVideoPlaying, isDataChannelConnected) => isVideoPlaying && isDataChannelConnected);
978
912
 
979
- const getImageFromVideoStream = (takeSizeFrom = 'video', imageOutput, sizes) => {
980
- try {
981
- const video = document.getElementById(STREAMING_VIDEO_ID);
982
- const { canvas, ctx } = getCanvasCached('video');
983
- canvas.width =
984
- takeSizeFrom === 'video'
985
- ? sizes?.width || video?.clientWidth || FULL_HD_WIDTH
986
- : FULL_HD_WIDTH;
987
- canvas.height =
988
- takeSizeFrom === 'video'
989
- ? sizes?.height || video?.clientHeight || FULL_HD_HEIGHT
990
- : FULL_HD_HEIGHT;
991
- ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
992
- return getSnapshot(canvas, canvas.width, imageOutput);
913
+ class WebrtcErrorModalComponent {
914
+ constructor() {
915
+ this.#dialogRef = inject(DialogRef);
916
+ this.#store = inject(Store);
917
+ this.isCirrusConnected = inject(Store).selectSignal(unrealFeature.selectCirrusConnected);
993
918
  }
994
- catch {
995
- return null;
919
+ #dialogRef;
920
+ #store;
921
+ closeModalWithCirrusDisconnect() {
922
+ if (!this.isCirrusConnected()) {
923
+ this.#store.dispatch(disconnectStream({
924
+ reason: DisconnectReason.DropConnection,
925
+ message: 'Modal Drop Connection',
926
+ }));
927
+ }
928
+ this.close();
996
929
  }
997
- };
998
-
999
- /**
1000
- * Generator that cycles through `urls` indefinitely. Each call to
1001
- * `getActiveUrl(urls)` returns a fresh generator with its own counter,
1002
- * so concurrent generators (e.g., overlapping reconnect attempts) do
1003
- * not share state. The counter is initialized once per generator
1004
- * instance — before any `yield` — so each `.next()` call advances
1005
- * within that single generator.
1006
- */
1007
- function* getActiveUrl(urls) {
1008
- let index = 0;
1009
- while (true) {
1010
- yield urls[index++ % urls.length];
930
+ close() {
931
+ this.#dialogRef.close();
1011
932
  }
933
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WebrtcErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
934
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: WebrtcErrorModalComponent, isStandalone: true, selector: "app-webrtc-error-modal", ngImport: i0, template: "<div [attr.data-testid]=\"'webrtc-error-modal'\" class=\"unreal-modal\">\n <header class=\"unreal-modal__header\"></header>\n <section class=\"unreal-modal__body\">\n <div [attr.data-testid]=\"'title'\" class=\"unreal-modal__title\">\n WebRTC error\n </div>\n <div style=\"text-align: left\">\n An internet connection type (WebRTC) appears to be blocked either by your\n browser settings or your current network. If WebRTC is blocked on your\n browser you may be able to adjust these settings yourself based on\n instructions here:\n <a href=\"https://myownconference.com/blog/en/webrtc/\" target=\"blank\"\n >https://myownconference.com/blog/en/webrtc/</a\n >\n <br /><br />\n Trying a different web browser may help confirm this as well. If WebRTC is\n blocked by your network, try switching to a different network if possible\n or contact your network administrator.<br /><br />\n WebRTC is common, safe and increasingly utilised method for streaming real\n time 3D experiences via a web browser. It typically consumes no more\n bandwidth than streaming an HD video.\n </div>\n </section>\n <footer class=\"unreal-modal__footer\">\n <app-unreal-button\n (clicked)=\"closeModalWithCirrusDisconnect()\"\n [data-testid]=\"'close-webrtc-error-modal'\"\n weight=\"primary\"\n >\n Ok\n </app-unreal-button>\n </footer>\n</div>\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__body{width:100%}.unreal-modal .unreal-modal__body p{color:var(--src-text-body-main, #1f2937);font-size:14px;font-style:normal;font-weight:400;line-height:24px;margin-top:0}.unreal-modal .unreal-modal__body a{word-wrap:break-word;white-space:normal}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1012
935
  }
936
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WebrtcErrorModalComponent, decorators: [{
937
+ type: Component,
938
+ args: [{ selector: 'app-webrtc-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "<div [attr.data-testid]=\"'webrtc-error-modal'\" class=\"unreal-modal\">\n <header class=\"unreal-modal__header\"></header>\n <section class=\"unreal-modal__body\">\n <div [attr.data-testid]=\"'title'\" class=\"unreal-modal__title\">\n WebRTC error\n </div>\n <div style=\"text-align: left\">\n An internet connection type (WebRTC) appears to be blocked either by your\n browser settings or your current network. If WebRTC is blocked on your\n browser you may be able to adjust these settings yourself based on\n instructions here:\n <a href=\"https://myownconference.com/blog/en/webrtc/\" target=\"blank\"\n >https://myownconference.com/blog/en/webrtc/</a\n >\n <br /><br />\n Trying a different web browser may help confirm this as well. If WebRTC is\n blocked by your network, try switching to a different network if possible\n or contact your network administrator.<br /><br />\n WebRTC is common, safe and increasingly utilised method for streaming real\n time 3D experiences via a web browser. It typically consumes no more\n bandwidth than streaming an HD video.\n </div>\n </section>\n <footer class=\"unreal-modal__footer\">\n <app-unreal-button\n (clicked)=\"closeModalWithCirrusDisconnect()\"\n [data-testid]=\"'close-webrtc-error-modal'\"\n weight=\"primary\"\n >\n Ok\n </app-unreal-button>\n </footer>\n</div>\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__body{width:100%}.unreal-modal .unreal-modal__body p{color:var(--src-text-body-main, #1f2937);font-size:14px;font-style:normal;font-weight:400;line-height:24px;margin-top:0}.unreal-modal .unreal-modal__body a{word-wrap:break-word;white-space:normal}\n"] }]
939
+ }] });
1013
940
 
1014
- class LatencyTimings {
941
+ class SubService {
1015
942
  constructor() {
1016
- this.TestStartTimeMs = null;
1017
- this.UEReceiptTimeMs = null;
1018
- this.UEEncodeMs = null;
1019
- this.UECaptureToSendMs = null;
1020
- this.UETransmissionTimeMs = null;
1021
- this.BrowserReceiptTimeMs = null;
1022
- this.FrameDisplayDeltaTimeMs = null;
1023
- }
1024
- Reset() {
1025
- this.TestStartTimeMs = null;
1026
- this.UEReceiptTimeMs = null;
1027
- this.UEEncodeMs = null;
1028
- this.UECaptureToSendMs = null;
1029
- this.UETransmissionTimeMs = null;
1030
- this.BrowserReceiptTimeMs = null;
1031
- this.FrameDisplayDeltaTimeMs = null;
943
+ this.destroyRef = inject(DestroyRef);
944
+ this.destroy$ = new Subject();
945
+ this.actions$ = inject(Actions);
946
+ this.store = inject(Store);
947
+ this.disconnect$ = this.store
948
+ .select(unrealFeature.selectCirrusConnected)
949
+ .pipe(skip(1), filter(Falsy), share());
950
+ this.destroyRef.onDestroy(() => {
951
+ this.destroy$.next();
952
+ this.destroy$.complete();
953
+ });
1032
954
  }
1033
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1034
- SetUETimings(UETimings) {
1035
- this.UEReceiptTimeMs = UETimings.ReceiptTimeMs;
1036
- this.UEEncodeMs = UETimings.EncodeMs;
1037
- this.UECaptureToSendMs = UETimings.CaptureToSendMs;
1038
- this.UETransmissionTimeMs = UETimings.TransmissionTimeMs;
1039
- this.BrowserReceiptTimeMs = Date.now();
955
+ }
956
+
957
+ class CommandTelemetryService extends SubService {
958
+ constructor() {
959
+ super();
960
+ this.appId = 'metabox-telemetry';
961
+ this.commandsSent = {};
962
+ this.exileTimeout = 60000;
963
+ this.pollingTime = 5000;
964
+ this.commandSequenceNumber = 0;
965
+ this.payloads = [];
966
+ this.httpClient = inject(HttpClient);
967
+ this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
968
+ this.init();
1040
969
  }
1041
- SetFrameDisplayDeltaTime(DeltaTimeMs) {
1042
- if (this.FrameDisplayDeltaTimeMs == null) {
1043
- this.FrameDisplayDeltaTimeMs = Math.round(DeltaTimeMs);
970
+ init() {
971
+ if (!this.unrealConfig?.commandTelemetryReceiver ||
972
+ this.unrealConfig?.playwright) {
973
+ return;
1044
974
  }
975
+ this.reset();
976
+ this.sessionId = sessionStorage.getItem(this.appId) || this.uuid;
977
+ this.userId = localStorage.getItem(this.appId) || this.uuid;
978
+ sessionStorage.setItem(this.appId, this.sessionId);
979
+ localStorage.setItem(this.appId, this.userId);
980
+ timer(0, this.pollingTime)
981
+ .pipe(takeUntil(this.destroy$))
982
+ .subscribe(() => {
983
+ this.send(this.payloads);
984
+ });
1045
985
  }
1046
- }
1047
-
1048
- function qpToQuality(VideoEncoderQP) {
1049
- const orangeQP = 26;
1050
- const redQP = 35;
1051
- let quality = 'lime';
1052
- if (VideoEncoderQP > redQP) {
1053
- quality = 'red';
986
+ get timeNow() {
987
+ return Date.now();
1054
988
  }
1055
- else if (VideoEncoderQP > orangeQP) {
1056
- quality = 'orange';
989
+ get sessionTime() {
990
+ return this.timeNow - this.startTime;
1057
991
  }
1058
- return quality;
1059
- }
1060
-
1061
- /**
1062
- * Base64-encodes a byte array.
1063
- *
1064
- * Builds the intermediate binary string in fixed-size chunks instead of
1065
- * concatenating one character at a time. The naive `bytes.reduce((s, b) => s +
1066
- * String.fromCharCode(b), '')` is O(n²) (each `+` re-copies the growing string)
1067
- * and stalls the main thread for a full-resolution frame; chunking keeps it
1068
- * O(n). The chunk size stays under the argument-count limit of
1069
- * `String.fromCharCode.apply`/spread.
1070
- *
1071
- * @param bytes - The raw bytes to encode.
1072
- * @returns The Base64 representation of `bytes`.
1073
- */
1074
- function uint8ToBase64(bytes) {
1075
- const CHUNK_SIZE = 0x8000;
1076
- let binary = '';
1077
- for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {
1078
- binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK_SIZE));
992
+ get canSkipSending() {
993
+ return !(this.timeNow - this.lastTime > this.pollingTime * 2);
1079
994
  }
1080
- return btoa(binary);
1081
- }
1082
-
1083
- function fromResizeObserver(elem) {
1084
- return new Observable((subscriber) => {
1085
- const observer = new window.ResizeObserver((entries) => subscriber.next(entries));
1086
- observer.observe(elem);
1087
- return () => observer.unobserve(elem);
1088
- });
1089
- }
1090
-
1091
- /*
1092
- * Copyright (c) 2026.
1093
- * 3DSource.com. Sergii Karanda steve@3dsource.com. All Rights Reserved.
1094
- */
1095
- /**
1096
- * Rounds a number to the nearest even integer (rounding up for odd values).
1097
- *
1098
- * Video encoders (H.264/H.265) require even dimensions because chroma subsampling
1099
- * operates on 2×2 pixel blocks. Odd dimensions cause encoding artifacts or failures.
1100
- *
1101
- * @param value - The number to round to the nearest even integer.
1102
- * @returns The nearest even integer greater than or equal to the input.
1103
- *
1104
- * @example
1105
- * makeEven(1079) // 1080
1106
- * makeEven(1080) // 1080
1107
- * makeEven(1081) // 1082
1108
- */
1109
- function makeEven(value) {
1110
- return Math.floor((value + 1) / 2) * 2;
1111
- }
1112
-
1113
- const FULL_HD_PIXELS = FULL_HD_WIDTH * FULL_HD_HEIGHT;
1114
- const UHD_PIXELS = FULL_HD_WIDTH * 2 * (FULL_HD_HEIGHT * 2);
1115
- /**
1116
- * Calculates the optimal stream resolution for studio mode.
1117
- *
1118
- * Fits the studio aspect ratio into the container (scaled by pixelRatio), then
1119
- * caps the total pixel count to a budget (Full HD or 4K) to avoid overloading
1120
- * the GPU/encoder while maximizing visual quality.
1121
- *
1122
- * The pixel budget approach (instead of per-dimension caps) ensures that
1123
- * non-standard aspect ratios (portrait, ultra-wide, square) utilize available
1124
- * pixels efficiently — e.g. a tall 1080×1920 stream uses the same pixel budget
1125
- * as a wide 1920×1080 stream.
1126
- *
1127
- * Resolution is always capped at the studio dimensions — never upscaled beyond
1128
- * what the Unreal scene was designed for.
1129
- *
1130
- * @param params.pixelRatio - Device pixel ratio (`window.devicePixelRatio`).
1131
- * @param params.containerWidth - CSS width of the video container in pixels.
1132
- * @param params.containerHeight - CSS height of the video container in pixels.
1133
- * @param params.studioWidth - Target width of the MetaBox Studio scene.
1134
- * @param params.studioHeight - Target height of the MetaBox Studio scene.
1135
- * @param params.maxResolution - When `true`, uses 4K pixel budget (3840×2160);
1136
- * otherwise Full HD (1920×1080). Controlled by `?maxresolution` query param.
1137
- * @returns An {@link Area} with the calculated `w`, `h`, position (`x`, `y`),
1138
- * and `scale` factor relative to the container's device-pixel size.
1139
- */
1140
- function getResizeStudioValues(params) {
1141
- const { pixelRatio, containerWidth, containerHeight, studioWidth, studioHeight, maxResolution, } = params;
1142
- const maxSpace = {
1143
- w: containerWidth * pixelRatio,
1144
- h: containerHeight * pixelRatio,
1145
- };
1146
- const maxPixels = maxResolution ? UHD_PIXELS : FULL_HD_PIXELS;
1147
- const videoSizePixelPerfect = fitIntoRectangle({ x: 0, y: 0, w: studioWidth, h: studioHeight }, { x: 0, y: 0, ...maxSpace });
1148
- let w = videoSizePixelPerfect.w;
1149
- let h = videoSizePixelPerfect.h;
1150
- if (w * h > maxPixels) {
1151
- // Derive uniform scale factor `s` from: (w*s) * (h*s) = maxPixels
1152
- // → w * h * s² = maxPixels → s = √(maxPixels / (w * h)).
1153
- // Applying the same `s` to both dimensions preserves the aspect ratio.
1154
- const scaleFactor = Math.sqrt(maxPixels / (w * h));
1155
- w = w * scaleFactor;
1156
- h = h * scaleFactor;
995
+ decorate(funcToDecorate) {
996
+ this.listenCallbacks();
997
+ return this.wrapper.bind(this, funcToDecorate);
1157
998
  }
1158
- const out = fitIntoRectangle(videoSizePixelPerfect, {
1159
- x: videoSizePixelPerfect.x,
1160
- y: videoSizePixelPerfect.y,
1161
- w,
1162
- h,
1163
- });
1164
- out.w = makeEven(out.w);
1165
- out.h = makeEven(out.h);
1166
- return out;
1167
- }
1168
- /**
1169
- * Calculates the optimal stream resolution for configurator (non-studio) mode.
1170
- *
1171
- * Uses the full container area (scaled by pixelRatio) as the stream resolution,
1172
- * then caps total pixel count to a budget (Full HD or 4K) to prevent excessive
1173
- * GPU/encoder load while preserving the container's aspect ratio.
1174
- *
1175
- * Unlike {@link getResizeStudioValues}, there is no fixed studio resolution to
1176
- * fit into — the container itself defines the aspect ratio, and the stream fills
1177
- * it entirely (no letterboxing).
1178
- *
1179
- * @param params.pixelRatio - Device pixel ratio (`window.devicePixelRatio`).
1180
- * @param params.containerWidth - CSS width of the video container in pixels.
1181
- * @param params.containerHeight - CSS height of the video container in pixels.
1182
- * @param params.maxResolution - When `true`, uses 4K pixel budget (3840×2160);
1183
- * otherwise Full HD (1920×1080). Controlled by `?maxresolution` query param.
1184
- * @returns An {@link Area} with the calculated `w`, `h`, position (`x`, `y`),
1185
- * and `scale` factor (1 when no downscale needed, <1 when capped).
1186
- */
1187
- function getResizeValuesUniversal(params) {
1188
- const { pixelRatio, containerWidth, containerHeight, maxResolution } = params;
1189
- const maxSpace = {
1190
- w: containerWidth * pixelRatio,
1191
- h: containerHeight * pixelRatio,
1192
- };
1193
- const maxPixels = maxResolution ? UHD_PIXELS : FULL_HD_PIXELS;
1194
- let w = maxSpace.w;
1195
- let h = maxSpace.h;
1196
- if (w * h > maxPixels) {
1197
- // Derive uniform scale factor `s` from: (w*s) * (h*s) = maxPixels
1198
- // → w * h * s² = maxPixels → s = √(maxPixels / (w * h)).
1199
- // Applying the same `s` to both dimensions preserves the aspect ratio.
1200
- const scaleFactor = Math.sqrt(maxPixels / (w * h));
1201
- w = w * scaleFactor;
1202
- h = h * scaleFactor;
1203
- }
1204
- return { w: makeEven(w), h: makeEven(h), x: 0, y: 0, scale: w / maxSpace.w };
1205
- }
1206
-
1207
- /**
1208
- * `'metabox'` — the default when `UNREAL_CONFIG` omits `mode` — speaks the full
1209
- * Metabox command protocol. `'default'` targets a stock Pixel Streaming
1210
- * application, which understands no `MetaBoxCommand` packet, so the module
1211
- * sends none of its own.
1212
- */
1213
- function isMetaboxMode(config) {
1214
- return (config?.mode ?? 'metabox') === 'metabox';
1215
- }
1216
-
1217
- /**
1218
- * Fraction of commands completed (0–1). Drives the second half of the
1219
- * loading bar, after signaling reaches `SIGNALLING_PERCENT_VALUE`.
1220
- */
1221
- const selectCommandProgress = createSelector(unrealFeature.selectTotalCommandsStarted, unrealFeature.selectTotalCommandsCompleted, (started, completed) => (started ? completed / started : 0));
1222
- const selectFreezeFrameDataUrlFromVideo = createSelector(unrealFeature.selectFreezeFrameFromVideo, (freezeFrameFromVideo) => freezeFrameFromVideo?.dataUrl || null);
1223
- const selectFreezeFrameProgressMessageFromVideo = createSelector(unrealFeature.selectFreezeFrameFromVideo, (freezeFrameFromVideo) => freezeFrameFromVideo?.progress || null);
1224
- const selectFreezeFrameDataUrl = createSelector(unrealFeature.selectFreezeFrame, (freezeFrame) => (freezeFrame?.dataUrl ? freezeFrame?.dataUrl : null));
1225
- const selectIsFreezeFrameLoading = createSelector(unrealFeature.selectFreezeFrame, (freezeFrame) => freezeFrame?.progress
1226
- ? freezeFrame.progress > 0 && freezeFrame.progress < 1
1227
- : false);
1228
- const selectFreezeFrameCombinedDataUrl = createSelector(selectFreezeFrameDataUrlFromVideo, selectFreezeFrameDataUrl, (dataUrlFromVideo, remoteDataUrl) => dataUrlFromVideo || remoteDataUrl || null);
1229
- const selectStreamConfig = createSelector(unrealFeature.selectStreamConfig, (config) => config);
1230
- const selectWarnTimeout = createSelector(selectStreamConfig, (config) => config?.warnTimeout || DEFAULT_AFK_TIMEOUT);
1231
- const selectIsExistMatchUrls = createSelector(unrealFeature.selectMatchUrls, (urls) => urls?.length > 0);
1232
- const selectIsAutostart = createSelector(selectStreamConfig, (config) => config?.autoStart);
1233
- const selectShowReconnectPopup = createSelector(unrealFeature.selectCirrusConnected, unrealFeature.selectEstablishingConnection, (cirrusConnected, establishingConnection) => !cirrusConnected && !establishingConnection);
1234
- const selectShowLoader = createSelector(selectShowReconnectPopup, unrealFeature.selectViewportReady, (showPopup, viewportReady) => !showPopup && !viewportReady);
1235
- /**
1236
- * The connection id of the current stream session.
1237
- *
1238
- * The id is issued on the Cirrus side and reaches us either as the
1239
- * orchestration's `streamRequestId` (polling response / `instanceReserved` /
1240
- * `instanceReady`) or, when the backend issues none, in the `ssInfo` message
1241
- * once Cirrus generated it itself. Inside the player it is ONE value —
1242
- * `connectionId` — and this selector is where the two arrival paths collapse
1243
- * into it. It names the session everywhere: the debug overlay ("Connection Id")
1244
- * and the stream telemetry's `sessionId`.
1245
- *
1246
- * Also used by external consumers (e.g., metabox). Do not remove.
1247
- */
1248
- const selectCirrusConnectionId = createSelector(unrealFeature.selectAwsInstance, unrealFeature.selectSsData, (awsInstance, ssData) => awsInstance?.streamRequestId ?? ssData?.connectionId);
1249
- const selectSignalingParameters = createSelector(unrealFeature.selectSsData, unrealFeature.selectAwsInstance, selectCirrusConnectionId, (data, instance, connectionId) => {
1250
- const info = [];
1251
- if (data) {
1252
- info.push(`${data.cirrusVersion}, ${data.branchInfo}, ${data.instanceType}`);
1253
- info.push(`Unreal App Version: ${data.streamerVersion}`);
1254
- info.push(`APP: ${data.streamPath}${data.streamApp}`);
1255
- }
1256
- // The endpoint that handed us the Cirrus address: an HTTP polling URL in one
1257
- // flow, a `wss://` orchestration URL in the other.
1258
- info.push(`Orchestration: ${instance.pollingUrl}`);
1259
- info.push(`WS: ${instance.wsUrl}`);
1260
- // The stream's `connectionId` — the telemetry ships it as its `sessionId`
1261
- // (a file name on the collector), and the viewer labels it `Connection Id`
1262
- // too, so the same value is named the same thing everywhere.
1263
- info.push(`Connection Id: ${connectionId ?? '—'}`);
1264
- return info.join('<br>');
1265
- });
1266
- const selectClientAndViewIds = createSelector(unrealFeature.selectStreamClientCompanyId, unrealFeature.selectStreamViewId, (clientId, viewId) => ({ clientId, viewId }));
1267
- const selectIsFullyConnected = createSelector(unrealFeature.selectViewportReady, unrealFeature.selectDataChannelConnected, unrealFeature.selectCirrusConnected, (viewportReady, dataChannelConnected, cirrusConnected) => viewportReady && dataChannelConnected && cirrusConnected);
1268
- const selectIsLoaderScreenVisible = createSelector(selectIsFullyConnected, (fullyConnected) => !fullyConnected);
1269
- /**
1270
- * Returns Scene load progress as a float value between 0 and 1.
1271
- *
1272
- * Progress is split into two phases:
1273
- * 1. **Signaling** (0 → ~56%): connection polling or orchestration progress.
1274
- * Starts at 0.1%, so the bar is never visually empty while connecting.
1275
- * 2. **Commands** (~56% → 100%): Unreal command progress after the data channel connects.
1276
- *
1277
- * The split point bumps by +1% once the WebSocket URL is known,
1278
- * producing a small visual step that indicates the WS handshake succeeded.
1279
- */
1280
- const selectTotalProgress = createSelector(unrealFeature.selectStatusPercentSignallingServer, selectCommandProgress, unrealFeature.selectAwsInstance, unrealFeature.selectDataChannelConnected, (statusPercentSignallingServer, commandProgress, awsInstance, dataChannelConnected) => {
1281
- const SIGNALLING_MAX = SIGNALLING_PERCENT_VALUE / 100;
1282
- // Stated by the service (`AwsInstance.kind`), not sniffed from the hostname.
1283
- // In the socket flow it is set by `instanceReserved` — i.e. before
1284
- // `setAwsInstance` — so the eta-driven bar is picked up from the start of
1285
- // the provisioning wait.
1286
- const isNewOrchestration = awsInstance?.kind === 'socket';
1287
- // Once the data channel is connected, signaling is fully complete (1.0) —
1288
- // regardless of orchestration type. This is what makes an ADOPTED stream
1289
- // (which never set `statusPercentSignallingServer`) correctly show the whole
1290
- // first phase done instead of stalling near the command-only value.
1291
- // Otherwise: new orchestration reports 0–1 progress; legacy uses the
1292
- // polling percent.
1293
- const signalingProgress = dataChannelConnected
1294
- ? 1
1295
- : isNewOrchestration
1296
- ? (awsInstance?.progressComplete ?? 0)
1297
- : (statusPercentSignallingServer ?? 0) / 100;
1298
- // +1% bump once WS URL is known (visual step for WS handshake)
1299
- const splitPoint = awsInstance?.wsUrl
1300
- ? SIGNALLING_MAX + 0.01
1301
- : SIGNALLING_MAX;
1302
- // 0.001 minimum so the bar is never completely empty while loading
1303
- const progressSignaling = lerp(0.001, splitPoint, signalingProgress);
1304
- const progressRest = lerp(0, 1 - splitPoint, commandProgress);
1305
- return clampf(0, 1, progressSignaling + progressRest);
1306
- });
1307
- /** Used by external consumers (e.g., metabox). Do not remove. */
1308
- const selectUserInactivityDetected = createSelector(unrealFeature.selectAfkCountdown, unrealFeature.selectIsAfkTimerVisible, (remainingSecondsToDisconnect, countdownVisible) => ({
1309
- remainingSecondsToDisconnect,
1310
- countdownVisible,
1311
- }));
1312
- /** Used by external consumers (e.g., metabox). Do not remove. */
1313
- const selectIsVideoPlayingAndDataChannelConnected = createSelector(unrealFeature.selectIsVideoPlaying, unrealFeature.selectDataChannelConnected, (isVideoPlaying, isDataChannelConnected) => isVideoPlaying && isDataChannelConnected);
1314
-
1315
- class WebrtcErrorModalComponent {
1316
- constructor() {
1317
- this.#dialogRef = inject(DialogRef);
1318
- this.#store = inject(Store);
1319
- this.isCirrusConnected = inject(Store).selectSignal(unrealFeature.selectCirrusConnected);
1320
- }
1321
- #dialogRef;
1322
- #store;
1323
- closeModalWithCirrusDisconnect() {
1324
- if (!this.isCirrusConnected()) {
1325
- this.#store.dispatch(disconnectStream({
1326
- reason: DisconnectReason.DropConnection,
1327
- message: 'Modal Drop Connection',
1328
- }));
1329
- }
1330
- this.close();
1331
- }
1332
- close() {
1333
- this.#dialogRef.close();
1334
- }
1335
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WebrtcErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1336
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.0", type: WebrtcErrorModalComponent, isStandalone: true, selector: "app-webrtc-error-modal", ngImport: i0, template: "<div [attr.data-testid]=\"'webrtc-error-modal'\" class=\"unreal-modal\">\r\n <header class=\"unreal-modal__header\"></header>\r\n <section class=\"unreal-modal__body\">\r\n <div [attr.data-testid]=\"'title'\" class=\"unreal-modal__title\">\r\n WebRTC error\r\n </div>\r\n <div style=\"text-align: left\">\r\n An internet connection type (WebRTC) appears to be blocked either by your\r\n browser settings or your current network. If WebRTC is blocked on your\r\n browser you may be able to adjust these settings yourself based on\r\n instructions here:\r\n <a href=\"https://myownconference.com/blog/en/webrtc/\" target=\"blank\"\r\n >https://myownconference.com/blog/en/webrtc/</a\r\n >\r\n <br /><br />\r\n Trying a different web browser may help confirm this as well. If WebRTC is\r\n blocked by your network, try switching to a different network if possible\r\n or contact your network administrator.<br /><br />\r\n WebRTC is common, safe and increasingly utilised method for streaming real\r\n time 3D experiences via a web browser. It typically consumes no more\r\n bandwidth than streaming an HD video.\r\n </div>\r\n </section>\r\n <footer class=\"unreal-modal__footer\">\r\n <app-unreal-button\r\n (clicked)=\"closeModalWithCirrusDisconnect()\"\r\n [data-testid]=\"'close-webrtc-error-modal'\"\r\n weight=\"primary\"\r\n >\r\n Ok\r\n </app-unreal-button>\r\n </footer>\r\n</div>\r\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__body{width:100%}.unreal-modal .unreal-modal__body p{color:var(--src-text-body-main, #1f2937);font-size:14px;font-style:normal;font-weight:400;line-height:24px;margin-top:0}.unreal-modal .unreal-modal__body a{word-wrap:break-word;white-space:normal}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1337
- }
1338
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WebrtcErrorModalComponent, decorators: [{
1339
- type: Component,
1340
- args: [{ selector: 'app-webrtc-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "<div [attr.data-testid]=\"'webrtc-error-modal'\" class=\"unreal-modal\">\r\n <header class=\"unreal-modal__header\"></header>\r\n <section class=\"unreal-modal__body\">\r\n <div [attr.data-testid]=\"'title'\" class=\"unreal-modal__title\">\r\n WebRTC error\r\n </div>\r\n <div style=\"text-align: left\">\r\n An internet connection type (WebRTC) appears to be blocked either by your\r\n browser settings or your current network. If WebRTC is blocked on your\r\n browser you may be able to adjust these settings yourself based on\r\n instructions here:\r\n <a href=\"https://myownconference.com/blog/en/webrtc/\" target=\"blank\"\r\n >https://myownconference.com/blog/en/webrtc/</a\r\n >\r\n <br /><br />\r\n Trying a different web browser may help confirm this as well. If WebRTC is\r\n blocked by your network, try switching to a different network if possible\r\n or contact your network administrator.<br /><br />\r\n WebRTC is common, safe and increasingly utilised method for streaming real\r\n time 3D experiences via a web browser. It typically consumes no more\r\n bandwidth than streaming an HD video.\r\n </div>\r\n </section>\r\n <footer class=\"unreal-modal__footer\">\r\n <app-unreal-button\r\n (clicked)=\"closeModalWithCirrusDisconnect()\"\r\n [data-testid]=\"'close-webrtc-error-modal'\"\r\n weight=\"primary\"\r\n >\r\n Ok\r\n </app-unreal-button>\r\n </footer>\r\n</div>\r\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__body{width:100%}.unreal-modal .unreal-modal__body p{color:var(--src-text-body-main, #1f2937);font-size:14px;font-style:normal;font-weight:400;line-height:24px;margin-top:0}.unreal-modal .unreal-modal__body a{word-wrap:break-word;white-space:normal}\n"] }]
1341
- }] });
1342
-
1343
- class CommandTelemetryService extends SubService {
1344
- constructor() {
1345
- super();
1346
- this.appId = 'metabox-telemetry';
1347
- this.commandsSent = {};
1348
- this.exileTimeout = 60000;
1349
- this.pollingTime = 5000;
1350
- this.commandSequenceNumber = 0;
1351
- this.payloads = [];
1352
- this.httpClient = inject(HttpClient);
1353
- this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
1354
- this.init();
1355
- }
1356
- init() {
1357
- if (!this.unrealConfig?.commandTelemetryReceiver ||
1358
- this.unrealConfig?.playwright) {
1359
- return;
1360
- }
1361
- this.reset();
1362
- this.sessionId = sessionStorage.getItem(this.appId) || this.uuid;
1363
- this.userId = localStorage.getItem(this.appId) || this.uuid;
1364
- sessionStorage.setItem(this.appId, this.sessionId);
1365
- localStorage.setItem(this.appId, this.userId);
1366
- timer(0, this.pollingTime)
1367
- .pipe(takeUntil(this.destroy$))
1368
- .subscribe(() => {
1369
- this.send(this.payloads);
1370
- });
1371
- }
1372
- get timeNow() {
1373
- return Date.now();
1374
- }
1375
- get sessionTime() {
1376
- return this.timeNow - this.startTime;
1377
- }
1378
- get canSkipSending() {
1379
- return !(this.timeNow - this.lastTime > this.pollingTime * 2);
1380
- }
1381
- decorate(funcToDecorate) {
1382
- this.listenCallbacks();
1383
- return this.wrapper.bind(this, funcToDecorate);
1384
- }
1385
- trackStartCommand(trackingId) {
1386
- const out = {
1387
- command: trackingId,
1388
- trackingId,
1389
- };
1390
- const timers = {
1391
- sessionElapsedTime: this.sessionTime,
1392
- };
1393
- this.pushStatToBuffer('commandSent', out, timers);
1394
- this.trackTime(out);
999
+ trackStartCommand(trackingId) {
1000
+ const out = {
1001
+ command: trackingId,
1002
+ trackingId,
1003
+ };
1004
+ const timers = {
1005
+ sessionElapsedTime: this.sessionTime,
1006
+ };
1007
+ this.pushStatToBuffer('commandSent', out, timers);
1008
+ this.trackTime(out);
1395
1009
  }
1396
1010
  trackStopCommand(trackingId, multi = false, response = {}, timeStampsRaw) {
1397
1011
  const commandResponse = this.commandsSent[trackingId];
@@ -1542,10 +1156,10 @@ class CommandTelemetryService extends SubService {
1542
1156
  this.trackTime(out);
1543
1157
  funcToDecorate(out);
1544
1158
  }
1545
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: CommandTelemetryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1546
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: CommandTelemetryService, providedIn: 'root' }); }
1159
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: CommandTelemetryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1160
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: CommandTelemetryService, providedIn: 'root' }); }
1547
1161
  }
1548
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: CommandTelemetryService, decorators: [{
1162
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: CommandTelemetryService, decorators: [{
1549
1163
  type: Injectable,
1550
1164
  args: [{ providedIn: 'root' }]
1551
1165
  }], ctorParameters: () => [] });
@@ -1566,10 +1180,10 @@ class DevModeService {
1566
1180
  localStorage.removeItem('devMode');
1567
1181
  }
1568
1182
  }
1569
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DevModeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1570
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DevModeService, providedIn: 'root' }); }
1183
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: DevModeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1184
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: DevModeService, providedIn: 'root' }); }
1571
1185
  }
1572
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: DevModeService, decorators: [{
1186
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: DevModeService, decorators: [{
1573
1187
  type: Injectable,
1574
1188
  args: [{
1575
1189
  providedIn: 'root',
@@ -1615,7 +1229,7 @@ class RegionsPingService {
1615
1229
  return of(cached).pipe(tap(() => this.store.dispatch(regionPingFetchEnd())), tap((data) => this.store.dispatch(regionResolved({
1616
1230
  region: data.region_code,
1617
1231
  pingsMs: data.result,
1618
- }))), map$1((data) => data.region_code));
1232
+ }))), map((data) => data.region_code));
1619
1233
  }
1620
1234
  // No regions URL and no cache: there is nothing to ping. Bail out loudly
1621
1235
  // instead of letting `HttpClient.get('')` request the current document
@@ -1638,7 +1252,7 @@ class RegionsPingService {
1638
1252
  }), tap((data) => this.store.dispatch(regionResolved({
1639
1253
  region: data?.region_code ?? '',
1640
1254
  pingsMs: data?.result ?? [],
1641
- }))), map$1((data) => data?.region_code));
1255
+ }))), map((data) => data?.region_code));
1642
1256
  });
1643
1257
  }
1644
1258
  /**
@@ -1888,10 +1502,10 @@ class RegionsPingService {
1888
1502
  }
1889
1503
  }
1890
1504
  }
1891
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: RegionsPingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1892
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: RegionsPingService, providedIn: 'root' }); }
1505
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: RegionsPingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1506
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: RegionsPingService, providedIn: 'root' }); }
1893
1507
  }
1894
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: RegionsPingService, decorators: [{
1508
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: RegionsPingService, decorators: [{
1895
1509
  type: Injectable,
1896
1510
  args: [{ providedIn: 'root' }]
1897
1511
  }], ctorParameters: () => [] });
@@ -2228,7 +1842,7 @@ class SignallingService extends SubService {
2228
1842
  // itself at `INNER_RETRY_LIMIT`; only its exhaustion reaches the outer retry,
2229
1843
  // which re-picks the region (rare, real "region down"). Outer delay > inner,
2230
1844
  // so escalation is bounded and region discovery runs once per outer cycle.
2231
- const connectCycle$ = this.getRegion().pipe(tap((region) => this.region.set(region ?? '')), map$1((region) => this.adaptUrlsToRegion(urlList, region)), switchMap((urls) => this.connectAttempt(urls)), takeUntil(this.abort$));
1845
+ const connectCycle$ = this.getRegion().pipe(tap((region) => this.region.set(region ?? '')), map((region) => this.adaptUrlsToRegion(urlList, region)), switchMap((urls) => this.connectAttempt(urls)), takeUntil(this.abort$));
2232
1846
  return connectCycle$.pipe(retry({
2233
1847
  delay: (err, attempt) => {
2234
1848
  this.store.dispatch(signalingRetryAttempted({
@@ -2353,7 +1967,7 @@ class SignallingService extends SubService {
2353
1967
  * `kind`: nothing was requested.
2354
1968
  */
2355
1969
  requestCirrusDirect(url) {
2356
- return this.waitForClientAndViewIds().pipe(map$1(() => ({
1970
+ return this.waitForClientAndViewIds().pipe(map(() => ({
2357
1971
  wsUrl: url,
2358
1972
  pollingUrl: null,
2359
1973
  instanceName: 'Direct Connection',
@@ -2375,7 +1989,7 @@ class SignallingService extends SubService {
2375
1989
  }
2376
1990
  }), filter(({ clientId, viewId }) => !!clientId && !!viewId), take(1), switchMap(({ clientId, viewId }) => this.pollLoop(`${url}${clientId}/${viewId}`).pipe(tap((data) => {
2377
1991
  lastResp = data;
2378
- }))), map$1((data) => ({
1992
+ }))), map((data) => ({
2379
1993
  wsUrl: httpUrlToWs(`${location.protocol}//${data.signallingServer}`),
2380
1994
  pollingUrl: url,
2381
1995
  instanceName: data.signallingServer ?? '',
@@ -2431,7 +2045,7 @@ class SignallingService extends SubService {
2431
2045
  this.controlWs = control;
2432
2046
  Logger.log('ORCHESTRATION CONTROL WS OPEN');
2433
2047
  this.sendRequestStream();
2434
- return merge(this.onInstanceReady$.pipe(map$1((payload) => ({
2048
+ return merge(this.onInstanceReady$.pipe(map((payload) => ({
2435
2049
  wsUrl: payload.originInstanceUri,
2436
2050
  // The endpoint that answered — the orchestration URL here, the HTTP
2437
2051
  // polling URL in the other flow. Shown as `Orchestration:` in the overlay.
@@ -2723,10 +2337,10 @@ class SignallingService extends SubService {
2723
2337
  Logger.log('Start Getting Region');
2724
2338
  return this.regionsPingService.getFastest().pipe(take(1));
2725
2339
  }
2726
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: SignallingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2727
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: SignallingService, providedIn: 'root' }); }
2340
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SignallingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2341
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SignallingService, providedIn: 'root' }); }
2728
2342
  }
2729
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: SignallingService, decorators: [{
2343
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SignallingService, decorators: [{
2730
2344
  type: Injectable,
2731
2345
  args: [{ providedIn: 'root' }]
2732
2346
  }], ctorParameters: () => [] });
@@ -2754,7 +2368,7 @@ class VideoService extends SubService {
2754
2368
  this.videoStats$ = this.videoTrack$.pipe(
2755
2369
  // If videoTrack$ emits null, switch to EMPTY → the current interval is canceled.
2756
2370
  switchMap$1((track) => track
2757
- ? interval(250).pipe(map(() => track.pcClient), switchMap$1((pcClient) => from(this.getStats(pcClient))), filter(Truthy))
2371
+ ? interval(250).pipe(map$1(() => track.pcClient), switchMap$1((pcClient) => from(this.getStats(pcClient))), filter(Truthy))
2758
2372
  : of(null)), filter(Truthy), share());
2759
2373
  this.destroyAbort = new AbortController();
2760
2374
  // Teardown is wired ONCE here instead of per `create()`. The per-create
@@ -3141,10 +2755,10 @@ class VideoService extends SubService {
3141
2755
  this.armGestureRetry(audio);
3142
2756
  }
3143
2757
  }
3144
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: VideoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3145
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: VideoService, providedIn: 'root' }); }
2758
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: VideoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
2759
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: VideoService, providedIn: 'root' }); }
3146
2760
  }
3147
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: VideoService, decorators: [{
2761
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: VideoService, decorators: [{
3148
2762
  type: Injectable,
3149
2763
  args: [{ providedIn: 'root' }]
3150
2764
  }], ctorParameters: () => [] });
@@ -3600,25 +3214,25 @@ class WebRtcPlayerService extends SubService {
3600
3214
  }
3601
3215
  handlePeerConnectionEvents(pcClient) {
3602
3216
  fromEvent(pcClient, 'signalingstatechange')
3603
- .pipe(map$1(() => this.pcClient?.signalingState), takeUntil(merge(this.disconnect$, this.destroy$)))
3217
+ .pipe(map(() => this.pcClient?.signalingState), takeUntil(merge(this.disconnect$, this.destroy$)))
3604
3218
  .subscribe((state) => {
3605
3219
  Logger.info('[Signaling state change] |', state, '|');
3606
3220
  this.commandTelemetryService.trackStopCommand('EXT-Signaling state change', true, { state, multi: true });
3607
3221
  });
3608
3222
  fromEvent(pcClient, 'iceconnectionstatechange')
3609
- .pipe(map$1(() => this.pcClient?.iceConnectionState), takeUntil(merge(this.disconnect$, this.destroy$)))
3223
+ .pipe(map(() => this.pcClient?.iceConnectionState), takeUntil(merge(this.disconnect$, this.destroy$)))
3610
3224
  .subscribe((state) => {
3611
3225
  Logger.info('[Browser ICE connection] |', state, '|');
3612
3226
  this.commandTelemetryService.trackStopCommand('EXT-Browser ICE connection', true, { state, multi: true });
3613
3227
  });
3614
3228
  fromEvent(pcClient, 'icegatheringstatechange')
3615
- .pipe(map$1(() => this.pcClient?.iceGatheringState), takeUntil(merge(this.disconnect$, this.destroy$)))
3229
+ .pipe(map(() => this.pcClient?.iceGatheringState), takeUntil(merge(this.disconnect$, this.destroy$)))
3616
3230
  .subscribe((state) => {
3617
3231
  Logger.info('[Browser ICE gathering] |', state, '|');
3618
3232
  this.commandTelemetryService.trackStopCommand('EXT-Browser ICE gathering', true, { state, multi: true });
3619
3233
  });
3620
3234
  fromEvent(pcClient, 'connectionstatechange')
3621
- .pipe(map$1(() => this.pcClient?.connectionState), takeUntil(merge(this.disconnect$, this.destroy$)))
3235
+ .pipe(map(() => this.pcClient?.connectionState), takeUntil(merge(this.disconnect$, this.destroy$)))
3622
3236
  .subscribe((state) => {
3623
3237
  Logger.info('[RTCPeerConnection state] |', state, '|');
3624
3238
  // A genuine ICE failure (not a manual dropDC/dropPC, which recover via
@@ -3635,7 +3249,7 @@ class WebRtcPlayerService extends SubService {
3635
3249
  }
3636
3250
  });
3637
3251
  fromEvent(pcClient, 'icecandidate')
3638
- .pipe(map$1((e) => e.candidate), filter(Truthy), tap$1((candidate) => Logger.info('[Browser ICE candidate]', '| Type=', candidate.type, '| Protocol=', candidate.protocol, '| Address=', candidate.address, '| Port=', candidate.port, '|')), takeUntil(merge(this.disconnect$, this.destroy$)))
3252
+ .pipe(map((e) => e.candidate), filter(Truthy), tap$1((candidate) => Logger.info('[Browser ICE candidate]', '| Type=', candidate.type, '| Protocol=', candidate.protocol, '| Address=', candidate.address, '| Port=', candidate.port, '|')), takeUntil(merge(this.disconnect$, this.destroy$)))
3639
3253
  .subscribe((candidate) => this.signallingSrv.send({
3640
3254
  type: 'iceCandidate',
3641
3255
  candidate,
@@ -3643,7 +3257,7 @@ class WebRtcPlayerService extends SubService {
3643
3257
  // When the server creates the DataChannel (server-offer flow),
3644
3258
  // we receive it here via the 'datachannel' event
3645
3259
  fromEvent(pcClient, 'datachannel')
3646
- .pipe(tap$1((e) => Logger.info(`[DATACHANNEL] Received remote DC: label="${e.channel.label}" id=${e.channel.id} protocol="${e.channel.protocol}" ordered=${e.channel.ordered}`)), map$1((e) => e.channel), takeUntil(merge(this.disconnect$, this.destroy$)))
3260
+ .pipe(tap$1((e) => Logger.info(`[DATACHANNEL] Received remote DC: label="${e.channel.label}" id=${e.channel.id} protocol="${e.channel.protocol}" ordered=${e.channel.ordered}`)), map((e) => e.channel), takeUntil(merge(this.disconnect$, this.destroy$)))
3647
3261
  .subscribe((datachannel) => {
3648
3262
  this.dcClient = this.setupDataChannelCallbacks(datachannel);
3649
3263
  });
@@ -3654,10 +3268,10 @@ class WebRtcPlayerService extends SubService {
3654
3268
  ' readyState=' +
3655
3269
  e.track.readyState)), share());
3656
3270
  onTrack$
3657
- .pipe(filter((e) => e.track.kind === 'audio'), map$1((e) => e.streams[0]))
3271
+ .pipe(filter((e) => e.track.kind === 'audio'), map((e) => e.streams[0]))
3658
3272
  .subscribe((stream) => this.videoService.attachAudioStream(stream));
3659
3273
  onTrack$
3660
- .pipe(filter((e) => e.track.kind === 'video'), map$1((e) => e.streams[0]), tap$1(() => Logger.info('Set video source from video track ontrack.')))
3274
+ .pipe(filter((e) => e.track.kind === 'video'), map((e) => e.streams[0]), tap$1(() => Logger.info('Set video source from video track ontrack.')))
3661
3275
  .subscribe((stream) => {
3662
3276
  if (this.pcClient) {
3663
3277
  this.videoService.attachVideoStream(stream, this.pcClient);
@@ -3758,7 +3372,7 @@ class WebRtcPlayerService extends SubService {
3758
3372
  `[DATACHANNEL] Message received on "${datachannel.label}" id=${datachannel.id}, byteCode=${view[0]}, size=${view.byteLength}`,
3759
3373
  );
3760
3374
  }),*/
3761
- map$1((e) => e.data), takeUntil(merge(this.disconnect$, this.destroy$)))
3375
+ map((e) => e.data), takeUntil(merge(this.disconnect$, this.destroy$)))
3762
3376
  .subscribe((data) => this.onDataChannelMessage$.next(data));
3763
3377
  return datachannel;
3764
3378
  }
@@ -3810,10 +3424,10 @@ class WebRtcPlayerService extends SubService {
3810
3424
  Logger.error("Couldn't create answer", e);
3811
3425
  }
3812
3426
  }
3813
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WebRtcPlayerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3814
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WebRtcPlayerService, providedIn: 'root' }); }
3427
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WebRtcPlayerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3428
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WebRtcPlayerService, providedIn: 'root' }); }
3815
3429
  }
3816
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WebRtcPlayerService, decorators: [{
3430
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: WebRtcPlayerService, decorators: [{
3817
3431
  type: Injectable,
3818
3432
  args: [{ providedIn: 'root' }]
3819
3433
  }], ctorParameters: () => [] });
@@ -3939,10 +3553,10 @@ class StreamAdoptionService {
3939
3553
  this.webRtc.adopt(parked.pc, parked.dc, parked.stream, parked.config ?? {}, parked.dcBuffer);
3940
3554
  return true;
3941
3555
  }
3942
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: StreamAdoptionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3943
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: StreamAdoptionService, providedIn: 'root' }); }
3556
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamAdoptionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3557
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamAdoptionService, providedIn: 'root' }); }
3944
3558
  }
3945
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: StreamAdoptionService, decorators: [{
3559
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamAdoptionService, decorators: [{
3946
3560
  type: Injectable,
3947
3561
  args: [{ providedIn: 'root' }]
3948
3562
  }] });
@@ -3974,10 +3588,10 @@ class UnrealCallbackService {
3974
3588
  * ```
3975
3589
  */
3976
3590
  fromUnrealCallback(command) {
3977
- return this.actions$.pipe(ofType(unrealCommandCallback), map$1(({ json }) => 'commandCallback' in json ? json.commandCallback : json), filter((json) => json.command === command),
3591
+ return this.actions$.pipe(ofType(unrealCommandCallback), map(({ json }) => 'commandCallback' in json ? json.commandCallback : json), filter((json) => json.command === command),
3978
3592
  // Cast is required: after a `command`-based filter TS cannot narrow to a
3979
3593
  // type discriminated on `callback`. The unwrapped object IS the full callback.
3980
- map$1((data) => data));
3594
+ map((data) => data));
3981
3595
  }
3982
3596
  /**
3983
3597
  * Sends a command and observes the matching response by correlationId.
@@ -4001,19 +3615,19 @@ class UnrealCallbackService {
4001
3615
  observeCommandResponse(data, sender, timeOut = 60000, dispatchOnTimeout = true) {
4002
3616
  const correlationId = generateUuid();
4003
3617
  return defer(() => {
4004
- const observable = this.actions$.pipe(ofType(unrealCommandCallback), map$1(({ json }) => 'commandCallback' in json ? json.commandCallback : json), filter((json) => json.correlationId === correlationId), timeout$1(timeOut), catchError(() => dispatchOnTimeout
3618
+ const observable = this.actions$.pipe(ofType(unrealCommandCallback), map(({ json }) => 'commandCallback' in json ? json.commandCallback : json), filter((json) => json.correlationId === correlationId), timeout$1(timeOut), catchError(() => dispatchOnTimeout
4005
3619
  ? of({ command: 'timeout', correlationId: 'timeout' })
4006
3620
  : of(null)), take(1), tapLog('Command Response Observer'), filter(Truthy),
4007
3621
  // Cast: response is matched by correlationId, so it is the callback for K.
4008
- map$1((data) => data));
3622
+ map((data) => data));
4009
3623
  setTimeout(() => sender({ ...data, correlationId }), 0);
4010
3624
  return observable;
4011
3625
  });
4012
3626
  }
4013
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealCallbackService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4014
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealCallbackService, providedIn: 'root' }); }
3627
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealCallbackService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3628
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealCallbackService, providedIn: 'root' }); }
4015
3629
  }
4016
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealCallbackService, decorators: [{
3630
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealCallbackService, decorators: [{
4017
3631
  type: Injectable,
4018
3632
  args: [{ providedIn: 'root' }]
4019
3633
  }] });
@@ -4130,10 +3744,10 @@ class UnrealCommunicatorService extends SubService {
4130
3744
  requestQualityControl() {
4131
3745
  this.sendInputData(new Uint8Array([MessageType.RequestQualityControl]).buffer);
4132
3746
  }
4133
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealCommunicatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4134
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealCommunicatorService, providedIn: 'root' }); }
3747
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealCommunicatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
3748
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealCommunicatorService, providedIn: 'root' }); }
4135
3749
  }
4136
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealCommunicatorService, decorators: [{
3750
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealCommunicatorService, decorators: [{
4137
3751
  type: Injectable,
4138
3752
  args: [{ providedIn: 'root' }]
4139
3753
  }], ctorParameters: () => [] });
@@ -4147,12 +3761,12 @@ class UnrealErrorModalComponent {
4147
3761
  close() {
4148
3762
  this.#dialogRef.close();
4149
3763
  }
4150
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
4151
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.0", type: UnrealErrorModalComponent, isStandalone: true, selector: "app-unreal-error-modal", ngImport: i0, template: "<div class=\"unreal-modal\">\r\n <header class=\"unreal-modal__header\">\r\n <div\r\n [attr.data-testid]=\"'unreal-error-header-title'\"\r\n class=\"unreal-modal__title\"\r\n >\r\n Warning\r\n </div>\r\n </header>\r\n <div class=\"unreal-modal__body\">\r\n <div>{{ dialogData.content }}</div>\r\n </div>\r\n <div class=\"unreal-modal__footer\">\r\n <app-unreal-button (clicked)=\"close()\">Ok</app-unreal-button>\r\n </div>\r\n</div>\r\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__header{padding:16px 24px 0}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
3764
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealErrorModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
3765
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: UnrealErrorModalComponent, isStandalone: true, selector: "app-unreal-error-modal", ngImport: i0, template: "<div class=\"unreal-modal\">\n <header class=\"unreal-modal__header\">\n <div\n [attr.data-testid]=\"'unreal-error-header-title'\"\n class=\"unreal-modal__title\"\n >\n Warning\n </div>\n </header>\n <div class=\"unreal-modal__body\">\n <div>{{ dialogData.content }}</div>\n </div>\n <div class=\"unreal-modal__footer\">\n <app-unreal-button (clicked)=\"close()\">Ok</app-unreal-button>\n </div>\n</div>\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__header{padding:16px 24px 0}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
4152
3766
  }
4153
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealErrorModalComponent, decorators: [{
3767
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealErrorModalComponent, decorators: [{
4154
3768
  type: Component,
4155
- args: [{ selector: 'app-unreal-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "<div class=\"unreal-modal\">\r\n <header class=\"unreal-modal__header\">\r\n <div\r\n [attr.data-testid]=\"'unreal-error-header-title'\"\r\n class=\"unreal-modal__title\"\r\n >\r\n Warning\r\n </div>\r\n </header>\r\n <div class=\"unreal-modal__body\">\r\n <div>{{ dialogData.content }}</div>\r\n </div>\r\n <div class=\"unreal-modal__footer\">\r\n <app-unreal-button (clicked)=\"close()\">Ok</app-unreal-button>\r\n </div>\r\n</div>\r\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__header{padding:16px 24px 0}\n"] }]
3769
+ args: [{ selector: 'app-unreal-error-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "<div class=\"unreal-modal\">\n <header class=\"unreal-modal__header\">\n <div\n [attr.data-testid]=\"'unreal-error-header-title'\"\n class=\"unreal-modal__title\"\n >\n Warning\n </div>\n </header>\n <div class=\"unreal-modal__body\">\n <div>{{ dialogData.content }}</div>\n </div>\n <div class=\"unreal-modal__footer\">\n <app-unreal-button (clicked)=\"close()\">Ok</app-unreal-button>\n </div>\n</div>\n", styles: [".unreal-modal{--unrealModalWidth: 422px;--unrealModalMaxWidth: calc(100% - 16px) ;--unrealModalMaxHeight: 80vh;--unrealModalBg: var(--src-surface-container-main, #fff);--unrealModalBoxShadow: 0 16px 36px 4px var(--src-shadow-hard, rgba(71, 85, 105, .24)), 0 1px 4px 0 var(--src-shadow-light, rgba(148, 163, 184, .16));--unrealModalBorderRadius: var(--src-layout-radius-const-rounded-md, 12px);--unrealModalTitleSize: var(--src-font-size-base, 16px);--unrealModalTitleLineHeight: var(--src-font-line-base, 24px);--unrealModalTitleColor: var(--src-text-body-main, #111827);--unrealModalBodyPadding: var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-2xl, 32px) var(--src-layout-padding-const-xl, 24px);--unrealModalTitleBorder: none;--unrealModalFooterBorder: 1px solid var(--src-border-container-light, rgba(148, 163, 184, .16));display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr) auto;width:var(--unrealModalWidth);max-width:var(--unrealModalMaxWidth);max-height:var(--unrealModalMaxHeight);margin:auto;background-color:var(--unrealModalBg);border-radius:var(--unrealModalBorderRadius);box-shadow:var(--unrealModalBoxShadow);color:var(--src-text-body-secondary, #4b5563);font-family:var(--src-font-family-header, Inter);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:var(--src-font-line-sm, 20px)}.unreal-modal .unreal-modal__header{position:relative;display:flex;padding:0;width:100%;border-bottom:var(--unrealModalTitleBorder)}.unreal-modal .unreal-modal__body{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);gap:var(--src-layout-gap-const-md, 12px);padding:var(--unrealModalBodyPadding);overflow:auto;scrollbar-width:thin;scrollbar-color:var(--src-border-container-basic, rgba(148, 163, 184, .24)) transparent}.unreal-modal .unreal-modal__body .unreal-modal__title{grid-column:1/-1}.unreal-modal .unreal-modal__body::-webkit-scrollbar{width:4px}.unreal-modal .unreal-modal__body::-webkit-scrollbar-track{background:transparent}.unreal-modal .unreal-modal__body::-webkit-scrollbar-thumb{background-color:var(--src-border-container-basic, rgba(148, 163, 184, .24));border-radius:10px}.unreal-modal .unreal-modal__footer{display:flex;justify-content:flex-end;align-items:center;padding:var(--src-layout-padding-const-md, 12px) var(--src-layout-padding-const-xl, 24px) var(--src-layout-padding-const-lg, 16px) var(--src-layout-padding-const-xl, 24px);width:100%;border-top:var(--unrealModalFooterBorder);gap:var(--src-layout-gap-const-sm, 8px)}.unreal-modal .unreal-modal__title{font-size:var(--unrealModalTitleSize);font-weight:600;line-height:var(--unrealModalTitleLineHeight);color:var(--unrealModalTitleColor);word-break:break-word}.unreal-modal .unreal-modal__header{padding:16px 24px 0}\n"] }]
4156
3770
  }] });
4157
3771
 
4158
3772
  class UnrealEffects {
@@ -4178,7 +3792,7 @@ class UnrealEffects {
4178
3792
  .select(unrealFeature.selectDataChannelConnected)
4179
3793
  .pipe(filter(Truthy));
4180
3794
  this.destroyConnections$ = createEffect(() => {
4181
- return this.actions$.pipe(ofType(destroyUnrealScene), map(() => destroyRemoteConnections({ reason: DisconnectReason.Destroy })));
3795
+ return this.actions$.pipe(ofType(destroyUnrealScene), map$1(() => destroyRemoteConnections({ reason: DisconnectReason.Destroy })));
4182
3796
  });
4183
3797
  // Stage 3 — accurate region re-ping in the background once the stream is up.
4184
3798
  // A few seconds after the data channel is ready (so it doesn't compete with
@@ -4197,10 +3811,10 @@ class UnrealEffects {
4197
3811
  // subscribe to single intent (and it shows up as a distinct entry in the
4198
3812
  // Redux DevTools timeline).
4199
3813
  this.abortEstablishingConnection$ = createEffect(() => {
4200
- return this.actions$.pipe(ofType(setCirrusDisconnected, dropConnection, destroyUnrealScene), map(() => abortEstablishingConnection()));
3814
+ return this.actions$.pipe(ofType(setCirrusDisconnected, dropConnection, destroyUnrealScene), map$1(() => abortEstablishingConnection()));
4201
3815
  });
4202
3816
  this.resetAfk$ = createEffect(() => {
4203
- return this.actions$.pipe(ofType(setConfig, setUserInactivityTimeout, resetWarnTimeout, resetConfig), map(() => resetAfk()));
3817
+ return this.actions$.pipe(ofType(setConfig, setUserInactivityTimeout, resetWarnTimeout, resetConfig), map$1(() => resetAfk()));
4204
3818
  });
4205
3819
  this.iframeMessaging$ = createEffect(() => {
4206
3820
  const cirrusConnected$ = this.store
@@ -4213,16 +3827,16 @@ class UnrealEffects {
4213
3827
  // Skip initial false; emit null on every viewport state change
4214
3828
  const viewportReset$ = this.store
4215
3829
  .select(unrealFeature.selectViewportReady)
4216
- .pipe(skip(1), delay(500), map(() => null));
3830
+ .pipe(skip(1), delay(500), map$1(() => null));
4217
3831
  return merge(cirrusStatus$, this.store.select(unrealFeature.selectStatusMessage), viewportReset$).pipe(debounceTime(0), distinctUntilChanged(), tapLog('STATUS=>'), tap((status) => this.postToScreenLocker(status)));
4218
3832
  }, { dispatch: false });
4219
3833
  this.setSignalingTo100$ = createEffect(() => {
4220
- return this.actions$.pipe(ofType(setAwsInstance), map(() => setStatusPercentSignallingServer({ percent: 100 })));
3834
+ return this.actions$.pipe(ofType(setAwsInstance), map$1(() => setStatusPercentSignallingServer({ percent: 100 })));
4221
3835
  });
4222
3836
  this.setOrchestrationParameters$ = createEffect(() => {
4223
- return this.actions$.pipe(ofType(setOrchestrationParameters), map(({ eta }) => eta), filter((value) => value > 0), switchMap((total) => {
3837
+ return this.actions$.pipe(ofType(setOrchestrationParameters), map$1(({ eta }) => eta), filter((value) => value > 0), switchMap((total) => {
4224
3838
  // Emit every second: 0,1,2,...,total (inclusive)
4225
- return timer(0, 1000).pipe(takeUntil(this.connectionCompleted$), take(total + 1), map((sec) => sec / total), distinctUntilChanged(), map((progressComplete) => setOrchestrationProgress({ progressComplete })));
3839
+ return timer(0, 1000).pipe(takeUntil(this.connectionCompleted$), take(total + 1), map$1((sec) => sec / total), distinctUntilChanged(), map$1((progressComplete) => setOrchestrationProgress({ progressComplete })));
4226
3840
  }));
4227
3841
  });
4228
3842
  this.setDataChannelTimeoutCheck$ = createEffect(() => {
@@ -4269,7 +3883,7 @@ class UnrealEffects {
4269
3883
  return of(null);
4270
3884
  }),
4271
3885
  // map response to the destroy action that ngrx will dispatch
4272
- map(() => disconnectStream({
3886
+ map$1(() => disconnectStream({
4273
3887
  reason: DisconnectReason.DataChannelTimeout,
4274
3888
  message: 'Data Channel Timeout',
4275
3889
  })));
@@ -4293,24 +3907,24 @@ class UnrealEffects {
4293
3907
  * a visible flicker (video flashing to black).
4294
3908
  */
4295
3909
  this.forceViewportNotReady$ = createEffect(() => {
4296
- return this.actions$.pipe(ofType(destroyRemoteConnections), withLatestFrom(this.store.select(unrealFeature.selectViewportReady)), filter(([, viewportReady]) => viewportReady), map(() => setViewportNotReady()));
3910
+ return this.actions$.pipe(ofType(destroyRemoteConnections), withLatestFrom(this.store.select(unrealFeature.selectViewportReady)), filter(([, viewportReady]) => viewportReady), map$1(() => setViewportNotReady()));
4297
3911
  });
4298
3912
  this.resetCirrusOnDestroy$ = createEffect(() => {
4299
- return this.actions$.pipe(ofType(destroyRemoteConnections), withLatestFrom(this.store.select(unrealFeature.selectCirrusConnected)), filter(([, cirrusConnected]) => cirrusConnected), map(() => setCirrusDisconnected()));
3913
+ return this.actions$.pipe(ofType(destroyRemoteConnections), withLatestFrom(this.store.select(unrealFeature.selectCirrusConnected)), filter(([, cirrusConnected]) => cirrusConnected), map$1(() => setCirrusDisconnected()));
4300
3914
  });
4301
3915
  this.destroyRemoteConnections$ = createEffect(() => {
4302
3916
  return this.actions$.pipe(ofType(destroyRemoteConnections), tap(({ reason }) => {
4303
3917
  this.webRtcPlayerService.releaseRemoteConnections(reason);
4304
- }), filter(({ reason }) => reason === DisconnectReason.DropConnection), map(() => dropConnection()));
3918
+ }), filter(({ reason }) => reason === DisconnectReason.DropConnection), map$1(() => dropConnection()));
4305
3919
  });
4306
3920
  this.destroyConnectionAndRestart$ = createEffect(() => {
4307
- return this.actions$.pipe(ofType(setCirrusDisconnected), withLatestFrom(this.store.select(unrealFeature.selectDisconnectReason)), filter(([, reason]) => reason === DisconnectReason.DataChannelTimeout), map(() => initSignalling()));
3921
+ return this.actions$.pipe(ofType(setCirrusDisconnected), withLatestFrom(this.store.select(unrealFeature.selectDisconnectReason)), filter(([, reason]) => reason === DisconnectReason.DataChannelTimeout), map$1(() => initSignalling()));
4308
3922
  });
4309
3923
  this.showUnrealError$ = createEffect(() => {
4310
- return this.actions$.pipe(ofType(showUnrealErrorMessage), map(({ code }) => getRtcErrorMessage(code)), distinctUntilChanged(), filter(Truthy), switchMap((content) => this.dialog.open(UnrealErrorModalComponent, {
3924
+ return this.actions$.pipe(ofType(showUnrealErrorMessage), map$1(({ code }) => getRtcErrorMessage(code)), distinctUntilChanged(), filter(Truthy), exhaustMap((content) => this.dialog.open(UnrealErrorModalComponent, {
4311
3925
  scrollStrategy: this.scrollStrategy,
4312
3926
  data: { content },
4313
- }).closed), map(() => showUnrealErrorMessage({ code: null })));
3927
+ }).closed), map$1(() => showUnrealErrorMessage({ code: null })));
4314
3928
  });
4315
3929
  /**
4316
3930
  * `dataChannelReady` is a ONCE-PER-SESSION signal: it starts app init
@@ -4355,21 +3969,21 @@ class UnrealEffects {
4355
3969
  // we proceed only after no more commands are started for 50 ms.
4356
3970
  return this.actions$.pipe(ofType(commandStarted), debounceTime(50), take(1), switchMap(() => this.unrealCallbackService.observeCommandResponse({ command: MetaBoxCommand.FLoopBackCommand }, (data) => this.commandsSender.sendCommandToUnreal(data))), switchMap(() => this.videoService.videoStats$), filter(({ aggregatedStats: s }) => !!s.framesPerSecond &&
4357
3971
  s.framesPerSecond > MINIMAL_FPS &&
4358
- (s.framesDecoded ?? 0) > 15), take(1), map(() => setLoopBackCommandIsCompleted()));
3972
+ (s.framesDecoded ?? 0) > 15), take(1), map$1(() => setLoopBackCommandIsCompleted()));
4359
3973
  }));
4360
3974
  });
4361
3975
  this.setViewportReadyBySetLoopBackCommandIsCompleted$ = createEffect(() => {
4362
- return this.actions$.pipe(ofType(setLoopBackCommandIsCompleted, reconnectPeerSuccess), tap(() => this.commandTelemetryService.trackStopCommand('EXT-SetViewportReady', false, { ready: true })), map(() => setViewportReady()));
3976
+ return this.actions$.pipe(ofType(setLoopBackCommandIsCompleted, reconnectPeerSuccess), tap(() => this.commandTelemetryService.trackStopCommand('EXT-SetViewportReady', false, { ready: true })), map$1(() => setViewportReady()));
4363
3977
  });
4364
3978
  this.startStream$ = createEffect(() => {
4365
- return this.actions$.pipe(ofType(startStream), map(() => initSignalling()));
3979
+ return this.actions$.pipe(ofType(startStream), map$1(() => initSignalling()));
4366
3980
  });
4367
3981
  // When the video stream is initialized but autoplay didn't kick in
4368
3982
  // (browser blocked it; user gesture pending), the user may need extra
4369
3983
  // time before interacting. Refresh the AFK timer so it doesn't tick
4370
3984
  // toward an inactivity warning while we're waiting for permission.
4371
3985
  this.resetAfkOnPausedVideoInit$ = createEffect(() => {
4372
- return this.actions$.pipe(ofType(videoStreamInitialized), filter(() => !!this.videoService.video?.paused), map(() => resetAfk()));
3986
+ return this.actions$.pipe(ofType(videoStreamInitialized), filter(() => !!this.videoService.video?.paused), map$1(() => resetAfk()));
4373
3987
  });
4374
3988
  /**
4375
3989
  * Effect: `disconnectReasonHandling$`
@@ -4392,7 +4006,7 @@ class UnrealEffects {
4392
4006
  return false;
4393
4007
  }
4394
4008
  return DESTROY_DISCONNECT_REASONS.includes(reason);
4395
- }), map(({ reason }) => destroyRemoteConnections({ reason })));
4009
+ }), map$1(({ reason }) => destroyRemoteConnections({ reason })));
4396
4010
  });
4397
4011
  /**
4398
4012
  * Effect: `handleDataChannelClosed$`
@@ -4406,7 +4020,7 @@ class UnrealEffects {
4406
4020
  reason === DisconnectReason.IceConnectionFailed) &&
4407
4021
  this.canPeerReconnect()), tap(({ reason }) => {
4408
4022
  Logger.warn(`[Reconnect] ${reason}, initiating peer reconnection`);
4409
- }), map(() => reconnectPeer({
4023
+ }), map$1(() => reconnectPeer({
4410
4024
  attempt: 1,
4411
4025
  maxAttempts: RECONNECT_CONFIG.maxAttempts,
4412
4026
  delay: 0,
@@ -4424,7 +4038,7 @@ class UnrealEffects {
4424
4038
  */
4425
4039
  this.resetStateForPeerReconnect$ = createEffect(() => {
4426
4040
  return this.actions$.pipe(ofType(reconnectPeer), filter(() => RECONNECT_CONFIG.enabled), filter(({ attempt }) => attempt === 1), // Only reset on the first attempt
4427
- map(() => resetDataChannelForReconnect()));
4041
+ map$1(() => resetDataChannelForReconnect()));
4428
4042
  });
4429
4043
  /**
4430
4044
  * Effect: `executePeerReconnect$`
@@ -4442,7 +4056,7 @@ class UnrealEffects {
4442
4056
  return of(this.scheduleRetryOrFail(attempt, maxAttempts, 'Signaling connection lost during peer reconnection'));
4443
4057
  }
4444
4058
  // Monitor for successful data channel connection
4445
- return this.actions$.pipe(ofType(dataChannelConnected), take(1), timeout$1(this.dataChannelConnectionTimeout), tap(() => Logger.info('[Reconnect] Peer reconnection successful!')), map(() => reconnectPeerSuccess()), catchError(() => {
4059
+ return this.actions$.pipe(ofType(dataChannelConnected), take(1), timeout$1(this.dataChannelConnectionTimeout), tap(() => Logger.info('[Reconnect] Peer reconnection successful!')), map$1(() => reconnectPeerSuccess()), catchError(() => {
4446
4060
  if (attempt < maxAttempts) {
4447
4061
  Logger.warn(`[Reconnect] Peer reconnection attempt ${attempt} timed out, scheduling retry`);
4448
4062
  }
@@ -4460,7 +4074,7 @@ class UnrealEffects {
4460
4074
  * Falls back to full disconnection which may trigger full reconnection.
4461
4075
  */
4462
4076
  this.handlePeerReconnectFailed$ = createEffect(() => {
4463
- return this.actions$.pipe(ofType(reconnectPeerFailed), map(({ reason }) => disconnectStream({
4077
+ return this.actions$.pipe(ofType(reconnectPeerFailed), map$1(({ reason }) => disconnectStream({
4464
4078
  reason: DisconnectReason.ReconnectFailed,
4465
4079
  message: reason,
4466
4080
  })));
@@ -4496,9 +4110,9 @@ class UnrealEffects {
4496
4110
  // carries a correlationId resolves a previously started command.
4497
4111
  // Skip in Playwright mode (deterministic command IDs are issued directly).
4498
4112
  this.listenUnrealCallbackByInitSignalling$ = createEffect(() => {
4499
- return this.actions$.pipe(ofType(initSignalling), filter(() => !this.unrealInitialConfig?.playwright), switchMap(() => this.actions$.pipe(ofType(unrealCommandCallback), map(({ json }) => 'commandCallback' in json
4113
+ return this.actions$.pipe(ofType(initSignalling), filter(() => !this.unrealInitialConfig?.playwright), switchMap(() => this.actions$.pipe(ofType(unrealCommandCallback), map$1(({ json }) => 'commandCallback' in json
4500
4114
  ? json.commandCallback?.correlationId
4501
- : json?.correlationId), filter(Truthy), map((id) => commandCompleted({ id, now: Date.now() })))));
4115
+ : json?.correlationId), filter(Truthy), map$1((id) => commandCompleted({ id, now: Date.now() })))));
4502
4116
  });
4503
4117
  this.connectToSignaling$ = createEffect(() => {
4504
4118
  return this.actions$.pipe(ofType(initSignalling), withLatestFrom(this.store.select(unrealFeature.selectMatchUrls), this.store.select(selectIsAutostart), this.store.select(unrealFeature.selectCirrusConnected)), filter(([, , autoStart, cirrusConnected]) => {
@@ -4506,7 +4120,7 @@ class UnrealEffects {
4506
4120
  Logger.warn(`SIGNALING REQUEST can't be called when cirrus connection is already established.`);
4507
4121
  }
4508
4122
  return autoStart && !cirrusConnected;
4509
- }), map(([, matchMakerUrls]) => [...matchMakerUrls].filter(Truthy)), filter((urls) => urls.length > 0),
4123
+ }), map$1(([, matchMakerUrls]) => [...matchMakerUrls].filter(Truthy)), filter((urls) => urls.length > 0),
4510
4124
  // Ensure a single in-flight request per attempt.
4511
4125
  exhaustMap((urls) =>
4512
4126
  // If a prefetched `window.__stream` is ready — or still connecting —
@@ -4523,35 +4137,434 @@ class UnrealEffects {
4523
4137
  ignoreElements(), startWith(setEstablishingConnection({ value: true })))));
4524
4138
  });
4525
4139
  }
4526
- canPeerReconnect() {
4527
- return RECONNECT_CONFIG.enabled && this.signallingService.isConnected();
4140
+ canPeerReconnect() {
4141
+ return RECONNECT_CONFIG.enabled && this.signallingService.isConnected();
4142
+ }
4143
+ /**
4144
+ * Either schedules the next peer-reconnect attempt or gives up with the
4145
+ * supplied reason. Used in two `executePeerReconnect$` branches that share
4146
+ * the same retry-or-fail decision.
4147
+ */
4148
+ scheduleRetryOrFail(attempt, maxAttempts, exhaustedReason) {
4149
+ return attempt < maxAttempts
4150
+ ? reconnectPeer({ attempt: attempt + 1, maxAttempts })
4151
+ : reconnectPeerFailed({ reason: exhaustedReason });
4152
+ }
4153
+ postToScreenLocker(text) {
4154
+ try {
4155
+ const el = document.getElementById(this.unrealInitialConfig?.screenLockerContainerId ??
4156
+ SCREEN_LOCKER_CONTAINER_ID);
4157
+ el?.contentWindow?.postMessage(text, '*');
4158
+ }
4159
+ catch {
4160
+ // Fails silently if cross-origin
4161
+ }
4162
+ }
4163
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealEffects, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4164
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealEffects }); }
4165
+ }
4166
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealEffects, decorators: [{
4167
+ type: Injectable
4168
+ }] });
4169
+
4170
+ function InstanceReadyHandler(msg) {
4171
+ const payload = msg?.payload;
4172
+ if (!payload) {
4173
+ Logger.warn('instanceReady received without payload — ignoring');
4174
+ return;
4175
+ }
4176
+ if (!payload.originInstanceUri) {
4177
+ Logger.warn('instanceReady without originInstanceUri — ignoring');
4178
+ return;
4179
+ }
4180
+ // Emit for observability (telemetry) and store the stream-machine coords.
4181
+ this.store.dispatch(instanceReady(payload));
4182
+ // This is the answer `requestCirrusViaSocket` is waiting for: the Cirrus
4183
+ // address (`originInstanceUri`) plus the connection id to hand it. The socket
4184
+ // itself is opened by the shared `connectToCirrus`, not here.
4185
+ this.onInstanceReady$.next(payload);
4186
+ }
4187
+
4188
+ function InstanceReservedHandler(msg) {
4189
+ this.store.dispatch(setOrchestrationParameters({
4190
+ instanceName: msg.payload.instanceId,
4191
+ streamRequestId: msg.payload.streamRequestId,
4192
+ eta: msg.payload.eta ?? 150,
4193
+ }));
4194
+ }
4195
+
4196
+ function PlayerCountHandler(msg) {
4197
+ Logger.log(msg);
4198
+ }
4199
+
4200
+ function SSInfoHandler(msg) {
4201
+ this.store.dispatch(updateCirrusInfo({ ssData: msg.data }));
4202
+ return null;
4203
+ }
4204
+
4205
+ const dropCodes = [
4206
+ WSCloseCode_UNKNOWN,
4207
+ WSCloseCode_CIRRUS_PLAYER_DISCONNECTED,
4208
+ WSCloseCode_CIRRUS_ABNORMAL_CLOSURE,
4209
+ WSCloseCode_CIRRUS_STREAMER_KIKED_PLAYER,
4210
+ WSCloseCode_CIRRUS_MAX_PLAYERS_ERROR,
4211
+ ];
4212
+ function OnCloseHandler(e) {
4213
+ const message = `WebSocket closed: ${JSON.stringify(e.code)} - ${e.reason}`;
4214
+ Logger.warn(message);
4215
+ this.store.dispatch(setCirrusDisconnected());
4216
+ if (dropCodes.includes(e.code)) {
4217
+ this.store.dispatch(dropConnection());
4218
+ }
4219
+ }
4220
+
4221
+ function OnErrorHandler(e) {
4222
+ Logger.warn(`WS error: ${JSON.stringify(e)}`);
4223
+ this.store.dispatch(disconnectStream({
4224
+ reason: DisconnectReason.WebSocketError,
4225
+ message: 'WebSocket Error',
4226
+ }));
4227
+ }
4228
+
4229
+ function OnMessageHandler(e) {
4230
+ const handleData = (data) => {
4231
+ //Logger.colored(...COLOR_CODES.FROM_SIGNALING, data);
4232
+ const msg = JSON.parse(data);
4233
+ this.handleMessage(msg);
4234
+ };
4235
+ if (typeof e.data === 'string') {
4236
+ try {
4237
+ handleData(e.data);
4238
+ }
4239
+ catch (err) {
4240
+ Logger.warn('OnMessageHandler: failed to parse string message', err);
4241
+ }
4242
+ }
4243
+ else if (e.data instanceof Blob) {
4244
+ e.data
4245
+ .text()
4246
+ .then(handleData)
4247
+ .catch((err) => Logger.warn('OnMessageHandler: failed to parse Blob message', err));
4248
+ }
4249
+ }
4250
+
4251
+ /**
4252
+ * Open handler of the CIRRUS socket only (`addWsHandlers`), so
4253
+ * `setCirrusConnected` now means what it says. It used to also send
4254
+ * `requestStream` here, which made the flag fire on the orchestration control
4255
+ * socket — a whole provisioning wait (`eta`, ~150 s) before any Cirrus existed.
4256
+ * `requestStream` belongs to the control socket and is sent by
4257
+ * `requestCirrusViaSocket`.
4258
+ */
4259
+ function OnOpenHandler() {
4260
+ this.store.dispatch(setCirrusConnected());
4261
+ }
4262
+
4263
+ /**
4264
+ * Keeps the max of numbers seen so far; resets to 0 whenever `reset$` emits.
4265
+ */
4266
+ const keepMaxUntilReset = (reset$) => (source$) => merge(source$, reset$.pipe(map$1(() => null))).pipe(scan((max, value) => (value === null ? 0 : Math.max(max, value)), 0));
4267
+
4268
+ // Reused across every inbound data-channel message — instantiating a
4269
+ // TextDecoder per call adds needless GC churn on a hot path.
4270
+ const utf16Decoder = new TextDecoder('utf-16');
4271
+ function decodeData(anyData) {
4272
+ try {
4273
+ return utf16Decoder.decode(anyData);
4274
+ }
4275
+ catch {
4276
+ return '';
4277
+ }
4278
+ }
4279
+
4280
+ const dispatchResize = () => {
4281
+ window.dispatchEvent(new Event('resize'));
4282
+ };
4283
+
4284
+ const errorCodes = {
4285
+ code404: 'Your asset is being synced on Metabox servers and is not yet available in Metabox Studio or Metabox Configurator. Please check again later after syncing is complete. ',
4286
+ };
4287
+ function getRtcErrorMessage(code) {
4288
+ if (code === null) {
4289
+ return undefined;
4290
+ }
4291
+ return errorCodes[`code${code}`];
4292
+ }
4293
+
4294
+ const JUMP_THRESHOLD = 0.95;
4295
+ const MAX_TRANSITION_DURATION_MS = 200;
4296
+ /**
4297
+ * Maps a 0..1 stream directly to a 0..100 integer percent stream.
4298
+ * No animation — emits whatever the source emits, rounded and clamped.
4299
+ */
4300
+ const floatToPercents = () => (source) => source.pipe(map((value) => clampf(0, 100, Math.round(value * 100))));
4301
+ /**
4302
+ * Maps a 0..1 progress stream to a smoothed 0..100 integer percent stream.
4303
+ * Animates between consecutive values over up to 200ms; jumps directly when
4304
+ * the delta exceeds 0.95 (treated as a reset, not a real progression).
4305
+ */
4306
+ const floatToSmoothPercents = () => (source) => source.pipe(timestamp(), startWith({ value: 0, timestamp: 0 }), pairwise(), concatMap(([prev, curr]) => {
4307
+ const isJump = Math.abs(curr.value - prev.value) > JUMP_THRESHOLD;
4308
+ const dt = prev.timestamp ? curr.timestamp - prev.timestamp : 0;
4309
+ if (isJump || dt === 0) {
4310
+ return of(curr.value);
4311
+ }
4312
+ return smoothTransition(prev.value, curr.value, Math.min(dt, MAX_TRANSITION_DURATION_MS));
4313
+ }), floatToPercents());
4314
+ /**
4315
+ * Smoothly interpolates from `start` to `end` over `duration`ms using the
4316
+ * animation frame scheduler. Completes when the transition finishes.
4317
+ *
4318
+ * NOTE: duplicates `smoothTransition` from `@3dsource/utils`. The utils version
4319
+ * is missing `takeWhile(... < 1, true)` and never completes — which would
4320
+ * deadlock the `concatMap` above. Keep this local copy until utils is fixed.
4321
+ * Not exported: internal to `floatToSmoothPercents`.
4322
+ */
4323
+ const smoothTransition = (start, end, duration) => {
4324
+ const startTime = animationFrameScheduler.now();
4325
+ return interval(0, animationFrameScheduler).pipe(map(() => clampf(0, 1, (animationFrameScheduler.now() - startTime) / duration)), distinctUntilChanged(), takeWhile((fraction) => fraction < 1, true), map((fraction) => lerp(start, end, fraction)));
4326
+ };
4327
+
4328
+ const getImageFromVideoStream = (takeSizeFrom = 'video', imageOutput, sizes) => {
4329
+ try {
4330
+ const video = document.getElementById(STREAMING_VIDEO_ID);
4331
+ const { canvas, ctx } = getCanvasCached('video');
4332
+ canvas.width =
4333
+ takeSizeFrom === 'video'
4334
+ ? sizes?.width || video?.clientWidth || FULL_HD_WIDTH
4335
+ : FULL_HD_WIDTH;
4336
+ canvas.height =
4337
+ takeSizeFrom === 'video'
4338
+ ? sizes?.height || video?.clientHeight || FULL_HD_HEIGHT
4339
+ : FULL_HD_HEIGHT;
4340
+ ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
4341
+ return getSnapshot(canvas, canvas.width, imageOutput);
4342
+ }
4343
+ catch {
4344
+ return null;
4345
+ }
4346
+ };
4347
+
4348
+ /**
4349
+ * Generator that cycles through `urls` indefinitely. Each call to
4350
+ * `getActiveUrl(urls)` returns a fresh generator with its own counter,
4351
+ * so concurrent generators (e.g., overlapping reconnect attempts) do
4352
+ * not share state. The counter is initialized once per generator
4353
+ * instance — before any `yield` — so each `.next()` call advances
4354
+ * within that single generator.
4355
+ */
4356
+ function* getActiveUrl(urls) {
4357
+ let index = 0;
4358
+ while (true) {
4359
+ yield urls[index++ % urls.length];
4360
+ }
4361
+ }
4362
+
4363
+ class LatencyTimings {
4364
+ constructor() {
4365
+ this.TestStartTimeMs = null;
4366
+ this.UEReceiptTimeMs = null;
4367
+ this.UEEncodeMs = null;
4368
+ this.UECaptureToSendMs = null;
4369
+ this.UETransmissionTimeMs = null;
4370
+ this.BrowserReceiptTimeMs = null;
4371
+ this.FrameDisplayDeltaTimeMs = null;
4372
+ }
4373
+ Reset() {
4374
+ this.TestStartTimeMs = null;
4375
+ this.UEReceiptTimeMs = null;
4376
+ this.UEEncodeMs = null;
4377
+ this.UECaptureToSendMs = null;
4378
+ this.UETransmissionTimeMs = null;
4379
+ this.BrowserReceiptTimeMs = null;
4380
+ this.FrameDisplayDeltaTimeMs = null;
4381
+ }
4382
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
4383
+ SetUETimings(UETimings) {
4384
+ this.UEReceiptTimeMs = UETimings.ReceiptTimeMs;
4385
+ this.UEEncodeMs = UETimings.EncodeMs;
4386
+ this.UECaptureToSendMs = UETimings.CaptureToSendMs;
4387
+ this.UETransmissionTimeMs = UETimings.TransmissionTimeMs;
4388
+ this.BrowserReceiptTimeMs = Date.now();
4389
+ }
4390
+ SetFrameDisplayDeltaTime(DeltaTimeMs) {
4391
+ if (this.FrameDisplayDeltaTimeMs == null) {
4392
+ this.FrameDisplayDeltaTimeMs = Math.round(DeltaTimeMs);
4393
+ }
4394
+ }
4395
+ }
4396
+
4397
+ function qpToQuality(VideoEncoderQP) {
4398
+ const orangeQP = 26;
4399
+ const redQP = 35;
4400
+ let quality = 'lime';
4401
+ if (VideoEncoderQP > redQP) {
4402
+ quality = 'red';
4403
+ }
4404
+ else if (VideoEncoderQP > orangeQP) {
4405
+ quality = 'orange';
4406
+ }
4407
+ return quality;
4408
+ }
4409
+
4410
+ /**
4411
+ * Base64-encodes a byte array.
4412
+ *
4413
+ * Builds the intermediate binary string in fixed-size chunks instead of
4414
+ * concatenating one character at a time. The naive `bytes.reduce((s, b) => s +
4415
+ * String.fromCharCode(b), '')` is O(n²) (each `+` re-copies the growing string)
4416
+ * and stalls the main thread for a full-resolution frame; chunking keeps it
4417
+ * O(n). The chunk size stays under the argument-count limit of
4418
+ * `String.fromCharCode.apply`/spread.
4419
+ *
4420
+ * @param bytes - The raw bytes to encode.
4421
+ * @returns The Base64 representation of `bytes`.
4422
+ */
4423
+ function uint8ToBase64(bytes) {
4424
+ const CHUNK_SIZE = 0x8000;
4425
+ let binary = '';
4426
+ for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {
4427
+ binary += String.fromCharCode(...bytes.subarray(i, i + CHUNK_SIZE));
4528
4428
  }
4529
- /**
4530
- * Either schedules the next peer-reconnect attempt or gives up with the
4531
- * supplied reason. Used in two `executePeerReconnect$` branches that share
4532
- * the same retry-or-fail decision.
4533
- */
4534
- scheduleRetryOrFail(attempt, maxAttempts, exhaustedReason) {
4535
- return attempt < maxAttempts
4536
- ? reconnectPeer({ attempt: attempt + 1, maxAttempts })
4537
- : reconnectPeerFailed({ reason: exhaustedReason });
4429
+ return btoa(binary);
4430
+ }
4431
+
4432
+ function fromResizeObserver(elem) {
4433
+ return new Observable((subscriber) => {
4434
+ const observer = new window.ResizeObserver((entries) => subscriber.next(entries));
4435
+ observer.observe(elem);
4436
+ return () => observer.unobserve(elem);
4437
+ });
4438
+ }
4439
+
4440
+ /*
4441
+ * Copyright (c) 2026.
4442
+ * 3DSource.com. Sergii Karanda steve@3dsource.com. All Rights Reserved.
4443
+ */
4444
+ /**
4445
+ * Rounds a number to the nearest even integer (rounding up for odd values).
4446
+ *
4447
+ * Video encoders (H.264/H.265) require even dimensions because chroma subsampling
4448
+ * operates on 2×2 pixel blocks. Odd dimensions cause encoding artifacts or failures.
4449
+ *
4450
+ * @param value - The number to round to the nearest even integer.
4451
+ * @returns The nearest even integer greater than or equal to the input.
4452
+ *
4453
+ * @example
4454
+ * makeEven(1079) // 1080
4455
+ * makeEven(1080) // 1080
4456
+ * makeEven(1081) // 1082
4457
+ */
4458
+ function makeEven(value) {
4459
+ return Math.floor((value + 1) / 2) * 2;
4460
+ }
4461
+
4462
+ const FULL_HD_PIXELS = FULL_HD_WIDTH * FULL_HD_HEIGHT;
4463
+ const UHD_PIXELS = FULL_HD_WIDTH * 2 * (FULL_HD_HEIGHT * 2);
4464
+ /**
4465
+ * Calculates the optimal stream resolution for studio mode.
4466
+ *
4467
+ * Fits the studio aspect ratio into the container (scaled by pixelRatio), then
4468
+ * caps the total pixel count to a budget (Full HD or 4K) to avoid overloading
4469
+ * the GPU/encoder while maximizing visual quality.
4470
+ *
4471
+ * The pixel budget approach (instead of per-dimension caps) ensures that
4472
+ * non-standard aspect ratios (portrait, ultra-wide, square) utilize available
4473
+ * pixels efficiently — e.g. a tall 1080×1920 stream uses the same pixel budget
4474
+ * as a wide 1920×1080 stream.
4475
+ *
4476
+ * Resolution is always capped at the studio dimensions — never upscaled beyond
4477
+ * what the Unreal scene was designed for.
4478
+ *
4479
+ * @param params.pixelRatio - Device pixel ratio (`window.devicePixelRatio`).
4480
+ * @param params.containerWidth - CSS width of the video container in pixels.
4481
+ * @param params.containerHeight - CSS height of the video container in pixels.
4482
+ * @param params.studioWidth - Target width of the MetaBox Studio scene.
4483
+ * @param params.studioHeight - Target height of the MetaBox Studio scene.
4484
+ * @param params.maxResolution - When `true`, uses 4K pixel budget (3840×2160);
4485
+ * otherwise Full HD (1920×1080). Controlled by `?maxresolution` query param.
4486
+ * @returns An {@link Area} with the calculated `w`, `h`, position (`x`, `y`),
4487
+ * and `scale` factor relative to the container's device-pixel size.
4488
+ */
4489
+ function getResizeStudioValues(params) {
4490
+ const { pixelRatio, containerWidth, containerHeight, studioWidth, studioHeight, maxResolution, } = params;
4491
+ const maxSpace = {
4492
+ w: containerWidth * pixelRatio,
4493
+ h: containerHeight * pixelRatio,
4494
+ };
4495
+ const maxPixels = maxResolution ? UHD_PIXELS : FULL_HD_PIXELS;
4496
+ const videoSizePixelPerfect = fitIntoRectangle({ x: 0, y: 0, w: studioWidth, h: studioHeight }, { x: 0, y: 0, ...maxSpace });
4497
+ let w = videoSizePixelPerfect.w;
4498
+ let h = videoSizePixelPerfect.h;
4499
+ if (w * h > maxPixels) {
4500
+ // Derive uniform scale factor `s` from: (w*s) * (h*s) = maxPixels
4501
+ // → w * h * s² = maxPixels → s = √(maxPixels / (w * h)).
4502
+ // Applying the same `s` to both dimensions preserves the aspect ratio.
4503
+ const scaleFactor = Math.sqrt(maxPixels / (w * h));
4504
+ w = w * scaleFactor;
4505
+ h = h * scaleFactor;
4538
4506
  }
4539
- postToScreenLocker(text) {
4540
- try {
4541
- const el = document.getElementById(this.unrealInitialConfig?.screenLockerContainerId ??
4542
- SCREEN_LOCKER_CONTAINER_ID);
4543
- el?.contentWindow?.postMessage(text, '*');
4544
- }
4545
- catch {
4546
- // Fails silently if cross-origin
4547
- }
4507
+ const out = fitIntoRectangle(videoSizePixelPerfect, {
4508
+ x: videoSizePixelPerfect.x,
4509
+ y: videoSizePixelPerfect.y,
4510
+ w,
4511
+ h,
4512
+ });
4513
+ out.w = makeEven(out.w);
4514
+ out.h = makeEven(out.h);
4515
+ return out;
4516
+ }
4517
+ /**
4518
+ * Calculates the optimal stream resolution for configurator (non-studio) mode.
4519
+ *
4520
+ * Uses the full container area (scaled by pixelRatio) as the stream resolution,
4521
+ * then caps total pixel count to a budget (Full HD or 4K) to prevent excessive
4522
+ * GPU/encoder load while preserving the container's aspect ratio.
4523
+ *
4524
+ * Unlike {@link getResizeStudioValues}, there is no fixed studio resolution to
4525
+ * fit into — the container itself defines the aspect ratio, and the stream fills
4526
+ * it entirely (no letterboxing).
4527
+ *
4528
+ * @param params.pixelRatio - Device pixel ratio (`window.devicePixelRatio`).
4529
+ * @param params.containerWidth - CSS width of the video container in pixels.
4530
+ * @param params.containerHeight - CSS height of the video container in pixels.
4531
+ * @param params.maxResolution - When `true`, uses 4K pixel budget (3840×2160);
4532
+ * otherwise Full HD (1920×1080). Controlled by `?maxresolution` query param.
4533
+ * @returns An {@link Area} with the calculated `w`, `h`, position (`x`, `y`),
4534
+ * and `scale` factor (1 when no downscale needed, <1 when capped).
4535
+ */
4536
+ function getResizeValuesUniversal(params) {
4537
+ const { pixelRatio, containerWidth, containerHeight, maxResolution } = params;
4538
+ const maxSpace = {
4539
+ w: containerWidth * pixelRatio,
4540
+ h: containerHeight * pixelRatio,
4541
+ };
4542
+ const maxPixels = maxResolution ? UHD_PIXELS : FULL_HD_PIXELS;
4543
+ let w = maxSpace.w;
4544
+ let h = maxSpace.h;
4545
+ if (w * h > maxPixels) {
4546
+ // Derive uniform scale factor `s` from: (w*s) * (h*s) = maxPixels
4547
+ // → w * h * s² = maxPixels → s = √(maxPixels / (w * h)).
4548
+ // Applying the same `s` to both dimensions preserves the aspect ratio.
4549
+ const scaleFactor = Math.sqrt(maxPixels / (w * h));
4550
+ w = w * scaleFactor;
4551
+ h = h * scaleFactor;
4548
4552
  }
4549
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealEffects, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4550
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealEffects }); }
4553
+ return { w: makeEven(w), h: makeEven(h), x: 0, y: 0, scale: w / maxSpace.w };
4554
+ }
4555
+
4556
+ /**
4557
+ * Picks the class that carries the decoration of a UI part: the host class when
4558
+ * one is supplied, the built-in one otherwise. An empty string counts as "not
4559
+ * supplied" so a part never ends up with no styling at all.
4560
+ */
4561
+ function resolveSkin(classes, part, fallback) {
4562
+ const custom = classes[part];
4563
+ if (custom === undefined || custom === '') {
4564
+ return fallback;
4565
+ }
4566
+ return custom;
4551
4567
  }
4552
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealEffects, decorators: [{
4553
- type: Injectable
4554
- }] });
4555
4568
 
4556
4569
  class AFKService extends SubService {
4557
4570
  constructor() {
@@ -4667,10 +4680,10 @@ class AFKService extends SubService {
4667
4680
  }
4668
4681
  }, 1000);
4669
4682
  }
4670
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AFKService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4671
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AFKService, providedIn: 'root' }); }
4683
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AFKService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4684
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AFKService, providedIn: 'root' }); }
4672
4685
  }
4673
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AFKService, decorators: [{
4686
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AFKService, decorators: [{
4674
4687
  type: Injectable,
4675
4688
  args: [{ providedIn: 'root' }]
4676
4689
  }], ctorParameters: () => [] });
@@ -4720,10 +4733,10 @@ class LoadingProgressService {
4720
4733
  // `switchMap` cancels the inner subscription on every visibility change
4721
4734
  // so stale emissions can't leak through.
4722
4735
  #boundedProgress$;
4723
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: LoadingProgressService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4724
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: LoadingProgressService, providedIn: 'root' }); }
4736
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: LoadingProgressService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4737
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: LoadingProgressService, providedIn: 'root' }); }
4725
4738
  }
4726
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: LoadingProgressService, decorators: [{
4739
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: LoadingProgressService, decorators: [{
4727
4740
  type: Injectable,
4728
4741
  args: [{ providedIn: 'root' }]
4729
4742
  }] });
@@ -4809,10 +4822,10 @@ class FreezeFrameService extends SubService {
4809
4822
  progress: 1,
4810
4823
  }));
4811
4824
  }
4812
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FreezeFrameService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4813
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FreezeFrameService, providedIn: 'root' }); }
4825
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FreezeFrameService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4826
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FreezeFrameService, providedIn: 'root' }); }
4814
4827
  }
4815
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FreezeFrameService, decorators: [{
4828
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FreezeFrameService, decorators: [{
4816
4829
  type: Injectable,
4817
4830
  args: [{ providedIn: 'root' }]
4818
4831
  }], ctorParameters: () => [] });
@@ -4857,6 +4870,121 @@ const deepEqual = (a, b) => {
4857
4870
  return false;
4858
4871
  };
4859
4872
 
4873
+ class FileReceiverService extends SubService {
4874
+ constructor() {
4875
+ super();
4876
+ this.fileComplete$ = new Subject();
4877
+ this.valid = false;
4878
+ this.chunks = 0;
4879
+ this.mimetype = '';
4880
+ this.receiving = false;
4881
+ this.extension = '';
4882
+ this.data = [];
4883
+ this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
4884
+ this.init();
4885
+ }
4886
+ init() {
4887
+ if (this.unrealConfig?.playwright) {
4888
+ return;
4889
+ }
4890
+ this.store
4891
+ .select(unrealFeature.selectViewportReady)
4892
+ .pipe(filter(Truthy), takeUntil(this.destroy$))
4893
+ .subscribe(() => this.reset());
4894
+ }
4895
+ reset() {
4896
+ this.mimetype = '';
4897
+ this.extension = '';
4898
+ this.receiving = false;
4899
+ this.valid = false;
4900
+ this.chunks = 0;
4901
+ this.data = [];
4902
+ }
4903
+ resetOnStart() {
4904
+ this.reset();
4905
+ this.receiving = true;
4906
+ }
4907
+ /**
4908
+ * Processes a file extension when received over data channel
4909
+ * @param view - the file extension data
4910
+ */
4911
+ setExtensionFromBytes(view) {
4912
+ // Reset this if we got a file message and we are not "receiving" it yet
4913
+ if (!this.receiving) {
4914
+ this.resetOnStart();
4915
+ }
4916
+ //Logger.info(extensionAsString);
4917
+ this.extension = decodeData(view.slice(1).buffer);
4918
+ }
4919
+ /**
4920
+ * Processes a file mime type when received over data channel
4921
+ * @param view - the file mime type data
4922
+ */
4923
+ setMimeTypeFromBytes(view) {
4924
+ // Reset this if we got a file message and we are not "receiving" it yet
4925
+ if (!this.receiving) {
4926
+ this.resetOnStart();
4927
+ }
4928
+ const mimeAsString = decodeData(view.slice(1).buffer);
4929
+ // Logger.info(mimeAsString);
4930
+ this.mimetype = mimeAsString;
4931
+ }
4932
+ /*-------------------------------------------------------------------------------------------*/
4933
+ setContentsFromBytes(view) {
4934
+ // If we haven't received the initial setup instructions, return
4935
+ if (!this.receiving)
4936
+ return;
4937
+ const typeSize = 1;
4938
+ const intSize = 4;
4939
+ const maxMessageSize = 16 * 1024;
4940
+ const headerSize = typeSize + intSize;
4941
+ const maxPayloadSize = maxMessageSize - headerSize;
4942
+ // Calculate the total number of chunks from the total this size
4943
+ this.chunks = Math.ceil(new DataView(view.slice(typeSize, headerSize).buffer).getInt32(0, true) /
4944
+ maxPayloadSize);
4945
+ // Get the file part of the payload
4946
+ const thisBytes = view.slice(headerSize);
4947
+ // Append to existing data that holds this
4948
+ this.data.push(thisBytes);
4949
+ // Uncomment for debug
4950
+ // Logger.info(`Received this chunk: ${this.data.length}/${this.chunks}`);
4951
+ if (this.data.length === this.chunks) {
4952
+ this.receiving = false;
4953
+ this.valid = true;
4954
+ /*Logger.info('Received complete file');
4955
+ const transferDuration = new Date().getTime() - this.timestampStart;
4956
+ const transferBitrate = Math.round(
4957
+ (this.chunks * maxMessageSize) / transferDuration,
4958
+ );
4959
+ Logger.info(
4960
+ `Average transfer bitrate: ${transferBitrate}kb/s over ${transferDuration / 1000} seconds`,
4961
+ );*/
4962
+ /**
4963
+ * Reconstruct the file
4964
+ * This code reconstructs the received data into the original this based on the mime type and extension provided
4965
+ */
4966
+ const blob = new Blob([...this.data], { type: this.mimetype });
4967
+ this.fileComplete$.next({
4968
+ blob,
4969
+ mimetype: this.mimetype,
4970
+ extension: this.extension,
4971
+ valid: this.valid,
4972
+ });
4973
+ this.reset();
4974
+ }
4975
+ else if (this.data.length > this.chunks) {
4976
+ Logger.error(`Received bigger this than advertised: ${this.data.length}/${this.chunks}`);
4977
+ this.reset();
4978
+ }
4979
+ }
4980
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FileReceiverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
4981
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FileReceiverService, providedIn: 'root' }); }
4982
+ }
4983
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FileReceiverService, decorators: [{
4984
+ type: Injectable,
4985
+ args: [{ providedIn: 'root' }]
4986
+ }], ctorParameters: () => [] });
4987
+
4860
4988
  const filteredLogs = [
4861
4989
  {
4862
4990
  command: 'onChangeSequence',
@@ -4869,6 +4997,7 @@ class AggregatorService extends SubService {
4869
4997
  this.videoService = inject(VideoService);
4870
4998
  this.webrtcPlayer = inject(WebRtcPlayerService);
4871
4999
  this.freezeFrame = inject(FreezeFrameService);
5000
+ this.fileReceiver = inject(FileReceiverService);
4872
5001
  this.unrealConfig = inject(UNREAL_CONFIG, { optional: true });
4873
5002
  this.responseEventListeners = new Map();
4874
5003
  this.init();
@@ -4983,12 +5112,17 @@ class AggregatorService extends SubService {
4983
5112
  }
4984
5113
  break;
4985
5114
  }
4986
- // DataChannel file transfer is recognized but deliberately ignored:
4987
- // nothing on the client consumes the reassembled file.
4988
5115
  case ToClientMessage.FileExtension:
5116
+ Logger.colored(...COLOR_CODES.FROM_UNREAL, 'FileExtension');
5117
+ this.fileReceiver.setExtensionFromBytes(view);
5118
+ break;
4989
5119
  case ToClientMessage.FileMimeType:
5120
+ Logger.colored(...COLOR_CODES.FROM_UNREAL, 'FileMimeType');
5121
+ this.fileReceiver.setMimeTypeFromBytes(view);
5122
+ break;
4990
5123
  case ToClientMessage.FileContents:
4991
- Logger.colored(...COLOR_CODES.FROM_UNREAL, 'File message ignored');
5124
+ Logger.colored(...COLOR_CODES.FROM_UNREAL, 'FileContents');
5125
+ this.fileReceiver.setContentsFromBytes(view);
4992
5126
  break;
4993
5127
  case ToClientMessage.FreezeFrame:
4994
5128
  Logger.colored(...COLOR_CODES.FROM_UNREAL, 'Freeze frame');
@@ -5025,10 +5159,10 @@ class AggregatorService extends SubService {
5025
5159
  Logger.warn(`unrecognized data received, packet ID ${view[0]}`);
5026
5160
  }
5027
5161
  }
5028
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AggregatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
5029
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AggregatorService, providedIn: 'root' }); }
5162
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AggregatorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
5163
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AggregatorService, providedIn: 'root' }); }
5030
5164
  }
5031
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AggregatorService, decorators: [{
5165
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AggregatorService, decorators: [{
5032
5166
  type: Injectable,
5033
5167
  args: [{ providedIn: 'root' }]
5034
5168
  }], ctorParameters: () => [] });
@@ -5174,7 +5308,7 @@ class ConsoleExtensionsService extends SubService {
5174
5308
  // `store.select` replays the current value synchronously, so if it already
5175
5309
  // equals `target` this resolves immediately; otherwise it waits for the
5176
5310
  // transition or falls back to `false` after `timeoutMs`.
5177
- return firstValueFrom(this.store.select(unrealFeature.selectDataChannelConnected).pipe(filter((connected) => connected === target), take(1), map(() => true), timeout$1({ first: timeoutMs, with: () => of(false) })));
5311
+ return firstValueFrom(this.store.select(unrealFeature.selectDataChannelConnected).pipe(filter((connected) => connected === target), take(1), map$1(() => true), timeout$1({ first: timeoutMs, with: () => of(false) })));
5178
5312
  }
5179
5313
  sleep(ms) {
5180
5314
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -5189,10 +5323,10 @@ class ConsoleExtensionsService extends SubService {
5189
5323
  Logger.info('emitCommand(command) => send command to Unreal Engine.');
5190
5324
  Logger.info('stressTest({iterations}) => hammer reconnect: repeatedly drop DC/PC and assert recovery.');
5191
5325
  }
5192
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: ConsoleExtensionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
5193
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: ConsoleExtensionsService, providedIn: 'root' }); }
5326
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ConsoleExtensionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
5327
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ConsoleExtensionsService, providedIn: 'root' }); }
5194
5328
  }
5195
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: ConsoleExtensionsService, decorators: [{
5329
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ConsoleExtensionsService, decorators: [{
5196
5330
  type: Injectable,
5197
5331
  args: [{ providedIn: 'root' }]
5198
5332
  }], ctorParameters: () => [] });
@@ -5271,8 +5405,8 @@ class InputService extends SubService {
5271
5405
  if (this.unrealConfig?.playwright) {
5272
5406
  return;
5273
5407
  }
5274
- const visibilityHiddenTrigger$ = fromEvent(document, 'visibilitychange').pipe(map$1(() => document.visibilityState === 'hidden'), filter(Truthy));
5275
- const visibilityVisibleTrigger$ = fromEvent(document, 'visibilitychange').pipe(map$1(() => document.visibilityState === 'visible'), filter(Truthy), startWith(true));
5408
+ const visibilityHiddenTrigger$ = fromEvent(document, 'visibilitychange').pipe(map(() => document.visibilityState === 'hidden'), filter(Truthy));
5409
+ const visibilityVisibleTrigger$ = fromEvent(document, 'visibilitychange').pipe(map(() => document.visibilityState === 'visible'), filter(Truthy), startWith(true));
5276
5410
  this.deactivatedVideoTrigger$ = merge(this.disconnect$, this.reInit$, visibilityHiddenTrigger$, this.destroy$);
5277
5411
  merge(visibilityVisibleTrigger$, this.store.select(unrealFeature.selectViewportReady).pipe(filter(Truthy)))
5278
5412
  .pipe(filter(() => !!this.video), takeUntil$1(this.destroy$))
@@ -5693,10 +5827,10 @@ class InputService extends SubService {
5693
5827
  this.sendInputData(data.buffer);
5694
5828
  });
5695
5829
  }
5696
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: InputService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
5697
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: InputService, providedIn: 'root' }); }
5830
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: InputService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
5831
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: InputService, providedIn: 'root' }); }
5698
5832
  }
5699
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: InputService, decorators: [{
5833
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: InputService, decorators: [{
5700
5834
  type: Injectable,
5701
5835
  args: [{ providedIn: 'root' }]
5702
5836
  }], ctorParameters: () => [] });
@@ -5726,7 +5860,7 @@ class StreamStatusTelemetryService extends SubService {
5726
5860
  return this.videoService.videoStats$.pipe(throttleTime(5000, asyncScheduler, {
5727
5861
  leading: true,
5728
5862
  trailing: true,
5729
- }), withLatestFrom(this.store.select(unrealFeature.selectAwsInstance), signalingReadyTime$, viewPortReadyTime$), map$1(([data, signalingServer, signalingReadyTime, viewPortReadyTime,]) => this.mapEventData({
5863
+ }), withLatestFrom(this.store.select(unrealFeature.selectAwsInstance), signalingReadyTime$, viewPortReadyTime$), map(([data, signalingServer, signalingReadyTime, viewPortReadyTime,]) => this.mapEventData({
5730
5864
  data,
5731
5865
  signalingServer,
5732
5866
  startTimeUtc,
@@ -5742,7 +5876,7 @@ class StreamStatusTelemetryService extends SubService {
5742
5876
  * Used with `withLatestFrom` so events carry a stable duration for the whole session.
5743
5877
  */
5744
5878
  readyTimeSince(readyState$, startedAt) {
5745
- return readyState$.pipe(filter(Boolean), take$1(1), map$1(() => Date.now() - startedAt), startWith$1(undefined));
5879
+ return readyState$.pipe(filter(Boolean), take$1(1), map(() => Date.now() - startedAt), startWith$1(undefined));
5746
5880
  }
5747
5881
  mapEventData(params) {
5748
5882
  const { data, signalingServer, startTimeUtc, signalingReadyTime, viewPortReadyTime, } = params;
@@ -5765,10 +5899,10 @@ class StreamStatusTelemetryService extends SubService {
5765
5899
  VideoEncoderQP,
5766
5900
  };
5767
5901
  }
5768
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: StreamStatusTelemetryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
5769
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: StreamStatusTelemetryService, providedIn: 'root' }); }
5902
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamStatusTelemetryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
5903
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamStatusTelemetryService, providedIn: 'root' }); }
5770
5904
  }
5771
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: StreamStatusTelemetryService, decorators: [{
5905
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamStatusTelemetryService, decorators: [{
5772
5906
  type: Injectable,
5773
5907
  args: [{ providedIn: 'root' }]
5774
5908
  }], ctorParameters: () => [] });
@@ -5893,7 +6027,7 @@ class StreamStatusTelemetryService2 {
5893
6027
  * `startWith(null)` seed makes `withLatestFrom` on this stream safe even
5894
6028
  * before the first video stat arrives (common at data-channel-open).
5895
6029
  */
5896
- this.selectedPair$ = this.videoService.videoStats$.pipe(map((s) => s.aggregatedStats.selectedPair ?? null), scan((acc, curr) => curr ?? acc, null), startWith(null));
6030
+ this.selectedPair$ = this.videoService.videoStats$.pipe(map$1((s) => s.aggregatedStats.selectedPair ?? null), scan((acc, curr) => curr ?? acc, null), startWith(null));
5897
6031
  /**
5898
6032
  * Correlation-matched Observable: emits once when the first `loopBack`
5899
6033
  * command's corresponding `command completed` action fires. Built from
@@ -5963,7 +6097,7 @@ class StreamStatusTelemetryService2 {
5963
6097
  // never ran or its cache expired.
5964
6098
  {
5965
6099
  id: 'region-resolved',
5966
- event: this.actions$.pipe(ofType(regionResolved), take(1), map(({ region, pingsMs }) => ({
6100
+ event: this.actions$.pipe(ofType(regionResolved), take(1), map$1(({ region, pingsMs }) => ({
5967
6101
  region,
5968
6102
  pingsMs: pingsMs.length ? `${pingsMs.join(', ')} ms` : null,
5969
6103
  }))),
@@ -6009,7 +6143,7 @@ class StreamStatusTelemetryService2 {
6009
6143
  // is shipped under — see {@link SessionState.wireId}.
6010
6144
  {
6011
6145
  id: 'ssinfo-received',
6012
- event: this.store.select(unrealFeature.selectSsData).pipe(filter$1(Boolean), take(1), withLatestFrom$1(this.store.select(unrealFeature.selectAwsInstance), this.store.select(selectCirrusConnectionId)), map(([ssData, aws, connectionId]) => ({
6146
+ event: this.store.select(unrealFeature.selectSsData).pipe(filter$1(Boolean), take(1), withLatestFrom$1(this.store.select(unrealFeature.selectAwsInstance), this.store.select(selectCirrusConnectionId)), map$1(([ssData, aws, connectionId]) => ({
6013
6147
  client: aws.wsUrl,
6014
6148
  instanceName: aws.instanceName,
6015
6149
  ...ssData,
@@ -6054,7 +6188,7 @@ class StreamStatusTelemetryService2 {
6054
6188
  id: 'datachannel-connected',
6055
6189
  event: this.store
6056
6190
  .select(unrealFeature.selectDataChannelConnected)
6057
- .pipe(filter$1(Boolean), take(1), map(() => ({
6191
+ .pipe(filter$1(Boolean), take(1), map$1(() => ({
6058
6192
  iceCandidateCount: this.session?.iceCandidateCount ?? 0,
6059
6193
  handshakeFlow: this.session?.handshakeFlow ?? null,
6060
6194
  }))),
@@ -6086,7 +6220,7 @@ class StreamStatusTelemetryService2 {
6086
6220
  // fired at Unreal before the viewport was ready.
6087
6221
  {
6088
6222
  id: 'viewport-ready',
6089
- event: this.store.select(unrealFeature.selectViewportReady).pipe(filter$1(Boolean), take(1), withLatestFrom$1(this.selectedPair$), map(([, selectedPair]) => ({
6223
+ event: this.store.select(unrealFeature.selectViewportReady).pipe(filter$1(Boolean), take(1), withLatestFrom$1(this.selectedPair$), map$1(([, selectedPair]) => ({
6090
6224
  localCandidate: fmtCandidate(selectedPair?.local),
6091
6225
  remoteCandidate: fmtCandidate(selectedPair?.remote),
6092
6226
  commandCount: this.session?.commandCount ?? 0,
@@ -6870,10 +7004,10 @@ class StreamStatusTelemetryService2 {
6870
7004
  emit(event, data) {
6871
7005
  this.store.dispatch(trackTelemetryData({ event, data }));
6872
7006
  }
6873
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: StreamStatusTelemetryService2, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
6874
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: StreamStatusTelemetryService2, providedIn: 'root' }); }
7007
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamStatusTelemetryService2, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
7008
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamStatusTelemetryService2, providedIn: 'root' }); }
6875
7009
  }
6876
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: StreamStatusTelemetryService2, decorators: [{
7010
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StreamStatusTelemetryService2, decorators: [{
6877
7011
  type: Injectable,
6878
7012
  args: [{ providedIn: 'root' }]
6879
7013
  }], ctorParameters: () => [] });
@@ -6925,6 +7059,48 @@ function resolveOverlays(recipes, times, phaseStartMs, phaseEndMs) {
6925
7059
  return out;
6926
7060
  }
6927
7061
 
7062
+ const ReceivedMimeTypes = {
7063
+ ApplicationJson: 'application/json',
7064
+ };
7065
+
7066
+ class FileHandlerService {
7067
+ constructor() {
7068
+ this.fileService = inject(FileReceiverService);
7069
+ this.fileHandlers = {
7070
+ [ReceivedMimeTypes.ApplicationJson]: this.handleJsonFile.bind(this),
7071
+ };
7072
+ }
7073
+ handleJsonFile(data, correlationId) {
7074
+ const { blob } = data;
7075
+ return from(blob.text()).pipe(map((text) => JSON.parse(text)), filter(({ commandCallback }) => {
7076
+ return commandCallback.correlationId === correlationId;
7077
+ }));
7078
+ }
7079
+ observeFileResponse(mimetype, data, sender, timeOut = 60000) {
7080
+ const correlationId = generateUuid();
7081
+ const out = { ...data, correlationId };
7082
+ return defer(() => {
7083
+ const observable = this.fileService.fileComplete$.pipe(switchMap((data) => {
7084
+ if (data.valid && this.fileHandlers[mimetype]) {
7085
+ return this.fileHandlers[mimetype](data, correlationId).pipe(filter(Truthy));
7086
+ }
7087
+ return of(null);
7088
+ }), timeout$1(timeOut), catchError((e) => {
7089
+ Logger.error(e);
7090
+ return of(null);
7091
+ }), take(1));
7092
+ setTimeout(() => sender(out), 0);
7093
+ return observable;
7094
+ });
7095
+ }
7096
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FileHandlerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
7097
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FileHandlerService, providedIn: 'root' }); }
7098
+ }
7099
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FileHandlerService, decorators: [{
7100
+ type: Injectable,
7101
+ args: [{ providedIn: 'root' }]
7102
+ }] });
7103
+
6928
7104
  class AnalyticsService extends SubService {
6929
7105
  #stopMouse$ = new Subject();
6930
7106
  constructor() {
@@ -7009,10 +7185,10 @@ class AnalyticsService extends SubService {
7009
7185
  Logger.log('Analytics Event:', name, params);
7010
7186
  this.store.dispatch(saveAnalyticsEvent({ event: { name, params } }));
7011
7187
  }
7012
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AnalyticsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
7013
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AnalyticsService, providedIn: 'root' }); }
7188
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AnalyticsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
7189
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AnalyticsService, providedIn: 'root' }); }
7014
7190
  }
7015
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AnalyticsService, decorators: [{
7191
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AnalyticsService, decorators: [{
7016
7192
  type: Injectable,
7017
7193
  args: [{ providedIn: 'root' }]
7018
7194
  }], ctorParameters: () => [] });
@@ -7379,10 +7555,10 @@ class FpsMonitorService extends SubService {
7379
7555
  }
7380
7556
  return { fps: fps / len, bitrate: bitrate / len, qp: qp / len };
7381
7557
  }
7382
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FpsMonitorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
7383
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FpsMonitorService, providedIn: 'root' }); }
7558
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FpsMonitorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
7559
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FpsMonitorService, providedIn: 'root' }); }
7384
7560
  }
7385
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FpsMonitorService, decorators: [{
7561
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FpsMonitorService, decorators: [{
7386
7562
  type: Injectable,
7387
7563
  args: [{ providedIn: 'root' }]
7388
7564
  }], ctorParameters: () => [] });
@@ -7396,19 +7572,34 @@ class AfkTimeoutModalComponent {
7396
7572
  this.afkCountdown = this.#store.selectSignal(unrealFeature.selectAfkCountdown);
7397
7573
  this.isShowAfkPopup = computed(() => this.isAfkTimerVisible() && this.showAfkTimeoutPopup(), /* @ts-ignore */
7398
7574
  ...(ngDevMode ? [{ debugName: "isShowAfkPopup" }] : /* istanbul ignore next */ []));
7575
+ this.uiClasses = input({}, /* @ts-ignore */
7576
+ ...(ngDevMode ? [{ debugName: "uiClasses" }] : /* istanbul ignore next */ []));
7577
+ this.contentTemplate = input(null, /* @ts-ignore */
7578
+ ...(ngDevMode ? [{ debugName: "contentTemplate" }] : /* istanbul ignore next */ []));
7579
+ this.scrimSkin = computed(() => resolveSkin(this.uiClasses(), 'afkScrim', 'afk-scrim'), /* @ts-ignore */
7580
+ ...(ngDevMode ? [{ debugName: "scrimSkin" }] : /* istanbul ignore next */ []));
7581
+ this.cardSkin = computed(() => resolveSkin(this.uiClasses(), 'afkCard', 'resume-box'), /* @ts-ignore */
7582
+ ...(ngDevMode ? [{ debugName: "cardSkin" }] : /* istanbul ignore next */ []));
7583
+ this.buttonSkin = computed(() => resolveSkin(this.uiClasses(), 'afkButton', 'afk-button'), /* @ts-ignore */
7584
+ ...(ngDevMode ? [{ debugName: "buttonSkin" }] : /* istanbul ignore next */ []));
7585
+ // Created once: identity stays stable, reactivity lives in the signals.
7586
+ this.slotContext = {
7587
+ countdown: this.afkCountdown,
7588
+ reset: () => this.resetAfk(),
7589
+ };
7399
7590
  }
7400
7591
  #store;
7401
7592
  #afkService;
7402
7593
  resetAfk() {
7403
7594
  this.#afkService.reset();
7404
7595
  }
7405
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AfkTimeoutModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7406
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: AfkTimeoutModalComponent, isStandalone: true, selector: "app-afk-timeout-modal", ngImport: i0, template: "@if (isShowAfkPopup()) {\r\n <div (click)=\"resetAfk()\" class=\"clickableState\" id=\"videoPlayOverlay\">\r\n <div class=\"resume-box\">\r\n <div aria-hidden=\"true\" class=\"resume-box__pic\" role=\"presentation\">\r\n <div [innerHTML]=\"afkCountdown()\" class=\"text-number\"></div>\r\n </div>\r\n <div class=\"resume-box__text\">\r\n <h3 class=\"resume-box__heading\">Session will time out soon</h3>\r\n <p>\r\n No activity detected. Press 'Continue' if you wish to keep your\r\n session active\r\n </p>\r\n </div>\r\n <app-unreal-button\r\n [fullWidth]=\"true\"\r\n [data-testid]=\"'continue-session'\"\r\n weight=\"primary\"\r\n size=\"lg\"\r\n >\r\n Continue\r\n </app-unreal-button>\r\n </div>\r\n </div>\r\n}\r\n", styles: ["#videoPlayOverlay{position:absolute;z-index:30;top:0;width:100%;height:100%;font-size:1.8em;font-family:var(--src-font-family-body, system-ui, sans-serif);background-color:#646464b3}.clickableState{display:flex;justify-content:center;align-items:center;cursor:pointer}.textDisplayState{display:flex}.hiddenState{display:none}.resume-box{width:340px;padding:32px 20px 20px;flex-direction:column;align-items:center;border-radius:var(--src-border-rounded-parent, 8px);background:var(--src-surface-container-main, #fff);box-shadow:0 26px 80px #0003,0 0 1px #0003}.resume-box .resume-box__pic{width:72px;height:72px;margin:0 auto 22px;border-radius:48px;background:#ecf0f2;padding:12px;display:flex;align-items:center;justify-content:center}.resume-box .resume-box__pic .text-number{color:#1f2937;text-align:center;font-family:var(--src-font-family-body, system-ui, sans-serif);font-size:30px;font-style:normal;font-weight:400;line-height:24px}.resume-box__text{margin-bottom:18px}.resume-box__text p{text-align:center;font-family:var(--src-font-family-body, system-ui, sans-serif);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:24px;color:var(--src-text-body-secondary, #6b7280)}.resume-box__text .resume-box__heading{color:var(--src-text-body-main, #1f2937);text-align:center;font-family:var(--src-font-family-body, system-ui, sans-serif);font-size:18px;font-style:normal;font-weight:500;line-height:26px;margin-bottom:8px}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7596
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AfkTimeoutModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7597
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: AfkTimeoutModalComponent, isStandalone: true, selector: "app-afk-timeout-modal", inputs: { uiClasses: { classPropertyName: "uiClasses", publicName: "uiClasses", isSignal: true, isRequired: false, transformFunction: null }, contentTemplate: { classPropertyName: "contentTemplate", publicName: "contentTemplate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isShowAfkPopup()) {\n <div\n (click)=\"resetAfk()\"\n [class]=\"scrimSkin()\"\n class=\"afk-anchor clickableState\"\n id=\"videoPlayOverlay\"\n >\n <div [class]=\"cardSkin()\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else {\n <div aria-hidden=\"true\" class=\"resume-box__pic\" role=\"presentation\">\n <div [innerHTML]=\"afkCountdown()\" class=\"text-number\"></div>\n </div>\n <div class=\"resume-box__text\">\n <h3 class=\"resume-box__heading\">Session will time out soon</h3>\n <p>\n No activity detected. Press 'Continue' if you wish to keep your\n session active\n </p>\n </div>\n <app-unreal-button\n [fullWidth]=\"true\"\n [data-testid]=\"'continue-session'\"\n [class]=\"buttonSkin()\"\n weight=\"primary\"\n size=\"lg\"\n >\n Continue\n </app-unreal-button>\n }\n </div>\n </div>\n}\n", styles: [".afk-anchor{position:absolute;z-index:30;top:0;width:100%;height:100%}.afk-scrim{font-size:1.8em;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));background-color:var(--unreal-surface-scrim, rgba(100, 100, 100, .7))}.clickableState{display:flex;justify-content:center;align-items:center;cursor:pointer}.textDisplayState{display:flex}.hiddenState{display:none}.resume-box{width:340px;padding:32px 20px 20px;flex-direction:column;align-items:center;border-radius:var(--unreal-radius-card, var(--src-border-rounded-parent, 8px));background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));box-shadow:var(--unreal-shadow-card, 0 26px 80px 0 rgba(0, 0, 0, .2), 0 0 1px 0 rgba(0, 0, 0, .2))}.resume-box__pic{width:72px;height:72px;margin:0 auto 22px;border-radius:48px;background:#ecf0f2;padding:12px;display:flex;align-items:center;justify-content:center}.text-number{color:var(--unreal-text-main, #1f2937);text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:30px;font-style:normal;font-weight:400;line-height:24px}.resume-box__text{margin-bottom:18px}.resume-box__text p{text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:24px;color:var(--unreal-text-secondary, var(--src-text-body-secondary, #6b7280))}.resume-box__text .resume-box__heading{color:var(--unreal-text-main, var(--src-text-body-main, #1f2937));text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:18px;font-style:normal;font-weight:500;line-height:26px;margin-bottom:8px}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7407
7598
  }
7408
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: AfkTimeoutModalComponent, decorators: [{
7599
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: AfkTimeoutModalComponent, decorators: [{
7409
7600
  type: Component,
7410
- args: [{ selector: 'app-afk-timeout-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "@if (isShowAfkPopup()) {\r\n <div (click)=\"resetAfk()\" class=\"clickableState\" id=\"videoPlayOverlay\">\r\n <div class=\"resume-box\">\r\n <div aria-hidden=\"true\" class=\"resume-box__pic\" role=\"presentation\">\r\n <div [innerHTML]=\"afkCountdown()\" class=\"text-number\"></div>\r\n </div>\r\n <div class=\"resume-box__text\">\r\n <h3 class=\"resume-box__heading\">Session will time out soon</h3>\r\n <p>\r\n No activity detected. Press 'Continue' if you wish to keep your\r\n session active\r\n </p>\r\n </div>\r\n <app-unreal-button\r\n [fullWidth]=\"true\"\r\n [data-testid]=\"'continue-session'\"\r\n weight=\"primary\"\r\n size=\"lg\"\r\n >\r\n Continue\r\n </app-unreal-button>\r\n </div>\r\n </div>\r\n}\r\n", styles: ["#videoPlayOverlay{position:absolute;z-index:30;top:0;width:100%;height:100%;font-size:1.8em;font-family:var(--src-font-family-body, system-ui, sans-serif);background-color:#646464b3}.clickableState{display:flex;justify-content:center;align-items:center;cursor:pointer}.textDisplayState{display:flex}.hiddenState{display:none}.resume-box{width:340px;padding:32px 20px 20px;flex-direction:column;align-items:center;border-radius:var(--src-border-rounded-parent, 8px);background:var(--src-surface-container-main, #fff);box-shadow:0 26px 80px #0003,0 0 1px #0003}.resume-box .resume-box__pic{width:72px;height:72px;margin:0 auto 22px;border-radius:48px;background:#ecf0f2;padding:12px;display:flex;align-items:center;justify-content:center}.resume-box .resume-box__pic .text-number{color:#1f2937;text-align:center;font-family:var(--src-font-family-body, system-ui, sans-serif);font-size:30px;font-style:normal;font-weight:400;line-height:24px}.resume-box__text{margin-bottom:18px}.resume-box__text p{text-align:center;font-family:var(--src-font-family-body, system-ui, sans-serif);font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:24px;color:var(--src-text-body-secondary, #6b7280)}.resume-box__text .resume-box__heading{color:var(--src-text-body-main, #1f2937);text-align:center;font-family:var(--src-font-family-body, system-ui, sans-serif);font-size:18px;font-style:normal;font-weight:500;line-height:26px;margin-bottom:8px}\n"] }]
7411
- }] });
7601
+ args: [{ selector: 'app-afk-timeout-modal', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent, NgTemplateOutlet], template: "@if (isShowAfkPopup()) {\n <div\n (click)=\"resetAfk()\"\n [class]=\"scrimSkin()\"\n class=\"afk-anchor clickableState\"\n id=\"videoPlayOverlay\"\n >\n <div [class]=\"cardSkin()\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else {\n <div aria-hidden=\"true\" class=\"resume-box__pic\" role=\"presentation\">\n <div [innerHTML]=\"afkCountdown()\" class=\"text-number\"></div>\n </div>\n <div class=\"resume-box__text\">\n <h3 class=\"resume-box__heading\">Session will time out soon</h3>\n <p>\n No activity detected. Press 'Continue' if you wish to keep your\n session active\n </p>\n </div>\n <app-unreal-button\n [fullWidth]=\"true\"\n [data-testid]=\"'continue-session'\"\n [class]=\"buttonSkin()\"\n weight=\"primary\"\n size=\"lg\"\n >\n Continue\n </app-unreal-button>\n }\n </div>\n </div>\n}\n", styles: [".afk-anchor{position:absolute;z-index:30;top:0;width:100%;height:100%}.afk-scrim{font-size:1.8em;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));background-color:var(--unreal-surface-scrim, rgba(100, 100, 100, .7))}.clickableState{display:flex;justify-content:center;align-items:center;cursor:pointer}.textDisplayState{display:flex}.hiddenState{display:none}.resume-box{width:340px;padding:32px 20px 20px;flex-direction:column;align-items:center;border-radius:var(--unreal-radius-card, var(--src-border-rounded-parent, 8px));background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));box-shadow:var(--unreal-shadow-card, 0 26px 80px 0 rgba(0, 0, 0, .2), 0 0 1px 0 rgba(0, 0, 0, .2))}.resume-box__pic{width:72px;height:72px;margin:0 auto 22px;border-radius:48px;background:#ecf0f2;padding:12px;display:flex;align-items:center;justify-content:center}.text-number{color:var(--unreal-text-main, #1f2937);text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:30px;font-style:normal;font-weight:400;line-height:24px}.resume-box__text{margin-bottom:18px}.resume-box__text p{text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:var(--src-font-size-sm, 14px);font-style:normal;font-weight:400;line-height:24px;color:var(--unreal-text-secondary, var(--src-text-body-secondary, #6b7280))}.resume-box__text .resume-box__heading{color:var(--unreal-text-main, var(--src-text-body-main, #1f2937));text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:18px;font-style:normal;font-weight:500;line-height:26px;margin-bottom:8px}\n"] }]
7602
+ }], propDecorators: { uiClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiClasses", required: false }] }], contentTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentTemplate", required: false }] }] } });
7412
7603
 
7413
7604
  class FreezeFrameComponent {
7414
7605
  constructor() {
@@ -7417,12 +7608,12 @@ class FreezeFrameComponent {
7417
7608
  this.combinedFreeze = this.#store.selectSignal(selectFreezeFrameCombinedDataUrl);
7418
7609
  }
7419
7610
  #store;
7420
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FreezeFrameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7421
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: FreezeFrameComponent, isStandalone: true, selector: "app-freeze-frame", ngImport: i0, template: "@let image = combinedFreeze();\r\n@let progress = freezeFrameProgressMessageFromVideo();\r\n\r\n<div class=\"freeze-images\">\r\n @if (image) {\r\n <img [src]=\"image\" class=\"videoStillImage\" alt=\"freezeFrameImage\" />\r\n }\r\n\r\n @if (progress) {\r\n <div class=\"progress-status\">\r\n {{ progress }}\r\n </div>\r\n }\r\n</div>\r\n", styles: [".freeze-images{pointer-events:none;position:absolute;left:0;top:0;width:100%;height:100%;z-index:1}.freeze-images .freezeFrameOverlay{top:0;left:0;width:100%;height:100%;position:absolute;object-fit:cover;object-position:center}.freeze-images .videoStillImage{position:absolute;z-index:1;top:0;left:0;width:100%;height:100%;object-fit:cover}.freeze-images .progress-status{position:absolute;top:50%;left:50%;z-index:1;display:flex;flex-direction:column;justify-content:center;align-items:center;width:auto;height:auto;margin:0;padding:10px;background-color:#ffffffb3;border:1px solid grey;transform:translate(-50%,-50%)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7611
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FreezeFrameComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7612
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: FreezeFrameComponent, isStandalone: true, selector: "app-freeze-frame", ngImport: i0, template: "@let image = combinedFreeze();\n@let progress = freezeFrameProgressMessageFromVideo();\n\n<div class=\"freeze-images\">\n @if (image) {\n <img [src]=\"image\" class=\"videoStillImage\" alt=\"freezeFrameImage\" />\n }\n\n @if (progress) {\n <div class=\"progress-status\">\n {{ progress }}\n </div>\n }\n</div>\n", styles: [".freeze-images{pointer-events:none;position:absolute;left:0;top:0;width:100%;height:100%;z-index:1}.freeze-images .freezeFrameOverlay{top:0;left:0;width:100%;height:100%;position:absolute;object-fit:cover;object-position:center}.freeze-images .videoStillImage{position:absolute;z-index:1;top:0;left:0;width:100%;height:100%;object-fit:cover}.freeze-images .progress-status{position:absolute;top:50%;left:50%;z-index:1;display:flex;flex-direction:column;justify-content:center;align-items:center;width:auto;height:auto;margin:0;padding:10px;background-color:#ffffffb3;border:1px solid grey;transform:translate(-50%,-50%)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7422
7613
  }
7423
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: FreezeFrameComponent, decorators: [{
7614
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FreezeFrameComponent, decorators: [{
7424
7615
  type: Component,
7425
- args: [{ selector: 'app-freeze-frame', changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = combinedFreeze();\r\n@let progress = freezeFrameProgressMessageFromVideo();\r\n\r\n<div class=\"freeze-images\">\r\n @if (image) {\r\n <img [src]=\"image\" class=\"videoStillImage\" alt=\"freezeFrameImage\" />\r\n }\r\n\r\n @if (progress) {\r\n <div class=\"progress-status\">\r\n {{ progress }}\r\n </div>\r\n }\r\n</div>\r\n", styles: [".freeze-images{pointer-events:none;position:absolute;left:0;top:0;width:100%;height:100%;z-index:1}.freeze-images .freezeFrameOverlay{top:0;left:0;width:100%;height:100%;position:absolute;object-fit:cover;object-position:center}.freeze-images .videoStillImage{position:absolute;z-index:1;top:0;left:0;width:100%;height:100%;object-fit:cover}.freeze-images .progress-status{position:absolute;top:50%;left:50%;z-index:1;display:flex;flex-direction:column;justify-content:center;align-items:center;width:auto;height:auto;margin:0;padding:10px;background-color:#ffffffb3;border:1px solid grey;transform:translate(-50%,-50%)}\n"] }]
7616
+ args: [{ selector: 'app-freeze-frame', changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = combinedFreeze();\n@let progress = freezeFrameProgressMessageFromVideo();\n\n<div class=\"freeze-images\">\n @if (image) {\n <img [src]=\"image\" class=\"videoStillImage\" alt=\"freezeFrameImage\" />\n }\n\n @if (progress) {\n <div class=\"progress-status\">\n {{ progress }}\n </div>\n }\n</div>\n", styles: [".freeze-images{pointer-events:none;position:absolute;left:0;top:0;width:100%;height:100%;z-index:1}.freeze-images .freezeFrameOverlay{top:0;left:0;width:100%;height:100%;position:absolute;object-fit:cover;object-position:center}.freeze-images .videoStillImage{position:absolute;z-index:1;top:0;left:0;width:100%;height:100%;object-fit:cover}.freeze-images .progress-status{position:absolute;top:50%;left:50%;z-index:1;display:flex;flex-direction:column;justify-content:center;align-items:center;width:auto;height:auto;margin:0;padding:10px;background-color:#ffffffb3;border:1px solid grey;transform:translate(-50%,-50%)}\n"] }]
7426
7617
  }] });
7427
7618
 
7428
7619
  class ImageLoadingSrcComponent {
@@ -7435,12 +7626,12 @@ class ImageLoadingSrcComponent {
7435
7626
  loadingImageError() {
7436
7627
  this.#store.dispatch(setLoadingImageSrc({ src: '' }));
7437
7628
  }
7438
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: ImageLoadingSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7439
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: ImageLoadingSrcComponent, isStandalone: true, selector: "app-image-loading-src", ngImport: i0, template: "@let image = imageLoadingSrc();\r\n@if (isLoaderScreenVisible()) {\r\n <div class=\"preload\">\r\n <div class=\"back\">\r\n @if (image) {\r\n <img\r\n (error)=\"loadingImageError()\"\r\n [ngSrc]=\"image\"\r\n fill\r\n loading=\"lazy\"\r\n alt=\"image loading src\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n}\r\n", styles: [".preload{position:absolute;top:0;left:0;width:100%;height:100%;text-align:center}.preload .back{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.preload .back img{width:100%;height:100%;object-fit:cover}.preload .back{background-color:#fff}\n"], dependencies: [{ kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7629
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ImageLoadingSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7630
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: ImageLoadingSrcComponent, isStandalone: true, selector: "app-image-loading-src", ngImport: i0, template: "@let image = imageLoadingSrc();\n@if (isLoaderScreenVisible()) {\n <div class=\"preload\">\n <div class=\"back\">\n @if (image) {\n <img\n (error)=\"loadingImageError()\"\n [ngSrc]=\"image\"\n fill\n loading=\"lazy\"\n alt=\"image loading src\"\n />\n }\n </div>\n </div>\n}\n", styles: [".preload{position:absolute;top:0;left:0;width:100%;height:100%;text-align:center}.preload .back{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.preload .back img{width:100%;height:100%;object-fit:cover}.preload .back{background-color:var(--unreal-surface-screen, #fff)}\n"], dependencies: [{ kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7440
7631
  }
7441
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: ImageLoadingSrcComponent, decorators: [{
7632
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ImageLoadingSrcComponent, decorators: [{
7442
7633
  type: Component,
7443
- args: [{ selector: 'app-image-loading-src', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgOptimizedImage], template: "@let image = imageLoadingSrc();\r\n@if (isLoaderScreenVisible()) {\r\n <div class=\"preload\">\r\n <div class=\"back\">\r\n @if (image) {\r\n <img\r\n (error)=\"loadingImageError()\"\r\n [ngSrc]=\"image\"\r\n fill\r\n loading=\"lazy\"\r\n alt=\"image loading src\"\r\n />\r\n }\r\n </div>\r\n </div>\r\n}\r\n", styles: [".preload{position:absolute;top:0;left:0;width:100%;height:100%;text-align:center}.preload .back{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.preload .back img{width:100%;height:100%;object-fit:cover}.preload .back{background-color:#fff}\n"] }]
7634
+ args: [{ selector: 'app-image-loading-src', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgOptimizedImage], template: "@let image = imageLoadingSrc();\n@if (isLoaderScreenVisible()) {\n <div class=\"preload\">\n <div class=\"back\">\n @if (image) {\n <img\n (error)=\"loadingImageError()\"\n [ngSrc]=\"image\"\n fill\n loading=\"lazy\"\n alt=\"image loading src\"\n />\n }\n </div>\n </div>\n}\n", styles: [".preload{position:absolute;top:0;left:0;width:100%;height:100%;text-align:center}.preload .back{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.preload .back img{width:100%;height:100%;object-fit:cover}.preload .back{background-color:var(--unreal-surface-screen, #fff)}\n"] }]
7444
7635
  }] });
7445
7636
 
7446
7637
  class StatGraphComponent {
@@ -7521,17 +7712,60 @@ class StatGraphComponent {
7521
7712
  }
7522
7713
  this.draw();
7523
7714
  }
7524
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: StatGraphComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7525
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.0", type: StatGraphComponent, isStandalone: true, selector: "app-stat-graph", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, stat: { classPropertyName: "stat", publicName: "stat", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, tickStep: { classPropertyName: "tickStep", publicName: "tickStep", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "window:resize": "resize()" } }, viewQueries: [{ propertyName: "graph", first: true, predicate: ["graph"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"content\">\r\n <p>{{ label() }}: {{ current() }} | Min:{{ min() }} | Max:{{ max() }}</p>\r\n <canvas #graph class=\"graph\"></canvas>\r\n</div>\r\n", styles: [".content{width:100%;height:100%}.content p{color:#fff;margin:5px 0 0;height:25px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7715
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StatGraphComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7716
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.1", type: StatGraphComponent, isStandalone: true, selector: "app-stat-graph", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, stat: { classPropertyName: "stat", publicName: "stat", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, tickStep: { classPropertyName: "tickStep", publicName: "tickStep", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "window:resize": "resize()" } }, viewQueries: [{ propertyName: "graph", first: true, predicate: ["graph"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"content\">\n <p>{{ label() }}: {{ current() }} | Min:{{ min() }} | Max:{{ max() }}</p>\n <canvas #graph class=\"graph\"></canvas>\n</div>\n", styles: [".content{width:100%;height:100%}.content p{color:#fff;margin:5px 0 0;height:25px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7526
7717
  }
7527
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: StatGraphComponent, decorators: [{
7718
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: StatGraphComponent, decorators: [{
7528
7719
  type: Component,
7529
- args: [{ selector: 'app-stat-graph', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"content\">\r\n <p>{{ label() }}: {{ current() }} | Min:{{ min() }} | Max:{{ max() }}</p>\r\n <canvas #graph class=\"graph\"></canvas>\r\n</div>\r\n", styles: [".content{width:100%;height:100%}.content p{color:#fff;margin:5px 0 0;height:25px}\n"] }]
7720
+ args: [{ selector: 'app-stat-graph', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"content\">\n <p>{{ label() }}: {{ current() }} | Min:{{ min() }} | Max:{{ max() }}</p>\n <canvas #graph class=\"graph\"></canvas>\n</div>\n", styles: [".content{width:100%;height:100%}.content p{color:#fff;margin:5px 0 0;height:25px}\n"] }]
7530
7721
  }], ctorParameters: () => [], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], stat: [{ type: i0.Input, args: [{ isSignal: true, alias: "stat", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], tickStep: [{ type: i0.Input, args: [{ isSignal: true, alias: "tickStep", required: false }] }], graph: [{ type: i0.ViewChild, args: ['graph', { isSignal: true }] }], resize: [{
7531
7722
  type: HostListener,
7532
7723
  args: ['window:resize']
7533
7724
  }] } });
7534
7725
 
7726
+ class UnrealResumeSlotDirective {
7727
+ constructor() {
7728
+ this.template = inject(TemplateRef);
7729
+ }
7730
+ static ngTemplateContextGuard(_dir, _ctx) {
7731
+ return true;
7732
+ }
7733
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealResumeSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
7734
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.1", type: UnrealResumeSlotDirective, isStandalone: true, selector: "ng-template[unrealResumeSlot]", ngImport: i0 }); }
7735
+ }
7736
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealResumeSlotDirective, decorators: [{
7737
+ type: Directive,
7738
+ args: [{ selector: 'ng-template[unrealResumeSlot]' }]
7739
+ }] });
7740
+ class UnrealAfkSlotDirective {
7741
+ constructor() {
7742
+ this.template = inject(TemplateRef);
7743
+ }
7744
+ static ngTemplateContextGuard(_dir, _ctx) {
7745
+ return true;
7746
+ }
7747
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealAfkSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
7748
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.1", type: UnrealAfkSlotDirective, isStandalone: true, selector: "ng-template[unrealAfkSlot]", ngImport: i0 }); }
7749
+ }
7750
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealAfkSlotDirective, decorators: [{
7751
+ type: Directive,
7752
+ args: [{ selector: 'ng-template[unrealAfkSlot]' }]
7753
+ }] });
7754
+ class UnrealStatusSlotDirective {
7755
+ constructor() {
7756
+ this.template = inject(TemplateRef);
7757
+ }
7758
+ static ngTemplateContextGuard(_dir, _ctx) {
7759
+ return true;
7760
+ }
7761
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealStatusSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
7762
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.1", type: UnrealStatusSlotDirective, isStandalone: true, selector: "ng-template[unrealStatusSlot]", ngImport: i0 }); }
7763
+ }
7764
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealStatusSlotDirective, decorators: [{
7765
+ type: Directive,
7766
+ args: [{ selector: 'ng-template[unrealStatusSlot]' }]
7767
+ }] });
7768
+
7535
7769
  class UnrealSpinnerComponent {
7536
7770
  constructor() {
7537
7771
  this.size = input(32, /* @ts-ignore */
@@ -7550,12 +7784,12 @@ class UnrealSpinnerComponent {
7550
7784
  this.viewBox = computed(() => `0 0 ${this.size()} ${this.size()}`, /* @ts-ignore */
7551
7785
  ...(ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []));
7552
7786
  }
7553
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealSpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7554
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.0", type: UnrealSpinnerComponent, isStandalone: true, selector: "app-unreal-spinner", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, strokeColor: { classPropertyName: "strokeColor", publicName: "strokeColor", isSignal: true, isRequired: false, transformFunction: null }, testID: { classPropertyName: "testID", publicName: "data-testid", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\r\n [attr.data-testid]=\"testID() || null\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n class=\"unreal-spinner-container\"\r\n role=\"status\"\r\n>\r\n <svg\r\n [attr.width]=\"size()\"\r\n [attr.height]=\"size()\"\r\n [attr.viewBox]=\"viewBox()\"\r\n [style.--unrealSpinnerSize]=\"size()\"\r\n class=\"unreal-spinner unreal-spinner--animation\"\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n style=\"transform: rotate(-90deg)\"\r\n aria-hidden=\"true\"\r\n >\r\n <circle\r\n [attr.r]=\"radius()\"\r\n [attr.cx]=\"center()\"\r\n [attr.cy]=\"center()\"\r\n [attr.stroke]=\"strokeColor()\"\r\n [attr.stroke-width]=\"strokeWidth()\"\r\n fill=\"transparent\"\r\n stroke-linecap=\"round\"\r\n ></circle>\r\n </svg>\r\n</div>\r\n", styles: [":host{display:block}.unreal-spinner-container{position:relative;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.unreal-spinner{position:relative;display:inline-block}.unreal-spinner--animation{animation:1.4s linear 0s infinite normal none running unrealSpinnerRotate}.unreal-spinner--animation circle{transform-origin:50% 50%;stroke-dasharray:calc(var(--unrealSpinnerSize) * 2 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0;animation:1.6s ease-in-out 0s infinite normal none running unrealSpinnerDash}@keyframes unrealSpinnerRotate{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes unrealSpinnerDash{0%{stroke-dasharray:1px,calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0}50%{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * .4 * -1px)}to{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * 3 * -1px)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7787
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealSpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7788
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: UnrealSpinnerComponent, isStandalone: true, selector: "app-unreal-spinner", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, strokeColor: { classPropertyName: "strokeColor", publicName: "strokeColor", isSignal: true, isRequired: false, transformFunction: null }, testID: { classPropertyName: "testID", publicName: "data-testid", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div\n [attr.data-testid]=\"testID() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n class=\"unreal-spinner-container\"\n role=\"status\"\n>\n <svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n [attr.viewBox]=\"viewBox()\"\n [style.--unrealSpinnerSize]=\"size()\"\n class=\"unreal-spinner unreal-spinner--animation\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style=\"transform: rotate(-90deg)\"\n aria-hidden=\"true\"\n >\n <circle\n [attr.r]=\"radius()\"\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.stroke]=\"strokeColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"transparent\"\n stroke-linecap=\"round\"\n ></circle>\n </svg>\n</div>\n", styles: [":host{display:block}.unreal-spinner-container{position:relative;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.unreal-spinner{position:relative;display:inline-block}.unreal-spinner--animation{animation:1.4s linear 0s infinite normal none running unrealSpinnerRotate}.unreal-spinner--animation circle{transform-origin:50% 50%;stroke-dasharray:calc(var(--unrealSpinnerSize) * 2 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0;animation:1.6s ease-in-out 0s infinite normal none running unrealSpinnerDash}@keyframes unrealSpinnerRotate{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes unrealSpinnerDash{0%{stroke-dasharray:1px,calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0}50%{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * .4 * -1px)}to{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * 3 * -1px)}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7555
7789
  }
7556
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealSpinnerComponent, decorators: [{
7790
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealSpinnerComponent, decorators: [{
7557
7791
  type: Component,
7558
- args: [{ selector: 'app-unreal-spinner', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n [attr.data-testid]=\"testID() || null\"\r\n [attr.aria-label]=\"ariaLabel()\"\r\n class=\"unreal-spinner-container\"\r\n role=\"status\"\r\n>\r\n <svg\r\n [attr.width]=\"size()\"\r\n [attr.height]=\"size()\"\r\n [attr.viewBox]=\"viewBox()\"\r\n [style.--unrealSpinnerSize]=\"size()\"\r\n class=\"unreal-spinner unreal-spinner--animation\"\r\n version=\"1.1\"\r\n xmlns=\"http://www.w3.org/2000/svg\"\r\n style=\"transform: rotate(-90deg)\"\r\n aria-hidden=\"true\"\r\n >\r\n <circle\r\n [attr.r]=\"radius()\"\r\n [attr.cx]=\"center()\"\r\n [attr.cy]=\"center()\"\r\n [attr.stroke]=\"strokeColor()\"\r\n [attr.stroke-width]=\"strokeWidth()\"\r\n fill=\"transparent\"\r\n stroke-linecap=\"round\"\r\n ></circle>\r\n </svg>\r\n</div>\r\n", styles: [":host{display:block}.unreal-spinner-container{position:relative;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.unreal-spinner{position:relative;display:inline-block}.unreal-spinner--animation{animation:1.4s linear 0s infinite normal none running unrealSpinnerRotate}.unreal-spinner--animation circle{transform-origin:50% 50%;stroke-dasharray:calc(var(--unrealSpinnerSize) * 2 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0;animation:1.6s ease-in-out 0s infinite normal none running unrealSpinnerDash}@keyframes unrealSpinnerRotate{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes unrealSpinnerDash{0%{stroke-dasharray:1px,calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0}50%{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * .4 * -1px)}to{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * 3 * -1px)}}\n"] }]
7792
+ args: [{ selector: 'app-unreal-spinner', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n [attr.data-testid]=\"testID() || null\"\n [attr.aria-label]=\"ariaLabel()\"\n class=\"unreal-spinner-container\"\n role=\"status\"\n>\n <svg\n [attr.width]=\"size()\"\n [attr.height]=\"size()\"\n [attr.viewBox]=\"viewBox()\"\n [style.--unrealSpinnerSize]=\"size()\"\n class=\"unreal-spinner unreal-spinner--animation\"\n version=\"1.1\"\n xmlns=\"http://www.w3.org/2000/svg\"\n style=\"transform: rotate(-90deg)\"\n aria-hidden=\"true\"\n >\n <circle\n [attr.r]=\"radius()\"\n [attr.cx]=\"center()\"\n [attr.cy]=\"center()\"\n [attr.stroke]=\"strokeColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"transparent\"\n stroke-linecap=\"round\"\n ></circle>\n </svg>\n</div>\n", styles: [":host{display:block}.unreal-spinner-container{position:relative;display:flex;justify-content:center;align-items:center;width:100%;height:100%}.unreal-spinner{position:relative;display:inline-block}.unreal-spinner--animation{animation:1.4s linear 0s infinite normal none running unrealSpinnerRotate}.unreal-spinner--animation circle{transform-origin:50% 50%;stroke-dasharray:calc(var(--unrealSpinnerSize) * 2 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0;animation:1.6s ease-in-out 0s infinite normal none running unrealSpinnerDash}@keyframes unrealSpinnerRotate{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes unrealSpinnerDash{0%{stroke-dasharray:1px,calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:0}50%{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * .4 * -1px)}to{stroke-dasharray:calc(var(--unrealSpinnerSize) * 2.5 * 1px),calc(var(--unrealSpinnerSize) * 5 * 1px);stroke-dashoffset:calc(var(--unrealSpinnerSize) * 3 * -1px)}}\n"] }]
7559
7793
  }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], strokeColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeColor", required: false }] }], testID: [{ type: i0.Input, args: [{ isSignal: true, alias: "data-testid", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
7560
7794
 
7561
7795
  class UnrealStatusComponent {
@@ -7568,16 +7802,29 @@ class UnrealStatusComponent {
7568
7802
  this.showLoadingProgress = this.#store.selectSignal(unrealFeature.selectShowLoadingProgress);
7569
7803
  this.isShowLoadingPercentsPopup = computed(() => this.showLoader() && this.showLoadingProgress(), /* @ts-ignore */
7570
7804
  ...(ngDevMode ? [{ debugName: "isShowLoadingPercentsPopup" }] : /* istanbul ignore next */ []));
7805
+ this.uiClasses = input({}, /* @ts-ignore */
7806
+ ...(ngDevMode ? [{ debugName: "uiClasses" }] : /* istanbul ignore next */ []));
7807
+ this.contentTemplate = input(null, /* @ts-ignore */
7808
+ ...(ngDevMode ? [{ debugName: "contentTemplate" }] : /* istanbul ignore next */ []));
7809
+ this.cardSkin = computed(() => resolveSkin(this.uiClasses(), 'statusCard', 'status-box'), /* @ts-ignore */
7810
+ ...(ngDevMode ? [{ debugName: "cardSkin" }] : /* istanbul ignore next */ []));
7811
+ this.messageSkin = computed(() => resolveSkin(this.uiClasses(), 'statusMessage', 'status-box__message'), /* @ts-ignore */
7812
+ ...(ngDevMode ? [{ debugName: "messageSkin" }] : /* istanbul ignore next */ []));
7813
+ // Created once: identity stays stable, reactivity lives in the signals.
7814
+ this.slotContext = {
7815
+ percents: this.smoothPercents,
7816
+ message: computed(() => this.awsInstance()?.message),
7817
+ };
7571
7818
  }
7572
7819
  #store;
7573
7820
  #loadingProgress;
7574
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealStatusComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7575
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: UnrealStatusComponent, isStandalone: true, selector: "app-unreal-status", ngImport: i0, template: "@if (isShowLoadingPercentsPopup()) {\r\n @let _awsInstance = awsInstance();\r\n <div class=\"status-box\">\r\n @if (_awsInstance?.message) {\r\n <p>{{ _awsInstance?.message }}</p>\r\n } @else {\r\n <div class=\"status-box__message\">\r\n <app-unreal-spinner [size]=\"30\" [strokeColor]=\"'#1F2937'\" />\r\n {{ smoothPercents() }}%\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: ["app-stat-graph{height:30px;width:100%}.status-box{position:absolute;top:80%;left:50%;transform:translate(-50%,-50%);z-index:5;display:flex;justify-content:center;align-items:center;width:auto;max-width:500px;margin:0;background:var(--src-surface-container-main, #fff);border:none;border-radius:var(--src-border-rounded-full, 9999px);box-shadow:0 8px 20px #1718181f,0 3px 6px #17181814;pointer-events:none}.status-box p{padding:10px 15px;margin:0;text-align:center}.status-box__message{display:flex;align-items:center;padding:12px 20px 12px 16px;color:var(--src-text-body-main, #1f2937);font-size:16px;font-weight:400;line-height:24px}.status-box__message .status-box__message_text{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.status-box__message app-unreal-spinner{margin-right:12px}\n"], dependencies: [{ kind: "component", type: UnrealSpinnerComponent, selector: "app-unreal-spinner", inputs: ["size", "strokeWidth", "strokeColor", "data-testid", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7821
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealStatusComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7822
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: UnrealStatusComponent, isStandalone: true, selector: "app-unreal-status", inputs: { uiClasses: { classPropertyName: "uiClasses", publicName: "uiClasses", isSignal: true, isRequired: false, transformFunction: null }, contentTemplate: { classPropertyName: "contentTemplate", publicName: "contentTemplate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isShowLoadingPercentsPopup()) {\n @let _awsInstance = awsInstance();\n <div [class]=\"cardSkin()\" class=\"status-anchor\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else if (_awsInstance?.message) {\n <p>{{ _awsInstance?.message }}</p>\n } @else {\n <div [class]=\"messageSkin()\">\n <app-unreal-spinner [size]=\"30\" [strokeColor]=\"'#1F2937'\" />\n {{ smoothPercents() }}%\n </div>\n }\n </div>\n}\n", styles: ["app-stat-graph{height:30px;width:100%}.status-anchor{position:absolute;top:80%;left:50%;transform:translate(-50%,-50%);z-index:5;pointer-events:none}.status-box{display:flex;justify-content:center;align-items:center;width:auto;max-width:500px;margin:0;background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));border:none;border-radius:var(--unreal-radius-pill, var(--src-border-rounded-full, 9999px));box-shadow:0 8px 20px #1718181f,0 3px 6px #17181814}.status-anchor p{padding:10px 15px;margin:0;text-align:center}.status-box__message{display:flex;align-items:center;padding:12px 20px 12px 16px;color:var(--unreal-text-main, var(--src-text-body-main, #1f2937));font-size:16px;font-weight:400;line-height:24px}.status-box__message .status-box__message_text{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.status-box__message app-unreal-spinner{margin-right:12px}\n"], dependencies: [{ kind: "component", type: UnrealSpinnerComponent, selector: "app-unreal-spinner", inputs: ["size", "strokeWidth", "strokeColor", "data-testid", "ariaLabel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7576
7823
  }
7577
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealStatusComponent, decorators: [{
7824
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealStatusComponent, decorators: [{
7578
7825
  type: Component,
7579
- args: [{ selector: 'app-unreal-status', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealSpinnerComponent], template: "@if (isShowLoadingPercentsPopup()) {\r\n @let _awsInstance = awsInstance();\r\n <div class=\"status-box\">\r\n @if (_awsInstance?.message) {\r\n <p>{{ _awsInstance?.message }}</p>\r\n } @else {\r\n <div class=\"status-box__message\">\r\n <app-unreal-spinner [size]=\"30\" [strokeColor]=\"'#1F2937'\" />\r\n {{ smoothPercents() }}%\r\n </div>\r\n }\r\n </div>\r\n}\r\n", styles: ["app-stat-graph{height:30px;width:100%}.status-box{position:absolute;top:80%;left:50%;transform:translate(-50%,-50%);z-index:5;display:flex;justify-content:center;align-items:center;width:auto;max-width:500px;margin:0;background:var(--src-surface-container-main, #fff);border:none;border-radius:var(--src-border-rounded-full, 9999px);box-shadow:0 8px 20px #1718181f,0 3px 6px #17181814;pointer-events:none}.status-box p{padding:10px 15px;margin:0;text-align:center}.status-box__message{display:flex;align-items:center;padding:12px 20px 12px 16px;color:var(--src-text-body-main, #1f2937);font-size:16px;font-weight:400;line-height:24px}.status-box__message .status-box__message_text{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.status-box__message app-unreal-spinner{margin-right:12px}\n"] }]
7580
- }] });
7826
+ args: [{ selector: 'app-unreal-status', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealSpinnerComponent, NgTemplateOutlet], template: "@if (isShowLoadingPercentsPopup()) {\n @let _awsInstance = awsInstance();\n <div [class]=\"cardSkin()\" class=\"status-anchor\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else if (_awsInstance?.message) {\n <p>{{ _awsInstance?.message }}</p>\n } @else {\n <div [class]=\"messageSkin()\">\n <app-unreal-spinner [size]=\"30\" [strokeColor]=\"'#1F2937'\" />\n {{ smoothPercents() }}%\n </div>\n }\n </div>\n}\n", styles: ["app-stat-graph{height:30px;width:100%}.status-anchor{position:absolute;top:80%;left:50%;transform:translate(-50%,-50%);z-index:5;pointer-events:none}.status-box{display:flex;justify-content:center;align-items:center;width:auto;max-width:500px;margin:0;background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));border:none;border-radius:var(--unreal-radius-pill, var(--src-border-rounded-full, 9999px));box-shadow:0 8px 20px #1718181f,0 3px 6px #17181814}.status-anchor p{padding:10px 15px;margin:0;text-align:center}.status-box__message{display:flex;align-items:center;padding:12px 20px 12px 16px;color:var(--unreal-text-main, var(--src-text-body-main, #1f2937));font-size:16px;font-weight:400;line-height:24px}.status-box__message .status-box__message_text{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}.status-box__message app-unreal-spinner{margin-right:12px}\n"] }]
7827
+ }], propDecorators: { uiClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiClasses", required: false }] }], contentTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentTemplate", required: false }] }] } });
7581
7828
 
7582
7829
  class SafePipe {
7583
7830
  constructor() {
@@ -7607,10 +7854,10 @@ class SafePipe {
7607
7854
  // content instead of disabling framework security checks.
7608
7855
  return (this.sanitizer.sanitize(context, value) ?? '');
7609
7856
  }
7610
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: SafePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
7611
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.0", ngImport: i0, type: SafePipe, isStandalone: true, name: "safe" }); }
7857
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SafePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
7858
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.1.1", ngImport: i0, type: SafePipe, isStandalone: true, name: "safe" }); }
7612
7859
  }
7613
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: SafePipe, decorators: [{
7860
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SafePipe, decorators: [{
7614
7861
  type: Pipe,
7615
7862
  args: [{
7616
7863
  name: 'safe',
@@ -7723,18 +7970,28 @@ class VideoStatsComponent {
7723
7970
  elements: this.elementsToShow(),
7724
7971
  }));
7725
7972
  }
7726
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: VideoStatsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7727
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: VideoStatsComponent, isStandalone: true, selector: "app-video-stats", ngImport: i0, template: "@if (videoStatus() && viewportReady()) {\r\n <div class=\"settings-container\">\r\n <button (click)=\"toggle()\" class=\"gear-button\">Stats</button>\r\n <div (click)=\"toggle()\" [class.min]=\"collapsed()\" id=\"aggregatedStats\">\r\n <div class=\"forNerds\">\r\n <div (click)=\"$event.stopPropagation()\" class=\"static\">\r\n <li>\r\n <app-stat-graph\r\n [stat]=\"fpsTick()!\"\r\n label=\"FPS (higher is better)\"\r\n />\r\n </li>\r\n <li>\r\n <app-stat-graph\r\n [stat]=\"videoQP()!\"\r\n label=\"QP (lower is better)\"\r\n color=\"#D5ff07\"\r\n />\r\n </li>\r\n <li>\r\n <app-stat-graph\r\n [stat]=\"bitrateTick()!\"\r\n label=\"Bitrate\"\r\n color=\"#D57F07\"\r\n />\r\n </li>\r\n </div>\r\n <div>\r\n @for (graph of graphList(); track graph.key) {\r\n <li (click)=\"toggleGraph($event, graph.key, 0)\" class=\"graph\">\r\n <app-stat-graph\r\n [label]=\"graph.key\"\r\n [stat]=\"graph.stat()\"\r\n [color]=\"graph.color\"\r\n />\r\n </li>\r\n }\r\n </div>\r\n </div>\r\n\r\n @for (el of videoStatus(); track el.key + $index) {\r\n <div (click)=\"toggleGraph($event, el.key, el.value)\" class=\"stat\">\r\n <span>{{ el.key }}: </span>{{ el.value | json }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n @if (!collapsed()) {\r\n <div [innerHTML]=\"ssData() | safe: 'html'\" class=\"ssInfo\"></div>\r\n }\r\n}\r\n", styles: [".settings-container{position:absolute;top:65px;left:10px;z-index:1000;bottom:10px}.gear-button{left:0;width:50px;position:absolute;background:none;cursor:pointer;font-size:10px;font-weight:500;border:1px solid;border-radius:9px;background:#0162cc;color:#fff;padding:4px}.gear-button>*{color:#fff;filter:drop-shadow(1px 1px 1px rgb(0,0,0))}#aggregatedStats{max-height:calc(100% - 25px);overflow-y:auto;margin-top:25px;left:20px;z-index:31;max-width:400px;padding:10px;background-color:#fff3;border:1px solid grey}#aggregatedStats>*{color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000}#aggregatedStats:empty{display:none}#aggregatedStats button{position:absolute;right:5px;top:5px}#aggregatedStats.min{display:none}#aggregatedStats .forNerds{width:100%}#aggregatedStats .forNerds li{list-style-type:none;height:60px}#aggregatedStats .forNerds li app-stat-graph{display:block;width:100%;height:100%}#aggregatedStats .stat span{font-weight:700}#aggregatedStats .stat,#aggregatedStats .graph{cursor:pointer}#aggregatedStats .static{pointer-events:all}.ssInfo{position:absolute;top:0;left:50%;transform:translate(-50%);color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000;text-align:center;width:80%;pointer-events:none}\n"], dependencies: [{ kind: "component", type: StatGraphComponent, selector: "app-stat-graph", inputs: ["label", "stat", "color", "tickStep"] }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: SafePipe, name: "safe" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7973
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: VideoStatsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7974
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: VideoStatsComponent, isStandalone: true, selector: "app-video-stats", ngImport: i0, template: "@if (videoStatus() && viewportReady()) {\n <div class=\"settings-container\">\n <button (click)=\"toggle()\" class=\"gear-button\">Stats</button>\n <div (click)=\"toggle()\" [class.min]=\"collapsed()\" id=\"aggregatedStats\">\n <div class=\"forNerds\">\n <div (click)=\"$event.stopPropagation()\" class=\"static\">\n <li>\n <app-stat-graph\n [stat]=\"fpsTick()!\"\n label=\"FPS (higher is better)\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"videoQP()!\"\n label=\"QP (lower is better)\"\n color=\"#D5ff07\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"bitrateTick()!\"\n label=\"Bitrate\"\n color=\"#D57F07\"\n />\n </li>\n </div>\n <div>\n @for (graph of graphList(); track graph.key) {\n <li (click)=\"toggleGraph($event, graph.key, 0)\" class=\"graph\">\n <app-stat-graph\n [label]=\"graph.key\"\n [stat]=\"graph.stat()\"\n [color]=\"graph.color\"\n />\n </li>\n }\n </div>\n </div>\n\n @for (el of videoStatus(); track el.key + $index) {\n <div (click)=\"toggleGraph($event, el.key, el.value)\" class=\"stat\">\n <span>{{ el.key }}: </span>{{ el.value | json }}\n </div>\n }\n </div>\n </div>\n @if (!collapsed()) {\n <div [innerHTML]=\"ssData() | safe: 'html'\" class=\"ssInfo\"></div>\n }\n}\n", styles: [".settings-container{position:absolute;top:65px;left:10px;z-index:1000;bottom:10px}.gear-button{left:0;width:50px;position:absolute;background:none;cursor:pointer;font-size:10px;font-weight:500;border:1px solid;border-radius:9px;background:#0162cc;color:#fff;padding:4px}.gear-button>*{color:#fff;filter:drop-shadow(1px 1px 1px rgb(0,0,0))}#aggregatedStats{max-height:calc(100% - 25px);overflow-y:auto;margin-top:25px;left:20px;z-index:31;max-width:400px;padding:10px;background-color:#fff3;border:1px solid grey}#aggregatedStats>*{color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000}#aggregatedStats:empty{display:none}#aggregatedStats button{position:absolute;right:5px;top:5px}#aggregatedStats.min{display:none}#aggregatedStats .forNerds{width:100%}#aggregatedStats .forNerds li{list-style-type:none;height:60px}#aggregatedStats .forNerds li app-stat-graph{display:block;width:100%;height:100%}#aggregatedStats .stat span{font-weight:700}#aggregatedStats .stat,#aggregatedStats .graph{cursor:pointer}#aggregatedStats .static{pointer-events:all}.ssInfo{position:absolute;top:0;left:50%;transform:translate(-50%);color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000;text-align:center;width:80%;pointer-events:none}\n"], dependencies: [{ kind: "component", type: StatGraphComponent, selector: "app-stat-graph", inputs: ["label", "stat", "color", "tickStep"] }, { kind: "pipe", type: JsonPipe, name: "json" }, { kind: "pipe", type: SafePipe, name: "safe" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7728
7975
  }
7729
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: VideoStatsComponent, decorators: [{
7976
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: VideoStatsComponent, decorators: [{
7730
7977
  type: Component,
7731
- args: [{ selector: 'app-video-stats', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StatGraphComponent, JsonPipe, SafePipe], template: "@if (videoStatus() && viewportReady()) {\r\n <div class=\"settings-container\">\r\n <button (click)=\"toggle()\" class=\"gear-button\">Stats</button>\r\n <div (click)=\"toggle()\" [class.min]=\"collapsed()\" id=\"aggregatedStats\">\r\n <div class=\"forNerds\">\r\n <div (click)=\"$event.stopPropagation()\" class=\"static\">\r\n <li>\r\n <app-stat-graph\r\n [stat]=\"fpsTick()!\"\r\n label=\"FPS (higher is better)\"\r\n />\r\n </li>\r\n <li>\r\n <app-stat-graph\r\n [stat]=\"videoQP()!\"\r\n label=\"QP (lower is better)\"\r\n color=\"#D5ff07\"\r\n />\r\n </li>\r\n <li>\r\n <app-stat-graph\r\n [stat]=\"bitrateTick()!\"\r\n label=\"Bitrate\"\r\n color=\"#D57F07\"\r\n />\r\n </li>\r\n </div>\r\n <div>\r\n @for (graph of graphList(); track graph.key) {\r\n <li (click)=\"toggleGraph($event, graph.key, 0)\" class=\"graph\">\r\n <app-stat-graph\r\n [label]=\"graph.key\"\r\n [stat]=\"graph.stat()\"\r\n [color]=\"graph.color\"\r\n />\r\n </li>\r\n }\r\n </div>\r\n </div>\r\n\r\n @for (el of videoStatus(); track el.key + $index) {\r\n <div (click)=\"toggleGraph($event, el.key, el.value)\" class=\"stat\">\r\n <span>{{ el.key }}: </span>{{ el.value | json }}\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n @if (!collapsed()) {\r\n <div [innerHTML]=\"ssData() | safe: 'html'\" class=\"ssInfo\"></div>\r\n }\r\n}\r\n", styles: [".settings-container{position:absolute;top:65px;left:10px;z-index:1000;bottom:10px}.gear-button{left:0;width:50px;position:absolute;background:none;cursor:pointer;font-size:10px;font-weight:500;border:1px solid;border-radius:9px;background:#0162cc;color:#fff;padding:4px}.gear-button>*{color:#fff;filter:drop-shadow(1px 1px 1px rgb(0,0,0))}#aggregatedStats{max-height:calc(100% - 25px);overflow-y:auto;margin-top:25px;left:20px;z-index:31;max-width:400px;padding:10px;background-color:#fff3;border:1px solid grey}#aggregatedStats>*{color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000}#aggregatedStats:empty{display:none}#aggregatedStats button{position:absolute;right:5px;top:5px}#aggregatedStats.min{display:none}#aggregatedStats .forNerds{width:100%}#aggregatedStats .forNerds li{list-style-type:none;height:60px}#aggregatedStats .forNerds li app-stat-graph{display:block;width:100%;height:100%}#aggregatedStats .stat span{font-weight:700}#aggregatedStats .stat,#aggregatedStats .graph{cursor:pointer}#aggregatedStats .static{pointer-events:all}.ssInfo{position:absolute;top:0;left:50%;transform:translate(-50%);color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000;text-align:center;width:80%;pointer-events:none}\n"] }]
7978
+ args: [{ selector: 'app-video-stats', changeDetection: ChangeDetectionStrategy.OnPush, imports: [StatGraphComponent, JsonPipe, SafePipe], template: "@if (videoStatus() && viewportReady()) {\n <div class=\"settings-container\">\n <button (click)=\"toggle()\" class=\"gear-button\">Stats</button>\n <div (click)=\"toggle()\" [class.min]=\"collapsed()\" id=\"aggregatedStats\">\n <div class=\"forNerds\">\n <div (click)=\"$event.stopPropagation()\" class=\"static\">\n <li>\n <app-stat-graph\n [stat]=\"fpsTick()!\"\n label=\"FPS (higher is better)\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"videoQP()!\"\n label=\"QP (lower is better)\"\n color=\"#D5ff07\"\n />\n </li>\n <li>\n <app-stat-graph\n [stat]=\"bitrateTick()!\"\n label=\"Bitrate\"\n color=\"#D57F07\"\n />\n </li>\n </div>\n <div>\n @for (graph of graphList(); track graph.key) {\n <li (click)=\"toggleGraph($event, graph.key, 0)\" class=\"graph\">\n <app-stat-graph\n [label]=\"graph.key\"\n [stat]=\"graph.stat()\"\n [color]=\"graph.color\"\n />\n </li>\n }\n </div>\n </div>\n\n @for (el of videoStatus(); track el.key + $index) {\n <div (click)=\"toggleGraph($event, el.key, el.value)\" class=\"stat\">\n <span>{{ el.key }}: </span>{{ el.value | json }}\n </div>\n }\n </div>\n </div>\n @if (!collapsed()) {\n <div [innerHTML]=\"ssData() | safe: 'html'\" class=\"ssInfo\"></div>\n }\n}\n", styles: [".settings-container{position:absolute;top:65px;left:10px;z-index:1000;bottom:10px}.gear-button{left:0;width:50px;position:absolute;background:none;cursor:pointer;font-size:10px;font-weight:500;border:1px solid;border-radius:9px;background:#0162cc;color:#fff;padding:4px}.gear-button>*{color:#fff;filter:drop-shadow(1px 1px 1px rgb(0,0,0))}#aggregatedStats{max-height:calc(100% - 25px);overflow-y:auto;margin-top:25px;left:20px;z-index:31;max-width:400px;padding:10px;background-color:#fff3;border:1px solid grey}#aggregatedStats>*{color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000}#aggregatedStats:empty{display:none}#aggregatedStats button{position:absolute;right:5px;top:5px}#aggregatedStats.min{display:none}#aggregatedStats .forNerds{width:100%}#aggregatedStats .forNerds li{list-style-type:none;height:60px}#aggregatedStats .forNerds li app-stat-graph{display:block;width:100%;height:100%}#aggregatedStats .stat span{font-weight:700}#aggregatedStats .stat,#aggregatedStats .graph{cursor:pointer}#aggregatedStats .static{pointer-events:all}.ssInfo{position:absolute;top:0;left:50%;transform:translate(-50%);color:#fff;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000;text-align:center;width:80%;pointer-events:none}\n"] }]
7732
7979
  }], ctorParameters: () => [] });
7733
7980
 
7734
7981
  class ResumeStreamButtonComponent {
7735
7982
  #store;
7736
7983
  constructor() {
7737
7984
  this.#store = inject(Store);
7985
+ this.uiClasses = input({}, /* @ts-ignore */
7986
+ ...(ngDevMode ? [{ debugName: "uiClasses" }] : /* istanbul ignore next */ []));
7987
+ this.contentTemplate = input(null, /* @ts-ignore */
7988
+ ...(ngDevMode ? [{ debugName: "contentTemplate" }] : /* istanbul ignore next */ []));
7989
+ this.cardSkin = computed(() => resolveSkin(this.uiClasses(), 'resumeCard', 'resume-box'), /* @ts-ignore */
7990
+ ...(ngDevMode ? [{ debugName: "cardSkin" }] : /* istanbul ignore next */ []));
7991
+ this.textSkin = computed(() => resolveSkin(this.uiClasses(), 'resumeText', 'resume-box__text'), /* @ts-ignore */
7992
+ ...(ngDevMode ? [{ debugName: "textSkin" }] : /* istanbul ignore next */ []));
7993
+ this.buttonSkin = computed(() => resolveSkin(this.uiClasses(), 'resumeButton', 'connect-button'), /* @ts-ignore */
7994
+ ...(ngDevMode ? [{ debugName: "buttonSkin" }] : /* istanbul ignore next */ []));
7738
7995
  this.streamConfig = this.#store.selectSignal(selectStreamConfig);
7739
7996
  this.isSecondStart = signal(this.streamConfig()?.autoStart && location.protocol === 'https:', /* @ts-ignore */
7740
7997
  ...(ngDevMode ? [{ debugName: "isSecondStart" }] : /* istanbul ignore next */ []));
@@ -7755,6 +8012,14 @@ class ResumeStreamButtonComponent {
7755
8012
  }, /* @ts-ignore */
7756
8013
  ...(ngDevMode ? [{ debugName: "isAfkDisconnect" }] : /* istanbul ignore next */ []));
7757
8014
  this.cirrusConnected = this.#store.selectSignal(unrealFeature.selectCirrusConnected);
8015
+ // Created once: the object identity must stay stable, reactivity lives in the
8016
+ // signals it carries. Declared after the signals it references so field
8017
+ // initialisation order holds.
8018
+ this.slotContext = {
8019
+ isSecondStart: this.isSecondStart,
8020
+ isAfkDisconnect: this.isAfkDisconnect,
8021
+ start: () => this.connect(),
8022
+ };
7758
8023
  let wasConnected = this.cirrusConnected();
7759
8024
  effect(() => {
7760
8025
  const connected = this.cirrusConnected();
@@ -7770,13 +8035,13 @@ class ResumeStreamButtonComponent {
7770
8035
  disconnect() {
7771
8036
  this.isSecondStart.set(true);
7772
8037
  }
7773
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: ResumeStreamButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7774
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: ResumeStreamButtonComponent, isStandalone: true, selector: "app-resume-stream-button", ngImport: i0, template: "@if (isShowResumeButton()) {\r\n <div class=\"resume-box\">\r\n @if (isSecondStart()) {\r\n <div class=\"resume-box__text\">\r\n Your stream {{ isAfkDisconnect() ? 'has been' : 'is' }} paused due to\r\n inactivity\r\n </div>\r\n }\r\n\r\n <app-unreal-button\r\n (clicked)=\"connect()\"\r\n [fullWidth]=\"true\"\r\n [data-testid]=\"'connect-button'\"\r\n size=\"lg\"\r\n weight=\"primary\"\r\n class=\"connect-button\"\r\n >\r\n {{ isSecondStart() ? 'Resume' : 'Start' }}\r\n </app-unreal-button>\r\n </div>\r\n}\r\n", styles: [".resume-box{padding:16px;position:absolute;bottom:0;left:50%;gap:12px;z-index:6;display:flex;transform:translate(-50%,-50%);flex-direction:column;align-items:center;border-radius:var(--src-border-rounded-parent, 8px);background:var(--src-surface-container-main, #fff);box-shadow:0 26px 80px #0003,0 0 1px #0003}.resume-box .connect-button{width:100%}.resume-box .resume-box__text{color:var(--src-color-grey-500, #6b7280);text-align:center;font-family:var(--src-font-family-body, system-ui, sans-serif);font-size:14px;font-style:normal;font-weight:400;line-height:24px}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8038
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ResumeStreamButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8039
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: ResumeStreamButtonComponent, isStandalone: true, selector: "app-resume-stream-button", inputs: { uiClasses: { classPropertyName: "uiClasses", publicName: "uiClasses", isSignal: true, isRequired: false, transformFunction: null }, contentTemplate: { classPropertyName: "contentTemplate", publicName: "contentTemplate", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isShowResumeButton()) {\n <div [class]=\"cardSkin()\" class=\"resume-anchor\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else {\n @if (isSecondStart()) {\n <div [class]=\"textSkin()\">\n Your stream {{ isAfkDisconnect() ? 'has been' : 'is' }} paused due to\n inactivity\n </div>\n }\n\n <app-unreal-button\n (clicked)=\"connect()\"\n [fullWidth]=\"true\"\n [data-testid]=\"'connect-button'\"\n [class]=\"buttonSkin()\"\n size=\"lg\"\n weight=\"primary\"\n >\n {{ isSecondStart() ? 'Resume' : 'Start' }}\n </app-unreal-button>\n }\n </div>\n}\n", styles: [".resume-anchor{position:absolute;bottom:0;left:50%;transform:translate(-50%,-50%);z-index:6}.resume-box{padding:16px;gap:12px;display:flex;flex-direction:column;align-items:center;border-radius:var(--unreal-radius-card, var(--src-border-rounded-parent, 8px));background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));box-shadow:var(--unreal-shadow-card, 0 26px 80px 0 rgba(0, 0, 0, .2), 0 0 1px 0 rgba(0, 0, 0, .2))}.connect-button{width:100%}.resume-box__text{color:var(--unreal-text-secondary, var(--src-color-grey-500, #6b7280));text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:14px;font-style:normal;font-weight:400;line-height:24px}\n"], dependencies: [{ kind: "component", type: UnrealButtonComponent, selector: "app-unreal-button", inputs: ["type", "weight", "size", "fullWidth", "isDisabled", "data-testid", "ariaLabel"], outputs: ["clicked"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7775
8040
  }
7776
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: ResumeStreamButtonComponent, decorators: [{
8041
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: ResumeStreamButtonComponent, decorators: [{
7777
8042
  type: Component,
7778
- args: [{ selector: 'app-resume-stream-button', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent], template: "@if (isShowResumeButton()) {\r\n <div class=\"resume-box\">\r\n @if (isSecondStart()) {\r\n <div class=\"resume-box__text\">\r\n Your stream {{ isAfkDisconnect() ? 'has been' : 'is' }} paused due to\r\n inactivity\r\n </div>\r\n }\r\n\r\n <app-unreal-button\r\n (clicked)=\"connect()\"\r\n [fullWidth]=\"true\"\r\n [data-testid]=\"'connect-button'\"\r\n size=\"lg\"\r\n weight=\"primary\"\r\n class=\"connect-button\"\r\n >\r\n {{ isSecondStart() ? 'Resume' : 'Start' }}\r\n </app-unreal-button>\r\n </div>\r\n}\r\n", styles: [".resume-box{padding:16px;position:absolute;bottom:0;left:50%;gap:12px;z-index:6;display:flex;transform:translate(-50%,-50%);flex-direction:column;align-items:center;border-radius:var(--src-border-rounded-parent, 8px);background:var(--src-surface-container-main, #fff);box-shadow:0 26px 80px #0003,0 0 1px #0003}.resume-box .connect-button{width:100%}.resume-box .resume-box__text{color:var(--src-color-grey-500, #6b7280);text-align:center;font-family:var(--src-font-family-body, system-ui, sans-serif);font-size:14px;font-style:normal;font-weight:400;line-height:24px}\n"] }]
7779
- }], ctorParameters: () => [] });
8043
+ args: [{ selector: 'app-resume-stream-button', changeDetection: ChangeDetectionStrategy.OnPush, imports: [UnrealButtonComponent, NgTemplateOutlet], template: "@if (isShowResumeButton()) {\n <div [class]=\"cardSkin()\" class=\"resume-anchor\">\n @if (contentTemplate(); as tpl) {\n <ng-container\n [ngTemplateOutlet]=\"tpl\"\n [ngTemplateOutletContext]=\"{ $implicit: slotContext }\"\n />\n } @else {\n @if (isSecondStart()) {\n <div [class]=\"textSkin()\">\n Your stream {{ isAfkDisconnect() ? 'has been' : 'is' }} paused due to\n inactivity\n </div>\n }\n\n <app-unreal-button\n (clicked)=\"connect()\"\n [fullWidth]=\"true\"\n [data-testid]=\"'connect-button'\"\n [class]=\"buttonSkin()\"\n size=\"lg\"\n weight=\"primary\"\n >\n {{ isSecondStart() ? 'Resume' : 'Start' }}\n </app-unreal-button>\n }\n </div>\n}\n", styles: [".resume-anchor{position:absolute;bottom:0;left:50%;transform:translate(-50%,-50%);z-index:6}.resume-box{padding:16px;gap:12px;display:flex;flex-direction:column;align-items:center;border-radius:var(--unreal-radius-card, var(--src-border-rounded-parent, 8px));background:var(--unreal-surface-card, var(--src-surface-container-main, #fff));box-shadow:var(--unreal-shadow-card, 0 26px 80px 0 rgba(0, 0, 0, .2), 0 0 1px 0 rgba(0, 0, 0, .2))}.connect-button{width:100%}.resume-box__text{color:var(--unreal-text-secondary, var(--src-color-grey-500, #6b7280));text-align:center;font-family:var(--unreal-font-family, var(--src-font-family-body, system-ui, sans-serif));font-size:14px;font-style:normal;font-weight:400;line-height:24px}\n"] }]
8044
+ }], ctorParameters: () => [], propDecorators: { uiClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiClasses", required: false }] }], contentTemplate: [{ type: i0.Input, args: [{ isSignal: true, alias: "contentTemplate", required: false }] }] } });
7780
8045
 
7781
8046
  class IntroSrcComponent {
7782
8047
  #store;
@@ -7840,12 +8105,12 @@ class IntroSrcComponent {
7840
8105
  sourceElement.addEventListener('error', () => this.#store.dispatch(resetIntroSrc()));
7841
8106
  videoContainer.appendChild(videoElement);
7842
8107
  }
7843
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: IntroSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7844
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: IntroSrcComponent, isStandalone: true, selector: "app-intro-src", viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoPlayerCover"], descendants: true, isSignal: true }], ngImport: i0, template: "@let image = imageIntroSrc();\r\n@if (image) {\r\n <div class=\"backImage\">\r\n <img (error)=\"loadingImageError()\" [ngSrc]=\"image\" fill alt=\"imageSrc\" />\r\n </div>\r\n} @else if (videoIntroSrc()) {\r\n <div #videoPlayerCover class=\"backVideo\"></div>\r\n}\r\n", styles: [".backVideo{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backVideo video{position:absolute;width:100%;height:100%;object-fit:cover}.backImage{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backImage img{position:absolute;width:100%;height:100%;object-fit:cover}\n"], dependencies: [{ kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8108
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: IntroSrcComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8109
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: IntroSrcComponent, isStandalone: true, selector: "app-intro-src", viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoPlayerCover"], descendants: true, isSignal: true }], ngImport: i0, template: "@let image = imageIntroSrc();\n@if (image) {\n <div class=\"backImage\">\n <img (error)=\"loadingImageError()\" [ngSrc]=\"image\" fill alt=\"imageSrc\" />\n </div>\n} @else if (videoIntroSrc()) {\n <div #videoPlayerCover class=\"backVideo\"></div>\n}\n", styles: [".backVideo{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backVideo video{position:absolute;width:100%;height:100%;object-fit:cover}.backImage{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backImage img{position:absolute;width:100%;height:100%;object-fit:cover}\n"], dependencies: [{ kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "decoding", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
7845
8110
  }
7846
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: IntroSrcComponent, decorators: [{
8111
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: IntroSrcComponent, decorators: [{
7847
8112
  type: Component,
7848
- args: [{ selector: 'app-intro-src', imports: [NgOptimizedImage], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = imageIntroSrc();\r\n@if (image) {\r\n <div class=\"backImage\">\r\n <img (error)=\"loadingImageError()\" [ngSrc]=\"image\" fill alt=\"imageSrc\" />\r\n </div>\r\n} @else if (videoIntroSrc()) {\r\n <div #videoPlayerCover class=\"backVideo\"></div>\r\n}\r\n", styles: [".backVideo{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backVideo video{position:absolute;width:100%;height:100%;object-fit:cover}.backImage{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backImage img{position:absolute;width:100%;height:100%;object-fit:cover}\n"] }]
8113
+ args: [{ selector: 'app-intro-src', imports: [NgOptimizedImage], changeDetection: ChangeDetectionStrategy.OnPush, template: "@let image = imageIntroSrc();\n@if (image) {\n <div class=\"backImage\">\n <img (error)=\"loadingImageError()\" [ngSrc]=\"image\" fill alt=\"imageSrc\" />\n </div>\n} @else if (videoIntroSrc()) {\n <div #videoPlayerCover class=\"backVideo\"></div>\n}\n", styles: [".backVideo{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backVideo video{position:absolute;width:100%;height:100%;object-fit:cover}.backImage{position:absolute;top:0;left:0;display:flex;justify-content:center;align-items:center;width:100%;height:100%;z-index:1}.backImage img{position:absolute;width:100%;height:100%;object-fit:cover}\n"] }]
7849
8114
  }], ctorParameters: () => [], propDecorators: { videoElement: [{ type: i0.ViewChild, args: ['videoPlayerCover', { isSignal: true }] }] } });
7850
8115
 
7851
8116
  class UnrealSceneComponent {
@@ -7879,6 +8144,15 @@ class UnrealSceneComponent {
7879
8144
  }, /* @ts-ignore */
7880
8145
  ...(ngDevMode ? [{ debugName: "resolutionSize" }] : /* istanbul ignore next */ []));
7881
8146
  this.changeMouseOverScene = output();
8147
+ /** Host classes replacing the built-in decoration of the scene overlays. */
8148
+ this.uiClasses = input({}, /* @ts-ignore */
8149
+ ...(ngDevMode ? [{ debugName: "uiClasses" }] : /* istanbul ignore next */ []));
8150
+ this.resumeSlot = contentChild(UnrealResumeSlotDirective, /* @ts-ignore */
8151
+ ...(ngDevMode ? [{ debugName: "resumeSlot" }] : /* istanbul ignore next */ []));
8152
+ this.afkSlot = contentChild(UnrealAfkSlotDirective, /* @ts-ignore */
8153
+ ...(ngDevMode ? [{ debugName: "afkSlot" }] : /* istanbul ignore next */ []));
8154
+ this.statusSlot = contentChild(UnrealStatusSlotDirective, /* @ts-ignore */
8155
+ ...(ngDevMode ? [{ debugName: "statusSlot" }] : /* istanbul ignore next */ []));
7882
8156
  this.videoElement = viewChild('videoContainer', /* @ts-ignore */
7883
8157
  ...(ngDevMode ? [{ debugName: "videoElement" }] : /* istanbul ignore next */ []));
7884
8158
  this.resolutionValues$ = toObservable(this.resolutionSize);
@@ -7976,7 +8250,7 @@ class UnrealSceneComponent {
7976
8250
  this.height = height;
7977
8251
  }));
7978
8252
  const resizeRequired$ = merge(this.actions$.pipe(ofType(videoStreamInitialized)), fromEvent(window, 'resize'));
7979
- const videoStreamSizeChanged$ = this.videoService.videoStats$.pipe(filter(() => !this.isFreezeFrameLoading()), map$1((stats) => ({
8253
+ const videoStreamSizeChanged$ = this.videoService.videoStats$.pipe(filter(() => !this.isFreezeFrameLoading()), map((stats) => ({
7980
8254
  w: stats.aggregatedStats.frameWidth || 0,
7981
8255
  h: stats.aggregatedStats.frameHeight || 0,
7982
8256
  })), distinctUntilChanged((previous, current) => fpIsASameAsB(previous.w, current.w, SAME_SIZE_THRESHOLD) &&
@@ -7985,8 +8259,8 @@ class UnrealSceneComponent {
7985
8259
  .pipe(debounceTime(DEBOUNCE_TO_MANY_RESIZE_CALLS), switchMap(() => {
7986
8260
  const key = Math.random();
7987
8261
  // Poll 3 times to capture late-arriving DOM measurements after layout settles
7988
- return timer(0, 300).pipe(take(3), map$1(() => key));
7989
- }), map$1((key) => ({ key, ...this.resizeValues })), distinctUntilChanged((previous, current) => fpIsASameAsB(previous.w, current.w, SAME_SIZE_THRESHOLD) &&
8262
+ return timer(0, 300).pipe(take(3), map(() => key));
8263
+ }), map((key) => ({ key, ...this.resizeValues })), distinctUntilChanged((previous, current) => fpIsASameAsB(previous.w, current.w, SAME_SIZE_THRESHOLD) &&
7990
8264
  fpIsASameAsB(previous.h, current.h, SAME_SIZE_THRESHOLD) &&
7991
8265
  previous.key === current.key), tap((size) => this.adaptVideo(size)),
7992
8266
  // Key excluded: only dispatch when actual pixel dimensions change
@@ -8065,10 +8339,10 @@ class UnrealSceneComponent {
8065
8339
  },
8066
8340
  });
8067
8341
  }
8068
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealSceneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8069
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: UnrealSceneComponent, isStandalone: true, selector: "app-unreal-scene", inputs: { useContainerAsSizeProvider: { classPropertyName: "useContainerAsSizeProvider", publicName: "useContainerAsSizeProvider", isSignal: true, isRequired: false, transformFunction: null }, isStudio: { classPropertyName: "isStudio", publicName: "isStudio", isSignal: true, isRequired: false, transformFunction: null }, resolutionSize: { classPropertyName: "resolutionSize", publicName: "resolutionSize", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changeMouseOverScene: "changeMouseOverScene" }, host: { listeners: { "mouseover": "onMouseOver()", "mouseout": "onMouseOut()", "contextmenu": "onContextMenu($event)" } }, viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"frame unreal-container\">\r\n <div #videoContainer id=\"player\"></div>\r\n\r\n <app-intro-src />\r\n <app-image-loading-src />\r\n <app-resume-stream-button />\r\n <app-unreal-status />\r\n <app-freeze-frame />\r\n <app-afk-timeout-modal />\r\n\r\n <ng-content select=\"app-pdf\"></ng-content>\r\n <ng-content select=\"app-show-case\"></ng-content>\r\n\r\n @if (isDevMode) {\r\n <app-video-stats />\r\n }\r\n</div>\r\n", styles: [".unreal-container{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#fff}.unreal-container #player{position:absolute;width:100%;height:100%;display:flex;justify-content:center;align-items:center;overflow:hidden}.unreal-container.select{cursor:url('data:image/svg+xml,<svg width=\"24\" height=\"24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M15.15 21.375a1.423 1.423 0 0 1-1.15.063 1.487 1.487 0 0 1-.85-.788l-3-6.45-2.325 3.25c-.283.4-.658.525-1.125.375-.467-.15-.7-.466-.7-.95V4.05c0-.417.188-.717.563-.9.375-.183.729-.142 1.062.125l10.1 7.95c.383.284.496.65.337 1.1-.158.45-.479.675-.962.675h-4.2l2.975 6.375c.183.384.204.767.063 1.15a1.487 1.487 0 0 1-.788.85Z\" fill=\"%23000\"/><path d=\"m12.697 20.861.002.005c.237.495.617.852 1.128 1.04.515.191 1.039.16 1.539-.08a1.987 1.987 0 0 0 1.04-1.128 1.922 1.922 0 0 0-.079-1.536v-.003L13.684 13.5H17.1c.32 0 .628-.075.89-.26.263-.184.438-.447.544-.749.106-.3.135-.617.04-.925a1.458 1.458 0 0 0-.545-.738L7.936 2.883a1.51 1.51 0 0 0-.768-.336 1.471 1.471 0 0 0-.825.154 1.495 1.495 0 0 0-.626.547 1.492 1.492 0 0 0-.217.802v12.825c0 .324.08.634.272.897.193.261.467.43.775.53.31.099.632.12.942.016.31-.103.555-.313.743-.578h.001l1.825-2.552 2.639 5.673Z\" stroke=\"%23fff\" stroke-opacity=\".7\"/></svg>') 6 2,auto}.unreal-container.orbit{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.998 21.6c-1.966 0-3.737-.53-5.312-1.588-1.575-1.058-2.738-2.437-3.488-4.137a.852.852 0 0 1 .013-.713.867.867 0 0 1 .512-.487.86.86 0 0 1 .688.037c.225.109.387.28.487.513.617 1.35 1.559 2.45 2.825 3.3 1.267.85 2.692 1.275 4.275 1.275 1.384 0 2.646-.33 3.788-.988a7.985 7.985 0 0 0 2.762-2.612h-.85a.873.873 0 0 1-.64-.257.863.863 0 0 1-.26-.638.88.88 0 0 1 .26-.643.864.864 0 0 1 .64-.262h3c.255 0 .47.086.642.259a.87.87 0 0 1 .258.64v3a.874.874 0 0 1-.257.642.863.863 0 0 1-.637.259.88.88 0 0 1-.643-.259.865.865 0 0 1-.263-.641v-.725a9.95 9.95 0 0 1-3.35 2.925c-1.35.733-2.833 1.1-4.45 1.1Zm0-17.4c-1.383 0-2.645.33-3.787.987A7.985 7.985 0 0 0 5.448 7.8h.85c.255 0 .47.086.642.257a.863.863 0 0 1 .258.638.88.88 0 0 1-.258.642.864.864 0 0 1-.642.263h-3a.87.87 0 0 1-.64-.259.87.87 0 0 1-.26-.641v-3c0-.255.086-.469.258-.641a.863.863 0 0 1 .637-.26.88.88 0 0 1 .643.26.864.864 0 0 1 .262.64v.726A9.95 9.95 0 0 1 7.548 3.5c1.35-.733 2.834-1.1 4.45-1.1 2 0 3.788.542 5.363 1.625 1.575 1.083 2.736 2.49 3.482 4.22a.724.724 0 0 1-.045.646.926.926 0 0 1-.525.437.87.87 0 0 1-.687-.04.977.977 0 0 1-.488-.513c-.616-1.35-1.558-2.45-2.825-3.3-1.266-.85-2.691-1.275-4.275-1.275Zm0 10.8a2.893 2.893 0 0 1-2.125-.875A2.893 2.893 0 0 1 8.998 12c0-.833.292-1.542.875-2.125A2.893 2.893 0 0 1 11.998 9c.834 0 1.542.292 2.125.875.584.583.875 1.292.875 2.125s-.291 1.542-.875 2.125a2.893 2.893 0 0 1-2.125.875Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"m2.739 16.072.002.005c.789 1.788 2.014 3.24 3.666 4.35 1.66 1.116 3.53 1.673 5.591 1.673 1.696 0 3.262-.386 4.69-1.16a10.54 10.54 0 0 0 2.714-2.097c.069.167.171.32.308.454.272.268.613.403.994.403.38 0 .722-.135.992-.406s.402-.614.402-.994v-3c0-.381-.134-.724-.405-.995a1.37 1.37 0 0 0-.995-.405h-3c-.383 0-.727.137-.997.411a1.38 1.38 0 0 0-.403.994c0 .38.135.723.407.992.238.237.532.369.858.397a7.552 7.552 0 0 1-2.027 1.685c-1.062.613-2.237.92-3.538.92-1.488 0-2.815-.397-3.996-1.19-1.19-.798-2.07-1.826-2.647-3.087-.147-.34-.393-.6-.727-.76a1.36 1.36 0 0 0-1.073-.058c-.37.133-.64.397-.8.754a1.351 1.351 0 0 0-.016 1.114Zm4.553-8.37a1.36 1.36 0 0 0-.858-.396A7.552 7.552 0 0 1 8.46 5.62c1.062-.613 2.237-.921 3.537-.921 1.489 0 2.816.398 3.997 1.19 1.19.8 2.07 1.827 2.646 3.088.148.34.394.6.728.76a1.37 1.37 0 0 0 1.068.063c.347-.12.62-.346.799-.668.187-.338.215-.71.072-1.072l-.003-.007-.003-.007c-.784-1.818-2.006-3.298-3.658-4.434C15.982 2.47 14.094 1.9 11.998 1.9c-1.695 0-3.261.385-4.688 1.16a10.536 10.536 0 0 0-2.715 2.096 1.364 1.364 0 0 0-.308-.453 1.38 1.38 0 0 0-.994-.403c-.38 0-.722.135-.992.406s-.403.614-.403.994v3c0 .38.135.724.406.995.27.27.614.405.994.405h3c.384 0 .727-.137.998-.412a1.38 1.38 0 0 0 .402-.993c0-.38-.135-.723-.406-.992ZM9.52 14.48a3.393 3.393 0 0 0 2.478 1.02c.965 0 1.8-.342 2.479-1.02a3.392 3.392 0 0 0 1.021-2.48c0-.963-.343-1.8-1.021-2.478A3.392 3.392 0 0 0 11.998 8.5c-.964 0-1.8.343-2.478 1.021A3.392 3.392 0 0 0 8.498 12c0 .964.344 1.8 1.022 2.479Z\"/></svg>') 12 12,auto}.unreal-container.pan{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.997 10.075a1.01 1.01 0 0 1-.738-.313 1.008 1.008 0 0 1-.312-.737V6.15l-.95.95a.998.998 0 0 1-.763.312 1.09 1.09 0 0 1-.763-.337 1.06 1.06 0 0 1-.324-.775c0-.3.108-.558.324-.775l2.776-2.775c.117-.116.237-.2.362-.25a1.04 1.04 0 0 1 .775 0c.125.05.246.134.363.25l2.8 2.8c.216.217.32.47.313.762a1.096 1.096 0 0 1-.338.763 1.058 1.058 0 0 1-.775.325c-.3 0-.558-.108-.775-.325l-.925-.925v2.875c0 .283-.104.53-.312.737a1.01 1.01 0 0 1-.738.313Zm0 11.5a1.04 1.04 0 0 1-.388-.075 1.103 1.103 0 0 1-.362-.25l-2.8-2.8a1.002 1.002 0 0 1-.313-.762c.009-.292.121-.546.337-.763.217-.217.475-.325.775-.325.3 0 .559.108.775.325l.926.925v-2.875c0-.283.104-.529.312-.737a1.01 1.01 0 0 1 .738-.313c.283 0 .529.104.738.313.208.208.312.454.312.737v2.875l.95-.95a.998.998 0 0 1 .762-.312c.292.008.546.12.763.337.216.217.324.475.324.775 0 .3-.108.559-.324.775l-2.775 2.775c-.117.116-.238.2-.363.25a1.04 1.04 0 0 1-.387.075Zm4.925-6.05a1.058 1.058 0 0 1-.326-.774c0-.3.109-.559.326-.776l.925-.925H14.97c-.283 0-.528-.104-.736-.312a1.01 1.01 0 0 1-.313-.738c0-.283.104-.53.313-.738.208-.208.453-.312.737-.312h2.875l-.95-.95a.998.998 0 0 1-.313-.762 1.09 1.09 0 0 1 .338-.764 1.06 1.06 0 0 1 .775-.324c.3 0 .558.108.775.324l2.774 2.776c.117.117.2.238.251.363a1.04 1.04 0 0 1 0 .775c-.05.124-.134.245-.25.362l-2.8 2.8c-.217.216-.471.32-.762.313a1.096 1.096 0 0 1-.763-.337Zm-11.4 0L2.746 12.75a1.103 1.103 0 0 1-.25-.362 1.04 1.04 0 0 1 0-.775c.05-.125.133-.246.25-.363l2.8-2.8c.216-.216.47-.32.762-.313.292.01.546.121.763.337.217.217.325.476.325.776 0 .3-.108.558-.325.775l-.925.925h2.875c.283 0 .529.104.737.312.208.209.313.455.313.738s-.105.53-.313.738a1.008 1.008 0 0 1-.737.312H6.147l.95.95c.217.217.32.471.312.762a1.09 1.09 0 0 1-.337.764 1.06 1.06 0 0 1-.775.324c-.3 0-.559-.108-.776-.324Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M9.22 7.912c.436.013.821-.15 1.13-.458l.097-.097v1.668c0 .422.16.793.458 1.09.298.299.67.46 1.092.46.422 0 .793-.161 1.091-.46.298-.297.459-.668.459-1.09V7.357l.071.072c.309.308.693.471 1.13.471.435 0 .82-.163 1.128-.471.301-.303.47-.676.483-1.102v-.001a1.501 1.501 0 0 0-.46-1.13l-2.799-2.8a1.6 1.6 0 0 0-.528-.36l-.003-.001a1.54 1.54 0 0 0-1.145 0l-.002.001a1.6 1.6 0 0 0-.529.36L8.118 5.172l-.001.001a1.56 1.56 0 0 0-.47 1.128c0 .435.163.82.47 1.128.303.303.676.472 1.103.484Zm0 0 .014-.5-.015.5Zm-1.311 6.865a1.497 1.497 0 0 0-.458-1.13l-.097-.097h1.668c.421 0 .793-.16 1.09-.458.298-.299.46-.67.46-1.092a1.51 1.51 0 0 0-.46-1.091 1.507 1.507 0 0 0-1.09-.459H7.354l.071-.072c.309-.308.472-.692.472-1.128 0-.436-.163-.82-.472-1.13a1.596 1.596 0 0 0-1.101-.482h-.002a1.501 1.501 0 0 0-1.129.459l-2.8 2.8a1.6 1.6 0 0 0-.36.528l-.001.003a1.54 1.54 0 0 0 0 1.144v.003c.081.2.208.375.362.529l2.774 2.775c.309.308.693.47 1.129.47.435 0 .82-.162 1.128-.47.303-.302.472-.676.484-1.102Zm0 0-.5-.014.5.015v-.001Zm3.038-8.627-.5.5.5.207V6.15Zm.475 15.814.002.001a1.54 1.54 0 0 0 1.145 0h.002c.2-.081.375-.208.53-.362l2.775-2.774a1.56 1.56 0 0 0 .47-1.129c0-.435-.162-.82-.47-1.128a1.589 1.589 0 0 0-1.103-.484 1.497 1.497 0 0 0-1.13.458l-.096.097v-1.668c0-.421-.161-.793-.459-1.09a1.509 1.509 0 0 0-1.091-.46c-.422 0-.794.161-1.092.46a1.507 1.507 0 0 0-.458 1.09v1.668l-.072-.072a1.558 1.558 0 0 0-1.129-.471c-.436 0-.82.163-1.128.471l-.001.001c-.301.302-.47.675-.483 1.101v.001c-.012.437.151.821.46 1.13l2.8 2.8c.153.153.328.28.528.36Zm5.146-6.085c.303.302.676.47 1.102.484a1.5 1.5 0 0 0 1.13-.46l2.8-2.8a1.6 1.6 0 0 0 .36-.528l.002-.003a1.54 1.54 0 0 0 0-1.144l-.001-.003a1.6 1.6 0 0 0-.361-.529l-2.774-2.775h-.001a1.56 1.56 0 0 0-1.128-.47c-.436 0-.82.162-1.128.47h-.001a1.59 1.59 0 0 0-.484 1.102c-.012.437.15.822.459 1.13l.097.097h-1.668c-.422 0-.793.16-1.09.459-.299.298-.46.67-.46 1.091 0 .422.161.793.46 1.092.297.297.668.458 1.09.458h1.668l-.072.072a1.558 1.558 0 0 0-.472 1.129c0 .435.164.82.472 1.128ZM6.147 13.05l.5.5.207-.5h-.707Z\"/></svg>') 12 12,auto}.unreal-container.dolly{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><mask id=\"a\" width=\"24\" height=\"24\" x=\"0\" y=\"0\" maskUnits=\"userSpaceOnUse\" style=\"mask-type:alpha\"><path fill=\"%23127392\" d=\"M0 0h24v24H0z\"/></mask><g mask=\"url(%23a)\"><path fill=\"%23000\" d=\"M12.002 20.575a1.026 1.026 0 0 1-.75-.325l-2.55-2.55a.933.933 0 0 1-.287-.713c.008-.275.113-.513.313-.713.2-.2.441-.3.725-.3.283 0 .524.1.724.3l.776.776V6.95l-.8.8c-.2.2-.438.296-.712.288a1.018 1.018 0 0 1-.713-.312c-.2-.2-.3-.442-.3-.726s.1-.525.3-.725l2.524-2.525a1.026 1.026 0 0 1 1.5 0l2.55 2.55c.2.2.296.438.289.713a1.023 1.023 0 0 1-.314.713c-.2.2-.441.3-.724.3a.988.988 0 0 1-.725-.3l-.775-.776v10.1l.8-.8c.2-.2.437-.296.712-.288.275.008.512.112.712.312.2.2.3.442.3.726s-.1.525-.3.725l-2.524 2.525a1.026 1.026 0 0 1-.75.325Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M13.553 8.153c.28.245.62.373 1 .373.415 0 .784-.153 1.078-.447.287-.287.446-.644.46-1.05v-.002a1.432 1.432 0 0 0-.435-1.08l-2.55-2.55-.354.353.354-.354a1.526 1.526 0 0 0-2.207 0L8.374 5.921A1.487 1.487 0 0 0 7.928 7c0 .416.152.785.446 1.08.288.287.645.446 1.052.457l4.127-.384Zm0 0v7.693m0-7.693a1.667 1.667 0 0 1-.079-.074l-3.021.075v7.693a1.482 1.482 0 0 0-1-.373c-.416 0-.785.153-1.079.447a1.522 1.522 0 0 0-.46 1.05v.002c-.011.417.14.786.435 1.08l2.55 2.55a1.527 1.527 0 0 0 2.207 0l2.525-2.524c.294-.294.446-.663.446-1.079 0-.416-.152-.785-.446-1.08a1.518 1.518 0 0 0-1.052-.457m0 0-.014.5.014-.5Zm0 0a1.424 1.424 0 0 0-1.027.383m0 0a1.583 1.583 0 0 0-.053.05l.354.354m-.3-.404v.104l.3.3m0 0-.3-.3v.6l.3-.3Z\"/></g></svg>%0D%0A') 12 12,auto}.unreal-container.disabled:before{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}#playerUI{position:absolute;z-index:10;width:100%}#statsContainer{display:none;text-align:left;background-color:#000c}#stats{padding:6px;font-weight:700;font-size:14px;color:#0f0}canvas{position:absolute;image-rendering:crisp-edges}#overlay{position:absolute;top:0;right:2%;z-index:100;padding:4px;border-top-width:0;-webkit-border-bottom-right-radius:5px;-moz-border-radius-bottomright:5px;border-bottom-right-radius:5px;-webkit-border-bottom-left-radius:5px;-moz-border-radius-bottomleft:5px;border-bottom-left-radius:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none}.overlay{font-weight:lighter;font-family:var(--src-font-family-body, system-ui, sans-serif)}#overlayButton:hover{cursor:pointer}#overlayButton{font-size:40px;text-align:right}#overlaySettings{display:none;width:300px;padding:4px}#videoMessageOverlay{position:absolute;z-index:20;width:100%;margin:auto;font-size:1.8em;font-family:var(--src-font-family-body, system-ui, sans-serif)}#playButton{display:inline-block;height:auto}img#playButton{width:10%;max-width:241px}#UIInteraction{position:fixed}#UIInteractionButtonBoundary{padding:2px}#UIInteractionButton{cursor:pointer}#hiddenInput{position:absolute;left:-10%;width:0;opacity:0}#editTextButton{position:absolute;width:40px;height:40px}\n"], dependencies: [{ kind: "component", type: AfkTimeoutModalComponent, selector: "app-afk-timeout-modal" }, { kind: "component", type: UnrealStatusComponent, selector: "app-unreal-status" }, { kind: "component", type: FreezeFrameComponent, selector: "app-freeze-frame" }, { kind: "component", type: VideoStatsComponent, selector: "app-video-stats" }, { kind: "component", type: ResumeStreamButtonComponent, selector: "app-resume-stream-button" }, { kind: "component", type: ImageLoadingSrcComponent, selector: "app-image-loading-src" }, { kind: "component", type: IntroSrcComponent, selector: "app-intro-src" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8342
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealSceneComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
8343
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: UnrealSceneComponent, isStandalone: true, selector: "app-unreal-scene", inputs: { useContainerAsSizeProvider: { classPropertyName: "useContainerAsSizeProvider", publicName: "useContainerAsSizeProvider", isSignal: true, isRequired: false, transformFunction: null }, isStudio: { classPropertyName: "isStudio", publicName: "isStudio", isSignal: true, isRequired: false, transformFunction: null }, resolutionSize: { classPropertyName: "resolutionSize", publicName: "resolutionSize", isSignal: true, isRequired: false, transformFunction: null }, uiClasses: { classPropertyName: "uiClasses", publicName: "uiClasses", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { changeMouseOverScene: "changeMouseOverScene" }, host: { listeners: { "mouseover": "onMouseOver()", "mouseout": "onMouseOut()", "contextmenu": "onContextMenu($event)" } }, queries: [{ propertyName: "resumeSlot", first: true, predicate: UnrealResumeSlotDirective, descendants: true, isSignal: true }, { propertyName: "afkSlot", first: true, predicate: UnrealAfkSlotDirective, descendants: true, isSignal: true }, { propertyName: "statusSlot", first: true, predicate: UnrealStatusSlotDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "videoElement", first: true, predicate: ["videoContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"frame unreal-container\">\n <div #videoContainer id=\"player\"></div>\n\n <app-intro-src />\n <app-image-loading-src />\n <app-freeze-frame />\n <app-resume-stream-button\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"resumeSlot()?.template ?? null\"\n />\n <app-unreal-status\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"statusSlot()?.template ?? null\"\n />\n <app-afk-timeout-modal\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"afkSlot()?.template ?? null\"\n />\n\n <ng-content select=\"app-pdf\"></ng-content>\n <ng-content select=\"app-show-case\"></ng-content>\n\n @if (isDevMode) {\n <app-video-stats />\n }\n</div>\n", styles: [".unreal-container{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#fff}.unreal-container #player{position:absolute;width:100%;height:100%;display:flex;justify-content:center;align-items:center;overflow:hidden}.unreal-container.select{cursor:url('data:image/svg+xml,<svg width=\"24\" height=\"24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M15.15 21.375a1.423 1.423 0 0 1-1.15.063 1.487 1.487 0 0 1-.85-.788l-3-6.45-2.325 3.25c-.283.4-.658.525-1.125.375-.467-.15-.7-.466-.7-.95V4.05c0-.417.188-.717.563-.9.375-.183.729-.142 1.062.125l10.1 7.95c.383.284.496.65.337 1.1-.158.45-.479.675-.962.675h-4.2l2.975 6.375c.183.384.204.767.063 1.15a1.487 1.487 0 0 1-.788.85Z\" fill=\"%23000\"/><path d=\"m12.697 20.861.002.005c.237.495.617.852 1.128 1.04.515.191 1.039.16 1.539-.08a1.987 1.987 0 0 0 1.04-1.128 1.922 1.922 0 0 0-.079-1.536v-.003L13.684 13.5H17.1c.32 0 .628-.075.89-.26.263-.184.438-.447.544-.749.106-.3.135-.617.04-.925a1.458 1.458 0 0 0-.545-.738L7.936 2.883a1.51 1.51 0 0 0-.768-.336 1.471 1.471 0 0 0-.825.154 1.495 1.495 0 0 0-.626.547 1.492 1.492 0 0 0-.217.802v12.825c0 .324.08.634.272.897.193.261.467.43.775.53.31.099.632.12.942.016.31-.103.555-.313.743-.578h.001l1.825-2.552 2.639 5.673Z\" stroke=\"%23fff\" stroke-opacity=\".7\"/></svg>') 6 2,auto}.unreal-container.orbit{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.998 21.6c-1.966 0-3.737-.53-5.312-1.588-1.575-1.058-2.738-2.437-3.488-4.137a.852.852 0 0 1 .013-.713.867.867 0 0 1 .512-.487.86.86 0 0 1 .688.037c.225.109.387.28.487.513.617 1.35 1.559 2.45 2.825 3.3 1.267.85 2.692 1.275 4.275 1.275 1.384 0 2.646-.33 3.788-.988a7.985 7.985 0 0 0 2.762-2.612h-.85a.873.873 0 0 1-.64-.257.863.863 0 0 1-.26-.638.88.88 0 0 1 .26-.643.864.864 0 0 1 .64-.262h3c.255 0 .47.086.642.259a.87.87 0 0 1 .258.64v3a.874.874 0 0 1-.257.642.863.863 0 0 1-.637.259.88.88 0 0 1-.643-.259.865.865 0 0 1-.263-.641v-.725a9.95 9.95 0 0 1-3.35 2.925c-1.35.733-2.833 1.1-4.45 1.1Zm0-17.4c-1.383 0-2.645.33-3.787.987A7.985 7.985 0 0 0 5.448 7.8h.85c.255 0 .47.086.642.257a.863.863 0 0 1 .258.638.88.88 0 0 1-.258.642.864.864 0 0 1-.642.263h-3a.87.87 0 0 1-.64-.259.87.87 0 0 1-.26-.641v-3c0-.255.086-.469.258-.641a.863.863 0 0 1 .637-.26.88.88 0 0 1 .643.26.864.864 0 0 1 .262.64v.726A9.95 9.95 0 0 1 7.548 3.5c1.35-.733 2.834-1.1 4.45-1.1 2 0 3.788.542 5.363 1.625 1.575 1.083 2.736 2.49 3.482 4.22a.724.724 0 0 1-.045.646.926.926 0 0 1-.525.437.87.87 0 0 1-.687-.04.977.977 0 0 1-.488-.513c-.616-1.35-1.558-2.45-2.825-3.3-1.266-.85-2.691-1.275-4.275-1.275Zm0 10.8a2.893 2.893 0 0 1-2.125-.875A2.893 2.893 0 0 1 8.998 12c0-.833.292-1.542.875-2.125A2.893 2.893 0 0 1 11.998 9c.834 0 1.542.292 2.125.875.584.583.875 1.292.875 2.125s-.291 1.542-.875 2.125a2.893 2.893 0 0 1-2.125.875Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"m2.739 16.072.002.005c.789 1.788 2.014 3.24 3.666 4.35 1.66 1.116 3.53 1.673 5.591 1.673 1.696 0 3.262-.386 4.69-1.16a10.54 10.54 0 0 0 2.714-2.097c.069.167.171.32.308.454.272.268.613.403.994.403.38 0 .722-.135.992-.406s.402-.614.402-.994v-3c0-.381-.134-.724-.405-.995a1.37 1.37 0 0 0-.995-.405h-3c-.383 0-.727.137-.997.411a1.38 1.38 0 0 0-.403.994c0 .38.135.723.407.992.238.237.532.369.858.397a7.552 7.552 0 0 1-2.027 1.685c-1.062.613-2.237.92-3.538.92-1.488 0-2.815-.397-3.996-1.19-1.19-.798-2.07-1.826-2.647-3.087-.147-.34-.393-.6-.727-.76a1.36 1.36 0 0 0-1.073-.058c-.37.133-.64.397-.8.754a1.351 1.351 0 0 0-.016 1.114Zm4.553-8.37a1.36 1.36 0 0 0-.858-.396A7.552 7.552 0 0 1 8.46 5.62c1.062-.613 2.237-.921 3.537-.921 1.489 0 2.816.398 3.997 1.19 1.19.8 2.07 1.827 2.646 3.088.148.34.394.6.728.76a1.37 1.37 0 0 0 1.068.063c.347-.12.62-.346.799-.668.187-.338.215-.71.072-1.072l-.003-.007-.003-.007c-.784-1.818-2.006-3.298-3.658-4.434C15.982 2.47 14.094 1.9 11.998 1.9c-1.695 0-3.261.385-4.688 1.16a10.536 10.536 0 0 0-2.715 2.096 1.364 1.364 0 0 0-.308-.453 1.38 1.38 0 0 0-.994-.403c-.38 0-.722.135-.992.406s-.403.614-.403.994v3c0 .38.135.724.406.995.27.27.614.405.994.405h3c.384 0 .727-.137.998-.412a1.38 1.38 0 0 0 .402-.993c0-.38-.135-.723-.406-.992ZM9.52 14.48a3.393 3.393 0 0 0 2.478 1.02c.965 0 1.8-.342 2.479-1.02a3.392 3.392 0 0 0 1.021-2.48c0-.963-.343-1.8-1.021-2.478A3.392 3.392 0 0 0 11.998 8.5c-.964 0-1.8.343-2.478 1.021A3.392 3.392 0 0 0 8.498 12c0 .964.344 1.8 1.022 2.479Z\"/></svg>') 12 12,auto}.unreal-container.pan{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.997 10.075a1.01 1.01 0 0 1-.738-.313 1.008 1.008 0 0 1-.312-.737V6.15l-.95.95a.998.998 0 0 1-.763.312 1.09 1.09 0 0 1-.763-.337 1.06 1.06 0 0 1-.324-.775c0-.3.108-.558.324-.775l2.776-2.775c.117-.116.237-.2.362-.25a1.04 1.04 0 0 1 .775 0c.125.05.246.134.363.25l2.8 2.8c.216.217.32.47.313.762a1.096 1.096 0 0 1-.338.763 1.058 1.058 0 0 1-.775.325c-.3 0-.558-.108-.775-.325l-.925-.925v2.875c0 .283-.104.53-.312.737a1.01 1.01 0 0 1-.738.313Zm0 11.5a1.04 1.04 0 0 1-.388-.075 1.103 1.103 0 0 1-.362-.25l-2.8-2.8a1.002 1.002 0 0 1-.313-.762c.009-.292.121-.546.337-.763.217-.217.475-.325.775-.325.3 0 .559.108.775.325l.926.925v-2.875c0-.283.104-.529.312-.737a1.01 1.01 0 0 1 .738-.313c.283 0 .529.104.738.313.208.208.312.454.312.737v2.875l.95-.95a.998.998 0 0 1 .762-.312c.292.008.546.12.763.337.216.217.324.475.324.775 0 .3-.108.559-.324.775l-2.775 2.775c-.117.116-.238.2-.363.25a1.04 1.04 0 0 1-.387.075Zm4.925-6.05a1.058 1.058 0 0 1-.326-.774c0-.3.109-.559.326-.776l.925-.925H14.97c-.283 0-.528-.104-.736-.312a1.01 1.01 0 0 1-.313-.738c0-.283.104-.53.313-.738.208-.208.453-.312.737-.312h2.875l-.95-.95a.998.998 0 0 1-.313-.762 1.09 1.09 0 0 1 .338-.764 1.06 1.06 0 0 1 .775-.324c.3 0 .558.108.775.324l2.774 2.776c.117.117.2.238.251.363a1.04 1.04 0 0 1 0 .775c-.05.124-.134.245-.25.362l-2.8 2.8c-.217.216-.471.32-.762.313a1.096 1.096 0 0 1-.763-.337Zm-11.4 0L2.746 12.75a1.103 1.103 0 0 1-.25-.362 1.04 1.04 0 0 1 0-.775c.05-.125.133-.246.25-.363l2.8-2.8c.216-.216.47-.32.762-.313.292.01.546.121.763.337.217.217.325.476.325.776 0 .3-.108.558-.325.775l-.925.925h2.875c.283 0 .529.104.737.312.208.209.313.455.313.738s-.105.53-.313.738a1.008 1.008 0 0 1-.737.312H6.147l.95.95c.217.217.32.471.312.762a1.09 1.09 0 0 1-.337.764 1.06 1.06 0 0 1-.775.324c-.3 0-.559-.108-.776-.324Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M9.22 7.912c.436.013.821-.15 1.13-.458l.097-.097v1.668c0 .422.16.793.458 1.09.298.299.67.46 1.092.46.422 0 .793-.161 1.091-.46.298-.297.459-.668.459-1.09V7.357l.071.072c.309.308.693.471 1.13.471.435 0 .82-.163 1.128-.471.301-.303.47-.676.483-1.102v-.001a1.501 1.501 0 0 0-.46-1.13l-2.799-2.8a1.6 1.6 0 0 0-.528-.36l-.003-.001a1.54 1.54 0 0 0-1.145 0l-.002.001a1.6 1.6 0 0 0-.529.36L8.118 5.172l-.001.001a1.56 1.56 0 0 0-.47 1.128c0 .435.163.82.47 1.128.303.303.676.472 1.103.484Zm0 0 .014-.5-.015.5Zm-1.311 6.865a1.497 1.497 0 0 0-.458-1.13l-.097-.097h1.668c.421 0 .793-.16 1.09-.458.298-.299.46-.67.46-1.092a1.51 1.51 0 0 0-.46-1.091 1.507 1.507 0 0 0-1.09-.459H7.354l.071-.072c.309-.308.472-.692.472-1.128 0-.436-.163-.82-.472-1.13a1.596 1.596 0 0 0-1.101-.482h-.002a1.501 1.501 0 0 0-1.129.459l-2.8 2.8a1.6 1.6 0 0 0-.36.528l-.001.003a1.54 1.54 0 0 0 0 1.144v.003c.081.2.208.375.362.529l2.774 2.775c.309.308.693.47 1.129.47.435 0 .82-.162 1.128-.47.303-.302.472-.676.484-1.102Zm0 0-.5-.014.5.015v-.001Zm3.038-8.627-.5.5.5.207V6.15Zm.475 15.814.002.001a1.54 1.54 0 0 0 1.145 0h.002c.2-.081.375-.208.53-.362l2.775-2.774a1.56 1.56 0 0 0 .47-1.129c0-.435-.162-.82-.47-1.128a1.589 1.589 0 0 0-1.103-.484 1.497 1.497 0 0 0-1.13.458l-.096.097v-1.668c0-.421-.161-.793-.459-1.09a1.509 1.509 0 0 0-1.091-.46c-.422 0-.794.161-1.092.46a1.507 1.507 0 0 0-.458 1.09v1.668l-.072-.072a1.558 1.558 0 0 0-1.129-.471c-.436 0-.82.163-1.128.471l-.001.001c-.301.302-.47.675-.483 1.101v.001c-.012.437.151.821.46 1.13l2.8 2.8c.153.153.328.28.528.36Zm5.146-6.085c.303.302.676.47 1.102.484a1.5 1.5 0 0 0 1.13-.46l2.8-2.8a1.6 1.6 0 0 0 .36-.528l.002-.003a1.54 1.54 0 0 0 0-1.144l-.001-.003a1.6 1.6 0 0 0-.361-.529l-2.774-2.775h-.001a1.56 1.56 0 0 0-1.128-.47c-.436 0-.82.162-1.128.47h-.001a1.59 1.59 0 0 0-.484 1.102c-.012.437.15.822.459 1.13l.097.097h-1.668c-.422 0-.793.16-1.09.459-.299.298-.46.67-.46 1.091 0 .422.161.793.46 1.092.297.297.668.458 1.09.458h1.668l-.072.072a1.558 1.558 0 0 0-.472 1.129c0 .435.164.82.472 1.128ZM6.147 13.05l.5.5.207-.5h-.707Z\"/></svg>') 12 12,auto}.unreal-container.dolly{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><mask id=\"a\" width=\"24\" height=\"24\" x=\"0\" y=\"0\" maskUnits=\"userSpaceOnUse\" style=\"mask-type:alpha\"><path fill=\"%23127392\" d=\"M0 0h24v24H0z\"/></mask><g mask=\"url(%23a)\"><path fill=\"%23000\" d=\"M12.002 20.575a1.026 1.026 0 0 1-.75-.325l-2.55-2.55a.933.933 0 0 1-.287-.713c.008-.275.113-.513.313-.713.2-.2.441-.3.725-.3.283 0 .524.1.724.3l.776.776V6.95l-.8.8c-.2.2-.438.296-.712.288a1.018 1.018 0 0 1-.713-.312c-.2-.2-.3-.442-.3-.726s.1-.525.3-.725l2.524-2.525a1.026 1.026 0 0 1 1.5 0l2.55 2.55c.2.2.296.438.289.713a1.023 1.023 0 0 1-.314.713c-.2.2-.441.3-.724.3a.988.988 0 0 1-.725-.3l-.775-.776v10.1l.8-.8c.2-.2.437-.296.712-.288.275.008.512.112.712.312.2.2.3.442.3.726s-.1.525-.3.725l-2.524 2.525a1.026 1.026 0 0 1-.75.325Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M13.553 8.153c.28.245.62.373 1 .373.415 0 .784-.153 1.078-.447.287-.287.446-.644.46-1.05v-.002a1.432 1.432 0 0 0-.435-1.08l-2.55-2.55-.354.353.354-.354a1.526 1.526 0 0 0-2.207 0L8.374 5.921A1.487 1.487 0 0 0 7.928 7c0 .416.152.785.446 1.08.288.287.645.446 1.052.457l4.127-.384Zm0 0v7.693m0-7.693a1.667 1.667 0 0 1-.079-.074l-3.021.075v7.693a1.482 1.482 0 0 0-1-.373c-.416 0-.785.153-1.079.447a1.522 1.522 0 0 0-.46 1.05v.002c-.011.417.14.786.435 1.08l2.55 2.55a1.527 1.527 0 0 0 2.207 0l2.525-2.524c.294-.294.446-.663.446-1.079 0-.416-.152-.785-.446-1.08a1.518 1.518 0 0 0-1.052-.457m0 0-.014.5.014-.5Zm0 0a1.424 1.424 0 0 0-1.027.383m0 0a1.583 1.583 0 0 0-.053.05l.354.354m-.3-.404v.104l.3.3m0 0-.3-.3v.6l.3-.3Z\"/></g></svg>%0A') 12 12,auto}.unreal-container.disabled:before{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}#playerUI{position:absolute;z-index:10;width:100%}#statsContainer{display:none;text-align:left;background-color:#000c}#stats{padding:6px;font-weight:700;font-size:14px;color:#0f0}canvas{position:absolute;image-rendering:crisp-edges}#overlay{position:absolute;top:0;right:2%;z-index:100;padding:4px;border-top-width:0;-webkit-border-bottom-right-radius:5px;-moz-border-radius-bottomright:5px;border-bottom-right-radius:5px;-webkit-border-bottom-left-radius:5px;-moz-border-radius-bottomleft:5px;border-bottom-left-radius:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none}.overlay{font-weight:lighter;font-family:var(--src-font-family-body, system-ui, sans-serif)}#overlayButton:hover{cursor:pointer}#overlayButton{font-size:40px;text-align:right}#overlaySettings{display:none;width:300px;padding:4px}#videoMessageOverlay{position:absolute;z-index:20;width:100%;margin:auto;font-size:1.8em;font-family:var(--src-font-family-body, system-ui, sans-serif)}#playButton{display:inline-block;height:auto}img#playButton{width:10%;max-width:241px}#UIInteraction{position:fixed}#UIInteractionButtonBoundary{padding:2px}#UIInteractionButton{cursor:pointer}#hiddenInput{position:absolute;left:-10%;width:0;opacity:0}#editTextButton{position:absolute;width:40px;height:40px}\n"], dependencies: [{ kind: "component", type: AfkTimeoutModalComponent, selector: "app-afk-timeout-modal", inputs: ["uiClasses", "contentTemplate"] }, { kind: "component", type: UnrealStatusComponent, selector: "app-unreal-status", inputs: ["uiClasses", "contentTemplate"] }, { kind: "component", type: FreezeFrameComponent, selector: "app-freeze-frame" }, { kind: "component", type: VideoStatsComponent, selector: "app-video-stats" }, { kind: "component", type: ResumeStreamButtonComponent, selector: "app-resume-stream-button", inputs: ["uiClasses", "contentTemplate"] }, { kind: "component", type: ImageLoadingSrcComponent, selector: "app-image-loading-src" }, { kind: "component", type: IntroSrcComponent, selector: "app-intro-src" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
8070
8344
  }
8071
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: UnrealSceneComponent, decorators: [{
8345
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: UnrealSceneComponent, decorators: [{
8072
8346
  type: Component,
8073
8347
  args: [{ selector: 'app-unreal-scene', changeDetection: ChangeDetectionStrategy.OnPush, imports: [
8074
8348
  AfkTimeoutModalComponent,
@@ -8078,8 +8352,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
8078
8352
  ResumeStreamButtonComponent,
8079
8353
  ImageLoadingSrcComponent,
8080
8354
  IntroSrcComponent,
8081
- ], template: "<div class=\"frame unreal-container\">\r\n <div #videoContainer id=\"player\"></div>\r\n\r\n <app-intro-src />\r\n <app-image-loading-src />\r\n <app-resume-stream-button />\r\n <app-unreal-status />\r\n <app-freeze-frame />\r\n <app-afk-timeout-modal />\r\n\r\n <ng-content select=\"app-pdf\"></ng-content>\r\n <ng-content select=\"app-show-case\"></ng-content>\r\n\r\n @if (isDevMode) {\r\n <app-video-stats />\r\n }\r\n</div>\r\n", styles: [".unreal-container{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#fff}.unreal-container #player{position:absolute;width:100%;height:100%;display:flex;justify-content:center;align-items:center;overflow:hidden}.unreal-container.select{cursor:url('data:image/svg+xml,<svg width=\"24\" height=\"24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M15.15 21.375a1.423 1.423 0 0 1-1.15.063 1.487 1.487 0 0 1-.85-.788l-3-6.45-2.325 3.25c-.283.4-.658.525-1.125.375-.467-.15-.7-.466-.7-.95V4.05c0-.417.188-.717.563-.9.375-.183.729-.142 1.062.125l10.1 7.95c.383.284.496.65.337 1.1-.158.45-.479.675-.962.675h-4.2l2.975 6.375c.183.384.204.767.063 1.15a1.487 1.487 0 0 1-.788.85Z\" fill=\"%23000\"/><path d=\"m12.697 20.861.002.005c.237.495.617.852 1.128 1.04.515.191 1.039.16 1.539-.08a1.987 1.987 0 0 0 1.04-1.128 1.922 1.922 0 0 0-.079-1.536v-.003L13.684 13.5H17.1c.32 0 .628-.075.89-.26.263-.184.438-.447.544-.749.106-.3.135-.617.04-.925a1.458 1.458 0 0 0-.545-.738L7.936 2.883a1.51 1.51 0 0 0-.768-.336 1.471 1.471 0 0 0-.825.154 1.495 1.495 0 0 0-.626.547 1.492 1.492 0 0 0-.217.802v12.825c0 .324.08.634.272.897.193.261.467.43.775.53.31.099.632.12.942.016.31-.103.555-.313.743-.578h.001l1.825-2.552 2.639 5.673Z\" stroke=\"%23fff\" stroke-opacity=\".7\"/></svg>') 6 2,auto}.unreal-container.orbit{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.998 21.6c-1.966 0-3.737-.53-5.312-1.588-1.575-1.058-2.738-2.437-3.488-4.137a.852.852 0 0 1 .013-.713.867.867 0 0 1 .512-.487.86.86 0 0 1 .688.037c.225.109.387.28.487.513.617 1.35 1.559 2.45 2.825 3.3 1.267.85 2.692 1.275 4.275 1.275 1.384 0 2.646-.33 3.788-.988a7.985 7.985 0 0 0 2.762-2.612h-.85a.873.873 0 0 1-.64-.257.863.863 0 0 1-.26-.638.88.88 0 0 1 .26-.643.864.864 0 0 1 .64-.262h3c.255 0 .47.086.642.259a.87.87 0 0 1 .258.64v3a.874.874 0 0 1-.257.642.863.863 0 0 1-.637.259.88.88 0 0 1-.643-.259.865.865 0 0 1-.263-.641v-.725a9.95 9.95 0 0 1-3.35 2.925c-1.35.733-2.833 1.1-4.45 1.1Zm0-17.4c-1.383 0-2.645.33-3.787.987A7.985 7.985 0 0 0 5.448 7.8h.85c.255 0 .47.086.642.257a.863.863 0 0 1 .258.638.88.88 0 0 1-.258.642.864.864 0 0 1-.642.263h-3a.87.87 0 0 1-.64-.259.87.87 0 0 1-.26-.641v-3c0-.255.086-.469.258-.641a.863.863 0 0 1 .637-.26.88.88 0 0 1 .643.26.864.864 0 0 1 .262.64v.726A9.95 9.95 0 0 1 7.548 3.5c1.35-.733 2.834-1.1 4.45-1.1 2 0 3.788.542 5.363 1.625 1.575 1.083 2.736 2.49 3.482 4.22a.724.724 0 0 1-.045.646.926.926 0 0 1-.525.437.87.87 0 0 1-.687-.04.977.977 0 0 1-.488-.513c-.616-1.35-1.558-2.45-2.825-3.3-1.266-.85-2.691-1.275-4.275-1.275Zm0 10.8a2.893 2.893 0 0 1-2.125-.875A2.893 2.893 0 0 1 8.998 12c0-.833.292-1.542.875-2.125A2.893 2.893 0 0 1 11.998 9c.834 0 1.542.292 2.125.875.584.583.875 1.292.875 2.125s-.291 1.542-.875 2.125a2.893 2.893 0 0 1-2.125.875Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"m2.739 16.072.002.005c.789 1.788 2.014 3.24 3.666 4.35 1.66 1.116 3.53 1.673 5.591 1.673 1.696 0 3.262-.386 4.69-1.16a10.54 10.54 0 0 0 2.714-2.097c.069.167.171.32.308.454.272.268.613.403.994.403.38 0 .722-.135.992-.406s.402-.614.402-.994v-3c0-.381-.134-.724-.405-.995a1.37 1.37 0 0 0-.995-.405h-3c-.383 0-.727.137-.997.411a1.38 1.38 0 0 0-.403.994c0 .38.135.723.407.992.238.237.532.369.858.397a7.552 7.552 0 0 1-2.027 1.685c-1.062.613-2.237.92-3.538.92-1.488 0-2.815-.397-3.996-1.19-1.19-.798-2.07-1.826-2.647-3.087-.147-.34-.393-.6-.727-.76a1.36 1.36 0 0 0-1.073-.058c-.37.133-.64.397-.8.754a1.351 1.351 0 0 0-.016 1.114Zm4.553-8.37a1.36 1.36 0 0 0-.858-.396A7.552 7.552 0 0 1 8.46 5.62c1.062-.613 2.237-.921 3.537-.921 1.489 0 2.816.398 3.997 1.19 1.19.8 2.07 1.827 2.646 3.088.148.34.394.6.728.76a1.37 1.37 0 0 0 1.068.063c.347-.12.62-.346.799-.668.187-.338.215-.71.072-1.072l-.003-.007-.003-.007c-.784-1.818-2.006-3.298-3.658-4.434C15.982 2.47 14.094 1.9 11.998 1.9c-1.695 0-3.261.385-4.688 1.16a10.536 10.536 0 0 0-2.715 2.096 1.364 1.364 0 0 0-.308-.453 1.38 1.38 0 0 0-.994-.403c-.38 0-.722.135-.992.406s-.403.614-.403.994v3c0 .38.135.724.406.995.27.27.614.405.994.405h3c.384 0 .727-.137.998-.412a1.38 1.38 0 0 0 .402-.993c0-.38-.135-.723-.406-.992ZM9.52 14.48a3.393 3.393 0 0 0 2.478 1.02c.965 0 1.8-.342 2.479-1.02a3.392 3.392 0 0 0 1.021-2.48c0-.963-.343-1.8-1.021-2.478A3.392 3.392 0 0 0 11.998 8.5c-.964 0-1.8.343-2.478 1.021A3.392 3.392 0 0 0 8.498 12c0 .964.344 1.8 1.022 2.479Z\"/></svg>') 12 12,auto}.unreal-container.pan{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.997 10.075a1.01 1.01 0 0 1-.738-.313 1.008 1.008 0 0 1-.312-.737V6.15l-.95.95a.998.998 0 0 1-.763.312 1.09 1.09 0 0 1-.763-.337 1.06 1.06 0 0 1-.324-.775c0-.3.108-.558.324-.775l2.776-2.775c.117-.116.237-.2.362-.25a1.04 1.04 0 0 1 .775 0c.125.05.246.134.363.25l2.8 2.8c.216.217.32.47.313.762a1.096 1.096 0 0 1-.338.763 1.058 1.058 0 0 1-.775.325c-.3 0-.558-.108-.775-.325l-.925-.925v2.875c0 .283-.104.53-.312.737a1.01 1.01 0 0 1-.738.313Zm0 11.5a1.04 1.04 0 0 1-.388-.075 1.103 1.103 0 0 1-.362-.25l-2.8-2.8a1.002 1.002 0 0 1-.313-.762c.009-.292.121-.546.337-.763.217-.217.475-.325.775-.325.3 0 .559.108.775.325l.926.925v-2.875c0-.283.104-.529.312-.737a1.01 1.01 0 0 1 .738-.313c.283 0 .529.104.738.313.208.208.312.454.312.737v2.875l.95-.95a.998.998 0 0 1 .762-.312c.292.008.546.12.763.337.216.217.324.475.324.775 0 .3-.108.559-.324.775l-2.775 2.775c-.117.116-.238.2-.363.25a1.04 1.04 0 0 1-.387.075Zm4.925-6.05a1.058 1.058 0 0 1-.326-.774c0-.3.109-.559.326-.776l.925-.925H14.97c-.283 0-.528-.104-.736-.312a1.01 1.01 0 0 1-.313-.738c0-.283.104-.53.313-.738.208-.208.453-.312.737-.312h2.875l-.95-.95a.998.998 0 0 1-.313-.762 1.09 1.09 0 0 1 .338-.764 1.06 1.06 0 0 1 .775-.324c.3 0 .558.108.775.324l2.774 2.776c.117.117.2.238.251.363a1.04 1.04 0 0 1 0 .775c-.05.124-.134.245-.25.362l-2.8 2.8c-.217.216-.471.32-.762.313a1.096 1.096 0 0 1-.763-.337Zm-11.4 0L2.746 12.75a1.103 1.103 0 0 1-.25-.362 1.04 1.04 0 0 1 0-.775c.05-.125.133-.246.25-.363l2.8-2.8c.216-.216.47-.32.762-.313.292.01.546.121.763.337.217.217.325.476.325.776 0 .3-.108.558-.325.775l-.925.925h2.875c.283 0 .529.104.737.312.208.209.313.455.313.738s-.105.53-.313.738a1.008 1.008 0 0 1-.737.312H6.147l.95.95c.217.217.32.471.312.762a1.09 1.09 0 0 1-.337.764 1.06 1.06 0 0 1-.775.324c-.3 0-.559-.108-.776-.324Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M9.22 7.912c.436.013.821-.15 1.13-.458l.097-.097v1.668c0 .422.16.793.458 1.09.298.299.67.46 1.092.46.422 0 .793-.161 1.091-.46.298-.297.459-.668.459-1.09V7.357l.071.072c.309.308.693.471 1.13.471.435 0 .82-.163 1.128-.471.301-.303.47-.676.483-1.102v-.001a1.501 1.501 0 0 0-.46-1.13l-2.799-2.8a1.6 1.6 0 0 0-.528-.36l-.003-.001a1.54 1.54 0 0 0-1.145 0l-.002.001a1.6 1.6 0 0 0-.529.36L8.118 5.172l-.001.001a1.56 1.56 0 0 0-.47 1.128c0 .435.163.82.47 1.128.303.303.676.472 1.103.484Zm0 0 .014-.5-.015.5Zm-1.311 6.865a1.497 1.497 0 0 0-.458-1.13l-.097-.097h1.668c.421 0 .793-.16 1.09-.458.298-.299.46-.67.46-1.092a1.51 1.51 0 0 0-.46-1.091 1.507 1.507 0 0 0-1.09-.459H7.354l.071-.072c.309-.308.472-.692.472-1.128 0-.436-.163-.82-.472-1.13a1.596 1.596 0 0 0-1.101-.482h-.002a1.501 1.501 0 0 0-1.129.459l-2.8 2.8a1.6 1.6 0 0 0-.36.528l-.001.003a1.54 1.54 0 0 0 0 1.144v.003c.081.2.208.375.362.529l2.774 2.775c.309.308.693.47 1.129.47.435 0 .82-.162 1.128-.47.303-.302.472-.676.484-1.102Zm0 0-.5-.014.5.015v-.001Zm3.038-8.627-.5.5.5.207V6.15Zm.475 15.814.002.001a1.54 1.54 0 0 0 1.145 0h.002c.2-.081.375-.208.53-.362l2.775-2.774a1.56 1.56 0 0 0 .47-1.129c0-.435-.162-.82-.47-1.128a1.589 1.589 0 0 0-1.103-.484 1.497 1.497 0 0 0-1.13.458l-.096.097v-1.668c0-.421-.161-.793-.459-1.09a1.509 1.509 0 0 0-1.091-.46c-.422 0-.794.161-1.092.46a1.507 1.507 0 0 0-.458 1.09v1.668l-.072-.072a1.558 1.558 0 0 0-1.129-.471c-.436 0-.82.163-1.128.471l-.001.001c-.301.302-.47.675-.483 1.101v.001c-.012.437.151.821.46 1.13l2.8 2.8c.153.153.328.28.528.36Zm5.146-6.085c.303.302.676.47 1.102.484a1.5 1.5 0 0 0 1.13-.46l2.8-2.8a1.6 1.6 0 0 0 .36-.528l.002-.003a1.54 1.54 0 0 0 0-1.144l-.001-.003a1.6 1.6 0 0 0-.361-.529l-2.774-2.775h-.001a1.56 1.56 0 0 0-1.128-.47c-.436 0-.82.162-1.128.47h-.001a1.59 1.59 0 0 0-.484 1.102c-.012.437.15.822.459 1.13l.097.097h-1.668c-.422 0-.793.16-1.09.459-.299.298-.46.67-.46 1.091 0 .422.161.793.46 1.092.297.297.668.458 1.09.458h1.668l-.072.072a1.558 1.558 0 0 0-.472 1.129c0 .435.164.82.472 1.128ZM6.147 13.05l.5.5.207-.5h-.707Z\"/></svg>') 12 12,auto}.unreal-container.dolly{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><mask id=\"a\" width=\"24\" height=\"24\" x=\"0\" y=\"0\" maskUnits=\"userSpaceOnUse\" style=\"mask-type:alpha\"><path fill=\"%23127392\" d=\"M0 0h24v24H0z\"/></mask><g mask=\"url(%23a)\"><path fill=\"%23000\" d=\"M12.002 20.575a1.026 1.026 0 0 1-.75-.325l-2.55-2.55a.933.933 0 0 1-.287-.713c.008-.275.113-.513.313-.713.2-.2.441-.3.725-.3.283 0 .524.1.724.3l.776.776V6.95l-.8.8c-.2.2-.438.296-.712.288a1.018 1.018 0 0 1-.713-.312c-.2-.2-.3-.442-.3-.726s.1-.525.3-.725l2.524-2.525a1.026 1.026 0 0 1 1.5 0l2.55 2.55c.2.2.296.438.289.713a1.023 1.023 0 0 1-.314.713c-.2.2-.441.3-.724.3a.988.988 0 0 1-.725-.3l-.775-.776v10.1l.8-.8c.2-.2.437-.296.712-.288.275.008.512.112.712.312.2.2.3.442.3.726s-.1.525-.3.725l-2.524 2.525a1.026 1.026 0 0 1-.75.325Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M13.553 8.153c.28.245.62.373 1 .373.415 0 .784-.153 1.078-.447.287-.287.446-.644.46-1.05v-.002a1.432 1.432 0 0 0-.435-1.08l-2.55-2.55-.354.353.354-.354a1.526 1.526 0 0 0-2.207 0L8.374 5.921A1.487 1.487 0 0 0 7.928 7c0 .416.152.785.446 1.08.288.287.645.446 1.052.457l4.127-.384Zm0 0v7.693m0-7.693a1.667 1.667 0 0 1-.079-.074l-3.021.075v7.693a1.482 1.482 0 0 0-1-.373c-.416 0-.785.153-1.079.447a1.522 1.522 0 0 0-.46 1.05v.002c-.011.417.14.786.435 1.08l2.55 2.55a1.527 1.527 0 0 0 2.207 0l2.525-2.524c.294-.294.446-.663.446-1.079 0-.416-.152-.785-.446-1.08a1.518 1.518 0 0 0-1.052-.457m0 0-.014.5.014-.5Zm0 0a1.424 1.424 0 0 0-1.027.383m0 0a1.583 1.583 0 0 0-.053.05l.354.354m-.3-.404v.104l.3.3m0 0-.3-.3v.6l.3-.3Z\"/></g></svg>%0D%0A') 12 12,auto}.unreal-container.disabled:before{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}#playerUI{position:absolute;z-index:10;width:100%}#statsContainer{display:none;text-align:left;background-color:#000c}#stats{padding:6px;font-weight:700;font-size:14px;color:#0f0}canvas{position:absolute;image-rendering:crisp-edges}#overlay{position:absolute;top:0;right:2%;z-index:100;padding:4px;border-top-width:0;-webkit-border-bottom-right-radius:5px;-moz-border-radius-bottomright:5px;border-bottom-right-radius:5px;-webkit-border-bottom-left-radius:5px;-moz-border-radius-bottomleft:5px;border-bottom-left-radius:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none}.overlay{font-weight:lighter;font-family:var(--src-font-family-body, system-ui, sans-serif)}#overlayButton:hover{cursor:pointer}#overlayButton{font-size:40px;text-align:right}#overlaySettings{display:none;width:300px;padding:4px}#videoMessageOverlay{position:absolute;z-index:20;width:100%;margin:auto;font-size:1.8em;font-family:var(--src-font-family-body, system-ui, sans-serif)}#playButton{display:inline-block;height:auto}img#playButton{width:10%;max-width:241px}#UIInteraction{position:fixed}#UIInteractionButtonBoundary{padding:2px}#UIInteractionButton{cursor:pointer}#hiddenInput{position:absolute;left:-10%;width:0;opacity:0}#editTextButton{position:absolute;width:40px;height:40px}\n"] }]
8082
- }], ctorParameters: () => [], propDecorators: { useContainerAsSizeProvider: [{ type: i0.Input, args: [{ isSignal: true, alias: "useContainerAsSizeProvider", required: false }] }], isStudio: [{ type: i0.Input, args: [{ isSignal: true, alias: "isStudio", required: false }] }], resolutionSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "resolutionSize", required: false }] }], changeMouseOverScene: [{ type: i0.Output, args: ["changeMouseOverScene"] }], videoElement: [{ type: i0.ViewChild, args: ['videoContainer', { isSignal: true }] }], onMouseOver: [{
8355
+ ], template: "<div class=\"frame unreal-container\">\n <div #videoContainer id=\"player\"></div>\n\n <app-intro-src />\n <app-image-loading-src />\n <app-freeze-frame />\n <app-resume-stream-button\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"resumeSlot()?.template ?? null\"\n />\n <app-unreal-status\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"statusSlot()?.template ?? null\"\n />\n <app-afk-timeout-modal\n [uiClasses]=\"uiClasses()\"\n [contentTemplate]=\"afkSlot()?.template ?? null\"\n />\n\n <ng-content select=\"app-pdf\"></ng-content>\n <ng-content select=\"app-show-case\"></ng-content>\n\n @if (isDevMode) {\n <app-video-stats />\n }\n</div>\n", styles: [".unreal-container{position:absolute;top:0;left:0;width:100%;height:100%;background-color:#fff}.unreal-container #player{position:absolute;width:100%;height:100%;display:flex;justify-content:center;align-items:center;overflow:hidden}.unreal-container.select{cursor:url('data:image/svg+xml,<svg width=\"24\" height=\"24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M15.15 21.375a1.423 1.423 0 0 1-1.15.063 1.487 1.487 0 0 1-.85-.788l-3-6.45-2.325 3.25c-.283.4-.658.525-1.125.375-.467-.15-.7-.466-.7-.95V4.05c0-.417.188-.717.563-.9.375-.183.729-.142 1.062.125l10.1 7.95c.383.284.496.65.337 1.1-.158.45-.479.675-.962.675h-4.2l2.975 6.375c.183.384.204.767.063 1.15a1.487 1.487 0 0 1-.788.85Z\" fill=\"%23000\"/><path d=\"m12.697 20.861.002.005c.237.495.617.852 1.128 1.04.515.191 1.039.16 1.539-.08a1.987 1.987 0 0 0 1.04-1.128 1.922 1.922 0 0 0-.079-1.536v-.003L13.684 13.5H17.1c.32 0 .628-.075.89-.26.263-.184.438-.447.544-.749.106-.3.135-.617.04-.925a1.458 1.458 0 0 0-.545-.738L7.936 2.883a1.51 1.51 0 0 0-.768-.336 1.471 1.471 0 0 0-.825.154 1.495 1.495 0 0 0-.626.547 1.492 1.492 0 0 0-.217.802v12.825c0 .324.08.634.272.897.193.261.467.43.775.53.31.099.632.12.942.016.31-.103.555-.313.743-.578h.001l1.825-2.552 2.639 5.673Z\" stroke=\"%23fff\" stroke-opacity=\".7\"/></svg>') 6 2,auto}.unreal-container.orbit{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.998 21.6c-1.966 0-3.737-.53-5.312-1.588-1.575-1.058-2.738-2.437-3.488-4.137a.852.852 0 0 1 .013-.713.867.867 0 0 1 .512-.487.86.86 0 0 1 .688.037c.225.109.387.28.487.513.617 1.35 1.559 2.45 2.825 3.3 1.267.85 2.692 1.275 4.275 1.275 1.384 0 2.646-.33 3.788-.988a7.985 7.985 0 0 0 2.762-2.612h-.85a.873.873 0 0 1-.64-.257.863.863 0 0 1-.26-.638.88.88 0 0 1 .26-.643.864.864 0 0 1 .64-.262h3c.255 0 .47.086.642.259a.87.87 0 0 1 .258.64v3a.874.874 0 0 1-.257.642.863.863 0 0 1-.637.259.88.88 0 0 1-.643-.259.865.865 0 0 1-.263-.641v-.725a9.95 9.95 0 0 1-3.35 2.925c-1.35.733-2.833 1.1-4.45 1.1Zm0-17.4c-1.383 0-2.645.33-3.787.987A7.985 7.985 0 0 0 5.448 7.8h.85c.255 0 .47.086.642.257a.863.863 0 0 1 .258.638.88.88 0 0 1-.258.642.864.864 0 0 1-.642.263h-3a.87.87 0 0 1-.64-.259.87.87 0 0 1-.26-.641v-3c0-.255.086-.469.258-.641a.863.863 0 0 1 .637-.26.88.88 0 0 1 .643.26.864.864 0 0 1 .262.64v.726A9.95 9.95 0 0 1 7.548 3.5c1.35-.733 2.834-1.1 4.45-1.1 2 0 3.788.542 5.363 1.625 1.575 1.083 2.736 2.49 3.482 4.22a.724.724 0 0 1-.045.646.926.926 0 0 1-.525.437.87.87 0 0 1-.687-.04.977.977 0 0 1-.488-.513c-.616-1.35-1.558-2.45-2.825-3.3-1.266-.85-2.691-1.275-4.275-1.275Zm0 10.8a2.893 2.893 0 0 1-2.125-.875A2.893 2.893 0 0 1 8.998 12c0-.833.292-1.542.875-2.125A2.893 2.893 0 0 1 11.998 9c.834 0 1.542.292 2.125.875.584.583.875 1.292.875 2.125s-.291 1.542-.875 2.125a2.893 2.893 0 0 1-2.125.875Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"m2.739 16.072.002.005c.789 1.788 2.014 3.24 3.666 4.35 1.66 1.116 3.53 1.673 5.591 1.673 1.696 0 3.262-.386 4.69-1.16a10.54 10.54 0 0 0 2.714-2.097c.069.167.171.32.308.454.272.268.613.403.994.403.38 0 .722-.135.992-.406s.402-.614.402-.994v-3c0-.381-.134-.724-.405-.995a1.37 1.37 0 0 0-.995-.405h-3c-.383 0-.727.137-.997.411a1.38 1.38 0 0 0-.403.994c0 .38.135.723.407.992.238.237.532.369.858.397a7.552 7.552 0 0 1-2.027 1.685c-1.062.613-2.237.92-3.538.92-1.488 0-2.815-.397-3.996-1.19-1.19-.798-2.07-1.826-2.647-3.087-.147-.34-.393-.6-.727-.76a1.36 1.36 0 0 0-1.073-.058c-.37.133-.64.397-.8.754a1.351 1.351 0 0 0-.016 1.114Zm4.553-8.37a1.36 1.36 0 0 0-.858-.396A7.552 7.552 0 0 1 8.46 5.62c1.062-.613 2.237-.921 3.537-.921 1.489 0 2.816.398 3.997 1.19 1.19.8 2.07 1.827 2.646 3.088.148.34.394.6.728.76a1.37 1.37 0 0 0 1.068.063c.347-.12.62-.346.799-.668.187-.338.215-.71.072-1.072l-.003-.007-.003-.007c-.784-1.818-2.006-3.298-3.658-4.434C15.982 2.47 14.094 1.9 11.998 1.9c-1.695 0-3.261.385-4.688 1.16a10.536 10.536 0 0 0-2.715 2.096 1.364 1.364 0 0 0-.308-.453 1.38 1.38 0 0 0-.994-.403c-.38 0-.722.135-.992.406s-.403.614-.403.994v3c0 .38.135.724.406.995.27.27.614.405.994.405h3c.384 0 .727-.137.998-.412a1.38 1.38 0 0 0 .402-.993c0-.38-.135-.723-.406-.992ZM9.52 14.48a3.393 3.393 0 0 0 2.478 1.02c.965 0 1.8-.342 2.479-1.02a3.392 3.392 0 0 0 1.021-2.48c0-.963-.343-1.8-1.021-2.478A3.392 3.392 0 0 0 11.998 8.5c-.964 0-1.8.343-2.478 1.021A3.392 3.392 0 0 0 8.498 12c0 .964.344 1.8 1.022 2.479Z\"/></svg>') 12 12,auto}.unreal-container.pan{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><path fill=\"%23000\" d=\"M11.997 10.075a1.01 1.01 0 0 1-.738-.313 1.008 1.008 0 0 1-.312-.737V6.15l-.95.95a.998.998 0 0 1-.763.312 1.09 1.09 0 0 1-.763-.337 1.06 1.06 0 0 1-.324-.775c0-.3.108-.558.324-.775l2.776-2.775c.117-.116.237-.2.362-.25a1.04 1.04 0 0 1 .775 0c.125.05.246.134.363.25l2.8 2.8c.216.217.32.47.313.762a1.096 1.096 0 0 1-.338.763 1.058 1.058 0 0 1-.775.325c-.3 0-.558-.108-.775-.325l-.925-.925v2.875c0 .283-.104.53-.312.737a1.01 1.01 0 0 1-.738.313Zm0 11.5a1.04 1.04 0 0 1-.388-.075 1.103 1.103 0 0 1-.362-.25l-2.8-2.8a1.002 1.002 0 0 1-.313-.762c.009-.292.121-.546.337-.763.217-.217.475-.325.775-.325.3 0 .559.108.775.325l.926.925v-2.875c0-.283.104-.529.312-.737a1.01 1.01 0 0 1 .738-.313c.283 0 .529.104.738.313.208.208.312.454.312.737v2.875l.95-.95a.998.998 0 0 1 .762-.312c.292.008.546.12.763.337.216.217.324.475.324.775 0 .3-.108.559-.324.775l-2.775 2.775c-.117.116-.238.2-.363.25a1.04 1.04 0 0 1-.387.075Zm4.925-6.05a1.058 1.058 0 0 1-.326-.774c0-.3.109-.559.326-.776l.925-.925H14.97c-.283 0-.528-.104-.736-.312a1.01 1.01 0 0 1-.313-.738c0-.283.104-.53.313-.738.208-.208.453-.312.737-.312h2.875l-.95-.95a.998.998 0 0 1-.313-.762 1.09 1.09 0 0 1 .338-.764 1.06 1.06 0 0 1 .775-.324c.3 0 .558.108.775.324l2.774 2.776c.117.117.2.238.251.363a1.04 1.04 0 0 1 0 .775c-.05.124-.134.245-.25.362l-2.8 2.8c-.217.216-.471.32-.762.313a1.096 1.096 0 0 1-.763-.337Zm-11.4 0L2.746 12.75a1.103 1.103 0 0 1-.25-.362 1.04 1.04 0 0 1 0-.775c.05-.125.133-.246.25-.363l2.8-2.8c.216-.216.47-.32.762-.313.292.01.546.121.763.337.217.217.325.476.325.776 0 .3-.108.558-.325.775l-.925.925h2.875c.283 0 .529.104.737.312.208.209.313.455.313.738s-.105.53-.313.738a1.008 1.008 0 0 1-.737.312H6.147l.95.95c.217.217.32.471.312.762a1.09 1.09 0 0 1-.337.764 1.06 1.06 0 0 1-.775.324c-.3 0-.559-.108-.776-.324Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M9.22 7.912c.436.013.821-.15 1.13-.458l.097-.097v1.668c0 .422.16.793.458 1.09.298.299.67.46 1.092.46.422 0 .793-.161 1.091-.46.298-.297.459-.668.459-1.09V7.357l.071.072c.309.308.693.471 1.13.471.435 0 .82-.163 1.128-.471.301-.303.47-.676.483-1.102v-.001a1.501 1.501 0 0 0-.46-1.13l-2.799-2.8a1.6 1.6 0 0 0-.528-.36l-.003-.001a1.54 1.54 0 0 0-1.145 0l-.002.001a1.6 1.6 0 0 0-.529.36L8.118 5.172l-.001.001a1.56 1.56 0 0 0-.47 1.128c0 .435.163.82.47 1.128.303.303.676.472 1.103.484Zm0 0 .014-.5-.015.5Zm-1.311 6.865a1.497 1.497 0 0 0-.458-1.13l-.097-.097h1.668c.421 0 .793-.16 1.09-.458.298-.299.46-.67.46-1.092a1.51 1.51 0 0 0-.46-1.091 1.507 1.507 0 0 0-1.09-.459H7.354l.071-.072c.309-.308.472-.692.472-1.128 0-.436-.163-.82-.472-1.13a1.596 1.596 0 0 0-1.101-.482h-.002a1.501 1.501 0 0 0-1.129.459l-2.8 2.8a1.6 1.6 0 0 0-.36.528l-.001.003a1.54 1.54 0 0 0 0 1.144v.003c.081.2.208.375.362.529l2.774 2.775c.309.308.693.47 1.129.47.435 0 .82-.162 1.128-.47.303-.302.472-.676.484-1.102Zm0 0-.5-.014.5.015v-.001Zm3.038-8.627-.5.5.5.207V6.15Zm.475 15.814.002.001a1.54 1.54 0 0 0 1.145 0h.002c.2-.081.375-.208.53-.362l2.775-2.774a1.56 1.56 0 0 0 .47-1.129c0-.435-.162-.82-.47-1.128a1.589 1.589 0 0 0-1.103-.484 1.497 1.497 0 0 0-1.13.458l-.096.097v-1.668c0-.421-.161-.793-.459-1.09a1.509 1.509 0 0 0-1.091-.46c-.422 0-.794.161-1.092.46a1.507 1.507 0 0 0-.458 1.09v1.668l-.072-.072a1.558 1.558 0 0 0-1.129-.471c-.436 0-.82.163-1.128.471l-.001.001c-.301.302-.47.675-.483 1.101v.001c-.012.437.151.821.46 1.13l2.8 2.8c.153.153.328.28.528.36Zm5.146-6.085c.303.302.676.47 1.102.484a1.5 1.5 0 0 0 1.13-.46l2.8-2.8a1.6 1.6 0 0 0 .36-.528l.002-.003a1.54 1.54 0 0 0 0-1.144l-.001-.003a1.6 1.6 0 0 0-.361-.529l-2.774-2.775h-.001a1.56 1.56 0 0 0-1.128-.47c-.436 0-.82.162-1.128.47h-.001a1.59 1.59 0 0 0-.484 1.102c-.012.437.15.822.459 1.13l.097.097h-1.668c-.422 0-.793.16-1.09.459-.299.298-.46.67-.46 1.091 0 .422.161.793.46 1.092.297.297.668.458 1.09.458h1.668l-.072.072a1.558 1.558 0 0 0-.472 1.129c0 .435.164.82.472 1.128ZM6.147 13.05l.5.5.207-.5h-.707Z\"/></svg>') 12 12,auto}.unreal-container.dolly{cursor:url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" fill=\"none\"><mask id=\"a\" width=\"24\" height=\"24\" x=\"0\" y=\"0\" maskUnits=\"userSpaceOnUse\" style=\"mask-type:alpha\"><path fill=\"%23127392\" d=\"M0 0h24v24H0z\"/></mask><g mask=\"url(%23a)\"><path fill=\"%23000\" d=\"M12.002 20.575a1.026 1.026 0 0 1-.75-.325l-2.55-2.55a.933.933 0 0 1-.287-.713c.008-.275.113-.513.313-.713.2-.2.441-.3.725-.3.283 0 .524.1.724.3l.776.776V6.95l-.8.8c-.2.2-.438.296-.712.288a1.018 1.018 0 0 1-.713-.312c-.2-.2-.3-.442-.3-.726s.1-.525.3-.725l2.524-2.525a1.026 1.026 0 0 1 1.5 0l2.55 2.55c.2.2.296.438.289.713a1.023 1.023 0 0 1-.314.713c-.2.2-.441.3-.724.3a.988.988 0 0 1-.725-.3l-.775-.776v10.1l.8-.8c.2-.2.437-.296.712-.288.275.008.512.112.712.312.2.2.3.442.3.726s-.1.525-.3.725l-2.524 2.525a1.026 1.026 0 0 1-.75.325Z\"/><path stroke=\"%23fff\" stroke-opacity=\".7\" d=\"M13.553 8.153c.28.245.62.373 1 .373.415 0 .784-.153 1.078-.447.287-.287.446-.644.46-1.05v-.002a1.432 1.432 0 0 0-.435-1.08l-2.55-2.55-.354.353.354-.354a1.526 1.526 0 0 0-2.207 0L8.374 5.921A1.487 1.487 0 0 0 7.928 7c0 .416.152.785.446 1.08.288.287.645.446 1.052.457l4.127-.384Zm0 0v7.693m0-7.693a1.667 1.667 0 0 1-.079-.074l-3.021.075v7.693a1.482 1.482 0 0 0-1-.373c-.416 0-.785.153-1.079.447a1.522 1.522 0 0 0-.46 1.05v.002c-.011.417.14.786.435 1.08l2.55 2.55a1.527 1.527 0 0 0 2.207 0l2.525-2.524c.294-.294.446-.663.446-1.079 0-.416-.152-.785-.446-1.08a1.518 1.518 0 0 0-1.052-.457m0 0-.014.5.014-.5Zm0 0a1.424 1.424 0 0 0-1.027.383m0 0a1.583 1.583 0 0 0-.053.05l.354.354m-.3-.404v.104l.3.3m0 0-.3-.3v.6l.3-.3Z\"/></g></svg>%0A') 12 12,auto}.unreal-container.disabled:before{content:\"\";position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}#playerUI{position:absolute;z-index:10;width:100%}#statsContainer{display:none;text-align:left;background-color:#000c}#stats{padding:6px;font-weight:700;font-size:14px;color:#0f0}canvas{position:absolute;image-rendering:crisp-edges}#overlay{position:absolute;top:0;right:2%;z-index:100;padding:4px;border-top-width:0;-webkit-border-bottom-right-radius:5px;-moz-border-radius-bottomright:5px;border-bottom-right-radius:5px;-webkit-border-bottom-left-radius:5px;-moz-border-radius-bottomleft:5px;border-bottom-left-radius:5px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-touch-callout:none}.overlay{font-weight:lighter;font-family:var(--src-font-family-body, system-ui, sans-serif)}#overlayButton:hover{cursor:pointer}#overlayButton{font-size:40px;text-align:right}#overlaySettings{display:none;width:300px;padding:4px}#videoMessageOverlay{position:absolute;z-index:20;width:100%;margin:auto;font-size:1.8em;font-family:var(--src-font-family-body, system-ui, sans-serif)}#playButton{display:inline-block;height:auto}img#playButton{width:10%;max-width:241px}#UIInteraction{position:fixed}#UIInteractionButtonBoundary{padding:2px}#UIInteractionButton{cursor:pointer}#hiddenInput{position:absolute;left:-10%;width:0;opacity:0}#editTextButton{position:absolute;width:40px;height:40px}\n"] }]
8356
+ }], ctorParameters: () => [], propDecorators: { useContainerAsSizeProvider: [{ type: i0.Input, args: [{ isSignal: true, alias: "useContainerAsSizeProvider", required: false }] }], isStudio: [{ type: i0.Input, args: [{ isSignal: true, alias: "isStudio", required: false }] }], resolutionSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "resolutionSize", required: false }] }], changeMouseOverScene: [{ type: i0.Output, args: ["changeMouseOverScene"] }], uiClasses: [{ type: i0.Input, args: [{ isSignal: true, alias: "uiClasses", required: false }] }], resumeSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => UnrealResumeSlotDirective), { isSignal: true }] }], afkSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => UnrealAfkSlotDirective), { isSignal: true }] }], statusSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => UnrealStatusSlotDirective), { isSignal: true }] }], videoElement: [{ type: i0.ViewChild, args: ['videoContainer', { isSignal: true }] }], onMouseOver: [{
8083
8357
  type: HostListener,
8084
8358
  args: ['mouseover']
8085
8359
  }], onMouseOut: [{
@@ -8138,5 +8412,5 @@ function provideUnrealModule() {
8138
8412
  * Generated bundle index. Do not edit.
8139
8413
  */
8140
8414
 
8141
- 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, DESTROY_DISCONNECT_REASONS, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, INSTANCE_READY_TIMEOUT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, LatencyTimings, LoadingProgressService, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, 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, isMetaboxMode, 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, startStream, streamAdopted, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
8415
+ 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, DESTROY_DISCONNECT_REASONS, DevModeService, DisconnectReason, FULL_HD_HEIGHT, FULL_HD_WIDTH, FileHandlerService, FileReceiverService, FpsMonitorService, FreezeFrameComponent, FreezeFrameService, INNER_RETRY_LIMIT, INSTANCE_READY_TIMEOUT, IceCandidateHandler, ImageLoadingSrcComponent, InputOptions, InputService, InstanceReadyHandler, InstanceReservedHandler, IntroSrcComponent, LatencyTimings, LoadingProgressService, MINIMAL_FPS, MIN_CONTAINER_SIZE, MessageType, MouseButton, MouseButtonsMask, OUTER_RETRY_DELAY, OnCloseHandler, OnErrorHandler, OnMessageHandler, OnOpenHandler, OrchestrationMessageTypes, POLLING_TIME, 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, UnrealAfkSlotDirective, UnrealCallbackService, UnrealCommunicatorService, UnrealEffects, UnrealResumeSlotDirective, UnrealSceneComponent, UnrealStatusMessage, UnrealStatusSlotDirective, 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, isMetaboxMode, keepMaxUntilReset, makeEven, pollingEnded, pollingStarted, provideUnrealModule, provideUnrealState, qpToQuality, reconnectPeer, reconnectPeerFailed, reconnectPeerSuccess, regionPingFetchEnd, regionPingFetchStart, regionResolved, resetAfk, resetConfig, resetDataChannelForReconnect, resetIntroSrc, resetUserInactivityTimeout, resetWarnTimeout, resolveSkin, 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, startStream, streamAdopted, trackMixpanelEvent, trackTelemetryData, uint8ToBase64, unrealCommandCallback, unrealFeature, unrealReducer, updateCirrusInfo, videoAdaptedToContainer, videoStreamInitialized };
8142
8416
  //# sourceMappingURL=3dsource-angular-unreal-module.mjs.map