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}
+
+{/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}
-

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)}
-
})
+
{/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 `