PageSourceSearch

https://pupwife.com/scripts/effects/spaGlobalServices.js

js pupwife.com collected 2026-09-30 15:05:40 UTC 4,393 bytes, 122 lines download raw bytes

1/**
2 * Global dashboard services that must stay alive across SPA navigations
3 * (music player, voice chat, listening party, casino invites, etc.).
4 */
5(function (global) {
6    'use strict';
7
8    var initPromise = null;
9
10    function loadScriptOnce(src) {
11        return new Promise(function (resolve, reject) {
12            if (document.querySelector('script[src="' + src + '"]')) {
13                resolve();
14                return;
15            }
16            var s = document.createElement('script');
17            s.src = src;
18            s.async = false;
19            s.onload = function () { resolve(); };
20            s.onerror = function () { reject(new Error('Failed to load ' + src)); };
21            document.body.appendChild(s);
22        });
23    }
24
25    function ensureVcOverlayStack() {
26        if (typeof global.ensureSpaVcOverlayLoaded === 'function') {
27            return global.ensureSpaVcOverlayLoaded();
28        }
29        return loadScriptOnce('/scripts/effects/spaVcOverlayShell.js')
30            .then(function () {
31                return loadScriptOnce('/scripts/effects/spaVcOverlay.js');
32            })
33            .then(function () {
34                if (global.SpaVcOverlay && typeof global.SpaVcOverlay.init === 'function') {
35                    global.SpaVcOverlay.init();
36                }
37            });
38    }
39
40    function ensureListeningParty() {
41        return loadScriptOnce('/scripts/effects/listeningParty.js').then(function () {
42            if (global.ListeningParty && typeof global.ListeningParty.boot === 'function') {
43                return global.ListeningParty.boot();
44            }
45        });
46    }
47
48    function ensureStaleRoomSweeper() {
49        return loadScriptOnce('/scripts/dependencies/staleRoomSweeper.js')
50            .then(function () {
51                if (global.StaleRoomSweeper && typeof global.StaleRoomSweeper.runIfDue === 'function') {
52                    return global.StaleRoomSweeper.runIfDue();
53                }
54            })
55            .catch(function (err) {
56                console.warn('[spaGlobalServices] stale room sweeper failed', err);
57            });
58    }
59
60    function bootReport(fraction, label) {
61        if (global.CitrusBoot && typeof global.CitrusBoot.reportBoot === 'function') {
62            global.CitrusBoot.reportBoot('services', fraction, label);
63        }
64    }
65
66    function ensureGlobalDashboardServices(deps) {
67        if (!deps || typeof deps.ensureMusicPlayer !== 'function') {
68            return Promise.resolve();
69        }
70        if (initPromise) return initPromise;
71
72        bootReport(0, 'Loading voice chat overlay...');
73
74        var overlayReady = ensureVcOverlayStack().catch(function (err) {
75            console.warn('[spaGlobalServices] VC overlay preload failed', err);
76        });
77
78        initPromise = overlayReady
79            .then(function () {
80                bootReport(0.12, 'Loading music player...');
81                return deps.ensureMusicPlayer();
82            })
83            .then(function () {
84                bootReport(0.42, 'Starting voice chat...');
85                if (typeof deps.ensureGlobalVoice === 'function') {
86                    return deps.ensureGlobalVoice();
87                }
88            })
89            .then(function () {
90                bootReport(0.58, 'Starting voice overlay...');
91                return ensureVcOverlayStack();
92            })
93            .then(function () {
94                bootReport(0.68, 'Starting listening party...');
95                return ensureListeningParty();
96            })
97            .then(function () {
98                bootReport(0.82, 'Starting casino invites...');
99                if (typeof deps.ensureCasinoInviteSystem === 'function') {
100                    return deps.ensureCasinoInviteSystem();
101                }
102            })
103            .then(function () {
104                bootReport(0.92, 'Running room sweeper...');
105                return ensureStaleRoomSweeper();
106            })
107            .catch(function (err) {
108                initPromise = null;
109                console.warn('[spaGlobalServices]', err);
110            });
111
112        return initPromise;
113    }
114
115    global.SpaGlobalServices = {
116        ensure: ensureGlobalDashboardServices,
117        ensureVcOverlay: ensureVcOverlayStack,
118        reset: function () {
119            initPromise = null;
120        }
121    };
122})(typeof window !== 'undefined' ? window : this);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.