mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-08-28 17:21:05 +00:00
fix(global search): CSS preload killed plugin load
This commit is contained in:
@@ -7,7 +7,10 @@ import {
|
||||
} from "../../core/settingsHelpers";
|
||||
import { isSeqtaEngageExperience } from "@/seqta/utils/isSeqtaEngage";
|
||||
import styles from "./src/core/styles.css?inline";
|
||||
import { resetSearchIndexes } from "./src/indexing/resetIndexes";
|
||||
import {
|
||||
resetSearchIndexes,
|
||||
notifyOpenTabsResetSearchIndex,
|
||||
} from "./src/indexing/resetIndexes";
|
||||
|
||||
// Platform-aware default hotkey
|
||||
const getDefaultHotkey = () => {
|
||||
@@ -52,9 +55,7 @@ const settings = defineSettings({
|
||||
if (!confirmed) return;
|
||||
|
||||
try {
|
||||
// `resetSearchIndexes` is a tiny statically-imported helper: no
|
||||
// dynamic chunks to chase, so the button keeps working even when
|
||||
// the settings page has been open across an extension update.
|
||||
await notifyOpenTabsResetSearchIndex();
|
||||
await resetSearchIndexes();
|
||||
alert(
|
||||
"Search index and storage were reset.\n\nReload this tab to regenerate the index.",
|
||||
|
||||
@@ -11,6 +11,8 @@ import { verboseDebug, verboseInfo, verboseLog } from "@/utils/verboseLog";
|
||||
import styles from "./styles.css?inline";
|
||||
import { waitForElm } from "@/seqta/utils/waitForElm";
|
||||
import { runIndexing, ensureSchemaCurrent } from "../indexing/indexer";
|
||||
import { installResetIndexMessageListener } from "../indexing/resetIndexes";
|
||||
import { isIndexingPaused } from "../indexing/indexingPause";
|
||||
import { initVectorSearch } from "../search/vector/vectorSearch";
|
||||
import { cleanupSearchBar, mountSearchBar } from "./mountSearchBar";
|
||||
import { IndexedDbManager } from "embeddia";
|
||||
@@ -168,6 +170,8 @@ const globalSearchPlugin: Plugin<typeof settings> = {
|
||||
run: async (api) => {
|
||||
const appRef = { current: null };
|
||||
|
||||
installResetIndexMessageListener();
|
||||
|
||||
// Run the version check BEFORE we open any IndexedDB connections.
|
||||
// On a normal load (no version change) this is just a string compare
|
||||
// and a manifest read, so the cost is negligible. On a real update,
|
||||
@@ -287,8 +291,9 @@ const globalSearchPlugin: Plugin<typeof settings> = {
|
||||
}
|
||||
}
|
||||
|
||||
if (api.settings.runIndexingOnLoad) {
|
||||
if (api.settings.runIndexingOnLoad && !isIndexingPaused()) {
|
||||
setTimeout(async () => {
|
||||
if (isIndexingPaused()) return;
|
||||
await runIndexing();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ export async function mountSearchBar(
|
||||
});
|
||||
|
||||
try {
|
||||
const { default: renderSvelte } = await import("@/interface/main");
|
||||
const { default: renderSvelte } = await import("@/interface/renderInShadow");
|
||||
appRef.current = renderSvelte(SearchBar, searchRootShadow, {
|
||||
transparencyEffects: api.settings.transparencyEffects ? true : false,
|
||||
showRecentFirst: api.settings.showRecentFirst,
|
||||
|
||||
@@ -7,6 +7,7 @@ import { loadDynamicItems } from "../utils/dynamicItems";
|
||||
import { getVectorizedItemIds, pruneOrphanVectorEmbeddings } from "./utils";
|
||||
import { INDEX_SCHEMA_VERSION, SCHEMA_VERSION_KEY } from "./schemaVersion";
|
||||
import { resetSearchIndexes } from "./resetIndexes";
|
||||
import { isIndexingPaused } from "./indexingPause";
|
||||
|
||||
import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog';
|
||||
const META_STORE = "meta";
|
||||
@@ -252,8 +253,19 @@ export async function loadAllStoredItems(): Promise<IndexItem[]> {
|
||||
}
|
||||
|
||||
export async function runIndexing(): Promise<void> {
|
||||
if (isIndexingPaused()) {
|
||||
verboseDebug(
|
||||
"[Indexer] Skipping indexing — index was reset; reload the page to rebuild.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await ensureSchemaCurrent();
|
||||
|
||||
if (isIndexingPaused()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(await acquireLock())) {
|
||||
verboseDebug(
|
||||
"%c[Indexer] Could not acquire lock - another tab is indexing or this tab is already indexing",
|
||||
@@ -272,6 +284,19 @@ export async function runIndexing(): Promise<void> {
|
||||
dispatchProgress(completedJobs, totalSteps, true, "Starting jobs");
|
||||
|
||||
for (const jobId of jobIds) {
|
||||
if (isIndexingPaused()) {
|
||||
verboseDebug(
|
||||
"[Indexer] Indexing stopped — index was reset; reload the page to rebuild.",
|
||||
);
|
||||
dispatchProgress(
|
||||
completedJobs,
|
||||
totalSteps,
|
||||
false,
|
||||
"Indexing paused — reload to rebuild",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
dispatchProgress(
|
||||
completedJobs,
|
||||
totalSteps,
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/** In-memory gate: after a manual reset, skip indexing until the tab reloads. */
|
||||
let pausedUntilReload = false;
|
||||
|
||||
export function pauseIndexingUntilReload(): void {
|
||||
pausedUntilReload = true;
|
||||
}
|
||||
|
||||
export function isIndexingPaused(): boolean {
|
||||
return pausedUntilReload;
|
||||
}
|
||||
@@ -395,7 +395,7 @@ export const messagesJob: Job = {
|
||||
progress.totalEstimated = await estimateMessageCount();
|
||||
|
||||
try {
|
||||
await vectorWorker.startStreamingSession(
|
||||
progress.streamingStarted = await vectorWorker.startStreamingSession(
|
||||
progress.totalEstimated,
|
||||
(progressData) => {
|
||||
verboseLog(
|
||||
@@ -405,10 +405,11 @@ export const messagesJob: Job = {
|
||||
RATE_LIMIT_CONFIG.vectorBatchSize,
|
||||
"messages",
|
||||
);
|
||||
progress.streamingStarted = true;
|
||||
verboseLog(
|
||||
`[Messages job] Started streaming vectorization session for ~${progress.totalEstimated} items`,
|
||||
);
|
||||
if (progress.streamingStarted) {
|
||||
verboseLog(
|
||||
`[Messages job] Started streaming vectorization session for ~${progress.totalEstimated} items`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
"[Messages job] Failed to start streaming session:",
|
||||
|
||||
@@ -199,7 +199,7 @@ export const notificationsJob: Job = {
|
||||
const estimatedTotal = Math.min(notifications.length * 1.2, 100);
|
||||
|
||||
try {
|
||||
await vectorWorker.startStreamingSession(
|
||||
progress.streamingStarted = await vectorWorker.startStreamingSession(
|
||||
estimatedTotal,
|
||||
(progressData) => {
|
||||
verboseLog(
|
||||
@@ -209,10 +209,11 @@ export const notificationsJob: Job = {
|
||||
NOTIFICATIONS_RATE_LIMIT.vectorBatchSize,
|
||||
"notifications",
|
||||
);
|
||||
progress.streamingStarted = true;
|
||||
verboseLog(
|
||||
`[Notifications job] Started streaming vectorization session for ~${estimatedTotal} items`,
|
||||
);
|
||||
if (progress.streamingStarted) {
|
||||
verboseLog(
|
||||
`[Notifications job] Started streaming vectorization session for ~${estimatedTotal} items`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
"[Notifications job] Failed to start streaming session:",
|
||||
|
||||
@@ -10,6 +10,7 @@ import { verboseDebug, verboseInfo, verboseLog } from "@/utils/verboseLog";
|
||||
import { isSensitiveSeqtaPath, normalizeSeqtaPath } from "./api";
|
||||
import { mergeDynamicItems } from "../utils/dynamicItems";
|
||||
import { decorateIndexItems } from "./renderComponents";
|
||||
import { isIndexingPaused } from "./indexingPause";
|
||||
|
||||
/**
|
||||
* Passive network observer.
|
||||
@@ -380,7 +381,7 @@ function synthesizeItems(
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
async function persistItems(items: IndexItem[]): Promise<void> {
|
||||
if (items.length === 0) return;
|
||||
if (items.length === 0 || isIndexingPaused()) return;
|
||||
|
||||
// Dedupe against existing entries. We replace on collision so the latest
|
||||
// observation wins (e.g. if a message changes title).
|
||||
@@ -401,16 +402,27 @@ async function persistItems(items: IndexItem[]): Promise<void> {
|
||||
}
|
||||
|
||||
function scheduleFlush() {
|
||||
if (pendingFlush) return;
|
||||
if (pendingFlush || isIndexingPaused()) return;
|
||||
pendingFlush = setTimeout(() => {
|
||||
pendingFlush = null;
|
||||
if (!pendingDirty) return;
|
||||
if (!pendingDirty || isIndexingPaused()) return;
|
||||
pendingDirty = false;
|
||||
void flushDynamicItems();
|
||||
}, FLUSH_DEBOUNCE_MS);
|
||||
}
|
||||
|
||||
/** Drop queued passive captures after a manual index reset. */
|
||||
export function pausePassiveObserver(): void {
|
||||
pendingChangedItems.clear();
|
||||
pendingDirty = false;
|
||||
if (pendingFlush) {
|
||||
clearTimeout(pendingFlush);
|
||||
pendingFlush = null;
|
||||
}
|
||||
}
|
||||
|
||||
async function flushDynamicItems(): Promise<void> {
|
||||
if (isIndexingPaused()) return;
|
||||
if (pendingChangedItems.size === 0) return;
|
||||
|
||||
const rawChanged = Array.from(pendingChangedItems.values());
|
||||
|
||||
@@ -1,4 +1,48 @@
|
||||
import { SCHEMA_VERSION_KEY } from "./schemaVersion";
|
||||
import { pauseIndexingUntilReload } from "./indexingPause";
|
||||
import { pausePassiveObserver } from "./passiveObserver";
|
||||
import browser from "webextension-polyfill";
|
||||
|
||||
export const RESET_INDEX_MESSAGE = "global-search-reset-index";
|
||||
|
||||
let resetMessageListenerInstalled = false;
|
||||
|
||||
/** Notify open SEQTA tabs to pause indexing and wipe page-origin stores. */
|
||||
export async function notifyOpenTabsResetSearchIndex(): Promise<void> {
|
||||
const tabs = await browser.tabs.query({});
|
||||
await Promise.allSettled(
|
||||
tabs.map((tab) =>
|
||||
tab.id != null
|
||||
? browser.tabs.sendMessage(tab.id, { type: RESET_INDEX_MESSAGE })
|
||||
: Promise.resolve(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/** Content scripts: handle reset broadcast from the settings popup. */
|
||||
export function installResetIndexMessageListener(): void {
|
||||
if (resetMessageListenerInstalled) return;
|
||||
resetMessageListenerInstalled = true;
|
||||
|
||||
browser.runtime.onMessage.addListener((message) => {
|
||||
if (message?.type !== RESET_INDEX_MESSAGE) return;
|
||||
pauseIndexingUntilReload();
|
||||
pausePassiveObserver();
|
||||
if (typeof window !== "undefined") {
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("indexing-progress", {
|
||||
detail: {
|
||||
completed: 0,
|
||||
total: 0,
|
||||
indexing: false,
|
||||
status: "Indexing paused — reload to rebuild",
|
||||
},
|
||||
}),
|
||||
);
|
||||
}
|
||||
void resetSearchIndexes();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Hard-reset of all global-search persistence.
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import { EmbeddingIndex, getEmbedding, initializeModel } from "embeddia";
|
||||
import type { IndexItem } from "../types";
|
||||
|
||||
import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog';
|
||||
import { verboseDebug, verboseInfo, verboseLog } from "./workerVerboseLog";
|
||||
|
||||
let ortWasmBase: string | null = null;
|
||||
|
||||
async function configureOrtWasm(base: string): Promise<void> {
|
||||
const { env } = await import("@huggingface/transformers");
|
||||
env.backends.onnx.wasm = env.backends.onnx.wasm ?? {};
|
||||
env.backends.onnx.wasm.wasmPaths = base.endsWith("/") ? base : `${base}/`;
|
||||
}
|
||||
let vectorIndex: EmbeddingIndex | null = null;
|
||||
let isInitialized = false;
|
||||
let initializationFailed = false;
|
||||
@@ -49,6 +57,9 @@ async function initWorker() {
|
||||
|
||||
verboseDebug("Initializing vector worker...");
|
||||
try {
|
||||
if (ortWasmBase) {
|
||||
await configureOrtWasm(ortWasmBase);
|
||||
}
|
||||
await initializeModel();
|
||||
vectorIndex = new EmbeddingIndex([]);
|
||||
|
||||
@@ -562,6 +573,9 @@ self.addEventListener("message", async (e) => {
|
||||
|
||||
switch (type) {
|
||||
case "init":
|
||||
if (data?.ortWasmBase) {
|
||||
ortWasmBase = data.ortWasmBase;
|
||||
}
|
||||
await initWorker();
|
||||
self.postMessage({ type: "ready" });
|
||||
break;
|
||||
@@ -594,13 +608,3 @@ self.addEventListener("message", async (e) => {
|
||||
console.warn("Unknown message type:", type);
|
||||
}
|
||||
});
|
||||
|
||||
initWorker()
|
||||
.then(() => {
|
||||
self.postMessage({ type: "ready" });
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error("Initial worker initialization failed:", err);
|
||||
|
||||
self.postMessage({ type: "ready" });
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { refreshVectorCache } from "../../search/vector/vectorSearch";
|
||||
import type { IndexItem } from "../types";
|
||||
import { isVectorSearchSupported } from "../../utils/browserDetection";
|
||||
import { getOrtWasmBaseUrl } from "@/lib/transformersExtension";
|
||||
import vectorWorker from "./vectorWorker.ts?inlineWorker";
|
||||
|
||||
import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog';
|
||||
@@ -91,7 +92,7 @@ export class VectorWorkerManager {
|
||||
this.isInitialized = false;
|
||||
|
||||
reject(new Error("Worker initialization timed out"));
|
||||
}, 10000);
|
||||
}, 60000);
|
||||
|
||||
this.worker!.addEventListener("message", (e) => {
|
||||
const { type, data } = e.data;
|
||||
@@ -158,7 +159,10 @@ export class VectorWorkerManager {
|
||||
}
|
||||
});
|
||||
|
||||
this.worker!.postMessage({ type: "init" });
|
||||
this.worker!.postMessage({
|
||||
type: "init",
|
||||
data: { ortWasmBase: getOrtWasmBaseUrl() },
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -388,7 +392,7 @@ export class VectorWorkerManager {
|
||||
onProgress?: ProgressCallback,
|
||||
batchSize: number = 10,
|
||||
jobId?: string,
|
||||
): Promise<void> {
|
||||
): Promise<boolean> {
|
||||
// Skip if vector search is not supported
|
||||
if (!isVectorSearchSupported()) {
|
||||
verboseDebug("[VectorWorker] Vector search not supported - skipping streaming session");
|
||||
@@ -398,13 +402,13 @@ export class VectorWorkerManager {
|
||||
message: "Vector search not available - using text search only",
|
||||
});
|
||||
}
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only initialize if we expect items to process
|
||||
if (totalExpectedItems === 0) {
|
||||
verboseDebug("[VectorWorker] No items expected, not starting streaming session");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
await this.ensureReady();
|
||||
@@ -419,7 +423,7 @@ export class VectorWorkerManager {
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
} else {
|
||||
verboseDebug(`Streaming session for job ${jobId} already active`);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,13 +459,20 @@ export class VectorWorkerManager {
|
||||
message: `Starting streaming vectorization for ${jobId}`,
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async streamItems(items: IndexItem[]): Promise<void> {
|
||||
if (!isVectorSearchSupported()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.streamingSession?.isActive) {
|
||||
throw new Error(
|
||||
"No active streaming session. Call startStreamingSession first.",
|
||||
verboseDebug(
|
||||
"[VectorWorker] streamItems skipped — no active streaming session",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const uniqueItems = items.filter((item, index, arr) => {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/** Worker-safe logging — no webextension-polyfill or SettingsState. */
|
||||
|
||||
export function verboseDebug(...args: unknown[]): void {
|
||||
if (typeof console !== "undefined") console.debug(...args);
|
||||
}
|
||||
|
||||
export function verboseInfo(...args: unknown[]): void {
|
||||
if (typeof console !== "undefined") console.info(...args);
|
||||
}
|
||||
|
||||
export function verboseLog(...args: unknown[]): void {
|
||||
if (typeof console !== "undefined") console.log(...args);
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { EmbeddingIndex, getEmbedding, initializeModel } from "embeddia";
|
||||
import type { IndexItem } from "../../indexing/types";
|
||||
import type { SearchResult } from "embeddia";
|
||||
import { isVectorSearchSupported } from "../../utils/browserDetection";
|
||||
import { ensureTransformersEnv } from "@/lib/transformersExtension";
|
||||
|
||||
import { verboseDebug, verboseInfo, verboseLog } from '@/utils/verboseLog';
|
||||
let vectorIndex: EmbeddingIndex | null = null;
|
||||
@@ -24,6 +25,7 @@ export async function initVectorSearch() {
|
||||
initializationAttempted = true;
|
||||
|
||||
try {
|
||||
await ensureTransformersEnv();
|
||||
await initializeModel();
|
||||
vectorIndex = new EmbeddingIndex([]);
|
||||
vectorIndex.preloadIndexedDB();
|
||||
|
||||
Reference in New Issue
Block a user