From 4b7aa8da750eb3fc13503bac3450a711946532e5 Mon Sep 17 00:00:00 2001 From: StroepWafel Date: Mon, 22 Jun 2026 21:08:12 +0930 Subject: [PATCH] fix(themes): theme wallpapers dont apply on firefox --- src/SEQTA.ts | 8 +- .../components/themes/ThemeBlobImage.svelte | 38 +++ .../components/themes/ThemeSelector.svelte | 5 +- src/interface/index.ts | 4 +- src/interface/pages/settings/general.svelte | 12 + src/interface/pages/settings/theme.svelte | 2 +- src/interface/pages/themeCreator.svelte | 5 +- .../src/components/SearchBar.svelte | 3 +- .../globalSearch/src/core/commands.ts | 3 +- .../built-in/globalSearch/src/core/index.ts | 23 +- .../globalSearch/src/indexing/actions.ts | 5 +- .../globalSearch/src/indexing/indexer.ts | 27 +- .../src/indexing/jobs/assignments.ts | 13 +- .../globalSearch/src/indexing/jobs/courses.ts | 5 +- .../src/indexing/jobs/documents.ts | 3 +- .../globalSearch/src/indexing/jobs/folio.ts | 3 +- .../globalSearch/src/indexing/jobs/goals.ts | 5 +- .../src/indexing/jobs/messages.ts | 19 +- .../globalSearch/src/indexing/jobs/notices.ts | 3 +- .../src/indexing/jobs/notifications.ts | 15 +- .../globalSearch/src/indexing/jobs/portals.ts | 3 +- .../globalSearch/src/indexing/jobs/reports.ts | 3 +- .../src/indexing/jobs/subjects.ts | 3 +- .../src/indexing/passiveObserver.ts | 7 +- .../globalSearch/src/indexing/selfTests.ts | 3 +- .../globalSearch/src/indexing/utils.ts | 7 +- .../src/indexing/worker/vectorWorker.ts | 57 ++-- .../indexing/worker/vectorWorkerManager.ts | 49 +-- .../globalSearch/src/search/searchUtils.ts | 3 +- .../src/search/vector/vectorSearch.ts | 7 +- .../globalSearch/src/utils/versionCheck.ts | 13 +- .../built-in/notificationCollector/index.ts | 3 +- src/plugins/built-in/themes/theme-manager.ts | 319 +++++------------- src/plugins/built-in/themes/themeImageUrl.ts | 38 +++ src/plugins/built-in/timetable/index.ts | 3 +- src/plugins/core/dynamicLoader.ts | 5 +- src/plugins/core/manager.ts | 7 +- src/plugins/monofile.ts | 17 +- src/seqta/main.ts | 2 + src/seqta/utils/Loaders/LoadHomePage.ts | 3 +- src/seqta/utils/SendNewsPage.ts | 3 +- .../utils/ensureSyncableStorageDefaults.ts | 1 + src/seqta/utils/menuItemVisibility.ts | 3 +- .../utils/patchThemeImagesPageContext.ts | 112 ++++++ src/seqta/utils/seqtaMenuColourPatch.js | 1 + src/seqta/utils/themeImagePagePatch.js | 210 ++++++++++++ src/seqta/utils/timetableColoris.ts | 3 +- src/types/storage.ts | 2 + src/utils/verboseLog.ts | 38 +++ vite.config.ts | 7 + 50 files changed, 744 insertions(+), 389 deletions(-) create mode 100644 src/interface/components/themes/ThemeBlobImage.svelte create mode 100644 src/plugins/built-in/themes/themeImageUrl.ts create mode 100644 src/seqta/utils/patchThemeImagesPageContext.ts create mode 100644 src/seqta/utils/themeImagePagePatch.js create mode 100644 src/utils/verboseLog.ts diff --git a/src/SEQTA.ts b/src/SEQTA.ts index 3c897407..f4697a6e 100644 --- a/src/SEQTA.ts +++ b/src/SEQTA.ts @@ -11,6 +11,8 @@ import { main } from "@/seqta/main"; import { delay } from "./seqta/utils/delay"; import { initializeHideSensitiveToggle } from "@/seqta/utils/hideSensitiveToggle"; import { installSeqtaMenuColourPatch } from "@/seqta/utils/patchSeqtaMenuUpdateColours"; +import { installThemeImagePagePatch } from "@/seqta/utils/patchThemeImagesPageContext"; +import { initVerboseLogging, verboseInfo } from "@/utils/verboseLog"; function registerFetchSeqtaAppLinkListener() { browser.runtime.onMessage.addListener((request, _sender, sendResponse) => { @@ -49,6 +51,7 @@ if (document.childNodes[1]) { ) ?? false; if (hasSEQTAText) { installSeqtaMenuColourPatch(); + installThemeImagePagePatch(); } init(); } @@ -61,7 +64,7 @@ async function init() { !IsSEQTAPage ) { IsSEQTAPage = true; - console.info("[BetterSEQTA+] Verified SEQTA Page"); + verboseInfo("[BetterSEQTA+] Verified SEQTA Page"); if (typeof window !== "undefined" && window === window.top) { void browser.runtime.sendMessage({ type: "cloudSettingsPoll" }).catch(() => {}); @@ -100,6 +103,7 @@ async function init() { try { await initializeSettingsState(); + initVerboseLogging(); if (typeof settingsState.onoff === "undefined") { await browser.runtime.sendMessage({ type: "setDefaultStorage" }); @@ -118,7 +122,7 @@ async function init() { initializeHideSensitiveToggle(); } - console.info( + verboseInfo( "[BetterSEQTA+] Successfully initialised BetterSEQTA+, starting to load assets.", ); } catch (error) { diff --git a/src/interface/components/themes/ThemeBlobImage.svelte b/src/interface/components/themes/ThemeBlobImage.svelte new file mode 100644 index 00000000..4332a5b5 --- /dev/null +++ b/src/interface/components/themes/ThemeBlobImage.svelte @@ -0,0 +1,38 @@ + + +{#if src} + {alt} +{/if} diff --git a/src/interface/components/themes/ThemeSelector.svelte b/src/interface/components/themes/ThemeSelector.svelte index 51a2cf16..9c6b54d7 100644 --- a/src/interface/components/themes/ThemeSelector.svelte +++ b/src/interface/components/themes/ThemeSelector.svelte @@ -9,6 +9,7 @@ import { ThemeManager } from '@/plugins/built-in/themes/theme-manager' import { cloudAuth } from '@/seqta/utils/CloudAuth' import SignInToFavoriteModal from '@/interface/components/SignInToFavoriteModal.svelte' + import ThemeBlobImage from '@/interface/components/themes/ThemeBlobImage.svelte' const themeManager = ThemeManager.getInstance(); @@ -237,8 +238,8 @@
{#if theme.coverImage} - {theme.name} diff --git a/src/interface/index.ts b/src/interface/index.ts index 76a4e9c1..a760b630 100644 --- a/src/interface/index.ts +++ b/src/interface/index.ts @@ -4,9 +4,10 @@ import IconFamily from "@/resources/fonts/IconFamily.woff"; import browser from "webextension-polyfill"; import renderSvelte from "./main"; import { initializeSettingsState } from "@/seqta/utils/listeners/SettingsState"; +import { initVerboseLogging, verboseInfo } from "@/utils/verboseLog"; function InjectCustomIcons() { - console.info("[BetterSEQTA+] Injecting Icons"); + verboseInfo("[BetterSEQTA+] Injecting Icons"); const style = document.createElement("style"); style.setAttribute("type", "text/css"); @@ -30,5 +31,6 @@ InjectCustomIcons(); (async () => { await initializeSettingsState(); + initVerboseLogging(); renderSvelte(Settings, mountPoint, { standalone: true }); })(); diff --git a/src/interface/pages/settings/general.svelte b/src/interface/pages/settings/general.svelte index 2f48d6d1..a25b46bf 100644 --- a/src/interface/pages/settings/general.svelte +++ b/src/interface/pages/settings/general.svelte @@ -492,6 +492,18 @@ settingsState.devMode = isOn} />
+
+
+

Verbose logging

+

Show diagnostic console output (indexer, theme manager, timetable colour patch, etc.)

+
+
+ settingsState.verboseLogging = isOn} + /> +
+

Sensitive Hider

diff --git a/src/interface/pages/settings/theme.svelte b/src/interface/pages/settings/theme.svelte index fece578a..422afe69 100644 --- a/src/interface/pages/settings/theme.svelte +++ b/src/interface/pages/settings/theme.svelte @@ -22,7 +22,7 @@ diff --git a/src/interface/pages/themeCreator.svelte b/src/interface/pages/themeCreator.svelte index 777cd411..48261bd2 100644 --- a/src/interface/pages/themeCreator.svelte +++ b/src/interface/pages/themeCreator.svelte @@ -27,6 +27,7 @@ import { ThemeManager } from '@/plugins/built-in/themes/theme-manager' import { themeUpdates } from '../hooks/ThemeUpdates' import { CloseThemeCreator } from '@/plugins/built-in/themes/ThemeCreator' + import ThemeBlobImage from '@/interface/components/themes/ThemeBlobImage.svelte' const { themeID } = $props<{ themeID: string }>() const themeManager = ThemeManager.getInstance(); @@ -230,7 +231,7 @@ {#each theme.CustomImages as image (image.id)}
- {image.variableName} +
- Cover + {/if}
diff --git a/src/plugins/built-in/globalSearch/src/components/SearchBar.svelte b/src/plugins/built-in/globalSearch/src/components/SearchBar.svelte index 67a75f59..f63fda71 100644 --- a/src/plugins/built-in/globalSearch/src/components/SearchBar.svelte +++ b/src/plugins/built-in/globalSearch/src/components/SearchBar.svelte @@ -15,6 +15,7 @@ import HighlightedText from '../utils/HighlightedText.svelte'; import { matchesHotkey } from '../utils/hotkeyUtils'; import browser from 'webextension-polyfill'; + import { verboseDebug } from '@/utils/verboseLog'; const { transparencyEffects, @@ -160,7 +161,7 @@ dynamicItems.forEach(item => dynamicIdToItemMap.set(item.id, item)); commands.forEach(item => commandIdToItemMap.set(item.id, item)); - console.debug(`[Global Search] Indexed ${commands.length} command items and ${dynamicItems.length} dynamic items.`); + verboseDebug(`[Global Search] Indexed ${commands.length} command items and ${dynamicItems.length} dynamic items.`); } const performSearch = async () => { diff --git a/src/plugins/built-in/globalSearch/src/core/commands.ts b/src/plugins/built-in/globalSearch/src/core/commands.ts index 54a7fc8a..9f83c482 100644 --- a/src/plugins/built-in/globalSearch/src/core/commands.ts +++ b/src/plugins/built-in/globalSearch/src/core/commands.ts @@ -2,6 +2,7 @@ import { settingsState } from "@/seqta/utils/listeners/SettingsState"; import { loadHomePage } from "@/seqta/utils/Loaders/LoadHomePage"; import { waitForElm } from "@/seqta/utils/waitForElm"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; export interface BaseCommandItem { id: string; text: string; @@ -105,7 +106,7 @@ async function navigateToSpecificLesson(lesson: any) { if (lessonDate === todayDateString && lessonPeriod === normalizedLessonPeriod) { // Found the exact matching lesson, click it (lessonElement as HTMLElement).click(); - console.log(`Navigated to exact lesson: ${lessonDate} ${lessonPeriod}`); + verboseLog(`Navigated to exact lesson: ${lessonDate} ${lessonPeriod}`); return true; } } diff --git a/src/plugins/built-in/globalSearch/src/core/index.ts b/src/plugins/built-in/globalSearch/src/core/index.ts index 2ad909fb..3681b649 100644 --- a/src/plugins/built-in/globalSearch/src/core/index.ts +++ b/src/plugins/built-in/globalSearch/src/core/index.ts @@ -7,6 +7,7 @@ import { hotkeySetting, Setting, } from "@/plugins/core/settingsHelpers"; +import { verboseDebug, verboseInfo, verboseLog } from "@/utils/verboseLog"; import styles from "./styles.css?inline"; import { waitForElm } from "@/seqta/utils/waitForElm"; import { runIndexing } from "../indexing/indexer"; @@ -70,7 +71,7 @@ const settings = defineSettings({ try { const workerManager = VectorWorkerManager.getInstance(); await workerManager.resetWorker(); - console.log("Vector worker reset successfully"); + verboseLog("Vector worker reset successfully"); } catch (e) { console.warn("Failed to reset vector worker:", e); } @@ -90,7 +91,7 @@ const settings = defineSettings({ return new Promise((resolve, reject) => { const req = indexedDB.deleteDatabase(dbName); req.onsuccess = () => { - console.log(`Successfully deleted database: ${dbName}`); + verboseLog(`Successfully deleted database: ${dbName}`); resolve(); }; req.onerror = () => { @@ -103,7 +104,7 @@ const settings = defineSettings({ setTimeout(() => { const retryReq = indexedDB.deleteDatabase(dbName); retryReq.onsuccess = () => { - console.log(`Successfully deleted database on retry: ${dbName}`); + verboseLog(`Successfully deleted database on retry: ${dbName}`); resolve(); }; retryReq.onerror = () => reject(retryReq.error); @@ -176,7 +177,7 @@ const globalSearchPlugin: Plugin = { try { const wasUpdated = await checkAndHandleUpdate(); if (wasUpdated) { - console.log( + verboseLog( "[Global Search] Extension updated — search index reset; the next indexing pass will repopulate.", ); } @@ -188,7 +189,7 @@ const globalSearchPlugin: Plugin = { error?.message?.includes("MIME type") || error?.message?.includes("NS_ERROR_CORRUPTED_CONTENT") ) { - console.debug( + verboseDebug( "[Global Search] Version check skipped due to asset loading restrictions:", error.message, ); @@ -217,7 +218,7 @@ const globalSearchPlugin: Plugin = { if (isVectorSearchSupported()) { VectorWorkerManager.getInstance(); } else { - console.debug("[Global Search] Skipping vector worker warm-up (Firefox detected - using text search only)"); + verboseDebug("[Global Search] Skipping vector worker warm-up (Firefox detected - using text search only)"); } } catch (error) { console.warn("[Global Search] Vector worker warm-up failed:", error); @@ -230,15 +231,15 @@ const globalSearchPlugin: Plugin = { resetWorker: async () => { const workerManager = VectorWorkerManager.getInstance(); await workerManager.resetWorker(); - console.log("Vector worker reset via debug helper"); + verboseLog("Vector worker reset via debug helper"); }, checkWorkerStatus: () => { const workerManager = VectorWorkerManager.getInstance(); - console.log("Streaming active:", workerManager.isStreamingActive()); + verboseLog("Streaming active:", workerManager.isStreamingActive()); }, passiveItems: async () => { const items = await getStoredPassiveItems(); - console.log(`Captured ${items.length} passive items`); + verboseLog(`Captured ${items.length} passive items`); return items; }, runSelfTests: async () => { @@ -250,7 +251,7 @@ const globalSearchPlugin: Plugin = { checkIndexedDBSize: async () => { try { const estimate = await navigator.storage.estimate(); - console.log("Storage estimate:", estimate); + verboseLog("Storage estimate:", estimate); // Check embeddiaDB size const dbRequest = indexedDB.open("embeddiaDB"); @@ -260,7 +261,7 @@ const globalSearchPlugin: Plugin = { const store = transaction.objectStore("embeddiaObjectStore"); const countRequest = store.count(); countRequest.onsuccess = () => { - console.log("embeddiaDB item count:", countRequest.result); + verboseLog("embeddiaDB item count:", countRequest.result); }; }; } catch (e) { diff --git a/src/plugins/built-in/globalSearch/src/indexing/actions.ts b/src/plugins/built-in/globalSearch/src/indexing/actions.ts index 954b6730..b485b3a5 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/actions.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/actions.ts @@ -3,6 +3,7 @@ import type { IndexItem } from "./types"; import ReactFiber from "@/seqta/utils/ReactFiber"; import { delay } from "@/seqta/utils/delay"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; interface MessageMetadata { messageId: number; author: string; @@ -171,7 +172,7 @@ export const actionMap: Record> = { if ((assessmentId === undefined || assessmentId === null) && itemClone.id && itemClone.id.startsWith('assignment-')) { const extractedId = itemClone.id.replace('assignment-', ''); assessmentId = Number(extractedId) || extractedId; - console.log("[Assessment Action] Extracted assessmentId from item ID:", assessmentId); + verboseLog("[Assessment Action] Extracted assessmentId from item ID:", assessmentId); } // Convert to numbers, but preserve 0 as valid @@ -198,7 +199,7 @@ export const actionMap: Record> = { if (hasProgrammeId && hasMetaclassId && hasAssessmentId) { const url = `#?page=/assessments/${programmeId}:${metaclassId}&item=${assessmentId}`; - console.log("[Assessment Action] ✅ Navigating to:", url); + verboseLog("[Assessment Action] ✅ Navigating to:", url); window.location.hash = url; } else { // Fallback: try to navigate to assessments page if metadata is incomplete diff --git a/src/plugins/built-in/globalSearch/src/indexing/indexer.ts b/src/plugins/built-in/globalSearch/src/indexing/indexer.ts index 70222ca8..57c86830 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/indexer.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/indexer.ts @@ -7,6 +7,7 @@ import { loadDynamicItems } from "../utils/dynamicItems"; import { getVectorizedItemIds } from "./utils"; import { INDEX_SCHEMA_VERSION, SCHEMA_VERSION_KEY } from "./schemaVersion"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; const META_STORE = "meta"; const LOCK_KEY = "bsq-indexer-lock"; const HEARTBEAT_INTERVAL = 10000; @@ -101,7 +102,7 @@ async function updateLastRunMeta(jobId: string): Promise { async function acquireLock(): Promise { if (isIndexingActive) { - console.debug("[Indexer] Already indexing in this tab"); + verboseDebug("[Indexer] Already indexing in this tab"); return false; } @@ -200,7 +201,7 @@ export async function loadAllStoredItems(): Promise { console.error(`Error loading items for job store ${jobId}:`, error); } } - console.debug( + verboseDebug( `[Indexer] Loaded ${all.length} items from all primary stores.`, ); return all; @@ -210,7 +211,7 @@ export async function runIndexing(): Promise { await ensureSchemaCurrent(); if (!(await acquireLock())) { - console.debug( + verboseDebug( "%c[Indexer] Could not acquire lock - another tab is indexing or this tab is already indexing", "color: gray", ); @@ -218,7 +219,7 @@ export async function runIndexing(): Promise { } startHeartbeat(); - console.debug("%c[Indexer] Starting indexing...", "color: green"); + verboseDebug("%c[Indexer] Starting indexing...", "color: green"); const jobIds = Object.keys(jobs); let completedJobs = 0; @@ -236,7 +237,7 @@ export async function runIndexing(): Promise { const lastRun = await getLastRunMeta(jobId); if (!shouldRun(job, lastRun)) { - console.debug( + verboseDebug( `%c[Indexer] Skipping job "${jobId}" (not due)`, "color: gray", ); @@ -288,7 +289,7 @@ export async function runIndexing(): Promise { setProgress: (p) => saveProgress(jobId, p), }; - console.debug(`%c[Indexer] Running job "${jobId}"...`, "color: #4ea1ff"); + verboseDebug(`%c[Indexer] Running job "${jobId}"...`, "color: #4ea1ff"); try { const newItemsRaw = await job.run(ctx); @@ -300,12 +301,12 @@ export async function runIndexing(): Promise { await setStoredItems(merged); await updateLastRunMeta(jobId); - console.debug( + verboseDebug( `%c[Indexer] ${job.label}: ${newItemsRaw.length} new items reported by run, ${merged.length} total items now in '${jobId}' store.`, "color: #00c46f", ); } catch (err) { - console.debug(`%c[Indexer] Job ${job.label} failed:`, "color: red"); + verboseDebug(`%c[Indexer] Job ${job.label} failed:`, "color: red"); console.error(err); } @@ -321,7 +322,7 @@ export async function runIndexing(): Promise { let allItemsInPrimaryStores = await loadAllStoredItems(); if (allItemsInPrimaryStores.length > 0) { - console.debug( + verboseDebug( `%c[Indexer] Checking ${allItemsInPrimaryStores.length} items for vectorization...`, "color: #4ea1ff", ); @@ -331,7 +332,7 @@ export async function runIndexing(): Promise { const newItemsToVectorize = allItemsInPrimaryStores.filter(item => !vectorizedItemIds.has(item.id)); if (newItemsToVectorize.length > 0) { - console.debug( + verboseDebug( `%c[Indexer] Sending ${newItemsToVectorize.length} new items to worker for vectorization (${allItemsInPrimaryStores.length - newItemsToVectorize.length} already vectorized)`, "color: #4ea1ff", ); @@ -389,7 +390,7 @@ export async function runIndexing(): Promise { ); } }); - console.debug( + verboseDebug( "%c[Indexer] Vectorization task for stored items sent to worker.", "color: green", ); @@ -408,7 +409,7 @@ export async function runIndexing(): Promise { ); } } else { - console.debug( + verboseDebug( `%c[Indexer] All ${allItemsInPrimaryStores.length} items are already vectorized, skipping worker initialization.`, "color: gray", ); @@ -421,7 +422,7 @@ export async function runIndexing(): Promise { ); } } else { - console.debug( + verboseDebug( "%c[Indexer] No items found in primary stores to send for vectorization.", "color: gray", ); diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/assignments.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/assignments.ts index ea0cc470..f04b40e8 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/assignments.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/assignments.ts @@ -1,5 +1,6 @@ import type { IndexItem, Job } from "../types"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; const fetchJSON = async (url: string, body: any) => { const res = await fetch(`${location.origin}${url}`, { method: "POST", @@ -128,7 +129,7 @@ export const assignmentsJob: Job = { const student = 69; // TODO: Get from context if available - console.debug("[Assignments job] Starting indexing - fetching all assessments (upcoming and past)..."); + verboseDebug("[Assignments job] Starting indexing - fetching all assessments (upcoming and past)..."); // Fetch data in parallel const [upcoming, subjects] = await Promise.all([ @@ -136,12 +137,12 @@ export const assignmentsJob: Job = { fetchSubjects(), ]); - console.debug(`[Assignments job] Fetched ${upcoming.length} upcoming assessments and ${subjects.length} subjects`); + verboseDebug(`[Assignments job] Fetched ${upcoming.length} upcoming assessments and ${subjects.length} subjects`); // Fetch past assessments for ALL subjects to ensure we get all historical assignments const past = await fetchPastAssessments(student, subjects); - console.debug(`[Assignments job] Fetched ${past.length} past assessments`); + verboseDebug(`[Assignments job] Fetched ${past.length} past assessments`); // Create a lookup map from subject code to programme/metaclass const subjectLookup = new Map(); @@ -220,7 +221,7 @@ export const assignmentsJob: Job = { const assessmentArray = Array.from(allAssessments.values()); const pastCount = assessmentArray.filter(a => !a.isUpcoming).length; const upcomingCount = assessmentArray.filter(a => a.isUpcoming).length; - console.debug(`[Assignments job] Processing ${assessmentArray.length} total assessments (${upcomingCount} upcoming, ${pastCount} past)`); + verboseDebug(`[Assignments job] Processing ${assessmentArray.length} total assessments (${upcomingCount} upcoming, ${pastCount} past)`); const batchSize = 15; // Increased batch size for better performance // Skip fetching assessment details - the API endpoint doesn't exist or returns 404 @@ -321,7 +322,7 @@ export const assignmentsJob: Job = { renderComponentId: "assessment", }; - console.debug(`[Assignments job] ✅ Created item for assignment ${assessment.id}:`, { + verboseDebug(`[Assignments job] ✅ Created item for assignment ${assessment.id}:`, { id: item.id, programmeId: item.metadata.programmeId, programmeID: item.metadata.programmeID, @@ -350,7 +351,7 @@ export const assignmentsJob: Job = { const newItemsCount = items.filter(item => !existingIds.has(item.id)).length; const updatedItemsCount = items.length - newItemsCount; - console.debug(`[Assignments job] Indexed ${items.length} assignment items (${newItemsCount} new, ${updatedItemsCount} updated)`); + verboseDebug(`[Assignments job] Indexed ${items.length} assignment items (${newItemsCount} new, ${updatedItemsCount} updated)`); return items; }, diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/courses.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/courses.ts index c5fa959f..ae3fb7b5 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/courses.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/courses.ts @@ -3,6 +3,7 @@ import { seqtaFetchPayload } from "../api"; import { buildIndexItem } from "../extract"; import { htmlToPlainText } from "../utils"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; /** * Indexes per-subject course content from `/seqta/student/load/courses`. * @@ -106,7 +107,7 @@ export const coursesJob: Job = { run: async (_ctx) => { const subjects = await fetchActiveSubjects(); if (subjects.length === 0) { - console.debug("[Courses job] No active subjects discovered."); + verboseDebug("[Courses job] No active subjects discovered."); return []; } @@ -169,7 +170,7 @@ export const coursesJob: Job = { ); } - console.debug( + verboseDebug( `[Courses job] Indexed ${items.length} courses across ${subjects.length} subjects.`, ); return items; diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/documents.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/documents.ts index a89c7955..22616956 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/documents.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/documents.ts @@ -1,6 +1,7 @@ import type { IndexItem, Job } from "../types"; import { seqtaFetchPayload } from "../api"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; /** * Indexes file metadata from `/seqta/student/load/documents`. * @@ -131,7 +132,7 @@ export const documentsJob: Job = { } } - console.debug(`[Documents job] Indexed ${items.length} document entries.`); + verboseDebug(`[Documents job] Indexed ${items.length} document entries.`); return items; }, diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/folio.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/folio.ts index 8131441f..fae51e2e 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/folio.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/folio.ts @@ -3,6 +3,7 @@ import { seqtaFetchPayload } from "../api"; import { htmlToPlainText } from "../utils"; import { delay } from "@/seqta/utils/delay"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; /** * Indexes student folio entries from `/seqta/student/folio`. * @@ -126,7 +127,7 @@ export const folioJob: Job = { await delay(PER_ITEM_DELAY_MS); } - console.debug(`[Folio job] Indexed ${items.length} folio entries.`); + verboseDebug(`[Folio job] Indexed ${items.length} folio entries.`); return items; }, diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/goals.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/goals.ts index 2b8f8265..87cbf309 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/goals.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/goals.ts @@ -3,6 +3,7 @@ import { seqtaFetchPayload } from "../api"; import { extractTextFromValue } from "../extract"; import { delay } from "@/seqta/utils/delay"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; /** * Indexes student goals from `/seqta/student/load/goals`. * @@ -42,7 +43,7 @@ export const goalsJob: Job = { { mode: "years" }, ); if (!Array.isArray(years) || years.length === 0) { - console.debug("[Goals job] No goal years available; skipping."); + verboseDebug("[Goals job] No goal years available; skipping."); return []; } @@ -101,7 +102,7 @@ export const goalsJob: Job = { await delay(PER_YEAR_DELAY_MS); } - console.debug(`[Goals job] Indexed ${items.length} goal entries.`); + verboseDebug(`[Goals job] Indexed ${items.length} goal entries.`); return items; }, diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/messages.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/messages.ts index 617b3cad..6e13d485 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/messages.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/messages.ts @@ -7,6 +7,7 @@ import { loadAllStoredItems } from "../indexer"; import { renderComponentMap } from "../renderComponents"; import { jobs } from "../jobs"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; const RATE_LIMIT_CONFIG = { minDelay: 30, maxDelay: 3000, @@ -208,7 +209,7 @@ function checkCircuitBreaker(progress: MessagesProgress): boolean { ) { progress.circuitBreakerOpen = false; progress.consecutiveFailures = 0; - console.info( + verboseInfo( `[Messages job] Circuit breaker closed after ${RATE_LIMIT_CONFIG.circuitBreakerResetTime}ms`, ); return false; @@ -352,7 +353,7 @@ async function processMessagesInParallel( batchResponseTime, ); - console.log( + verboseLog( `[Messages job] Processed parallel batch: ${batchSuccesses} successes, ${batchFailures} failures, ${batchResponseTime}ms total time`, ); } @@ -397,7 +398,7 @@ export const messagesJob: Job = { await vectorWorker.startStreamingSession( progress.totalEstimated, (progressData) => { - console.log( + verboseLog( `[Messages job] Vector streaming progress: ${progressData.processed}/${progressData.total} (${progressData.status})`, ); }, @@ -405,7 +406,7 @@ export const messagesJob: Job = { "messages", ); progress.streamingStarted = true; - console.log( + verboseLog( `[Messages job] Started streaming vectorization session for ~${progress.totalEstimated} items`, ); } catch (error) { @@ -422,7 +423,7 @@ export const messagesJob: Job = { let itemsStreamedToVector = 0; if (progress.retryQueue.length > 0) { - console.log( + verboseLog( `[Messages job] Processing ${Math.min(progress.retryQueue.length, 10)} items from retry queue`, ); @@ -505,7 +506,7 @@ export const messagesJob: Job = { batchResponseTime, ); - console.log( + verboseLog( `[Messages job] Processed retry batch: ${retrySuccesses} successes, ${retryFailures} failures`, ); } @@ -590,7 +591,7 @@ export const messagesJob: Job = { try { await vectorWorker.streamItems(itemsToStream); itemsStreamedToVector += itemsToStream.length; - console.log( + verboseLog( `[Messages job] Streamed ${itemsToStream.length} items to vector worker (total: ${itemsStreamedToVector})`, ); } catch (error) { @@ -659,7 +660,7 @@ export const messagesJob: Job = { await ctx.setProgress(progress); progressUpdateCounter = 0; - console.log( + verboseLog( `[Messages job] Progress: offset=${progress.offset}, batchSize=${progress.currentBatchSize}, delay=${progress.currentDelay}ms, failures=${progress.failedRequests}, retryQueue=${progress.retryQueue.length}, vectorStreamed=${itemsStreamedToVector}, parallelRequests=${RATE_LIMIT_CONFIG.parallelRequests}`, ); } @@ -673,7 +674,7 @@ export const messagesJob: Job = { if (progress.streamingStarted) { try { await vectorWorker.endStreamingSession(); - console.log( + verboseLog( `[Messages job] Ended streaming session. Total items streamed: ${itemsStreamedToVector}`, ); } catch (error) { diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/notices.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/notices.ts index 93e6be15..9ef0f09b 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/notices.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/notices.ts @@ -3,6 +3,7 @@ import { seqtaFetchPayload } from "../api"; import { htmlToPlainText } from "../utils"; import { delay } from "@/seqta/utils/delay"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; /** * Indexes daily notices from `/seqta/student/load/notices`. * @@ -205,7 +206,7 @@ export const noticesJob: Job = { await ctx.setProgress(progress); const newCount = items.filter((i) => !existingIds.has(i.id)).length; - console.debug( + verboseDebug( `[Notices job] Indexed ${items.length} notices across ${dates.length} dates (${newCount} new).`, ); return items; diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/notifications.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/notifications.ts index f0474bbc..523b00ed 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/notifications.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/notifications.ts @@ -8,6 +8,7 @@ import { loadAllStoredItems } from "../indexer"; import { renderComponentMap } from "../renderComponents"; import { jobs } from "../jobs"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; const NOTIFICATIONS_RATE_LIMIT = { baseDelay: 150, maxDelay: 3000, @@ -201,7 +202,7 @@ export const notificationsJob: Job = { await vectorWorker.startStreamingSession( estimatedTotal, (progressData) => { - console.log( + verboseLog( `[Notifications job] Vector streaming progress: ${progressData.processed}/${progressData.total} (${progressData.status})`, ); }, @@ -209,7 +210,7 @@ export const notificationsJob: Job = { "notifications", ); progress.streamingStarted = true; - console.log( + verboseLog( `[Notifications job] Started streaming vectorization session for ~${estimatedTotal} items`, ); } catch (error) { @@ -247,7 +248,7 @@ export const notificationsJob: Job = { let itemsStreamedToVector = 0; if (progress.retryQueue.length > 0) { - console.log( + verboseLog( `[Notifications job] Processing ${Math.min(progress.retryQueue.length, 3)} items from retry queue`, ); @@ -352,7 +353,7 @@ export const notificationsJob: Job = { try { await vectorWorker.streamItems([...itemsToStream]); itemsStreamedToVector += itemsToStream.length; - console.log( + verboseLog( `[Notifications job] Streamed ${itemsToStream.length} items to vector worker (total: ${itemsStreamedToVector})`, ); itemsToStream.length = 0; @@ -424,7 +425,7 @@ export const notificationsJob: Job = { try { await vectorWorker.streamItems([...itemsToStream]); itemsStreamedToVector += itemsToStream.length; - console.log( + verboseLog( `[Notifications job] Streamed final ${itemsToStream.length} items to vector worker (total: ${itemsStreamedToVector})`, ); } catch (error) { @@ -438,7 +439,7 @@ export const notificationsJob: Job = { if (progress.streamingStarted) { try { await vectorWorker.endStreamingSession(); - console.log( + verboseLog( `[Notifications job] Ended streaming session. Total items streamed: ${itemsStreamedToVector}`, ); progress.streamingStarted = false; @@ -459,7 +460,7 @@ export const notificationsJob: Job = { } await ctx.setProgress(progress); - console.log( + verboseLog( `[Notifications job] Processed ${processedCount} notifications, ${progress.retryQueue.length} in retry queue, ${progress.failedRequests} failures, ${itemsStreamedToVector} items streamed to vector worker`, ); diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/portals.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/portals.ts index 01d5bd71..0d40501f 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/portals.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/portals.ts @@ -1,6 +1,7 @@ import type { IndexItem, Job } from "../types"; import { seqtaFetchPayload } from "../api"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; /** * Indexes the user's external portal entries from `/seqta/student/load/portals`. * @@ -82,7 +83,7 @@ export const portalsJob: Job = { }); } - console.debug(`[Portals job] Indexed ${items.length} portal entries.`); + verboseDebug(`[Portals job] Indexed ${items.length} portal entries.`); return items; }, diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/reports.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/reports.ts index 9b3fc973..420aad9b 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/reports.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/reports.ts @@ -1,6 +1,7 @@ import type { IndexItem, Job } from "../types"; import { seqtaFetchPayload } from "../api"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; /** * Indexes report metadata from `/seqta/student/load/reports`. * @@ -89,7 +90,7 @@ export const reportsJob: Job = { }); } - console.debug(`[Reports job] Indexed ${items.length} reports.`); + verboseDebug(`[Reports job] Indexed ${items.length} reports.`); return items; }, diff --git a/src/plugins/built-in/globalSearch/src/indexing/jobs/subjects.ts b/src/plugins/built-in/globalSearch/src/indexing/jobs/subjects.ts index 342afd46..971b357e 100755 --- a/src/plugins/built-in/globalSearch/src/indexing/jobs/subjects.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/jobs/subjects.ts @@ -1,5 +1,6 @@ import type { IndexItem, Job } from "../types"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; const fetchSubjects = async () => { const res = await fetch(`${location.origin}/seqta/student/load/subjects`, { method: "POST", @@ -129,7 +130,7 @@ export const subjectsJob: Job = { } } - console.debug(`[Subjects job] Indexed ${items.length} subject items`); + verboseDebug(`[Subjects job] Indexed ${items.length} subject items`); return items; }, diff --git a/src/plugins/built-in/globalSearch/src/indexing/passiveObserver.ts b/src/plugins/built-in/globalSearch/src/indexing/passiveObserver.ts index c183eca6..df02a0d7 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/passiveObserver.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/passiveObserver.ts @@ -6,6 +6,7 @@ import { pickId, pickTitle, } from "./extract"; +import { verboseDebug, verboseInfo, verboseLog } from "@/utils/verboseLog"; import { isSensitiveSeqtaPath, normalizeSeqtaPath } from "./api"; import { loadAllStoredItems } from "./indexer"; import { loadDynamicItems } from "../utils/dynamicItems"; @@ -542,7 +543,7 @@ export function installPassiveObserver(): void { } } catch (e) { // Never let observer errors bubble up to the host page. - console.debug("[Passive Observer] fetch hook error:", e); + verboseDebug("[Passive Observer] fetch hook error:", e); } return response; @@ -605,7 +606,7 @@ export function installPassiveObserver(): void { void persistItems(items); } } catch (e) { - console.debug("[Passive Observer] xhr load error:", e); + verboseDebug("[Passive Observer] xhr load error:", e); } }); } @@ -616,7 +617,7 @@ export function installPassiveObserver(): void { }; } - console.debug("[Passive Observer] Installed."); + verboseDebug("[Passive Observer] Installed."); } /** diff --git a/src/plugins/built-in/globalSearch/src/indexing/selfTests.ts b/src/plugins/built-in/globalSearch/src/indexing/selfTests.ts index 36a7bae1..f85d6abe 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/selfTests.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/selfTests.ts @@ -7,6 +7,7 @@ import { pickId, buildIndexItem, } from "./extract"; +import { verboseDebug, verboseInfo, verboseLog } from "@/utils/verboseLog"; import { isSensitiveSeqtaPath, normalizeSeqtaPath } from "./api"; import { coursesPayload, @@ -320,7 +321,7 @@ export async function runGlobalSearchSelfTests(): Promise { report.failures, ); } else { - console.info( + verboseInfo( `[Global Search Self-Tests] All ${report.passed} cases passed`, ); } diff --git a/src/plugins/built-in/globalSearch/src/indexing/utils.ts b/src/plugins/built-in/globalSearch/src/indexing/utils.ts index a5365dfa..1592c270 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/utils.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/utils.ts @@ -1,3 +1,4 @@ +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; /** * Check which items are already vectorized in embeddia's IndexedDB * Returns a Set of item IDs that are already indexed @@ -7,7 +8,7 @@ export async function getVectorizedItemIds(): Promise> { const request = indexedDB.open("embeddiaDB"); request.onerror = () => { - console.debug("Could not open embeddiaDB, assuming no items are vectorized"); + verboseDebug("Could not open embeddiaDB, assuming no items are vectorized"); resolve(new Set()); }; @@ -15,7 +16,7 @@ export async function getVectorizedItemIds(): Promise> { const db = (event.target as IDBOpenDBRequest).result; if (!db.objectStoreNames.contains("embeddiaObjectStore")) { - console.debug("embeddiaObjectStore not found, assuming no items are vectorized"); + verboseDebug("embeddiaObjectStore not found, assuming no items are vectorized"); db.close(); resolve(new Set()); return; @@ -34,7 +35,7 @@ export async function getVectorizedItemIds(): Promise> { } }); - console.debug(`Found ${vectorizedIds.size} already vectorized items in embeddia DB`); + verboseDebug(`Found ${vectorizedIds.size} already vectorized items in embeddia DB`); db.close(); resolve(vectorizedIds); }; diff --git a/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorker.ts b/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorker.ts index 64f71f0d..cca5bc45 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorker.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorker.ts @@ -1,6 +1,7 @@ import { EmbeddingIndex, getEmbedding, initializeModel } from "embeddia"; import type { IndexItem } from "../types"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; let vectorIndex: EmbeddingIndex | null = null; let isInitialized = false; let initializationFailed = false; @@ -33,27 +34,27 @@ let streamingSession: { async function initWorker() { if (isInitialized) { - console.debug("Vector worker already initialized."); + verboseDebug("Vector worker already initialized."); return; } // Skip initialization in Firefox if (isFirefoxWorker()) { - console.debug("[Vector Worker] Vector search not supported in Firefox - skipping initialization"); + verboseDebug("[Vector Worker] Vector search not supported in Firefox - skipping initialization"); isInitialized = true; initializationFailed = true; vectorIndex = null; return; } - console.debug("Initializing vector worker..."); + verboseDebug("Initializing vector worker..."); try { await initializeModel(); vectorIndex = new EmbeddingIndex([]); const stored = await vectorIndex.getAllObjectsFromIndexedDB(); if (stored.length > 0) { - console.debug(`Found ${stored.length} existing items in IndexedDB`); + verboseDebug(`Found ${stored.length} existing items in IndexedDB`); loadedItemIds.clear(); @@ -64,14 +65,14 @@ async function initWorker() { } }); - console.debug( + verboseDebug( `Vector index loaded ${loadedItemIds.size} unique items from IndexedDB.`, ); } else { - console.debug("No existing vector index found in IndexedDB."); + verboseDebug("No existing vector index found in IndexedDB."); } isInitialized = true; - console.debug("Vector worker initialized successfully."); + verboseDebug("Vector worker initialized successfully."); } catch (e) { console.warn("[Vector Worker] Failed to initialize vector worker (will use text search only):", e); isInitialized = true; @@ -149,7 +150,7 @@ async function startStreamingSession( processingPromise: null, }; - console.debug( + verboseDebug( `Started streaming session for ${totalExpected} items with batch size ${batchSize}`, ); @@ -175,7 +176,7 @@ async function processStreamingBatch( streamingSession.totalReceived += items.length; streamingSession.pendingItems.push(...items); - console.debug( + verboseDebug( `Received streaming batch: ${items.length} items (${streamingSession.totalReceived}/${streamingSession.totalExpected})`, ); @@ -208,7 +209,7 @@ async function processStreamingItems() { if (unprocessedItems.length === 0) { streamingSession.totalProcessed += batchToProcess.length; - console.debug(`Skipped ${batchToProcess.length} already processed items`); + verboseDebug(`Skipped ${batchToProcess.length} already processed items`); continue; } @@ -231,7 +232,7 @@ async function processStreamingItems() { loadedItemIds.size % 200 === 0 ) { await vectorIndex!.saveIndex("indexedDB"); - console.debug( + verboseDebug( `Saved streaming index at ${streamingSession.totalProcessed} processed items (${loadedItemIds.size} total unique items)`, ); } @@ -272,7 +273,7 @@ async function finalizeStreamingSession() { try { if (vectorIndex) { await vectorIndex.saveIndex("indexedDB"); - console.debug("Final save of streaming index completed"); + verboseDebug("Final save of streaming index completed"); } } catch (e) { console.error("Error in final streaming save:", e); @@ -293,7 +294,7 @@ async function finalizeStreamingSession() { }, }); - console.debug( + verboseDebug( `Streaming session completed: ${totalProcessed}/${totalExpected} items processed`, ); } @@ -303,14 +304,14 @@ async function endStreamingSession() { return; } - console.debug("Ending streaming session..."); + verboseDebug("Ending streaming session..."); if (streamingSession.processingPromise) { await streamingSession.processingPromise; } if (streamingSession.pendingItems.length > 0) { - console.debug( + verboseDebug( `Processing ${streamingSession.pendingItems.length} remaining items before ending session`, ); streamingSession.processingPromise = processStreamingItems(); @@ -320,7 +321,7 @@ async function endStreamingSession() { try { if (vectorIndex) { await vectorIndex.saveIndex("indexedDB"); - console.debug("Final save before ending streaming session"); + verboseDebug("Final save before ending streaming session"); } } catch (e) { console.error("Error in final save before ending session:", e); @@ -341,7 +342,7 @@ async function endStreamingSession() { } async function processItems(items: IndexItem[], signal: AbortSignal) { - console.debug("Worker received process request."); + verboseDebug("Worker received process request."); if (initializationFailed || isFirefoxWorker()) { self.postMessage({ @@ -378,7 +379,7 @@ async function processItems(items: IndexItem[], signal: AbortSignal) { }); if (signal.aborted) { - console.debug("Processing cancelled before starting."); + verboseDebug("Processing cancelled before starting."); self.postMessage({ type: "progress", data: { @@ -390,7 +391,7 @@ async function processItems(items: IndexItem[], signal: AbortSignal) { } if (unprocessedItems.length === 0) { - console.debug( + verboseDebug( `No new items to process. ${loadedItemIds.size} items already in index.`, ); self.postMessage({ @@ -403,7 +404,7 @@ async function processItems(items: IndexItem[], signal: AbortSignal) { return; } - console.debug( + verboseDebug( `Starting processing of ${unprocessedItems.length} items (${items.length - unprocessedItems.length} already processed).`, ); self.postMessage({ @@ -419,7 +420,7 @@ async function processItems(items: IndexItem[], signal: AbortSignal) { let processedCount = 0; for (let i = 0; i < unprocessedItems.length; i += BATCH_SIZE) { if (signal.aborted) { - console.debug("Processing cancelled during batching."); + verboseDebug("Processing cancelled during batching."); self.postMessage({ type: "progress", data: { @@ -437,7 +438,7 @@ async function processItems(items: IndexItem[], signal: AbortSignal) { ) as (IndexItem & { embedding: number[] })[]; if (signal.aborted) { - console.debug("Processing cancelled after vectorization batch."); + verboseDebug("Processing cancelled after vectorization batch."); self.postMessage({ type: "progress", data: { @@ -464,7 +465,7 @@ async function processItems(items: IndexItem[], signal: AbortSignal) { } if (signal.aborted) { - console.debug("Processing cancelled before saving batch."); + verboseDebug("Processing cancelled before saving batch."); self.postMessage({ type: "progress", data: { @@ -481,7 +482,7 @@ async function processItems(items: IndexItem[], signal: AbortSignal) { ) { try { await vectorIndex!.saveIndex("indexedDB"); - console.debug( + verboseDebug( `Saved index after processing batch ${i / BATCH_SIZE + 1} (${loadedItemIds.size} total unique items)`, ); } catch (e) { @@ -505,7 +506,7 @@ async function processItems(items: IndexItem[], signal: AbortSignal) { }); } - console.debug( + verboseDebug( `Processing complete. Total unique items in index: ${loadedItemIds.size}`, ); self.postMessage({ @@ -520,7 +521,7 @@ async function processItems(items: IndexItem[], signal: AbortSignal) { } async function resetWorker() { - console.debug("Resetting vector worker state..."); + verboseDebug("Resetting vector worker state..."); loadedItemIds.clear(); @@ -532,7 +533,7 @@ async function resetWorker() { if (vectorIndex) { try { await vectorIndex.saveIndex("indexedDB"); - console.debug("Saved index before reset"); + verboseDebug("Saved index before reset"); } catch (e) { console.warn("Error saving index before reset:", e); } @@ -543,7 +544,7 @@ async function resetWorker() { await initWorker(); - console.debug( + verboseDebug( `Vector worker reset complete. Loaded ${loadedItemIds.size} items.`, ); diff --git a/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorkerManager.ts b/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorkerManager.ts index 33b92385..c1de4196 100644 --- a/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorkerManager.ts +++ b/src/plugins/built-in/globalSearch/src/indexing/worker/vectorWorkerManager.ts @@ -3,6 +3,7 @@ import type { IndexItem } from "../types"; import { isVectorSearchSupported } from "../../utils/browserDetection"; import vectorWorker from "./vectorWorker.ts?inlineWorker"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; export type ProgressCallback = (data: { status: "started" | "processing" | "complete" | "error" | "cancelled"; total?: number; @@ -38,7 +39,7 @@ export class VectorWorkerManager { static getInstance(): VectorWorkerManager { if (!VectorWorkerManager.instance) { - console.debug("Creating new VectorWorkerManager instance"); + verboseDebug("Creating new VectorWorkerManager instance"); VectorWorkerManager.instance = new VectorWorkerManager(); } return VectorWorkerManager.instance; @@ -47,7 +48,7 @@ export class VectorWorkerManager { private async initWorker(): Promise { // Skip initialization if vector search is not supported (e.g., Firefox) if (!isVectorSearchSupported()) { - console.debug("[VectorWorkerManager] Vector search not supported - skipping worker initialization"); + verboseDebug("[VectorWorkerManager] Vector search not supported - skipping worker initialization"); this.isInitialized = false; return Promise.resolve(); } @@ -55,19 +56,19 @@ export class VectorWorkerManager { if (this.isInitialized) return Promise.resolve(); if (this.readyPromise) return this.readyPromise; - console.debug("Lazy-loading vector worker..."); + verboseDebug("Lazy-loading vector worker..."); return new Promise((resolve, reject) => { if (this.worker) { - console.debug("Terminating existing worker before creating new one"); + verboseDebug("Terminating existing worker before creating new one"); this.worker.terminate(); this.worker = null; } - console.debug("Creating new vector worker instance"); + verboseDebug("Creating new vector worker instance"); this.worker = vectorWorker(); - console.log("Worker initialized", this.worker); + verboseLog("Worker initialized", this.worker); const timeout = setTimeout(() => { console.error("Vector worker initialization timed out"); @@ -82,14 +83,14 @@ export class VectorWorkerManager { this.worker!.addEventListener("message", (e) => { const { type, data } = e.data; - console.debug("Message from vector worker:", type, data); + verboseDebug("Message from vector worker:", type, data); switch (type) { case "ready": this.isInitialized = true; clearTimeout(timeout); this.updateActivity(); // Start idle timer after initialization - console.debug("Vector worker initialized and ready."); + verboseDebug("Vector worker initialized and ready."); resolve(); break; @@ -150,7 +151,7 @@ export class VectorWorkerManager { } private resetWorkerState() { - console.debug("Resetting vector worker state"); + verboseDebug("Resetting vector worker state"); if (this.worker) { this.worker.terminate(); this.worker = null; @@ -176,7 +177,7 @@ export class VectorWorkerManager { if (this.vectorizationLockCount > 0) return; if (this.streamingSession?.isActive) return; if (!this.isInitialized) return; - console.debug("[VectorWorker] Auto-shutting down due to 2 minutes of inactivity"); + verboseDebug("[VectorWorker] Auto-shutting down due to 2 minutes of inactivity"); this.resetWorkerState(); }, 120000); // 2 minutes } @@ -208,7 +209,7 @@ export class VectorWorkerManager { this.unloadTimer = setTimeout(() => { if (this.vectorizationLockCount > 0) return; if (!this.streamingSession?.isActive && this.isInitialized) { - console.debug("[VectorWorker] Auto-unloading after processing complete"); + verboseDebug("[VectorWorker] Auto-unloading after processing complete"); this.resetWorkerState(); } }, delay); @@ -295,7 +296,7 @@ export class VectorWorkerManager { }); if (uniqueItems.length !== items.length) { - console.debug( + verboseDebug( `Filtered out ${items.length - uniqueItems.length} duplicate items before processing`, ); } @@ -350,7 +351,7 @@ export class VectorWorkerManager { }; this.progressCallback = wrap; - console.debug( + verboseDebug( `Sending ${uniqueItems.length} unique items to worker for processing.`, ); @@ -378,7 +379,7 @@ export class VectorWorkerManager { ): Promise { // Skip if vector search is not supported if (!isVectorSearchSupported()) { - console.debug("[VectorWorker] Vector search not supported - skipping streaming session"); + verboseDebug("[VectorWorker] Vector search not supported - skipping streaming session"); if (onProgress) { onProgress({ status: "complete", @@ -390,7 +391,7 @@ export class VectorWorkerManager { // Only initialize if we expect items to process if (totalExpectedItems === 0) { - console.debug("[VectorWorker] No items expected, not starting streaming session"); + verboseDebug("[VectorWorker] No items expected, not starting streaming session"); return; } @@ -405,7 +406,7 @@ export class VectorWorkerManager { await new Promise((resolve) => setTimeout(resolve, 100)); } else { - console.debug(`Streaming session for job ${jobId} already active`); + verboseDebug(`Streaming session for job ${jobId} already active`); return; } } @@ -425,7 +426,7 @@ export class VectorWorkerManager { lastActivityTime: Date.now(), }; - console.debug( + verboseDebug( `Starting streaming session for job ${jobId} with ${totalExpectedItems} items (batch size ${batchSize})`, ); @@ -456,7 +457,7 @@ export class VectorWorkerManager { }); if (uniqueItems.length !== items.length) { - console.debug( + verboseDebug( `[Streaming] Filtered out ${items.length - uniqueItems.length} duplicate items before streaming`, ); } @@ -472,7 +473,7 @@ export class VectorWorkerManager { this.streamingSession.inactivityTimer = setTimeout(() => { if (this.streamingSession?.isActive) { - console.debug( + verboseDebug( "[VectorWorker] Auto-ending streaming session due to inactivity", ); this.endStreamingSession(); @@ -513,7 +514,7 @@ export class VectorWorkerManager { this.streamingSession.flushTimer = null; } - console.debug( + verboseDebug( `Streaming batch of ${batch.length} items to worker (${this.streamingSession.totalSent}/${this.streamingSession.totalExpected})`, ); @@ -549,7 +550,7 @@ export class VectorWorkerManager { type: "endStreaming", }); - console.debug("Streaming session ended"); + verboseDebug("Streaming session ended"); if (this.progressCallback) { this.progressCallback({ @@ -590,12 +591,12 @@ export class VectorWorkerManager { } terminate() { - console.debug("Terminating Vector Worker Manager..."); + verboseDebug("Terminating Vector Worker Manager..."); this.resetWorkerState(); } async resetWorker(): Promise { - console.debug("Resetting vector worker..."); + verboseDebug("Resetting vector worker..."); if (this.streamingSession?.isActive) { await this.endStreamingSession(); @@ -605,6 +606,6 @@ export class VectorWorkerManager { this.worker!.postMessage({ type: "reset" }); - console.debug("Reset command sent to worker"); + verboseDebug("Reset command sent to worker"); } } diff --git a/src/plugins/built-in/globalSearch/src/search/searchUtils.ts b/src/plugins/built-in/globalSearch/src/search/searchUtils.ts index b4d4b91d..67e26b3e 100644 --- a/src/plugins/built-in/globalSearch/src/search/searchUtils.ts +++ b/src/plugins/built-in/globalSearch/src/search/searchUtils.ts @@ -10,6 +10,7 @@ import { isStrongLexicalMatch, STRONG_LEXICAL_THRESHOLD, } from "./lexicalMatch"; +import { verboseDebug, verboseInfo, verboseLog } from "@/utils/verboseLog"; /** Same normalization as lexical matching (trim + lowercase). */ function normSearchKey(s: string): string { @@ -91,7 +92,7 @@ function setCachedResults(query: string, results: CombinedResult[]) { */ export function clearSearchCache(): void { searchCache.clear(); - console.debug("[Search] Search result cache cleared"); + verboseDebug("[Search] Search result cache cleared"); } // Listen for cache clear events (e.g., on extension update) diff --git a/src/plugins/built-in/globalSearch/src/search/vector/vectorSearch.ts b/src/plugins/built-in/globalSearch/src/search/vector/vectorSearch.ts index a56a5902..606a3b9e 100644 --- a/src/plugins/built-in/globalSearch/src/search/vector/vectorSearch.ts +++ b/src/plugins/built-in/globalSearch/src/search/vector/vectorSearch.ts @@ -3,6 +3,7 @@ import type { IndexItem } from "../../indexing/types"; import type { SearchResult } from "embeddia"; import { isVectorSearchSupported } from "../../utils/browserDetection"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; let vectorIndex: EmbeddingIndex | null = null; let initializationAttempted = false; let initializationFailed = false; @@ -11,7 +12,7 @@ export async function initVectorSearch() { // Skip initialization if already attempted and failed, or if not supported if (initializationFailed || !isVectorSearchSupported()) { if (!isVectorSearchSupported()) { - console.debug("[Vector Search] Vector search not supported in Firefox - using text search only"); + verboseDebug("[Vector Search] Vector search not supported in Firefox - using text search only"); } return; } @@ -26,7 +27,7 @@ export async function initVectorSearch() { await initializeModel(); vectorIndex = new EmbeddingIndex([]); vectorIndex.preloadIndexedDB(); - console.debug("[Vector Search] Initialized successfully"); + verboseDebug("[Vector Search] Initialized successfully"); } catch (e) { console.warn("[Vector Search] Failed to initialize vector search (will use text search only):", e); initializationFailed = true; @@ -66,7 +67,7 @@ function setCachedEmbedding(query: string, embedding: number[]) { */ export function clearEmbeddingCache(): void { embeddingCache.clear(); - console.debug("[Vector Search] Embedding cache cleared"); + verboseDebug("[Vector Search] Embedding cache cleared"); } // Listen for cache clear events (e.g., on extension update) diff --git a/src/plugins/built-in/globalSearch/src/utils/versionCheck.ts b/src/plugins/built-in/globalSearch/src/utils/versionCheck.ts index 2c4e9b04..37618793 100644 --- a/src/plugins/built-in/globalSearch/src/utils/versionCheck.ts +++ b/src/plugins/built-in/globalSearch/src/utils/versionCheck.ts @@ -1,6 +1,7 @@ import browser from "webextension-polyfill"; import { resetSearchIndexes } from "../indexing/resetIndexes"; +import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog'; const VERSION_STORAGE_KEY = "betterseqta-global-search-version"; const VERSION_CACHE_KEY = "betterseqta-global-search-cache-version"; @@ -60,7 +61,7 @@ export async function checkAndHandleUpdate(): Promise { // First run: just remember the version, don't reset (the user likely // just installed the extension; the index is already empty). if (!storedVersion) { - console.debug( + verboseDebug( `[Version Check] First run detected, storing version ${currentVersion}`, ); storeVersion(currentVersion); @@ -71,7 +72,7 @@ export async function checkAndHandleUpdate(): Promise { return false; } - console.log( + verboseLog( `[Version Check] Extension updated from ${storedVersion} to ${currentVersion}, resetting search index...`, ); @@ -79,7 +80,7 @@ export async function checkAndHandleUpdate(): Promise { try { await resetSearchIndexes(); - console.log( + verboseLog( "[Version Check] Search index reset; next indexing pass will repopulate from scratch.", ); } catch (e) { @@ -112,7 +113,7 @@ export async function clearAllCaches(): Promise { } catch (e: any) { // Module might not be loaded yet, or CSS preload error - that's okay if (!e?.message?.includes("preload CSS") && !e?.message?.includes("MIME type")) { - console.debug("[Version Check] Could not clear search cache:", e); + verboseDebug("[Version Check] Could not clear search cache:", e); } } @@ -122,12 +123,12 @@ export async function clearAllCaches(): Promise { } catch (e: any) { // Module might not be loaded yet, or CSS preload error - that's okay if (!e?.message?.includes("preload CSS") && !e?.message?.includes("MIME type")) { - console.debug("[Version Check] Could not clear embedding cache:", e); + verboseDebug("[Version Check] Could not clear embedding cache:", e); } } }, 50); - console.debug("[Version Check] All caches cleared"); + verboseDebug("[Version Check] All caches cleared"); } catch (e) { console.error("[Version Check] Error clearing caches:", e); } diff --git a/src/plugins/built-in/notificationCollector/index.ts b/src/plugins/built-in/notificationCollector/index.ts index 779183cb..78d30bea 100644 --- a/src/plugins/built-in/notificationCollector/index.ts +++ b/src/plugins/built-in/notificationCollector/index.ts @@ -1,5 +1,6 @@ import type { Plugin } from "../../core/types"; import { isSeqtaEngageExperience } from "@/seqta/utils/isSeqtaEngage"; +import { verboseInfo } from "@/utils/verboseLog"; interface NotificationCollectorStorage { lastNotificationCount: number; @@ -75,7 +76,7 @@ const notificationCollectorPlugin: Plugin<{}, NotificationCollectorStorage> = { if (alertDiv) { alertDiv.textContent = notificationCount.toString(); } else { - console.info("[BetterSEQTA+] No notifications currently"); + verboseInfo("[BetterSEQTA+] No notifications currently"); } } catch (error) { console.error("[BetterSEQTA+] Error fetching notifications:", error); diff --git a/src/plugins/built-in/themes/theme-manager.ts b/src/plugins/built-in/themes/theme-manager.ts index 492315df..33b5c7e9 100644 --- a/src/plugins/built-in/themes/theme-manager.ts +++ b/src/plugins/built-in/themes/theme-manager.ts @@ -17,6 +17,12 @@ import { clearCustomThemeAdaptiveCssVariables, setCustomThemeAdaptiveCssVariables, } from "@/seqta/ui/colors/customThemeAdaptiveBindings"; +import { + clearThemeInPage, + syncThemeToPage, + type ThemePageSyncInput, +} from "@/seqta/utils/patchThemeImagesPageContext"; +import { verboseDebug, verboseInfo } from "@/utils/verboseLog"; import { clearThemeRuntime, injectThemeDom, @@ -56,18 +62,15 @@ export type InstallThemeMeta = { export class ThemeManager { private static instance: ThemeManager; private currentTheme: CustomTheme | null = null; - private styleElement: HTMLStyleElement | null = null; - private previewStyleElement: HTMLStyleElement | null = null; private previousImageVariableNames: string[] = []; + private lastSyncedImageKey: string | null = null; private originalPreviewColor: string | null = null; private originalPreviewTheme: boolean | null = null; - private imageUrlCache: Map = new Map(); private lastTransitionPoint: { x: number; y: number } = { x: 0, y: 0 }; private storeUpdateCheckRunning = false; - private headObserver: MutationObserver | null = null; private constructor() { - console.debug("[ThemeManager] Initializing..."); + verboseDebug("[ThemeManager] Initializing..."); } public static getInstance(): ThemeManager { @@ -88,7 +91,7 @@ export class ThemeManager { * Get a theme by ID from storage */ public async getTheme(themeId: string): Promise { - console.debug("[ThemeManager] Getting theme:", themeId); + verboseDebug("[ThemeManager] Getting theme:", themeId); try { const theme = (await localforage.getItem(themeId)) as CustomTheme; return theme; @@ -164,17 +167,17 @@ export class ThemeManager { * Disable the current theme without deleting it */ public async disableTheme(): Promise { - console.debug("[ThemeManager] Disabling current theme"); + verboseDebug("[ThemeManager] Disabling current theme"); try { if (!this.currentTheme) { - console.debug("[ThemeManager] No theme to disable"); + verboseDebug("[ThemeManager] No theme to disable"); return; } await this.removeTheme(this.currentTheme); this.currentTheme = null; settingsState.selectedTheme = ""; - console.debug("[ThemeManager] Theme disabled successfully"); + verboseDebug("[ThemeManager] Theme disabled successfully"); } catch (error) { console.error("[ThemeManager] Error disabling theme:", error); } @@ -211,7 +214,7 @@ export class ThemeManager { * Initialize the theme system and restore previous state */ public async initialize(): Promise { - console.debug("[ThemeManager] Starting initialization"); + verboseDebug("[ThemeManager] Starting initialization"); try { const neumorphicThemeId = "9a9786d1-b5fc-4a91-8c7a-f8bf7f7679ad"; const migrationCSS = "#title {\nbackground: transparent !important;\n}"; @@ -224,7 +227,7 @@ export class ThemeManager { const themeCreatorOpen = localStorage.getItem("themeCreatorOpen"); if (themeCreatorOpen === "true") { - console.debug( + verboseDebug( "[ThemeManager] Theme creator was open, clearing preview state", ); this.clearPreview(); @@ -232,7 +235,7 @@ export class ThemeManager { } if (settingsState.selectedTheme) { - console.debug( + verboseDebug( "[ThemeManager] Found selected theme, restoring:", settingsState.selectedTheme, ); @@ -249,7 +252,7 @@ export class ThemeManager { * Clean up theme system resources */ public async cleanup(): Promise { - console.debug("[ThemeManager] Cleaning up resources"); + verboseDebug("[ThemeManager] Cleaning up resources"); try { if (this.currentTheme) { await this.removeTheme(this.currentTheme, false); @@ -263,7 +266,7 @@ export class ThemeManager { * Set and apply a theme by ID */ public async setTheme(themeId: string, applyViewTransition: boolean = true): Promise { - console.debug("[ThemeManager] Setting theme:", themeId); + verboseDebug("[ThemeManager] Setting theme:", themeId); try { const theme = (await localforage.getItem(themeId)) as CustomTheme; if (!theme) { @@ -273,7 +276,7 @@ export class ThemeManager { // Store original settings before applying new theme if (!settingsState.selectedTheme) { - console.debug("[ThemeManager] Storing original settings"); + verboseDebug("[ThemeManager] Storing original settings"); settingsState.originalSelectedColor = settingsState.selectedColor; if (shouldForceThemeAppearance(theme)) { @@ -286,7 +289,7 @@ export class ThemeManager { await this.applyViewTransition(async () => { // Remove current theme if exists if (this.currentTheme) { - console.debug("[ThemeManager] Removing current theme"); + verboseDebug("[ThemeManager] Removing current theme"); await this.removeThemeWithoutTransition(this.currentTheme); } @@ -298,7 +301,7 @@ export class ThemeManager { } else { // Remove current theme if exists if (this.currentTheme) { - console.debug("[ThemeManager] Removing current theme"); + verboseDebug("[ThemeManager] Removing current theme"); await this.removeThemeWithoutTransition(this.currentTheme); } @@ -317,7 +320,7 @@ export class ThemeManager { * Apply theme components (CSS, images, settings) */ private async applyTheme(theme: CustomTheme): Promise { - console.debug("[ThemeManager] Applying theme:", theme.name); + verboseDebug("[ThemeManager] Applying theme:", theme.name); try { // Run the theme script BEFORE injecting CustomCSS so any state the // script publishes (e.g. `data-city-state` and `--city-sky-color` for @@ -326,40 +329,34 @@ export class ThemeManager { // its previous state before snapping to the right colour. runThemeScript(theme.themeScript); - // Apply custom CSS - if (theme.CustomCSS) { - console.debug("[ThemeManager] Applying custom CSS"); - this.applyCustomCSS(theme.CustomCSS); - } - - // Apply custom images - if (theme.CustomImages) { - console.debug("[ThemeManager] Applying custom images"); - theme.CustomImages.forEach((image) => { - const imageUrl = URL.createObjectURL(image.blob); - document.documentElement.style.setProperty( - "--" + image.variableName, - `url(${imageUrl})`, - ); - }); + // Custom CSS + images must be applied in page context (Firefox). + verboseDebug("[ThemeManager] Applying theme styles in page context"); + await syncThemeToPage({ + customCss: theme.CustomCSS || "", + images: theme.CustomImages ?? [], + }); + if (theme.CustomImages?.length) { + this.lastSyncedImageKey = this.imageSyncKey(theme.CustomImages); + } else { + this.lastSyncedImageKey = null; } // Apply theme settings if (shouldForceThemeAppearance(theme)) { const dark = getForcedDarkMode(theme); - console.debug("[ThemeManager] Setting dark mode:", dark); + verboseDebug("[ThemeManager] Setting dark mode:", dark); settingsState.DarkMode = dark; } // Use the stored selected color if available, otherwise use the default if (theme.selectedColor) { - console.debug( + verboseDebug( "[ThemeManager] Restoring saved color:", theme.selectedColor, ); settingsState.selectedColor = theme.selectedColor; } else if (theme.defaultColour) { - console.debug( + verboseDebug( "[ThemeManager] Using default color:", theme.defaultColour, ); @@ -381,7 +378,7 @@ export class ThemeManager { theme: CustomTheme, clearSelectedTheme: boolean = true, ): Promise { - console.debug("[ThemeManager] Removing theme with transition:", theme.name); + verboseDebug("[ThemeManager] Removing theme with transition:", theme.name); try { await this.applyViewTransition(async () => { await this.removeThemeWithoutTransition(theme, clearSelectedTheme); @@ -398,37 +395,13 @@ export class ThemeManager { theme: CustomTheme, clearSelectedTheme: boolean = true, ): Promise { - console.debug("[ThemeManager] Removing theme:", theme.name); + verboseDebug("[ThemeManager] Removing theme:", theme.name); try { clearThemeRuntime(); - // Disconnect the head observer BEFORE removing the style element, - // otherwise the removal fires the observer and it would no-op only - // because the style is already gone — wasted work, but harmless. - this.disconnectStyleObserver(); - - // Remove custom CSS - if (this.styleElement) { - console.debug("[ThemeManager] Removing custom CSS"); - this.styleElement.remove(); - this.styleElement = null; - } - - // Remove custom images - if (theme.CustomImages) { - console.debug("[ThemeManager] Removing custom images"); - theme.CustomImages.forEach((image) => { - const value = document.documentElement.style.getPropertyValue( - "--" + image.variableName, - ); - if (value) { - URL.revokeObjectURL(value.slice(4, -1)); // Remove url() wrapper - } - document.documentElement.style.removeProperty( - "--" + image.variableName, - ); - }); - } + verboseDebug("[ThemeManager] Removing theme page styles"); + clearThemeInPage(); + this.lastSyncedImageKey = null; if (this.currentTheme) { // Store the current color with the theme before removing it @@ -449,7 +422,7 @@ export class ThemeManager { // Restore original settings if (settingsState.originalSelectedColor) { - console.debug( + verboseDebug( "[ThemeManager] Restoring original color:", settingsState.originalSelectedColor, ); @@ -457,7 +430,7 @@ export class ThemeManager { } if (settingsState.originalDarkMode !== undefined) { - console.debug( + verboseDebug( "[ThemeManager] Restoring original dark mode:", settingsState.originalDarkMode, ); @@ -476,58 +449,21 @@ export class ThemeManager { } /** - * Apply custom CSS to the document. The `