@addfox/rsbuild-plugin-extension-hmr 0.1.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/hmr/cleanup.ts","../src/constants.ts","../src/hmr/disable.ts","../src/browser/runner.ts","../src/browser/paths.ts","../src/server/ws-server.ts","../src/manager/extension.ts","../src/browser/web-ext-console-stream-hook.ts","../src/browser/launcher.ts","../src/hmr/rspack-plugin.ts","../src/hmr/scope.ts","../src/server/test-server.ts","../src/index.ts"],"sourcesContent":["import { resolve } from \"path\";\r\nimport { readdir, rm } from \"node:fs/promises\";\r\n\r\ntype StatsLike = { toJson?: (opts?: unknown) => { assets?: { name?: string }[] } } & {\r\n hasErrors?: () => boolean;\r\n};\r\n\r\nexport function collectHotUpdateAssetNames(statsList: unknown[]): Set<string> {\r\n const names = new Set<string>();\r\n for (const s of statsList) {\r\n const stats = s as StatsLike;\r\n if (!stats || typeof stats.toJson !== \"function\") continue;\r\n const json = stats.toJson({ all: false, assets: true }) as {\r\n assets?: { name?: string }[];\r\n };\r\n if (!json?.assets) continue;\r\n for (const asset of json.assets) {\r\n const name = asset?.name;\r\n if (typeof name === \"string\" && name.includes(\".hot-update.\")) {\r\n names.add(name);\r\n }\r\n }\r\n }\r\n return names;\r\n}\r\n\r\nexport async function removeStaleHotUpdateFiles(\r\n distPath: string,\r\n keepNames: Set<string>\r\n): Promise<void> {\r\n let entries;\r\n try {\r\n entries = await readdir(distPath, { withFileTypes: true });\r\n } catch {\r\n return;\r\n }\r\n for (const entry of entries) {\r\n const full = resolve(distPath, entry.name);\r\n if (entry.isDirectory()) {\r\n await removeStaleHotUpdateFiles(full, keepNames);\r\n continue;\r\n }\r\n if (!entry.name.includes(\".hot-update.\")) continue;\r\n const rel = full.slice(distPath.length + 1).replace(/\\\\/g, \"/\");\r\n if (!keepNames.has(entry.name) && !keepNames.has(rel)) {\r\n await rm(full, { force: true }).catch(() => {});\r\n }\r\n }\r\n}\r\n\r\nexport async function clearOutdatedHotUpdateFiles(\r\n distPath: string,\r\n stats: unknown\r\n): Promise<void> {\r\n if (!distPath) return;\r\n const rootStats = stats as { stats?: unknown[] } & StatsLike;\r\n if (rootStats?.hasErrors?.()) return;\r\n const list: unknown[] =\r\n rootStats && \"stats\" in rootStats && Array.isArray(rootStats.stats)\r\n ? rootStats.stats\r\n : [stats];\r\n const keepNames = collectHotUpdateAssetNames(list);\r\n if (keepNames.size === 0) return;\r\n await removeStaleHotUpdateFiles(distPath, keepNames);\r\n}\r\n","/**\r\n * Entry names and HMR snippets used across the HMR plugin.\r\n * RELOAD_MANAGER_ENTRY_NAMES comes from @addfox/core (single source of truth).\r\n */\r\n\r\nimport { RELOAD_MANAGER_ENTRY_NAMES } from \"@addfox/core\";\r\n\r\n/** Entry names that require chrome.runtime.reload() when changed (background). */\r\nexport const RELOAD_ENTRY_NAMES = new Set<string>([\"background\"]);\r\n\r\n/** Entry names injected into pages; when changed, reload manager refreshes active tab. */\r\nexport const CONTENT_ENTRY_NAMES = new Set<string>([\"content\"]);\r\n\r\n/** Injected at top of entry module for precise identification; only content/background. */\r\nexport const ADDFOX_ENTRY_TAG_PREFIX = \"/* addfox-entry:\";\r\n\r\n/** Build entry tag comment for a given entry name (content/background). Used for precise entry identification in built output. */\r\nexport function getEntryTag(entryName: string): string {\r\n return RELOAD_MANAGER_ENTRY_NAMES.has(entryName)\r\n ? `${ADDFOX_ENTRY_TAG_PREFIX}${entryName} */`\r\n : \"\";\r\n}\r\n\r\n/** Prepended to content/background entry modules: force full invalidation so reload is via reloadManager only. */\r\nexport const HMR_INVALIDATE_PREPEND =\r\n \"if(typeof module!=='undefined'&&module.hot){module.hot.invalidate();}\\n\";\r\n","import { resolve } from \"path\";\r\nimport { getEntryTag, HMR_INVALIDATE_PREPEND } from \"../constants\";\r\nimport type { ReloadManagerEntry } from \"@addfox/core\";\r\n\r\n// ==================== Path Utilities ====================\r\n\r\n/** Cache for normalized paths to avoid repeated resolve operations */\r\nconst pathCache = new Map<string, string>();\r\n\r\nexport function normalizePathForCompare(p: string): string {\r\n const cached = pathCache.get(p);\r\n if (cached) return cached;\r\n \r\n const normalized = resolve(p).replace(/\\\\/g, \"/\");\r\n pathCache.set(p, normalized);\r\n return normalized;\r\n}\r\n\r\n/** Clear the path cache (useful for testing or memory management) */\r\nexport function clearPathCache(): void {\r\n pathCache.clear();\r\n}\r\n\r\n// ==================== Entry Matching ====================\r\n\r\nfunction createPathComparer(resourcePath: string): {\r\n normalized: string;\r\n matches: (entryPath: string) => boolean;\r\n} {\r\n const normalized = normalizePathForCompare(resourcePath);\r\n return {\r\n normalized,\r\n matches: (entryPath: string) => normalizePathForCompare(entryPath) === normalized,\r\n };\r\n}\r\n\r\nfunction findEntryByPath<T extends { path: string }>(\r\n resourcePath: string,\r\n entries: T[]\r\n): T | undefined {\r\n const comparer = createPathComparer(resourcePath);\r\n return entries.find(e => comparer.matches(e.path));\r\n}\r\n\r\n// ==================== Type Guards ====================\r\n\r\nfunction isReloadManagerEntryList(\r\n v: unknown[]\r\n): v is ReloadManagerEntry[] {\r\n return v.length > 0 && \r\n typeof v[0] === \"object\" && \r\n v[0] !== null && \r\n \"path\" in v[0];\r\n}\r\n\r\n// ==================== Code Transformation ====================\r\n\r\n/**\r\n * Converts string paths to ReloadManagerEntry objects with empty names.\r\n */\r\nfunction normalizeEntries(\r\n entriesOrPaths: ReloadManagerEntry[] | string[]\r\n): ReloadManagerEntry[] {\r\n if (isReloadManagerEntryList(entriesOrPaths)) {\r\n return entriesOrPaths;\r\n }\r\n return (entriesOrPaths as string[]).map(path => ({ name: \"\", path }));\r\n}\r\n\r\n/**\r\n * Builds the transformed code by prepending entry tag and HMR invalidate.\r\n */\r\nfunction buildTransformedCode(entryName: string, originalCode: string): string {\r\n const tag = entryName ? getEntryTag(entryName) : \"\";\r\n const parts: string[] = [];\r\n \r\n if (tag) parts.push(tag);\r\n parts.push(HMR_INVALIDATE_PREPEND, originalCode);\r\n \r\n return parts.join(\"\\n\");\r\n}\r\n\r\n/**\r\n * Transforms content/background entry modules:\r\n * - Injects entry tag comment (addfox-entry:content / addfox-entry:background) at top when entries have names.\r\n * - Prepends module.hot.invalidate() so reload is via reloadManager only.\r\n */\r\nexport function transformCodeToDisableHmr(\r\n resourcePath: string,\r\n entriesOrPaths: ReloadManagerEntry[] | string[],\r\n code: string\r\n): string {\r\n if (entriesOrPaths.length === 0) return code;\r\n \r\n const entries = normalizeEntries(entriesOrPaths);\r\n const matchingEntry = findEntryByPath(resourcePath, entries);\r\n \r\n if (!matchingEntry) return code;\r\n \r\n return buildTransformedCode(matchingEntry.name, code);\r\n}\r\n","import {\r\n Launcher as ChromeLauncher,\r\n launch as defaultChromiumLaunch,\r\n} from \"chrome-launcher\";\r\nimport type { LaunchedChrome } from \"chrome-launcher\";\r\nimport { error as addfoxError } from \"@addfox/common\";\r\n\r\nconst EXCLUDED_CHROME_FLAGS = [\r\n \"--disable-extensions\",\r\n \"--mute-audio\",\r\n \"--disable-component-update\",\r\n];\r\n\r\nconst DEFAULT_CHROME_FLAGS = ChromeLauncher.defaultFlags().filter(\r\n (flag) => !EXCLUDED_CHROME_FLAGS.includes(flag)\r\n);\r\n\r\ntype DeferredResponse = {\r\n method: string;\r\n resolve: (result: unknown) => void;\r\n reject: (error: Error) => void;\r\n};\r\n\r\ntype ChromiumInstance = LaunchedChrome & {\r\n remoteDebuggingPipes: {\r\n incoming: NodeJS.ReadableStream & { closed?: boolean };\r\n outgoing: NodeJS.WritableStream;\r\n } | null;\r\n};\r\n\r\nclass ChromeDevtoolsProtocolClient {\r\n private receivedData = \"\";\r\n private isProcessing = false;\r\n private lastId = 0;\r\n private deferredResponses = new Map<number, DeferredResponse>();\r\n private disconnected = false;\r\n private resolveDisconnected!: () => void;\r\n private disconnectedPromise = new Promise<void>((resolve) => {\r\n this.resolveDisconnected = resolve;\r\n });\r\n private outgoingPipe: NodeJS.WritableStream;\r\n\r\n constructor(chromiumInstance: ChromiumInstance) {\r\n const pipes = chromiumInstance.remoteDebuggingPipes;\r\n if (!pipes) {\r\n throw new Error(\"remoteDebuggingPipes is not available\");\r\n }\r\n const { incoming, outgoing } = pipes;\r\n this.outgoingPipe = outgoing;\r\n if (incoming.closed) {\r\n this.finalizeDisconnect();\r\n return;\r\n }\r\n incoming.on(\"data\", (data) => this.onIncomingData(data));\r\n incoming.on(\"error\", (error) => this.handleIncomingError(error));\r\n incoming.on(\"close\", () => this.finalizeDisconnect());\r\n }\r\n\r\n waitUntilDisconnected(): Promise<void> {\r\n return this.disconnectedPromise;\r\n }\r\n\r\n async sendCommand(\r\n method: string,\r\n params: Record<string, unknown> = {},\r\n sessionId?: string\r\n ): Promise<unknown> {\r\n this.ensureConnected(method);\r\n const message = this.buildMessage(method, params, sessionId);\r\n return this.sendMessage(message);\r\n }\r\n\r\n private ensureConnected(method: string): void {\r\n if (!this.disconnected) return;\r\n throw new Error(`CDP disconnected, cannot send: command ${method}`);\r\n }\r\n\r\n private buildMessage(\r\n method: string,\r\n params: Record<string, unknown>,\r\n sessionId?: string\r\n ): { id: number; method: string; rawMessage: string } {\r\n const id = ++this.lastId;\r\n const message = { id, method, params, sessionId };\r\n const rawMessage = `${JSON.stringify(message)}\\x00`;\r\n return { id, method, rawMessage };\r\n }\r\n\r\n private sendMessage(message: { id: number; method: string; rawMessage: string }) {\r\n return new Promise((resolve, reject) => {\r\n this.deferredResponses.set(message.id, {\r\n method: message.method,\r\n resolve,\r\n reject,\r\n });\r\n this.outgoingPipe.write(message.rawMessage);\r\n });\r\n }\r\n\r\n private onIncomingData(data: Buffer): void {\r\n this.receivedData += data;\r\n this.processNextMessage();\r\n }\r\n\r\n private handleIncomingError(err: unknown): void {\r\n addfoxError(err);\r\n this.finalizeDisconnect();\r\n }\r\n\r\n private processNextMessage(): void {\r\n if (this.isProcessing) return;\r\n this.isProcessing = true;\r\n let end = this.receivedData.indexOf(\"\\x00\");\r\n while (end !== -1) {\r\n const rawMessage = this.receivedData.slice(0, end);\r\n this.receivedData = this.receivedData.slice(end + 1);\r\n this.handleRawMessage(rawMessage);\r\n end = this.receivedData.indexOf(\"\\x00\");\r\n }\r\n this.isProcessing = false;\r\n if (this.disconnected) this.resolvePending();\r\n }\r\n\r\n private handleRawMessage(rawMessage: string): void {\r\n const parsed = this.parseMessage(rawMessage);\r\n if (!parsed) return;\r\n const { id, error, result } = parsed;\r\n const deferred = this.deferredResponses.get(id);\r\n if (!deferred) return;\r\n this.deferredResponses.delete(id);\r\n if (error) deferred.reject(new Error(error.message || \"Unexpected CDP response\"));\r\n else deferred.resolve(result);\r\n }\r\n\r\n private parseMessage(rawMessage: string): { id: number; error?: { message?: string }; result?: unknown } | null {\r\n try {\r\n return JSON.parse(rawMessage);\r\n } catch (e) {\r\n addfoxError(e);\r\n return null;\r\n }\r\n }\r\n\r\n private finalizeDisconnect(): void {\r\n if (this.disconnected) return;\r\n this.disconnected = true;\r\n this.processNextMessage();\r\n }\r\n\r\n private resolvePending(): void {\r\n for (const { method, reject } of this.deferredResponses.values()) {\r\n reject(new Error(`CDP connection closed before response to ${method}`));\r\n }\r\n this.deferredResponses.clear();\r\n this.resolveDisconnected();\r\n }\r\n}\r\n\r\nexport type ChromiumRunnerOptions = {\r\n chromePath: string;\r\n extensions: string[];\r\n startUrl?: string;\r\n userDataDir?: string;\r\n args?: string[];\r\n verbose?: boolean;\r\n onExit?: () => void;\r\n};\r\n\r\nclass ChromiumExtensionRunner {\r\n private chromiumLaunch;\r\n private options: ChromiumRunnerOptions;\r\n private chromiumInstance: ChromiumInstance | null = null;\r\n private cdp: ChromeDevtoolsProtocolClient | null = null;\r\n private forceUseDeprecatedLoadExtension = false;\r\n private exiting = false;\r\n private setupPromise: Promise<void> | null = null;\r\n\r\n constructor(\r\n options: ChromiumRunnerOptions,\r\n chromiumLaunch = defaultChromiumLaunch\r\n ) {\r\n this.options = options;\r\n this.chromiumLaunch = chromiumLaunch;\r\n }\r\n\r\n async run(): Promise<void> {\r\n this.setupPromise = this.setupInstance();\r\n await this.setupPromise;\r\n }\r\n\r\n async exit(): Promise<void> {\r\n this.exiting = true;\r\n await this.awaitSetup();\r\n await this.killInstance();\r\n await this.disconnectCdp();\r\n }\r\n\r\n private async awaitSetup(): Promise<void> {\r\n if (!this.setupPromise) return;\r\n await this.setupPromise.catch((err) => {\r\n console.debug(`ignored setup error on chromium runner shutdown: ${err}`);\r\n });\r\n }\r\n\r\n private async setupInstance(): Promise<void> {\r\n const chromeFlags = buildChromeFlags({\r\n extensions: this.options.extensions,\r\n args: this.options.args,\r\n useDeprecatedLoadExtension: this.forceUseDeprecatedLoadExtension,\r\n });\r\n const instance = await this.launchChrome(chromeFlags);\r\n this.attachInstance(instance);\r\n const loaded = await this.loadExtensions();\r\n if (!loaded) {\r\n await this.fallbackToDeprecatedLoad(instance);\r\n return;\r\n }\r\n }\r\n\r\n private async launchChrome(chromeFlags: string[]): Promise<ChromiumInstance> {\r\n return this.chromiumLaunch({\r\n chromePath: this.options.chromePath,\r\n chromeFlags,\r\n startingUrl: this.options.startUrl,\r\n userDataDir: this.options.userDataDir,\r\n logLevel: this.options.verbose ? \"verbose\" : \"silent\",\r\n ignoreDefaultFlags: true,\r\n });\r\n }\r\n\r\n private attachInstance(instance: ChromiumInstance): void {\r\n this.chromiumInstance = instance;\r\n this.cdp = new ChromeDevtoolsProtocolClient(instance);\r\n this.listenToProcessClose(instance);\r\n }\r\n\r\n private listenToProcessClose(instance: ChromiumInstance): void {\r\n const initial = instance;\r\n instance.process.once(\"close\", () => {\r\n if (this.chromiumInstance !== initial) return;\r\n this.chromiumInstance = null;\r\n if (this.options.onExit) this.options.onExit();\r\n if (!this.exiting) this.exit().catch(() => {});\r\n });\r\n }\r\n\r\n private async loadExtensions(): Promise<boolean> {\r\n if (!this.cdp) return false;\r\n if (this.forceUseDeprecatedLoadExtension) return true;\r\n return this.loadExtensionsViaCdp(this.cdp, this.options.extensions);\r\n }\r\n\r\n private async loadExtensionsViaCdp(\r\n cdp: ChromeDevtoolsProtocolClient,\r\n extensions: string[]\r\n ): Promise<boolean> {\r\n for (const sourceDir of extensions) {\r\n const result = await this.tryLoadExtension(cdp, sourceDir);\r\n if (result === \"unsupported\") return false;\r\n }\r\n return true;\r\n }\r\n\r\n private async tryLoadExtension(\r\n cdp: ChromeDevtoolsProtocolClient,\r\n sourceDir: string\r\n ): Promise<\"ok\" | \"unsupported\"> {\r\n try {\r\n await cdp.sendCommand(\"Extensions.loadUnpacked\", { path: sourceDir });\r\n return \"ok\";\r\n } catch (e) {\r\n if (isLoadUnpackedUnsupported(e)) return \"unsupported\";\r\n addfoxError(\"Failed to load extension at\", sourceDir, String(e));\r\n throw e;\r\n }\r\n }\r\n\r\n private async fallbackToDeprecatedLoad(instance: ChromiumInstance): Promise<void> {\r\n this.forceUseDeprecatedLoadExtension = true;\r\n this.chromiumInstance = null;\r\n await instance.kill();\r\n await this.disconnectCdp();\r\n await this.setupInstance();\r\n }\r\n\r\n private async disconnectCdp(): Promise<void> {\r\n if (!this.cdp) return;\r\n await this.cdp.waitUntilDisconnected();\r\n this.cdp = null;\r\n }\r\n\r\n private async killInstance(): Promise<void> {\r\n if (!this.chromiumInstance) return;\r\n await this.chromiumInstance.kill();\r\n this.chromiumInstance = null;\r\n }\r\n}\r\n\r\nfunction isLoadUnpackedUnsupported(error: unknown): boolean {\r\n return error instanceof Error && error.message === \"'Extensions.loadUnpacked' wasn't found\";\r\n}\r\n\r\nfunction buildChromeFlags(options: {\r\n extensions: string[];\r\n args?: string[];\r\n useDeprecatedLoadExtension: boolean;\r\n}): string[] {\r\n const flags = [...DEFAULT_CHROME_FLAGS, \"--remote-debugging-pipe\"];\r\n if (options.useDeprecatedLoadExtension) {\r\n flags.push(`--load-extension=${options.extensions.join(\",\")}`);\r\n } else {\r\n flags.push(\"--enable-unsafe-extension-debugging\");\r\n }\r\n if (options.args?.length) flags.push(...options.args);\r\n return flags;\r\n}\r\n\r\nexport async function runChromiumRunner(\r\n options: ChromiumRunnerOptions\r\n): Promise<{ exit: () => Promise<void> }> {\r\n const runner = new ChromiumExtensionRunner(options);\r\n await runner.run();\r\n return { exit: () => runner.exit() };\r\n}\r\n","import { resolve } from \"path\";\r\nimport { existsSync } from \"node:fs\";\r\nimport type { LaunchTarget, ChromiumLaunchTarget } from \"@addfox/core\";\r\n\r\ntype PlatformPaths = Record<string, string[]>;\r\n\r\nconst BROWSER_DEFAULT_PATHS: Record<LaunchTarget, PlatformPaths> = {\r\n chrome: {\r\n win32: [\r\n \"C:\\\\Program Files\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe\",\r\n \"C:\\\\Program Files (x86)\\\\Google\\\\Chrome\\\\Application\\\\chrome.exe\",\r\n ],\r\n darwin: [\"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\"],\r\n linux: [\"/usr/bin/google-chrome\", \"/usr/bin/google-chrome-stable\", \"/usr/bin/chromium\", \"/usr/bin/chromium-browser\"],\r\n },\r\n chromium: {\r\n win32: [\r\n \"C:\\\\Program Files\\\\Chromium\\\\Application\\\\chrome.exe\",\r\n \"C:\\\\Program Files (x86)\\\\Chromium\\\\Application\\\\chrome.exe\",\r\n ],\r\n darwin: [\"/Applications/Chromium.app/Contents/MacOS/Chromium\"],\r\n linux: [\"/usr/bin/chromium\", \"/usr/bin/chromium-browser\", \"/usr/bin/google-chrome\", \"/usr/bin/google-chrome-stable\"],\r\n },\r\n edge: {\r\n win32: [\r\n \"C:\\\\Program Files\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe\",\r\n \"C:\\\\Program Files (x86)\\\\Microsoft\\\\Edge\\\\Application\\\\msedge.exe\",\r\n ],\r\n darwin: [\"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge\"],\r\n linux: [\"/usr/bin/microsoft-edge\", \"/usr/bin/microsoft-edge-stable\"],\r\n },\r\n brave: {\r\n win32: [\r\n \"C:\\\\Program Files\\\\BraveSoftware\\\\Brave-Browser\\\\Application\\\\brave.exe\",\r\n \"C:\\\\Program Files (x86)\\\\BraveSoftware\\\\Brave-Browser\\\\Application\\\\brave.exe\",\r\n ],\r\n darwin: [\"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser\"],\r\n linux: [\"/usr/bin/brave-browser\", \"/usr/bin/brave\"],\r\n },\r\n vivaldi: {\r\n win32: [\r\n \"C:\\\\Program Files\\\\Vivaldi\\\\Application\\\\vivaldi.exe\",\r\n \"C:\\\\Program Files (x86)\\\\Vivaldi\\\\Application\\\\vivaldi.exe\",\r\n ],\r\n darwin: [\"/Applications/Vivaldi.app/Contents/MacOS/Vivaldi\"],\r\n linux: [\"/usr/bin/vivaldi-stable\", \"/usr/bin/vivaldi\"],\r\n },\r\n opera: {\r\n win32: [\r\n \"C:\\\\Program Files\\\\Opera\\\\launcher.exe\",\r\n \"C:\\\\Program Files (x86)\\\\Opera\\\\launcher.exe\",\r\n ],\r\n darwin: [\"/Applications/Opera.app/Contents/MacOS/Opera\"],\r\n linux: [\"/usr/bin/opera\", \"/usr/bin/opera-stable\"],\r\n },\r\n santa: {\r\n win32: [\r\n \"C:\\\\Program Files\\\\Santa Browser\\\\Application\\\\Santa Browser.exe\",\r\n \"C:\\\\Program Files (x86)\\\\Santa Browser\\\\Application\\\\Santa Browser.exe\",\r\n ],\r\n darwin: [\"/Applications/Santa Browser.app/Contents/MacOS/Santa Browser\"],\r\n linux: [\"/usr/bin/santa-browser\"],\r\n },\r\n arc: {\r\n win32: [\r\n \"C:\\\\Program Files\\\\Arc\\\\Application\\\\Arc.exe\",\r\n \"C:\\\\Program Files (x86)\\\\Arc\\\\Application\\\\Arc.exe\",\r\n ],\r\n darwin: [\"/Applications/Arc.app/Contents/MacOS/Arc\"],\r\n linux: [\"/usr/bin/arc\", \"/opt/Arc/arc\"],\r\n },\r\n yandex: {\r\n win32: [\r\n \"C:\\\\Program Files\\\\Yandex\\\\YandexBrowser\\\\Application\\\\browser.exe\",\r\n \"C:\\\\Program Files (x86)\\\\Yandex\\\\YandexBrowser\\\\Application\\\\browser.exe\",\r\n ],\r\n darwin: [\"/Applications/Yandex.app/Contents/MacOS/Yandex\"],\r\n linux: [\"/usr/bin/yandex-browser\", \"/opt/yandex/browser/browser\"],\r\n },\r\n browseros: {\r\n win32: [\r\n \"C:\\\\Program Files\\\\BrowserOS\\\\BrowserOS.exe\",\r\n \"C:\\\\Program Files (x86)\\\\BrowserOS\\\\BrowserOS.exe\",\r\n ],\r\n darwin: [\"/Applications/BrowserOS.app/Contents/MacOS/BrowserOS\"],\r\n linux: [\"/usr/bin/browseros\", \"/opt/BrowserOS/browseros\"],\r\n },\r\n custom: { win32: [], darwin: [], linux: [] },\r\n firefox: {\r\n win32: [\r\n \"C:\\\\Program Files\\\\Mozilla Firefox\\\\firefox.exe\",\r\n \"C:\\\\Program Files (x86)\\\\Mozilla Firefox\\\\firefox.exe\",\r\n ],\r\n darwin: [\"/Applications/Firefox.app/Contents/MacOS/firefox\"],\r\n linux: [\"/usr/bin/firefox\", \"/usr/bin/firefox-esr\"],\r\n },\r\n};\r\n\r\nexport type LaunchPathOptions = Pick<\r\n Record<string, string | undefined>,\r\n \"chromePath\" | \"chromiumPath\" | \"edgePath\" | \"bravePath\" | \"vivaldiPath\" | \"operaPath\" | \"santaPath\" | \"arcPath\" | \"yandexPath\" | \"browserosPath\" | \"customPath\" | \"firefoxPath\"\r\n>;\r\n\r\nexport function getLaunchPathFromOptions(browser: LaunchTarget, options: LaunchPathOptions): string | undefined {\r\n const map: Record<LaunchTarget, string | undefined> = {\r\n chrome: options.chromePath,\r\n chromium: options.chromiumPath,\r\n edge: options.edgePath,\r\n brave: options.bravePath,\r\n vivaldi: options.vivaldiPath,\r\n opera: options.operaPath,\r\n santa: options.santaPath,\r\n arc: options.arcPath,\r\n yandex: options.yandexPath,\r\n browseros: options.browserosPath,\r\n custom: options.customPath,\r\n firefox: options.firefoxPath,\r\n };\r\n return map[browser];\r\n}\r\n\r\nexport function buildDefaultPaths(browser: LaunchTarget, platform: string): string[] | undefined {\r\n const basePaths = BROWSER_DEFAULT_PATHS[browser]?.[platform];\r\n if (platform === \"win32\") {\r\n const userProfile = process.env.USERPROFILE;\r\n const localAppData = process.env.LOCALAPPDATA;\r\n if (browser === \"vivaldi\" && userProfile) {\r\n return [resolve(userProfile, \"AppData\\\\Local\\\\Vivaldi\\\\Application\\\\vivaldi.exe\"), ...(basePaths ?? [])];\r\n }\r\n if (browser === \"arc\" && localAppData) {\r\n return [resolve(localAppData, \"Programs\\\\Arc\\\\Application\\\\Arc.exe\"), ...(basePaths ?? [])];\r\n }\r\n if (browser === \"yandex\" && localAppData) {\r\n return [resolve(localAppData, \"Yandex\\\\YandexBrowser\\\\Application\\\\browser.exe\"), ...(basePaths ?? [])];\r\n }\r\n }\r\n return basePaths;\r\n}\r\n\r\nexport function getBrowserPath(browser: LaunchTarget, options: LaunchPathOptions): string | null {\r\n const userPath = getLaunchPathFromOptions(browser, options);\r\n if (userPath != null && userPath.trim() !== \"\") return userPath.trim();\r\n const paths = buildDefaultPaths(browser, process.platform);\r\n if (!paths || paths.length === 0) {\r\n if (browser === \"chromium\") return getBrowserPath(\"chrome\", options);\r\n return null;\r\n }\r\n for (const p of paths) {\r\n if (existsSync(p)) return p;\r\n }\r\n if (browser === \"chromium\") return getBrowserPath(\"chrome\", options);\r\n return null;\r\n}\r\n\r\nexport function isChromiumBrowser(browser: LaunchTarget): browser is ChromiumLaunchTarget {\r\n return browser !== \"firefox\";\r\n}\r\n","import { createServer } from \"node:http\";\r\nimport { join } from \"node:path\";\r\nimport { mkdir, unlink, writeFile } from \"node:fs/promises\";\r\nimport { existsSync } from \"node:fs\";\r\nimport { WebSocketServer, WebSocket } from \"ws\";\r\nimport { logDone, logDoneTimed, writeExtensionErrorBlock } from \"@addfox/common\";\r\nimport { detectFrontendFramework } from \"@addfox/core\";\r\nimport type { ReloadKind } from \"../hmr/scope\";\r\n\r\nlet wsServer: WebSocketServer | null = null;\r\nlet httpServer: ReturnType<typeof createServer> | null = null;\r\n\r\n/** Stored when startWebSocketServer is called with debug opts; used by error handler. */\r\nlet debugServerOpts: DebugServerOpts | null = null;\r\n\r\n/** `full`: WebSocket + HTTP (reload + /addfox-error). `httpOnly`: HTTP only for monitor errors (Firefox / debug without Chromium reload). */\r\nexport type WsServerMode = \"full\" | \"httpOnly\";\r\n\r\nexport type ExtensionErrorPayload = {\r\n entry?: string;\r\n type?: string;\r\n message?: string;\r\n stack?: string;\r\n filename?: string;\r\n lineno?: number;\r\n colno?: number;\r\n time?: number;\r\n};\r\n\r\nexport type DebugServerOpts = {\r\n debug?: boolean;\r\n root?: string;\r\n outputRoot?: string;\r\n distPath?: string;\r\n};\r\n\r\nfunction getBundlerLine(): string {\r\n return \"bundler: rsbuild\";\r\n}\r\n\r\nfunction getFrameworkLine(root: string | undefined): string {\r\n const name = root ? detectFrontendFramework(root) : \"Vanilla\";\r\n return `front-end-framework: ${name}`;\r\n}\r\n\r\nexport function buildExtensionErrorLines(\r\n payload: ExtensionErrorPayload,\r\n opts?: DebugServerOpts | null\r\n): string[] {\r\n const entry = typeof payload.entry === \"string\" && payload.entry.trim() ? payload.entry.trim() : \"unknown\";\r\n const errorType = typeof payload.type === \"string\" && payload.type.trim() ? payload.type.trim() : \"error\";\r\n const timeStr =\r\n payload.time != null && Number.isFinite(Number(payload.time))\r\n ? new Date(Number(payload.time)).toLocaleString()\r\n : new Date().toLocaleString();\r\n const message = payload.message != null ? String(payload.message) : \"Unknown error\";\r\n const stack = payload.stack && String(payload.stack).trim() ? String(payload.stack).trim() : \"\";\r\n const filename = payload.filename ? String(payload.filename) : \"\";\r\n const lineno = payload.lineno != null && Number.isFinite(Number(payload.lineno)) ? Number(payload.lineno) : undefined;\r\n const colno = payload.colno != null && Number.isFinite(Number(payload.colno)) ? payload.colno : undefined;\r\n const loc = filename ? (filename + (lineno != null ? `:${lineno}` : \"\") + (colno != null ? `:${colno}` : \"\")) : \"\";\r\n const aiPromptLines = buildAiPromptForExtensionRuntimeError().split(\"\\n\");\r\n const lines: string[] = [\r\n ...aiPromptLines,\r\n \"--- Addfox extension error ---\",\r\n getBundlerLine(),\r\n getFrameworkLine(opts?.root),\r\n `entry: ${entry}`,\r\n `type: ${errorType}`,\r\n `time: ${timeStr}`,\r\n `message: ${message}`,\r\n ];\r\n if (loc) lines.push(`location: ${loc}`);\r\n if (stack) lines.push(\"stack:\", ...stack.split(\"\\n\"));\r\n lines.push(\"---------------------------\");\r\n return lines;\r\n}\r\n\r\nfunction logExtensionErrorToTerminal(payload: ExtensionErrorPayload, opts: DebugServerOpts | null): void {\r\n writeExtensionErrorBlock(buildExtensionErrorLines(payload, opts));\r\n}\r\n\r\nfunction buildErrorMarkdown(payload: ExtensionErrorPayload, root?: string): string {\r\n const entry = typeof payload.entry === \"string\" && payload.entry.trim() ? payload.entry.trim() : \"unknown\";\r\n const errorType = typeof payload.type === \"string\" && payload.type.trim() ? payload.type.trim() : \"error\";\r\n const timeStr =\r\n payload.time != null && Number.isFinite(Number(payload.time))\r\n ? new Date(Number(payload.time)).toLocaleString()\r\n : new Date().toLocaleString();\r\n const message = payload.message != null ? String(payload.message) : \"Unknown error\";\r\n const stack = payload.stack && String(payload.stack).trim() ? String(payload.stack).trim() : \"\";\r\n const filename = payload.filename ? String(payload.filename) : \"\";\r\n const lineno = payload.lineno != null && Number.isFinite(Number(payload.lineno)) ? payload.lineno : undefined;\r\n const colno = payload.colno != null && Number.isFinite(Number(payload.colno)) ? payload.colno : undefined;\r\n const loc = filename ? (filename + (lineno != null ? `:${lineno}` : \"\") + (colno != null ? `:${colno}` : \"\")) : \"\";\r\n const frameworkName = root ? detectFrontendFramework(root) : \"Vanilla\";\r\n\r\n // Keep markdown output stable: terminal gets the new AI prompt, but error.md keeps the original ai_context.\r\n const aiContext = [\r\n \"---\",\r\n \"ai_context: addfox_extension_error_report\",\r\n \"description: Runtime error from the browser extension\",\r\n \"when_to_use:\",\r\n \" - User reports extension not working / crashes\",\r\n \" - Console errors in extension context\",\r\n \" - Entry-specific failures (popup/background/content errors)\",\r\n \" - Errors after successful build (runtime vs build issues)\",\r\n \"structure:\",\r\n \" - Error summary: entry, type, message, location\",\r\n \" - Build context: bundler and framework info\",\r\n \" - Stack trace: Full error stack for debugging\",\r\n \"related_files:\",\r\n \" - llms.txt: Project AI guide (read first if new to project)\",\r\n \" - meta.md: Entry configurations and build outputs\",\r\n \"note: This file is cleared on dev server restart\",\r\n \"---\",\r\n ].join(\"\\n\");\r\n\r\n const summary = [\r\n \"## Error Summary\",\r\n \"\",\r\n \"| Field | Value |\",\r\n \"|-------|-------|\",\r\n `| Entry | \\`${entry}\\` |`,\r\n `| Type | \\`${errorType}\\` |`,\r\n `| Time | ${timeStr} |`,\r\n `| Message | ${message} |`,\r\n ];\r\n\r\n if (loc) {\r\n summary.push(`| Location | \\`${loc}\\` |`);\r\n }\r\n\r\n summary.push(\"\", \"## Build Context\", \"\", `- **Bundler**: rsbuild`, `- **Framework**: ${frameworkName}`);\r\n\r\n const parts: string[] = [aiContext, \"\", ...summary];\r\n\r\n if (stack) {\r\n parts.push(\"\", \"## Stack Trace\", \"\", \"```\", stack, \"```\");\r\n }\r\n\r\n return parts.join(\"\\n\");\r\n}\r\n\r\nexport function buildAiPromptForExtensionRuntimeError(): string {\r\n // Intentionally kept as a single string block so downstream AI tools\r\n // can treat it as a \"prompt\" with minimal parsing.\r\n return [\r\n \"--- BEGIN AI PROMPT ---\",\r\n \"You are a frontend and browser extension development expert, proficient with the Addfox framework.\",\r\n \"This is an Addfox-based browser extension runtime error (MV3).\",\r\n \"\",\r\n \"Before proposing fixes:\",\r\n \"1) Read `.addfox/llms.txt` first.\",\r\n \"2) Apply the `addfox-debugging` skills to analyze this report (and `.addfox/error.md` / `.addfox/meta.md` if available).\",\r\n \"--- END AI PROMPT ---\",\r\n ].join(\"\\n\");\r\n}\r\n\r\nfunction getErrorMdPath(root: string, outputRoot: string): string {\r\n return join(root, outputRoot, \"error.md\");\r\n}\r\n\r\nfunction deleteErrorMdOnStart(root: string, outputRoot: string): void {\r\n const path = getErrorMdPath(root, outputRoot);\r\n if (!existsSync(path)) return;\r\n unlink(path).catch(() => {});\r\n}\r\n\r\nfunction writeErrorMdAsync(\r\n root: string,\r\n outputRoot: string,\r\n payload: ExtensionErrorPayload\r\n): void {\r\n const dir = join(root, outputRoot);\r\n const path = getErrorMdPath(root, outputRoot);\r\n const content = buildErrorMarkdown(payload, root);\r\n queueMicrotask(async () => {\r\n try {\r\n await mkdir(dir, { recursive: true });\r\n await writeFile(path, content, \"utf-8\");\r\n } catch {\r\n /* ignore */\r\n }\r\n });\r\n}\r\n\r\nfunction handleHttpRequest(\r\n req: import(\"node:http\").IncomingMessage,\r\n res: import(\"node:http\").ServerResponse\r\n): void {\r\n // Allow extension pages (chrome-extension:// / moz-extension://) to post errors.\r\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\r\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type\");\r\n res.setHeader(\"Access-Control-Allow-Methods\", \"POST, OPTIONS\");\r\n if (req.method === \"OPTIONS\" && req.url === \"/addfox-error\") {\r\n res.writeHead(204).end();\r\n return;\r\n }\r\n if (req.method === \"POST\" && req.url === \"/addfox-error\") {\r\n let body = \"\";\r\n req.setEncoding(\"utf8\");\r\n req.on(\"data\", (chunk: string) => { body += chunk; });\r\n req.on(\"end\", () => {\r\n try {\r\n const payload = JSON.parse(body) as ExtensionErrorPayload;\r\n if (payload && (payload.entry != null || payload.message != null)) {\r\n const opts = debugServerOpts;\r\n logExtensionErrorToTerminal(payload, opts);\r\n if (opts?.debug && opts.root && opts.outputRoot) {\r\n writeErrorMdAsync(opts.root, opts.outputRoot, payload);\r\n }\r\n }\r\n } catch { /* ignore */ }\r\n res.writeHead(204).end();\r\n });\r\n return;\r\n }\r\n res.writeHead(404).end();\r\n}\r\n\r\nfunction bindHttpListen(\r\n server: ReturnType<typeof createServer>,\r\n port: number\r\n): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n server.once(\"error\", reject);\r\n server.listen(port, () => {\r\n server.off(\"error\", reject);\r\n resolve();\r\n });\r\n });\r\n}\r\n\r\nasync function startHttpServerOnly(\r\n port: number,\r\n startTime: number,\r\n opts: DebugServerOpts | null\r\n): Promise<void> {\r\n debugServerOpts = opts ?? null;\r\n if (opts?.debug && opts.root && opts.outputRoot) {\r\n deleteErrorMdOnStart(opts.root, opts.outputRoot);\r\n }\r\n const t0 = startTime;\r\n httpServer = createServer(handleHttpRequest);\r\n await bindHttpListen(httpServer, port);\r\n const ms = Math.round(performance.now() - t0);\r\n logDoneTimed(\"Addfox debug HTTP (errors): http://127.0.0.1:\" + port + \"/addfox-error\", ms);\r\n}\r\n\r\nexport async function startWebSocketServer(\r\n port: number,\r\n startTime?: number,\r\n opts?: DebugServerOpts,\r\n mode: WsServerMode = \"full\"\r\n): Promise<WebSocketServer | null> {\r\n if (mode === \"httpOnly\") {\r\n if (httpServer || wsServer) return null;\r\n await startHttpServerOnly(port, startTime ?? performance.now(), opts ?? null);\r\n return null;\r\n }\r\n if (wsServer) return wsServer;\r\n debugServerOpts = opts ?? null;\r\n if (opts?.debug && opts.root && opts.outputRoot) {\r\n deleteErrorMdOnStart(opts.root, opts.outputRoot);\r\n }\r\n const t0 = startTime ?? performance.now();\r\n httpServer = createServer(handleHttpRequest);\r\n wsServer = new WebSocketServer({ server: httpServer });\r\n wsServer.on(\"connection\", (ws: WebSocket) => {\r\n if (ws.readyState === WebSocket.OPEN) ws.send(\"connected\");\r\n });\r\n await bindHttpListen(httpServer, port);\r\n const ms = Math.round(performance.now() - t0);\r\n logDoneTimed(\"Hot reload WebSocket: ws://127.0.0.1:\" + port, ms);\r\n return wsServer;\r\n}\r\n\r\nexport type { ReloadKind } from \"../hmr/scope\";\r\n\r\nexport function notifyReload(kind: ReloadKind): void {\r\n if (!wsServer) return;\r\n wsServer.clients.forEach((client: WebSocket) => {\r\n if (client.readyState === WebSocket.OPEN) client.send(kind);\r\n });\r\n logDone(\"hotreload success\", kind, new Date().toLocaleString());\r\n}\r\n\r\nexport function closeWebSocketServer(): void {\r\n debugServerOpts = null;\r\n if (wsServer) {\r\n wsServer.close();\r\n wsServer = null;\r\n }\r\n if (httpServer) {\r\n httpServer.close();\r\n httpServer = null;\r\n }\r\n}\r\n","import { resolve, sep } from \"path\";\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport type { ChromiumLaunchTarget } from \"@addfox/core\";\n\n/** Cache directory for browser profiles */\nconst BROWSER_PROFILE_DIR = \"browser-profile\";\nconst DEFAULT_OUTPUT_ROOT = \".addfox\";\n\nfunction splitPathSegments(path: string): string[] {\n return resolve(path)\n .split(/[\\\\/]+/)\n .filter(Boolean);\n}\n\nfunction resolveCacheRootByOutputRoot(distPath: string, outputRoot: string): string | null {\n const rootName = outputRoot.replace(/^[/\\\\]+|[/\\\\]+$/g, \"\");\n if (!rootName) return null;\n\n const parts = splitPathSegments(distPath);\n const rootIndex = parts.lastIndexOf(rootName);\n if (rootIndex < 0) return null;\n\n const prefix = parts.slice(0, rootIndex + 1).join(sep);\n const hasDrivePrefix = /^[a-zA-Z]:$/.test(parts[0] ?? \"\");\n const normalizedPrefix = hasDrivePrefix ? prefix : `${sep}${prefix}`;\n return resolve(normalizedPrefix, \"cache\");\n}\n\n/** Get the cache root directory (parent of distPath/cache) */\nexport function getCacheRoot(distPath: string, outputRoot = DEFAULT_OUTPUT_ROOT): string {\n const resolved = resolveCacheRootByOutputRoot(distPath, outputRoot);\n if (resolved) return resolved;\n return resolve(distPath, \"..\", \"cache\");\n}\n\n/** Get the browser profile directory path */\nexport function getBrowserProfileDir(distPath: string, outputRoot = DEFAULT_OUTPUT_ROOT): string {\n return resolve(getCacheRoot(distPath, outputRoot), BROWSER_PROFILE_DIR);\n}\n\n/** @deprecated Use getBrowserProfileDir instead */\nexport function getCacheTempRoot(distPath: string, outputRoot = DEFAULT_OUTPUT_ROOT): string {\n return getBrowserProfileDir(distPath, outputRoot);\n}\n\nexport function getChromiumUserDataDir(\n distPath: string,\n browser: ChromiumLaunchTarget,\n outputRoot = DEFAULT_OUTPUT_ROOT\n): string {\n return resolve(getBrowserProfileDir(distPath, outputRoot), `${browser}-user-data`);\n}\n\nexport function getReloadManagerPath(distPath: string, outputRoot = DEFAULT_OUTPUT_ROOT): string {\n return resolve(getCacheRoot(distPath, outputRoot), \"reload-manager-extension\");\n}\n\nexport function findExistingReloadManager(distPath: string, outputRoot = DEFAULT_OUTPUT_ROOT): string | null {\n const cacheRoot = getCacheRoot(distPath, outputRoot);\n if (!existsSync(cacheRoot)) return null;\n const extPath = getReloadManagerPath(distPath, outputRoot);\n const manifestPath = resolve(extPath, \"manifest.json\");\n const bgPath = resolve(extPath, \"bg.js\");\n if (existsSync(manifestPath) && existsSync(bgPath)) return extPath;\n return null;\n}\n\nconst RELOAD_MANAGER_SCRIPT_VERSION = 3;\n\nexport async function ensureDistReady(distPath: string, timeoutMs = 15000): Promise<boolean> {\n const { statSync } = await import(\"node:fs\");\n const manifestPath = resolve(distPath, \"manifest.json\");\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n if (existsSync(manifestPath) && statSync(manifestPath).size > 0) return true;\n await new Promise((r) => setTimeout(r, 300));\n }\n throw new Error(`dist not ready: ${manifestPath}`);\n}\n\nexport async function createReloadManagerExtension(wsPort: number, distPath: string): Promise<string> {\n const extPath = getReloadManagerPath(distPath);\n const bgJsPath = resolve(extPath, \"bg.js\");\n const portCachePath = resolve(extPath, \".port-cache\");\n const scriptVersionPath = resolve(extPath, \".script-version\");\n let needsUpdate = true;\n if (existsSync(portCachePath) && existsSync(scriptVersionPath)) {\n try {\n const cachedPort = parseInt(await readFile(portCachePath, \"utf-8\"), 10);\n const cachedVer = parseInt(await readFile(scriptVersionPath, \"utf-8\"), 10);\n if (cachedPort === wsPort && cachedVer === RELOAD_MANAGER_SCRIPT_VERSION) needsUpdate = false;\n } catch { /* ignore */ }\n }\n await mkdir(extPath, { recursive: true });\n if (needsUpdate) {\n await writeFile(\n resolve(extPath, \"manifest.json\"),\n JSON.stringify(\n {\n manifest_version: 3,\n name: \"Reload Manager\",\n version: \"1.0\",\n permissions: [\"management\", \"tabs\"],\n background: { service_worker: \"bg.js\" },\n },\n null,\n 2\n ),\n \"utf-8\"\n );\n const bgJs = `\nlet ws=null,rt=null;\nfunction canReloadTab(tab){\n if(!tab||!tab.url)return false;\n const u=tab.url;\n return u.startsWith(\"http://\")||u.startsWith(\"https://\")||u.startsWith(\"file://\");\n}\nfunction connect(){\n try{if(ws)ws.close();\n ws=new WebSocket(\"ws://localhost:${wsPort}\");\n ws.onopen=()=>{if(rt)clearInterval(rt);rt=null;};\n ws.onmessage=async(e)=>{\n const msg=String(e.data==null?\"\":e.data);\n if(msg===\"connected\")return;\n if(msg===\"reload-extension\")return;\n const refreshPage=msg===\"toggle-extension-refresh-page\"||msg===\"toggle-extension-refresh-tab\";\n if(msg===\"toggle-extension\"||refreshPage){\n const all=await chrome.management.getAll();\n for(const x of all){\n if(x.enabled&&x.installType===\"development\"&&x.id!==chrome.runtime.id){\n try{await chrome.management.setEnabled(x.id,false);\n await new Promise(r=>setTimeout(r,100));\n await chrome.management.setEnabled(x.id,true);}catch(err){}\n }\n }\n if(refreshPage){\n await new Promise(r=>setTimeout(r,200));\n try{\n const [tab]=await chrome.tabs.query({active:true,currentWindow:true});\n if(tab?.id&&canReloadTab(tab))await chrome.tabs.reload(tab.id);\n }catch(err){}\n }\n }\n };\n ws.onclose=()=>{if(!rt)rt=setInterval(connect,3000);};\n }catch(err){}\n}\n connect();\n`;\n await writeFile(bgJsPath, bgJs, \"utf-8\");\n await writeFile(portCachePath, String(wsPort), \"utf-8\");\n await writeFile(scriptVersionPath, String(RELOAD_MANAGER_SCRIPT_VERSION), \"utf-8\");\n }\n return extPath;\n}\n","import { popWebExtStdoutOrigin, pushWebExtStdoutOrigin } from \"@addfox/common\";\r\n\r\nexport type WebExtConsoleStreamHookUninstall = () => void;\r\n\r\nlet installedUninstall: WebExtConsoleStreamHookUninstall | null = null;\r\n\r\n/**\r\n * Wraps web-ext's pino `ConsoleStream.write` so CLI line-prefixing can tag [Web-ext] at the real\r\n * output source (not string matching). Idempotent while active.\r\n */\r\nexport async function installWebExtConsoleStreamHook(): Promise<void> {\r\n if (installedUninstall) return;\r\n const { consoleStream } = await import(\"web-ext/util/logger\");\r\n const stream = consoleStream as { write: (json: string, opts?: { localProcess?: typeof process }) => void };\r\n const originalWrite = stream.write.bind(stream);\r\n stream.write = (jsonString: string, options?: { localProcess?: typeof process }): void => {\r\n pushWebExtStdoutOrigin();\r\n try {\r\n originalWrite(jsonString, options);\r\n } finally {\r\n popWebExtStdoutOrigin();\r\n }\r\n };\r\n installedUninstall = (): void => {\r\n stream.write = originalWrite;\r\n installedUninstall = null;\r\n };\r\n}\r\n\r\nexport function removeWebExtConsoleStreamHook(): void {\r\n installedUninstall?.();\r\n}\r\n","import { mkdir } from \"node:fs/promises\";\r\nimport { existsSync } from \"node:fs\";\r\nimport { rm } from \"node:fs/promises\";\r\nimport { once } from \"node:events\";\r\nimport type { ChildProcess } from \"node:child_process\";\r\nimport type { LaunchTarget, ChromiumLaunchTarget } from \"@addfox/core\";\r\nimport { log, logDoneTimed, warn, error, ANSI_COLORS } from \"@addfox/common\";\r\nimport { runChromiumRunner } from \"./runner\";\r\nimport type { ChromiumRunnerOptions } from \"./runner\";\r\nimport { getBrowserPath, isChromiumBrowser, type LaunchPathOptions } from \"./paths\";\r\nimport {\r\n startWebSocketServer,\r\n closeWebSocketServer,\r\n notifyReload,\r\n type DebugServerOpts,\r\n type WsServerMode,\r\n} from \"../server/ws-server\";\r\nimport {\r\n ensureDistReady,\r\n createReloadManagerExtension,\r\n getChromiumUserDataDir,\r\n getReloadManagerPath,\r\n} from \"../manager/extension\";\r\nimport {\r\n installWebExtConsoleStreamHook,\r\n removeWebExtConsoleStreamHook,\r\n} from \"./web-ext-console-stream-hook\";\r\n\r\ntype ReloadServerPlan = { mode: WsServerMode | \"none\"; debugOpts?: DebugServerOpts };\r\n\r\nfunction buildDebugServerOpts(ctx: LaunchContext): DebugServerOpts | undefined {\r\n if (!ctx.debug || !ctx.root || !ctx.outputRoot) return undefined;\r\n return { debug: true, root: ctx.root, outputRoot: ctx.outputRoot, distPath: ctx.distPath };\r\n}\r\n\r\nfunction computeReloadServerPlan(ctx: LaunchContext): ReloadServerPlan {\r\n const debugOpts = buildDebugServerOpts(ctx);\r\n const full = ctx.enableReload && isChromiumBrowser(ctx.browser);\r\n if (full) return { mode: \"full\", debugOpts };\r\n // Start HTTP server for error reporting in debug mode (Firefox or when reload is disabled)\r\n if (ctx.debug && debugOpts) return { mode: \"httpOnly\", debugOpts };\r\n return { mode: \"none\" };\r\n}\r\n\r\nasync function startReloadServersForPlan(ctx: LaunchContext, plan: ReloadServerPlan): Promise<void> {\r\n if (plan.mode === \"none\") return;\r\n const t0 = performance.now();\r\n await startWebSocketServer(ctx.wsPort, t0, plan.debugOpts, plan.mode);\r\n}\r\n\r\ntype ExtensionRunnerLike = {\r\n exit: () => Promise<void>;\r\n reloadAllExtensions?: () => Promise<unknown>;\r\n registerCleanup?: (fn: () => void) => void;\r\n};\r\n\r\nlet extensionRunner: ExtensionRunnerLike | null = null;\r\nlet reloadManagerPath: string | null = null;\r\nlet browserLaunched = false;\r\nlet isCleaningUp = false;\r\nlet cleanupHandlersRegistered = false;\r\nlet lastDistPath: string | null = null;\r\nlet lastOutputRoot: string | undefined;\r\nlet chromiumUserDataDirPath: string | null = null;\r\nlet lastChromiumBrowser: ChromiumLaunchTarget = \"chrome\";\r\nlet cacheEnabled = false;\r\nlet keyboardReloadCleanup: (() => void) | null = null;\r\n/** Idempotent tail of {@link cleanup} (WS, keyboard, profile dirs) without touching extensionRunner. */\r\nlet addfoxDevResourcesTornDown = false;\r\n/** True after `web-ext run` (Firefox) has started in this process. */\r\nlet firefoxWebExtSessionActive = false;\r\n/** First SIGINT hint for Firefox dev; second SIGINT performs cleanup. */\r\nlet firefoxSigintHintConsumed = false;\r\n\r\nconst MSG_FIREFOX_CLOSE_BROWSER_THEN_CTRL_C =\r\n \"Please close the browser first, then press Ctrl+C again to exit.\";\r\n\r\nconst EXIT_TIMEOUT_MS = 2000;\r\n/** web-ext `exit()` only calls kill(); wait for child `close` so firefox-profile can delete temp dir (Windows EBUSY). */\r\nconst FIREFOX_CHILD_CLOSE_MAX_MS = 8000;\r\nconst WIN32_PROFILE_UNLOCK_MS = 250;\r\n\r\nasync function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T | undefined> {\r\n let timer: ReturnType<typeof setTimeout> | null = null;\r\n try {\r\n return await Promise.race([\r\n promise,\r\n new Promise<undefined>((resolve) => {\r\n timer = setTimeout(() => resolve(undefined), ms);\r\n }),\r\n ]);\r\n } finally {\r\n if (timer) clearTimeout(timer);\r\n }\r\n}\r\n\r\nfunction getFirefoxChildFromWebExtRunner(runner: ExtensionRunnerLike): ChildProcess | undefined {\r\n const multi = runner as unknown as {\r\n extensionRunners?: Array<{ runningInfo?: { firefox?: ChildProcess } }>;\r\n };\r\n return multi.extensionRunners?.[0]?.runningInfo?.firefox;\r\n}\r\n\r\nfunction isFirefoxChildLikelyRunning(): boolean {\r\n if (!extensionRunner) return false;\r\n const firefox = getFirefoxChildFromWebExtRunner(extensionRunner);\r\n if (!firefox) return false;\r\n return firefox.exitCode === null;\r\n}\r\n\r\nfunction delayMs(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\nasync function yieldForWindowsProfileUnlock(): Promise<void> {\r\n if (process.platform !== \"win32\") return;\r\n await delayMs(WIN32_PROFILE_UNLOCK_MS);\r\n}\r\n\r\nasync function waitForFirefoxChildAfterWebExtExit(runner: ExtensionRunnerLike): Promise<void> {\r\n const firefox = getFirefoxChildFromWebExtRunner(runner);\r\n if (!firefox) return;\r\n if (firefox.exitCode !== null) {\r\n await yieldForWindowsProfileUnlock();\r\n return;\r\n }\r\n await Promise.race([\r\n once(firefox, \"close\"),\r\n delayMs(FIREFOX_CHILD_CLOSE_MAX_MS),\r\n ]);\r\n await yieldForWindowsProfileUnlock();\r\n}\r\n\r\nexport type ChromiumRunnerOverride = (\r\n opts: ChromiumRunnerOptions\r\n) => Promise<{ exit: () => Promise<void> }>;\r\n\r\nexport interface LaunchContext {\r\n distPath: string;\r\n browser: LaunchTarget;\r\n pathOpts: LaunchPathOptions;\r\n cache: boolean;\r\n enableReload: boolean;\r\n wsPort: number;\r\n chromiumRunnerOverride?: ChromiumRunnerOverride;\r\n ensureDistReadyOverride?: (distPath: string) => Promise<boolean>;\r\n getBrowserPathOverride?: (b: LaunchTarget, o: LaunchPathOptions) => string | null;\r\n onBrowserExit: () => void;\r\n debug?: boolean;\r\n root?: string;\r\n outputRoot?: string;\r\n}\r\n\r\nasync function teardownAddfoxDevResources(): Promise<void> {\r\n if (addfoxDevResourcesTornDown) return;\r\n addfoxDevResourcesTornDown = true;\r\n firefoxWebExtSessionActive = false;\r\n removeWebExtConsoleStreamHook();\r\n const userDataDir =\r\n chromiumUserDataDirPath ??\r\n (lastDistPath ? getChromiumUserDataDir(lastDistPath, lastChromiumBrowser, lastOutputRoot) : null);\r\n if (!cacheEnabled && userDataDir && existsSync(userDataDir)) {\r\n await rm(userDataDir, { recursive: true, force: true }).catch(() => {});\r\n }\r\n chromiumUserDataDirPath = null;\r\n reloadManagerPath = null;\r\n if (keyboardReloadCleanup) {\r\n keyboardReloadCleanup();\r\n keyboardReloadCleanup = null;\r\n }\r\n closeWebSocketServer();\r\n}\r\n\r\nexport async function cleanup(): Promise<void> {\r\n if (isCleaningUp) return;\r\n restoreStdinAfterWebExt();\r\n isCleaningUp = true;\r\n if (extensionRunner) {\r\n const er = extensionRunner;\r\n try {\r\n await withTimeout(er.exit(), EXIT_TIMEOUT_MS);\r\n await waitForFirefoxChildAfterWebExtExit(er);\r\n } catch {\r\n /* Runner already stopped (e.g. Firefox closed via web-ext). */\r\n }\r\n extensionRunner = null;\r\n }\r\n await teardownAddfoxDevResources();\r\n}\r\n\r\n/**\r\n * web-ext leaves stdin in raw mode; Ctrl+C is delivered as keypress bytes, not SIGINT.\r\n * Always restore TTY before relying on SIGINT or exiting.\r\n */\r\nfunction restoreStdinAfterWebExt(): void {\r\n const stdin = process.stdin;\r\n if (!stdin.isTTY || typeof stdin.setRawMode !== \"function\") return;\r\n try {\r\n stdin.setRawMode(false);\r\n } catch {\r\n /* ignore */\r\n }\r\n try {\r\n stdin.pause();\r\n } catch {\r\n /* ignore */\r\n }\r\n}\r\n\r\n/**\r\n * web-ext keypress Ctrl+C calls `extensionRunner.exit()` but never `process.exit()`; when Firefox\r\n * closes, `registerCleanup` runs after web-ext (watcher + stdin). We teardown and must exit the\r\n * dev server; `finally` ensures exit even if teardown throws or hangs were avoided.\r\n */\r\nasync function exitProcessAfterWebExtFirefoxClosed(): Promise<void> {\r\n restoreStdinAfterWebExt();\r\n try {\r\n if (isCleaningUp) {\r\n await teardownAddfoxDevResources();\r\n return;\r\n }\r\n isCleaningUp = true;\r\n extensionRunner = null;\r\n await teardownAddfoxDevResources();\r\n } catch {\r\n /* teardown best-effort */\r\n } finally {\r\n process.exit(0);\r\n }\r\n}\r\n\r\nfunction registerWebExtFirefoxResourceTeardown(runner: ExtensionRunnerLike): void {\r\n const reg = runner.registerCleanup;\r\n if (typeof reg !== \"function\") return;\r\n reg.call(runner, () => {\r\n void exitProcessAfterWebExtFirefoxClosed();\r\n });\r\n}\r\n\r\n/** Same as SIGINT handler: stdin raw mode often delivers Ctrl+C as \\\\x03 instead of raising SIGINT (notably on Windows). */\r\nfunction handleTerminalExitRequest(signal: NodeJS.Signals): void {\r\n restoreStdinAfterWebExt();\r\n if (isCleaningUp) {\r\n log(\"Force exit (cleanup in progress).\");\r\n process.exit(0);\r\n return;\r\n }\r\n if (\r\n signal === \"SIGINT\" &&\r\n firefoxWebExtSessionActive &&\r\n !firefoxSigintHintConsumed &&\r\n isFirefoxChildLikelyRunning()\r\n ) {\r\n firefoxSigintHintConsumed = true;\r\n log(MSG_FIREFOX_CLOSE_BROWSER_THEN_CTRL_C);\r\n return;\r\n }\r\n void cleanup().then(() => process.exit(0)).catch(() => process.exit(1));\r\n}\r\n\r\nfunction stdinChunkHasCtrlC(chunk: Buffer | string): boolean {\r\n if (typeof chunk === \"string\") {\r\n for (let i = 0; i < chunk.length; i++) {\r\n if (chunk.charCodeAt(i) === 3) return true;\r\n }\r\n return false;\r\n }\r\n return chunk.includes(3);\r\n}\r\n\r\nfunction registerStdinRShortcut(onPressR: () => void): void {\r\n const stdin = process.stdin;\r\n const onData = (chunk: Buffer | string): void => {\r\n if (stdinChunkHasCtrlC(chunk)) {\r\n handleTerminalExitRequest(\"SIGINT\");\r\n return;\r\n }\r\n const s = typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\");\r\n if (!s) return;\r\n const c = s.trim().toLowerCase();\r\n if (c === \"r\") onPressR();\r\n };\r\n stdin.setEncoding(\"utf8\");\r\n if (typeof stdin.setRawMode === \"function\") {\r\n stdin.setRawMode(true);\r\n }\r\n stdin.resume();\r\n stdin.on(\"data\", onData);\r\n log(\"Press R to reload extension (and Ctrl-C to quit)\");\r\n keyboardReloadCleanup = () => {\r\n stdin.off(\"data\", onData);\r\n if (typeof stdin.setRawMode === \"function\") {\r\n stdin.setRawMode(false);\r\n }\r\n stdin.pause();\r\n };\r\n}\r\n\r\nfunction registerManualReloadShortcut(enableReload: boolean, browser: LaunchTarget): void {\r\n if (!enableReload || !isChromiumBrowser(browser) || !process.stdin.isTTY) return;\r\n if (keyboardReloadCleanup) return;\r\n registerStdinRShortcut(() => {\r\n // Manual terminal shortcut must use direct extension reload path.\r\n notifyReload(\"reload-extension\");\r\n });\r\n}\r\n\r\nexport function registerCleanupHandlers(): void {\r\n if (cleanupHandlersRegistered) return;\r\n cleanupHandlersRegistered = true;\r\n process.on(\"SIGINT\", () => handleTerminalExitRequest(\"SIGINT\"));\r\n process.on(\"SIGTERM\", () => handleTerminalExitRequest(\"SIGTERM\"));\r\n}\r\n\r\nasync function runFirefoxWebExt(\r\n distPath: string,\r\n browserBinary: string | undefined,\r\n onExit: () => void,\r\n opts: { debug: boolean; reloadOnChange: boolean }\r\n): Promise<void> {\r\n const webExt = await import(\"web-ext\");\r\n const runOptions: {\r\n sourceDir: string;\r\n target: \"firefox-desktop\";\r\n firefox?: string;\r\n devtools?: boolean;\r\n browserConsole?: boolean;\r\n noReload?: boolean;\r\n verbose?: boolean;\r\n } = {\r\n sourceDir: distPath,\r\n target: \"firefox-desktop\" as const,\r\n noReload: !opts.reloadOnChange,\r\n // Omit noInput: use web-ext default (false) so R / Ctrl+C keypress loop matches CLI; teardown via registerCleanup.\r\n verbose: opts.debug,\r\n };\r\n if (opts.debug) {\r\n runOptions.devtools = true;\r\n runOptions.browserConsole = true;\r\n }\r\n if (browserBinary) runOptions.firefox = browserBinary;\r\n await installWebExtConsoleStreamHook();\r\n const runner = (await webExt.default.cmd.run(runOptions, {\r\n shouldExitProgram: false,\r\n })) as ExtensionRunnerLike;\r\n extensionRunner = runner;\r\n firefoxWebExtSessionActive = true;\r\n registerWebExtFirefoxResourceTeardown(runner);\r\n const firefoxExited = (): void => {\r\n log(`${ANSI_COLORS.RED}Exiting because the browser was closed.${ANSI_COLORS.RESET}`);\r\n onExit();\r\n };\r\n const r = runner as unknown as Record<string, unknown>;\r\n if (typeof (r.exitPromise as Promise<void> | undefined)?.then === \"function\") {\r\n (r.exitPromise as Promise<void>).then(firefoxExited).catch(() => {});\r\n return;\r\n }\r\n const proc = r.browserProcess ?? r.process ?? r.firefoxProcess;\r\n if (proc && typeof (proc as { on?: (e: string, h: () => void) => void }).on === \"function\") {\r\n (proc as { on(event: string, handler: () => void): void }).on(\"exit\", firefoxExited);\r\n }\r\n}\r\n\r\nexport async function launchBrowserCore(ctx: LaunchContext): Promise<void> {\r\n const launchStart = performance.now();\r\n addfoxDevResourcesTornDown = false;\r\n firefoxWebExtSessionActive = false;\r\n firefoxSigintHintConsumed = false;\r\n cacheEnabled = ctx.cache;\r\n lastDistPath = ctx.distPath;\r\n lastOutputRoot = ctx.outputRoot;\r\n const browserBinary = (ctx.getBrowserPathOverride ?? getBrowserPath)(ctx.browser, ctx.pathOpts);\r\n const readyFn = ctx.ensureDistReadyOverride ?? (() => ensureDistReady(ctx.distPath));\r\n await readyFn(ctx.distPath).catch((e: Error) => { error(e.message); });\r\n\r\n const plan = computeReloadServerPlan(ctx);\r\n await startReloadServersForPlan(ctx, plan);\r\n if (plan.mode === \"full\") {\r\n reloadManagerPath = await createReloadManagerExtension(ctx.wsPort, ctx.distPath);\r\n registerManualReloadShortcut(ctx.enableReload, ctx.browser);\r\n }\r\n\r\n if (isChromiumBrowser(ctx.browser)) {\r\n await launchChromiumBrowser(ctx, browserBinary, launchStart);\r\n return;\r\n }\r\n await launchFirefoxBrowser(ctx, browserBinary, launchStart);\r\n}\r\n\r\nasync function launchChromiumBrowser(\r\n ctx: LaunchContext,\r\n browserBinary: string | null,\r\n launchStart: number\r\n): Promise<void> {\r\n if (!browserBinary) {\r\n warn(ctx.browser, \"path not found; set\", `browserPath.${ctx.browser}`, \"in addfox.config, or install the browser at a default location\");\r\n return;\r\n }\r\n lastChromiumBrowser = ctx.browser as ChromiumLaunchTarget;\r\n chromiumUserDataDirPath = getChromiumUserDataDir(\r\n ctx.distPath,\r\n ctx.browser as ChromiumLaunchTarget,\r\n ctx.outputRoot\r\n );\r\n await mkdir(chromiumUserDataDirPath, { recursive: true });\r\n const extensions = [ctx.distPath, reloadManagerPath].filter(Boolean) as string[];\r\n const runnerFn = ctx.chromiumRunnerOverride ?? runChromiumRunner;\r\n extensionRunner = await runnerFn({\r\n chromePath: browserBinary,\r\n userDataDir: chromiumUserDataDirPath,\r\n extensions,\r\n startUrl: \"chrome://extensions\",\r\n onExit: ctx.onBrowserExit,\r\n });\r\n logDoneTimed(ctx.browser + \" started, extensions loaded.\", Math.round(performance.now() - launchStart));\r\n}\r\n\r\nasync function launchFirefoxBrowser(\r\n ctx: LaunchContext,\r\n browserBinary: string | null,\r\n launchStart: number\r\n): Promise<void> {\r\n await runFirefoxWebExt(ctx.distPath, browserBinary || undefined, ctx.onBrowserExit, {\r\n debug: ctx.debug === true,\r\n reloadOnChange: ctx.enableReload,\r\n });\r\n logDoneTimed(\"Firefox started via web-ext, extension loaded.\", Math.round(performance.now() - launchStart));\r\n}\r\n\r\nexport interface HmrPluginOptionsForLaunch {\r\n distPath: string;\r\n browser?: LaunchTarget;\r\n cache?: boolean;\r\n wsPort?: number;\r\n enableReload?: boolean;\r\n debug?: boolean;\r\n root?: string;\r\n outputRoot?: string;\r\n chromePath?: string;\r\n chromiumPath?: string;\r\n edgePath?: string;\r\n bravePath?: string;\r\n vivaldiPath?: string;\r\n operaPath?: string;\r\n santaPath?: string;\r\n arcPath?: string;\r\n yandexPath?: string;\r\n browserosPath?: string;\r\n customPath?: string;\r\n firefoxPath?: string;\r\n}\r\n\r\nexport async function launchBrowser(\r\n options: HmrPluginOptionsForLaunch,\r\n chromiumRunnerOverride?: ChromiumRunnerOverride,\r\n ensureDistReadyOverride?: (distPath: string) => Promise<boolean>,\r\n getBrowserPathOverride?: (b: LaunchTarget, o: LaunchPathOptions) => string | null\r\n): Promise<void> {\r\n const {\r\n distPath,\r\n browser = \"chrome\",\r\n cache = false,\r\n wsPort = 23333,\r\n enableReload = true,\r\n debug,\r\n root,\r\n outputRoot,\r\n } = options;\r\n const onBrowserExit = () => {\r\n log(`${ANSI_COLORS.RED}Exiting because the browser was closed.${ANSI_COLORS.RESET}`);\r\n cleanup().then(() => process.exit(0)).catch(() => process.exit(1));\r\n };\r\n await launchBrowserCore({\r\n distPath,\r\n browser,\r\n debug,\r\n root,\r\n outputRoot,\r\n pathOpts: {\r\n chromePath: options.chromePath,\r\n chromiumPath: options.chromiumPath,\r\n edgePath: options.edgePath,\r\n bravePath: options.bravePath,\r\n vivaldiPath: options.vivaldiPath,\r\n operaPath: options.operaPath,\r\n santaPath: options.santaPath,\r\n arcPath: options.arcPath,\r\n yandexPath: options.yandexPath,\r\n browserosPath: options.browserosPath,\r\n customPath: options.customPath,\r\n firefoxPath: options.firefoxPath,\r\n },\r\n cache,\r\n enableReload,\r\n wsPort,\r\n chromiumRunnerOverride,\r\n ensureDistReadyOverride,\r\n getBrowserPathOverride,\r\n onBrowserExit,\r\n });\r\n}\r\n\r\nexport function setBrowserLaunched(value: boolean): void {\r\n browserLaunched = value;\r\n}\r\n\r\nexport function getBrowserLaunched(): boolean {\r\n return browserLaunched;\r\n}\r\n\r\nexport function statsHasErrors(stats: unknown): boolean {\r\n if (!stats || typeof stats !== \"object\") return false;\r\n const s = stats as { hasErrors?: () => boolean };\r\n return Boolean(s.hasErrors?.());\r\n}\r\n\r\nexport {\r\n getReloadManagerPath,\r\n getChromiumUserDataDir,\r\n getCacheRoot,\r\n getBrowserProfileDir,\r\n /** @deprecated Use getCacheRoot/getBrowserProfileDir instead */\r\n getCacheTempRoot,\r\n findExistingReloadManager,\r\n ensureDistReady,\r\n} from \"../manager/extension\";\r\n\r\nexport async function launchBrowserOnly(\r\n options: LaunchOnlyOptions,\r\n chromiumRunnerOverride?: ChromiumRunnerOverride\r\n): Promise<void> {\r\n const { distPath, browser = \"chrome\", cache = false } = options;\r\n addfoxDevResourcesTornDown = false;\r\n firefoxWebExtSessionActive = false;\r\n firefoxSigintHintConsumed = false;\r\n cacheEnabled = cache;\r\n lastDistPath = distPath;\r\n lastOutputRoot = options.outputRoot;\r\n registerCleanupHandlers();\r\n\r\n let resolveClosed: () => void;\r\n const closedPromise = new Promise<void>((r) => { resolveClosed = r; });\r\n const onBrowserExit = () => {\r\n log(`${ANSI_COLORS.RED}Exiting because the browser was closed.${ANSI_COLORS.RESET}`);\r\n cleanup().then(() => { resolveClosed(); process.exit(0); }).catch(() => process.exit(1));\r\n };\r\n\r\n const doLaunch = async (): Promise<void> => {\r\n const browserBinary = getBrowserPath(browser, {\r\n chromePath: options.chromePath,\r\n chromiumPath: options.chromiumPath,\r\n edgePath: options.edgePath,\r\n bravePath: options.bravePath,\r\n vivaldiPath: options.vivaldiPath,\r\n operaPath: options.operaPath,\r\n santaPath: options.santaPath,\r\n arcPath: options.arcPath,\r\n yandexPath: options.yandexPath,\r\n browserosPath: options.browserosPath,\r\n customPath: options.customPath,\r\n firefoxPath: options.firefoxPath,\r\n });\r\n await ensureDistReady(distPath);\r\n if (isChromiumBrowser(browser)) {\r\n if (!browserBinary) {\r\n throw new Error(`${browser} path not found; set browserPath.${browser} in addfox.config, or install the browser at a default location`);\r\n }\r\n lastChromiumBrowser = browser;\r\n chromiumUserDataDirPath = getChromiumUserDataDir(distPath, browser, options.outputRoot);\r\n await mkdir(chromiumUserDataDirPath, { recursive: true });\r\n const runnerFn = chromiumRunnerOverride ?? runChromiumRunner;\r\n extensionRunner = await runnerFn({\r\n chromePath: browserBinary,\r\n userDataDir: chromiumUserDataDirPath,\r\n extensions: [distPath],\r\n startUrl: \"chrome://extensions\",\r\n onExit: onBrowserExit,\r\n });\r\n logDoneTimed(browser + \" started (build launch), extension loaded.\", Math.round(performance.now()));\r\n return;\r\n }\r\n await runFirefoxWebExt(distPath, browserBinary ?? undefined, onBrowserExit, {\r\n debug: options.debug ?? false,\r\n reloadOnChange: options.enableReload ?? false,\r\n });\r\n logDoneTimed(\"Firefox started (build launch), extension loaded.\", 0);\r\n };\r\n return doLaunch().then(() => closedPromise);\r\n}\r\n\r\nexport type LaunchOnlyOptions = Pick<\r\n HmrPluginOptionsForLaunch,\r\n | \"distPath\"\r\n | \"browser\"\r\n | \"chromePath\"\r\n | \"chromiumPath\"\r\n | \"edgePath\"\r\n | \"bravePath\"\r\n | \"vivaldiPath\"\r\n | \"operaPath\"\r\n | \"santaPath\"\r\n | \"arcPath\"\r\n | \"yandexPath\"\r\n | \"browserosPath\"\r\n | \"customPath\"\r\n | \"firefoxPath\"\r\n | \"cache\"\r\n | \"outputRoot\"\r\n | \"debug\"\r\n | \"enableReload\"\r\n>;\r\n","import type { Compiler } from \"@rspack/core\";\r\nimport {\r\n launchBrowser,\r\n registerCleanupHandlers,\r\n statsHasErrors,\r\n setBrowserLaunched,\r\n getBrowserLaunched,\r\n type ChromiumRunnerOverride,\r\n} from \"../browser/launcher\";\r\nimport type { HmrPluginOptions, HmrPluginTestDeps } from \"../types\";\r\n\r\n// ==================== Type Definitions ====================\r\n\r\ntype WatchFileSystem = {\r\n watcher?: {\r\n mtimes?: Map<string, number> | Record<string, number>;\r\n getTimes?: () => Map<string, number> | Record<string, number>;\r\n };\r\n};\r\n\r\ntype ExtendedCompiler = Compiler & {\r\n modifiedFiles?: ReadonlySet<string>;\r\n watchFileSystem?: WatchFileSystem;\r\n};\r\n\r\n// ==================== State ====================\r\n\r\nlet lastCompiler: Compiler | null = null;\r\n\r\nexport function getLastCompiler(): Compiler | null {\r\n return lastCompiler;\r\n}\r\n\r\n// ==================== Modified Files Extraction ====================\r\n\r\n/**\r\n * Collects modified file paths from compiler:\r\n * - Prefers compiler.modifiedFiles when available (Rspack >= 0.5)\r\n * - Falls back to watchFileSystem.watcher.mtimes for older versions\r\n */\r\nexport function getModifiedFilesFromCompiler(compiler: Compiler | null): Set<string> {\r\n const out = new Set<string>();\r\n if (!compiler) return out;\r\n \r\n const c = compiler as ExtendedCompiler;\r\n \r\n // Prefer the modern modifiedFiles API\r\n if (c.modifiedFiles?.size) {\r\n c.modifiedFiles.forEach(p => out.add(p));\r\n return out;\r\n }\r\n \r\n // Fall back to watch file system\r\n const watcher = c.watchFileSystem?.watcher;\r\n if (!watcher) return out;\r\n \r\n try {\r\n const mtimes = watcher.mtimes ?? watcher.getTimes?.();\r\n if (!mtimes) return out;\r\n \r\n if (mtimes instanceof Map) {\r\n mtimes.forEach((_, key) => out.add(key));\r\n } else if (typeof mtimes === \"object\") {\r\n Object.keys(mtimes).forEach(key => out.add(key));\r\n }\r\n } catch {\r\n /* ignore watcher access errors */\r\n }\r\n \r\n return out;\r\n}\r\n\r\n// ==================== Plugin Factory ====================\r\n\r\nconst LAUNCH_PLUGIN_NAME = \"rsbuild-plugin-extension-hmr:launch\";\r\nconst LAUNCH_DELAY_MS = 1000;\r\n\r\n/**\r\n * Creates the HMR Rspack plugin that handles browser launch on first successful compilation.\r\n */\r\nexport function createHmrRspackPlugin(\r\n options: HmrPluginOptions,\r\n testDeps?: HmrPluginTestDeps\r\n): { name: string; apply(compiler: Compiler): void } {\r\n const { autoOpen = true } = options;\r\n\r\n return {\r\n name: \"rsbuild-plugin-extension-hmr:rspack\",\r\n apply(compiler: Compiler) {\r\n lastCompiler = compiler;\r\n const { done } = compiler.hooks;\r\n if (!done) return;\r\n\r\n registerCleanupHandlers();\r\n\r\n done.tap(LAUNCH_PLUGIN_NAME, async (stats) => {\r\n if (!autoOpen || getBrowserLaunched()) return;\r\n if (statsHasErrors(stats)) return;\r\n setBrowserLaunched(true);\r\n await new Promise(r => setTimeout(r, LAUNCH_DELAY_MS));\r\n try {\r\n await launchBrowser(\r\n options,\r\n testDeps?.runChromiumRunner as ChromiumRunnerOverride | undefined,\r\n testDeps?.ensureDistReady,\r\n testDeps?.getBrowserPath\r\n );\r\n } catch (e) {\r\n const { error } = await import(\"@addfox/common\");\r\n error(\"Failed to launch browser:\", e);\r\n }\r\n });\r\n },\r\n };\r\n}\r\n","import { RELOAD_MANAGER_ENTRY_NAMES as RELOAD_MANAGER_NAMES } from \"@addfox/core\";\r\nimport {\r\n RELOAD_ENTRY_NAMES as RELOAD_NAMES,\r\n CONTENT_ENTRY_NAMES as CONTENT_NAMES,\r\n} from \"../constants\";\r\n\r\n// ==================== Type Definitions ====================\r\n\r\ntype AssetLike = { \r\n filename?: string; \r\n info?: { contenthash?: string[]; chunkhash?: string[] } \r\n};\r\n\r\ntype ChunkLike = { \r\n id?: string; \r\n name?: string; \r\n hash?: string \r\n};\r\n\r\ntype EntrypointLike = {\r\n name?: string;\r\n chunks?: ReadonlyArray<ChunkLike>;\r\n getFiles?: () => ReadonlyArray<string>;\r\n};\r\n\r\ntype CompilationLike = {\r\n entrypoints?: ReadonlyMap<string, EntrypointLike>;\r\n getAsset?: (name: string) => AssetLike | void;\r\n getAssets?: () => ReadonlyArray<AssetLike>;\r\n getStats?: () => { toJson: (opts?: unknown) => unknown };\r\n};\r\n\r\ntype StatsChunk = {\r\n id?: string;\r\n name?: string;\r\n names?: string[];\r\n modules?: StatsModule[];\r\n};\r\n\r\ntype StatsModule = {\r\n name?: string;\r\n nameForCondition?: string;\r\n identifier?: string;\r\n chunks?: (string | null | undefined)[];\r\n};\r\n\r\ntype StatsJson = {\r\n chunks?: StatsChunk[];\r\n modules?: StatsModule[];\r\n};\r\n\r\nexport interface ReloadManagerDecision {\r\n /** True only when content or background entry output actually changed (precise). */\r\n shouldNotify: boolean;\r\n /** True when content entry changed (for toggle-extension-refresh-page). */\r\n contentChanged: boolean;\r\n /** True when background entry changed (for reload-extension). */\r\n backgroundChanged: boolean;\r\n}\r\n\r\nexport type ReloadKind = \"reload-extension\" | \"toggle-extension\" | \"toggle-extension-refresh-page\";\r\n\r\n// ==================== State Management ====================\r\n\r\ninterface SignatureState {\r\n lastReload: string | null;\r\n lastContent: string | null;\r\n lastBackground: string | null;\r\n}\r\n\r\nconst state: SignatureState = {\r\n lastReload: null,\r\n lastContent: null,\r\n lastBackground: null,\r\n};\r\n\r\n// ==================== Stats Normalization ====================\r\n\r\n/** Use first child stats when MultiCompiler produces MultiStats (stats.stats array). */\r\nfunction getNormalizedStats(stats: unknown): unknown {\r\n if (!stats || typeof stats !== \"object\") return stats;\r\n const arr = (stats as { stats?: unknown[] }).stats;\r\n return Array.isArray(arr) && arr.length > 0 ? arr[0] : stats;\r\n}\r\n\r\nfunction getStatsJson(stats: unknown): StatsJson | null {\r\n try {\r\n const s = getNormalizedStats(stats);\r\n if (!s || typeof s !== \"object\") return null;\r\n const toJson = (s as { toJson?: (opts?: unknown) => unknown }).toJson;\r\n return typeof toJson === \"function\" \r\n ? (toJson({ chunks: true, modules: true }) as StatsJson) \r\n : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function getCompilationFromStats(stats: unknown): CompilationLike | null {\r\n const s = getNormalizedStats(stats);\r\n if (!s || typeof s !== \"object\") return null;\r\n const comp = (s as { compilation?: CompilationLike }).compilation;\r\n return comp && typeof comp === \"object\" ? comp : null;\r\n}\r\n\r\nfunction getStatsFromCompilation(compilation: CompilationLike | null): StatsJson | null {\r\n if (!compilation || typeof compilation.getStats !== \"function\") return null;\r\n return compilation.getStats()?.toJson?.({ chunks: true, modules: true }) as StatsJson | null;\r\n}\r\n\r\n// ==================== Path Utilities ====================\r\n\r\nconst normalizePath = (p: string): string => p.replace(/\\\\/g, \"/\");\r\n\r\nfunction createPathMatcher(filePath: string) {\r\n const norm = normalizePath(filePath);\r\n return {\r\n norm,\r\n exact: (other: string): boolean => norm === normalizePath(other),\r\n endsWith: (suffix: string): boolean => {\r\n const sn = suffix.startsWith(\"./\") ? suffix.slice(2) : suffix;\r\n return norm.endsWith(sn) || normalizePath(suffix).endsWith(norm);\r\n },\r\n matches: (other: string): boolean => {\r\n const on = normalizePath(other);\r\n return norm === on || \r\n (other.startsWith(\"./\") && norm.endsWith(other.slice(2))) ||\r\n norm.endsWith(on) || on.endsWith(norm);\r\n }\r\n };\r\n}\r\n\r\n// ==================== Asset & Signature Utilities ====================\r\n\r\nfunction collectAssetHashes(asset: AssetLike | undefined): string[] {\r\n const info = asset?.info;\r\n return info?.contenthash?.length \r\n ? [...info.contenthash] \r\n : info?.chunkhash?.length \r\n ? [...info.chunkhash] \r\n : [];\r\n}\r\n\r\nfunction findAsset(compilation: CompilationLike, name: string): AssetLike | undefined {\r\n const raw = compilation.getAsset?.(name);\r\n if (raw != null && typeof raw === \"object\") return raw;\r\n \r\n const list = compilation.getAssets?.();\r\n return list?.find((a) => a?.filename === name);\r\n}\r\n\r\n/**\r\n * Signature from asset contenthash/chunkhash for this entry's output files only.\r\n * Stable when only other entries (e.g. options, popup) change — avoids fullHash pollution.\r\n */\r\nfunction getEntrypointSignatureFromAssets(\r\n compilation: CompilationLike,\r\n entrypoint: EntrypointLike | undefined\r\n): string | null {\r\n if (!entrypoint || typeof entrypoint.getFiles !== \"function\") return null;\r\n \r\n try {\r\n const files = entrypoint.getFiles();\r\n if (!files?.length) return null;\r\n \r\n const parts = files.flatMap(name => collectAssetHashes(findAsset(compilation, name)));\r\n return parts.length > 0 ? [...parts].sort().join(\",\") : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nexport function getEntrypointSignature(entrypoint: EntrypointLike | undefined): string | null {\r\n if (!entrypoint) return null;\r\n \r\n const hashes = entrypoint.chunks\r\n ? entrypoint.chunks\r\n .map(c => c?.hash)\r\n .filter((h): h is string => Boolean(h))\r\n : [];\r\n \r\n if (hashes.length > 0) return hashes.sort().join(\",\");\r\n \r\n if (typeof entrypoint.getFiles === \"function\") {\r\n try {\r\n const files = entrypoint.getFiles();\r\n if (files?.length) return [...files].sort().join(\",\");\r\n } catch { /* proxy may throw */ }\r\n }\r\n \r\n return null;\r\n}\r\n\r\nfunction getSingleEntrySignature(\r\n compilation: CompilationLike,\r\n entryName: string\r\n): string | null {\r\n if (!RELOAD_MANAGER_NAMES.has(entryName)) return null;\r\n if (!compilation?.entrypoints || typeof compilation.entrypoints.get !== \"function\") return null;\r\n \r\n const entrypoint = compilation.entrypoints.get(entryName) ?? undefined;\r\n return getEntrypointSignatureFromAssets(compilation, entrypoint) ?? getEntrypointSignature(entrypoint);\r\n}\r\n\r\nfunction getEntrySignatures(\r\n compilation: CompilationLike,\r\n entryNames: Set<string>\r\n): string[] {\r\n if (!compilation.entrypoints || typeof compilation.entrypoints.get !== \"function\") return [];\r\n \r\n return Array.from(entryNames)\r\n .map(name => getEntrypointSignature(compilation.entrypoints!.get(name)))\r\n .filter((sig): sig is string => Boolean(sig));\r\n}\r\n\r\nexport function getEntriesSignature(\r\n compilation: CompilationLike,\r\n entryNames: Set<string>\r\n): string | null {\r\n const sigs = getEntrySignatures(compilation, entryNames);\r\n return sigs.length > 0 ? sigs.sort().join(\"|\") : null;\r\n}\r\n\r\n// ==================== Entry-to-Module Mapping ====================\r\n\r\ntype ChunkIdToEntryNames = Map<string, Set<string>>;\r\ntype EntryToPaths = Map<string, Set<string>>;\r\n\r\nfunction buildChunkIdToEntryNames(compilation: CompilationLike): ChunkIdToEntryNames {\r\n const map = new Map<string, Set<string>>();\r\n if (!compilation.entrypoints || typeof compilation.entrypoints.forEach !== \"function\") return map;\r\n \r\n try {\r\n compilation.entrypoints.forEach((entrypoint, entryName) => {\r\n const chunks = entrypoint?.chunks;\r\n if (!Array.isArray(chunks)) return;\r\n \r\n for (const ch of chunks) {\r\n const id = ch?.id != null ? String(ch.id) : undefined;\r\n if (!id) continue;\r\n \r\n const set = map.get(id) ?? new Set<string>();\r\n set.add(entryName);\r\n map.set(id, set);\r\n }\r\n });\r\n } catch {\r\n /* proxy may throw */\r\n }\r\n \r\n return map;\r\n}\r\n\r\nfunction buildChunkIdToEntryNamesFromStats(stats: StatsJson): ChunkIdToEntryNames {\r\n const map = new Map<string, Set<string>>();\r\n if (!stats.chunks) return map;\r\n \r\n for (const ch of stats.chunks) {\r\n if (ch.id == null) continue;\r\n const id = String(ch.id);\r\n const names = Array.isArray(ch.names) ? ch.names : ch.name != null ? [ch.name] : [];\r\n \r\n const set = map.get(id) ?? new Set<string>();\r\n names.forEach(n => set.add(n));\r\n map.set(id, set);\r\n }\r\n \r\n return map;\r\n}\r\n\r\nfunction addPathToEntries(\r\n entryToPaths: EntryToPaths,\r\n path: string,\r\n entryNames: Set<string>\r\n): void {\r\n const norm = normalizePath(path);\r\n for (const name of entryNames) {\r\n const set = entryToPaths.get(name) ?? new Set<string>();\r\n set.add(norm);\r\n entryToPaths.set(name, set);\r\n }\r\n}\r\n\r\nfunction extractModulePath(mod: StatsModule): string | undefined {\r\n return mod?.nameForCondition ?? mod?.name ?? mod?.identifier;\r\n}\r\n\r\nfunction collectModuleEntryNames(\r\n mod: StatsModule,\r\n chunkIdToEntryNames: ChunkIdToEntryNames\r\n): Set<string> {\r\n const entryNames = new Set<string>();\r\n if (!mod.chunks?.length) return entryNames;\r\n \r\n for (const id of mod.chunks) {\r\n if (id == null) continue;\r\n const names = chunkIdToEntryNames.get(String(id));\r\n names?.forEach(n => entryNames.add(n));\r\n }\r\n \r\n return entryNames;\r\n}\r\n\r\nfunction processFlatModules(\r\n entryToPaths: EntryToPaths,\r\n modules: StatsModule[],\r\n chunkIdToEntryNames: ChunkIdToEntryNames\r\n): void {\r\n for (const mod of modules) {\r\n const path = extractModulePath(mod);\r\n if (!path) continue;\r\n \r\n const entryNames = collectModuleEntryNames(mod, chunkIdToEntryNames);\r\n if (entryNames.size) addPathToEntries(entryToPaths, path, entryNames);\r\n }\r\n}\r\n\r\nfunction processNestedModules(\r\n entryToPaths: EntryToPaths,\r\n chunks: StatsChunk[],\r\n chunkIdToEntryNames: ChunkIdToEntryNames\r\n): void {\r\n for (const ch of chunks) {\r\n if (!ch.modules?.length) continue;\r\n \r\n const names = Array.isArray(ch.names) ? ch.names : ch.name != null ? [ch.name] : [];\r\n const entryNames = new Set(names);\r\n if (!entryNames.size) continue;\r\n \r\n for (const mod of ch.modules) {\r\n const path = extractModulePath(mod);\r\n if (path) addPathToEntries(entryToPaths, path, entryNames);\r\n }\r\n }\r\n}\r\n\r\nexport function getEntryToModulePaths(stats: unknown): EntryToPaths {\r\n const entryToPaths = new Map<string, Set<string>>();\r\n const compilation = getCompilationFromStats(stats);\r\n const statsJson = getStatsFromCompilation(compilation) ?? getStatsJson(stats);\r\n \r\n if (!statsJson?.chunks?.length) return entryToPaths;\r\n \r\n const chunkIdToEntryNames = compilation \r\n ? buildChunkIdToEntryNames(compilation)\r\n : buildChunkIdToEntryNamesFromStats(statsJson);\r\n \r\n if (Array.isArray(statsJson.modules) && statsJson.modules.length > 0) {\r\n processFlatModules(entryToPaths, statsJson.modules, chunkIdToEntryNames);\r\n } else {\r\n processNestedModules(entryToPaths, statsJson.chunks, chunkIdToEntryNames);\r\n }\r\n \r\n return entryToPaths;\r\n}\r\n\r\n// ==================== File-to-Entry Resolution ====================\r\n\r\n/** Which entry names contain this file path (using path normalization / endsWith). */\r\nexport function getEntriesForFile(\r\n entryToPaths: EntryToPaths,\r\n filePath: string\r\n): string[] {\r\n const matcher = createPathMatcher(filePath);\r\n const entries: string[] = [];\r\n \r\n for (const [entryName, paths] of entryToPaths) {\r\n for (const p of paths) {\r\n if (matcher.matches(p)) {\r\n entries.push(entryName);\r\n break;\r\n }\r\n }\r\n }\r\n \r\n return entries;\r\n}\r\n\r\n// ==================== Reload Manager Detection ====================\r\n\r\nfunction getReloadManagerModulePaths(entryToPaths: EntryToPaths): Set<string> {\r\n const paths = new Set<string>();\r\n for (const name of RELOAD_MANAGER_NAMES) {\r\n entryToPaths.get(name)?.forEach(p => paths.add(p));\r\n }\r\n return paths;\r\n}\r\n\r\nfunction pathMatchesReloadManager(modifiedPath: string, reloadPaths: Set<string>): boolean {\r\n const matcher = createPathMatcher(modifiedPath);\r\n if (reloadPaths.has(matcher.norm)) return true;\r\n \r\n for (const r of reloadPaths) {\r\n if (matcher.matches(r)) return true;\r\n }\r\n return false;\r\n}\r\n\r\nfunction doFilesAffectReloadManager(\r\n modifiedFiles: ReadonlySet<string>,\r\n entryToPaths: EntryToPaths\r\n): boolean {\r\n for (const filePath of modifiedFiles) {\r\n const entries = getEntriesForFile(entryToPaths, filePath);\r\n if (entries.some(e => RELOAD_MANAGER_NAMES.has(e))) return true;\r\n }\r\n return false;\r\n}\r\n\r\nfunction filesAffectEntry(\r\n modifiedFiles: ReadonlySet<string>,\r\n entryToPaths: EntryToPaths,\r\n entryName: string\r\n): boolean {\r\n for (const filePath of modifiedFiles) {\r\n const entries = getEntriesForFile(entryToPaths, filePath);\r\n if (entries.includes(entryName)) return true;\r\n }\r\n return false;\r\n}\r\n\r\n// ==================== Decision Engine ====================\r\n\r\ninterface SignatureComparison {\r\n contentChanged: boolean;\r\n backgroundChanged: boolean;\r\n shouldNotify: boolean;\r\n}\r\n\r\nfunction compareSignatures(\r\n contentSig: string | null,\r\n backgroundSig: string | null\r\n): SignatureComparison {\r\n const contentChanged = contentSig != null && state.lastContent != null && contentSig !== state.lastContent;\r\n const backgroundChanged = backgroundSig != null && state.lastBackground != null && backgroundSig !== state.lastBackground;\r\n const shouldNotify = contentChanged || backgroundChanged;\r\n \r\n return { contentChanged, backgroundChanged, shouldNotify };\r\n}\r\n\r\nfunction updateSignatures(contentSig: string | null, backgroundSig: string | null): void {\r\n if (contentSig != null) state.lastContent = contentSig;\r\n if (backgroundSig != null) state.lastBackground = backgroundSig;\r\n}\r\n\r\n/**\r\n * Single place to decide reloadManager WS notification and content-refresh.\r\n * Extension.js-style: when compiler.modifiedFiles is available, only notify if a modified file\r\n * belongs to content/background chunk. Otherwise fall back to signature comparison.\r\n */\r\nexport function getReloadManagerDecision(\r\n stats: unknown,\r\n context?: { compiler?: { modifiedFiles?: ReadonlySet<string> } }\r\n): ReloadManagerDecision {\r\n const modifiedFiles = context?.compiler?.modifiedFiles;\r\n const entryToPaths = getEntryToModulePaths(stats);\r\n \r\n const compilation = getCompilationFromStats(stats);\r\n const contentSig = compilation ? getSingleEntrySignature(compilation, \"content\") : null;\r\n const backgroundSig = compilation ? getSingleEntrySignature(compilation, \"background\") : null;\r\n \r\n const sigComparison = compareSignatures(contentSig, backgroundSig);\r\n updateSignatures(contentSig, backgroundSig);\r\n \r\n const hasModifiedFiles = modifiedFiles != null && modifiedFiles.size > 0;\r\n const hasEntryMapping = entryToPaths.size > 0;\r\n \r\n if (hasModifiedFiles && hasEntryMapping) {\r\n const shouldNotify = doFilesAffectReloadManager(modifiedFiles, entryToPaths);\r\n return {\r\n shouldNotify,\r\n contentChanged: shouldNotify && filesAffectEntry(modifiedFiles, entryToPaths, \"content\"),\r\n backgroundChanged: shouldNotify && filesAffectEntry(modifiedFiles, entryToPaths, \"background\"),\r\n };\r\n }\r\n \r\n return {\r\n shouldNotify: sigComparison.shouldNotify,\r\n contentChanged: sigComparison.contentChanged,\r\n backgroundChanged: sigComparison.backgroundChanged,\r\n };\r\n}\r\n\r\n/**\r\n * Choose reload kind from decision and config.\r\n * - backgroundChanged → reload-extension (browser reload API).\r\n * - contentChanged + autoRefreshContentPage → toggle-extension-refresh-page (toggle + refresh current page).\r\n * - else → toggle-extension (toggle only).\r\n */\r\nexport function getReloadKindFromDecision(\r\n contentChanged: boolean,\r\n backgroundChanged: boolean,\r\n autoRefreshContentPage: boolean\r\n): ReloadKind {\r\n if (backgroundChanged) return \"reload-extension\";\r\n if (contentChanged && autoRefreshContentPage) return \"toggle-extension-refresh-page\";\r\n return \"toggle-extension\";\r\n}\r\n\r\n/** True when content entry signature changed (uses same state as getReloadManagerDecision). */\r\nexport function isContentChanged(stats: unknown): boolean {\r\n const compilation = getCompilationFromStats(stats);\r\n if (!compilation) return false;\r\n \r\n const sig = getEntriesSignature(compilation, CONTENT_NAMES);\r\n const changed = sig !== null && state.lastContent !== null && sig !== state.lastContent;\r\n \r\n if (sig !== null) state.lastContent = sig;\r\n return changed;\r\n}\r\n\r\n// ==================== Convenience Exports ====================\r\n\r\nexport function getReloadEntriesSignature(stats: unknown): string | null {\r\n const compilation = getCompilationFromStats(stats);\r\n return compilation ? getEntriesSignature(compilation, RELOAD_NAMES) : null;\r\n}\r\n\r\nexport function getContentEntriesSignature(stats: unknown): string | null {\r\n const compilation = getCompilationFromStats(stats);\r\n return compilation ? getEntriesSignature(compilation, CONTENT_NAMES) : null;\r\n}\r\n","import { createServer } from \"node:http\";\r\nimport { WebSocketServer, WebSocket } from \"ws\";\r\n\r\n/** Test helper: minimal WebSocket server with notifyReload. */\r\nexport function createTestWsServer(\r\n port: number\r\n): Promise<{\r\n close: () => Promise<void>;\r\n notifyReload: () => void;\r\n}> {\r\n const http = createServer();\r\n const wss = new WebSocketServer({ server: http });\r\n wss.on(\"connection\", (ws: WebSocket) => {\r\n if (ws.readyState === WebSocket.OPEN) ws.send(\"connected\");\r\n });\r\n return new Promise((resolve, reject) => {\r\n http.listen(port, () => {\r\n resolve({\r\n close: () =>\r\n new Promise((done) => {\r\n wss.close(() => { http.close(() => done()); });\r\n }),\r\n notifyReload() {\r\n wss.clients.forEach((client: WebSocket) => {\r\n if (client.readyState === WebSocket.OPEN) client.send(\"reload-extension\");\r\n });\r\n },\r\n });\r\n });\r\n http.on(\"error\", reject);\r\n });\r\n}\r\n","/**\r\n * @addfox/rsbuild-plugin-extension-hmr\r\n *\r\n * Dev mode: launch browser, WebSocket reload manager, and precise HMR/liveReload\r\n * control for content/background entries (reload via WS only).\r\n */\r\n\r\nimport type { RsbuildPlugin, RsbuildPluginAPI } from \"@rsbuild/core\";\r\nimport { clearOutdatedHotUpdateFiles } from \"./hmr/cleanup\";\r\nimport { transformCodeToDisableHmr } from \"./hmr/disable\";\r\nimport { createHmrRspackPlugin, getLastCompiler, getModifiedFilesFromCompiler } from \"./hmr/rspack-plugin\";\r\nimport { getReloadManagerDecision, getReloadKindFromDecision } from \"./hmr/scope\";\r\nimport { notifyReload } from \"./server/ws-server\";\r\nimport type { HmrPluginOptions, HmrPluginTestDeps } from \"./types\";\r\n\r\nexport type { HmrPluginOptions, HmrPluginTestDeps } from \"./types\";\r\nexport { RELOAD_ENTRY_NAMES, CONTENT_ENTRY_NAMES, getEntryTag } from \"./constants\";\r\nexport { clearOutdatedHotUpdateFiles } from \"./hmr/cleanup\";\r\nexport { getLaunchPathFromOptions, buildDefaultPaths, getBrowserPath, isChromiumBrowser } from \"./browser/paths\";\r\nexport type { LaunchPathOptions } from \"./browser/paths\";\r\nexport { startWebSocketServer, notifyReload } from \"./server/ws-server\";\r\nexport type { ExtensionErrorPayload, DebugServerOpts, WsServerMode } from \"./server/ws-server\";\r\nexport {\r\n getCompilationFromStats,\r\n getEntrypointSignature,\r\n getEntriesSignature,\r\n getReloadEntriesSignature,\r\n getContentEntriesSignature,\r\n getReloadManagerDecision,\r\n getReloadKindFromDecision,\r\n isContentChanged,\r\n getEntryToModulePaths,\r\n getEntriesForFile,\r\n} from \"./hmr/scope\";\r\nexport type { ReloadManagerDecision, ReloadKind } from \"./hmr/scope\";\r\nexport { normalizePathForCompare } from \"./hmr/disable\";\r\nexport {\r\n getCacheRoot,\r\n getBrowserProfileDir,\r\n /** @deprecated Use getCacheRoot/getBrowserProfileDir instead */\r\n getCacheTempRoot,\r\n getChromiumUserDataDir,\r\n getReloadManagerPath,\r\n findExistingReloadManager,\r\n ensureDistReady,\r\n} from \"./manager/extension\";\r\nexport {\r\n launchBrowser,\r\n launchBrowserOnly,\r\n cleanup,\r\n registerCleanupHandlers,\r\n statsHasErrors,\r\n} from \"./browser/launcher\";\r\nexport type { LaunchOnlyOptions, ChromiumRunnerOverride } from \"./browser/launcher\";\r\nexport { createTestWsServer } from \"./server/test-server\";\r\nexport { createHmrRspackPlugin } from \"./hmr/rspack-plugin\";\r\n\r\n/**\r\n * Rsbuild plugin: in dev mode launches browser after first compile;\r\n * notifies reload only when content or background entry (or their dependencies) changed;\r\n * disables HMR/liveReload for content/background via transform and optional entry tag injection.\r\n */\r\nexport function hmrPlugin(\r\n options: HmrPluginOptions,\r\n testDeps?: HmrPluginTestDeps\r\n): RsbuildPlugin {\r\n const entriesOrPaths = options.reloadManagerEntries ?? [];\r\n\r\n return {\r\n name: \"rsbuild-plugin-extension-hmr\",\r\n setup(api: RsbuildPluginAPI) {\r\n api.onAfterDevCompile(async ({ stats }) => {\r\n await clearOutdatedHotUpdateFiles(options.distPath, stats);\r\n\r\n if (options.enableReload === false || !stats) return;\r\n\r\n const compiler = getLastCompiler();\r\n const modifiedFiles = getModifiedFilesFromCompiler(compiler);\r\n\r\n const { shouldNotify, contentChanged, backgroundChanged } = getReloadManagerDecision(stats, {\r\n compiler: { modifiedFiles: modifiedFiles.size > 0 ? modifiedFiles : undefined },\r\n });\r\n if (shouldNotify) {\r\n const kind = getReloadKindFromDecision(\r\n contentChanged,\r\n backgroundChanged,\r\n options.autoRefreshContentPage ?? false\r\n );\r\n notifyReload(kind);\r\n }\r\n });\r\n\r\n api.onBeforeStartDevServer(() => {\r\n if (entriesOrPaths.length === 0) return;\r\n api.transform(\r\n { test: /\\.(js|ts)$/, environments: [\"web\"] },\r\n ({ resourcePath, code }) =>\r\n transformCodeToDisableHmr(resourcePath, entriesOrPaths, code)\r\n );\r\n });\r\n\r\n api.onBeforeCreateCompiler(async ({ bundlerConfigs }) => {\r\n const config = bundlerConfigs[0] as { plugins?: unknown[] } | undefined;\r\n if (!config) return;\r\n config.plugins = config.plugins ?? [];\r\n config.plugins.push(createHmrRspackPlugin(options, testDeps));\r\n });\r\n },\r\n };\r\n}\r\n"],"names":["collectHotUpdateAssetNames","statsList","names","Set","s","stats","json","asset","name","removeStaleHotUpdateFiles","distPath","keepNames","entries","readdir","entry","full","resolve","rel","rm","clearOutdatedHotUpdateFiles","rootStats","list","Array","RELOAD_ENTRY_NAMES","CONTENT_ENTRY_NAMES","ADDFOX_ENTRY_TAG_PREFIX","getEntryTag","entryName","RELOAD_MANAGER_ENTRY_NAMES","HMR_INVALIDATE_PREPEND","pathCache","Map","normalizePathForCompare","p","cached","normalized","createPathComparer","resourcePath","entryPath","findEntryByPath","comparer","e","isReloadManagerEntryList","v","normalizeEntries","entriesOrPaths","path","buildTransformedCode","originalCode","tag","parts","transformCodeToDisableHmr","code","matchingEntry","EXCLUDED_CHROME_FLAGS","DEFAULT_CHROME_FLAGS","ChromeLauncher","flag","ChromeDevtoolsProtocolClient","Promise","chromiumInstance","pipes","Error","incoming","outgoing","data","error","method","params","sessionId","message","id","rawMessage","JSON","reject","err","addfoxError","end","parsed","result","deferred","ChromiumExtensionRunner","options","chromiumLaunch","defaultChromiumLaunch","console","chromeFlags","buildChromeFlags","instance","loaded","initial","cdp","extensions","sourceDir","isLoadUnpackedUnsupported","String","flags","runChromiumRunner","runner","BROWSER_DEFAULT_PATHS","getLaunchPathFromOptions","browser","map","buildDefaultPaths","platform","basePaths","userProfile","process","localAppData","getBrowserPath","userPath","paths","existsSync","isChromiumBrowser","wsServer","httpServer","debugServerOpts","getBundlerLine","getFrameworkLine","root","detectFrontendFramework","buildExtensionErrorLines","payload","opts","errorType","timeStr","Number","Date","stack","filename","lineno","undefined","colno","loc","aiPromptLines","buildAiPromptForExtensionRuntimeError","lines","logExtensionErrorToTerminal","writeExtensionErrorBlock","buildErrorMarkdown","frameworkName","aiContext","summary","getErrorMdPath","outputRoot","join","deleteErrorMdOnStart","unlink","writeErrorMdAsync","dir","content","queueMicrotask","mkdir","writeFile","handleHttpRequest","req","res","body","chunk","bindHttpListen","server","port","startHttpServerOnly","startTime","t0","createServer","ms","Math","performance","logDoneTimed","startWebSocketServer","mode","WebSocketServer","ws","WebSocket","notifyReload","kind","client","logDone","closeWebSocketServer","BROWSER_PROFILE_DIR","DEFAULT_OUTPUT_ROOT","splitPathSegments","Boolean","resolveCacheRootByOutputRoot","rootName","rootIndex","prefix","sep","hasDrivePrefix","normalizedPrefix","getCacheRoot","resolved","getBrowserProfileDir","getCacheTempRoot","getChromiumUserDataDir","getReloadManagerPath","findExistingReloadManager","cacheRoot","extPath","manifestPath","bgPath","RELOAD_MANAGER_SCRIPT_VERSION","ensureDistReady","timeoutMs","statSync","start","r","setTimeout","createReloadManagerExtension","wsPort","bgJsPath","portCachePath","scriptVersionPath","needsUpdate","cachedPort","parseInt","readFile","cachedVer","bgJs","installedUninstall","installWebExtConsoleStreamHook","consoleStream","stream","originalWrite","jsonString","pushWebExtStdoutOrigin","popWebExtStdoutOrigin","removeWebExtConsoleStreamHook","buildDebugServerOpts","ctx","computeReloadServerPlan","debugOpts","startReloadServersForPlan","plan","extensionRunner","reloadManagerPath","browserLaunched","isCleaningUp","cleanupHandlersRegistered","lastDistPath","lastOutputRoot","chromiumUserDataDirPath","lastChromiumBrowser","cacheEnabled","keyboardReloadCleanup","addfoxDevResourcesTornDown","firefoxWebExtSessionActive","firefoxSigintHintConsumed","MSG_FIREFOX_CLOSE_BROWSER_THEN_CTRL_C","EXIT_TIMEOUT_MS","FIREFOX_CHILD_CLOSE_MAX_MS","WIN32_PROFILE_UNLOCK_MS","withTimeout","promise","timer","clearTimeout","getFirefoxChildFromWebExtRunner","multi","isFirefoxChildLikelyRunning","firefox","delayMs","yieldForWindowsProfileUnlock","waitForFirefoxChildAfterWebExtExit","once","teardownAddfoxDevResources","userDataDir","cleanup","restoreStdinAfterWebExt","er","stdin","exitProcessAfterWebExtFirefoxClosed","registerWebExtFirefoxResourceTeardown","reg","handleTerminalExitRequest","signal","log","stdinChunkHasCtrlC","i","registerStdinRShortcut","onPressR","onData","c","registerManualReloadShortcut","enableReload","registerCleanupHandlers","runFirefoxWebExt","browserBinary","onExit","webExt","runOptions","firefoxExited","ANSI_COLORS","proc","launchBrowserCore","launchStart","readyFn","launchChromiumBrowser","launchFirefoxBrowser","warn","runnerFn","launchBrowser","chromiumRunnerOverride","ensureDistReadyOverride","getBrowserPathOverride","cache","debug","onBrowserExit","setBrowserLaunched","value","getBrowserLaunched","statsHasErrors","launchBrowserOnly","resolveClosed","closedPromise","doLaunch","lastCompiler","getLastCompiler","getModifiedFilesFromCompiler","compiler","out","watcher","mtimes","_","key","Object","LAUNCH_PLUGIN_NAME","LAUNCH_DELAY_MS","createHmrRspackPlugin","testDeps","autoOpen","done","state","getNormalizedStats","arr","getStatsJson","toJson","getCompilationFromStats","comp","getStatsFromCompilation","compilation","normalizePath","createPathMatcher","filePath","norm","other","suffix","sn","on","collectAssetHashes","info","findAsset","raw","a","getEntrypointSignatureFromAssets","entrypoint","files","getEntrypointSignature","hashes","h","getSingleEntrySignature","RELOAD_MANAGER_NAMES","getEntrySignatures","entryNames","sig","getEntriesSignature","sigs","buildChunkIdToEntryNames","chunks","ch","set","buildChunkIdToEntryNamesFromStats","n","addPathToEntries","entryToPaths","extractModulePath","mod","collectModuleEntryNames","chunkIdToEntryNames","processFlatModules","modules","processNestedModules","getEntryToModulePaths","statsJson","getEntriesForFile","matcher","doFilesAffectReloadManager","modifiedFiles","filesAffectEntry","compareSignatures","contentSig","backgroundSig","contentChanged","backgroundChanged","shouldNotify","updateSignatures","getReloadManagerDecision","context","sigComparison","hasModifiedFiles","hasEntryMapping","getReloadKindFromDecision","autoRefreshContentPage","isContentChanged","CONTENT_NAMES","changed","getReloadEntriesSignature","RELOAD_NAMES","getContentEntriesSignature","createTestWsServer","http","wss","hmrPlugin","api","bundlerConfigs","config"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { ChromiumLaunchTarget } from "@addfox/core";
2
+ /** Get the cache root directory (parent of distPath/cache) */
3
+ export declare function getCacheRoot(distPath: string, outputRoot?: string): string;
4
+ /** Get the browser profile directory path */
5
+ export declare function getBrowserProfileDir(distPath: string, outputRoot?: string): string;
6
+ /** @deprecated Use getBrowserProfileDir instead */
7
+ export declare function getCacheTempRoot(distPath: string, outputRoot?: string): string;
8
+ export declare function getChromiumUserDataDir(distPath: string, browser: ChromiumLaunchTarget, outputRoot?: string): string;
9
+ export declare function getReloadManagerPath(distPath: string, outputRoot?: string): string;
10
+ export declare function findExistingReloadManager(distPath: string, outputRoot?: string): string | null;
11
+ export declare function ensureDistReady(distPath: string, timeoutMs?: number): Promise<boolean>;
12
+ export declare function createReloadManagerExtension(wsPort: number, distPath: string): Promise<string>;
@@ -0,0 +1 @@
1
+ export { getCacheTempRoot, getChromiumUserDataDir, getReloadManagerPath, findExistingReloadManager, ensureDistReady, createReloadManagerExtension, } from "./extension";
@@ -0,0 +1,2 @@
1
+ export { startWebSocketServer, notifyReload, closeWebSocketServer, buildExtensionErrorLines, type ExtensionErrorPayload, type DebugServerOpts, } from "./ws-server";
2
+ export { createTestWsServer } from "./test-server";
@@ -0,0 +1,5 @@
1
+ /** Test helper: minimal WebSocket server with notifyReload. */
2
+ export declare function createTestWsServer(port: number): Promise<{
3
+ close: () => Promise<void>;
4
+ notifyReload: () => void;
5
+ }>;
@@ -0,0 +1,26 @@
1
+ import { WebSocketServer } from "ws";
2
+ import type { ReloadKind } from "../hmr/scope";
3
+ /** `full`: WebSocket + HTTP (reload + /addfox-error). `httpOnly`: HTTP only for monitor errors (Firefox / debug without Chromium reload). */
4
+ export type WsServerMode = "full" | "httpOnly";
5
+ export type ExtensionErrorPayload = {
6
+ entry?: string;
7
+ type?: string;
8
+ message?: string;
9
+ stack?: string;
10
+ filename?: string;
11
+ lineno?: number;
12
+ colno?: number;
13
+ time?: number;
14
+ };
15
+ export type DebugServerOpts = {
16
+ debug?: boolean;
17
+ root?: string;
18
+ outputRoot?: string;
19
+ distPath?: string;
20
+ };
21
+ export declare function buildExtensionErrorLines(payload: ExtensionErrorPayload, opts?: DebugServerOpts | null): string[];
22
+ export declare function buildAiPromptForExtensionRuntimeError(): string;
23
+ export declare function startWebSocketServer(port: number, startTime?: number, opts?: DebugServerOpts, mode?: WsServerMode): Promise<WebSocketServer | null>;
24
+ export type { ReloadKind } from "../hmr/scope";
25
+ export declare function notifyReload(kind: ReloadKind): void;
26
+ export declare function closeWebSocketServer(): void;
@@ -0,0 +1,40 @@
1
+ import type { LaunchTarget, ReloadManagerEntry } from "@addfox/core";
2
+ import type { LaunchPathOptions } from "./browser/paths";
3
+ import type { ChromiumRunnerOverride } from "./browser/launcher";
4
+ export interface HmrPluginOptions {
5
+ distPath: string;
6
+ autoOpen?: boolean;
7
+ browser?: LaunchTarget;
8
+ chromePath?: string;
9
+ chromiumPath?: string;
10
+ edgePath?: string;
11
+ bravePath?: string;
12
+ vivaldiPath?: string;
13
+ operaPath?: string;
14
+ santaPath?: string;
15
+ arcPath?: string;
16
+ yandexPath?: string;
17
+ browserosPath?: string;
18
+ customPath?: string;
19
+ firefoxPath?: string;
20
+ cache?: boolean;
21
+ wsPort?: number;
22
+ enableReload?: boolean;
23
+ autoRefreshContentPage?: boolean;
24
+ /**
25
+ * Content/background entries with name and absolute path.
26
+ * Enables precise entry tag injection and reloadManager-only scope; only these entries trigger WS notify.
27
+ */
28
+ reloadManagerEntries?: ReloadManagerEntry[];
29
+ /** When true, enable debug: error output with bundler/framework, and .addfox/error.md write/delete. */
30
+ debug?: boolean;
31
+ /** Project root (for framework detection and error.md path). */
32
+ root?: string;
33
+ /** Output root under project (e.g. ".addfox") for error.md path. */
34
+ outputRoot?: string;
35
+ }
36
+ export interface HmrPluginTestDeps {
37
+ runChromiumRunner?: ChromiumRunnerOverride;
38
+ ensureDistReady?: (distPath: string) => Promise<boolean>;
39
+ getBrowserPath?: (b: LaunchTarget, o: LaunchPathOptions) => string | null;
40
+ }
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@addfox/rsbuild-plugin-extension-hmr",
3
+ "version": "0.1.1-beta.2",
4
+ "description": "Rsbuild plugin: launch browser and HMR in dev (internal)",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "main": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "dependencies": {
21
+ "chrome-launcher": "^1.0.0",
22
+ "web-ext": "^9.0.0",
23
+ "@addfox/core": "0.1.1-beta.2",
24
+ "@addfox/common": "0.1.1-beta.2"
25
+ },
26
+ "devDependencies": {
27
+ "@rspack/core": "^1.7.8",
28
+ "@rsbuild/core": "^1.7.3",
29
+ "@rslib/core": "^0.20.0",
30
+ "@rstest/core": "^0.9.2",
31
+ "@rstest/coverage-istanbul": "^0.3.0",
32
+ "@types/node": "^20.0.0",
33
+ "@types/ws": "^8.5.0",
34
+ "typescript": "^5.0.0"
35
+ },
36
+ "peerDependencies": {
37
+ "@rsbuild/core": ">=1.0.0",
38
+ "@rspack/core": ">=1.0.0"
39
+ },
40
+ "optionalDependencies": {
41
+ "ws": "^8.18.0"
42
+ },
43
+ "scripts": {
44
+ "build": "rslib build",
45
+ "dev": "rslib build --watch",
46
+ "test": "rstest run",
47
+ "test:coverage": "rstest run --coverage"
48
+ }
49
+ }