// kernel/services.js — the dependency-injection container (window.LP.services). // // An ADDITIVE, typed, lazy view onto the existing cross-cutting singletons. It // constructs NOTHING: every member is a getter that returns the live global, so // there is no double-instantiation and the globals stay authoritative. Feature // modules receive it as ctx.services (kernel/lifecycle.js) and use it instead of // reaching for window.* directly — the seam the rest of the de-globalisation // builds on. Access only inside mount()/unmount() (post-boot), never at a // feature's module top level, so the lazy getters always resolve. // // NOTE: page-owned controllers (appsManager, appTabbedManager, configManager, // backupPage, adminSystem, …) are NOT services — they belong to their feature — // so they are deliberately absent here. Slot names + globals were verified // against the real code (the design doc's §4 list had several wrong names). (function () { const LP = (window.LP = window.LP || {}); LP.services = { // Task system — the locked-down mutation front door + the live status bus. tasks: { get bus() { return window.taskEventBus; }, // the single SSE EventSource get refresh() { return window.taskRefresh; }, // refresh coordinator (register/unregister) // .routeAction(action, params) is the mutation path (mutations-via-tasks). // Can be null if TasksManager construction failed — callers keep `?.`. get route() { return window.tasksManager ? window.tasksManager.router : null; }, }, get live() { return window.LiveSystem; }, // 1 Hz system SSE: subscribe/pause/resume get auth() { return window.authManager; }, // logout()/interceptFetch()/isAuthenticated // DataLoader is a bare classic-script class (not a window property), so fall // back to the lexical binding. get data() { return (typeof DataLoader !== 'undefined') ? DataLoader : (window.DataLoader || null); }, // Reuse the codebase's own get-or-create net; never `new NotificationSystem()` // here (would append a second toast container). get notify() { return window.notificationSystem || (window.ensureNotificationSystem && window.ensureNotificationSystem()); }, get theme() { return window.ThemeRegistry; }, // theme discovery/list // The eo-modal toolkit is six free functions, not one object — group them. get modal() { return { open: window.openEoModal, section: window.eoSection, badgeRow: window.eoBadgeRow, urlList: window.eoUrlList, credList: window.eoCredList, empty: window.eoEmpty, }; }, // The router surface is split: the spaClean instance (runtime methods, bound // to preserve `this`) + the standalone URL helpers. Return a fresh delegating // object — never Object.assign onto the live singleton. get router() { const spa = window.spaClean; return { navigate: (...a) => spa && spa.navigate(...a), loadScript: (s) => spa && spa.loadScript(s), fetchContent: (u) => spa && spa.fetchContent(u), loadContent: (h, t) => spa && spa.loadContent(h, t), navigateToRoute: window.navigateToRoute, appPath: window.appPath, appPartsFromPath: window.appPartsFromPath, adminPath: window.adminPath, adminCategoryFromPath: window.adminCategoryFromPath, }; }, }; })();