From 9899c902a596813a543be89b1c90a4fc31a136ce Mon Sep 17 00:00:00 2001 From: MagellaX Date: Tue, 28 Oct 2025 13:35:43 +0530 Subject: [PATCH] refactor: use adapters for chat hosts in extension --- .../content/adapters/platform-adapter.ts | 17 ++++++ .../entrypoints/content/chatgpt.ts | 9 ++++ .../entrypoints/content/claude.ts | 8 +++ .../entrypoints/content/index.ts | 54 +++++++++---------- 4 files changed, 61 insertions(+), 27 deletions(-) create mode 100644 apps/browser-extension/entrypoints/content/adapters/platform-adapter.ts diff --git a/apps/browser-extension/entrypoints/content/adapters/platform-adapter.ts b/apps/browser-extension/entrypoints/content/adapters/platform-adapter.ts new file mode 100644 index 00000000..15229306 --- /dev/null +++ b/apps/browser-extension/entrypoints/content/adapters/platform-adapter.ts @@ -0,0 +1,17 @@ +export interface PlatformAdapter { + /** + * Unique identifier for the adapter. Useful for debugging and telemetry. + */ + readonly id: string + + /** + * Determines whether this adapter should run for the current page. + */ + matches(): boolean + + /** + * Performs any one-time setup. Implementations should be idempotent. + */ + init(): void +} + diff --git a/apps/browser-extension/entrypoints/content/chatgpt.ts b/apps/browser-extension/entrypoints/content/chatgpt.ts index 73e0354f..cca01fd3 100644 --- a/apps/browser-extension/entrypoints/content/chatgpt.ts +++ b/apps/browser-extension/entrypoints/content/chatgpt.ts @@ -10,6 +10,7 @@ import { createChatGPTInputBarElement, DOMUtils, } from "../../utils/ui-components" +import type { PlatformAdapter } from "./adapters/platform-adapter" let chatGPTDebounceTimeout: NodeJS.Timeout | null = null let chatGPTRouteObserver: MutationObserver | null = null @@ -38,6 +39,7 @@ export function initializeChatGPT() { document.body.setAttribute("data-chatgpt-initialized", "true") } + function setupChatGPTRouteChangeDetection() { if (chatGPTRouteObserver) { chatGPTRouteObserver.disconnect() @@ -254,6 +256,13 @@ function addSupermemoryButtonToMemoriesDialog() { ) } +export const chatGPTAdapter: PlatformAdapter = { + id: "chatgpt", + matches: () => DOMUtils.isOnDomain(DOMAINS.CHATGPT), + init: initializeChatGPT, +} + + async function saveMemoriesToSupermemory() { try { DOMUtils.showToast("loading") diff --git a/apps/browser-extension/entrypoints/content/claude.ts b/apps/browser-extension/entrypoints/content/claude.ts index e0853d41..51e712a9 100644 --- a/apps/browser-extension/entrypoints/content/claude.ts +++ b/apps/browser-extension/entrypoints/content/claude.ts @@ -10,6 +10,7 @@ import { createClaudeInputBarElement, DOMUtils, } from "../../utils/ui-components" +import type { PlatformAdapter } from "./adapters/platform-adapter" let claudeDebounceTimeout: NodeJS.Timeout | null = null let claudeRouteObserver: MutationObserver | null = null @@ -589,6 +590,13 @@ function setupClaudePromptCapture() { ) } +export const claudeAdapter: PlatformAdapter = { + id: "claude", + matches: () => DOMUtils.isOnDomain(DOMAINS.CLAUDE), + init: initializeClaude, +} + + async function setupClaudeAutoFetch() { const result = await chrome.storage.local.get([ STORAGE_KEYS.AUTO_SEARCH_ENABLED, diff --git a/apps/browser-extension/entrypoints/content/index.ts b/apps/browser-extension/entrypoints/content/index.ts index a79f50fb..bf186d8f 100644 --- a/apps/browser-extension/entrypoints/content/index.ts +++ b/apps/browser-extension/entrypoints/content/index.ts @@ -1,7 +1,7 @@ import { DOMAINS, MESSAGE_TYPES } from "../../utils/constants" import { DOMUtils } from "../../utils/ui-components" -import { initializeChatGPT } from "./chatgpt" -import { initializeClaude } from "./claude" +import { chatGPTAdapter } from "./chatgpt" +import { claudeAdapter } from "./claude" import { saveMemory, setupGlobalKeyboardShortcut, setupStorageListener } from "./shared" import { initializeT3 } from "./t3" import { handleTwitterNavigation, initializeTwitter, updateTwitterImportUI } from "./twitter" @@ -28,40 +28,40 @@ export default defineContentScript({ // Setup storage listener setupStorageListener() - // Observer for dynamic content changes - const observeForDynamicChanges = () => { - const observer = new MutationObserver(() => { - if (DOMUtils.isOnDomain(DOMAINS.CHATGPT)) { - initializeChatGPT() - } - if (DOMUtils.isOnDomain(DOMAINS.CLAUDE)) { - initializeClaude() - } - if (DOMUtils.isOnDomain(DOMAINS.T3)) { - initializeT3() - } - if (DOMUtils.isOnDomain(DOMAINS.TWITTER)) { - handleTwitterNavigation() + const platformAdapters = [chatGPTAdapter, claudeAdapter] + + const runPlatformAdapters = () => { + platformAdapters.forEach((adapter) => { + if (adapter.matches()) { + adapter.init() } }) + if (DOMUtils.isOnDomain(DOMAINS.T3)) { + initializeT3() + } + + if (DOMUtils.isOnDomain(DOMAINS.TWITTER)) { + handleTwitterNavigation() + } + } + + runPlatformAdapters() + initializeTwitter() + + const observer = new MutationObserver(runPlatformAdapters) + const startObserving = () => observer.observe(document.body, { childList: true, subtree: true, }) - } - // Initialize platform-specific functionality - initializeChatGPT() - initializeClaude() - initializeT3() - initializeTwitter() - - // Start observing for dynamic changes if (document.readyState === "loading") { - document.addEventListener("DOMContentLoaded", observeForDynamicChanges) + document.addEventListener("DOMContentLoaded", startObserving, { + once: true, + }) } else { - observeForDynamicChanges() + startObserving() } }, -}) \ No newline at end of file +})