/** * Shell entry point — loaded on every page. * * Registers the three header web components: * * * */ import { RStackIdentity } from "../shared/components/rstack-identity"; import { RStackNotificationBell } from "../shared/components/rstack-notification-bell"; import { RStackAppSwitcher } from "../shared/components/rstack-app-switcher"; import { RStackSpaceSwitcher } from "../shared/components/rstack-space-switcher"; import { RStackTabBar } from "../shared/components/rstack-tab-bar"; import { RStackMi } from "../shared/components/rstack-mi"; import { RStackSpaceSettings } from "../shared/components/rstack-space-settings"; import { RStackHistoryPanel } from "../shared/components/rstack-history-panel"; import { RStackOfflineIndicator } from "../shared/components/rstack-offline-indicator"; import { RStackUserDashboard } from "../shared/components/rstack-user-dashboard"; import { rspaceNavUrl } from "../shared/url-helpers"; import { TabCache } from "../shared/tab-cache"; import { RSpaceOfflineRuntime } from "../shared/local-first/runtime"; // Expose URL helper globally (used by shell inline scripts + components) (window as any).__rspaceNavUrl = rspaceNavUrl; // Expose TabCache for inline shell script to instantiate (window as any).__RSpaceTabCache = TabCache; // Register all header components RStackIdentity.define(); RStackNotificationBell.define(); RStackAppSwitcher.define(); RStackSpaceSwitcher.define(); RStackTabBar.define(); RStackMi.define(); RStackSpaceSettings.define(); RStackHistoryPanel.define(); RStackOfflineIndicator.define(); RStackUserDashboard.define(); // ── Offline Runtime ── // Instantiate the shared runtime from the space slug on the tag. // Components access it via window.__rspaceOfflineRuntime. const spaceSlug = document.body?.getAttribute("data-space-slug"); if (spaceSlug && spaceSlug !== "demo") { const runtime = new RSpaceOfflineRuntime(spaceSlug); (window as any).__rspaceOfflineRuntime = runtime; // Configure module scope resolution from server-rendered data try { const scopeJson = document.body?.getAttribute("data-scope-overrides"); const overrides: Record = scopeJson ? JSON.parse(scopeJson) : {}; // Build scope config: merge module defaults with space overrides const moduleList: Array<{ id: string; scoping?: { defaultScope: string } }> = (window as any).__rspaceModuleList || []; const scopes: Array<{ id: string; scope: 'global' | 'space' }> = moduleList.map(m => ({ id: m.id, scope: (overrides[m.id] || m.scoping?.defaultScope || 'space') as 'global' | 'space', })); runtime.setModuleScopes(scopes); } catch { /* scope config unavailable — defaults to space-scoped */ } runtime.init().catch((e: unknown) => { console.warn("[shell] Offline runtime init failed — REST fallback only:", e); }); // Flush pending writes before the page unloads window.addEventListener("beforeunload", () => { runtime.flush(); }); } // ── Track space visits for dashboard recency sorting ── if (spaceSlug) { try { const RECENT_KEY = "rspace_recent_spaces"; const visits = JSON.parse(localStorage.getItem(RECENT_KEY) || "{}"); visits[spaceSlug] = Date.now(); localStorage.setItem(RECENT_KEY, JSON.stringify(visits)); } catch { /* localStorage unavailable */ } } // Reload space list when user signs in/out (to show/hide private spaces) document.addEventListener("auth-change", () => { const spaceSwitcher = document.querySelector("rstack-space-switcher") as any; spaceSwitcher?.reload?.(); // If signed out, redirect to homepage const session = localStorage.getItem("encryptid_session"); if (!session) { window.location.href = "/"; } });