@raydiant/playlist-window-manager 0.29.1 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
26
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
27
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -35,8 +58,13 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
35
58
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
59
  }
37
60
  };
61
+ var __importDefault = (this && this.__importDefault) || function (mod) {
62
+ return (mod && mod.__esModule) ? mod : { "default": mod };
63
+ };
38
64
  Object.defineProperty(exports, "__esModule", { value: true });
39
65
  var testUtils_1 = require("./testUtils");
66
+ var re = __importStar(require("@raydiant/playlist-rule-engine"));
67
+ var SurfaceBroker_1 = __importDefault(require("./SurfaceBroker"));
40
68
  var delay = function (ms) { return new Promise(function (resolve) { return setTimeout(resolve, ms); }); };
41
69
  describe('embedded apps', function () {
42
70
  test('loads embedded url format', function () { return __awaiter(void 0, void 0, void 0, function () {
@@ -431,3 +459,484 @@ describe('interrupt locks', function () {
431
459
  }); });
432
460
  });
433
461
  // TODO: Backfill tests for all legacy and embedded apps.
462
+ describe('waitForFirstPaint', function () {
463
+ // The default (non-embedded) window resolves load() only after the app
464
+ // reports ready, so drive the handshake through the mock renderer.
465
+ var loadPresentationWindow = function (testRenderer, window) { return __awaiter(void 0, void 0, void 0, function () {
466
+ var loadPromise;
467
+ return __generator(this, function (_a) {
468
+ switch (_a.label) {
469
+ case 0:
470
+ loadPromise = window.load();
471
+ return [4 /*yield*/, delay(0)];
472
+ case 1:
473
+ _a.sent();
474
+ testRenderer.runReceiveMessageCallback('loaded', undefined);
475
+ testRenderer.runReceiveMessageCallback('presentation_ready', undefined);
476
+ return [4 /*yield*/, loadPromise];
477
+ case 2:
478
+ _a.sent();
479
+ return [2 /*return*/];
480
+ }
481
+ });
482
+ }); };
483
+ test('resolves when the window reports first_painted', function () { return __awaiter(void 0, void 0, void 0, function () {
484
+ var testRenderer, window, resolved, wait;
485
+ return __generator(this, function (_a) {
486
+ switch (_a.label) {
487
+ case 0:
488
+ testRenderer = (0, testUtils_1.createRenderer)();
489
+ window = (0, testUtils_1.createPresentationWindow)({
490
+ windowId: 'test-first-paint',
491
+ renderer: testRenderer,
492
+ });
493
+ return [4 /*yield*/, loadPresentationWindow(testRenderer, window)];
494
+ case 1:
495
+ _a.sent();
496
+ resolved = false;
497
+ wait = window.waitForFirstPaint(5000).then(function () {
498
+ resolved = true;
499
+ });
500
+ return [4 /*yield*/, delay(10)];
501
+ case 2:
502
+ _a.sent();
503
+ expect(resolved).toBe(false);
504
+ testRenderer.runReceiveMessageCallback('first_painted', undefined);
505
+ return [4 /*yield*/, wait];
506
+ case 3:
507
+ _a.sent();
508
+ expect(resolved).toBe(true);
509
+ return [2 /*return*/];
510
+ }
511
+ });
512
+ }); });
513
+ test('falls back to the timeout when no paint signal arrives', function () { return __awaiter(void 0, void 0, void 0, function () {
514
+ var testRenderer, window;
515
+ return __generator(this, function (_a) {
516
+ switch (_a.label) {
517
+ case 0:
518
+ testRenderer = (0, testUtils_1.createRenderer)();
519
+ window = (0, testUtils_1.createPresentationWindow)({
520
+ windowId: 'test-first-paint-timeout',
521
+ renderer: testRenderer,
522
+ });
523
+ return [4 /*yield*/, loadPresentationWindow(testRenderer, window)];
524
+ case 1:
525
+ _a.sent();
526
+ // Resolves via the timeout even though first_painted never arrives.
527
+ return [4 /*yield*/, window.waitForFirstPaint(20)];
528
+ case 2:
529
+ // Resolves via the timeout even though first_painted never arrives.
530
+ _a.sent();
531
+ return [2 /*return*/];
532
+ }
533
+ });
534
+ }); });
535
+ test('resolves immediately when the window already painted since the last play', function () { return __awaiter(void 0, void 0, void 0, function () {
536
+ var testRenderer, window, resolved;
537
+ return __generator(this, function (_a) {
538
+ switch (_a.label) {
539
+ case 0:
540
+ testRenderer = (0, testUtils_1.createRenderer)();
541
+ window = (0, testUtils_1.createPresentationWindow)({
542
+ windowId: 'test-first-paint-immediate',
543
+ renderer: testRenderer,
544
+ });
545
+ return [4 /*yield*/, loadPresentationWindow(testRenderer, window)];
546
+ case 1:
547
+ _a.sent();
548
+ testRenderer.runReceiveMessageCallback('first_painted', undefined);
549
+ resolved = false;
550
+ window.waitForFirstPaint(5000).then(function () {
551
+ resolved = true;
552
+ });
553
+ return [4 /*yield*/, Promise.resolve()];
554
+ case 2:
555
+ _a.sent();
556
+ expect(resolved).toBe(true);
557
+ return [2 /*return*/];
558
+ }
559
+ });
560
+ }); });
561
+ test('play starts a new paint cycle', function () { return __awaiter(void 0, void 0, void 0, function () {
562
+ var testRenderer, window, resolved, wait;
563
+ return __generator(this, function (_a) {
564
+ switch (_a.label) {
565
+ case 0:
566
+ testRenderer = (0, testUtils_1.createRenderer)();
567
+ window = (0, testUtils_1.createPresentationWindow)({
568
+ windowId: 'test-first-paint-replay',
569
+ renderer: testRenderer,
570
+ });
571
+ return [4 /*yield*/, loadPresentationWindow(testRenderer, window)];
572
+ case 1:
573
+ _a.sent();
574
+ testRenderer.runReceiveMessageCallback('first_painted', undefined);
575
+ window.play();
576
+ resolved = false;
577
+ wait = window.waitForFirstPaint(5000).then(function () {
578
+ resolved = true;
579
+ });
580
+ return [4 /*yield*/, delay(10)];
581
+ case 2:
582
+ _a.sent();
583
+ expect(resolved).toBe(false);
584
+ testRenderer.runReceiveMessageCallback('first_painted', undefined);
585
+ return [4 /*yield*/, wait];
586
+ case 3:
587
+ _a.sent();
588
+ expect(resolved).toBe(true);
589
+ return [2 /*return*/];
590
+ }
591
+ });
592
+ }); });
593
+ test('resolves pending waiters when the window is removed', function () { return __awaiter(void 0, void 0, void 0, function () {
594
+ var testRenderer, window, wait;
595
+ return __generator(this, function (_a) {
596
+ switch (_a.label) {
597
+ case 0:
598
+ testRenderer = (0, testUtils_1.createRenderer)();
599
+ window = (0, testUtils_1.createPresentationWindow)({
600
+ windowId: 'test-first-paint-removed',
601
+ renderer: testRenderer,
602
+ });
603
+ return [4 /*yield*/, loadPresentationWindow(testRenderer, window)];
604
+ case 1:
605
+ _a.sent();
606
+ wait = window.waitForFirstPaint(5000);
607
+ return [4 /*yield*/, window.remove()];
608
+ case 2:
609
+ _a.sent();
610
+ return [4 /*yield*/, wait];
611
+ case 3:
612
+ _a.sent();
613
+ return [2 /*return*/];
614
+ }
615
+ });
616
+ }); });
617
+ });
618
+ describe('detachCallbacks', function () {
619
+ test('stops delivering events to the window manager', function () { return __awaiter(void 0, void 0, void 0, function () {
620
+ var testRenderer, window, loadPromise, onComplete;
621
+ return __generator(this, function (_a) {
622
+ switch (_a.label) {
623
+ case 0:
624
+ testRenderer = (0, testUtils_1.createRenderer)();
625
+ window = (0, testUtils_1.createPresentationWindow)({
626
+ windowId: 'test-detach',
627
+ renderer: testRenderer,
628
+ });
629
+ loadPromise = window.load();
630
+ return [4 /*yield*/, delay(0)];
631
+ case 1:
632
+ _a.sent();
633
+ testRenderer.runReceiveMessageCallback('loaded', undefined);
634
+ testRenderer.runReceiveMessageCallback('presentation_ready', undefined);
635
+ return [4 /*yield*/, loadPromise];
636
+ case 2:
637
+ _a.sent();
638
+ onComplete = jest.fn();
639
+ window.onComplete(onComplete);
640
+ window.detachCallbacks();
641
+ testRenderer.runReceiveMessageCallback('presentation_complete', undefined);
642
+ expect(onComplete).not.toHaveBeenCalled();
643
+ return [2 /*return*/];
644
+ }
645
+ });
646
+ }); });
647
+ });
648
+ describe('video surfaces', function () {
649
+ var CONTENT_URL = 'https://cdn.test/clip.mp4';
650
+ function setupVideoWindow(opts) {
651
+ var _a;
652
+ if (opts === void 0) { opts = {}; }
653
+ var testRenderer = (0, testUtils_1.createRenderer)();
654
+ var host = (0, testUtils_1.createFakeSurfaceHost)();
655
+ var warn = jest.fn();
656
+ var logger = (0, testUtils_1.createLogger)({ warn: warn });
657
+ var window = (0, testUtils_1.createPresentationWindow)({
658
+ windowId: 'video-window',
659
+ presentation: (0, testUtils_1.createPresentation)({
660
+ id: 'p1',
661
+ applicationVariables: (_a = opts.applicationVariables) !== null && _a !== void 0 ? _a : {
662
+ content: { url: CONTENT_URL, filename: 'clip.mp4' },
663
+ },
664
+ }),
665
+ applicationVersion: (0, testUtils_1.createApplicationVersion)(opts.applicationVersion),
666
+ renderer: testRenderer,
667
+ logger: logger,
668
+ surfaceBroker: opts.withHost === false
669
+ ? undefined
670
+ : new SurfaceBroker_1.default(host.surfaces, logger),
671
+ });
672
+ var messages = function () {
673
+ return testRenderer.sendMessageString.mock.calls.map(function (_a) {
674
+ var message = _a[1];
675
+ return JSON.parse(message);
676
+ });
677
+ };
678
+ var refusals = function () {
679
+ return messages()
680
+ .filter(function (m) { return m.type === 'video_refused'; })
681
+ .map(function (m) { return m.payload.reason; });
682
+ };
683
+ var refusalsLogged = function () {
684
+ return warn.mock.calls.filter(function (_a) {
685
+ var message = _a[0];
686
+ return /video_refused/.test(message);
687
+ })
688
+ .length;
689
+ };
690
+ var openVideo = function (url) {
691
+ return testRenderer.runReceiveMessageCallback('open_video', {
692
+ url: url,
693
+ bounds: { x: 0.4, y: 10.6, width: 1919.6, height: 1080 },
694
+ muted: false,
695
+ });
696
+ };
697
+ return {
698
+ testRenderer: testRenderer,
699
+ host: host,
700
+ window: window,
701
+ messages: messages,
702
+ refusals: refusals,
703
+ refusalsLogged: refusalsLogged,
704
+ openVideo: openVideo,
705
+ };
706
+ }
707
+ test('open_video reaches the host, and render carries nativeVideo, only with a host', function () { return __awaiter(void 0, void 0, void 0, function () {
708
+ var offered, unoffered;
709
+ return __generator(this, function (_a) {
710
+ switch (_a.label) {
711
+ case 0:
712
+ offered = setupVideoWindow();
713
+ offered.window.load();
714
+ return [4 /*yield*/, delay(0)];
715
+ case 1:
716
+ _a.sent();
717
+ offered.testRenderer.runReceiveMessageCallback('loaded', undefined);
718
+ expect(offered.messages().find(function (m) { return m.type === 'render'; }).payload.nativeVideo).toBe(true);
719
+ offered.openVideo(CONTENT_URL);
720
+ return [4 /*yield*/, delay(0)];
721
+ case 2:
722
+ _a.sent();
723
+ expect(offered.host.calls.filter(function (c) { return c.method === 'openVideo'; })[0].args[0]).toEqual({
724
+ url: CONTENT_URL,
725
+ bounds: { x: 0, y: 11, width: 1920, height: 1080 },
726
+ muted: true,
727
+ label: 'p1',
728
+ });
729
+ expect(offered.messages().map(function (m) { return m.type; })).toContain('video_opened');
730
+ return [4 /*yield*/, offered.window.remove()];
731
+ case 3:
732
+ _a.sent();
733
+ unoffered = setupVideoWindow({ withHost: false });
734
+ unoffered.window.load();
735
+ return [4 /*yield*/, delay(0)];
736
+ case 4:
737
+ _a.sent();
738
+ unoffered.testRenderer.runReceiveMessageCallback('loaded', undefined);
739
+ expect(unoffered.messages().find(function (m) { return m.type === 'render'; }).payload).not.toHaveProperty('nativeVideo');
740
+ unoffered.openVideo(CONTENT_URL);
741
+ expect(unoffered.refusals()).toEqual(['not_offered']);
742
+ expect(unoffered.refusalsLogged()).toBe(1);
743
+ return [4 /*yield*/, unoffered.window.remove()];
744
+ case 5:
745
+ _a.sent();
746
+ return [2 /*return*/];
747
+ }
748
+ });
749
+ }); });
750
+ test('a rendition beside the presentation url opens a surface', function () { return __awaiter(void 0, void 0, void 0, function () {
751
+ var _a, window, host, openVideo, refusals;
752
+ return __generator(this, function (_b) {
753
+ switch (_b.label) {
754
+ case 0:
755
+ _a = setupVideoWindow(), window = _a.window, host = _a.host, openVideo = _a.openVideo, refusals = _a.refusals;
756
+ window.load();
757
+ return [4 /*yield*/, delay(0)];
758
+ case 1:
759
+ _b.sent();
760
+ openVideo("".concat(CONTENT_URL, "_720p"));
761
+ return [4 /*yield*/, delay(0)];
762
+ case 2:
763
+ _b.sent();
764
+ expect(host.calls.filter(function (c) { return c.method === 'openVideo'; })).toHaveLength(1);
765
+ expect(refusals()).toEqual([]);
766
+ return [4 /*yield*/, window.remove()];
767
+ case 3:
768
+ _b.sent();
769
+ return [2 /*return*/];
770
+ }
771
+ });
772
+ }); });
773
+ test.each([
774
+ ['a url the presentation does not hold', 'https://cdn.test/other.mp4'],
775
+ ['a url beside it with another suffix', "".concat(CONTENT_URL, "_1080p")],
776
+ ])('%s is refused not_offered', function (_, url) { return __awaiter(void 0, void 0, void 0, function () {
777
+ var _a, window, host, openVideo, refusals, refusalsLogged;
778
+ return __generator(this, function (_b) {
779
+ switch (_b.label) {
780
+ case 0:
781
+ _a = setupVideoWindow(), window = _a.window, host = _a.host, openVideo = _a.openVideo, refusals = _a.refusals, refusalsLogged = _a.refusalsLogged;
782
+ window.load();
783
+ return [4 /*yield*/, delay(0)];
784
+ case 1:
785
+ _b.sent();
786
+ openVideo(url);
787
+ return [4 /*yield*/, delay(0)];
788
+ case 2:
789
+ _b.sent();
790
+ expect(refusals()).toEqual(['not_offered']);
791
+ expect(refusalsLogged()).toBe(1);
792
+ expect(host.calls).toEqual([]);
793
+ return [4 /*yield*/, window.remove()];
794
+ case 3:
795
+ _b.sent();
796
+ return [2 /*return*/];
797
+ }
798
+ });
799
+ }); });
800
+ test('a url that is not http(s) is refused not_offered', function () { return __awaiter(void 0, void 0, void 0, function () {
801
+ var _a, window, host, openVideo, refusals;
802
+ return __generator(this, function (_b) {
803
+ switch (_b.label) {
804
+ case 0:
805
+ _a = setupVideoWindow({
806
+ applicationVariables: { content: { url: 'blob:https://cdn.test/1' } },
807
+ }), window = _a.window, host = _a.host, openVideo = _a.openVideo, refusals = _a.refusals;
808
+ window.load();
809
+ return [4 /*yield*/, delay(0)];
810
+ case 1:
811
+ _b.sent();
812
+ openVideo('blob:https://cdn.test/1');
813
+ return [4 /*yield*/, delay(0)];
814
+ case 2:
815
+ _b.sent();
816
+ expect(refusals()).toEqual(['not_offered']);
817
+ expect(host.calls).toEqual([]);
818
+ return [4 /*yield*/, window.remove()];
819
+ case 3:
820
+ _b.sent();
821
+ return [2 /*return*/];
822
+ }
823
+ });
824
+ }); });
825
+ test('an embedded app is refused not_offered', function () { return __awaiter(void 0, void 0, void 0, function () {
826
+ var _a, window, host, testRenderer, refusals, refusalsLogged;
827
+ return __generator(this, function (_b) {
828
+ switch (_b.label) {
829
+ case 0:
830
+ _a = setupVideoWindow({
831
+ applicationVersion: { embeddedUrlFormat: 'https://embedded.test/' },
832
+ }), window = _a.window, host = _a.host, testRenderer = _a.testRenderer, refusals = _a.refusals, refusalsLogged = _a.refusalsLogged;
833
+ return [4 /*yield*/, window.load()];
834
+ case 1:
835
+ _b.sent();
836
+ testRenderer.runReceiveMessageCallback('open_video', {
837
+ url: CONTENT_URL,
838
+ bounds: { x: 0, y: 0, width: 1920, height: 1080 },
839
+ });
840
+ return [4 /*yield*/, delay(0)];
841
+ case 2:
842
+ _b.sent();
843
+ expect(refusals()).toEqual(['not_offered']);
844
+ expect(refusalsLogged()).toBe(1);
845
+ expect(host.calls).toEqual([]);
846
+ return [4 /*yield*/, window.remove()];
847
+ case 3:
848
+ _b.sent();
849
+ return [2 /*return*/];
850
+ }
851
+ });
852
+ }); });
853
+ test("a zone's windows are offered no surface and refused not_offered", function () { return __awaiter(void 0, void 0, void 0, function () {
854
+ var testRenderer, host, logger, zonePresentation, window, zoneWindowId, zoneMessages;
855
+ return __generator(this, function (_a) {
856
+ switch (_a.label) {
857
+ case 0:
858
+ testRenderer = (0, testUtils_1.createRenderer)();
859
+ host = (0, testUtils_1.createFakeSurfaceHost)();
860
+ logger = (0, testUtils_1.createLogger)();
861
+ zonePresentation = (0, testUtils_1.createPresentation)({
862
+ id: 'z1',
863
+ applicationDeploymentId: 'zone-app',
864
+ applicationVariables: { content: { url: CONTENT_URL } },
865
+ });
866
+ window = (0, testUtils_1.createPresentationWindow)({
867
+ windowId: 'multizone',
868
+ presentation: (0, testUtils_1.createPresentation)({
869
+ id: 'mz',
870
+ r: {
871
+ resource: { updatedAt: 'updatedAt', createdAt: 'createdAt' },
872
+ presentationsPlaylists: [{ playlistId: 'zone-playlist' }],
873
+ },
874
+ }),
875
+ playlistWindowManagerState: (0, testUtils_1.createPlaylistWindowManagerState)({
876
+ presentations: { z1: zonePresentation },
877
+ applicationVersions: {
878
+ 'zone-app': (0, testUtils_1.createApplicationVersion)({ id: 'zone-app' }),
879
+ },
880
+ }),
881
+ ruleEngineState: (0, testUtils_1.createRuleEngineState)({
882
+ 'zone-playlist': {
883
+ id: 'zone-playlist',
884
+ mode: re.PlaylistMode.Sequential,
885
+ items: [{ presentationId: 'z1' }],
886
+ },
887
+ }, { z1: { id: 'z1', applicationName: 'videos' } }),
888
+ renderer: testRenderer,
889
+ logger: logger,
890
+ surfaceBroker: new SurfaceBroker_1.default(host.surfaces, logger),
891
+ });
892
+ window.load();
893
+ return [4 /*yield*/, delay(0)];
894
+ case 1:
895
+ _a.sent();
896
+ testRenderer.runReceiveMessageCallback('open_child_window', {
897
+ windowId: 'zone1',
898
+ playlistId: 'zone-playlist',
899
+ x: 0,
900
+ y: 0,
901
+ width: 960,
902
+ height: 1080,
903
+ isMuted: false,
904
+ isFocused: false,
905
+ });
906
+ return [4 /*yield*/, delay(0)];
907
+ case 2:
908
+ _a.sent();
909
+ zoneWindowId = testRenderer.createWindow.mock.calls[1][0].windowId;
910
+ testRenderer.runReceiveMessageCallback('loaded', undefined);
911
+ zoneMessages = function () {
912
+ return testRenderer.sendMessageString.mock.calls
913
+ .filter(function (_a) {
914
+ var windowId = _a[0];
915
+ return windowId === zoneWindowId;
916
+ })
917
+ .map(function (_a) {
918
+ var message = _a[1];
919
+ return JSON.parse(message);
920
+ });
921
+ };
922
+ expect(zoneMessages().find(function (m) { return m.type === 'render'; }).payload).not.toHaveProperty('nativeVideo');
923
+ testRenderer.runReceiveMessageCallback('open_video', {
924
+ url: CONTENT_URL,
925
+ bounds: { x: 0, y: 0, width: 960, height: 1080 },
926
+ muted: false,
927
+ });
928
+ return [4 /*yield*/, delay(0)];
929
+ case 3:
930
+ _a.sent();
931
+ expect(zoneMessages()
932
+ .filter(function (m) { return m.type === 'video_refused'; })
933
+ .map(function (m) { return m.payload.reason; })).toEqual(['not_offered']);
934
+ expect(host.calls).toEqual([]);
935
+ return [4 /*yield*/, window.remove()];
936
+ case 4:
937
+ _a.sent();
938
+ return [2 /*return*/];
939
+ }
940
+ });
941
+ }); });
942
+ });
@@ -0,0 +1,30 @@
1
+ import { Logger } from './types';
2
+ import { SurfaceHost, VideoEvent, VideoOptions, VideoSurface, VideoRefusalReason } from './surfaces';
3
+ export declare const SURFACE_OPEN_DEADLINE_MS = 2000;
4
+ export declare const SURFACE_FIRST_FRAME_DEADLINE_MS = 10000;
5
+ export declare const MAX_LIVE_SURFACES = 2;
6
+ export declare const DEFAULT_SURFACE_SWAP_DELAY_MS = 1000;
7
+ export declare const DEFAULT_SHOW_AFTER_REVEAL_MS = 80;
8
+ export type SurfaceRefusalReason = Exclude<VideoRefusalReason, 'not_offered'>;
9
+ export declare class SurfaceRefusal extends Error {
10
+ reason: SurfaceRefusalReason | 'closed';
11
+ constructor(reason: SurfaceRefusalReason | 'closed');
12
+ }
13
+ export default class SurfaceBroker {
14
+ private host;
15
+ private logger;
16
+ private entries;
17
+ constructor(host: SurfaceHost, logger: Logger);
18
+ open(windowId: string, opts: VideoOptions, onEvent: (e: VideoEvent) => void, onRefused: (reason: SurfaceRefusalReason) => void): Promise<VideoSurface>;
19
+ leaving(windowId: string): void;
20
+ close(windowId: string): Promise<void>;
21
+ closeAll(): Promise<void>;
22
+ onHole(open: boolean): void;
23
+ private openWithDeadline;
24
+ private throwIfGivenUp;
25
+ private liveOthers;
26
+ private pendingCloses;
27
+ private refuse;
28
+ private warnRefusal;
29
+ private forget;
30
+ }