@mherod/get-cookie 4.4.1 → 4.4.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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/utils/logger.ts","../src/utils/logHelpers.ts","../src/utils/platformUtils.ts","../src/utils/execSimple.ts","../src/core/browsers/chrome/ChromeApplicationSupport.ts","../src/core/browsers/chrome/windows/getChromePassword.ts","../src/core/browsers/chrome/linux/getChromePassword.ts","../src/core/browsers/sql/CookieQueryBuilder.ts","../src/utils/flatMapAsync.ts","../src/core/browsers/CompositeCookieQueryStrategy.ts","../src/core/browsers/chromium/BaseChromiumCookieQueryStrategy.ts","../src/utils/errorUtils.ts","../src/utils/ProcessDetector.ts","../src/utils/chromeDates.ts","../src/core/browsers/BaseCookieQueryStrategy.ts","../src/utils/BrowserControl.ts","../src/utils/FileHandleDetector.ts","../src/core/browsers/platform/PlatformBrowserControl.ts","../src/core/browsers/BrowserLockHandler.ts","../src/core/browsers/chrome/decrypt.ts","../src/core/browsers/chrome/windows/decryptV10Cookie.ts","../src/core/browsers/chrome/getChromiumPassword.ts","../src/core/browsers/sql/DatabaseConnectionManager.ts","../src/core/browsers/sql/QueryMonitor.ts","../src/core/browsers/listChromeProfiles.ts","../src/core/browsers/chrome/ChromeCookieQueryStrategy.ts","../src/core/browsers/chrome/ChromiumBrowsers.ts","../src/core/browsers/chromium/ChromiumCookieQueryStrategy.ts","../src/core/browsers/firefox/FirefoxCookieQueryStrategy.ts","../src/core/browsers/safari/SafariCookieQueryStrategy.ts","../src/utils/SystemPermissions.ts","../src/core/browsers/safari/BinaryCodableCookies.ts","../src/core/browsers/safari/BinaryCodablePage.ts","../src/types/schemas.ts","../src/core/browsers/safari/BinaryCodableCookie.ts","../src/core/browsers/safari/decodeBinaryCookies.ts","../src/core/cookies/getCookie.ts","../src/core/cookies/queryCookies.ts","../src/core/cookies/batchGetCookies.ts","../src/core/cookies/batchQueryCookies.ts"],"names":["EnvironmentSchema","env","init_config","__esmMin","config","z","val","homedir","consola","logger","logger_default","init_logger","createConsola","logError","message","error","context","errorMessage","logWarn","component","createTaggedLogger","init_logHelpers","getPlatform","platformCache","osPlatform","isMacOS","isWindows","isPlatformSupported","p","assertPlatformSupported","init_platformUtils","execSimple","command","options","result","execPromise","CommandExecutionError","init_execSimple","promisify","exec","originalError","chromeApplicationSupport","init_ChromeApplicationSupport","home","join","getChromePassword_exports","__export","getChromePassword","decryptDPAPIKey","encryptedKey","DPAPI_PREFIX","encryptedData","dpapi","localStatePath","localStateContent","readFileSync","localState","encryptedKeyBuffer","init_getChromePassword","password","CookieQueryBuilder_exports","CookieQueryBuilder","createQueryBuilder","isSqlBrowser","browser","BROWSER_SCHEMAS","init_CookieQueryBuilder","name","domain","exactDomain","limit","includeExpired","schema","selectColumns","whereClause","params","sql","specs","specConditions","allParams","spec","combinedWhere","minLimit","min","key","columns","col","conditions","nowSeconds","sqlKeywords","checkString","str","field","upperStr","keyword","flatMapAsync","array","callback","defaultValue","item","CompositeCookieQueryStrategy","strategies","strategy","store","force","getErrorMessage","getErrorDetails","errorMessageContains","searchText","DATABASE_ERROR_PATTERNS","containsAnyPattern","patterns","pattern","getDatabaseErrorType","formatErrorForLogging","details","ensureError","fallbackMessage","standardError","parseProcessLine","line","defaultCommand","parts","pidStr","pid","parsedCommand","parseWindowsProcessLine","detectBrowserProcesses","browserName","grepPattern","windowsProcessMap","processName","stdout","processes","lines","processInfo","isFirefoxRunning","isChromeRunning","isSafariRunning","getBrowserConflictAdvice","processCount","browserDisplayName","chromeTimestampToDate","chromeTimestamp","unixTimestampSeconds","fallbackLogger","BaseCookieQueryStrategy","strategyName","taggedLogger","execAsync","isInteractiveEnvironment","isCI","isTest","BROWSER_APP_NAMES","isBrowserRunningMacOS","appName","script","quitBrowserMacOS","quitScript","resolve","saveBrowserSessionMacOS","promptUserConfirmation","rl","readline","answer","closeBrowserGracefully","success","waitForBrowserToClose","maxWaitMs","startTime","checkInterval","execFileAsync","execFile","parseFuserLine","user","mode","isValidProcessResult","value","parsePowerShellOutput","handles","parsed","results","processId","parseError","detectWithLsof","filePath","fd","handle","detectWithFuser","output","detectOnWindows","escapedPath","psScript","detectWithHandleExe","match","detectFileHandles","os","h","getFileLockInfo","BasePlatformBrowserControl","_BasePlatformBrowserControl","executables","exe","checkCommand","args","MacOSBrowserControl","WindowsBrowserControl","LinuxBrowserControl","cmd","platformControlInstance","createPlatformBrowserControl","platformOverride","currentPlatform","control","createControlForPlatform","platform","BrowserLockHandler","platformControl","file","autoClose","dbErrorType","fileHandles","lockInfo","handleError","processError","processesWithDetails","advice","relaunchError","decryptV10Cookie","encryptedValue","VERSION_PREFIX","ciphertext","NONCE_LENGTH","TAG_LENGTH","nonce","authTag","decipher","createDecipheriv","isV10Cookie","memoizeBuffer","fn","keyFn","cache","cachedResult","removeV10Prefix","removePadding","decrypted","padding","extractValue","decodedString","uuidMatch","endPatterns","cleanupPatterns","decrypt","metaVersion","reject","pbkdf2","iv","e","MACOS_KEYCHAIN_SERVICES","getMacOSPassword","service","chromeCommand","getWindowsPassword","getLinuxPassword","getChromiumPassword","DatabaseConnectionManager","EventEmitter","filepath","now","existing","lastError","attempt","database","BetterSqlite3","metadata","connectionTime","queryFn","queryDescription","connection","duration","metrics","totalQueryTime","totalQueryCount","activeConnections","toClose","lruPath","lruTime","ms","globalManager","exitHandler","getGlobalConnectionManager","QueryMonitor","db","execution","stmt","MonitoredStatement","statement","monitor","globalMonitor","getGlobalQueryMonitor","createExportedCookie","expiry","BaseChromiumCookieQueryStrategy","browserType","files","fileResults","connectionManager","queryBuilder","queryOptions","queryConfig","encryptedCookies","row","cookie","cookieFiles","lockResult","shouldRelaunch","cookies","retryError","metaQuery","metaResult","decryptedValue","listChromeProfilePaths","fg","ChromeCookieQueryStrategy","profileName","paths","fs","path","firstPath","chromeDataDir","dirname","profileCache","targetDir","dir","info","cookiePath","getChromiumBrowserPath","ChromiumCookieQueryStrategy","browserPath","findFirefoxCookieFiles","profileDirs","devEditionPath","existsSync","esrPath","localFirefoxPath","matches","FirefoxCookieQueryStrategy","retryConfig","fileList","openFullDiskAccessSettings","getTerminalApp","termProgram","promptForPermissionGrant","handleSafariPermissionError","terminalApp","checkFilePermission","CookieDomainSchema","CookieNameSchema","CookiePathSchema","CookieValueSchema","destr","BinaryCookieRowSchema","CookieSpecSchema","CookieMetaSchema","BrowserNameSchema","CookieQueryStrategySchema","BaseCookieQueryOptionsSchema","SqlBrowserTypeSchema","BinaryCodableCookie","buffer","container","processed","lastProcessed","token","payloadPart","payload","Buffer","primitiveResult","stringValue","decoded","jwtResult","jsonResult","jwtPayload","jsonValue","macTimestamp","flagsValue","expiryUnix","creationUnix","size","version","hasPort","offsets","expirationBuffer","i","expiration","creationBuffer","creation","offsetEntries","entry","a","b","offset","length","end","baseOffset","_BinaryCodablePage","cookieRow","header","cookieCount","pageStart","cookieOffsets","cookieOffset","footer","cookieSize","cookieBuffer","BinaryCodablePage","_BinaryCodableCookies","page","pageCookies","magic","pageCount","pageSizes","pageSize","currentOffset","pageBuffer","checksum","BinaryCodableCookies","decodeBinaryCookies","cookieDbPath","SafariCookieQueryStrategy","flags","bit","formattedDomain","nameMatches","domainMatches","cookieObj","normalizedName","normalizedDomain","firstAttemptResult","queryCookies","cookieSpec","getCookie","validateSpecs","supportsBatchQueries","processIndividualResults","continueOnError","errors","queryStrategy","validSpecs","err","batchQueryCookies","allResults","allErrors","batchGetCookies","deduplicate","concurrency","fallbackToIndividualQueries","deduped","deduplicateCookies","groupCookiesBySpec","allCookies","specCookies","processChunkWithResults","chunk","chunkPromises","batchGetCookiesWithResults","chunkResults","processChunk","cookieMap","existingLength","currentLength"],"mappings":"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","file":"index.js","sourcesContent":["import { homedir } from \"node:os\";\n\nimport { config } from \"dotenv\";\nimport { z } from \"zod\";\n\n// Load environment variables from .env file\nconfig();\n\nconst EnvironmentSchema = z.object({\n LOG_LEVEL: z.enum([\"debug\", \"info\", \"warn\", \"error\"]).default(\"info\"),\n HOME: z\n .string()\n .optional()\n .transform((val) => val ?? process.env.USERPROFILE ?? \"\")\n .pipe(z.string().min(1)),\n});\n\n/**\n * Validated environment variables with type safety and fallbacks\n * @example\n * // Using the environment variables\n * if (env.LOG_LEVEL === \"debug\") {\n * console.log(\"Debug mode enabled\");\n * }\n *\n * // Accessing home directory\n * const cookiePath = join(env.HOME, \"Library/Cookies\");\n */\nexport const env = EnvironmentSchema.parse({\n LOG_LEVEL: process.env.LOG_LEVEL,\n HOME: homedir(),\n});\n","import { type ConsolaInstance, createConsola } from \"consola\";\n\nimport { env } from \"../config\";\n\n/**\n * Standard log levels and their usage:\n * - debug: Detailed information for debugging\n * - info: General operational information\n * - success: Successful operations\n * - warn: Warning conditions\n * - error: Error conditions that might still allow the app to continue\n * - fatal: Critical errors that prevent the app from continuing\n */\nconst consola = createConsola({\n formatOptions: {\n showLogLevel: false,\n colors: true,\n date: false,\n compact: true,\n columns:\n typeof process.stdout.columns === \"number\" ? process.stdout.columns : 80,\n },\n level: env.LOG_LEVEL === \"debug\" ? 5 : 2,\n});\n\n/**\n * Indicates whether debug logging is enabled\n * @example\n * if (isDebug) {\n * logger.debug(\"Detailed debugging information\");\n * }\n */\nexport const isDebug = env.LOG_LEVEL === \"debug\";\n\n/**\n * Configured logger instance with standardized formatting and colored output.\n * Used for consistent logging throughout the application.\n * @example\n * // Basic usage\n * logger.info('Operation started');\n * logger.success('Task completed');\n * logger.error('Failed to process', error);\n *\n * // Tagged logging for module context\n * const moduleLogger = logger.withTag('ModuleName');\n * moduleLogger.info('Module specific log');\n *\n * // Structured logging\n * logger.info('User action', {\n * userId: '123',\n * action: 'login',\n * timestamp: new Date()\n * });\n *\n * // Error logging with full context\n * logger.error('Operation failed', {\n * error: error,\n * context: 'operation name',\n * input: data\n * });\n */\nconst logger: ConsolaInstance = consola;\n\n/**\n *\n */\nexport default logger;\n","import type { ConsolaInstance } from \"consola\";\n\nimport logger from \"./logger\";\n\n/**\n * Helper functions for common logging patterns.\n * @module\n * @example\n * ```typescript\n * import { logOperationResult, logError } from './logHelpers';\n *\n * try {\n * const result = await someOperation();\n * logOperationResult('Operation', true, { data: result });\n * } catch (error) {\n * logError('Operation failed', error);\n * }\n * ```\n */\n\ninterface OperationContext {\n [key: string]: unknown;\n}\n\n/**\n * Log the result of an operation with consistent formatting\n * @param operation - The name of the operation\n * @param success - Whether the operation was successful\n * @param context - Additional context to log\n */\nexport function logOperationResult(\n operation: string,\n success: boolean,\n context?: OperationContext,\n): void {\n if (success) {\n logger.success(`${operation} succeeded`, context);\n } else {\n logger.error(`${operation} failed`, context);\n }\n}\n\n/**\n * Log an error with consistent formatting\n * @param message - The error message\n * @param error - The error object\n * @param context - Additional context to log\n */\nexport function logError(\n message: string,\n error: unknown,\n context?: OperationContext,\n): void {\n const errorMessage = error instanceof Error ? error.message : String(error);\n logger.error(message, { ...context, error: errorMessage });\n}\n\n/**\n * Log a warning with consistent formatting\n * @param component - The component generating the warning\n * @param message - The warning message\n * @param context - Additional context to log\n */\nexport function logWarn(\n component: string,\n message: string,\n context?: OperationContext,\n): void {\n logger.warn(`[${component}] ${message}`, context);\n}\n\n/**\n * Create a logger instance with a component tag\n * @param component - The component name to tag logs with\n * @returns A logger instance that prefixes all messages with the component tag\n * @example\n * ```typescript\n * const dbLogger = createTaggedLogger('Database');\n * dbLogger.info('Connection established');\n * ```\n */\nexport function createTaggedLogger(component: string): ConsolaInstance {\n return logger.withTag(component);\n}\n\n// Re-export the base logger for direct usage\n/**\n * Re-export of the base logger for direct usage.\n */\nexport { default as logger } from \"./logger\";\n","import { platform as osPlatform } from \"node:os\";\n\n/**\n * Cache for platform value\n */\nlet platformCache: string | undefined;\n\n/**\n * Clear the platform cache (for testing)\n * @internal\n */\nexport function clearPlatformCache(): void {\n platformCache = undefined;\n}\n\n/**\n * Supported platform types\n */\nexport type Platform = \"darwin\" | \"win32\" | \"linux\";\n\n/**\n * Get the current platform (with caching)\n * @returns The current platform from os.platform()\n */\nexport function getPlatform(): string {\n platformCache ??= osPlatform();\n return platformCache;\n}\n\n/**\n * Check if the current platform is macOS\n * @returns True if running on macOS\n */\nexport function isMacOS(): boolean {\n return getPlatform() === \"darwin\";\n}\n\n/**\n * Check if the current platform is Windows\n * @returns True if running on Windows\n */\nexport function isWindows(): boolean {\n return getPlatform() === \"win32\";\n}\n\n/**\n * Check if the current platform is Linux\n * @returns True if running on Linux\n */\nexport function isLinux(): boolean {\n return getPlatform() === \"linux\";\n}\n\n/**\n * Check if the current platform is Unix-like (macOS, Linux, FreeBSD, etc.)\n * @returns True if running on a Unix-like system\n */\nexport function isUnixLike(): boolean {\n const p = getPlatform();\n return p !== \"win32\";\n}\n\n/**\n * Check if the current platform is supported\n * @returns True if the platform is supported\n */\nexport function isPlatformSupported(): boolean {\n const p = getPlatform();\n return p === \"darwin\" || p === \"win32\" || p === \"linux\";\n}\n\n/**\n * Get a human-readable platform name\n * @returns A human-readable platform name\n */\nexport function getPlatformDisplayName(): string {\n const platform = getPlatform();\n switch (platform) {\n case \"darwin\":\n return \"macOS\";\n case \"win32\":\n return \"Windows\";\n case \"linux\":\n return \"Linux\";\n default:\n return platform;\n }\n}\n\n/**\n * Throw an error if the current platform is not supported\n * @throws Error if platform is not supported\n */\nexport function assertPlatformSupported(): void {\n if (!isPlatformSupported()) {\n throw new Error(\n `Unsupported platform: ${getPlatform()}. Supported platforms are: darwin, win32, linux`,\n );\n }\n}\n\n/**\n * Get platform-specific path separator\n * @returns The path separator for the current platform\n */\nexport function getPathSeparator(): string {\n return isWindows() ? \"\\\\\" : \"/\";\n}\n\n/**\n * Get platform-specific executable extension\n * @returns The executable extension for the current platform\n */\nexport function getExecutableExtension(): string {\n return isWindows() ? \".exe\" : \"\";\n}\n\n/**\n * Check if the current platform matches any of the specified platforms\n * @param platforms - Platform or platforms to check against current platform\n * @returns True if the current platform matches any of the specified platforms\n */\nexport function isPlatform(...platforms: string[]): boolean {\n const current = osPlatform();\n return platforms.includes(current);\n}\n","// External imports\nimport { type ExecOptions, exec } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\n// Internal imports\nimport { logError } from \"./logHelpers\";\n\nconst execPromise = promisify(exec);\n\n/**\n * Custom error class for command execution failures.\n * @property {string} command - The command that failed to execute\n * @property {Error} [originalError] - The underlying error that caused the failure\n * @throws CommandExecutionError Always throws with appropriate error context\n * @example\n * ```typescript\n * throw new CommandExecutionError(\n * 'Command timed out',\n * 'git status',\n * originalError\n * );\n * ```\n */\nclass CommandExecutionError extends Error {\n public constructor(\n message: string,\n public readonly command: string,\n public readonly originalError?: Error,\n ) {\n super(message);\n this.name = \"CommandExecutionError\";\n }\n}\n\n/**\n * Executes a shell command and returns its output.\n * @param command - The command to execute\n * @param options - Optional execution options\n * @returns Promise resolving to command output\n * @throws CommandExecutionError if execution fails\n * @example\n * ```typescript\n * try {\n * const { stdout } = await execSimple('git status');\n * logger.info('Git status:', stdout);\n * } catch (error) {\n * if (error instanceof CommandExecutionError) {\n * logger.error('Git command failed:', error.message);\n * }\n * }\n * ```\n */\nexport async function execSimple(\n command: string,\n options?: ExecOptions,\n): Promise<{ stdout: string; stderr: string }> {\n try {\n const result = await execPromise(command, {\n ...options,\n encoding: \"utf8\",\n });\n return {\n stdout: result.stdout.toString(),\n stderr: result.stderr.toString(),\n };\n } catch (error) {\n logError(\"Command execution failed\", error, { command });\n throw new CommandExecutionError(\n error instanceof Error ? error.message : String(error),\n command,\n error instanceof Error ? error : undefined,\n );\n }\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { assertPlatformSupported, getPlatform } from \"@utils/platformUtils\";\n\n/**\n * The path to Chrome's application support directory for the current platform\n * This constant is used to locate Chrome's profile and cookie storage directories\n * @throws {Error} If unable to determine user's home directory or platform is not supported\n */\nexport const chromeApplicationSupport = (() => {\n const home = homedir();\n if (!home) {\n throw new Error(\"Unable to determine user home directory\");\n }\n\n assertPlatformSupported();\n\n switch (getPlatform()) {\n case \"darwin\":\n return join(home, \"Library\", \"Application Support\", \"Google\", \"Chrome\");\n case \"win32\":\n return join(home, \"AppData\", \"Local\", \"Google\", \"Chrome\", \"User Data\");\n case \"linux\":\n return join(home, \".config\", \"google-chrome\");\n default:\n // This should never happen due to assertPlatformSupported\n throw new Error(`Platform ${getPlatform()} is not supported`);\n }\n})();\n","import { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { isWindows } from \"@utils/platformUtils\";\n\nimport { chromeApplicationSupport } from \"../ChromeApplicationSupport\";\n\n/**\n * Windows Chrome Local State file structure for encrypted key\n */\ninterface WindowsChromeLocalState {\n os_crypt: {\n encrypted_key: string;\n };\n}\n\n/**\n * Decrypts Windows DPAPI encrypted key using Windows CryptoAPI\n * On Windows, Chrome uses DPAPI (Data Protection API) to encrypt the master key\n * which is then used to encrypt cookies.\n * @param encryptedKey - The DPAPI encrypted key buffer\n * @returns A promise that resolves to the decrypted key as a Buffer\n * @throws {Error} If DPAPI decryption fails or key format is invalid\n */\nasync function decryptDPAPIKey(encryptedKey: Buffer): Promise<Buffer> {\n // Remove the DPAPI prefix (first 5 bytes: \"DPAPI\")\n const DPAPI_PREFIX = Buffer.from(\"DPAPI\");\n if (!encryptedKey.subarray(0, 5).equals(DPAPI_PREFIX)) {\n throw new Error(\"Invalid DPAPI key prefix\");\n }\n\n const encryptedData = encryptedKey.subarray(5);\n\n // Try to use native DPAPI if available on Windows\n if (isWindows()) {\n try {\n // Use dynamic import to load optional dependency at runtime\n // This works in both ESM and CommonJS contexts\n const moduleName = \"@primno\" + \"/dpapi\"; // Split to prevent static analysis\n const dpapi = (await import(moduleName)) as {\n unprotectData: (data: Buffer) => Buffer;\n };\n\n if (typeof dpapi.unprotectData === \"function\") {\n return dpapi.unprotectData(encryptedData);\n }\n } catch (error) {\n // Module not available or failed to load - this is expected for optional dependency\n // Don't log the full error to avoid cluttering output\n if (process.env.VERBOSE !== undefined && process.env.VERBOSE !== \"\") {\n console.warn(\"DPAPI module not available:\", error);\n }\n }\n }\n\n // Fallback for testing or when DPAPI is not available\n // This won't work for real encrypted cookies but allows the code to run\n throw new Error(\n \"Windows DPAPI decryption requires native bindings. Install @primno/dpapi package for Windows support.\",\n );\n}\n\n/**\n * Retrieves the Chrome Safe Storage password on Windows\n * On Windows, Chrome stores an encrypted master key in Local State file\n * which is encrypted using Windows DPAPI (Data Protection API)\n * @returns A promise that resolves to the Chrome Safe Storage password\n * @throws {Error} If the password cannot be retrieved from Local State file\n */\nexport async function getChromePassword(): Promise<string> {\n try {\n const localStatePath = join(chromeApplicationSupport, \"Local State\");\n const localStateContent = readFileSync(localStatePath, \"utf8\");\n const localState = JSON.parse(localStateContent) as WindowsChromeLocalState;\n\n if (!localState.os_crypt.encrypted_key) {\n throw new Error(\"No encrypted key found in Chrome Local State\");\n }\n\n // Decode the base64 encrypted key\n const encryptedKeyBuffer = Buffer.from(\n localState.os_crypt.encrypted_key,\n \"base64\",\n );\n\n // Decrypt using DPAPI\n const masterKey = await decryptDPAPIKey(encryptedKeyBuffer);\n\n // Return the key as a buffer (not string) for use in AES-GCM decryption\n return masterKey.toString(\"latin1\");\n } catch (error) {\n throw new Error(\n `Failed to retrieve Chrome password on Windows: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n","import { execSimple } from \"../../../../utils/execSimple\";\n\n/**\n * Attempts to retrieve Chrome password from various Linux keyrings\n *\n * Chrome on Linux can store passwords in:\n * 1. GNOME Keyring (via libsecret)\n * 2. KWallet (KDE)\n * 3. Basic password store (plaintext \"peanuts\")\n * @returns The Chrome Safe Storage password\n */\nexport async function getChromePassword(): Promise<string> {\n // Try different methods in order of preference\n\n // Method 1: Try libsecret (GNOME Keyring)\n try {\n const command =\n \"secret-tool lookup application chrome-libsecret-password-v2 || \" +\n \"secret-tool lookup application chrome\";\n const result = await execSimple(command);\n const password = result.stdout.trim();\n if (password) {\n return password;\n }\n } catch {\n // Continue to next method\n }\n\n // Method 2: Try python keyring module\n try {\n const command =\n \"python3 -c \\\"import keyring; print(keyring.get_password('Chrome Safe Storage', 'Chrome'))\\\"\";\n const result = await execSimple(command);\n const password = result.stdout.trim();\n if (password && password !== \"None\") {\n return password;\n }\n } catch {\n // Continue to next method\n }\n\n // Method 3: Try KWallet (KDE)\n try {\n const command =\n 'kwallet-query kdewallet -f \"Chrome Safe Storage\" -r Chrome';\n const result = await execSimple(command);\n const password = result.stdout.trim();\n if (password) {\n return password;\n }\n } catch {\n // Continue to fallback\n }\n\n // Method 4: Fallback to default password\n // On some Linux systems, Chrome uses a hardcoded password\n return \"peanuts\";\n}\n","/**\n * Unified SQL query builder for cookie database operations\n * Provides a centralized, type-safe way to build SQL queries for different browsers\n */\n\nimport type { SqlCookieQueryOptions } from \"../../../types/schemas\";\n\n/**\n * Browser types that use SQL databases for cookie storage\n */\nexport type SqlBrowserType =\n | \"chrome\"\n | \"chromium\"\n | \"edge\"\n | \"firefox\"\n | \"opera\"\n | \"brave\"\n | \"arc\";\n\n/**\n * SQL query configuration\n */\nexport interface SqlQueryConfig {\n sql: string;\n params: unknown[];\n description?: string;\n}\n\n/**\n * Cookie query options - re-export from schemas for backward compatibility\n */\nexport type CookieQueryOptions = SqlCookieQueryOptions;\n\n/**\n * Database schema information\n */\ninterface BrowserSchema {\n tableName: string;\n nameColumn: string;\n valueColumn: string;\n domainColumn: string;\n expiryColumn: string;\n encryptedValueColumn?: string;\n pathColumn?: string;\n secureColumn?: string;\n httpOnlyColumn?: string;\n}\n\n/**\n * Browser-specific SQL schemas\n */\nconst BROWSER_SCHEMAS: Record<SqlBrowserType, BrowserSchema> = {\n chrome: {\n tableName: \"cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host_key\",\n expiryColumn: \"expires_utc\",\n encryptedValueColumn: \"encrypted_value\",\n pathColumn: \"path\",\n secureColumn: \"is_secure\",\n httpOnlyColumn: \"is_httponly\",\n },\n chromium: {\n tableName: \"cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host_key\",\n expiryColumn: \"expires_utc\",\n encryptedValueColumn: \"encrypted_value\",\n pathColumn: \"path\",\n secureColumn: \"is_secure\",\n httpOnlyColumn: \"is_httponly\",\n },\n edge: {\n tableName: \"cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host_key\",\n expiryColumn: \"expires_utc\",\n encryptedValueColumn: \"encrypted_value\",\n pathColumn: \"path\",\n secureColumn: \"is_secure\",\n httpOnlyColumn: \"is_httponly\",\n },\n opera: {\n tableName: \"cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host_key\",\n expiryColumn: \"expires_utc\",\n encryptedValueColumn: \"encrypted_value\",\n pathColumn: \"path\",\n secureColumn: \"is_secure\",\n httpOnlyColumn: \"is_httponly\",\n },\n brave: {\n tableName: \"cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host_key\",\n expiryColumn: \"expires_utc\",\n encryptedValueColumn: \"encrypted_value\",\n pathColumn: \"path\",\n secureColumn: \"is_secure\",\n httpOnlyColumn: \"is_httponly\",\n },\n arc: {\n tableName: \"cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host_key\",\n expiryColumn: \"expires_utc\",\n encryptedValueColumn: \"encrypted_value\",\n pathColumn: \"path\",\n secureColumn: \"is_secure\",\n httpOnlyColumn: \"is_httponly\",\n },\n firefox: {\n tableName: \"moz_cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host\",\n expiryColumn: \"expiry\",\n pathColumn: \"path\",\n secureColumn: \"isSecure\",\n httpOnlyColumn: \"isHttpOnly\",\n },\n};\n\n/**\n * SQL query builder for cookie operations\n */\nexport class CookieQueryBuilder {\n private readonly schema: BrowserSchema;\n private readonly browser: SqlBrowserType;\n\n /**\n *\n * @param browser\n */\n constructor(browser: SqlBrowserType) {\n this.browser = browser;\n this.schema = BROWSER_SCHEMAS[browser];\n if (!this.schema) {\n throw new Error(`Unsupported browser type: ${browser}`);\n }\n }\n\n /**\n * Build a SELECT query for cookies\n * @param options\n */\n buildSelectQuery(options: CookieQueryOptions): SqlQueryConfig {\n const { name, domain, exactDomain, limit, includeExpired } = options;\n const schema = this.schema;\n\n // Build SELECT clause based on browser type\n const selectColumns = this.buildSelectColumns();\n\n // Build WHERE clause\n const { whereClause, params } = this.buildWhereClause(\n name,\n domain,\n exactDomain,\n includeExpired,\n );\n\n // Build complete SQL\n let sql = `SELECT ${selectColumns} FROM ${schema.tableName}`;\n if (whereClause) {\n sql += ` WHERE ${whereClause}`;\n }\n\n // Add ORDER BY for consistent results\n sql += ` ORDER BY ${schema.expiryColumn} DESC`;\n\n // Add LIMIT if specified\n if (limit && limit > 0) {\n sql += ` LIMIT ${limit}`;\n }\n\n return {\n sql,\n params,\n description: `Query ${this.browser} cookies: name=${name}, domain=${domain}`,\n };\n }\n\n /**\n * Build a batch SELECT query for multiple cookie specs\n * Combines multiple cookie specs into a single query with OR conditions\n * @param specs - Array of cookie query options\n */\n buildBatchSelectQuery(specs: CookieQueryOptions[]): SqlQueryConfig {\n if (specs.length === 0) {\n throw new Error(\"At least one spec is required for batch query\");\n }\n\n const schema = this.schema;\n const selectColumns = this.buildSelectColumns();\n\n // Build combined WHERE clause\n const specConditions: string[] = [];\n const allParams: unknown[] = [];\n\n for (const spec of specs) {\n const { whereClause, params } = this.buildWhereClause(\n spec.name,\n spec.domain,\n spec.exactDomain,\n spec.includeExpired,\n );\n\n if (whereClause) {\n // Wrap each spec's conditions in parentheses\n specConditions.push(`(${whereClause})`);\n allParams.push(...params);\n }\n }\n\n // Combine all specs with OR\n const combinedWhere = specConditions.join(\" OR \");\n\n // Build complete SQL\n let sql = `SELECT ${selectColumns} FROM ${schema.tableName}`;\n if (combinedWhere) {\n sql += ` WHERE ${combinedWhere}`;\n }\n\n // Add ORDER BY for consistent results\n sql += ` ORDER BY ${schema.expiryColumn} DESC`;\n\n // Find the minimum limit across all specs (if any have limits)\n const minLimit = specs.reduce(\n (min, spec) => {\n if (spec.limit && spec.limit > 0) {\n return min ? Math.min(min, spec.limit) : spec.limit;\n }\n return min;\n },\n undefined as number | undefined,\n );\n\n if (minLimit && minLimit > 0) {\n sql += ` LIMIT ${minLimit * specs.length}`; // Multiply by specs count to ensure we get enough results\n }\n\n return {\n sql,\n params: allParams,\n description: `Batch query ${this.browser} cookies for ${specs.length} specs`,\n };\n }\n\n /**\n * Build a query to get database metadata\n * @param key\n */\n buildMetaQuery(key: string): SqlQueryConfig {\n // Only Chromium-based browsers have meta table\n if (this.browser === \"firefox\") {\n throw new Error(\"Firefox does not have a meta table\");\n }\n\n return {\n sql: \"SELECT value FROM meta WHERE key = ?\",\n params: [key],\n description: `Get metadata: ${key}`,\n };\n }\n\n /**\n * Build a query to check if table exists\n */\n buildTableExistsQuery(): SqlQueryConfig {\n return {\n sql: \"SELECT name FROM sqlite_master WHERE type='table' AND name=?\",\n params: [this.schema.tableName],\n description: `Check if ${this.schema.tableName} table exists`,\n };\n }\n\n /**\n * Build SELECT columns based on browser\n */\n private buildSelectColumns(): string {\n const schema = this.schema;\n const columns = [\n schema.nameColumn,\n schema.domainColumn,\n schema.expiryColumn,\n ];\n\n // Add encrypted_value for Chromium-based browsers\n if (schema.encryptedValueColumn && this.browser !== \"firefox\") {\n columns.push(schema.encryptedValueColumn);\n } else {\n columns.push(schema.valueColumn);\n }\n\n // Add additional columns if available\n if (schema.pathColumn) {\n columns.push(schema.pathColumn);\n }\n if (schema.secureColumn) {\n columns.push(schema.secureColumn);\n }\n if (schema.httpOnlyColumn) {\n columns.push(schema.httpOnlyColumn);\n }\n\n // Use aliases for consistent output\n return columns\n .map((col) => {\n switch (col) {\n case schema.domainColumn:\n return `${col} AS domain`;\n case schema.expiryColumn:\n return `${col} AS expiry`;\n case schema.encryptedValueColumn:\n return `${col} AS encrypted_value`;\n case schema.valueColumn:\n return `${col} AS value`;\n case schema.nameColumn:\n return `${col} AS name`;\n case schema.pathColumn:\n return `${col} AS path`;\n case schema.secureColumn:\n return `${col} AS is_secure`;\n case schema.httpOnlyColumn:\n return `${col} AS is_httponly`;\n default:\n return col;\n }\n })\n .join(\", \");\n }\n\n /**\n * Build WHERE clause with proper parameter binding\n * @param name\n * @param domain\n * @param exactDomain\n * @param includeExpired\n */\n private buildWhereClause(\n name: string,\n domain: string,\n exactDomain?: boolean,\n includeExpired?: boolean,\n ): { whereClause: string; params: unknown[] } {\n const schema = this.schema;\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n // Handle name condition\n if (name === \"%\") {\n // Wildcard - no name condition needed\n } else if (name.includes(\"%\") || name.includes(\"_\")) {\n // Pattern matching\n conditions.push(`${schema.nameColumn} LIKE ?`);\n params.push(name);\n } else {\n // Exact match\n conditions.push(`${schema.nameColumn} = ?`);\n params.push(name);\n }\n\n // Handle domain condition\n if (domain) {\n if (exactDomain) {\n conditions.push(`${schema.domainColumn} = ?`);\n params.push(domain);\n } else {\n // Optimize domain matching:\n // 1. For domains starting with \".\", use suffix match (more efficient)\n // 2. For regular domains, try to match the domain and subdomains\n if (domain.startsWith(\".\")) {\n // Match exact suffix (e.g., \".github.com\")\n conditions.push(`${schema.domainColumn} LIKE ?`);\n params.push(`%${domain}`);\n } else {\n // Match domain and all subdomains efficiently\n // This matches \"github.com\", \".github.com\", \"api.github.com\", etc.\n conditions.push(\n `(${schema.domainColumn} = ? OR ${schema.domainColumn} = ? OR ${schema.domainColumn} LIKE ?)`,\n );\n params.push(domain, `.${domain}`, `%.${domain}`);\n }\n }\n }\n\n // Handle expiry condition\n if (!includeExpired) {\n // Firefox uses seconds, Chrome uses microseconds since 1601\n if (this.browser === \"firefox\") {\n // Pre-calculate the timestamp to avoid function call per row\n const nowSeconds = Math.floor(Date.now() / 1000);\n conditions.push(`${schema.expiryColumn} > ?`);\n params.push(nowSeconds);\n } else {\n // Chrome timestamp: microseconds since January 1, 1601\n // We'll let the caller handle the conversion\n conditions.push(`${schema.expiryColumn} > 0`);\n }\n }\n\n return {\n whereClause: conditions.join(\" AND \"),\n params,\n };\n }\n\n /**\n * Validate and sanitize query parameters\n * @param options\n */\n static validateQueryParams(options: CookieQueryOptions): void {\n const { name, domain, limit } = options;\n\n // Validate name\n if (typeof name !== \"string\" || name.length === 0) {\n throw new Error(\"Cookie name must be a non-empty string\");\n }\n\n // Validate domain\n if (typeof domain !== \"string\" || domain.length === 0) {\n throw new Error(\"Domain must be a non-empty string\");\n }\n\n // Prevent SQL injection attempts\n const sqlKeywords = [\n \"SELECT\",\n \"INSERT\",\n \"UPDATE\",\n \"DELETE\",\n \"DROP\",\n \"CREATE\",\n \"ALTER\",\n \"--\",\n \";\",\n ];\n const checkString = (str: string, field: string) => {\n const upperStr = str.toUpperCase();\n for (const keyword of sqlKeywords) {\n if (upperStr.includes(keyword)) {\n throw new Error(\n `Invalid ${field}: contains SQL keyword '${keyword}'`,\n );\n }\n }\n };\n\n checkString(name, \"name\");\n checkString(domain, \"domain\");\n\n // Validate limit\n if (limit !== undefined) {\n if (!Number.isInteger(limit) || limit <= 0 || limit > 10000) {\n throw new Error(\"Limit must be a positive integer between 1 and 10000\");\n }\n }\n }\n\n /**\n * Get browser type for a query builder\n */\n getBrowserType(): SqlBrowserType {\n return this.browser;\n }\n\n /**\n * Get schema information\n */\n getSchema(): Readonly<BrowserSchema> {\n return Object.freeze({ ...this.schema });\n }\n}\n\n/**\n * Factory function for creating query builders\n * @param browser\n */\nexport function createQueryBuilder(\n browser: SqlBrowserType,\n): CookieQueryBuilder {\n return new CookieQueryBuilder(browser);\n}\n\n/**\n * Check if a browser uses SQL for cookie storage\n * @param browser\n */\nexport function isSqlBrowser(browser: string): browser is SqlBrowserType {\n return browser in BROWSER_SCHEMAS;\n}\n","/**\n * Asynchronously maps over an array and flattens the result.\n * Similar to Array.prototype.flatMap but for async operations.\n * @param array - The input array to map over\n * @param callback - The async mapping function to apply to each element\n * @param defaultValue - The default value to return if the array is empty\n * @returns A flattened array of results\n * @example\n * // Basic usage with number arrays\n * const numbers = [1, 2, 3];\n * const result = await flatMapAsync(\n * numbers,\n * async (num) => [num, num * 2]\n * );\n * console.log(result); // [1, 2, 2, 4, 3, 6]\n * @example\n * // Error handling with default value\n * const data = ['valid', 'invalid'];\n * const result = await flatMapAsync(\n * data,\n * async (item) => {\n * if (item === 'invalid') throw new Error();\n * return [item.toUpperCase()];\n * },\n * ['DEFAULT']\n * );\n * console.log(result); // ['VALID', 'DEFAULT']\n */\nexport async function flatMapAsync<T, U>(\n array: T[],\n callback: (item: T) => Promise<U[]>,\n defaultValue: U[] = [],\n): Promise<U[]> {\n if (array.length === 0) {\n return defaultValue;\n }\n\n const results = await Promise.all(\n array.map(async (item) => {\n try {\n return await callback(item);\n } catch (_error) {\n return defaultValue;\n }\n }),\n );\n return results.flat();\n}\n","import { flatMapAsync } from \"@utils/flatMapAsync\";\nimport { createTaggedLogger } from \"@utils/logHelpers\";\n\nimport type {\n BrowserName,\n CookieQueryStrategy,\n ExportedCookie,\n} from \"../../types/schemas\";\n\n/**\n * A composite strategy that combines multiple cookie query strategies.\n * This class implements the CookieQueryStrategy interface and allows querying cookies\n * from multiple browser-specific strategies simultaneously.\n * @example\n * ```typescript\n * const strategy = new CompositeCookieQueryStrategy([\n * new ChromeCookieQueryStrategy(),\n * new FirefoxCookieQueryStrategy(),\n * new SafariCookieQueryStrategy()\n * ]);\n * const cookies = await strategy.queryCookies('sessionId', 'example.com');\n * ```\n */\nexport class CompositeCookieQueryStrategy implements CookieQueryStrategy {\n private readonly logger = createTaggedLogger(\"CompositeCookieQueryStrategy\");\n\n /**\n * The browser name identifier for this strategy\n * @remarks Always returns 'internal' as this is a composite strategy\n */\n public readonly browserName: BrowserName = \"internal\";\n\n /**\n * Creates a new instance of CompositeCookieQueryStrategy\n * @param strategies - Array of browser-specific strategies to use for querying cookies\n * @remarks\n * - Each strategy in the array should implement the CookieQueryStrategy interface\n * - The order of strategies determines the order of cookie querying\n * - Failed strategies will be gracefully handled and skipped\n * @example\n * ```typescript\n * const strategy = new CompositeCookieQueryStrategy([\n * new ChromeCookieQueryStrategy(),\n * new FirefoxCookieQueryStrategy()\n * ]);\n * ```\n */\n public constructor(private readonly strategies: CookieQueryStrategy[]) {}\n\n /**\n * Handles strategy-specific errors and logs them appropriately\n * @internal\n * @param error - The error that occurred during strategy execution\n * @param strategy - The strategy that failed\n */\n private handleStrategyError(\n error: unknown,\n strategy: CookieQueryStrategy,\n ): void {\n if (error instanceof Error) {\n this.logger.error(\"Strategy failed\", { error, strategy });\n } else {\n this.logger.error(\"Strategy failed with unknown error\", {\n error: String(error),\n strategy,\n });\n }\n }\n\n /**\n * Queries cookies using all available strategies in parallel\n * @param name - The name pattern to match cookies against\n * @param domain - The domain pattern to match cookies against\n * @param store - The store pattern to match cookies against\n * @param force - Whether to force operations despite warnings (e.g., locked databases)\n * @returns Promise resolving to combined array of cookies from all strategies\n * @remarks\n * - Failures in individual strategies are logged but don't affect other strategies\n * - Results are combined from all successful strategy queries\n * - Empty arrays are returned for failed strategy queries\n * @example\n * ```typescript\n * const strategy = new CompositeCookieQueryStrategy([\n * new ChromeCookieQueryStrategy(),\n * new FirefoxCookieQueryStrategy()\n * ]);\n * const cookies = await strategy.queryCookies('sessionId', 'example.com');\n * console.log(cookies); // Combined results from all browsers\n * ```\n */\n public async queryCookies(\n name: string,\n domain: string,\n store?: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n try {\n this.logger.info(\"Querying cookies from all strategies\", {\n name,\n domain,\n store,\n force,\n strategyCount: this.strategies.length,\n });\n\n /**\n * Use flatMapAsync to process strategies in sequence while collecting results\n * This approach provides better error isolation than Promise.all\n * Each strategy failure is handled independently\n */\n return await flatMapAsync(\n this.strategies,\n async (strategy) => {\n try {\n return await strategy.queryCookies(name, domain, store, force);\n } catch (error) {\n this.handleStrategyError(error, strategy);\n return [];\n }\n },\n [],\n );\n } catch (error) {\n /**\n * Handle top-level errors that may occur during strategy processing\n * This ensures the function always returns an array, even in catastrophic failure\n */\n if (error instanceof Error) {\n this.logger.error(\"Failed to query cookies\", { error });\n } else {\n this.logger.error(\"Failed to query cookies with unknown error\", {\n error: String(error),\n });\n }\n return [];\n }\n }\n}\n","import { getPlatform, isPlatformSupported } from \"@utils/platformUtils\";\nimport { isChromeRunning } from \"@utils/ProcessDetector\";\n\nimport type {\n CookieRow,\n CookieSpec,\n ExportedCookie,\n} from \"../../../types/schemas\";\nimport { chromeTimestampToDate } from \"../../../utils/chromeDates\";\nimport { BaseCookieQueryStrategy } from \"../BaseCookieQueryStrategy\";\nimport { BrowserLockHandler } from \"../BrowserLockHandler\";\nimport type { ChromiumBrowser } from \"../chrome/ChromiumBrowsers\";\nimport { decrypt } from \"../chrome/decrypt\";\nimport { getChromiumPassword } from \"../chrome/getChromiumPassword\";\nimport { CookieQueryBuilder } from \"../sql/CookieQueryBuilder\";\nimport { getGlobalConnectionManager } from \"../sql/DatabaseConnectionManager\";\nimport { getGlobalQueryMonitor } from \"../sql/QueryMonitor\";\n\ninterface DecryptionContext {\n file: string;\n password: string | Buffer;\n browser: string;\n metaVersion?: number;\n}\n\n/**\n * Create an exported cookie object\n * @param domain - Cookie domain\n * @param name - Cookie name\n * @param value - Cookie value\n * @param expiry - Cookie expiry timestamp\n * @param file - Source file path\n * @param browser - Browser name\n * @param decrypted - Whether the cookie was decrypted\n * @returns ExportedCookie object\n */\nexport function createExportedCookie(\n domain: string,\n name: string,\n value: string,\n expiry: number | undefined | null,\n file: string,\n browser: string,\n decrypted: boolean,\n): ExportedCookie {\n return {\n domain,\n name,\n value,\n expiry: chromeTimestampToDate(expiry),\n meta: {\n file,\n browser,\n decrypted,\n },\n };\n}\n\n/**\n * Base strategy for querying cookies from Chromium-based browsers.\n * This abstract class provides shared logic for Chrome, Chromium, Brave, Edge, etc.\n */\nexport abstract class BaseChromiumCookieQueryStrategy extends BaseCookieQueryStrategy {\n protected lockHandler: BrowserLockHandler;\n protected browserDisplayName: string;\n protected browserType: ChromiumBrowser;\n\n /**\n * Creates a new instance of BaseChromiumCookieQueryStrategy\n * @param strategyName - Name of the strategy for logging\n * @param browserName - Display name of the browser\n * @param browserType - The Chromium browser type for password retrieval\n */\n public constructor(\n strategyName: string,\n browserName: string,\n browserType: ChromiumBrowser = \"chrome\",\n ) {\n super(strategyName, \"Chrome\"); // Use \"Chrome\" for base class compatibility\n this.browserDisplayName = browserName;\n this.browserType = browserType;\n this.lockHandler = new BrowserLockHandler(this.logger, \"Chrome\");\n }\n\n /**\n * Batch query cookies for multiple specs\n * Optimized to execute combined SQL queries per database file\n * @param specs - Array of cookie specifications\n * @returns Array of exported cookies\n */\n async batchQueryCookies(specs: CookieSpec[]): Promise<ExportedCookie[]> {\n if (!this.isPlatformSupported()) {\n return [];\n }\n\n const files = this.getCookieFiles();\n if (files.length === 0) {\n this.logger.debug(`No ${this.browserDisplayName} cookie files found`);\n return [];\n }\n\n try {\n const password = await getChromiumPassword(this.browserType);\n const results: ExportedCookie[] = [];\n\n for (const file of files) {\n const fileResults = await this.processBatchFile(file, specs, password);\n results.push(...fileResults);\n }\n\n return results;\n } catch (error) {\n this.logger.error(\n `Failed to get ${this.browserDisplayName} password for batch query`,\n {\n error: this.getErrorMessage(error),\n },\n );\n return [];\n }\n }\n\n /**\n * Process a batch of specs for a single cookie file\n * @param file - Cookie file path\n * @param specs - Array of cookie specifications\n * @param password - Decryption password\n * @returns Array of exported cookies\n */\n protected async processBatchFile(\n file: string,\n specs: CookieSpec[],\n password: string | Buffer,\n ): Promise<ExportedCookie[]> {\n try {\n const connectionManager = getGlobalConnectionManager();\n const monitor = getGlobalQueryMonitor();\n const queryBuilder = new CookieQueryBuilder(\"chrome\");\n\n // Convert CookieSpec to CookieQueryOptions\n const queryOptions = specs.map((spec) => ({\n name: spec.name,\n domain: spec.domain,\n browser: \"chrome\" as const,\n }));\n\n const queryConfig = queryBuilder.buildBatchSelectQuery(queryOptions);\n\n const encryptedCookies = await connectionManager.executeQuery(\n file,\n (db) => {\n const rows = monitor.executeQuery<{\n encrypted_value: Buffer;\n name: string;\n domain: string;\n expiry: number;\n }>(db, queryConfig.sql, queryConfig.params, file);\n\n return rows.map(\n (row): CookieRow => ({\n name: row.name,\n domain: row.domain,\n value: row.encrypted_value,\n expiry: row.expiry,\n }),\n );\n },\n queryConfig.description || queryConfig.sql,\n );\n\n const metaVersion = await this.getMetaVersion(file);\n const context: DecryptionContext = {\n file,\n password,\n browser: this.browserDisplayName,\n metaVersion,\n };\n\n const results = await Promise.allSettled(\n encryptedCookies.map(async (cookie) =>\n this.processCookie(cookie, context),\n ),\n );\n\n return results\n .filter(\n (result): result is PromiseFulfilledResult<ExportedCookie> =>\n result.status === \"fulfilled\",\n )\n .map((result) => result.value);\n } catch (error) {\n this.logger.warn(\n `Error batch processing ${this.browserDisplayName} cookie file ${file}`,\n {\n error: this.getErrorMessage(error),\n file,\n specsCount: specs.length,\n },\n );\n return [];\n }\n }\n\n /**\n * Get cookie file paths for the browser\n * @param store - Optional specific store path\n * @returns Array of cookie file paths\n */\n protected abstract getCookieFilePaths(store?: string): string[];\n\n /**\n * Get the browser-specific display name\n * @returns Browser display name\n */\n protected getBrowserName(): string {\n return this.browserDisplayName;\n }\n\n /**\n * Executes the Chromium-specific query logic\n * @param name - The name pattern to match cookies against\n * @param domain - The domain pattern to match cookies against\n * @param store - Optional path to a specific cookie store file\n * @param force - Whether to force operations despite warnings\n * @returns A promise that resolves to an array of exported cookies\n */\n protected async executeQuery(\n name: string,\n domain: string,\n store?: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n if (!this.isPlatformSupported()) {\n return [];\n }\n\n const files = this.getCookieFiles(store);\n if (files.length === 0) {\n this.logger.debug(`No ${this.browserDisplayName} cookie files found`);\n return [];\n }\n\n try {\n const password = await getChromiumPassword(this.browserType);\n const results: ExportedCookie[] = [];\n\n for (const file of files) {\n const fileResults = await this.processFileWithRetry(\n file,\n name,\n domain,\n password,\n force,\n );\n results.push(...fileResults);\n }\n\n return results;\n } catch (error) {\n this.logger.error(`Failed to get ${this.browserDisplayName} password`, {\n error: this.getErrorMessage(error),\n });\n return [];\n }\n }\n\n /**\n * Check if the current platform is supported\n * @returns True if platform is supported\n */\n protected isPlatformSupported(): boolean {\n if (!isPlatformSupported()) {\n this.logger.warn(\"Platform not supported\", {\n platform: getPlatform(),\n supportedPlatforms: [\"darwin\", \"win32\", \"linux\"],\n });\n return false;\n }\n return true;\n }\n\n /**\n * Get cookie files to process\n * @param store - Optional specific store path\n * @returns Array of file paths\n */\n protected getCookieFiles(store?: string): string[] {\n const cookieFiles = store ?? this.getCookieFilePaths();\n return Array.isArray(cookieFiles) ? cookieFiles : [cookieFiles];\n }\n\n /**\n * Convert error to string message\n * @param error - The error to convert\n * @returns Error message string\n */\n protected getErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n }\n\n /**\n * Process a file with retry logic for lock conflicts\n * @param file - Cookie file path\n * @param name - Cookie name pattern\n * @param domain - Domain pattern\n * @param password - Decryption password\n * @param force - Force processing\n * @returns Array of exported cookies\n */\n private async processFileWithRetry(\n file: string,\n name: string,\n domain: string,\n password: string | Buffer,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n try {\n return await this.processFile(file, name, domain, password);\n } catch (error) {\n const lockResult = await this.handleFileError(\n error,\n file,\n name,\n domain,\n force,\n );\n\n if (lockResult.resolved) {\n return this.retryAfterBrowserClose(\n file,\n name,\n domain,\n password,\n lockResult.shouldRelaunch,\n );\n }\n\n return [];\n }\n }\n\n /**\n * Handle file processing errors\n * @param error - The error that occurred\n * @param file - File path\n * @param name - Cookie name pattern\n * @param domain - Domain pattern\n * @param force - Whether to force operations\n * @returns Lock result indicating if resolved and should relaunch\n */\n private async handleFileError(\n error: unknown,\n file: string,\n name: string,\n domain: string,\n force?: boolean,\n ): Promise<{ resolved: boolean; shouldRelaunch: boolean }> {\n const processes = await isChromeRunning();\n const lockResult = await this.lockHandler.handleBrowserConflict(\n error,\n file,\n processes,\n force !== true,\n );\n\n if (!lockResult.resolved) {\n this.logger.warn(\n `Error reading ${this.browserDisplayName} cookie file ${file}`,\n {\n error: this.getErrorMessage(error),\n file,\n name,\n domain,\n },\n );\n }\n\n return lockResult;\n }\n\n /**\n * Retry after browser close\n * @param file - Cookie file path\n * @param name - Cookie name pattern\n * @param domain - Domain pattern\n * @param password - Decryption password\n * @param shouldRelaunch - Whether to relaunch browser\n * @returns Array of exported cookies\n */\n private async retryAfterBrowserClose(\n file: string,\n name: string,\n domain: string,\n password: string | Buffer,\n shouldRelaunch: boolean,\n ): Promise<ExportedCookie[]> {\n try {\n this.logger.info(\n `Retrying ${this.browserDisplayName} cookie extraction after browser close...`,\n );\n const cookies = await this.processFile(file, name, domain, password);\n this.logger.success(\n `Successfully extracted cookies after closing ${this.browserDisplayName}`,\n );\n\n if (shouldRelaunch) {\n await this.lockHandler.relaunchBrowser();\n }\n\n return cookies;\n } catch (retryError) {\n this.logger.error(\n `Failed to extract cookies even after closing ${this.browserDisplayName}`,\n {\n error: this.getErrorMessage(retryError),\n file,\n },\n );\n\n if (shouldRelaunch) {\n await this.lockHandler.relaunchBrowser();\n }\n\n return [];\n }\n }\n\n /**\n * Process a single cookie file\n * @param file - Cookie file path\n * @param name - Cookie name pattern\n * @param domain - Domain pattern\n * @param password - Decryption password\n * @returns Array of exported cookies\n */\n protected async processFile(\n file: string,\n name: string,\n domain: string,\n password: string | Buffer,\n ): Promise<ExportedCookie[]> {\n try {\n // Use SQL utilities directly instead of getEncryptedChromeCookie\n const connectionManager = getGlobalConnectionManager();\n const monitor = getGlobalQueryMonitor();\n const queryBuilder = new CookieQueryBuilder(\"chrome\");\n\n const queryConfig = queryBuilder.buildSelectQuery({\n name,\n domain,\n browser: \"chrome\",\n });\n\n const encryptedCookies = await connectionManager.executeQuery(\n file,\n (db) => {\n // The CookieQueryBuilder aliases columns, so we get 'domain' not 'host_key'\n const rows = monitor.executeQuery<{\n encrypted_value: Buffer;\n name: string;\n domain: string;\n expiry: number;\n }>(db, queryConfig.sql, queryConfig.params, file);\n\n // Transform to CookieRow format\n return rows.map(\n (row): CookieRow => ({\n name: row.name,\n domain: row.domain,\n value: row.encrypted_value,\n expiry: row.expiry,\n }),\n );\n },\n queryConfig.sql,\n );\n\n const metaVersion = await this.getMetaVersion(file);\n const context: DecryptionContext = {\n file,\n password,\n browser: this.browserDisplayName,\n metaVersion,\n };\n\n const results = await Promise.allSettled(\n encryptedCookies.map(async (cookie) =>\n this.processCookie(cookie, context),\n ),\n );\n\n return results\n .map((result) => (result.status === \"fulfilled\" ? result.value : null))\n .filter((cookie): cookie is ExportedCookie => cookie !== null);\n } catch (error) {\n this.logger.error(\n `Failed to process ${this.browserDisplayName} cookie file`,\n {\n error: this.getErrorMessage(error),\n file,\n name,\n domain,\n },\n );\n return [];\n }\n }\n\n /**\n * Get meta version from Chrome database\n * @param file - Database file path\n * @returns Meta version number\n */\n protected async getMetaVersion(file: string): Promise<number> {\n try {\n const connectionManager = getGlobalConnectionManager();\n const queryBuilder = new CookieQueryBuilder(\"chrome\");\n const metaQuery = queryBuilder.buildMetaQuery(\"version\");\n\n const metaResult = await connectionManager.executeQuery(\n file,\n (db) => {\n const stmt = db.prepare(metaQuery.sql);\n return stmt.get(...metaQuery.params) as { value: string } | undefined;\n },\n \"Get meta version\",\n );\n\n return metaResult ? Number.parseInt(metaResult.value, 10) : 0;\n } catch (error) {\n this.logger.debug(\"Could not retrieve meta version, defaulting to 0\", {\n error: this.getErrorMessage(error),\n });\n return 0;\n }\n }\n\n /**\n * Process a single cookie\n * @param cookie - Cookie row from database\n * @param context - Decryption context\n * @returns Exported cookie\n */\n protected async processCookie(\n cookie: CookieRow,\n context: DecryptionContext,\n ): Promise<ExportedCookie> {\n try {\n const value = Buffer.isBuffer(cookie.value)\n ? cookie.value\n : Buffer.from(String(cookie.value));\n\n const decryptedValue = await decrypt(\n value,\n context.password,\n context.metaVersion,\n );\n\n return createExportedCookie(\n cookie.domain,\n cookie.name,\n decryptedValue,\n cookie.expiry,\n context.file,\n context.browser,\n true,\n );\n } catch (error) {\n this.logger.warn(`Failed to decrypt ${context.browser} cookie`, {\n error: this.getErrorMessage(error),\n });\n\n return createExportedCookie(\n cookie.domain,\n cookie.name,\n cookie.value.toString(\"utf-8\"),\n cookie.expiry,\n context.file,\n context.browser,\n false,\n );\n }\n }\n}\n","/**\n * Utility functions for consistent error handling across the codebase\n * Following DRY principle to eliminate repetitive error handling patterns\n */\n\n/**\n * Safely extract error message from unknown error types\n * @param error - Any thrown value (Error, string, unknown)\n * @returns A string representation of the error\n * @example\n * try {\n * // some operation\n * } catch (error) {\n * const message = getErrorMessage(error);\n * logger.error('Operation failed', { error: message });\n * }\n */\nexport function getErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n if (typeof error === \"string\") {\n return error;\n }\n if (\n error !== null &&\n error !== undefined &&\n typeof error === \"object\" &&\n \"message\" in error\n ) {\n return String(error.message);\n }\n return String(error);\n}\n\n/**\n * Get detailed error information including stack trace\n * @param error - Any thrown value\n * @returns Object with error details\n */\nexport function getErrorDetails(error: unknown): {\n message: string;\n stack?: string;\n name?: string;\n code?: string;\n} {\n const message = getErrorMessage(error);\n\n if (error instanceof Error) {\n const result: ReturnType<typeof getErrorDetails> = { message };\n if (error.stack !== undefined) {\n result.stack = error.stack;\n }\n if (error.name !== undefined) {\n result.name = error.name;\n }\n if (\"code\" in error && error.code !== undefined) {\n result.code = String(error.code);\n }\n return result;\n }\n\n return { message };\n}\n\n/**\n * Check if error message contains specific text (case-insensitive)\n * @param error - Any thrown value\n * @param searchText - Text to search for\n * @returns True if error message contains the text\n */\nexport function errorMessageContains(\n error: unknown,\n searchText: string,\n): boolean {\n const message = getErrorMessage(error).toLowerCase();\n return message.includes(searchText.toLowerCase());\n}\n\n/**\n * Error pattern constants for database error classification\n */\nconst DATABASE_ERROR_PATTERNS = {\n locked: [\"database is locked\", \"database locked\", \"sqlite_busy\"],\n busy: [\"busy\"],\n permission: [\n \"eperm\",\n \"permission denied\",\n \"operation not permitted\",\n \"eacces\",\n ],\n not_found: [\"enoent\", \"no such file\", \"not found\"],\n} as const;\n\n/**\n * Checks if a message contains any of the given patterns\n * @param message - The error message to check\n * @param patterns - Array of patterns to match against\n * @returns True if any pattern is found\n */\nfunction containsAnyPattern(\n message: string,\n patterns: readonly string[],\n): boolean {\n return patterns.some((pattern) => message.includes(pattern));\n}\n\n/**\n * Check if error is a specific type of database error\n * @param error - Any thrown value\n * @returns Type of database error or null\n */\nexport function getDatabaseErrorType(\n error: unknown,\n): \"locked\" | \"busy\" | \"permission\" | \"not_found\" | null {\n const message = getErrorMessage(error).toLowerCase();\n\n if (containsAnyPattern(message, DATABASE_ERROR_PATTERNS.locked)) {\n return \"locked\";\n }\n\n if (containsAnyPattern(message, DATABASE_ERROR_PATTERNS.busy)) {\n return \"busy\";\n }\n\n if (containsAnyPattern(message, DATABASE_ERROR_PATTERNS.permission)) {\n return \"permission\";\n }\n\n if (containsAnyPattern(message, DATABASE_ERROR_PATTERNS.not_found)) {\n return \"not_found\";\n }\n\n return null;\n}\n\n/**\n * Format error for logging with consistent structure\n * @param error - Any thrown value\n * @param context - Additional context for the error\n * @returns Formatted error object for logging\n */\nexport function formatErrorForLogging(\n error: unknown,\n context?: Record<string, unknown>,\n): Record<string, unknown> {\n const details = getErrorDetails(error);\n\n return {\n ...context,\n error: details.message,\n errorName: details.name,\n errorCode: details.code,\n // Only include stack in development/debug mode\n ...(process.env.NODE_ENV !== \"production\" &&\n details.stack !== undefined &&\n details.stack !== \"\"\n ? { errorStack: details.stack }\n : {}),\n };\n}\n\n/**\n * Type guard to check if value is an Error instance\n * @param error - Any value to check\n * @returns True if error is an Error instance\n */\nexport function isError(error: unknown): error is Error {\n return error instanceof Error;\n}\n\n/**\n * Type guard to check if error has a message property\n * @param error - Any value to check\n * @returns True if error has a message property\n */\nexport function hasErrorMessage(error: unknown): error is { message: unknown } {\n return (\n error !== null &&\n error !== undefined &&\n typeof error === \"object\" &&\n \"message\" in error\n );\n}\n\n/**\n * Create a standardized error from unknown input\n * @param error - Any thrown value\n * @param fallbackMessage - Message to use if error can't be converted\n * @returns Error instance\n */\nexport function ensureError(\n error: unknown,\n fallbackMessage = \"An unknown error occurred\",\n): Error {\n if (error instanceof Error) {\n return error;\n }\n\n const message = getErrorMessage(error) || fallbackMessage;\n const standardError = new Error(message);\n\n // Preserve original error as cause if supported\n if (\"cause\" in standardError) {\n standardError.cause = error;\n }\n\n return standardError;\n}\n\n/**\n * Wrap an async operation with consistent error handling\n * @param operation - Async function to execute\n * @param errorHandler - Function to handle errors\n * @returns Result of operation or undefined if error\n */\nexport async function withErrorHandling<T>(\n operation: () => Promise<T>,\n errorHandler: (error: unknown) => void,\n): Promise<T | undefined> {\n try {\n return await operation();\n } catch (error) {\n errorHandler(error);\n return undefined;\n }\n}\n\n/**\n * Retry an operation with exponential backoff\n * @param operation - Async function to execute\n * @param options - Retry options\n * @param options.maxAttempts - Maximum number of retry attempts\n * @param options.initialDelay - Initial delay in milliseconds\n * @param options.maxDelay - Maximum delay in milliseconds\n * @param options.shouldRetry - Function to determine if retry should be attempted\n * @returns Result of successful operation\n */\nexport async function retryWithBackoff<T>(\n operation: () => Promise<T>,\n options: {\n maxAttempts?: number;\n initialDelay?: number;\n maxDelay?: number;\n shouldRetry?: (error: unknown) => boolean;\n } = {},\n): Promise<T> {\n const {\n maxAttempts = 3,\n initialDelay = 100,\n maxDelay = 5000,\n shouldRetry = () => true,\n } = options;\n\n let lastError: unknown;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await operation();\n } catch (error) {\n lastError = error;\n\n if (attempt === maxAttempts || !shouldRetry(error)) {\n throw error;\n }\n\n const delay = Math.min(initialDelay * 2 ** (attempt - 1), maxDelay);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw lastError;\n}\n","import { getErrorMessage } from \"./errorUtils\";\nimport { execSimple } from \"./execSimple\";\nimport { createTaggedLogger } from \"./logHelpers\";\nimport { isWindows, getPlatform } from \"./platformUtils\";\n\nconst logger = createTaggedLogger(\"ProcessDetector\");\n\n/**\n * Parse a process line from ps output\n * @param line - The process line from ps output\n * @param defaultCommand - Default command name if parsing fails\n * @returns ProcessInfo if valid, null otherwise\n */\nfunction parseProcessLine(\n line: string,\n defaultCommand: string,\n): ProcessInfo | null {\n const parts = line.trim().split(/\\s+/);\n if (parts.length < 2) {\n return null;\n }\n\n const pidStr = parts[1];\n if (pidStr === undefined || pidStr === \"\") {\n return null;\n }\n\n const pid = Number.parseInt(pidStr, 10);\n if (Number.isNaN(pid)) {\n return null;\n }\n\n const parsedCommand = parts.slice(10).join(\" \");\n return {\n pid,\n command: parsedCommand !== \"\" ? parsedCommand : defaultCommand,\n details: line.trim(),\n };\n}\n\n/**\n * Parse a process line from Windows tasklist CSV output\n * @param line - Process line from tasklist /FO CSV\n * @param defaultCommand - Default command name if parsing fails\n * @returns ProcessInfo if valid, null otherwise\n */\nfunction parseWindowsProcessLine(\n line: string,\n defaultCommand: string,\n): ProcessInfo | null {\n // Windows tasklist CSV format: \"Image Name\",\"PID\",\"Session Name\",\"Session#\",\"Mem Usage\"\n // Example: \"firefox.exe\",\"1234\",\"Console\",\"1\",\"123,456 K\"\n const parts = line.split(\",\").map((p) => p.replace(/\"/g, \"\").trim());\n if (parts.length < 2) {\n return null;\n }\n\n const pidStr = parts[1];\n if (pidStr === undefined || pidStr === \"\") {\n return null;\n }\n\n const pid = Number.parseInt(pidStr, 10);\n if (Number.isNaN(pid)) {\n return null;\n }\n\n return {\n pid,\n command: parts[0] ?? defaultCommand,\n details: line.trim(),\n };\n}\n\n/**\n * Information about a detected process\n */\nexport interface ProcessInfo {\n /** Process ID */\n pid: number;\n /** Process name/command */\n command: string;\n /** Full process details */\n details: string;\n}\n\n/**\n * Generic browser process detection\n * @param browserName - Name of the browser to detect\n * @param grepPattern - Pattern to grep for in ps output\n * @returns Promise that resolves to array of process information\n */\nasync function detectBrowserProcesses(\n browserName: string,\n grepPattern: string,\n): Promise<ProcessInfo[]> {\n try {\n let command: string;\n\n if (isWindows()) {\n // On Windows, use tasklist or wmic to find processes\n // Map common browser names to Windows process names\n const windowsProcessMap: Record<string, string> = {\n firefox: \"firefox.exe\",\n chrome: \"chrome.exe\",\n \"google chrome\": \"chrome.exe\",\n chromium: \"chromium.exe\",\n safari: \"safari.exe\", // Won't exist on Windows but included for consistency\n edge: \"msedge.exe\",\n };\n\n const processName =\n windowsProcessMap[browserName.toLowerCase()] ??\n windowsProcessMap[grepPattern.toLowerCase()] ??\n `${browserName.toLowerCase()}.exe`;\n\n // Use tasklist which is available on all Windows versions\n command = `tasklist /FI \"IMAGENAME eq ${processName}\" /FO CSV | findstr /i \"${processName}\"`;\n } else {\n // Unix-like systems (macOS, Linux)\n command = `ps aux | grep -i '${grepPattern}' | grep -v grep`;\n }\n\n const { stdout } = await execSimple(command);\n\n if (!stdout || stdout.trim() === \"\") {\n return [];\n }\n\n const processes: ProcessInfo[] = [];\n const lines = stdout.split(\"\\n\").filter((line) => line.trim() !== \"\");\n\n for (const line of lines) {\n const processInfo = isWindows()\n ? parseWindowsProcessLine(line, browserName.toLowerCase())\n : parseProcessLine(line, browserName.toLowerCase());\n if (processInfo) {\n processes.push(processInfo);\n }\n }\n\n logger.debug(`${browserName} process detection completed`, {\n processCount: processes.length,\n processes: processes.map((p) => ({ pid: p.pid, command: p.command })),\n platform: getPlatform(),\n });\n\n return processes;\n } catch (error) {\n logger.debug(`Failed to detect ${browserName} processes`, {\n error: getErrorMessage(error),\n platform: getPlatform(),\n });\n return [];\n }\n}\n\n/**\n * Check if Firefox browser is currently running\n * @returns Promise that resolves to array of Firefox process information\n * @example\n * ```typescript\n * const firefoxProcesses = await isFirefoxRunning();\n * if (firefoxProcesses.length > 0) {\n * console.log('Firefox is running, consider closing it for reliable cookie access');\n * }\n * ```\n */\nexport async function isFirefoxRunning(): Promise<ProcessInfo[]> {\n return detectBrowserProcesses(\"Firefox\", \"firefox\");\n}\n\n/**\n * Check if Chrome browser is currently running\n * @returns Promise that resolves to array of Chrome process information\n */\nexport async function isChromeRunning(): Promise<ProcessInfo[]> {\n return detectBrowserProcesses(\"Chrome\", \"google chrome\\\\|chromium\");\n}\n\n/**\n * Check if Safari browser is currently running\n * @returns Promise that resolves to array of Safari process information\n */\nexport async function isSafariRunning(): Promise<ProcessInfo[]> {\n return detectBrowserProcesses(\n \"Safari\",\n \"/Applications/Safari.app/Contents/MacOS/Safari\",\n );\n}\n\n/**\n * Get user-friendly advice for browser conflicts\n * @param browserName - Name of the browser\n * @param processes - Array of detected processes\n * @returns User-friendly message with advice\n */\nexport function getBrowserConflictAdvice(\n browserName: string,\n processes: ProcessInfo[],\n): string {\n if (processes.length === 0) {\n return \"\";\n }\n\n const processCount = processes.length;\n const browserDisplayName =\n browserName.charAt(0).toUpperCase() + browserName.slice(1);\n\n return `${browserDisplayName} is currently running (${processCount} process${processCount > 1 ? \"es\" : \"\"} detected). For reliable cookie access, consider closing ${browserDisplayName} and trying again. Alternatively, use the --force flag to attempt access despite the lock.`;\n}\n","/**\n * Chrome date conversion utilities\n *\n * Chrome/Chromium stores timestamps as microseconds since 1601-01-01 00:00:00 UTC\n * JavaScript Date uses milliseconds since 1970-01-01 00:00:00 UTC\n */\n\n/**\n * The number of seconds between Chrome epoch (1601-01-01) and Unix epoch (1970-01-01)\n * This is 369 years worth of seconds\n */\nexport const CHROME_EPOCH_OFFSET_SECONDS = 11644473600;\n\n/**\n * Microseconds per second\n */\nexport const MICROSECONDS_PER_SECOND = 1000000;\n\n/**\n * Milliseconds per second\n */\nexport const MILLISECONDS_PER_SECOND = 1000;\n\n/**\n * Converts a Chrome timestamp to a JavaScript Date object\n * @param chromeTimestamp - Microseconds since 1601-01-01 00:00:00 UTC\n * @returns JavaScript Date object or \"Infinity\" for session cookies, undefined for null/undefined\n */\nexport function chromeTimestampToDate(\n chromeTimestamp: number | undefined | null,\n): Date | \"Infinity\" | undefined {\n // Handle null or undefined\n if (chromeTimestamp === null || chromeTimestamp === undefined) {\n return undefined;\n }\n\n // Handle invalid numbers\n if (typeof chromeTimestamp !== \"number\" || Number.isNaN(chromeTimestamp)) {\n return undefined;\n }\n\n // Chrome uses 0 for session cookies\n if (chromeTimestamp <= 0) {\n return \"Infinity\";\n }\n\n // Convert Chrome timestamp to Unix timestamp\n const unixTimestampSeconds =\n chromeTimestamp / MICROSECONDS_PER_SECOND - CHROME_EPOCH_OFFSET_SECONDS;\n\n // Sanity check: Unix timestamp should be positive and reasonable\n // Max date: year 3000 (32503680000 seconds since Unix epoch)\n if (unixTimestampSeconds < 0 || unixTimestampSeconds > 32503680000) {\n // Treat unreasonable dates as session cookies\n return \"Infinity\";\n }\n\n // Convert to milliseconds for JavaScript Date\n return new Date(unixTimestampSeconds * MILLISECONDS_PER_SECOND);\n}\n\n/**\n * Converts a JavaScript Date to a Chrome timestamp\n * @param date - JavaScript Date object\n * @returns Microseconds since 1601-01-01 00:00:00 UTC\n */\nexport function dateToChromeTimestamp(date: Date): number {\n if (!(date instanceof Date) || Number.isNaN(date.getTime())) {\n return 0; // Session cookie\n }\n\n // Get Unix timestamp in seconds\n const unixTimestampSeconds = date.getTime() / MILLISECONDS_PER_SECOND;\n\n // Convert to Chrome timestamp\n const chromeTimestampSeconds =\n unixTimestampSeconds + CHROME_EPOCH_OFFSET_SECONDS;\n\n // Convert to microseconds\n return chromeTimestampSeconds * MICROSECONDS_PER_SECOND;\n}\n\n/**\n * Checks if a Chrome timestamp represents a session cookie\n * @param chromeTimestamp - Microseconds since 1601-01-01 00:00:00 UTC\n * @returns True if this is a session cookie (no expiry)\n */\nexport function isChromeSessionCookie(\n chromeTimestamp: number | undefined | null,\n): boolean {\n return (\n chromeTimestamp === null ||\n chromeTimestamp === undefined ||\n chromeTimestamp === 0 ||\n (typeof chromeTimestamp === \"number\" && chromeTimestamp <= 0) ||\n // Far future dates (like year 4000) are treated as session cookies by Chrome\n (typeof chromeTimestamp === \"number\" &&\n chromeTimestamp >= 64092211200 * MICROSECONDS_PER_SECOND)\n );\n}\n\n/**\n * Formats a Chrome timestamp for display\n * @param chromeTimestamp - Microseconds since 1601-01-01 00:00:00 UTC\n * @returns Human-readable string representation\n */\nexport function formatChromeTimestamp(\n chromeTimestamp: number | undefined | null,\n): string {\n if (isChromeSessionCookie(chromeTimestamp)) {\n return \"Session\";\n }\n\n const date = chromeTimestampToDate(chromeTimestamp);\n\n if (date === undefined) {\n return \"Session\";\n }\n\n if (date === \"Infinity\") {\n return \"Session\";\n }\n\n return date.toISOString();\n}\n","import { createTaggedLogger } from \"@utils/logHelpers\";\n\nimport type {\n BrowserName,\n CookieQueryStrategy,\n ExportedCookie,\n} from \"../../types/schemas\";\n\n// Create a simple fallback logger for tests\nconst fallbackLogger = {\n info: () => {},\n warn: () => {},\n error: () => {},\n debug: () => {},\n success: () => {},\n fatal: () => {},\n log: () => {},\n};\n\n/**\n * Base class for cookie query strategies.\n * Provides common functionality and standardized error handling for browser-specific implementations.\n * @implements {CookieQueryStrategy}\n * @abstract\n */\nexport abstract class BaseCookieQueryStrategy implements CookieQueryStrategy {\n /**\n * Logger instance for this strategy\n * @protected\n */\n protected readonly logger;\n\n /**\n * Creates a new instance of BaseCookieQueryStrategy\n * @param strategyName - The name of the strategy for logging purposes\n * @param browserName - The name of the browser this strategy is for\n */\n public constructor(\n strategyName: string,\n public readonly browserName: BrowserName,\n ) {\n const taggedLogger = createTaggedLogger(strategyName);\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, @typescript-eslint/strict-boolean-expressions\n this.logger = taggedLogger || fallbackLogger;\n }\n\n /**\n * Queries cookies from the browser's cookie store\n * @param name - The name pattern to match cookies against\n * @param domain - The domain pattern to match cookies against\n * @param store - Optional path to a specific cookie store file\n * @param force - Whether to force operations despite warnings (e.g., locked databases)\n * @returns A promise that resolves to an array of exported cookies\n */\n public async queryCookies(\n name: string,\n domain: string,\n store?: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n try {\n this.logger.info(\"Querying cookies\", { name, domain, store, force });\n return await this.executeQuery(name, domain, store, force);\n } catch (error) {\n if (error instanceof Error) {\n this.logger.error(\"Failed to query cookies\", {\n error: error.message,\n browser: this.browserName,\n strategy: this.constructor.name,\n name,\n domain,\n store,\n force,\n });\n } else {\n this.logger.error(\"Failed to query cookies\", {\n error: String(error),\n browser: this.browserName,\n strategy: this.constructor.name,\n name,\n domain,\n store,\n force,\n });\n }\n return [];\n }\n }\n\n /**\n * Executes the browser-specific query logic\n * @abstract\n * @param name - The name pattern to match cookies against\n * @param domain - The domain pattern to match cookies against\n * @param store - Optional path to a specific cookie store file\n * @param force - Whether to force operations despite warnings (e.g., locked databases)\n * @returns A promise that resolves to an array of exported cookies\n * @protected\n */\n protected abstract executeQuery(\n name: string,\n domain: string,\n store?: string,\n force?: boolean,\n ): Promise<ExportedCookie[]>;\n}\n","import { exec } from \"node:child_process\";\nimport readline from \"node:readline\";\nimport { promisify } from \"node:util\";\n\nimport type { BrowserName } from \"../types/schemas\";\n\nimport { createTaggedLogger } from \"./logHelpers\";\nimport { isMacOS } from \"./platformUtils\";\n\n// Re-export BrowserName from schemas for backward compatibility\n/**\n *\n */\nexport type { BrowserName } from \"../types/schemas\";\n\nconst execAsync = promisify(exec);\nconst logger = createTaggedLogger(\"BrowserControl\");\n\n/**\n * Check if the current environment supports interactive prompts\n * @returns True if environment can handle interactive prompts\n */\nfunction isInteractiveEnvironment(): boolean {\n const isCI = process.env.CI === \"true\" || process.env.CI === \"1\";\n const isTest =\n process.env.NODE_ENV === \"test\" || process.env.JEST_WORKER_ID !== undefined;\n const hasTTY = process.stdin.isTTY && process.stdout.isTTY;\n\n return hasTTY && !isCI && !isTest;\n}\n\n/**\n *\n */\nexport interface BrowserControlOptions {\n force?: boolean;\n interactive?: boolean;\n}\n\n/**\n * Map of browser names to their macOS application names\n * Only includes browsers that can be controlled on macOS\n */\nconst BROWSER_APP_NAMES: Partial<Record<BrowserName, string>> = {\n Firefox: \"Firefox\",\n Chrome: \"Google Chrome\",\n Safari: \"Safari\",\n};\n\n/**\n * Check if a browser is running on macOS\n * @param browserName - Name of the browser to check\n * @returns Promise that resolves to true if browser is running\n */\nasync function isBrowserRunningMacOS(\n browserName: BrowserName,\n): Promise<boolean> {\n try {\n const appName = BROWSER_APP_NAMES[browserName];\n if (!appName) {\n logger.debug(\"Browser not supported for macOS control\", { browserName });\n return false;\n }\n const script = `tell application \"System Events\" to (name of processes) contains \"${appName}\"`;\n const { stdout } = await execAsync(`osascript -e '${script}'`);\n return stdout.trim() === \"true\";\n } catch (error) {\n logger.debug(\"Failed to check if browser is running\", {\n browserName,\n error,\n });\n return false;\n }\n}\n\n/**\n * Gracefully quit a browser on macOS\n * @param browserName - Name of the browser to quit\n * @returns Promise that resolves to true if browser was quit successfully\n */\nasync function quitBrowserMacOS(browserName: BrowserName): Promise<boolean> {\n try {\n const appName = BROWSER_APP_NAMES[browserName];\n if (!appName) {\n logger.debug(\"Browser not supported for macOS control\", { browserName });\n return false;\n }\n\n // First, try to quit gracefully\n const quitScript = `tell application \"${appName}\" to quit`;\n await execAsync(`osascript -e '${quitScript}'`);\n\n // Wait a moment for the browser to quit\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Check if it's still running\n const stillRunning = await isBrowserRunningMacOS(browserName);\n if (!stillRunning) {\n logger.info(\"Browser quit successfully\", { browserName });\n return true;\n }\n\n logger.warn(\"Browser did not quit gracefully\", { browserName });\n return false;\n } catch (error) {\n logger.error(\"Failed to quit browser\", { browserName, error });\n return false;\n }\n}\n\n/**\n * Save open tabs in browser before closing (macOS only)\n * This will attempt to save the session so tabs can be restored\n * @param browserName - Name of the browser\n * @returns Promise that resolves when tabs are saved\n */\nasync function saveBrowserSessionMacOS(\n browserName: BrowserName,\n): Promise<void> {\n try {\n const appName = BROWSER_APP_NAMES[browserName];\n if (!appName) {\n logger.debug(\"Browser not supported for macOS control\", { browserName });\n return;\n }\n\n if (browserName === \"Firefox\") {\n // Firefox: Use keyboard shortcut to save session (Cmd+Shift+D to bookmark all tabs)\n const script = `\n tell application \"${appName}\"\n activate\n end tell\n tell application \"System Events\"\n keystroke \"d\" using {command down, shift down}\n delay 0.5\n key code 36\n end tell\n `;\n await execAsync(`osascript -e '${script}'`);\n logger.debug(\"Attempted to save Firefox session\", { browserName });\n } else if (browserName === \"Chrome\") {\n // Chrome will restore tabs automatically if quit gracefully\n logger.debug(\"Chrome will restore tabs automatically\", { browserName });\n } else {\n // Safari will restore tabs if quit gracefully\n logger.debug(\"Safari will restore tabs automatically\", { browserName });\n }\n } catch (error) {\n logger.debug(\"Failed to save browser session\", { browserName, error });\n }\n}\n\n/**\n * Prompt user for confirmation before closing browser\n * @param browserName - Name of the browser\n * @returns Promise that resolves to true if user confirms\n */\nasync function promptUserConfirmation(\n browserName: BrowserName,\n): Promise<boolean> {\n // Check if we're in a TTY-capable environment\n if (!isInteractiveEnvironment()) {\n logger.debug(\"Non-interactive environment detected, skipping prompt\", {\n browserName,\n CI: process.env.CI,\n NODE_ENV: process.env.NODE_ENV,\n JEST_WORKER_ID: process.env.JEST_WORKER_ID,\n stdin_tty: process.stdin.isTTY,\n stdout_tty: process.stdout.isTTY,\n });\n return false;\n }\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n rl.question(\n `\\n⚠️ ${browserName} is currently running and blocking cookie access.\\n` +\n `Would you like to close ${browserName}? Your tabs will be restored when you reopen it. (y/N): `,\n (answer) => {\n rl.close();\n resolve(answer.toLowerCase() === \"y\" || answer.toLowerCase() === \"yes\");\n },\n );\n });\n}\n\n/**\n * Relaunch a browser after it has been closed\n * @param browserName - Name of the browser to relaunch\n * @returns Promise that resolves to true if browser was relaunched\n */\nasync function relaunchBrowserMacOS(\n browserName: BrowserName,\n): Promise<boolean> {\n try {\n const appName = BROWSER_APP_NAMES[browserName];\n\n // Launch the browser\n const launchScript = `tell application \"${appName}\" to activate`;\n await execAsync(`osascript -e '${launchScript}'`);\n\n // Give it a moment to start\n await new Promise((resolve) => setTimeout(resolve, 3000));\n\n // Check if it's running\n const isRunning = await isBrowserRunningMacOS(browserName);\n if (isRunning) {\n logger.info(\"Browser relaunched successfully\", { browserName });\n return true;\n }\n\n logger.warn(\"Browser did not relaunch\", { browserName });\n return false;\n } catch (error) {\n logger.error(\"Failed to relaunch browser\", { browserName, error });\n return false;\n }\n}\n\n/**\n * Attempt to close a browser gracefully\n * @param browserName - Name of the browser to close\n * @param options - Control options\n * @returns Promise that resolves to true if browser was closed\n */\nexport async function closeBrowserGracefully(\n browserName: BrowserName,\n options: BrowserControlOptions = {},\n): Promise<boolean> {\n if (!isMacOS()) {\n logger.debug(\"Browser control only supported on macOS\");\n return false;\n }\n\n try {\n // Check if browser is running\n const isRunning = await isBrowserRunningMacOS(browserName);\n if (!isRunning) {\n logger.debug(\"Browser is not running\", { browserName });\n return true;\n }\n\n // If interactive mode, prompt user\n if (options.interactive === true && options.force !== true) {\n const confirmed = await promptUserConfirmation(browserName);\n if (!confirmed) {\n logger.info(\"User cancelled browser close\", { browserName });\n return false;\n }\n }\n\n // Try to save session first (for browsers that support it)\n await saveBrowserSessionMacOS(browserName);\n\n // Quit the browser\n const success = await quitBrowserMacOS(browserName);\n\n if (success) {\n logger.success(\n `${browserName} closed successfully. Tabs will be restored on next launch.`,\n );\n } else {\n logger.warn(\n `Failed to close ${browserName}. You may need to close it manually.`,\n );\n }\n\n return success;\n } catch (error) {\n logger.error(\"Failed to control browser\", { browserName, error });\n return false;\n }\n}\n\n/**\n * Close browser, perform an action, then relaunch the browser\n * @param browserName - Name of the browser\n * @param action - Action to perform while browser is closed\n * @param options - Control options\n * @returns Promise that resolves to the result of the action\n */\nexport async function closeBrowserForAction<T>(\n browserName: BrowserName,\n action: () => Promise<T>,\n options: BrowserControlOptions = {},\n): Promise<T | null> {\n if (!isMacOS()) {\n logger.debug(\"Browser control only supported on macOS\");\n return null;\n }\n\n let browserWasClosed = false;\n\n try {\n // Check if browser is running\n const wasRunning = await isBrowserRunningMacOS(browserName);\n\n if (wasRunning) {\n // Close the browser\n browserWasClosed = await closeBrowserGracefully(browserName, options);\n\n if (!browserWasClosed) {\n logger.warn(\"Failed to close browser, attempting action anyway\");\n } else {\n // Wait for browser to fully close\n await waitForBrowserToClose(browserName, 5000);\n }\n }\n\n // Perform the action\n const result = await action();\n\n // Relaunch browser if we closed it\n if (wasRunning && browserWasClosed) {\n logger.info(`Relaunching ${browserName}...`);\n const relaunched = await relaunchBrowserMacOS(browserName);\n\n if (relaunched) {\n logger.success(\n `${browserName} has been relaunched with your tabs restored`,\n );\n } else {\n logger.warn(\n `Could not relaunch ${browserName} automatically. Please reopen it manually.`,\n );\n }\n }\n\n return result;\n } catch (error) {\n logger.error(\"Failed during browser action\", { browserName, error });\n\n // Try to relaunch browser if we closed it\n if (browserWasClosed) {\n await relaunchBrowserMacOS(browserName);\n }\n\n return null;\n }\n}\n\n/**\n * Wait for a browser to close\n * @param browserName - Name of the browser\n * @param maxWaitMs - Maximum time to wait in milliseconds\n * @returns Promise that resolves to true if browser closed within timeout\n */\nexport async function waitForBrowserToClose(\n browserName: BrowserName,\n maxWaitMs = 10000,\n): Promise<boolean> {\n if (!isMacOS()) {\n return false;\n }\n\n const startTime = Date.now();\n const checkInterval = 500;\n\n while (Date.now() - startTime < maxWaitMs) {\n const isRunning = await isBrowserRunningMacOS(browserName);\n if (!isRunning) {\n return true;\n }\n await new Promise((resolve) => setTimeout(resolve, checkInterval));\n }\n\n return false;\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nimport { errorMessageContains, getErrorMessage } from \"./errorUtils\";\nimport { createTaggedLogger } from \"./logHelpers\";\nimport { getPlatform, isWindows } from \"./platformUtils\";\n\nconst execFileAsync = promisify(execFile);\nconst logger = createTaggedLogger(\"FileHandleDetector\");\n\n/**\n * Parse a fuser output line into FileHandleInfo\n * @param line - Line from fuser output\n * @returns FileHandleInfo or null if parsing fails\n */\nfunction parseFuserLine(line: string): FileHandleInfo | null {\n const parts = line.trim().split(/\\s+/);\n if (parts.length < 2) {\n return null;\n }\n\n const pidStr = parts[1];\n if (pidStr === undefined || pidStr === \"\") {\n return null;\n }\n\n const pid = Number.parseInt(pidStr, 10);\n if (Number.isNaN(pid)) {\n return null;\n }\n\n const result: FileHandleInfo = {\n pid: pid,\n command: parts[2] ?? \"unknown\",\n };\n\n const user = parts[0];\n if (user !== undefined && user !== \"\") {\n result.user = user;\n }\n\n const mode = parts[3];\n if (mode !== undefined && mode !== \"\") {\n result.mode = mode;\n }\n\n return result;\n}\n\n/**\n * Check if value is a valid process result object\n * @param value - Value to check\n * @returns True if valid process result\n */\nfunction isValidProcessResult(\n value: unknown,\n): value is Record<string, unknown> {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"ProcessId\" in value &&\n \"ProcessName\" in value\n );\n}\n\n/**\n * Parse PowerShell output into FileHandleInfo array\n * @param stdout - PowerShell command output\n * @returns Array of FileHandleInfo\n */\nfunction parsePowerShellOutput(stdout: string): FileHandleInfo[] {\n const handles: FileHandleInfo[] = [];\n\n try {\n const parsed: unknown = JSON.parse(stdout);\n const results = Array.isArray(parsed) ? parsed : [parsed];\n\n for (const result of results) {\n if (!isValidProcessResult(result)) {\n continue;\n }\n\n const processId = result.ProcessId;\n const processName = result.ProcessName;\n\n if (typeof processId === \"string\" && processId !== \"\") {\n handles.push({\n command: typeof processName === \"string\" ? processName : \"unknown\",\n pid: Number.parseInt(processId, 10),\n });\n }\n }\n } catch (parseError) {\n logger.debug(\"Failed to parse PowerShell output\", {\n error: getErrorMessage(parseError),\n });\n }\n\n return handles;\n}\n\n/**\n * Information about a process holding a file handle\n */\nexport interface FileHandleInfo {\n /** Process ID */\n pid: number;\n /** Process name/command */\n command: string;\n /** User running the process */\n user?: string;\n /** File descriptor or handle type */\n fd?: string;\n /** Access mode (read, write, etc.) */\n mode?: string;\n}\n\n/**\n * Detect processes holding handles to a specific file using lsof\n * SECURITY: Uses execFile to prevent shell injection\n * @param filePath - Path to the file to check\n * @returns Array of processes holding handles to the file\n */\nasync function detectWithLsof(filePath: string): Promise<FileHandleInfo[]> {\n try {\n // Use execFile instead of exec to prevent shell injection\n const { stdout } = await execFileAsync(\"lsof\", [filePath], {\n encoding: \"utf8\",\n });\n\n if (!stdout || stdout.trim() === \"\") {\n return [];\n }\n\n const lines = stdout.split(\"\\n\").slice(1); // Skip header\n const handles: FileHandleInfo[] = [];\n\n for (const line of lines) {\n const parts = line.trim().split(/\\s+/);\n const command = parts[0];\n const pidStr = parts[1];\n const user = parts[2];\n const fd = parts[3];\n\n if (\n command !== undefined &&\n command !== \"\" &&\n pidStr !== undefined &&\n pidStr !== \"\" &&\n parts.length >= 4\n ) {\n const pid = Number.parseInt(pidStr, 10);\n if (!Number.isNaN(pid)) {\n const handle: FileHandleInfo = {\n command,\n pid,\n };\n if (user !== undefined && user !== \"\") {\n handle.user = user;\n }\n if (fd !== undefined && fd !== \"\") {\n handle.fd = fd;\n handle.mode = fd.includes(\"w\") ? \"write\" : \"read\";\n }\n handles.push(handle);\n }\n }\n }\n\n logger.debug(\"Detected file handles with lsof\", {\n file: filePath,\n handleCount: handles.length,\n });\n\n return handles;\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n\n // Check if lsof is not found\n if (errorMessageContains(error, \"ENOENT\")) {\n logger.debug(\"lsof not available on this system\");\n } else if (errorMessageContains(error, \"No such file\")) {\n // File doesn't exist - return empty array\n logger.debug(\"File does not exist\", { file: filePath });\n } else {\n logger.debug(\"lsof detection failed\", { error: errorMessage });\n }\n\n return [];\n }\n}\n\n/**\n * Detect processes holding handles to a specific file using fuser\n * SECURITY: Uses execFile to prevent shell injection\n * @param filePath - Path to the file to check\n * @returns Array of processes holding handles to the file\n */\nasync function detectWithFuser(filePath: string): Promise<FileHandleInfo[]> {\n try {\n // fuser outputs to stderr, not stdout\n // Use execFile to prevent shell injection\n const result = await execFileAsync(\"fuser\", [\"-v\", filePath], {\n encoding: \"utf8\",\n });\n\n // fuser writes to stderr even on success\n const output = result.stderr || result.stdout || \"\";\n\n if (output.trim() === \"\") {\n return [];\n }\n\n const handles: FileHandleInfo[] = [];\n const lines = output.split(\"\\n\").slice(1); // Skip header\n\n for (const line of lines) {\n const handle = parseFuserLine(line);\n if (handle) {\n handles.push(handle);\n }\n }\n\n logger.debug(\"Detected file handles with fuser\", {\n file: filePath,\n handleCount: handles.length,\n });\n\n return handles;\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n\n if (errorMessageContains(error, \"ENOENT\")) {\n logger.debug(\"fuser not available on this system\");\n } else {\n logger.debug(\"fuser detection failed\", { error: errorMessage });\n }\n\n return [];\n }\n}\n\n/**\n * Windows-specific handle detection using PowerShell\n * SECURITY: Properly escapes file path for PowerShell\n * @param filePath - Path to the file to check\n * @returns Array of processes holding handles to the file\n */\nasync function detectOnWindows(filePath: string): Promise<FileHandleInfo[]> {\n try {\n // Escape single quotes in the file path for PowerShell\n const escapedPath = filePath.replace(/'/g, \"''\");\n\n // Use Get-Process with error handling\n const psScript = `\n $ErrorActionPreference = 'SilentlyContinue'\n $handles = @()\n \n # Try to find processes with the file open\n Get-Process | ForEach-Object {\n try {\n $proc = $_\n # Check if any modules match the file path\n $modules = $proc.Modules | Where-Object { $_.FileName -eq '${escapedPath}' }\n if ($modules) {\n $handles += [PSCustomObject]@{\n ProcessName = $proc.ProcessName\n ProcessId = $proc.Id\n }\n }\n } catch {\n # Skip processes we can't access\n }\n }\n \n # Also try using Get-CimInstance for better file handle detection\n try {\n $query = \"SELECT * FROM CIM_DataFile WHERE Name='${escapedPath.replace(/\\\\/g, \"\\\\\\\\\")}'\"\n $file = Get-CimInstance -Query $query -ErrorAction SilentlyContinue\n if ($file) {\n $assoc = Get-CimAssociatedInstance -InputObject $file -ResultClassName Win32_Process\n foreach ($proc in $assoc) {\n $handles += [PSCustomObject]@{\n ProcessName = $proc.Name\n ProcessId = $proc.ProcessId\n }\n }\n }\n } catch {\n # WMI query failed, ignore\n }\n \n $handles | ConvertTo-Json -Compress\n `;\n\n const { stdout } = await execFileAsync(\n \"powershell\",\n [\"-NoProfile\", \"-NonInteractive\", \"-Command\", psScript],\n { encoding: \"utf8\", maxBuffer: 1024 * 1024 },\n );\n\n if (!stdout || stdout.trim() === \"\" || stdout.trim() === \"null\") {\n return [];\n }\n\n const handles = parsePowerShellOutput(stdout);\n\n logger.debug(\"Detected file handles with PowerShell\", {\n file: filePath,\n handleCount: handles.length,\n });\n\n return handles;\n } catch (error) {\n logger.debug(\"Windows handle detection failed\", {\n error: getErrorMessage(error),\n });\n return [];\n }\n}\n\n/**\n * Try to detect using handle.exe from Sysinternals (if available)\n * SECURITY: Uses execFile to prevent shell injection\n * @param filePath - Path to the file to check\n * @returns Array of processes holding handles to the file\n */\nasync function detectWithHandleExe(\n filePath: string,\n): Promise<FileHandleInfo[]> {\n try {\n // handle.exe must be in PATH or current directory\n const { stdout } = await execFileAsync(\"handle\", [\"-nobanner\", filePath], {\n encoding: \"utf8\",\n });\n\n if (!stdout || stdout.trim() === \"\") {\n return [];\n }\n\n const handles: FileHandleInfo[] = [];\n const lines = stdout.split(\"\\n\");\n\n for (const line of lines) {\n // Format: process.exe pid: type handle: path\n const match = line.match(\n /^(.+?)\\s+pid:\\s+(\\d+)\\s+type:\\s+(\\w+)\\s+.+:\\s+(.+)$/i,\n );\n if (\n match?.[1] !== undefined &&\n match?.[1] !== \"\" &&\n match?.[2] !== undefined &&\n match?.[2] !== \"\"\n ) {\n const pid = Number.parseInt(match[2], 10);\n if (!Number.isNaN(pid)) {\n const handle: FileHandleInfo = {\n command: match[1],\n pid,\n };\n if (match?.[3] !== undefined && match[3] !== \"\") {\n handle.fd = match[3];\n }\n handle.mode = \"unknown\";\n handles.push(handle);\n }\n }\n }\n\n logger.debug(\"Detected file handles with handle.exe\", {\n file: filePath,\n handleCount: handles.length,\n });\n\n return handles;\n } catch {\n // handle.exe not available, silently fall back\n return [];\n }\n}\n\n/**\n * Detect all processes that have open handles to a specific file\n * @param filePath - Path to the file to check\n * @returns Array of processes holding handles to the file\n */\nexport async function detectFileHandles(\n filePath: string,\n): Promise<FileHandleInfo[]> {\n const os = getPlatform();\n\n logger.debug(\"Detecting file handles\", { file: filePath, platform: os });\n\n if (isWindows()) {\n // Try handle.exe first (most accurate)\n const handles = await detectWithHandleExe(filePath);\n if (handles.length > 0) {\n return handles;\n }\n\n // Fall back to PowerShell\n return detectOnWindows(filePath);\n }\n\n // Unix-like systems: try lsof first\n let handles = await detectWithLsof(filePath);\n\n // Fallback to fuser if lsof didn't work\n if (handles.length === 0) {\n handles = await detectWithFuser(filePath);\n }\n\n if (handles.length > 0) {\n logger.info(\"File has open handles\", {\n file: filePath,\n handleCount: handles.length,\n processes: handles.map((h) => ({\n pid: h.pid,\n command: h.command,\n mode: h.mode,\n })),\n });\n }\n\n return handles;\n}\n\n/**\n * Check if a file is locked by any process\n * @param filePath - Path to the file to check\n * @returns True if file has open handles, false otherwise\n */\nexport async function isFileLocked(filePath: string): Promise<boolean> {\n const handles = await detectFileHandles(filePath);\n return handles.length > 0;\n}\n\n/**\n * Get detailed information about processes locking a file\n * @param filePath - Path to the file to check\n * @returns Human-readable string describing the lock status\n */\nexport async function getFileLockInfo(filePath: string): Promise<string> {\n const handles = await detectFileHandles(filePath);\n\n if (handles.length === 0) {\n return \"File is not locked\";\n }\n\n const processInfo = handles\n .map(\n (h) =>\n `${h.command} (PID: ${h.pid}${h.user !== undefined && h.user !== \"\" ? `, User: ${h.user}` : \"\"}${h.mode !== undefined && h.mode !== \"\" ? `, Mode: ${h.mode}` : \"\"})`,\n )\n .join(\", \");\n\n return `File is locked by ${handles.length} process${handles.length > 1 ? \"es\" : \"\"}: ${processInfo}`;\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nimport type { BrowserName } from \"@utils/BrowserControl\";\nimport { getPlatform, isWindows, type Platform } from \"@utils/platformUtils\";\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Interface for platform-specific browser control operations\n * Following SOLID principles - Interface Segregation\n */\nexport interface PlatformBrowserControl {\n /**\n * Check if the browser is supported on this platform\n * @param browserName - The name of the browser to check\n * @returns True if the browser is supported on this platform\n */\n isBrowserSupported(browserName: BrowserName): boolean;\n\n /**\n * Get executable names for a browser on this platform\n * @param browserName - The name of the browser\n * @returns Array of executable names for the browser\n */\n getBrowserExecutables(browserName: BrowserName): string[];\n\n /**\n * Launch a browser on this platform\n * @param browserName - The name of the browser to launch\n * @returns Promise that resolves when the browser is launched\n * @throws {Error} When the browser is not supported or cannot be launched\n */\n launchBrowser(browserName: BrowserName): Promise<void>;\n\n /**\n * Get the platform name\n * @returns The name of the current platform\n */\n getPlatformName(): string;\n\n /**\n * Check if a browser is installed\n * @param browserName - The name of the browser to check\n * @returns Promise that resolves to true if the browser is installed\n */\n isBrowserInstalled(browserName: BrowserName): Promise<boolean>;\n}\n\n/**\n * Base implementation with common functionality\n * Following DRY principle\n */\nexport abstract class BasePlatformBrowserControl\n implements PlatformBrowserControl\n{\n protected readonly browserExecutables: Partial<Record<BrowserName, string[]>>;\n\n /**\n * Creates a new instance of BasePlatformBrowserControl\n */\n public constructor() {\n this.browserExecutables = this.initializeBrowserExecutables();\n }\n\n /**\n * Initialize browser executables for this platform\n * @returns Record mapping browser names to their executable names\n */\n protected abstract initializeBrowserExecutables(): Partial<\n Record<BrowserName, string[]>\n >;\n\n public isBrowserSupported(browserName: BrowserName): boolean {\n const executables = this.browserExecutables[browserName];\n return Boolean(executables && executables.length > 0);\n }\n\n public getBrowserExecutables(browserName: BrowserName): string[] {\n return this.browserExecutables[browserName] || [];\n }\n\n /**\n * Launch a browser on this platform\n * @param browserName - The name of the browser to launch\n * @returns Promise that resolves when the browser is launched\n * @throws {Error} When the browser is not supported or cannot be launched\n */\n public abstract launchBrowser(browserName: BrowserName): Promise<void>;\n\n /**\n * Get the platform name\n * @returns The name of the current platform\n */\n public abstract getPlatformName(): string;\n\n /**\n * Default implementation to check if browser is installed\n * Can be overridden by platform-specific implementations\n * @param browserName - The name of the browser to check\n * @returns Promise that resolves to true if the browser is installed\n */\n public async isBrowserInstalled(browserName: BrowserName): Promise<boolean> {\n const executables = this.getBrowserExecutables(browserName);\n\n for (const exe of executables) {\n try {\n // Try to check if executable exists using 'which' or 'where'\n const checkCommand = isWindows() ? \"where\" : \"which\";\n await execFileAsync(checkCommand, [exe], { timeout: 1000 });\n return true;\n } catch {\n // Continue checking other executables\n }\n }\n\n return false;\n }\n\n /**\n * Execute command helper with proper escaping\n * @param command - The command to execute\n * @param args - Arguments to pass to the command\n * @returns Promise that resolves when the command completes\n */\n protected async executeCommand(\n command: string,\n args: string[] = [],\n ): Promise<void> {\n try {\n await execFileAsync(command, args, {\n timeout: 5000,\n windowsHide: true,\n });\n } catch (error: unknown) {\n // Log but don't throw - browser may still launch\n if (this.isNodeError(error) && error.code !== \"ENOENT\") {\n console.debug(\n `Browser launch warning: ${BasePlatformBrowserControl.getErrorMessage(error)}`,\n );\n }\n }\n }\n\n /**\n * Helper to check if error is a Node.js error with code property\n * @param error - The error to check\n * @returns True if the error has a code property\n */\n private isNodeError(error: unknown): error is { code: string } {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n typeof (error as { code: unknown }).code === \"string\"\n );\n }\n\n /**\n * Helper to get error message from unknown error\n * @param error - The error to get message from\n * @returns Error message as string\n */\n protected static getErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n if (typeof error === \"string\") {\n return error;\n }\n return String(error);\n }\n}\n\n/**\n * macOS implementation for browser control operations\n * Handles browser launching using AppleScript on macOS systems\n */\nexport class MacOSBrowserControl extends BasePlatformBrowserControl {\n /**\n * Initialize browser executables for macOS platform\n * @returns Record mapping browser names to their executable names on macOS\n */\n protected initializeBrowserExecutables(): Partial<\n Record<BrowserName, string[]>\n > {\n return {\n Firefox: [\"Firefox\"],\n Chrome: [\"Google Chrome\"],\n Safari: [\"Safari\"],\n };\n }\n\n /**\n * Launch a browser on macOS using AppleScript\n * @param browserName - The name of the browser to launch\n * @returns Promise that resolves when the browser is launched\n * @throws {Error} When the browser is not supported on macOS\n */\n public async launchBrowser(browserName: BrowserName): Promise<void> {\n const appNames: Partial<Record<BrowserName, string>> = {\n Firefox: \"Firefox\",\n Chrome: \"Google Chrome\",\n Safari: \"Safari\",\n };\n\n const appName = appNames[browserName];\n if (!appName) {\n throw new Error(`${browserName} not supported on macOS`);\n }\n\n // Use osascript with proper argument separation to avoid injection\n await this.executeCommand(\"osascript\", [\n \"-e\",\n `tell application \"${appName}\" to activate`,\n ]);\n }\n\n /**\n * Get the platform name for macOS\n * @returns The platform name \"macOS\"\n */\n public getPlatformName(): string {\n return \"macOS\";\n }\n}\n\n/**\n * Windows implementation for browser control operations\n * Handles browser launching using cmd.exe start command on Windows systems\n */\nexport class WindowsBrowserControl extends BasePlatformBrowserControl {\n /**\n * Initialize browser executables for Windows platform\n * @returns Record mapping browser names to their executable names on Windows\n */\n protected initializeBrowserExecutables(): Partial<\n Record<BrowserName, string[]>\n > {\n return {\n Firefox: [\"firefox.exe\", \"Firefox\"],\n Chrome: [\"chrome.exe\", \"Google Chrome\"],\n Safari: [], // Not available on Windows\n };\n }\n\n /**\n * Launch a browser on Windows using cmd.exe start command\n * @param browserName - The name of the browser to launch\n * @returns Promise that resolves when the browser is launched\n * @throws {Error} When the browser is not available or fails to launch\n */\n public async launchBrowser(browserName: BrowserName): Promise<void> {\n const executables = this.getBrowserExecutables(browserName);\n\n if (executables.length === 0) {\n throw new Error(`${browserName} not available on Windows`);\n }\n\n // Try each executable until one works\n for (const exe of executables) {\n if (await this.tryLaunchExecutable(exe)) {\n return; // Success, exit early\n }\n }\n\n throw new Error(`Failed to launch ${browserName} on Windows`);\n }\n\n /**\n * Try to launch a specific executable on Windows\n * @param exe - The executable name to launch\n * @returns Promise that resolves to true if launch was successful\n */\n private async tryLaunchExecutable(exe: string): Promise<boolean> {\n try {\n // Use cmd.exe with /c flag to run start command safely\n await execFileAsync(\"cmd.exe\", [\"/c\", \"start\", \"\", exe], {\n timeout: 5000,\n windowsHide: true,\n });\n return true;\n } catch {\n // Try next executable\n return false;\n }\n }\n\n /**\n * Get the platform name for Windows\n * @returns The platform name \"Windows\"\n */\n public getPlatformName(): string {\n return \"Windows\";\n }\n}\n\n/**\n * Linux implementation for browser control operations\n * Handles browser launching using direct executable calls or xdg-open on Linux systems\n */\nexport class LinuxBrowserControl extends BasePlatformBrowserControl {\n /**\n * Initialize browser executables for Linux platform\n * @returns Record mapping browser names to their executable names on Linux\n */\n protected initializeBrowserExecutables(): Partial<\n Record<BrowserName, string[]>\n > {\n return {\n Firefox: [\"firefox\", \"firefox-bin\"],\n Chrome: [\n \"google-chrome\",\n \"google-chrome-stable\",\n \"chromium\",\n \"chromium-browser\",\n ],\n Safari: [], // Not available on Linux\n };\n }\n\n /**\n * Launch a browser on Linux using direct executable calls or xdg-open fallback\n * @param browserName - The name of the browser to launch\n * @returns Promise that resolves when the browser is launched\n * @throws {Error} When the browser is not available or fails to launch\n */\n public async launchBrowser(browserName: BrowserName): Promise<void> {\n const executables = this.getBrowserExecutables(browserName);\n\n if (executables.length === 0) {\n throw new Error(`${browserName} not available on Linux`);\n }\n\n // Try each possible command\n if (await this.tryLaunchExecutables(executables)) {\n return; // Success\n }\n\n // Fallback to xdg-open if no browser executable worked\n await this.tryXdgOpenFallback(browserName);\n }\n\n /**\n * Try to launch browser executables\n * @param executables - Array of executable names to try\n * @returns Promise that resolves to true if any executable was successful\n */\n private async tryLaunchExecutables(executables: string[]): Promise<boolean> {\n for (const cmd of executables) {\n try {\n // Use direct execution without shell to avoid injection\n await execFileAsync(cmd, [], {\n timeout: 5000,\n });\n return true; // Success\n } catch {}\n }\n return false;\n }\n\n /**\n * Try xdg-open as fallback when direct executables fail\n * @param browserName - The name of the browser that failed to launch\n * @returns Promise that resolves when xdg-open succeeds\n * @throws {Error} When xdg-open also fails\n */\n private async tryXdgOpenFallback(browserName: BrowserName): Promise<void> {\n try {\n await execFileAsync(\"xdg-open\", [\"http://localhost\"], {\n timeout: 5000,\n });\n } catch (error: unknown) {\n throw new Error(\n `Failed to launch ${browserName} on Linux: ${BasePlatformBrowserControl.getErrorMessage(error)}`,\n );\n }\n }\n\n /**\n * Get the platform name for Linux\n * @returns The platform name \"Linux\"\n */\n public getPlatformName(): string {\n return \"Linux\";\n }\n}\n\n/**\n * Factory to create platform-specific browser control\n * Following SOLID - Single Responsibility and Open/Closed principles\n */\nlet platformControlInstance: PlatformBrowserControl | null = null;\n\n/**\n * Creates platform-specific browser control instance\n * @param platformOverride - Optional platform override for testing\n * @returns Platform-specific browser control instance\n * @throws {Error} When platform is not supported\n */\nexport function createPlatformBrowserControl(\n platformOverride?: Platform | NodeJS.Platform,\n): PlatformBrowserControl {\n // Use singleton for efficiency when not overriding\n if (platformControlInstance !== null && platformOverride === undefined) {\n return platformControlInstance;\n }\n\n const currentPlatform = platformOverride ?? getPlatform();\n const control = createControlForPlatform(currentPlatform);\n\n if (platformOverride === undefined) {\n platformControlInstance = control;\n }\n\n return control;\n}\n\n/**\n * Creates the appropriate control instance for the given platform\n * @param platform - The platform to create control for\n * @returns Platform-specific browser control instance\n * @throws {Error} When platform is not supported\n */\nfunction createControlForPlatform(platform: string): PlatformBrowserControl {\n switch (platform) {\n case \"darwin\":\n return new MacOSBrowserControl();\n case \"win32\":\n return new WindowsBrowserControl();\n case \"linux\":\n case \"freebsd\":\n case \"openbsd\":\n return new LinuxBrowserControl();\n default:\n // For any other platform string, try Linux as fallback\n return new LinuxBrowserControl();\n }\n}\n\n/**\n * Clear the singleton instance (useful for testing)\n */\nexport function clearPlatformControlInstance(): void {\n platformControlInstance = null;\n}\n","import {\n type BrowserName,\n closeBrowserGracefully,\n waitForBrowserToClose,\n} from \"@utils/BrowserControl\";\nimport { getDatabaseErrorType, getErrorMessage } from \"@utils/errorUtils\";\nimport { detectFileHandles, getFileLockInfo } from \"@utils/FileHandleDetector\";\nimport type { createTaggedLogger } from \"@utils/logHelpers\";\nimport { getBrowserConflictAdvice } from \"@utils/ProcessDetector\";\n\nimport {\n createPlatformBrowserControl,\n type PlatformBrowserControl,\n} from \"./platform/PlatformBrowserControl\";\n\n/**\n * Result of a browser conflict handling operation\n */\nexport interface BrowserLockResult {\n /** Whether the conflict was resolved */\n resolved: boolean;\n /** Whether the browser should be relaunched */\n shouldRelaunch: boolean;\n}\n\n/**\n * Shared handler for browser lock/permission issues\n * Follows DRY principle to avoid duplicating logic across browser strategies\n * Uses Strategy pattern for platform-specific operations\n */\nexport class BrowserLockHandler {\n private readonly platformControl: PlatformBrowserControl;\n\n /**\n * Creates a new BrowserLockHandler instance\n * @param logger - Tagged logger instance for this handler\n * @param browserName - Name of the browser this handler manages\n * @param platformControl - Optional platform control strategy (for testing)\n */\n public constructor(\n private readonly logger: ReturnType<typeof createTaggedLogger>,\n private readonly browserName: BrowserName,\n platformControl?: PlatformBrowserControl,\n ) {\n // Use provided control or create platform-specific one\n this.platformControl = platformControl ?? createPlatformBrowserControl();\n }\n\n /**\n * Handle database lock or permission errors\n * @param error - The error to check\n * @param file - The file that was locked/inaccessible\n * @param processes - Running processes for this browser\n * @param autoClose - Whether to attempt auto-closing the browser\n * @returns Promise that resolves to lock result\n */\n public async handleBrowserConflict(\n error: unknown,\n file: string,\n processes: Array<{ pid: number; command: string }>,\n autoClose = false,\n ): Promise<BrowserLockResult> {\n if (!(error instanceof Error)) {\n return { resolved: false, shouldRelaunch: false };\n }\n\n if (!this.isLockError(error)) {\n return { resolved: false, shouldRelaunch: false };\n }\n\n await this.logFileHandleInfo(file, processes);\n return this.handleProcessConflict(file, processes, autoClose);\n }\n\n /**\n * Check if an error indicates a database lock or permission issue\n * @param error - The error to check\n * @returns True if this is a lock-related error\n */\n private isLockError(error: Error): boolean {\n const dbErrorType = getDatabaseErrorType(error);\n return dbErrorType === \"locked\" || dbErrorType === \"permission\";\n }\n\n /**\n * Log detailed file handle information\n * @param file - The file that was locked\n * @param processes - Browser processes detected\n */\n private async logFileHandleInfo(\n file: string,\n processes: Array<{ pid: number; command: string }>,\n ): Promise<void> {\n try {\n const fileHandles = await detectFileHandles(file);\n\n if (fileHandles.length > 0) {\n const lockInfo = await getFileLockInfo(file);\n\n this.logger.debug(\"Database locked by specific processes\", {\n file,\n lockInfo,\n handleCount: fileHandles.length,\n handles: fileHandles.map((h) => ({\n pid: h.pid,\n command: h.command,\n mode: h.mode,\n user: h.user,\n })),\n });\n\n if (processes.length === 0) {\n this.logger.info(\n \"File is locked but no browser processes detected - another tool may be accessing the database\",\n {\n lockingProcesses: fileHandles\n .map((h) => `${h.command} (PID: ${h.pid})`)\n .join(\", \"),\n },\n );\n }\n }\n } catch (handleError) {\n this.logger.debug(\"Could not detect file handles\", {\n error:\n handleError instanceof Error\n ? handleError.message\n : String(handleError),\n });\n }\n }\n\n /**\n * Handle process conflicts and optionally close the browser\n * @param file - The file that was locked\n * @param processes - Browser processes detected\n * @param autoClose - Whether to attempt auto-closing\n * @returns Promise that resolves to lock result\n */\n private async handleProcessConflict(\n file: string,\n processes: Array<{ pid: number; command: string }>,\n autoClose: boolean,\n ): Promise<BrowserLockResult> {\n try {\n if (processes.length > 0) {\n return await this.handleBrowserProcesses(file, processes, autoClose);\n }\n\n this.logger.debug(\n \"Database/file locked but no browser processes detected\",\n {\n file,\n browserName: this.browserName,\n suggestion: \"Another process may be accessing the file\",\n },\n );\n } catch (processError) {\n this.logger.debug(\"Failed to check browser processes\", {\n error:\n processError instanceof Error\n ? processError.message\n : String(processError),\n });\n }\n\n return { resolved: false, shouldRelaunch: false };\n }\n\n /**\n * Handle detected browser processes\n * @param file - The file that was locked\n * @param processes - Browser processes detected\n * @param autoClose - Whether to attempt auto-closing\n * @returns Promise that resolves to lock result\n */\n private async handleBrowserProcesses(\n file: string,\n processes: Array<{ pid: number; command: string }>,\n autoClose: boolean,\n ): Promise<BrowserLockResult> {\n const processesWithDetails = processes.map((p) => ({\n ...p,\n details: `PID: ${p.pid}, Command: ${p.command}`,\n }));\n\n const advice = getBrowserConflictAdvice(\n this.browserName.toLowerCase(),\n processesWithDetails,\n );\n\n this.logger.debug(`${this.browserName} process conflict detected`, {\n file,\n processCount: processes.length,\n advice,\n });\n\n if (autoClose) {\n return this.attemptBrowserClose();\n }\n\n return Promise.resolve({ resolved: false, shouldRelaunch: false });\n }\n\n /**\n * Attempt to close the browser gracefully\n * @returns Promise that resolves to lock result\n */\n private async attemptBrowserClose(): Promise<BrowserLockResult> {\n this.logger.info(`Attempting to close ${this.browserName} gracefully...`);\n\n const closed = await closeBrowserGracefully(this.browserName, {\n interactive: true,\n force: false,\n });\n\n if (closed) {\n await waitForBrowserToClose(this.browserName, 5000);\n return { resolved: true, shouldRelaunch: true };\n }\n\n return { resolved: false, shouldRelaunch: false };\n }\n\n /**\n * Relaunch browser after successful operation\n * @returns Promise that resolves when browser is relaunched\n */\n public async relaunchBrowser(): Promise<void> {\n this.logger.info(`Relaunching ${this.browserName}...`);\n\n try {\n // Check if browser is supported on this platform\n if (!this.platformControl.isBrowserSupported(this.browserName)) {\n this.logger.debug(\n `${this.browserName} is not available on ${this.platformControl.getPlatformName()}`,\n );\n return;\n }\n\n // Use platform-specific strategy to launch browser\n await this.platformControl.launchBrowser(this.browserName);\n\n this.logger.success(\n `${this.browserName} has been relaunched with your tabs restored`,\n );\n } catch (relaunchError) {\n this.logger.debug(\n `Could not relaunch ${this.browserName} automatically`,\n {\n error: getErrorMessage(relaunchError),\n platform: this.platformControl.getPlatformName(),\n },\n );\n }\n }\n}\n","// External imports\nimport { createDecipheriv, pbkdf2 } from \"node:crypto\";\n\nimport { isMacOS, isWindows } from \"@utils/platformUtils\";\n\n/**\n * Simple memoization utility for caching Buffer operations\n * @param fn - The function to memoize that takes a Buffer and returns a Buffer\n * @param keyFn - Optional function to generate cache keys from Buffer values\n * @returns A memoized version of the input function\n */\nfunction memoizeBuffer(\n fn: (value: Buffer) => Buffer,\n keyFn?: (value: Buffer) => string,\n): (value: Buffer) => Buffer {\n const cache = new Map<string, Buffer>();\n\n return (value: Buffer): Buffer => {\n const key = keyFn ? keyFn(value) : value.toString(\"hex\");\n\n if (cache.has(key)) {\n const cachedResult = cache.get(key);\n if (cachedResult !== undefined) {\n return cachedResult;\n }\n }\n\n const result = fn(value);\n cache.set(key, result);\n return result;\n };\n}\n\nimport { decryptV10Cookie, isV10Cookie } from \"./windows/decryptV10Cookie\";\n\n/**\n * Removes the v10 prefix from the encrypted value if present\n * @param value - The encrypted value\n * @returns The value without the v10 prefix\n */\nconst removeV10Prefix = memoizeBuffer(\n (value: Buffer): Buffer => {\n if (\n value.length >= 3 &&\n value[0] === 0x76 && // 'v'\n value[1] === 0x31 && // '1'\n value[2] === 0x30\n ) {\n // '0'\n return value.slice(3);\n }\n return value;\n },\n (value: Buffer) => value.toString(\"hex\"),\n);\n\n/**\n * Removes PKCS7 padding from the decrypted value\n * @param decrypted - The decrypted buffer\n * @returns The buffer without padding\n */\nconst removePadding = memoizeBuffer(\n (decrypted: Buffer): Buffer => {\n const padding = decrypted[decrypted.length - 1];\n if (padding && padding <= 16) {\n return decrypted.slice(0, -padding);\n }\n return decrypted;\n },\n (decrypted: Buffer) => decrypted.toString(\"hex\"),\n);\n\n/**\n * Extracts the actual value from the decoded string by removing Chrome's prefixes\n * @param decodedString - The decoded string to clean up\n * @returns The cleaned up value\n */\nfunction extractValue(decodedString: string): string {\n // First try to find a UUID pattern which is common in cookies\n const uuidMatch = decodedString.match(\n /([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/i,\n );\n if (uuidMatch?.[1]) {\n return uuidMatch[1];\n }\n\n // Look for common patterns at the end of the string\n const endPatterns = [\n /([A-Z]{3})$/, // Currency codes (USD, GBP, EUR)\n /([a-z]{2}_[A-Z]{2})$/, // Locale codes (en_US, en_GB)\n /(\\d{3}-\\d{7}-\\d{7})$/, // Amazon session IDs\n ];\n\n for (const pattern of endPatterns) {\n const match = decodedString.match(pattern);\n if (match?.[1]) {\n return match[1];\n }\n }\n\n // Then try other cleanup patterns\n const cleanupPatterns = [\n /.*?0t(.+)$/, // Pattern ending in \"0t\" followed by value\n /.*?1e`(.+)$/, // Pattern ending in \"1e`\" followed by value\n /.*?[`'](.+)$/, // Any backtick or quote followed by value\n /[^\\x20-\\x7E]*([\\x20-\\x7E]+)$/, // Non-printable chars followed by printable chars\n /.*?([a-zA-Z0-9_\\-.]+)$/, // Alphanumeric value at the end\n ];\n\n for (const pattern of cleanupPatterns) {\n const match = decodedString.match(pattern);\n const value = match?.[1] ?? \"\";\n if (value.length > 0) {\n return value;\n }\n }\n return decodedString;\n}\n\n/**\n * Decrypts Chrome's encrypted cookie values\n * @param encryptedValue - The encrypted cookie value as a Buffer\n * @param password - The Chrome encryption password\n * @param metaVersion - Optional meta version for determining decryption behavior\n * @returns A promise that resolves to the decrypted cookie value\n * @throws {Error} If decryption fails\n * @example\n */\nexport async function decrypt(\n encryptedValue: Buffer,\n password: string | Buffer,\n metaVersion?: number,\n): Promise<string> {\n // v10 cookies use AES-GCM on Windows only\n // On macOS, cookies starting with v10 are actually v11 encrypted with a value that starts with \"v10,\"\n // Only treat as v10 cookie if we're on Windows AND it has sufficient length AND password is a Buffer (real scenario)\n if (\n isWindows() &&\n isV10Cookie(encryptedValue) &&\n encryptedValue.length >= 31 &&\n Buffer.isBuffer(password)\n ) {\n return decryptV10Cookie(encryptedValue, password);\n }\n\n // On macOS, cookies that don't start with v10 are considered 'old data' stored as plaintext\n // Ref: https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/os_crypt/sync/os_crypt_mac.mm\n if (isMacOS()) {\n // Check if this looks like encrypted data (starts with common version prefixes)\n const hasVersionPrefix = encryptedValue\n .slice(0, 3)\n .toString()\n .match(/^v\\d\\d$/);\n if (!hasVersionPrefix) {\n // Not a version prefix - treat as plaintext on macOS\n return Promise.resolve(encryptedValue.toString(\"utf8\"));\n }\n }\n\n // v11 cookies and other encrypted cookies use AES-CBC with PBKDF2\n if (typeof password !== \"string\") {\n throw new Error(\"password must be a string\");\n }\n if (!Buffer.isBuffer(encryptedValue)) {\n throw new Error(\"encryptedData must be a Buffer\");\n }\n\n return new Promise((resolve, reject) => {\n pbkdf2(password, \"saltysalt\", 1003, 16, \"sha1\", (error, key) => {\n try {\n if (error) {\n reject(new Error(`Failed to derive key: ${error.message}`));\n return;\n }\n\n const value = removeV10Prefix(encryptedValue);\n if (value.length % 16 !== 0) {\n reject(new Error(\"Encrypted data length is not a multiple of 16\"));\n return;\n }\n\n // Chrome's encryption parameters\n const iv = Buffer.alloc(16, \" \"); // 16 spaces\n const decipher = createDecipheriv(\"aes-128-cbc\", key, iv);\n decipher.setAutoPadding(false);\n\n // Decrypt the value\n let decrypted: Buffer = decipher.update(value);\n try {\n decipher.final();\n } catch (e) {\n reject(\n new Error(`Failed to finalize decryption: ${(e as Error).message}`),\n );\n return;\n }\n\n decrypted = removePadding(decrypted);\n\n // Skip the first 32 bytes (hash prefix) if meta version >= 24\n // Ref: https://chromium.googlesource.com/chromium/src/+/b02dcebd7cafab92770734dc2bc317bd07f1d891/net/extras/sqlite/sqlite_persistent_cookie_store.cc#223\n const useHashPrefix = (metaVersion ?? 0) >= 24;\n const finalDecrypted =\n useHashPrefix && decrypted.length > 32\n ? decrypted.slice(32)\n : decrypted;\n\n const decodedString = finalDecrypted.toString(\"utf8\");\n resolve(extractValue(decodedString));\n } catch (e) {\n reject(new Error(`Decryption failed: ${(e as Error).message}`));\n }\n });\n });\n}\n","import { createDecipheriv } from \"node:crypto\";\n\n/**\n * Decrypts Chrome v10 encrypted cookies on Windows using AES-256-GCM\n *\n * Chrome v10 cookies use AES-256-GCM encryption with:\n * - 12-byte nonce (96 bits)\n * - 16-byte authentication tag\n * @param encryptedValue - The encrypted cookie value starting with 'v10' prefix\n * @param key - The decrypted master key from DPAPI\n * @returns The decrypted cookie value\n * @throws {Error} If the cookie is not v10 format or decryption fails\n */\nexport function decryptV10Cookie(encryptedValue: Buffer, key: Buffer): string {\n // Check for v10 prefix\n const VERSION_PREFIX = Buffer.from(\"v10\");\n if (!encryptedValue.subarray(0, 3).equals(VERSION_PREFIX)) {\n throw new Error(\"Not a v10 encrypted cookie\");\n }\n\n // Remove the version prefix\n const ciphertext = encryptedValue.subarray(3);\n\n // Extract components\n const NONCE_LENGTH = 12; // 96 bits / 8\n const TAG_LENGTH = 16; // 128 bits / 8\n\n if (ciphertext.length < NONCE_LENGTH + TAG_LENGTH) {\n throw new Error(\"Invalid v10 cookie: too short\");\n }\n\n const nonce = ciphertext.subarray(0, NONCE_LENGTH);\n const encryptedData = ciphertext.subarray(\n NONCE_LENGTH,\n ciphertext.length - TAG_LENGTH,\n );\n const authTag = ciphertext.subarray(ciphertext.length - TAG_LENGTH);\n\n // Decrypt using AES-256-GCM\n const decipher = createDecipheriv(\"aes-256-gcm\", key, nonce);\n decipher.setAuthTag(authTag);\n\n const decrypted = Buffer.concat([\n decipher.update(encryptedData),\n decipher.final(),\n ]);\n\n return decrypted.toString(\"utf8\");\n}\n\n/**\n * Checks if a cookie value is v10 encrypted\n * @param value - The cookie value to check\n * @returns True if the cookie starts with 'v10' prefix\n */\nexport function isV10Cookie(value: Buffer): boolean {\n const VERSION_PREFIX = Buffer.from(\"v10\");\n return value.length >= 3 && value.subarray(0, 3).equals(VERSION_PREFIX);\n}\n","import { assertPlatformSupported, getPlatform } from \"@utils/platformUtils\";\n\nimport { execSimple } from \"../../../utils/execSimple\";\n\nimport type { ChromiumBrowser } from \"./ChromiumBrowsers\";\n\n/**\n * Maps browser types to their keychain service names on macOS\n */\nconst MACOS_KEYCHAIN_SERVICES: Record<ChromiumBrowser, string> = {\n chrome: \"Chrome Safe Storage\",\n chromium: \"Chromium Safe Storage\",\n brave: \"Brave Safe Storage\",\n edge: \"Microsoft Edge Safe Storage\",\n arc: \"Arc Safe Storage\",\n opera: \"Opera Safe Storage\",\n \"opera-gx\": \"Opera Safe Storage\", // Opera GX shares Opera's keychain\n vivaldi: \"Vivaldi Safe Storage\",\n whale: \"Whale Safe Storage\",\n};\n\n/**\n * Gets the Chromium browser Safe Storage password for macOS\n * @param browser - The browser type to get the password for\n * @returns A promise that resolves to the browser's Safe Storage password\n */\nasync function getMacOSPassword(browser: ChromiumBrowser): Promise<string> {\n const service = MACOS_KEYCHAIN_SERVICES[browser];\n if (!service) {\n throw new Error(`Unknown browser type: ${browser}`);\n }\n\n try {\n const command = `security find-generic-password -w -s \"${service}\"`;\n const result = await execSimple(command);\n return result.stdout.trim();\n } catch (error) {\n // Fallback to Chrome if browser-specific key not found\n // This is useful for browsers that share Chrome's encryption\n if (browser !== \"chrome\") {\n const chromeCommand = `security find-generic-password -w -s \"Chrome Safe Storage\"`;\n try {\n const result = await execSimple(chromeCommand);\n return result.stdout.trim();\n } catch {\n // If Chrome fallback also fails, throw original error\n }\n }\n throw new Error(\n `Failed to get ${browser} password from keychain: ${error}`,\n );\n }\n}\n\n/**\n * Gets the Chromium browser password for Windows\n * Windows uses DPAPI which is browser-agnostic\n */\nasync function getWindowsPassword(): Promise<string | Buffer> {\n // Import dynamically to avoid loading on non-Windows platforms\n const { getChromePassword } = await import(\"./windows/getChromePassword\");\n return getChromePassword();\n}\n\n/**\n * Gets the Chromium browser password for Linux\n * Linux typically uses a hardcoded key or libsecret\n */\nasync function getLinuxPassword(): Promise<string> {\n // Import dynamically to avoid loading on non-Linux platforms\n const { getChromePassword } = await import(\"./linux/getChromePassword\");\n return getChromePassword();\n}\n\n/**\n * Gets the Chromium-based browser Safe Storage password for the current platform.\n * This password is used to decrypt cookies stored in the browser's cookie database.\n * Supports macOS (keychain), Windows (DPAPI), and Linux (keyring/libsecret).\n * @param browser - The Chromium-based browser to get the password for\n * @returns A promise that resolves to the browser's Safe Storage password or Buffer\n * @throws {Error} If the password cannot be retrieved or the platform is not supported\n */\nexport async function getChromiumPassword(\n browser: ChromiumBrowser = \"chrome\",\n): Promise<string | Buffer> {\n assertPlatformSupported();\n\n switch (getPlatform()) {\n case \"darwin\": {\n return getMacOSPassword(browser);\n }\n case \"win32\": {\n // Windows uses DPAPI which works for all Chromium browsers\n return getWindowsPassword();\n }\n case \"linux\": {\n // Linux uses a hardcoded key for all Chromium browsers\n return getLinuxPassword();\n }\n default:\n throw new Error(`Platform ${getPlatform()} is not supported`);\n }\n}\n","/**\n * Database connection manager with pooling and performance monitoring\n * Manages SQLite connections efficiently with automatic cleanup and monitoring\n */\n\nimport { EventEmitter } from \"node:events\";\n\nimport BetterSqlite3, { type Database } from \"better-sqlite3\";\n\nimport { createTaggedLogger, logError } from \"@utils/logHelpers\";\n\nconst logger = createTaggedLogger(\"DatabaseConnectionManager\");\n\n/**\n * Connection pool configuration\n */\nexport interface PoolConfig {\n /** Maximum number of connections in the pool */\n maxConnections?: number;\n /** Connection timeout in milliseconds */\n connectionTimeout?: number;\n /** Idle timeout before closing connection */\n idleTimeout?: number;\n /** Enable performance monitoring */\n enableMonitoring?: boolean;\n /** Retry attempts for locked databases */\n retryAttempts?: number;\n /** Retry delay in milliseconds */\n retryDelay?: number;\n /** Query execution timeout in milliseconds */\n queryTimeout?: number;\n}\n\n/**\n * Database connection metadata\n */\ninterface ConnectionMetadata {\n database: Database;\n filepath: string;\n inUse: boolean;\n lastAccessed: number;\n queryCount: number;\n totalQueryTime: number;\n created: number;\n}\n\n/**\n * Query performance metrics\n */\nexport interface QueryMetrics {\n query: string;\n duration: number;\n rowCount: number;\n filepath: string;\n timestamp: number;\n success: boolean;\n error?: string;\n}\n\n/**\n * Connection pool statistics\n */\nexport interface PoolStatistics {\n totalConnections: number;\n activeConnections: number;\n idleConnections: number;\n totalQueries: number;\n averageQueryTime: number;\n cacheHitRate: number;\n connectionReuse: number;\n}\n\n/**\n * Database connection manager with pooling\n */\nexport class DatabaseConnectionManager extends EventEmitter {\n private readonly connections: Map<string, ConnectionMetadata>;\n private readonly config: Required<PoolConfig>;\n private readonly queryMetrics: QueryMetrics[];\n private lastCleanupTime: number;\n private totalQueries: number;\n private cacheHits: number;\n private connectionReuses: number;\n\n /**\n *\n * @param config\n */\n constructor(config: PoolConfig = {}) {\n super();\n\n this.connections = new Map();\n this.queryMetrics = [];\n this.totalQueries = 0;\n this.cacheHits = 0;\n this.connectionReuses = 0;\n this.lastCleanupTime = Date.now();\n\n this.config = {\n maxConnections: config.maxConnections ?? 5,\n connectionTimeout: config.connectionTimeout ?? 5000,\n idleTimeout: config.idleTimeout ?? 30000,\n enableMonitoring: config.enableMonitoring ?? true,\n retryAttempts: config.retryAttempts ?? 3,\n retryDelay: config.retryDelay ?? 100,\n queryTimeout: config.queryTimeout ?? 3000, // 3 seconds default\n };\n }\n\n /**\n * Get or create a database connection\n * @param filepath\n */\n async getConnection(filepath: string): Promise<Database> {\n // Perform cleanup if needed (every 30 seconds)\n const now = Date.now();\n if (now - this.lastCleanupTime > 30000) {\n this.cleanupIdleConnections();\n this.lastCleanupTime = now;\n }\n\n // Check existing connection\n const existing = this.connections.get(filepath);\n if (existing && !existing.inUse) {\n existing.inUse = true;\n existing.lastAccessed = Date.now();\n this.connectionReuses++;\n\n logger.debug(\"Reusing existing connection\", {\n filepath,\n queryCount: existing.queryCount,\n });\n\n return existing.database;\n }\n\n // Check pool limit\n if (this.connections.size >= this.config.maxConnections) {\n await this.evictLeastRecentlyUsed();\n }\n\n // Create new connection\n return this.createConnection(filepath);\n }\n\n /**\n * Create a new database connection\n * @param filepath\n */\n private async createConnection(filepath: string): Promise<Database> {\n const startTime = Date.now();\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < this.config.retryAttempts; attempt++) {\n try {\n const database = new BetterSqlite3(filepath, {\n readonly: true,\n fileMustExist: true,\n });\n\n // Set busy timeout for all queries on this connection\n // This timeout only applies to actual query execution, not connection retries\n database.pragma(`busy_timeout = ${this.config.queryTimeout}`);\n\n const metadata: ConnectionMetadata = {\n database,\n filepath,\n inUse: true,\n lastAccessed: Date.now(),\n queryCount: 0,\n totalQueryTime: 0,\n created: Date.now(),\n };\n\n this.connections.set(filepath, metadata);\n\n const connectionTime = Date.now() - startTime;\n logger.debug(\"Created new connection\", {\n filepath,\n connectionTime,\n attempt: attempt + 1,\n });\n\n this.emit(\"connection:created\", { filepath, connectionTime });\n\n return database;\n } catch (error) {\n lastError = error as Error;\n\n if (this.isDatabaseLocked(error)) {\n logger.warn(\"Database locked, retrying\", {\n filepath,\n attempt: attempt + 1,\n maxAttempts: this.config.retryAttempts,\n });\n\n await this.delay(this.config.retryDelay * 2 ** attempt);\n continue;\n }\n\n throw error;\n }\n }\n\n throw lastError || new Error(`Failed to connect to database: ${filepath}`);\n }\n\n /**\n * Execute a query with the connection manager\n * The connection already has busy_timeout set, so queries will timeout appropriately\n * @param filepath\n * @param queryFn\n * @param queryDescription\n */\n async executeQuery<T>(\n filepath: string,\n queryFn: (db: Database) => T,\n queryDescription?: string,\n ): Promise<T> {\n const startTime = Date.now();\n const connection = await this.getConnection(filepath);\n const metadata = this.connections.get(filepath);\n\n try {\n const result = queryFn(connection);\n const duration = Date.now() - startTime;\n\n if (metadata) {\n metadata.queryCount++;\n metadata.totalQueryTime += duration;\n }\n\n this.totalQueries++;\n this.cacheHits++; // Increment cache hits for successful queries\n\n // Log slow queries at debug level\n if (duration > 100) {\n logger.debug(\"Slow query detected\", {\n query: queryDescription || \"Unknown query\",\n duration,\n filepath,\n });\n }\n\n // Record metrics\n if (this.config.enableMonitoring) {\n const metrics: QueryMetrics = {\n query: queryDescription || \"Unknown query\",\n duration,\n rowCount: Array.isArray(result) ? result.length : 1,\n filepath,\n timestamp: Date.now(),\n success: true,\n };\n\n this.recordMetrics(metrics);\n }\n\n return result;\n } catch (error) {\n const duration = Date.now() - startTime;\n\n // Increment query count even for failed queries\n this.totalQueries++;\n\n // Record error metrics\n if (this.config.enableMonitoring) {\n const metrics: QueryMetrics = {\n query: queryDescription || \"Unknown query\",\n duration,\n rowCount: 0,\n filepath,\n timestamp: Date.now(),\n success: false,\n error: (error as Error).message,\n };\n\n this.recordMetrics(metrics);\n }\n\n throw error;\n } finally {\n // Release connection\n if (metadata) {\n metadata.inUse = false;\n metadata.lastAccessed = Date.now();\n }\n }\n }\n\n /**\n * Release a connection back to the pool\n * @param filepath\n */\n releaseConnection(filepath: string): void {\n const metadata = this.connections.get(filepath);\n if (metadata) {\n metadata.inUse = false;\n metadata.lastAccessed = Date.now();\n logger.debug(\"Released connection\", { filepath });\n }\n }\n\n /**\n * Close a specific connection\n * @param filepath\n */\n closeConnection(filepath: string): void {\n const metadata = this.connections.get(filepath);\n if (metadata) {\n try {\n metadata.database.close();\n this.connections.delete(filepath);\n\n logger.debug(\"Closed connection\", {\n filepath,\n queryCount: metadata.queryCount,\n lifetime: Date.now() - metadata.created,\n });\n\n this.emit(\"connection:closed\", { filepath });\n } catch (error) {\n logError(\"Failed to close connection\", error, { filepath });\n }\n }\n }\n\n /**\n * Close all connections\n */\n closeAll(): void {\n for (const [filepath, metadata] of this.connections) {\n try {\n metadata.database.close();\n logger.debug(\"Closed connection\", { filepath });\n } catch (error) {\n logError(\"Failed to close connection\", error, { filepath });\n }\n }\n\n this.connections.clear();\n\n logger.info(\"Closed all connections\", {\n totalQueries: this.totalQueries,\n connectionReuses: this.connectionReuses,\n });\n }\n\n /**\n * Get pool statistics\n */\n getStatistics(): PoolStatistics {\n let totalQueryTime = 0;\n let totalQueryCount = 0;\n let activeConnections = 0;\n\n for (const metadata of this.connections.values()) {\n totalQueryTime += metadata.totalQueryTime;\n totalQueryCount += metadata.queryCount;\n if (metadata.inUse) {\n activeConnections++;\n }\n }\n\n return {\n totalConnections: this.connections.size,\n activeConnections,\n idleConnections: this.connections.size - activeConnections,\n totalQueries: this.totalQueries,\n averageQueryTime:\n totalQueryCount > 0 ? totalQueryTime / totalQueryCount : 0,\n cacheHitRate:\n this.totalQueries > 0 ? this.cacheHits / this.totalQueries : 0,\n connectionReuse: this.connectionReuses,\n };\n }\n\n /**\n * Get recent query metrics\n * @param limit\n */\n getQueryMetrics(limit = 100): QueryMetrics[] {\n return this.queryMetrics.slice(-limit);\n }\n\n /**\n * Clear query metrics\n */\n clearMetrics(): void {\n this.queryMetrics.length = 0;\n }\n\n /**\n * Clean up idle connections\n */\n private cleanupIdleConnections(): void {\n const now = Date.now();\n const toClose: string[] = [];\n\n for (const [filepath, metadata] of this.connections) {\n if (\n !metadata.inUse &&\n now - metadata.lastAccessed > this.config.idleTimeout\n ) {\n toClose.push(filepath);\n }\n }\n\n for (const filepath of toClose) {\n this.closeConnection(filepath);\n }\n\n if (toClose.length > 0) {\n logger.debug(\"Cleaned up idle connections\", { count: toClose.length });\n }\n }\n\n /**\n * Evict least recently used connection\n */\n private async evictLeastRecentlyUsed(): Promise<void> {\n let lruPath: string | null = null;\n let lruTime = Date.now();\n\n for (const [filepath, metadata] of this.connections) {\n if (!metadata.inUse && metadata.lastAccessed < lruTime) {\n lruPath = filepath;\n lruTime = metadata.lastAccessed;\n }\n }\n\n if (lruPath) {\n this.closeConnection(lruPath);\n logger.debug(\"Evicted LRU connection\", { filepath: lruPath });\n } else {\n // All connections are in use, wait a bit\n await this.delay(100);\n }\n }\n\n /**\n * Record query metrics\n * @param metrics\n */\n private recordMetrics(metrics: QueryMetrics): void {\n this.queryMetrics.push(metrics);\n\n // Keep only recent metrics (last 1000)\n if (this.queryMetrics.length > 1000) {\n this.queryMetrics.splice(0, this.queryMetrics.length - 1000);\n }\n\n this.emit(\"query:executed\", metrics);\n }\n\n /**\n * Check if error indicates database lock\n * @param error\n */\n private isDatabaseLocked(error: unknown): boolean {\n if (error instanceof Error) {\n const message = error.message.toLowerCase();\n return (\n message.includes(\"database is locked\") ||\n message.includes(\"database locked\") ||\n message.includes(\"sqlite_busy\")\n );\n }\n return false;\n }\n\n /**\n * Delay helper\n * @param ms\n */\n private async delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\n/**\n * Global connection manager instance\n */\nlet globalManager: DatabaseConnectionManager | null = null;\n\n/**\n * Process exit handler function\n */\nlet exitHandler: (() => void) | null = null;\n\n/**\n * Get or create global connection manager\n * @param config\n */\nexport function getGlobalConnectionManager(\n config?: PoolConfig,\n): DatabaseConnectionManager {\n if (!globalManager) {\n globalManager = new DatabaseConnectionManager(config);\n\n // Ensure cleanup on process exit (only add once)\n if (!exitHandler) {\n exitHandler = () => {\n if (globalManager) {\n globalManager.closeAll();\n }\n };\n process.on(\"exit\", exitHandler);\n }\n }\n\n return globalManager;\n}\n\n/**\n * Reset global connection manager (mainly for testing)\n */\nexport function resetGlobalConnectionManager(): void {\n if (globalManager) {\n globalManager.closeAll();\n globalManager = null;\n }\n\n // Remove the exit handler to prevent memory leaks in tests\n if (exitHandler) {\n process.removeListener(\"exit\", exitHandler);\n exitHandler = null;\n }\n}\n","/**\n * Query monitoring wrapper for SQL operations\n * Provides clean, type-safe monitoring without monkey-patching\n */\n\nimport type { Database, Statement } from \"better-sqlite3\";\n\nimport { createTaggedLogger } from \"@utils/logHelpers\";\n\nconst logger = createTaggedLogger(\"QueryMonitor\");\n\n/**\n * Query execution metrics\n */\nexport interface QueryExecution {\n sql: string;\n params: unknown[];\n startTime: number;\n endTime?: number;\n duration?: number;\n rowCount?: number;\n error?: Error;\n filepath?: string;\n}\n\n/**\n * Query monitoring options\n */\nexport interface MonitoringOptions {\n /** Log slow queries (in ms) */\n slowQueryThreshold?: number;\n /** Enable detailed logging */\n verbose?: boolean;\n /** Track query history */\n trackHistory?: boolean;\n /** Maximum history size */\n maxHistorySize?: number;\n}\n\n/**\n * Query monitor for tracking SQL performance\n */\nexport class QueryMonitor {\n private readonly options: Required<MonitoringOptions>;\n private readonly queryHistory: QueryExecution[];\n private totalQueries: number;\n private totalDuration: number;\n private slowQueries: number;\n private errors: number;\n\n /**\n * Creates a new QueryMonitor instance for tracking SQL query performance and metrics.\n * @param options - Configuration options for monitoring behavior\n * @param options.slowQueryThreshold - Milliseconds before a query is considered slow (default: 100ms)\n * @param options.verbose - Whether to log detailed query information (default: false)\n * @param options.trackHistory - Whether to maintain query history (default: true)\n * @param options.maxHistorySize - Maximum number of queries to keep in history (default: 1000)\n */\n constructor(options: MonitoringOptions = {}) {\n this.options = {\n slowQueryThreshold: options.slowQueryThreshold ?? 100,\n verbose: options.verbose ?? false,\n trackHistory: options.trackHistory ?? true,\n maxHistorySize: options.maxHistorySize ?? 1000,\n };\n\n this.queryHistory = [];\n this.totalQueries = 0;\n this.totalDuration = 0;\n this.slowQueries = 0;\n this.errors = 0;\n }\n\n /**\n * Execute a query with monitoring\n * @param db\n * @param sql\n * @param params\n * @param filepath\n */\n executeQuery<T>(\n db: Database,\n sql: string,\n params: unknown[] = [],\n filepath?: string,\n ): T[] {\n const execution: QueryExecution = {\n sql,\n params,\n startTime: Date.now(),\n };\n if (filepath !== undefined) {\n execution.filepath = filepath;\n }\n\n try {\n // Execute the query (timeout is already set on the connection)\n const stmt = db.prepare(sql);\n const result = stmt.all(...params) as T[];\n\n // Record success metrics\n execution.endTime = Date.now();\n execution.duration = execution.endTime - execution.startTime;\n execution.rowCount = result.length;\n\n this.recordExecution(execution);\n\n return result;\n } catch (error) {\n // Record error metrics\n execution.endTime = Date.now();\n execution.duration = execution.endTime - execution.startTime;\n execution.error = error as Error;\n\n this.recordExecution(execution);\n\n throw error;\n }\n }\n\n /**\n * Execute a single row query with monitoring\n * @param db\n * @param sql\n * @param params\n * @param filepath\n */\n executeGet<T>(\n db: Database,\n sql: string,\n params: unknown[] = [],\n filepath?: string,\n ): T | undefined {\n const execution: QueryExecution = {\n sql,\n params,\n startTime: Date.now(),\n };\n if (filepath !== undefined) {\n execution.filepath = filepath;\n }\n\n try {\n // Execute the query (timeout is already set on the connection)\n const stmt = db.prepare(sql);\n const result = stmt.get(...params) as T | undefined;\n\n // Record success metrics\n execution.endTime = Date.now();\n execution.duration = execution.endTime - execution.startTime;\n execution.rowCount = result ? 1 : 0;\n\n this.recordExecution(execution);\n\n return result;\n } catch (error) {\n // Record error metrics\n execution.endTime = Date.now();\n execution.duration = execution.endTime - execution.startTime;\n execution.error = error as Error;\n\n this.recordExecution(execution);\n\n throw error;\n }\n }\n\n /**\n * Create a monitored statement wrapper\n * @param db\n * @param sql\n * @param filepath\n */\n prepareStatement<T>(\n db: Database,\n sql: string,\n filepath?: string,\n ): MonitoredStatement<T> {\n const stmt = db.prepare(sql);\n return new MonitoredStatement(stmt, sql, this, filepath);\n }\n\n /**\n * Record query execution\n * @param execution\n */\n private recordExecution(execution: QueryExecution): void {\n // Update statistics\n this.totalQueries++;\n\n if (execution.duration !== undefined) {\n this.totalDuration += execution.duration;\n\n // Check for slow query\n if (execution.duration > this.options.slowQueryThreshold) {\n this.slowQueries++;\n\n logger.debug(\"Slow query detected\", {\n sql: execution.sql,\n duration: execution.duration,\n rowCount: execution.rowCount,\n filepath: execution.filepath,\n });\n }\n }\n\n if (execution.error) {\n this.errors++;\n\n if (this.options.verbose) {\n logger.error(\"Query failed\", {\n sql: execution.sql,\n error: execution.error.message,\n filepath: execution.filepath,\n });\n }\n } else if (this.options.verbose) {\n logger.debug(\"Query executed\", {\n sql: execution.sql,\n duration: execution.duration,\n rowCount: execution.rowCount,\n });\n }\n\n // Track history\n if (this.options.trackHistory) {\n this.queryHistory.push(execution);\n\n // Trim history if needed\n if (this.queryHistory.length > this.options.maxHistorySize) {\n this.queryHistory.splice(\n 0,\n this.queryHistory.length - this.options.maxHistorySize,\n );\n }\n }\n }\n\n /**\n * Get monitoring statistics\n */\n getStatistics() {\n return {\n totalQueries: this.totalQueries,\n averageDuration:\n this.totalQueries > 0 ? this.totalDuration / this.totalQueries : 0,\n slowQueries: this.slowQueries,\n slowQueryRate:\n this.totalQueries > 0 ? this.slowQueries / this.totalQueries : 0,\n errors: this.errors,\n errorRate: this.totalQueries > 0 ? this.errors / this.totalQueries : 0,\n historySize: this.queryHistory.length,\n };\n }\n\n /**\n * Get query history\n * @param limit\n */\n getHistory(limit?: number): QueryExecution[] {\n if (limit) {\n return this.queryHistory.slice(-limit);\n }\n return [...this.queryHistory];\n }\n\n /**\n * Clear history\n */\n clearHistory(): void {\n this.queryHistory.length = 0;\n }\n\n /**\n * Reset all statistics\n */\n reset(): void {\n this.clearHistory();\n this.totalQueries = 0;\n this.totalDuration = 0;\n this.slowQueries = 0;\n this.errors = 0;\n }\n}\n\n/**\n * Monitored statement wrapper\n */\nexport class MonitoredStatement<T> {\n /**\n * Creates a monitored wrapper around a prepared SQL statement.\n * This wrapper automatically tracks execution metrics for all queries run through it.\n * @param statement - The prepared SQLite statement to monitor\n * @param sql - The SQL query string for logging and debugging\n * @param monitor - The QueryMonitor instance that will track metrics\n * @param filepath - Optional database file path for additional context in logs\n */\n constructor(\n private readonly statement: Statement,\n private readonly sql: string,\n private readonly monitor: QueryMonitor,\n private readonly filepath?: string,\n ) {}\n\n /**\n * Execute all with monitoring\n * @param {...any} params\n */\n all(...params: unknown[]): T[] {\n return this.monitor.executeQuery<T>(\n { prepare: () => this.statement } as unknown as Database,\n this.sql,\n params,\n this.filepath,\n );\n }\n\n /**\n * Execute get with monitoring\n * @param {...any} params\n */\n get(...params: unknown[]): T | undefined {\n return this.monitor.executeGet<T>(\n { prepare: () => this.statement } as unknown as Database,\n this.sql,\n params,\n this.filepath,\n );\n }\n\n /**\n * Get underlying statement\n */\n getStatement(): Statement {\n return this.statement;\n }\n}\n\n/**\n * Create a global query monitor instance\n */\nlet globalMonitor: QueryMonitor | null = null;\n\n/**\n * Get or create global query monitor\n * @param options\n */\nexport function getGlobalQueryMonitor(\n options?: MonitoringOptions,\n): QueryMonitor {\n if (!globalMonitor) {\n globalMonitor = new QueryMonitor(options);\n }\n return globalMonitor;\n}\n\n/**\n * Reset global query monitor\n */\nexport function resetGlobalQueryMonitor(): void {\n if (globalMonitor) {\n globalMonitor.reset();\n globalMonitor = null;\n }\n}\n","// External imports\nimport { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport fg from \"fast-glob\";\n\n// Internal imports\nimport { createTaggedLogger } from \"../../utils/logHelpers\";\n\nimport { chromeApplicationSupport } from \"./chrome/ChromeApplicationSupport\";\n\nconst logger = createTaggedLogger(\"listChromeProfiles\");\n\n/**\n * Lists all Chrome profile paths that contain cookie files\n * @internal\n * @returns An array of absolute paths to Chrome cookie files\n * @throws {Error} If Chrome's application support directory cannot be accessed\n * @example\n * ```typescript\n * // Get all Chrome cookie file paths\n * const cookiePaths = listChromeProfilePaths();\n * // Returns: [\n * // '/Users/name/Library/Application Support/Chrome/Profile 1/Cookies',\n * // '/Users/name/Library/Application Support/Chrome/Profile 2/Cookies'\n * // ]\n *\n * // Handle errors\n * try {\n * const paths = listChromeProfilePaths();\n * } catch (error) {\n * logger.error('Failed to access Chrome profiles', { error });\n * }\n * ```\n */\nexport function listChromeProfilePaths(): string[] {\n const files: string[] = fg.sync(\"./**/Cookies\", {\n cwd: chromeApplicationSupport,\n absolute: true,\n });\n\n logger.debug(\"Found cookie files:\", files);\n return files;\n}\n\n/**\n * Chrome Local State file structure\n * @internal\n */\ninterface ChromeLocalState {\n profile: {\n info_cache: Record<string, ChromeProfileInfo>;\n };\n}\n\n/**\n * Chrome profile information structure\n * @property {string} name - The name of the profile\n * @property {number} active_time - Unix timestamp of last profile activity\n * @property {string} account_id - Unique identifier for the Chrome profile\n * @property {Record<string, unknown>} accountcapabilities - Account feature flags\n * @property {string} email - User's email address\n * @property {string} full_name - User's full name\n * @property {boolean} is_using_default_avatar - Whether using default profile picture\n * @property {boolean} is_using_default_name - Whether using default profile name\n * @property {string} last_downloaded_gaia_picture_url_with_size - Profile picture URL\n * @property {string} local_auth_credentials - Authentication credentials\n * @property {string} shortcut_name - Profile shortcut name\n * @property {string} user_name - Username associated with profile\n */\ninterface ChromeProfileInfo {\n /** The name of the profile */\n name: string;\n /** Unix timestamp of last profile activity */\n active_time: number;\n /** Unique identifier for the Chrome profile */\n account_id: string;\n /** Account feature flags */\n accountcapabilities: Record<string, unknown>;\n /** User's email address */\n email: string;\n /** User's full name */\n full_name: string;\n /** Whether using default profile picture */\n is_using_default_avatar: boolean;\n /** Whether using default profile name */\n is_using_default_name: boolean;\n /** Profile picture URL */\n last_downloaded_gaia_picture_url_with_size: string;\n /** Authentication credentials */\n local_auth_credentials: string;\n /** Profile shortcut name */\n shortcut_name: string;\n /** Username associated with profile */\n user_name: string;\n}\n\n/**\n * Lists all Chrome profiles and their associated information\n * @internal\n * @returns An array of Chrome profile information objects. Returns empty array if profiles cannot be read\n * @throws {Error} If Chrome's application support directory cannot be accessed\n * @example\n * ```typescript\n * // Get all Chrome profiles\n * const profiles = listChromeProfiles();\n * // Returns: [\n * // {\n * // name: \"Default\",\n * // email: \"user@example.com\",\n * // full_name: \"John Doe\",\n * // ...\n * // },\n * // ...\n * // ]\n *\n * // Handle empty or error case\n * const profiles = listChromeProfiles();\n * if (profiles.length === 0) {\n * logger.warn('No Chrome profiles found');\n * }\n * ```\n */\nexport function listChromeProfiles(): ChromeProfileInfo[] {\n try {\n const localStatePath = join(chromeApplicationSupport, \"Local State\");\n const localState = JSON.parse(\n readFileSync(localStatePath, \"utf8\"),\n ) as ChromeLocalState;\n return Object.values(localState.profile.info_cache);\n } catch (error) {\n logger.debug(\"Failed to access Chrome profiles\", { error });\n return [];\n }\n}\n","import { dirname } from \"node:path\";\n\nimport { BaseChromiumCookieQueryStrategy } from \"../chromium/BaseChromiumCookieQueryStrategy\";\nimport { listChromeProfilePaths } from \"../listChromeProfiles\";\n\n/**\n * Interface representing Chrome profile information from Local State\n */\ninterface ChromeProfileInfo {\n name?: string;\n user_name?: string;\n [key: string]: unknown;\n}\n\n/**\n * Strategy for querying cookies from Chrome browser.\n * This class extends the BaseChromiumCookieQueryStrategy with Chrome-specific logic.\n * @example\n * ```typescript\n * const strategy = new ChromeCookieQueryStrategy();\n * const cookies = await strategy.queryCookies('session', 'example.com');\n * ```\n */\nexport class ChromeCookieQueryStrategy extends BaseChromiumCookieQueryStrategy {\n private readonly profileName?: string;\n\n /**\n * Creates a new instance of ChromeCookieQueryStrategy\n * @param profileName - Optional specific profile name to target\n */\n public constructor(profileName?: string) {\n super(\"ChromeCookieQueryStrategy\", \"Chrome\");\n if (profileName !== undefined) {\n this.profileName = profileName;\n }\n }\n\n /**\n * Get Chrome-specific cookie file paths\n * @param store - Optional specific store path\n * @returns Array of cookie file paths\n */\n protected getCookieFilePaths(store?: string): string[] {\n if (store !== undefined && store !== \"\") {\n return [store];\n }\n\n let paths = listChromeProfilePaths();\n\n // Filter by profile name if specified\n if (this.profileName) {\n // Read Chrome's Local State to map profile names to directories\n try {\n const fs = require(\"node:fs\");\n const path = require(\"node:path\");\n\n // Ensure we have at least one path to determine the Chrome data directory\n if (paths.length === 0) {\n this.logger.warn(\"No Chrome cookie files found\");\n return [];\n }\n\n const firstPath = paths[0];\n if (!firstPath) {\n return [];\n }\n const chromeDataDir = dirname(dirname(firstPath)); // Get Chrome data directory\n const localStatePath = path.join(chromeDataDir, \"Local State\");\n\n if (fs.existsSync(localStatePath)) {\n const localState = JSON.parse(\n fs.readFileSync(localStatePath, \"utf8\"),\n );\n const profileCache = localState.profile?.info_cache || {};\n\n // Find the directory for the given profile name\n let targetDir: string | undefined;\n\n for (const [dir, info] of Object.entries(profileCache)) {\n const profile = info as ChromeProfileInfo;\n if (\n profile.name?.toLowerCase() === this.profileName.toLowerCase()\n ) {\n targetDir = dir;\n break;\n }\n }\n\n // Also check if user passed the directory name directly (e.g., \"Default\" or \"Profile 2\")\n if (!targetDir) {\n for (const dir of Object.keys(profileCache)) {\n if (dir.toLowerCase() === this.profileName.toLowerCase()) {\n targetDir = dir;\n break;\n }\n }\n }\n\n if (targetDir) {\n // Filter paths to only include the target directory\n paths = paths.filter((cookiePath) => {\n const dir = dirname(cookiePath);\n return dir.endsWith(targetDir);\n });\n\n if (paths.length === 0) {\n this.logger.warn(\n `No cookie files found for profile: ${this.profileName} (directory: ${targetDir})`,\n );\n } else {\n this.logger.debug(\n `Found ${paths.length} cookie file(s) for profile: ${this.profileName}`,\n );\n }\n } else {\n this.logger.debug(\"Profile not found in Chrome Local State\", {\n requestedProfile: this.profileName,\n availableProfiles: Object.entries(profileCache).map(\n ([dir, info]) => ({\n directory: dir,\n name: (info as ChromeProfileInfo).name,\n }),\n ),\n });\n\n // Return empty array to avoid querying wrong profile\n return [];\n }\n }\n } catch (error) {\n this.logger.warn(`Failed to read Chrome profile info: ${error}`);\n }\n }\n\n return Array.isArray(paths) ? paths : [paths];\n }\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { assertPlatformSupported, getPlatform } from \"@utils/platformUtils\";\n\n/**\n * Chromium browser configuration and path management\n * Supports Chrome, Chromium, Brave, Edge, Opera, Vivaldi, and Whale browsers\n * across Windows, macOS, and Linux platforms\n */\n\n/**\n * Supported Chromium-based browsers\n */\nexport const CHROMIUM_BASED_BROWSERS = [\n \"chrome\",\n \"chromium\",\n \"brave\",\n \"edge\",\n \"arc\",\n \"opera\",\n \"opera-gx\",\n \"vivaldi\",\n \"whale\",\n] as const;\n\n/**\n * Type representing all supported Chromium-based browsers.\n * This includes Chrome, Edge, Brave, Arc, Opera, and other Chromium derivatives.\n */\nexport type ChromiumBrowser = (typeof CHROMIUM_BASED_BROWSERS)[number];\n\n/**\n * Browser directory configuration for different platforms\n */\ninterface BrowserPaths {\n windows: string;\n macos: string;\n linux: string;\n}\n\n/**\n * Get the browser configuration directory for a specific browser and platform\n * @param browser - The chromium browser type\n * @returns The path to the browser's configuration directory\n * @throws {Error} If the user home directory cannot be determined or platform is unsupported\n */\nexport function getChromiumBrowserPath(browser: ChromiumBrowser): string {\n const home = homedir();\n if (!home) {\n throw new Error(\"Unable to determine user home directory\");\n }\n\n assertPlatformSupported();\n const currentPlatform = getPlatform();\n\n const browserPaths: Record<ChromiumBrowser, BrowserPaths> = {\n chrome: {\n windows: join(home, \"AppData\", \"Local\", \"Google\", \"Chrome\", \"User Data\"),\n macos: join(home, \"Library\", \"Application Support\", \"Google\", \"Chrome\"),\n linux: join(home, \".config\", \"google-chrome\"),\n },\n chromium: {\n windows: join(home, \"AppData\", \"Local\", \"Chromium\", \"User Data\"),\n macos: join(home, \"Library\", \"Application Support\", \"Chromium\"),\n linux: join(home, \".config\", \"chromium\"),\n },\n brave: {\n windows: join(\n home,\n \"AppData\",\n \"Local\",\n \"BraveSoftware\",\n \"Brave-Browser\",\n \"User Data\",\n ),\n macos: join(\n home,\n \"Library\",\n \"Application Support\",\n \"BraveSoftware\",\n \"Brave-Browser\",\n ),\n linux: join(home, \".config\", \"BraveSoftware\", \"Brave-Browser\"),\n },\n edge: {\n windows: join(home, \"AppData\", \"Local\", \"Microsoft\", \"Edge\", \"User Data\"),\n macos: join(home, \"Library\", \"Application Support\", \"Microsoft Edge\"),\n linux: join(home, \".config\", \"microsoft-edge\"),\n },\n arc: {\n windows: join(home, \"AppData\", \"Local\", \"Arc\", \"User Data\"),\n macos: join(home, \"Library\", \"Application Support\", \"Arc\", \"User Data\"),\n linux: join(home, \".config\", \"arc\"),\n },\n opera: {\n windows: join(\n home,\n \"AppData\",\n \"Roaming\",\n \"Opera Software\",\n \"Opera Stable\",\n ),\n macos: join(\n home,\n \"Library\",\n \"Application Support\",\n \"com.operasoftware.Opera\",\n ),\n linux: join(home, \".config\", \"opera\"),\n },\n \"opera-gx\": {\n windows: join(\n home,\n \"AppData\",\n \"Roaming\",\n \"Opera Software\",\n \"Opera GX Stable\",\n ),\n macos: join(\n home,\n \"Library\",\n \"Application Support\",\n \"com.operasoftware.OperaGX\",\n ),\n linux: join(home, \".config\", \"opera-gx\"),\n },\n vivaldi: {\n windows: join(home, \"AppData\", \"Local\", \"Vivaldi\", \"User Data\"),\n macos: join(home, \"Library\", \"Application Support\", \"Vivaldi\"),\n linux: join(home, \".config\", \"vivaldi\"),\n },\n whale: {\n windows: join(\n home,\n \"AppData\",\n \"Local\",\n \"Naver\",\n \"Naver Whale\",\n \"User Data\",\n ),\n macos: join(home, \"Library\", \"Application Support\", \"Naver\", \"Whale\"),\n linux: join(home, \".config\", \"naver-whale\"),\n },\n };\n\n const paths = browserPaths[browser];\n\n switch (currentPlatform) {\n case \"win32\":\n return paths.windows;\n case \"darwin\":\n return paths.macos;\n case \"linux\":\n return paths.linux;\n default:\n throw new Error(`Platform ${currentPlatform} is not supported`);\n }\n}\n\n/**\n * Get all Chromium browser paths for the current platform\n * @returns Record mapping browser names to their configuration directory paths\n */\nexport function getAllChromiumBrowserPaths(): Record<ChromiumBrowser, string> {\n const result: Partial<Record<ChromiumBrowser, string>> = {};\n\n for (const browser of CHROMIUM_BASED_BROWSERS) {\n try {\n result[browser] = getChromiumBrowserPath(browser);\n } catch {\n // Skip browsers that fail (e.g., unsupported platform)\n }\n }\n\n return result as Record<ChromiumBrowser, string>;\n}\n","import fg from \"fast-glob\";\n\nimport {\n type ChromiumBrowser,\n getChromiumBrowserPath,\n} from \"../chrome/ChromiumBrowsers\";\n\nimport { BaseChromiumCookieQueryStrategy } from \"./BaseChromiumCookieQueryStrategy\";\n\n/**\n * Strategy for querying cookies from Chromium-based browsers (Chrome, Brave, Edge, etc.)\n * This class extends the BaseChromiumCookieQueryStrategy with browser-specific path discovery.\n * @example\n * ```typescript\n * const strategy = new ChromiumCookieQueryStrategy('brave');\n * const cookies = await strategy.queryCookies('session', 'example.com');\n * ```\n */\nexport class ChromiumCookieQueryStrategy extends BaseChromiumCookieQueryStrategy {\n private readonly browser: ChromiumBrowser;\n\n /**\n * Creates a new instance of ChromiumCookieQueryStrategy\n * @param browser - The Chromium-based browser to query (chrome, brave, edge, etc.)\n */\n public constructor(browser: ChromiumBrowser = \"chrome\") {\n const browserName = browser.charAt(0).toUpperCase() + browser.slice(1);\n super(`${browserName}CookieQueryStrategy`, browserName, browser);\n this.browser = browser;\n }\n\n /**\n * Get browser-specific cookie file paths\n * @param store - Optional specific store path\n * @returns Array of cookie file paths\n */\n protected getCookieFilePaths(store?: string): string[] {\n if (store !== undefined && store !== \"\") {\n return [store];\n }\n\n try {\n const browserPath = getChromiumBrowserPath(this.browser);\n const files = fg.sync(\"./**/Cookies\", {\n cwd: browserPath,\n absolute: true,\n });\n\n this.logger.debug(\n `Found ${files.length} cookie files for ${this.browser}`,\n );\n\n return files;\n } catch (error) {\n this.logger.warn(`Failed to find ${this.browser} cookie files`, {\n error: this.getErrorMessage(error),\n });\n return [];\n }\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport fg from \"fast-glob\";\n\nimport type { createTaggedLogger } from \"@utils/logHelpers\";\nimport { getPlatform } from \"@utils/platformUtils\";\nimport { isFirefoxRunning } from \"@utils/ProcessDetector\";\n\nimport type { ExportedCookie } from \"../../../types/schemas\";\nimport { BaseCookieQueryStrategy } from \"../BaseCookieQueryStrategy\";\nimport { BrowserLockHandler } from \"../BrowserLockHandler\";\nimport { getGlobalConnectionManager } from \"../sql/DatabaseConnectionManager\";\nimport { getGlobalQueryMonitor } from \"../sql/QueryMonitor\";\n\ninterface FirefoxCookieRow {\n name: string;\n value: string;\n domain: string;\n expiry: number;\n}\n\n/**\n * Find all Firefox cookie database files\n * @param logger - Logger instance for logging messages\n * @returns An array of file paths to Firefox cookie databases\n */\nfunction findFirefoxCookieFiles(\n logger: ReturnType<typeof createTaggedLogger>,\n): string[] {\n const home = homedir();\n if (!home) {\n logger.warn(\"Failed to get home directory\");\n return [];\n }\n\n // Fast path: Check if Firefox profile directories exist before attempting glob\n const platform = getPlatform();\n const profileDirs: string[] = [];\n const patterns: string[] = [];\n\n switch (platform) {\n case \"darwin\":\n profileDirs.push(join(home, \"Library/Application Support/Firefox\"));\n patterns.push(\n join(\n home,\n \"Library/Application Support/Firefox/Profiles/*/cookies.sqlite\",\n ),\n );\n break;\n case \"win32\": {\n // Regular Firefox\n profileDirs.push(join(home, \"AppData\", \"Roaming\", \"Mozilla\", \"Firefox\"));\n patterns.push(\n join(\n home,\n \"AppData\",\n \"Roaming\",\n \"Mozilla\",\n \"Firefox\",\n \"Profiles\",\n \"*\",\n \"cookies.sqlite\",\n ),\n );\n // Firefox Developer Edition\n const devEditionPath = join(\n home,\n \"AppData\",\n \"Roaming\",\n \"Mozilla\",\n \"Firefox Developer Edition\",\n );\n if (existsSync(devEditionPath)) {\n profileDirs.push(devEditionPath);\n patterns.push(join(devEditionPath, \"Profiles\", \"*\", \"cookies.sqlite\"));\n }\n // Firefox ESR (Extended Support Release)\n const esrPath = join(\n home,\n \"AppData\",\n \"Roaming\",\n \"Mozilla\",\n \"Firefox ESR\",\n );\n if (existsSync(esrPath)) {\n profileDirs.push(esrPath);\n patterns.push(join(esrPath, \"Profiles\", \"*\", \"cookies.sqlite\"));\n }\n // Also check Local AppData for some installations\n const localFirefoxPath = join(\n home,\n \"AppData\",\n \"Local\",\n \"Mozilla\",\n \"Firefox\",\n );\n if (existsSync(localFirefoxPath)) {\n profileDirs.push(localFirefoxPath);\n patterns.push(\n join(localFirefoxPath, \"Profiles\", \"*\", \"cookies.sqlite\"),\n );\n }\n break;\n }\n case \"linux\":\n profileDirs.push(join(home, \".mozilla/firefox\"));\n patterns.push(join(home, \".mozilla/firefox/*/cookies.sqlite\"));\n break;\n default:\n logger.debug(\"Unsupported platform for Firefox cookie extraction\", {\n platform,\n });\n return [];\n }\n\n const existingProfileDirs = profileDirs.filter((dir) => existsSync(dir));\n\n if (existingProfileDirs.length === 0) {\n logger.debug(\n \"No Firefox profile directories found - Firefox may not be installed\",\n {\n checked: profileDirs,\n platform,\n },\n );\n return [];\n }\n\n const files: string[] = [];\n for (const pattern of patterns) {\n const matches = fg.sync(pattern);\n files.push(...matches);\n }\n\n logger.debug(\"Found Firefox cookie files\", { files });\n return files;\n}\n\n/**\n * Strategy for querying cookies from Firefox browser.\n * This class extends the BaseCookieQueryStrategy and implements Firefox-specific\n * cookie extraction logic. It searches for cookie databases in standard Firefox\n * profile locations and extracts cookies matching the specified name and domain.\n * @example\n * ```typescript\n * import { FirefoxCookieQueryStrategy } from './FirefoxCookieQueryStrategy';\n *\n * const strategy = new FirefoxCookieQueryStrategy();\n * const cookies = await strategy.queryCookies('sessionid', 'example.com');\n * console.log(cookies);\n * ```\n */\nexport class FirefoxCookieQueryStrategy extends BaseCookieQueryStrategy {\n private readonly lockHandler: BrowserLockHandler;\n\n /**\n * Creates a new instance of FirefoxCookieQueryStrategy\n */\n public constructor() {\n super(\"FirefoxCookieQueryStrategy\", \"Firefox\");\n this.lockHandler = new BrowserLockHandler(this.logger, \"Firefox\");\n }\n\n /**\n * Creates the query parameters for cookie extraction using the new query builder\n * @param name - The cookie name to search for\n * @param domain - The domain pattern to match cookies against\n * @param file - The database file path for metadata\n * @returns Query configuration object\n * @private\n */\n private async createCookieQueryConfig(\n name: string,\n domain: string,\n file: string,\n ): Promise<{\n file: string;\n sql: string;\n params: unknown[];\n rowTransform: (row: FirefoxCookieRow) => ExportedCookie;\n }> {\n // Import the query builder dynamically to avoid circular dependencies\n const { CookieQueryBuilder } = await import(\"../sql/CookieQueryBuilder\");\n const queryBuilder = new CookieQueryBuilder(\"firefox\");\n\n const queryConfig = queryBuilder.buildSelectQuery({\n name,\n domain,\n browser: \"firefox\",\n });\n\n return {\n file,\n sql: queryConfig.sql,\n params: queryConfig.params,\n rowTransform: (row: FirefoxCookieRow): ExportedCookie => ({\n name: row.name,\n value: row.value,\n domain: row.domain,\n expiry: row.expiry > 0 ? new Date(row.expiry * 1000) : \"Infinity\",\n meta: {\n file,\n browser: \"Firefox\",\n decrypted: false,\n },\n }),\n };\n }\n\n /**\n * Handles errors that occur during cookie extraction\n * @param error - The error that occurred\n * @param file - The database file being queried\n * @param force - Whether operations are being forced\n * @param name - The cookie name being searched\n * @param domain - The domain being searched\n * @returns Promise resolving to retry configuration\n * @private\n */\n private async handleCookieExtractionError(\n error: unknown,\n file: string,\n force: boolean | undefined,\n name: string,\n domain: string,\n ): Promise<{ retryAfterClose: boolean; shouldRelaunch: boolean }> {\n const processes = await isFirefoxRunning();\n const lockResult = await this.lockHandler.handleBrowserConflict(\n error,\n file,\n processes,\n force !== true,\n );\n\n if (lockResult.resolved) {\n return {\n retryAfterClose: true,\n shouldRelaunch: lockResult.shouldRelaunch,\n };\n }\n\n this.logExtractError(error, file, name, domain);\n return { retryAfterClose: false, shouldRelaunch: false };\n }\n\n /**\n * Logs cookie extraction errors in a consistent format\n * @param error - The error to log\n * @param file - The file that failed\n * @param name - The cookie name\n * @param domain - The domain\n * @private\n */\n private logExtractError(\n error: unknown,\n file: string,\n name: string,\n domain: string,\n ): void {\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.logger.debug(`Error reading Firefox cookie file ${file}`, {\n error: errorMessage,\n file,\n name,\n domain,\n });\n }\n\n /**\n * Performs a retry attempt after browser closure\n * @param queryConfig - The cookie query configuration\n * @param shouldRelaunch - Whether to relaunch the browser after success\n * @returns Promise resolving to extracted cookies\n * @private\n */\n private async performRetryAfterClose(\n queryConfig: Awaited<ReturnType<typeof this.createCookieQueryConfig>>,\n shouldRelaunch: boolean,\n ): Promise<ExportedCookie[]> {\n this.logger.info(\n \"Retrying Firefox cookie extraction after browser close...\",\n );\n\n try {\n const cookies = await this.executeQueryWithNewUtilities(queryConfig);\n this.logger.success(\n \"Successfully extracted cookies after closing Firefox\",\n );\n\n if (shouldRelaunch) {\n await this.lockHandler.relaunchBrowser();\n }\n\n return cookies;\n } catch (retryError) {\n this.logger.error(\n \"Failed to extract cookies even after closing Firefox\",\n {\n error:\n retryError instanceof Error\n ? retryError.message\n : String(retryError),\n file: queryConfig.file,\n },\n );\n\n if (shouldRelaunch) {\n await this.lockHandler.relaunchBrowser();\n }\n\n return [];\n }\n }\n\n /**\n * Processes a single Firefox cookie file for the given parameters\n * @param file - The cookie file to process\n * @param name - The cookie name to search for\n * @param domain - The domain pattern to match\n * @param force - Whether to force operations despite warnings\n * @returns Promise resolving to extracted cookies from this file\n * @private\n */\n private async processCookieFile(\n file: string,\n name: string,\n domain: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n const queryConfig = await this.createCookieQueryConfig(name, domain, file);\n\n try {\n return await this.executeQueryWithNewUtilities(queryConfig);\n } catch (error) {\n const retryConfig = await this.handleCookieExtractionError(\n error,\n file,\n force,\n name,\n domain,\n );\n\n if (retryConfig.retryAfterClose) {\n return this.performRetryAfterClose(\n queryConfig,\n retryConfig.shouldRelaunch,\n );\n }\n\n return [];\n }\n }\n\n /**\n * Execute query using the new SQL utilities\n * @param queryConfig - Query configuration from createCookieQueryConfig\n * @param queryConfig.file\n * @param queryConfig.sql\n * @param queryConfig.params\n * @param queryConfig.rowTransform\n * @returns Promise resolving to exported cookies\n * @private\n */\n private async executeQueryWithNewUtilities(queryConfig: {\n file: string;\n sql: string;\n params: unknown[];\n rowTransform: (row: FirefoxCookieRow) => ExportedCookie;\n }): Promise<ExportedCookie[]> {\n const connectionManager = getGlobalConnectionManager({\n retryAttempts: 1, // Fail fast for Firefox - we have lock handling\n retryDelay: 0, // No delay - let lock handler deal with it\n queryTimeout: 100, // Very short timeout for Firefox to fail fast on locks\n enableMonitoring: true,\n });\n\n const monitor = getGlobalQueryMonitor();\n\n return connectionManager.executeQuery(\n queryConfig.file,\n (db) => {\n // Use the query monitor for tracking\n const rows = monitor.executeQuery<FirefoxCookieRow>(\n db,\n queryConfig.sql,\n queryConfig.params,\n queryConfig.file,\n );\n\n // Apply transformation\n return rows.map(queryConfig.rowTransform);\n },\n queryConfig.sql, // Pass SQL for monitoring\n );\n }\n\n /**\n * Executes the Firefox-specific query logic\n * @param name - The name pattern to match cookies against\n * @param domain - The domain pattern to match cookies against\n * @param store - Optional path to a specific cookie store file\n * @param force - Whether to force operations despite warnings (e.g., locked databases)\n * @returns A promise that resolves to an array of exported cookies\n * @protected\n */\n protected async executeQuery(\n name: string,\n domain: string,\n store?: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n const files = store ?? findFirefoxCookieFiles(this.logger);\n const fileList = Array.isArray(files) ? files : [files];\n\n // Fast path: If no Firefox cookie files found (Firefox not installed),\n // return early to avoid unnecessary database queries and process detection\n if (fileList.length === 0) {\n this.logger.debug(\"No Firefox cookie files to query\");\n return [];\n }\n\n const results: ExportedCookie[] = [];\n\n for (const file of fileList) {\n const cookies = await this.processCookieFile(file, name, domain, force);\n results.push(...cookies);\n }\n\n return results;\n }\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { errorMessageContains, formatErrorForLogging } from \"@utils/errorUtils\";\nimport { isMacOS } from \"@utils/platformUtils\";\nimport { isSafariRunning } from \"@utils/ProcessDetector\";\nimport {\n checkFilePermission,\n handleSafariPermissionError,\n} from \"@utils/SystemPermissions\";\n\nimport type { ExportedCookie } from \"../../../types/schemas\";\nimport { BaseCookieQueryStrategy } from \"../BaseCookieQueryStrategy\";\nimport { BrowserLockHandler } from \"../BrowserLockHandler\";\n\nimport { decodeBinaryCookies } from \"./decodeBinaryCookies\";\n\n/**\n * Strategy for querying cookies from Safari browser.\n * This class extends the BaseCookieQueryStrategy and implements Safari-specific\n * cookie extraction logic.\n */\nexport class SafariCookieQueryStrategy extends BaseCookieQueryStrategy {\n private readonly lockHandler: BrowserLockHandler;\n\n /**\n * Creates a new instance of SafariCookieQueryStrategy\n */\n public constructor() {\n super(\"SafariCookieQueryStrategy\", \"Safari\");\n this.lockHandler = new BrowserLockHandler(this.logger, \"Safari\");\n }\n\n /**\n * Gets the path to Safari's cookie database\n * @param home - The user's home directory\n * @returns Path to the cookie database\n */\n private getCookieDbPath(home: string): string {\n return join(\n home,\n \"Library\",\n \"Containers\",\n \"com.apple.Safari\",\n \"Data\",\n \"Library\",\n \"Cookies\",\n \"Cookies.binarycookies\",\n );\n }\n\n /**\n * Formats the domain by removing leading dot if present\n * @param domain - Domain to format\n * @returns Formatted domain or empty string if domain is invalid\n */\n private formatDomain(domain: string | undefined | null): string {\n if (domain === null || domain === undefined || typeof domain !== \"string\") {\n return \"\";\n }\n return domain.startsWith(\".\") ? domain.slice(1) : domain;\n }\n\n /**\n * Formats the expiry date\n * @param expiry - Expiry timestamp (Unix epoch seconds)\n * @returns Formatted expiry date or \"Infinity\"\n */\n private formatExpiry(\n expiry: number | undefined | null,\n ): Date | \"Infinity\" | undefined {\n // Handle undefined or null - return undefined instead of NaN date\n if (expiry === undefined || expiry === null) {\n return undefined;\n }\n\n if (typeof expiry !== \"number\" || Number.isNaN(expiry) || expiry <= 0) {\n return \"Infinity\";\n }\n\n // Validate timestamp is reasonable (1970-2100 range in seconds)\n const minTimestamp = 0; // 1970-01-01\n const maxTimestamp = 4102444800; // 2100-01-01\n\n if (expiry < minTimestamp || expiry > maxTimestamp) {\n this.logger.warn(\"Invalid expiry timestamp, treating as session cookie\", {\n expiry,\n });\n return \"Infinity\";\n }\n\n return new Date(expiry * 1000);\n }\n\n /**\n * Checks if a flag bit is set\n * @param flags - The flags value\n * @param bit - The bit to check\n * @returns True if the bit is set, false otherwise\n */\n private isFlagSet(flags: number | undefined | null, bit: number): boolean {\n if (typeof flags !== \"number\" || Number.isNaN(flags) || flags <= 0) {\n return false;\n }\n return (flags & bit) === bit;\n }\n\n /**\n * Formats the creation timestamp\n * @param creation - Creation timestamp (Unix epoch seconds)\n * @returns Formatted creation timestamp in milliseconds or undefined\n */\n private formatCreation(\n creation: number | undefined | null,\n ): number | undefined {\n if (\n typeof creation !== \"number\" ||\n Number.isNaN(creation) ||\n creation <= 0\n ) {\n return undefined;\n }\n\n // Validate timestamp is reasonable (1970-2100 range in seconds)\n const minTimestamp = 0; // 1970-01-01\n const maxTimestamp = 4102444800; // 2100-01-01\n\n if (creation < minTimestamp || creation > maxTimestamp) {\n this.logger.warn(\"Invalid creation timestamp, ignoring\", { creation });\n return undefined;\n }\n\n return creation * 1000;\n }\n\n /**\n * Processes a cookie value to ensure it's a string\n * @param value - The cookie value to process\n * @returns The processed value as a string\n */\n private processValue(value: unknown): string {\n if (value === null) {\n return \"null\";\n }\n\n if (value === undefined) {\n return \"undefined\";\n }\n\n if (Buffer.isBuffer(value)) {\n return value.toString();\n }\n\n if (typeof value === \"object\") {\n try {\n return JSON.stringify(value);\n } catch {\n // If JSON.stringify fails (e.g., circular reference), return a placeholder\n return \"[object]\";\n }\n }\n\n // Handle primitives (string, number, boolean, etc.)\n if (typeof value === \"string\") {\n return value;\n }\n\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n\n // Fallback for any other type (should not happen with proper typing)\n return \"[unknown value]\";\n }\n\n /**\n * Decodes cookies from Safari's binary cookie file\n * @param cookieDbPath - Path to the cookie database\n * @param name - Name of the cookie to find\n * @param domain - Domain to filter cookies by\n * @param force - Whether to skip interactive prompts\n * @returns Array of exported cookies\n */\n private async decodeCookies(\n cookieDbPath: string,\n name: string,\n domain: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n try {\n // Check permissions first\n const permissionResult = await this.checkAndHandlePermissions(\n cookieDbPath,\n force,\n );\n if (!permissionResult) {\n return [];\n }\n\n // Decode cookies and process them\n const cookies = decodeBinaryCookies(cookieDbPath);\n return this.processCookies(cookies, name, domain, cookieDbPath);\n } catch (error: unknown) {\n return this.handleDecodingError(error, cookieDbPath, name, domain, force);\n }\n }\n\n /**\n * Check file permissions and handle permission errors\n * @param cookieDbPath - Path to the cookie database\n * @param force - Whether to skip interactive prompts\n * @returns True if permissions are granted, false otherwise\n */\n private async checkAndHandlePermissions(\n cookieDbPath: string,\n force?: boolean,\n ): Promise<boolean> {\n const hasPermission = await checkFilePermission(cookieDbPath);\n if (hasPermission) {\n return true;\n }\n\n this.logger.warn(\"Cannot access Safari cookies due to macOS permissions\", {\n file: cookieDbPath,\n suggestion: \"Terminal application needs Full Disk Access permission\",\n });\n\n // Try to handle the permission error interactively\n const permissionGranted = await handleSafariPermissionError(\n new Error(\"EPERM: operation not permitted\"),\n {\n appName: process.env.TERM_PROGRAM ?? \"Terminal\",\n browserName: \"Safari\",\n interactive: force !== true,\n },\n );\n\n if (!permissionGranted) {\n return false;\n }\n\n // Check again after permission might have been granted\n const stillNoPermission = !(await checkFilePermission(cookieDbPath));\n if (stillNoPermission) {\n this.logger.error(\n \"Still cannot access Safari cookies after permission attempt\",\n {\n file: cookieDbPath,\n advice:\n \"Please restart your terminal application after granting Full Disk Access\",\n },\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * Process and filter cookies based on name and domain criteria\n * @param cookies - Raw cookies from binary file\n * @param name - Name filter\n * @param domain - Domain filter\n * @param cookieDbPath - Path to cookie database for metadata\n * @returns Processed and filtered cookies\n */\n private processCookies(\n cookies: unknown[],\n name: string,\n domain: string,\n cookieDbPath: string,\n ): ExportedCookie[] {\n return cookies\n .filter((cookie) => this.matchesCriteria(cookie, name, domain))\n .map((cookie) => this.mapToExportedCookie(cookie, cookieDbPath));\n }\n\n /**\n * Check if cookie matches the search criteria\n * @param cookie - Raw cookie object\n * @param name - Name filter\n * @param domain - Domain filter\n * @returns True if cookie matches criteria\n */\n private matchesCriteria(\n cookie: unknown,\n name: string,\n domain: string,\n ): boolean {\n // Type guard for cookie object\n if (!this.isCookieObject(cookie)) {\n return false;\n }\n\n const formattedDomain = this.formatDomain(cookie.domain);\n\n // Skip cookies with invalid domains\n if (formattedDomain === \"\") {\n return false;\n }\n\n const nameMatches = name === \"%\" || cookie.name === name;\n const domainMatches = domain === \"%\" || formattedDomain.includes(domain);\n\n return nameMatches && domainMatches;\n }\n\n /**\n * Type guard to check if an object is a valid cookie object\n * @param cookie - Object to check\n * @returns True if object has expected cookie properties\n */\n private isCookieObject(cookie: unknown): cookie is {\n domain?: string;\n name: string;\n value: unknown;\n expiry?: number;\n creation?: number;\n flags?: number;\n path?: string;\n version?: number;\n comment?: string;\n commentURL?: string;\n port?: number;\n } {\n return (\n typeof cookie === \"object\" &&\n cookie !== null &&\n \"name\" in cookie &&\n typeof (cookie as { name: unknown }).name === \"string\"\n );\n }\n\n /**\n * Map raw cookie to ExportedCookie format\n * @param cookie - Raw cookie object\n * @param cookieDbPath - Path to cookie database for metadata\n * @returns Formatted ExportedCookie\n */\n private mapToExportedCookie(\n cookie: unknown,\n cookieDbPath: string,\n ): ExportedCookie {\n // We know it's a cookie object due to prior filtering\n const cookieObj = cookie as {\n domain?: string | null;\n name: string;\n value: unknown;\n expiry?: number | null;\n creation?: number | null;\n flags?: number | null;\n path?: string | null;\n version?: number | null;\n comment?: string | null;\n commentURL?: string | null;\n port?: number | null;\n };\n\n return {\n domain: this.formatDomain(cookieObj.domain),\n name: cookieObj.name,\n value: this.processValue(cookieObj.value),\n expiry: this.formatExpiry(cookieObj.expiry),\n meta: {\n file: cookieDbPath,\n browser: \"Safari\" as const,\n decrypted: false,\n secure: this.isFlagSet(cookieObj.flags, 0x1),\n httpOnly: this.isFlagSet(cookieObj.flags, 0x4),\n path: cookieObj.path ?? undefined,\n version:\n cookieObj.version === undefined ? undefined : cookieObj.version,\n comment: cookieObj.comment ?? undefined,\n commentURL: cookieObj.commentURL ?? undefined,\n port: cookieObj.port === undefined ? undefined : cookieObj.port,\n creation: this.formatCreation(cookieObj.creation),\n },\n };\n }\n\n /**\n * Handle errors that occur during cookie decoding\n * @param error - The error that occurred\n * @param cookieDbPath - Path to the cookie database\n * @param name - Name filter used\n * @param domain - Domain filter used\n * @param force - Whether interactive prompts were skipped\n * @returns Empty array as fallback\n */\n private async handleDecodingError(\n error: unknown,\n cookieDbPath: string,\n name: string,\n domain: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n const isPermissionError =\n errorMessageContains(error, \"EPERM\") ||\n errorMessageContains(error, \"operation not permitted\") ||\n errorMessageContains(error, \"Permission denied\");\n\n if (isPermissionError) {\n await this.handlePermissionError(\n error,\n cookieDbPath,\n name,\n domain,\n force,\n );\n } else {\n this.logDecodingError(error, cookieDbPath, name, domain);\n }\n\n return [];\n }\n\n /**\n * Handle permission-related errors\n * @param error - The error that occurred\n * @param cookieDbPath - Path to the cookie database\n * @param name - Name filter used\n * @param domain - Domain filter used\n * @param force - Whether interactive prompts were skipped\n */\n private async handlePermissionError(\n error: unknown,\n cookieDbPath: string,\n name: string,\n domain: string,\n force?: boolean,\n ): Promise<void> {\n const handled = await handleSafariPermissionError(error as Error, {\n appName: process.env.TERM_PROGRAM ?? \"Terminal\",\n browserName: \"Safari\",\n interactive: force !== true,\n });\n\n if (handled) {\n this.logger.info(\n \"Permission flow completed. Please run the command again after granting access.\",\n );\n } else {\n this.logger.warn(\n `Permission denied accessing Safari cookies at ${cookieDbPath}`,\n formatErrorForLogging(error, {\n file: cookieDbPath,\n name,\n domain,\n advice:\n \"Grant Full Disk Access to your terminal in System Settings > Privacy & Security\",\n }),\n );\n }\n }\n\n /**\n * Log non-permission errors that occur during decoding\n * @param error - The error that occurred\n * @param cookieDbPath - Path to the cookie database\n * @param name - Name filter used\n * @param domain - Domain filter used\n */\n private logDecodingError(\n error: unknown,\n cookieDbPath: string,\n name: string,\n domain: string,\n ): void {\n this.logger.error(\n `Error decoding ${cookieDbPath}`,\n formatErrorForLogging(error, {\n file: cookieDbPath,\n name,\n domain,\n }),\n );\n }\n\n /**\n * Executes the Safari-specific query logic\n * @param name - Name of the cookie to find\n * @param domain - Domain to filter cookies by\n * @param store - Optional store path\n * @param force - Whether to force operations despite warnings (e.g., locked databases)\n * @returns Array of matching cookies, or empty array if none found\n * @protected\n */\n protected async executeQuery(\n name: string,\n domain: string,\n store?: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n // Fast path: Safari only exists on macOS\n if (!isMacOS()) {\n this.logger.debug(\"Safari strategy skipped on non-macOS platform\");\n return [];\n }\n\n try {\n this.logger.info(\"Querying cookies\", { name, domain, store });\n\n // Validate home directory\n const home = homedir();\n if (!this.isValidHomeDirectory(home)) {\n return [];\n }\n\n const cookieDbPath = store ?? this.getCookieDbPath(home);\n const normalizedName = name || \"%\";\n const normalizedDomain = domain || \"%\";\n\n // First attempt to decode cookies\n const firstAttemptResult = await this.attemptDecodeWithLockHandling(\n cookieDbPath,\n normalizedName,\n normalizedDomain,\n force,\n );\n\n if (firstAttemptResult.success) {\n return firstAttemptResult.cookies;\n }\n\n // Handle retry scenario if browser was closed\n if (firstAttemptResult.shouldRetry) {\n return this.retryAfterBrowserClose(\n cookieDbPath,\n normalizedName,\n normalizedDomain,\n force,\n firstAttemptResult.shouldRelaunch,\n );\n }\n\n return [];\n } catch (error: unknown) {\n this.logQueryError(error, name, domain);\n return [];\n }\n }\n\n /**\n * Validate home directory\n * @param home - Home directory path\n * @returns True if valid, false otherwise\n */\n private isValidHomeDirectory(home: string): boolean {\n if (typeof home !== \"string\" || home.length === 0) {\n this.logger.error(\"Failed to get home directory\");\n return false;\n }\n return true;\n }\n\n /**\n * Attempt to decode cookies with lock conflict handling\n * @param cookieDbPath - Path to cookie database\n * @param name - Normalized cookie name filter\n * @param domain - Normalized domain filter\n * @param force - Whether to force operations\n * @returns Result object with success status and data\n */\n private async attemptDecodeWithLockHandling(\n cookieDbPath: string,\n name: string,\n domain: string,\n force?: boolean,\n ): Promise<{\n success: boolean;\n cookies: ExportedCookie[];\n shouldRetry: boolean;\n shouldRelaunch: boolean;\n }> {\n try {\n const cookies = await this.decodeCookies(\n cookieDbPath,\n name,\n domain,\n force,\n );\n return {\n success: true,\n cookies,\n shouldRetry: false,\n shouldRelaunch: false,\n };\n } catch (error: unknown) {\n return this.handleLockConflict(error, cookieDbPath, force);\n }\n }\n\n /**\n * Handle browser lock conflicts\n * @param error - The error that occurred\n * @param cookieDbPath - Path to cookie database\n * @param force - Whether to force operations\n * @returns Result indicating what action to take next\n */\n private async handleLockConflict(\n error: unknown,\n cookieDbPath: string,\n force?: boolean,\n ): Promise<{\n success: boolean;\n cookies: ExportedCookie[];\n shouldRetry: boolean;\n shouldRelaunch: boolean;\n }> {\n if (!this.isLockError(error)) {\n throw error; // Re-throw non-lock errors\n }\n\n const processes = await isSafariRunning();\n const lockResult = await this.lockHandler.handleBrowserConflict(\n error,\n cookieDbPath,\n processes,\n force !== true,\n );\n\n if (lockResult.resolved) {\n return {\n success: false,\n cookies: [],\n shouldRetry: true,\n shouldRelaunch: lockResult.shouldRelaunch,\n };\n }\n\n this.logger.warn(\n \"Safari cookie file locked\",\n formatErrorForLogging(error, {\n file: cookieDbPath,\n advice:\n \"Safari may be accessing the cookie file. Try closing Safari and running again.\",\n }),\n );\n\n return {\n success: false,\n cookies: [],\n shouldRetry: false,\n shouldRelaunch: false,\n };\n }\n\n /**\n * Check if error indicates a lock conflict\n * @param error - Error to check\n * @returns True if this is a lock-related error\n */\n private isLockError(error: unknown): boolean {\n return (\n errorMessageContains(error, \"EPERM\") ||\n errorMessageContains(error, \"operation not permitted\") ||\n errorMessageContains(error, \"Permission denied\") ||\n errorMessageContains(error, \"EBUSY\")\n );\n }\n\n /**\n * Retry cookie extraction after browser was closed\n * @param cookieDbPath - Path to cookie database\n * @param name - Cookie name filter\n * @param domain - Domain filter\n * @param force - Whether to force operations\n * @param shouldRelaunch - Whether browser should be relaunched\n * @returns Cookies or empty array\n */\n private async retryAfterBrowserClose(\n cookieDbPath: string,\n name: string,\n domain: string,\n force?: boolean,\n shouldRelaunch?: boolean,\n ): Promise<ExportedCookie[]> {\n try {\n this.logger.info(\n \"Retrying Safari cookie extraction after browser close...\",\n );\n\n const cookies = await this.decodeCookies(\n cookieDbPath,\n name,\n domain,\n force,\n );\n\n this.logger.success(\n \"Successfully extracted cookies after closing Safari\",\n );\n\n if (shouldRelaunch === true) {\n await this.lockHandler.relaunchBrowser();\n }\n\n return cookies;\n } catch (retryError: unknown) {\n return this.handleRetryFailure(retryError, cookieDbPath, shouldRelaunch);\n }\n }\n\n /**\n * Handle failure during retry attempt\n * @param retryError - Error that occurred during retry\n * @param cookieDbPath - Path to cookie database\n * @param shouldRelaunch - Whether browser should be relaunched\n * @returns Empty array\n */\n private async handleRetryFailure(\n retryError: unknown,\n cookieDbPath: string,\n shouldRelaunch?: boolean,\n ): Promise<ExportedCookie[]> {\n this.logger.error(\n \"Failed to extract cookies even after closing Safari\",\n formatErrorForLogging(retryError, { file: cookieDbPath }),\n );\n\n // Still try to relaunch Safari if needed\n if (shouldRelaunch === true) {\n await this.lockHandler.relaunchBrowser();\n }\n\n return [];\n }\n\n /**\n * Log query errors\n * @param error - The error that occurred\n * @param name - Cookie name filter\n * @param domain - Domain filter\n */\n private logQueryError(error: unknown, name: string, domain: string): void {\n this.logger.error(\n \"Failed to query cookies\",\n formatErrorForLogging(error, { name, domain }),\n );\n }\n}\n","import { exec } from \"node:child_process\";\nimport readline from \"node:readline\";\nimport { promisify } from \"node:util\";\n\nimport { errorMessageContains, getErrorMessage } from \"./errorUtils\";\nimport { createTaggedLogger } from \"./logHelpers\";\nimport { isMacOS } from \"./platformUtils\";\n\nconst execAsync = promisify(exec);\nconst logger = createTaggedLogger(\"SystemPermissions\");\n\n/**\n *\n */\nexport interface PermissionRequestOptions {\n appName: string;\n browserName: string;\n interactive?: boolean;\n}\n\n/**\n * Open System Settings to the Full Disk Access page on macOS\n */\nasync function openFullDiskAccessSettings(): Promise<void> {\n try {\n // Open System Settings directly to Privacy & Security > Full Disk Access\n await execAsync(\n 'open \"x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles\"',\n );\n logger.info(\n \"Opened System Settings > Privacy & Security > Full Disk Access\",\n );\n } catch (_error) {\n // Fallback to general Privacy & Security\n try {\n await execAsync(\n 'open \"x-apple.systempreferences:com.apple.preference.security?Privacy\"',\n );\n logger.info(\"Opened System Settings > Privacy & Security\");\n } catch (_fallbackError) {\n // Last resort: just open System Settings\n await execAsync(\"open -b com.apple.systempreferences\");\n logger.info(\"Opened System Settings\");\n }\n }\n}\n\n/**\n * Check which terminal application is running\n * @returns The name of the terminal application or a fallback message\n */\nfunction getTerminalApp(): string {\n const termProgram = process.env.TERM_PROGRAM;\n\n if (termProgram === \"iTerm.app\") {\n return \"iTerm\";\n }\n if (termProgram === \"Apple_Terminal\") {\n return \"Terminal\";\n }\n if (termProgram === \"vscode\") {\n return \"Visual Studio Code\";\n }\n return termProgram ?? \"your terminal application\";\n}\n\n/**\n * Prompt user to grant permissions\n * @param appName - The name of the application requesting permissions\n * @param browserName - The name of the browser being accessed\n * @returns A promise that resolves to true if user grants permission\n */\nasync function promptForPermissionGrant(\n appName: string,\n browserName: string,\n): Promise<boolean> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n console.log(`\n⚠️ ${browserName} cookie access is blocked by macOS security.\n\nTo grant access, ${appName} needs permission to read ${browserName} data.\n\nWould you like to:\n1. Open System Settings to grant permission (recommended)\n2. Skip ${browserName} cookies for now\n3. Exit\n\nPlease enter your choice (1/2/3): `);\n\n rl.question(\"\", (answer) => {\n rl.close();\n resolve(answer.trim() === \"1\");\n });\n });\n}\n\n/**\n * Handle Safari permission errors with user guidance\n * @param error - The error encountered when accessing Safari cookies\n * @param options - Configuration options for permission requests\n * @returns A promise that resolves to true if permissions should be granted\n */\nexport async function handleSafariPermissionError(\n error: Error,\n options: PermissionRequestOptions,\n): Promise<boolean> {\n if (!isMacOS()) {\n return false;\n }\n\n const isPermissionError =\n errorMessageContains(error, \"eperm\") ||\n errorMessageContains(error, \"operation not permitted\") ||\n errorMessageContains(error, \"permission denied\") ||\n errorMessageContains(error, \"authorization denied\");\n\n if (!isPermissionError) {\n return false;\n }\n\n const terminalApp = options.appName || getTerminalApp();\n\n logger.warn(`${options.browserName} cookie access denied by macOS`, {\n app: terminalApp,\n error: getErrorMessage(error),\n });\n\n if (options.interactive !== false) {\n const shouldOpenSettings = await promptForPermissionGrant(\n terminalApp,\n options.browserName,\n );\n\n if (shouldOpenSettings) {\n await openFullDiskAccessSettings();\n\n console.log(`\n✅ System Settings opened to Privacy & Security\n\nPlease follow these steps:\n1. Look for \"${terminalApp}\" in the list\n2. If not present, click the \"+\" button and add it\n3. Enable the toggle next to \"${terminalApp}\"\n4. You may need to restart ${terminalApp} after granting permission\n5. Then run this command again\n\nPress Enter when you've completed these steps...`);\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n await new Promise<void>((resolve) => {\n rl.question(\"\", () => {\n rl.close();\n resolve();\n });\n });\n\n return true;\n }\n } else {\n logger.info(\n `To grant ${options.browserName} access, add ${terminalApp} to System Settings > Privacy & Security > Full Disk Access`,\n );\n }\n\n return false;\n}\n\n/**\n * Check if we have permission to access a file\n * @param filePath - The path to the file to check permissions for\n * @returns A promise that resolves to true if file is accessible\n */\nexport async function checkFilePermission(filePath: string): Promise<boolean> {\n try {\n const { exec } = await import(\"node:child_process\");\n const { promisify } = await import(\"node:util\");\n const execAsync = promisify(exec);\n\n // Try to read the file\n await execAsync(`cat \"${filePath}\" > /dev/null 2>&1`);\n return true;\n } catch {\n return false;\n }\n}\n","import { Buffer } from \"node:buffer\";\nimport { readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport type { BinaryCookieRow } from \"../../../types/schemas\";\nimport { createTaggedLogger, logWarn } from \"../../../utils/logHelpers\";\n\nimport { BinaryCodablePage } from \"./BinaryCodablePage\";\nimport type { BinaryCodableContainer } from \"./interfaces/BinaryCodableContainer\";\n\nconst logger = createTaggedLogger(\"BinaryCodableCookies\");\n\n/**\n * Represents a binary cookies file structure used by Safari\n */\nexport class BinaryCodableCookies {\n /**\n *\n */\n public pages: BinaryCodablePage[];\n /**\n *\n */\n public metadata: Record<string, unknown>;\n private static readonly MAGIC = Buffer.from(\"cook\", \"utf8\");\n private static readonly FOOTER = BigInt(\"0x071720050000004b\");\n private static readonly DEFAULT_COOKIE_PATH = join(\n homedir(),\n \"Library/Containers/com.apple.Safari/Data/Library/Cookies/Cookies.binarycookies\",\n );\n\n /**\n * Creates a new BinaryCookies instance from a buffer\n * @param buffer - The raw binary cookie file data\n */\n public constructor(buffer: Buffer) {\n const container: BinaryCodableContainer = { offset: 0, buffer };\n this.pages = [];\n this.metadata = {};\n this.decode(container);\n }\n\n /**\n * Creates a BinaryCookies instance from a file path\n * @param path - Path to the Safari Cookies.binarycookies file\n * @returns A new BinaryCookies instance\n */\n public static fromFile(path: string): BinaryCodableCookies {\n const buffer = readFileSync(path);\n return new BinaryCodableCookies(buffer);\n }\n\n /**\n * Creates a BinaryCookies instance from the default Safari cookies location\n * @returns A new BinaryCookies instance\n */\n public static fromDefaultPath(): BinaryCodableCookies {\n return BinaryCodableCookies.fromFile(\n BinaryCodableCookies.DEFAULT_COOKIE_PATH,\n );\n }\n\n /**\n * Converts the binary cookie data into a validated array of cookie rows\n * @returns Array of validated cookie objects\n */\n public toCookieRows(): BinaryCookieRow[] {\n const cookies: BinaryCookieRow[] = [];\n\n for (const page of this.pages) {\n try {\n const pageCookies = page.toCookieRows();\n if (Array.isArray(pageCookies)) {\n cookies.push(...pageCookies);\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n logWarn(\"BinaryCookies\", \"Error converting page cookies\", {\n error: errorMessage,\n });\n }\n }\n\n return cookies;\n }\n\n private decode(container: BinaryCodableContainer): void {\n try {\n // Check magic value\n const magic = container.buffer.subarray(\n container.offset,\n container.offset + 4,\n );\n container.offset += 4;\n logger.debug(\"Magic bytes:\", magic.toString());\n if (!magic.equals(BinaryCodableCookies.MAGIC)) {\n throw new Error(\"Missing magic value\");\n }\n\n // Read page count\n const pageCount = container.buffer.readUInt32BE(container.offset);\n logger.debug(\"Page count:\", pageCount);\n container.offset += 4;\n\n // Read page sizes\n const pageSizes: number[] = [];\n for (let i = 0; i < pageCount; i++) {\n const pageSize = container.buffer.readUInt32BE(container.offset);\n pageSizes.push(pageSize);\n logger.debug(`Page ${i} size:`, pageSize);\n container.offset += 4;\n }\n\n // Calculate page offsets\n let currentOffset = container.offset;\n logger.debug(\"Starting page data at offset:\", currentOffset);\n for (const pageSize of pageSizes) {\n try {\n logger.debug(\n \"Reading page at offset:\",\n currentOffset,\n \"with size:\",\n pageSize,\n );\n const pageBuffer = container.buffer.subarray(\n currentOffset,\n currentOffset + pageSize,\n );\n const page = new BinaryCodablePage(pageBuffer);\n this.pages.push(page);\n currentOffset += pageSize;\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n logger.warn(\"Error decoding page:\", { error: errorMessage });\n currentOffset += pageSize; // Skip the problematic page\n }\n }\n container.offset = currentOffset;\n\n // Read checksum\n const checksum = container.buffer.readUInt32BE(container.offset);\n logger.debug(\"Checksum:\", checksum.toString(16));\n container.offset += 4;\n\n // Read footer\n const footer = container.buffer.readBigUInt64BE(container.offset);\n logger.debug(\"Footer:\", footer.toString(16));\n container.offset += 8;\n if (footer !== BinaryCodableCookies.FOOTER) {\n logWarn(\"BinaryCookies\", \"Invalid cookie file format: wrong footer\");\n }\n\n // Read metadata plist\n // const plistData = container.buffer.subarray(container.offset);\n // Note: You'll need to implement or use a plist parser library here\n this.metadata = {}; // Placeholder for plist data\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n logWarn(\"BinaryCookies\", \"Error decoding binary cookies file\", {\n error: errorMessage,\n });\n throw error;\n }\n }\n}\n","import type { Buffer } from \"node:buffer\";\n\nimport type { BinaryCookieRow } from \"../../../types/schemas\";\nimport { createTaggedLogger, logWarn } from \"../../../utils/logHelpers\";\n\nimport { BinaryCodableCookie } from \"./BinaryCodableCookie\";\nimport type { BinaryCodableContainer } from \"./interfaces/BinaryCodableContainer\";\n\nconst logger = createTaggedLogger(\"BinaryCodablePage\");\n\n/**\n * Represents a page of cookies within the binary cookies file\n */\nexport class BinaryCodablePage {\n /**\n *\n */\n public cookies: BinaryCodableCookie[];\n private static readonly HEADER = 0x00000100;\n private static readonly FOOTER = 0x00000000;\n\n /**\n * Creates a new Page instance from a buffer\n * @param buffer - The raw binary page data\n */\n public constructor(buffer: Buffer) {\n this.cookies = [];\n const container: BinaryCodableContainer = { offset: 0, buffer };\n this.decode(container);\n }\n\n /**\n * Converts the page's cookies into validated cookie rows\n * @returns Array of validated cookie objects\n */\n public toCookieRows(): BinaryCookieRow[] {\n const cookies: BinaryCookieRow[] = [];\n\n for (const cookie of this.cookies) {\n try {\n const cookieRow = cookie.toCookieRow();\n if (cookieRow !== null) {\n cookies.push(cookieRow);\n }\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n logWarn(\"BinaryCookies\", \"Error converting cookie\", {\n error: errorMessage,\n });\n }\n }\n\n return cookies;\n }\n\n private decode(container: BinaryCodableContainer): void {\n // Read page tag (4 bytes)\n const header = container.buffer.readUInt32BE(container.offset);\n logger.debug(\"Page header:\", header.toString(16));\n container.offset += 4;\n if (header !== BinaryCodablePage.HEADER) {\n throw new Error(\"Invalid page header\");\n }\n\n // Read number of cookies (4 bytes)\n const cookieCount = container.buffer.readUInt32LE(container.offset);\n logger.debug(\"Cookie count:\", cookieCount);\n container.offset += 4;\n\n // Store the page start offset for calculating absolute cookie positions\n const pageStart = container.offset - 8;\n logger.debug(\"Page start offset:\", pageStart);\n\n // Read cookie offsets (4 bytes each)\n const cookieOffsets: number[] = [];\n for (let i = 0; i < cookieCount; i++) {\n const cookieOffset = container.buffer.readUInt32LE(container.offset);\n cookieOffsets.push(cookieOffset);\n logger.debug(`Cookie ${i} offset:`, cookieOffset);\n container.offset += 4;\n }\n\n // Read page end marker (4 bytes)\n const footer = container.buffer.readUInt32BE(container.offset);\n logger.debug(\"Page footer:\", footer.toString(16));\n container.offset += 4;\n if (footer !== BinaryCodablePage.FOOTER) {\n throw new Error(\"Invalid page footer\");\n }\n\n // Read cookies at their offsets\n for (let i = 0; i < cookieCount; i++) {\n try {\n const cookieOffset = cookieOffsets[i]!;\n logger.debug(`Reading cookie ${i} at offset:`, cookieOffset);\n\n // Read cookie size from the cookie header\n const cookieSize = container.buffer.readUInt32LE(cookieOffset);\n logger.debug(`Cookie ${i} size:`, cookieSize);\n if (cookieSize < 48) {\n // Minimum cookie size is 48 bytes (header)\n logger.warn(`Invalid cookie size ${cookieSize} at index ${i}`);\n continue;\n }\n\n // Ensure we don't read past the buffer\n if (cookieOffset + cookieSize > container.buffer.length) {\n logger.warn(\n `Cookie size ${cookieSize} at index ${i} would exceed buffer length ${container.buffer.length}`,\n );\n continue;\n }\n\n const cookieBuffer = container.buffer.subarray(\n cookieOffset,\n cookieOffset + cookieSize,\n );\n const cookie = new BinaryCodableCookie(cookieBuffer);\n this.cookies.push(cookie);\n } catch (error) {\n logger.warn(\"Invalid cookie data\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n }\n}\n","import destr from \"destr\";\nimport { z } from \"zod\";\n\n/**\n * Zod schema for cookie domain validation.\n * Enforces standard cookie domain rules.\n * @example\n * ```typescript\n * // Valid domains\n * CookieDomainSchema.parse(\"example.com\"); // OK\n * CookieDomainSchema.parse(\".example.com\"); // OK - leading dot is valid\n * CookieDomainSchema.parse(\"sub.example.com\"); // OK\n *\n * // Invalid domains\n * CookieDomainSchema.parse(\"\"); // Error: Domain cannot be empty\n * CookieDomainSchema.parse(\"invalid domain\"); // Error: Invalid domain format\n * ```\n */\nexport const CookieDomainSchema = z\n .string()\n .trim()\n .min(1, \"Domain cannot be empty\")\n .refine(\n (domain) =>\n /^\\.?[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(\n domain,\n ),\n \"Invalid domain format\",\n );\n\n/**\n * Zod schema for cookie name validation.\n * Enforces standard cookie name rules according to RFC 6265.\n * @example\n * ```typescript\n * // Valid names\n * CookieNameSchema.parse(\"session\"); // OK\n * CookieNameSchema.parse(\"auth_token\"); // OK\n * CookieNameSchema.parse(\"user-preference\"); // OK\n *\n * // Invalid names\n * CookieNameSchema.parse(\"\"); // Error: Cookie name cannot be empty\n * CookieNameSchema.parse(\"session;\"); // Error: Invalid cookie name format\n * CookieNameSchema.parse(\"my cookie\"); // Error: Invalid cookie name format\n * ```\n */\nexport const CookieNameSchema = z\n .string()\n .trim()\n .min(1, \"Cookie name cannot be empty\")\n .refine(\n (name) => name === \"%\" || /^[!#$%&'()*+\\-.:0-9A-Z ^_`a-z|~]+$/.test(name),\n \"Invalid cookie name format - must contain only valid characters (letters, numbers, and certain symbols) or be '%' for wildcard\",\n );\n\n/**\n * Zod schema for cookie path validation.\n * Enforces standard cookie path rules according to RFC 6265.\n * @example\n * ```typescript\n * // Valid paths\n * CookiePathSchema.parse(\"/\"); // OK\n * CookiePathSchema.parse(\"/api\"); // OK\n * CookiePathSchema.parse(\"/path/to/page\"); // OK\n *\n * // Invalid paths\n * CookiePathSchema.parse(\"\"); // Error: Path cannot be empty\n * CookiePathSchema.parse(\"invalid\"); // Error: Path must start with /\n * CookiePathSchema.parse(\"/path?query\"); // Error: Invalid path format\n * ```\n */\nexport const CookiePathSchema = z\n .string()\n .trim()\n .min(1, \"Path cannot be empty\")\n .refine((path) => path.startsWith(\"/\"), \"Path must start with /\")\n .refine(\n (path) => /^\\/[!#$%&'()*+,\\-./:=@\\w~]*$/.test(path),\n \"Invalid path format - must contain only valid URL path characters\",\n )\n .default(\"/\");\n\n/**\n * Zod schema for cookie value.\n * Attempts to parse JSON values using destr for better readability.\n */\nexport const CookieValueSchema = z\n .string()\n .trim()\n .transform((value) => destr(value))\n .pipe(z.any());\n\n/**\n * Zod schema for Safari binary cookie row.\n * Validates and enforces the structure of cookie data read from Safari's Cookies.binarycookies file.\n * @example\n * ```typescript\n * const cookieData = {\n * name: \"session\",\n * value: \"abc123\",\n * domain: \"example.com\",\n * path: \"/\",\n * expiry: 1735689600,\n * creation: 1672531200,\n * flags: 0x5, // Secure + HTTPOnly\n * };\n * const validCookie = BinaryCookieRowSchema.parse(cookieData);\n * ```\n */\nexport const BinaryCookieRowSchema = z.object({\n name: CookieNameSchema,\n value: CookieValueSchema,\n domain: CookieDomainSchema,\n path: CookiePathSchema,\n expiry: z.number().int(),\n creation: z.number().int(),\n flags: z.number().optional(),\n version: z.number().int().optional(),\n port: z.number().int().optional(),\n comment: z.string().optional(),\n commentURL: z.string().optional(),\n});\n\n/**\n * Type representing a decoded Safari binary cookie.\n * This type is inferred from the BinaryCookieRowSchema and includes all cookie properties.\n * @property name - The name of the cookie (non-empty string)\n * @property value - The value stored in the cookie\n * @property domain - The domain the cookie belongs to (non-empty string)\n * @property path - The path where the cookie is valid (defaults to \"/\")\n * @property expiry - Unix timestamp when the cookie expires\n * @property creation - Unix timestamp when the cookie was created\n * @property flags - Optional bit flags (e.g., Secure, HTTPOnly)\n * @property version - Optional cookie version number\n * @property port - Optional port number restriction\n * @property comment - Optional cookie comment\n * @property commentURL - Optional URL for the cookie's comment\n */\nexport type BinaryCookieRow = z.infer<typeof BinaryCookieRowSchema>;\n\n/**\n * Schema for cookie specification parameters\n * Defines the required fields for identifying a cookie\n * @example\n * ```typescript\n * // Validate a cookie specification\n * const spec = {\n * name: 'session',\n * domain: 'example.com'\n * };\n * const result = CookieSpecSchema.safeParse(spec);\n * if (result.success) {\n * logger.info('Valid cookie spec:', result.data);\n * } else {\n * logger.error('Invalid cookie spec:', result.error);\n * }\n *\n * // Invalid spec (empty name)\n * const invalidSpec = {\n * name: '',\n * domain: 'example.com'\n * };\n * // Throws: \"Cookie name cannot be empty\"\n * CookieSpecSchema.parse(invalidSpec);\n * ```\n */\nexport const CookieSpecSchema = z\n .object({\n name: CookieNameSchema,\n domain: CookieDomainSchema,\n })\n .strict();\n\n/**\n * Type definition for cookie specification\n * Used for specifying which cookie to query\n * @example\n * ```typescript\n * // Basic cookie spec\n * const spec: CookieSpec = {\n * name: 'auth',\n * domain: 'api.example.com'\n * };\n *\n * // Use in function parameters\n * function queryCookie(spec: CookieSpec): Promise<ExportedCookie[]> {\n * return getCookie(spec);\n * }\n *\n * // Array of specs\n * const specs: CookieSpec[] = [\n * { name: 'session', domain: 'app.example.com' },\n * { name: 'theme', domain: 'example.com' }\n * ];\n * ```\n */\nexport type CookieSpec = z.infer<typeof CookieSpecSchema>;\n\n/**\n * Schema for metadata about a cookie\n */\nexport const CookieMetaSchema = z\n .object({\n file: z.string().trim().min(1, \"File path cannot be empty\").optional(),\n browser: z.string().trim().optional(),\n decrypted: z.boolean().optional(),\n secure: z.boolean().optional(),\n httpOnly: z.boolean().optional(),\n path: CookiePathSchema.optional(),\n })\n .catchall(z.unknown());\n\n/**\n * Type definition for cookie metadata\n */\nexport type CookieMeta = z.infer<typeof CookieMetaSchema>;\n\n/**\n * Schema for exported cookie data\n * Represents a cookie with all its properties and metadata\n * @example\n * ```typescript\n * // Validate an exported cookie\n * const cookie = {\n * domain: 'example.com',\n * name: 'session',\n * value: 'abc123',\n * expiry: new Date('2024-12-31'),\n * meta: {\n * file: '/path/to/cookies.db'\n * }\n * };\n * const result = ExportedCookieSchema.safeParse(cookie);\n * if (result.success) {\n * logger.info('Valid cookie:', result.data);\n * } else {\n * logger.error('Invalid cookie:', result.error);\n * }\n *\n * // Cookie with infinite expiry\n * const infiniteCookie = {\n * ...cookie,\n * expiry: \"Infinity\"\n * };\n * ExportedCookieSchema.parse(infiniteCookie); // OK\n * ```\n */\nexport const ExportedCookieSchema = z\n .object({\n domain: CookieDomainSchema,\n name: CookieNameSchema,\n value: CookieValueSchema,\n expiry: z\n .union([\n z.literal(\"Infinity\"),\n z.date(),\n z.number().int().positive(\"Expiry must be a positive number\"),\n ])\n .optional(),\n meta: CookieMetaSchema.optional(),\n })\n .strict();\n\n/**\n * Type definition for exported cookie data\n * Represents the structure of a cookie after it has been retrieved\n * @example\n * ```typescript\n * // Basic exported cookie\n * const cookie: ExportedCookie = {\n * domain: 'example.com',\n * name: 'session',\n * value: 'abc123',\n * expiry: new Date('2024-12-31'),\n * meta: {\n * file: '/path/to/cookies.db'\n * }\n * };\n *\n * // Process exported cookies\n * function processCookies(cookies: ExportedCookie[]): string[] {\n * return cookies.map(cookie => `${cookie.name}=${cookie.value}`);\n * }\n *\n * // Filter expired cookies\n * function filterExpired(cookies: ExportedCookie[]): ExportedCookie[] {\n * const now = new Date();\n * return cookies.filter(cookie =>\n * cookie.expiry === \"Infinity\" ||\n * (cookie.expiry instanceof Date && cookie.expiry > now)\n * );\n * }\n * ```\n */\nexport type ExportedCookie = z.infer<typeof ExportedCookieSchema>;\n\n/**\n * Schema for raw cookie data from browser stores\n */\nexport const CookieRowSchema = z\n .object({\n expiry: z.number().int().optional(),\n domain: CookieDomainSchema,\n name: CookieNameSchema,\n value: z.union([z.string(), z.instanceof(Buffer)]),\n })\n .strict();\n\n/**\n * Type definition for raw cookie data\n */\nexport type CookieRow = z.infer<typeof CookieRowSchema>;\n\n/**\n * Schema for cookie render options\n */\nexport const RenderOptionsSchema = z\n .object({\n format: z.enum([\"merged\", \"grouped\"]).optional(),\n separator: z.string().optional(),\n showFilePaths: z.boolean().optional(),\n })\n .strict();\n\n/**\n * Type definition for render options\n */\nexport type RenderOptions = z.infer<typeof RenderOptionsSchema>;\n\n/**\n * Schema for browser names\n */\nexport const BrowserNameSchema = z.enum([\n \"Chrome\",\n \"Firefox\",\n \"Safari\",\n \"internal\",\n \"unknown\",\n]);\n\n/**\n * Type definition for browser names\n */\nexport type BrowserName = z.infer<typeof BrowserNameSchema>;\n\n/**\n * Type definition for cookie query strategy\n */\nexport type CookieQueryStrategy = {\n browserName: BrowserName;\n queryCookies: (\n domain: string,\n name: string,\n path?: string,\n secure?: boolean,\n ) => Promise<ExportedCookie[]>;\n};\n\n/**\n * Schema for cookie query strategy\n */\nexport const CookieQueryStrategySchema = z\n .object({\n browserName: BrowserNameSchema,\n queryCookies: z.function(),\n })\n .strict();\n\n/**\n * Type representing either a single cookie specification or an array of specifications.\n * Useful when you need to query multiple cookies in a single operation.\n * @example\n * ```typescript\n * // Single cookie spec\n * const single: MultiCookieSpec = {\n * domain: \"example.com\",\n * name: \"sessionId\"\n * };\n *\n * // Multiple cookie specs\n * const multiple: MultiCookieSpec = [\n * { domain: \"example.com\", name: \"sessionId\" },\n * { domain: \"api.example.com\", name: \"authToken\" }\n * ];\n * ```\n */\nexport type MultiCookieSpec = CookieSpec | CookieSpec[];\n\n/**\n * Schema for base cookie query options\n */\nexport const BaseCookieQueryOptionsSchema = z.object({\n /** Maximum number of cookies to return */\n limit: z.number().int().positive().optional(),\n /** Whether to remove expired cookies from results */\n removeExpired: z.boolean().optional(),\n /** Include expired cookies in results */\n includeExpired: z.boolean().optional(),\n /** Storage location override */\n store: z.string().optional(),\n /** Force query even if browser is running */\n force: z.boolean().optional(),\n});\n\n/**\n * Schema for strategy-based cookie query options\n */\nexport const CookieQueryOptionsSchema = BaseCookieQueryOptionsSchema.extend({\n /** Strategy to use for querying cookies */\n strategy: CookieQueryStrategySchema.optional(),\n});\n\n/**\n * Schema for SQL browser types\n */\nexport const SqlBrowserTypeSchema = z.enum([\n \"chrome\",\n \"chromium\",\n \"edge\",\n \"firefox\",\n \"opera\",\n \"brave\",\n \"arc\",\n]);\n\n/**\n * Schema for SQL-specific cookie query options\n */\nexport const SqlCookieQueryOptionsSchema = CookieSpecSchema.extend({\n /** Browser type for SQL queries */\n browser: SqlBrowserTypeSchema,\n /** Enable exact domain matching instead of wildcard */\n exactDomain: z.boolean().optional(),\n /** Enable case-sensitive matching */\n caseSensitive: z.boolean().optional(),\n /** Maximum number of results */\n limit: z.number().int().positive().optional(),\n /** Include expired cookies */\n includeExpired: z.boolean().optional(),\n});\n\n/**\n * Type for base cookie query options\n */\nexport type BaseCookieQueryOptions = z.infer<\n typeof BaseCookieQueryOptionsSchema\n>;\n\n/**\n * Type for strategy-based cookie query options\n */\nexport type CookieQueryOptions<\n T extends CookieQueryStrategy = CookieQueryStrategy,\n> = BaseCookieQueryOptions & {\n strategy?: T;\n};\n\n/**\n * Type for SQL browser types\n */\nexport type SqlBrowserType = z.infer<typeof SqlBrowserTypeSchema>;\n\n/**\n * Type for SQL-specific cookie query options\n */\nexport type SqlCookieQueryOptions = z.infer<typeof SqlCookieQueryOptionsSchema>;\n","import { Buffer } from \"node:buffer\";\n\nimport {\n type BinaryCookieRow,\n BinaryCookieRowSchema,\n} from \"../../../types/schemas\";\nimport { createTaggedLogger } from \"../../../utils/logHelpers\";\n\nimport type { BinaryCodableContainer } from \"./interfaces/BinaryCodableContainer\";\nimport type { BinaryCodableFlags } from \"./interfaces/BinaryCodableFlags\";\nimport type { BinaryCodableOffsets } from \"./interfaces/BinaryCodableOffsets\";\n\nconst logger = createTaggedLogger(\"BinaryCodableCookie\");\n\n/**\n * Represents a single cookie within a page\n * Handles decoding of Safari's binary cookie format\n */\nexport class BinaryCodableCookie {\n /**\n * Cookie version number\n */\n public version = 0;\n\n /**\n * URL the cookie is associated with\n */\n public url = \"\";\n\n /**\n * Port number if specified\n */\n public port?: number;\n\n /**\n * Cookie name\n */\n public name = \"\";\n\n /**\n * Cookie path\n */\n public path = \"\";\n\n /**\n * Cookie value\n */\n public value = \"\";\n\n /**\n * Optional comment\n */\n public comment?: string;\n\n /**\n * Optional comment URL\n */\n public commentURL?: string;\n\n /**\n * Cookie flags (secure, httpOnly, etc.)\n */\n public flags: BinaryCodableFlags = {\n isSecure: false,\n isHTTPOnly: false,\n unknown1: false,\n unknown2: false,\n };\n\n /**\n * Expiration timestamp (Mac epoch seconds)\n */\n public expiration = 0;\n\n /**\n * Creation timestamp (Mac epoch seconds)\n */\n public creation = 0;\n\n /**\n * Creates a new Cookie instance from a buffer\n * @param buffer - The raw binary cookie data\n */\n public constructor(buffer: Buffer) {\n const container: BinaryCodableContainer = { offset: 0, buffer };\n this.decode(container);\n }\n\n /**\n * Decode URL encoded values with multiple passes\n * @param value - The URL encoded string\n * @returns Decoded string\n */\n private decodeUrlValue(value: string): string {\n let processed = value;\n let lastProcessed: string;\n do {\n lastProcessed = processed;\n try {\n processed = decodeURIComponent(processed);\n } catch {\n return lastProcessed;\n }\n } while (processed !== lastProcessed && processed.includes(\"%\"));\n return processed;\n }\n\n /**\n * Decode JWT payload if the value is a valid JWT token\n * @param token - The JWT token string\n * @returns Decoded payload as JSON string or null if invalid\n */\n private decodeJwtPayload(token: string): string | null {\n const parts = token.split(\".\");\n if (parts.length !== 3) {\n return null;\n }\n\n try {\n const payloadPart = parts[1];\n if (!payloadPart) {\n return null;\n }\n const payload = Buffer.from(payloadPart, \"base64\").toString(\"utf8\");\n const parsed = JSON.parse(payload) as Record<string, unknown>;\n return JSON.stringify(parsed);\n } catch {\n return null;\n }\n }\n\n /**\n * Parse JSON value and return formatted JSON string\n * @param value - The JSON string to parse\n * @returns Formatted JSON string or null if invalid\n */\n private parseJsonValue(value: string): string | null {\n try {\n const parsed = JSON.parse(value) as Record<string, unknown>;\n return JSON.stringify(parsed);\n } catch {\n return null;\n }\n }\n\n /**\n * Process cookie value with appropriate decoding\n * @param value - The raw cookie value\n * @returns Processed and decoded value as string\n */\n private processValue(value: unknown): string {\n // Handle non-string values\n const primitiveResult = this.handlePrimitiveValues(value);\n if (primitiveResult !== null) {\n return primitiveResult;\n }\n\n // Must be a string at this point\n const stringValue = value as string;\n\n // First, try URL decoding\n const decoded = this.decodeUrlValue(stringValue);\n\n // Try specialized decoding\n return this.trySpecializedDecoding(decoded);\n }\n\n /**\n * Handle primitive value types (null, undefined, buffer, non-string)\n * @param value - The value to check\n * @returns String representation or null if not a primitive type\n */\n private handlePrimitiveValues(value: unknown): string | null {\n if (value === null) {\n return \"null\";\n }\n\n if (value === undefined) {\n return \"undefined\";\n }\n\n if (Buffer.isBuffer(value)) {\n return value.toString();\n }\n\n if (typeof value !== \"string\") {\n return this.safeStringify(value);\n }\n\n return null; // Not a primitive type\n }\n\n /**\n * Try specialized decoding (JWT, JSON) on the decoded string\n * @param decoded - The URL-decoded string\n * @returns Specialized decoded value or the original decoded string\n */\n private trySpecializedDecoding(decoded: string): string {\n // Try JWT decoding if it looks like a JWT token\n const jwtResult = this.tryJwtDecoding(decoded);\n if (jwtResult !== null) {\n return jwtResult;\n }\n\n // Try JSON parsing if it looks like JSON\n const jsonResult = this.tryJsonDecoding(decoded);\n if (jsonResult !== null) {\n return jsonResult;\n }\n\n return decoded;\n }\n\n /**\n * Try JWT decoding if the value looks like a JWT token\n * @param decoded - The decoded string to check\n * @returns Decoded JWT payload or null if not a JWT or decoding failed\n */\n private tryJwtDecoding(decoded: string): string | null {\n if (decoded.match(/^ey[A-Za-z0-9_-]+\\.ey[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/)) {\n const jwtPayload = this.decodeJwtPayload(decoded);\n if (typeof jwtPayload === \"string\" && jwtPayload.length > 0) {\n return jwtPayload;\n }\n }\n return null;\n }\n\n /**\n * Try JSON decoding if the value looks like JSON\n * @param decoded - The decoded string to check\n * @returns Decoded JSON string or null if not JSON or decoding failed\n */\n private tryJsonDecoding(decoded: string): string | null {\n if (decoded.startsWith(\"{\") || decoded.startsWith(\"[\")) {\n const jsonValue = this.parseJsonValue(decoded);\n if (typeof jsonValue === \"string\" && jsonValue.length > 0) {\n return jsonValue;\n }\n }\n return null;\n }\n\n /**\n * Safely convert unknown value to string\n * @param value - The value to stringify\n * @returns String representation of the value\n */\n private safeStringify(value: unknown): string {\n try {\n if (typeof value === \"object\" && value !== null) {\n // For objects, use JSON.stringify if possible, otherwise use toString\n return JSON.stringify(value);\n }\n return String(value);\n } catch {\n // Fallback to String() if JSON.stringify fails\n return String(value);\n }\n }\n\n /**\n * Validates and converts Mac epoch timestamp to Unix epoch\n * @param macTimestamp - Timestamp in Mac epoch (seconds since 2001-01-01)\n * @returns Unix epoch timestamp or 0 for invalid timestamps\n */\n private convertMacTimestamp(macTimestamp: number): number {\n const macToUnixOffset = 978307200; // Seconds between 1970-01-01 and 2001-01-01\n\n if (macTimestamp <= 0) {\n return macTimestamp;\n }\n\n // Validate timestamp bounds - reasonable range is 0 to ~1 billion seconds (2032)\n const isValid =\n macTimestamp >= 0 &&\n macTimestamp <= 1000000000 &&\n Number.isFinite(macTimestamp);\n\n return isValid ? macTimestamp + macToUnixOffset : 0;\n }\n\n /**\n * Converts the cookie to a validated cookie row\n * @returns Validated cookie row object or null if validation fails\n */\n public toCookieRow(): BinaryCookieRow | null {\n try {\n // Convert flags to number\n const flagsValue = this.convertFlags();\n\n // Extract domain from URL\n const domain =\n this.url.replace(/^https?:\\/\\//, \"\").replace(/\\/.*$/, \"\") || \"uk\";\n\n // Convert timestamps from Mac epoch to Unix epoch with validation\n const expiryUnix = this.convertMacTimestamp(this.expiration);\n const creationUnix = this.convertMacTimestamp(this.creation);\n\n // Create cookie row with converted timestamps\n const cookieRow = BinaryCookieRowSchema.parse({\n name: this.name.replace(/^: /, \"\"), // Remove leading ': ' if present\n value: this.processValue(this.value) || \"\", // Process and ensure value is never undefined\n domain,\n path: this.path || \"/\",\n expiry: expiryUnix,\n creation: creationUnix,\n flags: flagsValue,\n version: this.version,\n port: this.port,\n comment: this.comment,\n commentURL: this.commentURL,\n });\n\n return cookieRow;\n } catch (_error) {\n return null;\n }\n }\n\n /**\n * Read the cookie header information\n * @param container - The binary container\n * @returns Object containing size, port flag, and string offsets\n */\n private readHeader(container: BinaryCodableContainer): {\n size: number;\n hasPort: number;\n offsets: BinaryCodableOffsets;\n } {\n // Cookie size (4 bytes)\n const size = container.buffer.readUInt32LE(container.offset);\n logger.debug(\"Cookie size:\", size);\n container.offset += 4;\n\n // Version (4 bytes)\n const version = container.buffer.readUInt32LE(container.offset);\n logger.debug(\"Cookie version:\", version);\n container.offset += 4;\n\n // Cookie flags (4 bytes)\n const flagsValue = container.buffer.readUInt32LE(container.offset);\n logger.debug(\"Cookie flags:\", flagsValue.toString(2).padStart(8, \"0\"));\n container.offset += 4;\n this.flags = {\n isSecure: (flagsValue & 1) !== 0,\n isHTTPOnly: (flagsValue & 4) !== 0,\n unknown1: (flagsValue & 8) !== 0,\n unknown2: (flagsValue & 16) !== 0,\n };\n\n // Has port (4 bytes)\n const hasPort = container.buffer.readUInt32LE(container.offset);\n logger.debug(\"Has port:\", hasPort);\n container.offset += 4;\n\n // String offsets (24 bytes total)\n const offsets = {\n urlOffset: container.buffer.readUInt32LE(container.offset),\n nameOffset: container.buffer.readUInt32LE(container.offset + 4),\n pathOffset: container.buffer.readUInt32LE(container.offset + 8),\n valueOffset: container.buffer.readUInt32LE(container.offset + 12),\n commentOffset: container.buffer.readUInt32LE(container.offset + 16),\n commentURLOffset: container.buffer.readUInt32LE(container.offset + 20),\n };\n logger.debug(\"String offsets:\", offsets);\n\n return { size, hasPort, offsets };\n }\n\n /**\n * Read expiration and creation timestamps from the container\n * @param container - The binary container\n */\n private readTimestamps(container: BinaryCodableContainer): void {\n // Read expiration time (8 bytes, little-endian double)\n const expirationBuffer = Buffer.alloc(8);\n for (let i = 0; i < 8; i++) {\n expirationBuffer[i] = container.buffer[container.offset + i]!;\n }\n const expiration = expirationBuffer.readDoubleLE(0);\n container.offset += 8;\n\n // Read creation time (8 bytes, little-endian double)\n const creationBuffer = Buffer.alloc(8);\n for (let i = 0; i < 8; i++) {\n creationBuffer[i] = container.buffer[container.offset + i]!;\n }\n const creation = creationBuffer.readDoubleLE(0);\n container.offset += 8;\n\n // Store raw timestamps (seconds since 2001-01-01)\n // For expiration time, 0 means \"session cookie\" (expires when browser closes)\n // For creation time, 0 means \"no creation time recorded\"\n this.expiration = expiration;\n this.creation = creation;\n }\n\n /**\n * Read cookie string fields from the container\n * @param container - The binary container\n * @param size - Total size of the cookie\n * @param offsets - String field offsets\n */\n private readStrings(\n container: BinaryCodableContainer,\n size: number,\n offsets: BinaryCodableOffsets,\n ): void {\n // All offsets are relative to the start of the cookie\n const cookieStart = 0; // Offsets are relative to the cookie buffer start\n logger.debug(\"Reading strings from cookie buffer of size:\", size);\n\n // Read strings in order of their offsets\n const offsetEntries = [\n { field: \"url\", offset: offsets.urlOffset },\n { field: \"name\", offset: offsets.nameOffset },\n { field: \"path\", offset: offsets.pathOffset },\n { field: \"value\", offset: offsets.valueOffset },\n { field: \"comment\", offset: offsets.commentOffset },\n ]\n .filter((entry) => entry.offset > 0)\n .sort((a, b) => a.offset - b.offset);\n\n logger.debug(\n \"Reading strings in order:\",\n offsetEntries.map((e) => e.field),\n );\n\n // Calculate string lengths based on offset differences\n for (let i = 0; i < offsetEntries.length; i++) {\n const entry = offsetEntries[i]!;\n const { field, offset } = entry;\n const nextOffset =\n i < offsetEntries.length - 1 ? offsetEntries[i + 1]!.offset : size;\n const length = nextOffset - offset;\n\n // Read string up to null terminator\n let end = cookieStart + offset;\n while (\n end < cookieStart + offset + length &&\n container.buffer[end] !== 0\n ) {\n end++;\n }\n const value = container.buffer.toString(\n \"utf8\",\n cookieStart + offset,\n end,\n );\n logger.debug(`Read ${field}:`, value);\n\n switch (field) {\n case \"url\":\n this.url = value;\n break;\n case \"name\":\n this.name = value;\n break;\n case \"path\":\n this.path = value;\n break;\n case \"value\":\n this.value = value;\n break;\n case \"comment\":\n this.comment = value;\n break;\n }\n }\n }\n\n /**\n * Decode the cookie from the binary container\n * @param container - The binary container with cookie data\n */\n private decode(container: BinaryCodableContainer): void {\n const { size, hasPort, offsets } = this.readHeader(container);\n\n // Skip past all offsets (24 bytes)\n const baseOffset = container.offset;\n container.offset = baseOffset + 24;\n\n this.readTimestamps(container);\n\n if (hasPort > 0) {\n this.port = container.buffer.readUInt16LE(container.offset);\n container.offset += 2;\n }\n\n // Reset offset for string reading\n container.offset = baseOffset;\n this.readStrings(container, size, offsets);\n }\n\n /**\n * Convert cookie flags to numeric representation\n * @returns Numeric flags value\n */\n private convertFlags(): number {\n return (\n (this.flags.isSecure ? 0x1 : 0) |\n (this.flags.isHTTPOnly ? 0x4 : 0) |\n (this.flags.unknown1 ? 0x8 : 0) |\n (this.flags.unknown2 ? 0x10 : 0)\n );\n }\n}\n","import type { BinaryCookieRow } from \"../../../types/schemas\";\n\nimport { BinaryCodableCookies } from \"./BinaryCodableCookies\";\n\n/**\n * Decodes a Safari binary cookie file into an array of cookie objects.\n * @param cookieDbPath - Path to the Safari Cookies.binarycookies file\n * @returns Array of decoded cookie objects\n * @throws {Error} If the file cannot be read or has invalid format\n */\nexport function decodeBinaryCookies(cookieDbPath: string): BinaryCookieRow[] {\n const cookies = BinaryCodableCookies.fromFile(cookieDbPath);\n return cookies.toCookieRows();\n}\n\n/**\n * Retrieves cookies from Safari's binary cookie store.\n * @returns Array of decoded Safari cookies\n */\nexport function getSafariCookies(): BinaryCookieRow[] {\n const cookies = BinaryCodableCookies.fromDefaultPath();\n return cookies.toCookieRows();\n}\n","import type { CookieSpec, ExportedCookie } from \"../../types/schemas\";\nimport logger from \"../../utils/logger\";\n\nimport { queryCookies } from \"./queryCookies\";\n\n/**\n * Retrieves browser cookies that match the specified cookie name and domain criteria.\n * This function provides a way to search and filter cookies based on given specifications.\n * @param cookieSpec - The cookie specification containing search criteria\n * @param cookieSpec.name - The name of the cookie to search for\n * @param cookieSpec.domain - (optional) The domain to filter cookies by\n * @returns An array of ExportedCookie objects that match the specification\n * @throws Will catch and handle any errors during cookie querying, logging a warning\n * to the console without throwing to the caller\n * @example\n * ```typescript\n * import { getCookie } from \"@mherod/get-cookie\";\n *\n * // Get all cookies named \"sessionId\"\n * const cookies = await getCookie({ name: \"sessionId\" });\n * // Returns: [{ name: \"sessionId\", value: \"abc123\", domain: \".example.com\", ... }]\n *\n * // Get cookies named \"userPref\" from specific domain\n * const domainCookies = await getCookie({\n * name: \"userPref\",\n * domain: \"example.com\"\n * });\n * // Returns: [{ name: \"userPref\", value: \"darkMode\", domain: \"example.com\", ... }]\n * ```\n */\nexport async function getCookie(\n cookieSpec: CookieSpec,\n): Promise<ExportedCookie[]> {\n try {\n const cookies = await queryCookies(cookieSpec);\n logger.debug(\"Cookies retrieved:\", cookies);\n return cookies;\n } catch (error: unknown) {\n logger.warn(\n \"Error querying cookies:\",\n error instanceof Error ? error.message : String(error),\n );\n return [];\n }\n}\n\n/**\n * Default export of the getCookie function.\n * @example\n * ```typescript\n * import { getCookie } from \"@mherod/get-cookie\";\n * const authCookies = await getCookie({\n * name: \"auth-token\",\n * domain: \"api.example.com\"\n * });\n * ```\n */\nexport default getCookie;\n","import type { CookieSpec, ExportedCookie } from \"../../types/schemas\";\nimport { ChromeCookieQueryStrategy } from \"../browsers/chrome/ChromeCookieQueryStrategy\";\nimport { FirefoxCookieQueryStrategy } from \"../browsers/firefox/FirefoxCookieQueryStrategy\";\nimport { SafariCookieQueryStrategy } from \"../browsers/safari/SafariCookieQueryStrategy\";\n\n/**\n * Queries cookies from all available browser strategies (Chrome, Firefox, Safari).\n * This function acts as a unified interface to retrieve cookies across different browsers.\n * @param cookieSpec - The cookie specification to query\n * @param cookieSpec.name - The name pattern to match cookies against (can include '%' as wildcard)\n * @param cookieSpec.domain - The domain to match cookies against\n * @returns Promise resolving to array of exported cookies from all available browsers\n * @remarks\n * - Returns empty array if cookieSpec is invalid or missing required fields\n * - Aggregates results from all available browser strategies\n * - Failed browser queries are gracefully handled and excluded from results\n * - Both name and domain fields are required and must be strings\n * @example\n * ```typescript\n * const cookies = await queryCookies({\n * name: 'sessionId',\n * domain: 'example.com'\n * });\n * console.log(cookies); // Array of matching cookies from all browsers\n * ```\n */\nexport async function queryCookies(\n cookieSpec: CookieSpec,\n): Promise<ExportedCookie[]> {\n if (!cookieSpec.name || !cookieSpec.domain) {\n return [];\n }\n\n const { name, domain } = cookieSpec;\n if (typeof name !== \"string\" || typeof domain !== \"string\") {\n return [];\n }\n\n /**\n * Initialize all available browser-specific strategies\n * The order of strategies can affect performance but not functionality\n * Each strategy is responsible for its own error handling\n */\n const strategies = [\n new ChromeCookieQueryStrategy(),\n new FirefoxCookieQueryStrategy(),\n new SafariCookieQueryStrategy(),\n ];\n\n /**\n * Query all strategies in parallel and handle failures gracefully\n * Using Promise.allSettled ensures that failures in one strategy\n * don't prevent results from other strategies\n */\n const results = await Promise.allSettled(\n strategies.map(async (strategy) => strategy.queryCookies(name, domain)),\n );\n\n /**\n * Filter out failed promises and flatten successful results\n * Using PromiseFulfilledResult<ExportedCookie[]> ensures that only successful results are included\n */\n return results\n .filter(\n (result): result is PromiseFulfilledResult<ExportedCookie[]> =>\n result.status === \"fulfilled\",\n )\n .flatMap((result) => result.value);\n}\n\n/**\n * Default export of the queryCookies function.\n * This is the recommended way to import the function for most use cases.\n * @example\n * ```typescript\n * import queryCookies from './queryCookies';\n *\n * // Query cookies with specific name\n * const sessionCookies = await queryCookies({\n * name: 'sessionId',\n * domain: 'example.com'\n * });\n *\n * // Query all cookies for a domain using wildcard\n * const allCookies = await queryCookies({\n * name: '%',\n * domain: 'example.com'\n * });\n * ```\n */\nexport default queryCookies;\n","import type { CookieSpec, ExportedCookie } from \"../../types/schemas\";\nimport { ensureError, getErrorMessage } from \"../../utils/errorUtils\";\nimport logger from \"../../utils/logger\";\n\nimport { batchQueryCookies } from \"./batchQueryCookies\";\nimport { getCookie } from \"./getCookie\";\n\n/**\n * Options for batch cookie retrieval\n */\nexport interface BatchGetCookiesOptions {\n /**\n * Whether to deduplicate cookies across all specs\n * When true, keeps the cookie with the longest value for each unique name+domain combination\n * @default true\n */\n deduplicate?: boolean;\n\n /**\n * Maximum number of concurrent requests\n * @default 10\n */\n concurrency?: number;\n\n /**\n * Whether to continue on errors for individual specs\n * When true, errors for individual specs won't fail the entire batch\n * @default true\n */\n continueOnError?: boolean;\n}\n\n/**\n * Result for a single cookie spec in batch operation\n */\nexport interface BatchCookieResult {\n /**\n * The original spec that was queried\n */\n spec: CookieSpec;\n\n /**\n * The cookies retrieved for this spec\n */\n cookies: ExportedCookie[];\n\n /**\n * Error if the query failed (only when continueOnError is true)\n */\n error?: Error;\n}\n\n/**\n * Retrieves multiple cookie specifications in parallel with intelligent deduplication.\n * This function efficiently fetches cookies for multiple specifications and can optionally\n * deduplicate the results to keep only the most valid cookie for each unique name+domain pair.\n * @param specs - Array of cookie specifications to retrieve\n * @param options - Options for batch retrieval\n * @returns Array of exported cookies, optionally deduplicated\n * @example\n * ```typescript\n * import { batchGetCookies } from \"@mherod/get-cookie\";\n *\n * // Fetch multiple cookies in parallel\n * const cookies = await batchGetCookies([\n * { name: \"auth\", domain: \"api.example.com\" },\n * { name: \"session\", domain: \"example.com\" },\n * { name: \"token\", domain: \"*.example.com\" }\n * ]);\n *\n * // With options\n * const cookies = await batchGetCookies(\n * [\n * { name: \"auth\", domain: \"api.example.com\" },\n * { name: \"session\", domain: \"example.com\" }\n * ],\n * {\n * deduplicate: true, // Keep only the best cookie for each name+domain\n * concurrency: 5, // Limit concurrent requests\n * continueOnError: true // Don't fail entire batch on individual errors\n * }\n * );\n * ```\n */\nexport async function batchGetCookies(\n specs: CookieSpec[],\n options: BatchGetCookiesOptions = {},\n): Promise<ExportedCookie[]> {\n const {\n deduplicate = true,\n concurrency = 10,\n continueOnError = true,\n } = options;\n\n logger.debug(`Batch fetching ${specs.length} cookie specs`, {\n deduplicate,\n concurrency,\n continueOnError,\n });\n\n // Use optimized batch query that combines SQL queries\n let results: ExportedCookie[];\n\n try {\n results = await batchQueryCookies(specs, continueOnError);\n logger.debug(`Batch query returned ${results.length} cookies`);\n } catch (error) {\n // If continueOnError is false and batch query fails, throw the error\n if (!continueOnError) {\n throw error;\n }\n\n // Fall back to individual queries if batch query fails\n logger.warn(\"Batch query failed, falling back to individual queries\", {\n error: getErrorMessage(error),\n });\n\n results = await fallbackToIndividualQueries(\n specs,\n concurrency,\n continueOnError,\n );\n }\n\n // Deduplicate if requested\n if (deduplicate && results.length > 0) {\n const deduped = deduplicateCookies(results);\n logger.debug(`Deduplicated ${results.length} to ${deduped.length}`);\n return deduped;\n }\n\n return results;\n}\n\n/**\n * Retrieves multiple cookie specifications with detailed results for each spec.\n * Unlike `batchGetCookies`, this returns detailed results including any errors\n * that occurred for individual specs.\n * @param specs - Array of cookie specifications to retrieve\n * @param options - Options for batch retrieval\n * @returns Array of batch results with cookies and potential errors\n * @example\n * ```typescript\n * import { batchGetCookiesWithResults } from \"@mherod/get-cookie\";\n *\n * const results = await batchGetCookiesWithResults([\n * { name: \"auth\", domain: \"api.example.com\" },\n * { name: \"session\", domain: \"example.com\" }\n * ]);\n *\n * results.forEach(result => {\n * if (result.error) {\n * console.error(`Failed to get cookies for ${result.spec.name}: ${result.error.message}`);\n * } else {\n * console.log(`Got ${result.cookies.length} cookies for ${result.spec.name}`);\n * }\n * });\n * ```\n */\n/**\n * Process cookies and group them by spec\n * @param specs - Cookie specifications\n * @param allCookies - All retrieved cookies\n * @returns Array of batch results\n */\nfunction groupCookiesBySpec(\n specs: CookieSpec[],\n allCookies: ExportedCookie[],\n): BatchCookieResult[] {\n return specs.map((spec) => {\n const specCookies = allCookies.filter(\n (cookie) => cookie.name === spec.name && cookie.domain === spec.domain,\n );\n return { spec, cookies: specCookies };\n });\n}\n\n/**\n * Process a chunk of specs for detailed results\n * @param chunk - Chunk of specs to process\n * @param continueOnError - Whether to continue on errors\n * @returns Array of batch cookie results\n */\nasync function processChunkWithResults(\n chunk: CookieSpec[],\n continueOnError: boolean,\n): Promise<BatchCookieResult[]> {\n const chunkPromises = chunk.map(async (spec): Promise<BatchCookieResult> => {\n try {\n const cookies = await getCookie(spec);\n return { spec, cookies };\n } catch (error) {\n const err = ensureError(error, \"Failed to fetch cookies\");\n if (!continueOnError) {\n throw err;\n }\n logger.warn(\"Failed to fetch cookies for spec\", {\n spec,\n error: getErrorMessage(err),\n });\n return { spec, cookies: [], error: err };\n }\n });\n\n return Promise.all(chunkPromises);\n}\n\n/**\n * Retrieves multiple cookie specifications with detailed results for each spec\n * @param specs - Array of cookie specifications to retrieve\n * @param options - Options for batch retrieval\n * @returns Array of batch results with cookies and potential errors\n */\nexport async function batchGetCookiesWithResults(\n specs: CookieSpec[],\n options: Omit<BatchGetCookiesOptions, \"deduplicate\"> = {},\n): Promise<BatchCookieResult[]> {\n const { concurrency = 10, continueOnError = true } = options;\n\n logger.debug(`Batch fetching ${specs.length} cookie specs with results`, {\n concurrency,\n continueOnError,\n });\n\n // Try using optimized batch query first\n try {\n const allCookies = await batchQueryCookies(specs, continueOnError);\n return groupCookiesBySpec(specs, allCookies);\n } catch (error) {\n logger.warn(\"Batch query failed, falling back to individual queries\", {\n error: getErrorMessage(error),\n });\n\n // Fall back to individual queries\n const results: BatchCookieResult[] = [];\n\n for (let i = 0; i < specs.length; i += concurrency) {\n const chunk = specs.slice(i, i + concurrency);\n const chunkResults = await processChunkWithResults(\n chunk,\n continueOnError,\n );\n results.push(...chunkResults);\n }\n\n return results;\n }\n}\n\n/**\n * Process a single chunk of cookie specs\n * @param chunk - Array of cookie specs to process\n * @param continueOnError - Whether to continue on errors\n * @returns Object containing results and errors\n */\nasync function processChunk(\n chunk: CookieSpec[],\n continueOnError: boolean,\n): Promise<{\n cookies: ExportedCookie[];\n errors: Array<{ spec: CookieSpec; error: Error }>;\n}> {\n const cookies: ExportedCookie[] = [];\n const errors: Array<{ spec: CookieSpec; error: Error }> = [];\n\n const chunkPromises = chunk.map(async (spec) => {\n try {\n const specCookies = await getCookie(spec);\n return { spec, cookies: specCookies, error: undefined };\n } catch (error) {\n const err = ensureError(error, \"Failed to fetch cookies\");\n if (!continueOnError) {\n throw err;\n }\n logger.warn(\"Failed to fetch cookies for spec\", {\n spec,\n error: getErrorMessage(err),\n });\n return { spec, cookies: [], error: err };\n }\n });\n\n const chunkResults = await Promise.all(chunkPromises);\n\n for (const result of chunkResults) {\n if (result.error) {\n errors.push({ spec: result.spec, error: result.error });\n } else {\n cookies.push(...result.cookies);\n }\n }\n\n return { cookies, errors };\n}\n\n/**\n * Fallback to individual queries when batch query fails\n * @param specs - Array of cookie specifications\n * @param concurrency - Maximum concurrent requests\n * @param continueOnError - Whether to continue on errors\n * @returns Array of exported cookies\n */\nasync function fallbackToIndividualQueries(\n specs: CookieSpec[],\n concurrency: number,\n continueOnError: boolean,\n): Promise<ExportedCookie[]> {\n const results: ExportedCookie[] = [];\n const allErrors: Array<{ spec: CookieSpec; error: Error }> = [];\n\n for (let i = 0; i < specs.length; i += concurrency) {\n const chunk = specs.slice(i, i + concurrency);\n const { cookies, errors } = await processChunk(chunk, continueOnError);\n results.push(...cookies);\n allErrors.push(...errors);\n }\n\n // Log any errors that occurred\n if (allErrors.length > 0) {\n logger.warn(`${allErrors.length} specs failed during batch retrieval`, {\n failedSpecs: allErrors.map((e) => e.spec),\n });\n }\n\n return results;\n}\n\n/**\n * Deduplicates an array of cookies, keeping the most valid value for each unique name+domain pair.\n * Prioritizes cookies with longer values as they are more likely to be valid/complete.\n * @param cookies - Array of cookies to deduplicate\n * @returns Deduplicated array of cookies\n */\nfunction deduplicateCookies(cookies: ExportedCookie[]): ExportedCookie[] {\n const cookieMap = new Map<string, ExportedCookie>();\n\n for (const cookie of cookies) {\n const key = `${cookie.name}:${cookie.domain}`;\n const existing = cookieMap.get(key);\n\n // Keep the cookie with the longest value (most likely to be valid)\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n const existingLength: number = existing?.value.length ?? 0;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n const currentLength: number = cookie.value.length;\n if (!existing || currentLength > existingLength) {\n cookieMap.set(key, cookie);\n }\n }\n\n return Array.from(cookieMap.values());\n}\n\n/**\n * Default export of the batchGetCookies function\n */\nexport default batchGetCookies;\n","import type { CookieSpec, ExportedCookie } from \"../../types/schemas\";\nimport { ensureError, getErrorMessage } from \"../../utils/errorUtils\";\nimport logger from \"../../utils/logger\";\nimport type { BaseCookieQueryStrategy } from \"../browsers/BaseCookieQueryStrategy\";\nimport { ChromeCookieQueryStrategy } from \"../browsers/chrome/ChromeCookieQueryStrategy\";\nimport { FirefoxCookieQueryStrategy } from \"../browsers/firefox/FirefoxCookieQueryStrategy\";\nimport { SafariCookieQueryStrategy } from \"../browsers/safari/SafariCookieQueryStrategy\";\n/**\n * Batch query cookies from browser strategies with optimized SQL queries.\n * This function groups cookie specs and executes combined queries where possible.\n * @param specs - Array of cookie specifications to query\n * @param continueOnError - Whether to continue on errors for individual specs\n * @returns Promise resolving to array of exported cookies\n * @example\n * ```typescript\n * const cookies = await batchQueryCookies([\n * { name: \"auth\", domain: \"example.com\" },\n * { name: \"session\", domain: \"example.com\" },\n * { name: \"token\", domain: \"api.example.com\" }\n * ]);\n * ```\n */\n/**\n * Validate cookie specs\n * @param specs - Array of cookie specifications\n * @returns Array of valid cookie specs\n */\nfunction validateSpecs(specs: CookieSpec[]): CookieSpec[] {\n return specs.filter(\n (spec) =>\n Boolean(spec.name) &&\n Boolean(spec.domain) &&\n typeof spec.name === \"string\" &&\n typeof spec.domain === \"string\",\n );\n}\n\n/**\n * Type guard to check if strategy supports batch queries\n * @param strategy - Cookie query strategy\n * @returns True if strategy supports batch queries\n */\nfunction supportsBatchQueries(\n strategy: BaseCookieQueryStrategy,\n): strategy is BaseCookieQueryStrategy & {\n batchQueryCookies: (specs: CookieSpec[]) => Promise<ExportedCookie[]>;\n} {\n return (\n \"batchQueryCookies\" in strategy &&\n typeof strategy.batchQueryCookies === \"function\"\n );\n}\n\n/**\n * Process individual query results\n * @param results - Promise settlement results\n * @param continueOnError - Whether to continue on errors\n * @returns Object with cookies and errors\n * @throws Error if continueOnError is false and a query fails\n */\nfunction processIndividualResults(\n results: PromiseSettledResult<ExportedCookie[]>[],\n continueOnError: boolean,\n): { cookies: ExportedCookie[]; errors: Error[] } {\n const cookies: ExportedCookie[] = [];\n const errors: Error[] = [];\n\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n cookies.push(...result.value);\n } else if (!continueOnError) {\n throw result.reason;\n } else {\n errors.push(ensureError(result.reason, \"Query failed\"));\n }\n }\n\n return { cookies, errors };\n}\n\n/**\n * Query a single strategy for cookies\n * @param strategy - Cookie query strategy\n * @param validSpecs - Valid cookie specifications\n * @param continueOnError - Whether to continue on errors\n * @returns Object with cookies and errors\n */\nasync function queryStrategy(\n strategy: BaseCookieQueryStrategy,\n validSpecs: CookieSpec[],\n continueOnError: boolean,\n): Promise<{ cookies: ExportedCookie[]; errors: Error[] }> {\n const cookies: ExportedCookie[] = [];\n const errors: Error[] = [];\n\n try {\n if (supportsBatchQueries(strategy)) {\n // Use optimized batch query if available\n const results = await strategy.batchQueryCookies(validSpecs);\n cookies.push(...results);\n } else {\n // Fall back to parallel individual queries\n const results = await Promise.allSettled(\n validSpecs.map(async (spec) =>\n strategy.queryCookies(spec.name, spec.domain),\n ),\n );\n\n const processed = processIndividualResults(results, continueOnError);\n cookies.push(...processed.cookies);\n errors.push(...processed.errors);\n }\n } catch (error) {\n const err = ensureError(\n error,\n `Failed to query ${strategy.constructor.name}`,\n );\n if (!continueOnError) {\n throw err;\n }\n errors.push(err);\n logger.warn(`Strategy ${strategy.constructor.name} failed`, {\n error: getErrorMessage(err),\n });\n }\n\n return { cookies, errors };\n}\n\n/**\n * Batch query cookies from browser strategies with optimized SQL queries\n * @param specs - Array of cookie specifications to query\n * @param continueOnError - Whether to continue on errors for individual specs\n * @returns Promise resolving to array of exported cookies\n */\nexport async function batchQueryCookies(\n specs: CookieSpec[],\n continueOnError = true,\n): Promise<ExportedCookie[]> {\n // Filter out invalid specs\n const validSpecs = validateSpecs(specs);\n\n if (validSpecs.length === 0) {\n return [];\n }\n\n logger.debug(`Batch querying ${validSpecs.length} cookie specs`);\n\n // Initialize strategies\n const strategies = [\n new ChromeCookieQueryStrategy(),\n new FirefoxCookieQueryStrategy(),\n new SafariCookieQueryStrategy(),\n ];\n\n const allResults: ExportedCookie[] = [];\n const allErrors: Error[] = [];\n\n // Query each strategy with all specs\n for (const strategy of strategies) {\n const { cookies, errors } = await queryStrategy(\n strategy,\n validSpecs,\n continueOnError,\n );\n allResults.push(...cookies);\n allErrors.push(...errors);\n }\n\n if (allErrors.length > 0) {\n logger.debug(`${allErrors.length} errors occurred during batch query`);\n }\n\n return allResults;\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/errorUtils.ts","../src/config.ts","../src/utils/logger.ts","../src/utils/logHelpers.ts","../src/utils/platformUtils.ts","../src/utils/execSimple.ts","../src/core/browsers/chrome/ChromeApplicationSupport.ts","../src/core/browsers/chrome/windows/getChromePassword.ts","../src/core/browsers/chrome/linux/getChromePassword.ts","../src/core/browsers/sql/CookieQueryBuilder.ts","../src/core/browsers/sql/adapters/BunSqliteAdapter.ts","../src/core/browsers/sql/adapters/BetterSqlite3Adapter.ts","../src/core/browsers/CompositeCookieQueryStrategy.ts","../src/utils/flatMapAsync.ts","../src/core/browsers/chromium/BaseChromiumCookieQueryStrategy.ts","../src/utils/ProcessDetector.ts","../src/utils/chromeDates.ts","../src/core/browsers/BaseCookieQueryStrategy.ts","../src/utils/BrowserControl.ts","../src/core/browsers/BrowserLockHandler.ts","../src/utils/FileHandleDetector.ts","../src/core/browsers/platform/PlatformBrowserControl.ts","../src/core/browsers/chrome/decrypt.ts","../src/core/browsers/chrome/windows/decryptV10Cookie.ts","../src/core/browsers/chrome/getChromiumPassword.ts","../src/core/browsers/sql/adapters/DatabaseAdapter.ts","../src/core/browsers/sql/DatabaseConnectionManager.ts","../src/core/browsers/sql/QueryMonitor.ts","../src/core/browsers/listChromeProfiles.ts","../src/core/browsers/chrome/ChromeCookieQueryStrategy.ts","../src/core/browsers/chrome/ChromiumBrowsers.ts","../src/core/browsers/chromium/ChromiumCookieQueryStrategy.ts","../src/core/browsers/firefox/FirefoxCookieQueryStrategy.ts","../src/core/browsers/safari/SafariCookieQueryStrategy.ts","../src/utils/SystemPermissions.ts","../src/core/browsers/safari/BinaryCodableCookies.ts","../src/core/browsers/safari/BinaryCodablePage.ts","../src/types/schemas.ts","../src/core/browsers/safari/BinaryCodableCookie.ts","../src/core/browsers/safari/decodeBinaryCookies.ts","../src/core/cookies/getCookie.ts","../src/core/cookies/queryCookies.ts","../src/core/cookies/batchGetCookies.ts","../src/core/cookies/batchQueryCookies.ts"],"names":["getErrorMessage","error","getErrorDetails","message","result","errorMessageContains","searchText","containsAnyPattern","patterns","pattern","getDatabaseErrorType","DATABASE_ERROR_PATTERNS","formatErrorForLogging","context","details","isError","ensureError","fallbackMessage","standardError","init_errorUtils","__esmMin","EnvironmentSchema","env","init_config","config","z","val","homedir","consola","logger","logger_default","init_logger","createConsola","logError","errorMessage","logWarn","component","createTaggedLogger","init_logHelpers","getPlatform","platformCache","osPlatform","isMacOS","isWindows","isPlatformSupported","p","assertPlatformSupported","init_platformUtils","execSimple","command","options","execPromise","CommandExecutionError","init_execSimple","promisify","exec","originalError","chromeApplicationSupport","init_ChromeApplicationSupport","home","join","getChromePassword_exports","__export","getChromePassword","decryptDPAPIKey","encryptedKey","DPAPI_PREFIX","encryptedData","dpapi","localStatePath","localStateContent","readFileSync","localState","encryptedKeyBuffer","init_getChromePassword","password","CookieQueryBuilder_exports","CookieQueryBuilder","createQueryBuilder","isSqlBrowser","browser","BROWSER_SCHEMAS","init_CookieQueryBuilder","name","domain","exactDomain","limit","includeExpired","schema","selectColumns","whereClause","params","sql","specs","specConditions","allParams","spec","combinedWhere","minLimit","min","key","columns","col","conditions","domainColumn","nowSeconds","sqlKeywords","checkString","str","field","upperStr","keyword","BunSqliteAdapter_exports","BunSqliteAdapter","BunStatement","init_BunSqliteAdapter","statement","filepath","Database","dbOptions","stmt","pragma","pragmaSql","BetterSqlite3Adapter_exports","BetterSqlite3Adapter","BetterSqlite3Statement","init_BetterSqlite3Adapter","BetterSqlite3","flatMapAsync","array","callback","defaultValue","item","CompositeCookieQueryStrategy","strategies","strategy","store","force","parseProcessLine","line","defaultCommand","parts","pidStr","pid","parsedCommand","parseWindowsProcessLine","detectBrowserProcesses","browserName","grepPattern","windowsProcessMap","processName","stdout","processes","lines","processInfo","isFirefoxRunning","isChromeRunning","isSafariRunning","getBrowserConflictAdvice","processCount","browserDisplayName","chromeTimestampToDate","chromeTimestamp","unixTimestampSeconds","fallbackLogger","BaseCookieQueryStrategy","strategyName","taggedLogger","errorDetails","execAsync","isInteractiveEnvironment","isCI","isTest","BROWSER_APP_NAMES","isBrowserRunningMacOS","appName","script","quitBrowserMacOS","quitScript","resolve","saveBrowserSessionMacOS","promptUserConfirmation","rl","readline","answer","closeBrowserGracefully","success","waitForBrowserToClose","maxWaitMs","startTime","checkInterval","execFileAsync","execFile","parseFuserLine","user","mode","isValidProcessResult","value","parsePowerShellOutput","handles","parsed","results","processId","parseError","detectWithLsof","filePath","fd","handle","detectWithFuser","output","detectOnWindows","escapedPath","psScript","detectWithHandleExe","match","detectFileHandles","os","h","getFileLockInfo","BasePlatformBrowserControl","_BasePlatformBrowserControl","executables","exe","checkCommand","args","MacOSBrowserControl","WindowsBrowserControl","LinuxBrowserControl","cmd","platformControlInstance","createPlatformBrowserControl","platformOverride","currentPlatform","control","createControlForPlatform","platform","BrowserLockHandler","platformControl","file","autoClose","dbErrorType","fileHandles","lockInfo","handleError","processError","processesWithDetails","advice","relaunchError","decryptV10Cookie","encryptedValue","VERSION_PREFIX","ciphertext","NONCE_LENGTH","TAG_LENGTH","nonce","authTag","decipher","createDecipheriv","isV10Cookie","memoizeBuffer","fn","keyFn","cache","cachedResult","removeV10Prefix","removePadding","decrypted","padding","extractValue","decodedString","uuidMatch","endPatterns","cleanupPatterns","decrypt","metaVersion","reject","pbkdf2","iv","e","MACOS_KEYCHAIN_SERVICES","getMacOSPassword","service","chromeCommand","getWindowsPassword","getLinuxPassword","getChromiumPassword","detectRuntime","createSqliteDatabase","DatabaseConnectionManager","EventEmitter","now","existing","lastError","attempt","database","metadata","connectionTime","queryFn","queryDescription","connection","duration","metrics","totalQueryTime","totalQueryCount","activeConnections","toClose","lruPath","lruTime","ms","globalManager","exitHandler","getGlobalConnectionManager","QueryMonitor","db","execution","MonitoredStatement","monitor","globalMonitor","getGlobalQueryMonitor","createExportedCookie","expiry","BaseChromiumCookieQueryStrategy","browserType","files","fileResults","connectionManager","queryBuilder","queryOptions","queryConfig","encryptedCookies","row","cookie","cookieFiles","lockResult","shouldRelaunch","cookies","retryError","metaQuery","metaResult","decryptedValue","listChromeProfilePaths","fg","ChromeCookieQueryStrategy","profileName","paths","fs","path","firstPath","chromeDataDir","dirname","profileCache","targetDir","dir","info","cookiePath","getChromiumBrowserPath","ChromiumCookieQueryStrategy","browserPath","findFirefoxCookieFiles","profileDirs","devEditionPath","existsSync","esrPath","localFirefoxPath","matches","FirefoxCookieQueryStrategy","retryConfig","fileList","openFullDiskAccessSettings","getTerminalApp","termProgram","promptForPermissionGrant","handleSafariPermissionError","terminalApp","checkFilePermission","CookieDomainSchema","CookieNameSchema","CookiePathSchema","CookieValueSchema","destr","BinaryCookieRowSchema","CookieSpecSchema","CookieMetaSchema","BrowserNameSchema","CookieQueryStrategySchema","BaseCookieQueryOptionsSchema","SqlBrowserTypeSchema","BinaryCodableCookie","buffer","container","processed","lastProcessed","token","payloadPart","payload","Buffer","primitiveResult","stringValue","decoded","jwtResult","jsonResult","jwtPayload","jsonValue","macTimestamp","flagsValue","expiryUnix","creationUnix","size","version","hasPort","offsets","expirationBuffer","i","expiration","creationBuffer","creation","offsetEntries","entry","a","b","offset","length","end","baseOffset","_BinaryCodablePage","cookieRow","header","cookieCount","pageStart","cookieOffsets","cookieOffset","footer","cookieSize","cookieBuffer","BinaryCodablePage","_BinaryCodableCookies","page","pageCookies","magic","pageCount","pageSizes","pageSize","currentOffset","pageBuffer","checksum","BinaryCodableCookies","decodeBinaryCookies","cookieDbPath","SafariCookieQueryStrategy","flags","bit","formattedDomain","nameMatches","domainMatches","cookieObj","normalizedName","normalizedDomain","firstAttemptResult","queryCookies","cookieSpec","getCookie","validateSpecs","supportsBatchQueries","processIndividualResults","continueOnError","errors","queryStrategy","validSpecs","err","batchQueryCookies","allResults","allErrors","batchGetCookies","deduplicate","concurrency","fallbackToIndividualQueries","deduped","deduplicateCookies","groupCookiesBySpec","allCookies","specCookies","processChunkWithResults","chunk","chunkPromises","batchGetCookiesWithResults","chunkResults","processChunk","cookieMap","existingLength","currentLength"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Utility functions for consistent error handling across the codebase\n * Following DRY principle to eliminate repetitive error handling patterns\n */\n\n/**\n * Safely extract error message from unknown error types\n * @param error - Any thrown value (Error, string, unknown)\n * @returns A string representation of the error\n * @example\n * try {\n * // some operation\n * } catch (error) {\n * const message = getErrorMessage(error);\n * logger.error('Operation failed', { error: message });\n * }\n */\nexport function getErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n if (typeof error === \"string\") {\n return error;\n }\n if (\n error !== null &&\n error !== undefined &&\n typeof error === \"object\" &&\n \"message\" in error\n ) {\n return String(error.message);\n }\n return String(error);\n}\n\n/**\n * Get detailed error information including stack trace\n * @param error - Any thrown value\n * @returns Object with error details\n */\nexport function getErrorDetails(error: unknown): {\n message: string;\n stack?: string;\n name?: string;\n code?: string;\n} {\n const message = getErrorMessage(error);\n\n if (error instanceof Error) {\n const result: ReturnType<typeof getErrorDetails> = { message };\n if (error.stack !== undefined) {\n result.stack = error.stack;\n }\n if (error.name !== undefined) {\n result.name = error.name;\n }\n if (\"code\" in error && error.code !== undefined) {\n result.code = String(error.code);\n }\n return result;\n }\n\n return { message };\n}\n\n/**\n * Check if error message contains specific text (case-insensitive)\n * @param error - Any thrown value\n * @param searchText - Text to search for\n * @returns True if error message contains the text\n */\nexport function errorMessageContains(\n error: unknown,\n searchText: string,\n): boolean {\n const message = getErrorMessage(error).toLowerCase();\n return message.includes(searchText.toLowerCase());\n}\n\n/**\n * Error pattern constants for database error classification\n */\nconst DATABASE_ERROR_PATTERNS = {\n locked: [\"database is locked\", \"database locked\", \"sqlite_busy\"],\n busy: [\"busy\"],\n permission: [\n \"eperm\",\n \"permission denied\",\n \"operation not permitted\",\n \"eacces\",\n ],\n not_found: [\"enoent\", \"no such file\", \"not found\"],\n} as const;\n\n/**\n * Checks if a message contains any of the given patterns\n * @param message - The error message to check\n * @param patterns - Array of patterns to match against\n * @returns True if any pattern is found\n */\nfunction containsAnyPattern(\n message: string,\n patterns: readonly string[],\n): boolean {\n return patterns.some((pattern) => message.includes(pattern));\n}\n\n/**\n * Check if error is a specific type of database error\n * @param error - Any thrown value\n * @returns Type of database error or null\n */\nexport function getDatabaseErrorType(\n error: unknown,\n): \"locked\" | \"busy\" | \"permission\" | \"not_found\" | null {\n const message = getErrorMessage(error).toLowerCase();\n\n if (containsAnyPattern(message, DATABASE_ERROR_PATTERNS.locked)) {\n return \"locked\";\n }\n\n if (containsAnyPattern(message, DATABASE_ERROR_PATTERNS.busy)) {\n return \"busy\";\n }\n\n if (containsAnyPattern(message, DATABASE_ERROR_PATTERNS.permission)) {\n return \"permission\";\n }\n\n if (containsAnyPattern(message, DATABASE_ERROR_PATTERNS.not_found)) {\n return \"not_found\";\n }\n\n return null;\n}\n\n/**\n * Format error for logging with consistent structure\n * @param error - Any thrown value\n * @param context - Additional context for the error\n * @returns Formatted error object for logging\n */\nexport function formatErrorForLogging(\n error: unknown,\n context?: Record<string, unknown>,\n): Record<string, unknown> {\n const details = getErrorDetails(error);\n\n return {\n ...context,\n error: details.message,\n errorName: details.name,\n errorCode: details.code,\n // Only include stack in development/debug mode\n ...(process.env.NODE_ENV !== \"production\" &&\n details.stack !== undefined &&\n details.stack !== \"\"\n ? { errorStack: details.stack }\n : {}),\n };\n}\n\n/**\n * Type guard to check if value is an Error instance\n * @param error - Any value to check\n * @returns True if error is an Error instance\n */\nexport function isError(error: unknown): error is Error {\n return error instanceof Error;\n}\n\n/**\n * Type guard to check if error has a message property\n * @param error - Any value to check\n * @returns True if error has a message property\n */\nexport function hasErrorMessage(error: unknown): error is { message: unknown } {\n return (\n error !== null &&\n error !== undefined &&\n typeof error === \"object\" &&\n \"message\" in error\n );\n}\n\n/**\n * Create a standardized error from unknown input\n * @param error - Any thrown value\n * @param fallbackMessage - Message to use if error can't be converted\n * @returns Error instance\n */\nexport function ensureError(\n error: unknown,\n fallbackMessage = \"An unknown error occurred\",\n): Error {\n if (error instanceof Error) {\n return error;\n }\n\n const message = getErrorMessage(error) || fallbackMessage;\n const standardError = new Error(message);\n\n // Preserve original error as cause if supported\n if (\"cause\" in standardError) {\n standardError.cause = error;\n }\n\n return standardError;\n}\n\n/**\n * Wrap an async operation with consistent error handling\n * @param operation - Async function to execute\n * @param errorHandler - Function to handle errors\n * @returns Result of operation or undefined if error\n */\nexport async function withErrorHandling<T>(\n operation: () => Promise<T>,\n errorHandler: (error: unknown) => void,\n): Promise<T | undefined> {\n try {\n return await operation();\n } catch (error) {\n errorHandler(error);\n return undefined;\n }\n}\n\n/**\n * Retry an operation with exponential backoff\n * @param operation - Async function to execute\n * @param options - Retry options\n * @param options.maxAttempts - Maximum number of retry attempts\n * @param options.initialDelay - Initial delay in milliseconds\n * @param options.maxDelay - Maximum delay in milliseconds\n * @param options.shouldRetry - Function to determine if retry should be attempted\n * @returns Result of successful operation\n */\nexport async function retryWithBackoff<T>(\n operation: () => Promise<T>,\n options: {\n maxAttempts?: number;\n initialDelay?: number;\n maxDelay?: number;\n shouldRetry?: (error: unknown) => boolean;\n } = {},\n): Promise<T> {\n const {\n maxAttempts = 3,\n initialDelay = 100,\n maxDelay = 5000,\n shouldRetry = () => true,\n } = options;\n\n let lastError: unknown;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await operation();\n } catch (error) {\n lastError = error;\n\n if (attempt === maxAttempts || !shouldRetry(error)) {\n throw error;\n }\n\n const delay = Math.min(initialDelay * 2 ** (attempt - 1), maxDelay);\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw lastError;\n}\n","import { homedir } from \"node:os\";\n\nimport { config } from \"dotenv\";\nimport { z } from \"zod\";\n\n// Load environment variables from .env file\nconfig();\n\nconst EnvironmentSchema = z.object({\n LOG_LEVEL: z.enum([\"debug\", \"info\", \"warn\", \"error\"]).default(\"info\"),\n HOME: z\n .string()\n .optional()\n .transform((val) => val ?? process.env.USERPROFILE ?? \"\")\n .pipe(z.string().min(1)),\n});\n\n/**\n * Validated environment variables with type safety and fallbacks\n * @example\n * // Using the environment variables\n * if (env.LOG_LEVEL === \"debug\") {\n * console.log(\"Debug mode enabled\");\n * }\n *\n * // Accessing home directory\n * const cookiePath = join(env.HOME, \"Library/Cookies\");\n */\nexport const env = EnvironmentSchema.parse({\n LOG_LEVEL: process.env.LOG_LEVEL,\n HOME: homedir(),\n});\n","import { type ConsolaInstance, createConsola } from \"consola\";\n\nimport { env } from \"../config\";\n\n/**\n * Standard log levels and their usage:\n * - debug: Detailed information for debugging\n * - info: General operational information\n * - success: Successful operations\n * - warn: Warning conditions\n * - error: Error conditions that might still allow the app to continue\n * - fatal: Critical errors that prevent the app from continuing\n */\nconst consola = createConsola({\n formatOptions: {\n showLogLevel: false,\n colors: true,\n date: false,\n compact: true,\n columns:\n typeof process.stdout.columns === \"number\" ? process.stdout.columns : 80,\n },\n level: env.LOG_LEVEL === \"debug\" ? 5 : 2,\n});\n\n/**\n * Indicates whether debug logging is enabled\n * @example\n * if (isDebug) {\n * logger.debug(\"Detailed debugging information\");\n * }\n */\nexport const isDebug = env.LOG_LEVEL === \"debug\";\n\n/**\n * Configured logger instance with standardized formatting and colored output.\n * Used for consistent logging throughout the application.\n * @example\n * // Basic usage\n * logger.info('Operation started');\n * logger.success('Task completed');\n * logger.error('Failed to process', error);\n *\n * // Tagged logging for module context\n * const moduleLogger = logger.withTag('ModuleName');\n * moduleLogger.info('Module specific log');\n *\n * // Structured logging\n * logger.info('User action', {\n * userId: '123',\n * action: 'login',\n * timestamp: new Date()\n * });\n *\n * // Error logging with full context\n * logger.error('Operation failed', {\n * error: error,\n * context: 'operation name',\n * input: data\n * });\n */\nconst logger: ConsolaInstance = consola;\n\n/**\n *\n */\nexport default logger;\n","import type { ConsolaInstance } from \"consola\";\n\nimport { getErrorMessage } from \"./errorUtils\";\nimport logger from \"./logger\";\n\n/**\n * Helper functions for common logging patterns.\n * @module\n * @example\n * ```typescript\n * import { logOperationResult, logError } from './logHelpers';\n *\n * try {\n * const result = await someOperation();\n * logOperationResult('Operation', true, { data: result });\n * } catch (error) {\n * logError('Operation failed', error);\n * }\n * ```\n */\n\ninterface OperationContext {\n [key: string]: unknown;\n}\n\n/**\n * Log the result of an operation with consistent formatting\n * @param operation - The name of the operation\n * @param success - Whether the operation was successful\n * @param context - Additional context to log\n */\nexport function logOperationResult(\n operation: string,\n success: boolean,\n context?: OperationContext,\n): void {\n if (success) {\n logger.success(`${operation} succeeded`, context);\n } else {\n logger.error(`${operation} failed`, context);\n }\n}\n\n/**\n * Log an error with consistent formatting\n * @param message - The error message\n * @param error - The error object\n * @param context - Additional context to log\n */\nexport function logError(\n message: string,\n error: unknown,\n context?: OperationContext,\n): void {\n const errorMessage = getErrorMessage(error);\n logger.error(message, { ...context, error: errorMessage });\n}\n\n/**\n * Log a warning with consistent formatting\n * @param component - The component generating the warning\n * @param message - The warning message\n * @param context - Additional context to log\n */\nexport function logWarn(\n component: string,\n message: string,\n context?: OperationContext,\n): void {\n logger.warn(`[${component}] ${message}`, context);\n}\n\n/**\n * Create a logger instance with a component tag\n * @param component - The component name to tag logs with\n * @returns A logger instance that prefixes all messages with the component tag\n * @example\n * ```typescript\n * const dbLogger = createTaggedLogger('Database');\n * dbLogger.info('Connection established');\n * ```\n */\nexport function createTaggedLogger(component: string): ConsolaInstance {\n return logger.withTag(component);\n}\n\n// Re-export the base logger for direct usage\n/**\n * Re-export of the base logger for direct usage.\n */\nexport { default as logger } from \"./logger\";\n","import { platform as osPlatform } from \"node:os\";\n\n/**\n * Cache for platform value\n */\nlet platformCache: string | undefined;\n\n/**\n * Clear the platform cache (for testing)\n * @internal\n */\nexport function clearPlatformCache(): void {\n platformCache = undefined;\n}\n\n/**\n * Supported platform types\n */\nexport type Platform = \"darwin\" | \"win32\" | \"linux\";\n\n/**\n * Get the current platform (with caching)\n * @returns The current platform from os.platform()\n */\nexport function getPlatform(): string {\n platformCache ??= osPlatform();\n return platformCache;\n}\n\n/**\n * Check if the current platform is macOS\n * @returns True if running on macOS\n */\nexport function isMacOS(): boolean {\n return getPlatform() === \"darwin\";\n}\n\n/**\n * Check if the current platform is Windows\n * @returns True if running on Windows\n */\nexport function isWindows(): boolean {\n return getPlatform() === \"win32\";\n}\n\n/**\n * Check if the current platform is Linux\n * @returns True if running on Linux\n */\nexport function isLinux(): boolean {\n return getPlatform() === \"linux\";\n}\n\n/**\n * Check if the current platform is Unix-like (macOS, Linux, FreeBSD, etc.)\n * @returns True if running on a Unix-like system\n */\nexport function isUnixLike(): boolean {\n const p = getPlatform();\n return p !== \"win32\";\n}\n\n/**\n * Check if the current platform is supported\n * @returns True if the platform is supported\n */\nexport function isPlatformSupported(): boolean {\n const p = getPlatform();\n return p === \"darwin\" || p === \"win32\" || p === \"linux\";\n}\n\n/**\n * Get a human-readable platform name\n * @returns A human-readable platform name\n */\nexport function getPlatformDisplayName(): string {\n const platform = getPlatform();\n switch (platform) {\n case \"darwin\":\n return \"macOS\";\n case \"win32\":\n return \"Windows\";\n case \"linux\":\n return \"Linux\";\n default:\n return platform;\n }\n}\n\n/**\n * Throw an error if the current platform is not supported\n * @throws Error if platform is not supported\n */\nexport function assertPlatformSupported(): void {\n if (!isPlatformSupported()) {\n throw new Error(\n `Unsupported platform: ${getPlatform()}. Supported platforms are: darwin, win32, linux`,\n );\n }\n}\n\n/**\n * Get platform-specific path separator\n * @returns The path separator for the current platform\n */\nexport function getPathSeparator(): string {\n return isWindows() ? \"\\\\\" : \"/\";\n}\n\n/**\n * Get platform-specific executable extension\n * @returns The executable extension for the current platform\n */\nexport function getExecutableExtension(): string {\n return isWindows() ? \".exe\" : \"\";\n}\n\n/**\n * Check if the current platform matches any of the specified platforms\n * @param platforms - Platform or platforms to check against current platform\n * @returns True if the current platform matches any of the specified platforms\n */\nexport function isPlatform(...platforms: string[]): boolean {\n const current = osPlatform();\n return platforms.includes(current);\n}\n","// External imports\nimport { type ExecOptions, exec } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\n// Internal imports\nimport { getErrorMessage, isError } from \"./errorUtils\";\nimport { logError } from \"./logHelpers\";\n\nconst execPromise = promisify(exec);\n\n/**\n * Custom error class for command execution failures.\n * @property {string} command - The command that failed to execute\n * @property {Error} [originalError] - The underlying error that caused the failure\n * @throws CommandExecutionError Always throws with appropriate error context\n * @example\n * ```typescript\n * throw new CommandExecutionError(\n * 'Command timed out',\n * 'git status',\n * originalError\n * );\n * ```\n */\nclass CommandExecutionError extends Error {\n public constructor(\n message: string,\n public readonly command: string,\n public readonly originalError?: Error,\n ) {\n super(message);\n this.name = \"CommandExecutionError\";\n }\n}\n\n/**\n * Executes a shell command and returns its output.\n * @param command - The command to execute\n * @param options - Optional execution options\n * @returns Promise resolving to command output\n * @throws CommandExecutionError if execution fails\n * @example\n * ```typescript\n * try {\n * const { stdout } = await execSimple('git status');\n * logger.info('Git status:', stdout);\n * } catch (error) {\n * if (error instanceof CommandExecutionError) {\n * logger.error('Git command failed:', error.message);\n * }\n * }\n * ```\n */\nexport async function execSimple(\n command: string,\n options?: ExecOptions,\n): Promise<{ stdout: string; stderr: string }> {\n try {\n const result = await execPromise(command, {\n ...options,\n encoding: \"utf8\",\n });\n return {\n stdout: result.stdout.toString(),\n stderr: result.stderr.toString(),\n };\n } catch (error) {\n logError(\"Command execution failed\", error, { command });\n throw new CommandExecutionError(\n getErrorMessage(error),\n command,\n isError(error) ? error : undefined,\n );\n }\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { assertPlatformSupported, getPlatform } from \"@utils/platformUtils\";\n\n/**\n * The path to Chrome's application support directory for the current platform\n * This constant is used to locate Chrome's profile and cookie storage directories\n * @throws {Error} If unable to determine user's home directory or platform is not supported\n */\nexport const chromeApplicationSupport = (() => {\n const home = homedir();\n if (!home) {\n throw new Error(\"Unable to determine user home directory\");\n }\n\n assertPlatformSupported();\n\n switch (getPlatform()) {\n case \"darwin\":\n return join(home, \"Library\", \"Application Support\", \"Google\", \"Chrome\");\n case \"win32\":\n return join(home, \"AppData\", \"Local\", \"Google\", \"Chrome\", \"User Data\");\n case \"linux\":\n return join(home, \".config\", \"google-chrome\");\n default:\n // This should never happen due to assertPlatformSupported\n throw new Error(`Platform ${getPlatform()} is not supported`);\n }\n})();\n","import { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { getErrorMessage } from \"@utils/errorUtils\";\nimport { isWindows } from \"@utils/platformUtils\";\n\nimport { chromeApplicationSupport } from \"../ChromeApplicationSupport\";\n\n/**\n * Windows Chrome Local State file structure for encrypted key\n */\ninterface WindowsChromeLocalState {\n os_crypt: {\n encrypted_key: string;\n };\n}\n\n/**\n * Decrypts Windows DPAPI encrypted key using Windows CryptoAPI\n * On Windows, Chrome uses DPAPI (Data Protection API) to encrypt the master key\n * which is then used to encrypt cookies.\n * @param encryptedKey - The DPAPI encrypted key buffer\n * @returns A promise that resolves to the decrypted key as a Buffer\n * @throws {Error} If DPAPI decryption fails or key format is invalid\n */\nasync function decryptDPAPIKey(encryptedKey: Buffer): Promise<Buffer> {\n // Remove the DPAPI prefix (first 5 bytes: \"DPAPI\")\n const DPAPI_PREFIX = Buffer.from(\"DPAPI\");\n if (!encryptedKey.subarray(0, 5).equals(DPAPI_PREFIX)) {\n throw new Error(\"Invalid DPAPI key prefix\");\n }\n\n const encryptedData = encryptedKey.subarray(5);\n\n // Try to use native DPAPI if available on Windows\n if (isWindows()) {\n try {\n // Use dynamic import to load optional dependency at runtime\n // This works in both ESM and CommonJS contexts\n const moduleName = \"@primno\" + \"/dpapi\"; // Split to prevent static analysis\n const dpapi = (await import(moduleName)) as {\n unprotectData: (data: Buffer) => Buffer;\n };\n\n if (typeof dpapi.unprotectData === \"function\") {\n return dpapi.unprotectData(encryptedData);\n }\n } catch (error) {\n // Module not available or failed to load - this is expected for optional dependency\n // Don't log the full error to avoid cluttering output\n if (process.env.VERBOSE !== undefined && process.env.VERBOSE !== \"\") {\n console.warn(\"DPAPI module not available:\", error);\n }\n }\n }\n\n // Fallback for testing or when DPAPI is not available\n // This won't work for real encrypted cookies but allows the code to run\n throw new Error(\n \"Windows DPAPI decryption requires native bindings. Install @primno/dpapi package for Windows support.\",\n );\n}\n\n/**\n * Retrieves the Chrome Safe Storage password on Windows\n * On Windows, Chrome stores an encrypted master key in Local State file\n * which is encrypted using Windows DPAPI (Data Protection API)\n * @returns A promise that resolves to the Chrome Safe Storage password\n * @throws {Error} If the password cannot be retrieved from Local State file\n */\nexport async function getChromePassword(): Promise<string> {\n try {\n const localStatePath = join(chromeApplicationSupport, \"Local State\");\n const localStateContent = readFileSync(localStatePath, \"utf8\");\n const localState = JSON.parse(localStateContent) as WindowsChromeLocalState;\n\n if (!localState.os_crypt.encrypted_key) {\n throw new Error(\"No encrypted key found in Chrome Local State\");\n }\n\n // Decode the base64 encrypted key\n const encryptedKeyBuffer = Buffer.from(\n localState.os_crypt.encrypted_key,\n \"base64\",\n );\n\n // Decrypt using DPAPI\n const masterKey = await decryptDPAPIKey(encryptedKeyBuffer);\n\n // Return the key as a buffer (not string) for use in AES-GCM decryption\n return masterKey.toString(\"latin1\");\n } catch (error) {\n throw new Error(\n `Failed to retrieve Chrome password on Windows: ${getErrorMessage(error)}`,\n );\n }\n}\n","import { execSimple } from \"../../../../utils/execSimple\";\n\n/**\n * Attempts to retrieve Chrome password from various Linux keyrings\n *\n * Chrome on Linux can store passwords in:\n * 1. GNOME Keyring (via libsecret)\n * 2. KWallet (KDE)\n * 3. Basic password store (plaintext \"peanuts\")\n * @returns The Chrome Safe Storage password\n */\nexport async function getChromePassword(): Promise<string> {\n // Try different methods in order of preference\n\n // Method 1: Try libsecret (GNOME Keyring)\n try {\n const command =\n \"secret-tool lookup application chrome-libsecret-password-v2 || \" +\n \"secret-tool lookup application chrome\";\n const result = await execSimple(command);\n const password = result.stdout.trim();\n if (password) {\n return password;\n }\n } catch {\n // Continue to next method\n }\n\n // Method 2: Try python keyring module\n try {\n const command =\n \"python3 -c \\\"import keyring; print(keyring.get_password('Chrome Safe Storage', 'Chrome'))\\\"\";\n const result = await execSimple(command);\n const password = result.stdout.trim();\n if (password && password !== \"None\") {\n return password;\n }\n } catch {\n // Continue to next method\n }\n\n // Method 3: Try KWallet (KDE)\n try {\n const command =\n 'kwallet-query kdewallet -f \"Chrome Safe Storage\" -r Chrome';\n const result = await execSimple(command);\n const password = result.stdout.trim();\n if (password) {\n return password;\n }\n } catch {\n // Continue to fallback\n }\n\n // Method 4: Fallback to default password\n // On some Linux systems, Chrome uses a hardcoded password\n return \"peanuts\";\n}\n","/**\n * Unified SQL query builder for cookie database operations\n * Provides a centralized, type-safe way to build SQL queries for different browsers\n */\n\nimport type { SqlCookieQueryOptions } from \"../../../types/schemas\";\n\n/**\n * Browser types that use SQL databases for cookie storage\n */\nexport type SqlBrowserType =\n | \"chrome\"\n | \"chromium\"\n | \"edge\"\n | \"firefox\"\n | \"opera\"\n | \"brave\"\n | \"arc\";\n\n/**\n * SQL query configuration\n */\nexport interface SqlQueryConfig {\n sql: string;\n params: unknown[];\n description?: string;\n}\n\n/**\n * Cookie query options - re-export from schemas for backward compatibility\n */\nexport type CookieQueryOptions = SqlCookieQueryOptions;\n\n/**\n * Database schema information\n */\ninterface BrowserSchema {\n tableName: string;\n nameColumn: string;\n valueColumn: string;\n domainColumn: string;\n expiryColumn: string;\n encryptedValueColumn?: string;\n pathColumn?: string;\n secureColumn?: string;\n httpOnlyColumn?: string;\n}\n\n/**\n * Browser-specific SQL schemas\n */\nconst BROWSER_SCHEMAS: Record<SqlBrowserType, BrowserSchema> = {\n chrome: {\n tableName: \"cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host_key\",\n expiryColumn: \"expires_utc\",\n encryptedValueColumn: \"encrypted_value\",\n pathColumn: \"path\",\n secureColumn: \"is_secure\",\n httpOnlyColumn: \"is_httponly\",\n },\n chromium: {\n tableName: \"cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host_key\",\n expiryColumn: \"expires_utc\",\n encryptedValueColumn: \"encrypted_value\",\n pathColumn: \"path\",\n secureColumn: \"is_secure\",\n httpOnlyColumn: \"is_httponly\",\n },\n edge: {\n tableName: \"cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host_key\",\n expiryColumn: \"expires_utc\",\n encryptedValueColumn: \"encrypted_value\",\n pathColumn: \"path\",\n secureColumn: \"is_secure\",\n httpOnlyColumn: \"is_httponly\",\n },\n opera: {\n tableName: \"cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host_key\",\n expiryColumn: \"expires_utc\",\n encryptedValueColumn: \"encrypted_value\",\n pathColumn: \"path\",\n secureColumn: \"is_secure\",\n httpOnlyColumn: \"is_httponly\",\n },\n brave: {\n tableName: \"cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host_key\",\n expiryColumn: \"expires_utc\",\n encryptedValueColumn: \"encrypted_value\",\n pathColumn: \"path\",\n secureColumn: \"is_secure\",\n httpOnlyColumn: \"is_httponly\",\n },\n arc: {\n tableName: \"cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host_key\",\n expiryColumn: \"expires_utc\",\n encryptedValueColumn: \"encrypted_value\",\n pathColumn: \"path\",\n secureColumn: \"is_secure\",\n httpOnlyColumn: \"is_httponly\",\n },\n firefox: {\n tableName: \"moz_cookies\",\n nameColumn: \"name\",\n valueColumn: \"value\",\n domainColumn: \"host\",\n expiryColumn: \"expiry\",\n pathColumn: \"path\",\n secureColumn: \"isSecure\",\n httpOnlyColumn: \"isHttpOnly\",\n },\n};\n\n/**\n * SQL query builder for cookie operations\n */\nexport class CookieQueryBuilder {\n private readonly schema: BrowserSchema;\n private readonly browser: SqlBrowserType;\n\n /**\n * Creates a new CookieQueryBuilder instance for the specified browser\n * @param browser - The SQL browser type to build queries for\n * @throws {Error} if browser type is not supported\n */\n public constructor(browser: SqlBrowserType) {\n this.browser = browser;\n // Defense-in-depth: validates at runtime in case of type assertions or\n // external callers bypassing TypeScript's compile-time checks\n if (!isSqlBrowser(browser)) {\n throw new Error(`Unsupported browser type: ${browser}`);\n }\n this.schema = BROWSER_SCHEMAS[browser];\n }\n\n /**\n * Build a SELECT query for cookies\n * @param options - Cookie query options including name, domain, and filters\n * @returns SQL query configuration object\n */\n public buildSelectQuery(options: CookieQueryOptions): SqlQueryConfig {\n const { name, domain, exactDomain, limit, includeExpired } = options;\n const schema = this.schema;\n\n // Build SELECT clause based on browser type\n const selectColumns = this.buildSelectColumns();\n\n // Build WHERE clause\n const { whereClause, params } = this.buildWhereClause(\n name,\n domain,\n exactDomain,\n includeExpired,\n );\n\n // Build complete SQL\n let sql = `SELECT ${selectColumns} FROM ${schema.tableName}`;\n if (whereClause) {\n sql += ` WHERE ${whereClause}`;\n }\n\n // Add ORDER BY for consistent results\n sql += ` ORDER BY ${schema.expiryColumn} DESC`;\n\n // Add LIMIT if specified\n if (limit !== undefined && limit > 0) {\n sql += ` LIMIT ${limit}`;\n }\n\n return {\n sql,\n params,\n description: `Query ${this.browser} cookies: name=${name}, domain=${domain}`,\n };\n }\n\n /**\n * Build a batch SELECT query for multiple cookie specs\n * Combines multiple cookie specs into a single query with OR conditions\n * @param specs - Array of cookie query options\n * @returns SQL query configuration object\n * @throws {Error} if specs array is empty\n */\n public buildBatchSelectQuery(specs: CookieQueryOptions[]): SqlQueryConfig {\n if (specs.length === 0) {\n throw new Error(\"At least one spec is required for batch query\");\n }\n\n const schema = this.schema;\n const selectColumns = this.buildSelectColumns();\n\n // Build combined WHERE clause\n const specConditions: string[] = [];\n const allParams: unknown[] = [];\n\n for (const spec of specs) {\n const { whereClause, params } = this.buildWhereClause(\n spec.name,\n spec.domain,\n spec.exactDomain,\n spec.includeExpired,\n );\n\n if (whereClause) {\n // Wrap each spec's conditions in parentheses\n specConditions.push(`(${whereClause})`);\n allParams.push(...params);\n }\n }\n\n // Combine all specs with OR\n const combinedWhere = specConditions.join(\" OR \");\n\n // Build complete SQL\n let sql = `SELECT ${selectColumns} FROM ${schema.tableName}`;\n if (combinedWhere) {\n sql += ` WHERE ${combinedWhere}`;\n }\n\n // Add ORDER BY for consistent results\n sql += ` ORDER BY ${schema.expiryColumn} DESC`;\n\n // Find the minimum limit across all specs (if any have limits)\n const minLimit = specs.reduce(\n (min, spec) => {\n if (spec.limit !== undefined && spec.limit > 0) {\n return min !== undefined ? Math.min(min, spec.limit) : spec.limit;\n }\n return min;\n },\n undefined as number | undefined,\n );\n\n if (minLimit !== undefined && minLimit > 0) {\n sql += ` LIMIT ${minLimit * specs.length}`; // Multiply by specs count to ensure we get enough results\n }\n\n return {\n sql,\n params: allParams,\n description: `Batch query ${this.browser} cookies for ${specs.length} specs`,\n };\n }\n\n /**\n * Build a query to get database metadata\n * @param key - Metadata key to query\n * @returns SQL query configuration for fetching metadata\n * @throws {Error} if browser is Firefox (does not have meta table)\n */\n public buildMetaQuery(key: string): SqlQueryConfig {\n // Only Chromium-based browsers have meta table\n if (this.browser === \"firefox\") {\n throw new Error(\"Firefox does not have a meta table\");\n }\n\n return {\n sql: \"SELECT value FROM meta WHERE key = ?\",\n params: [key],\n description: `Get metadata: ${key}`,\n };\n }\n\n /**\n * Build a query to check if table exists\n * @returns SQL query configuration for checking table existence\n */\n public buildTableExistsQuery(): SqlQueryConfig {\n return {\n sql: \"SELECT name FROM sqlite_master WHERE type='table' AND name=?\",\n params: [this.schema.tableName],\n description: `Check if ${this.schema.tableName} table exists`,\n };\n }\n\n /**\n * Build SELECT columns based on browser\n * @returns Comma-separated list of SELECT columns with aliases\n */\n private buildSelectColumns(): string {\n const schema = this.schema;\n const columns = [\n schema.nameColumn,\n schema.domainColumn,\n schema.expiryColumn,\n ];\n\n // Add encrypted_value for Chromium-based browsers\n if (\n schema.encryptedValueColumn !== undefined &&\n this.browser !== \"firefox\"\n ) {\n columns.push(schema.encryptedValueColumn);\n } else {\n columns.push(schema.valueColumn);\n }\n\n // Add additional columns if available\n if (schema.pathColumn !== undefined) {\n columns.push(schema.pathColumn);\n }\n if (schema.secureColumn !== undefined) {\n columns.push(schema.secureColumn);\n }\n if (schema.httpOnlyColumn !== undefined) {\n columns.push(schema.httpOnlyColumn);\n }\n\n // Use aliases for consistent output\n return columns\n .map((col) => {\n switch (col) {\n case schema.domainColumn:\n return `${col} AS domain`;\n case schema.expiryColumn:\n return `${col} AS expiry`;\n case schema.encryptedValueColumn:\n return `${col} AS encrypted_value`;\n case schema.valueColumn:\n return `${col} AS value`;\n case schema.nameColumn:\n return `${col} AS name`;\n case schema.pathColumn:\n return `${col} AS path`;\n case schema.secureColumn:\n return `${col} AS is_secure`;\n case schema.httpOnlyColumn:\n return `${col} AS is_httponly`;\n default:\n return col;\n }\n })\n .join(\", \");\n }\n\n /**\n * Add domain condition to WHERE clause\n * @param conditions - Array of condition strings\n * @param params - Array of parameter values\n * @param domainColumn - Column name for domain\n * @param domain - Domain value to match\n * @param exactDomain - Whether to use exact matching\n */\n private addDomainCondition(\n conditions: string[],\n params: unknown[],\n domainColumn: string,\n domain: string,\n exactDomain?: boolean,\n ): void {\n if (exactDomain === true) {\n conditions.push(`${domainColumn} = ?`);\n params.push(domain);\n return;\n }\n\n // Optimize domain matching:\n // 1. For domains starting with \".\", use suffix match (more efficient)\n // 2. For regular domains, try to match the domain and subdomains\n if (domain.startsWith(\".\")) {\n // Match exact suffix (e.g., \".github.com\")\n conditions.push(`${domainColumn} LIKE ?`);\n params.push(`%${domain}`);\n } else {\n // Match domain and all subdomains efficiently\n // This matches \"github.com\", \".github.com\", \"api.github.com\", etc.\n conditions.push(\n `(${domainColumn} = ? OR ${domainColumn} = ? OR ${domainColumn} LIKE ?)`,\n );\n params.push(domain, `.${domain}`, `%.${domain}`);\n }\n }\n\n /**\n * Build WHERE clause with proper parameter binding\n * @param name - Cookie name pattern or exact name\n * @param domain - Domain name for filtering\n * @param exactDomain - Whether to use exact domain matching\n * @param includeExpired - Whether to include expired cookies\n * @returns Object containing WHERE clause SQL and parameter values\n */\n private buildWhereClause(\n name: string,\n domain: string,\n exactDomain?: boolean,\n includeExpired?: boolean,\n ): { whereClause: string; params: unknown[] } {\n const schema = this.schema;\n const conditions: string[] = [];\n const params: unknown[] = [];\n\n // Handle name condition\n if (name === \"%\") {\n // Wildcard - no name condition needed\n } else if (name.includes(\"%\") || name.includes(\"_\")) {\n // Pattern matching\n conditions.push(`${schema.nameColumn} LIKE ?`);\n params.push(name);\n } else {\n // Exact match\n conditions.push(`${schema.nameColumn} = ?`);\n params.push(name);\n }\n\n // Handle domain condition\n if (domain !== \"\") {\n this.addDomainCondition(\n conditions,\n params,\n schema.domainColumn,\n domain,\n exactDomain,\n );\n }\n\n // Handle expiry condition\n if (includeExpired !== true) {\n // Firefox uses seconds, Chrome uses microseconds since 1601\n if (this.browser === \"firefox\") {\n // Pre-calculate the timestamp to avoid function call per row\n const nowSeconds = Math.floor(Date.now() / 1000);\n conditions.push(`${schema.expiryColumn} > ?`);\n params.push(nowSeconds);\n } else {\n // Chrome timestamp: microseconds since January 1, 1601\n // We'll let the caller handle the conversion\n conditions.push(`${schema.expiryColumn} > 0`);\n }\n }\n\n return {\n whereClause: conditions.join(\" AND \"),\n params,\n };\n }\n\n /**\n * Validate and sanitize query parameters\n * @param options - Cookie query options to validate\n * @throws {Error} if validation fails\n */\n public static validateQueryParams(options: CookieQueryOptions): void {\n const { name, domain, limit } = options;\n\n // Validate name\n if (typeof name !== \"string\" || name.length === 0) {\n throw new Error(\"Cookie name must be a non-empty string\");\n }\n\n // Validate domain\n if (typeof domain !== \"string\" || domain.length === 0) {\n throw new Error(\"Domain must be a non-empty string\");\n }\n\n // Prevent SQL injection attempts\n const sqlKeywords = [\n \"SELECT\",\n \"INSERT\",\n \"UPDATE\",\n \"DELETE\",\n \"DROP\",\n \"CREATE\",\n \"ALTER\",\n \"--\",\n \";\",\n ];\n const checkString = (str: string, field: string): void => {\n const upperStr = str.toUpperCase();\n for (const keyword of sqlKeywords) {\n if (upperStr.includes(keyword)) {\n throw new Error(\n `Invalid ${field}: contains SQL keyword '${keyword}'`,\n );\n }\n }\n };\n\n checkString(name, \"name\");\n checkString(domain, \"domain\");\n\n // Validate limit\n if (limit !== undefined) {\n if (!Number.isInteger(limit) || limit <= 0 || limit > 10000) {\n throw new Error(\"Limit must be a positive integer between 1 and 10000\");\n }\n }\n }\n\n /**\n * Get browser type for a query builder\n * @returns The SQL browser type\n */\n public getBrowserType(): SqlBrowserType {\n return this.browser;\n }\n\n /**\n * Get schema information\n * @returns A read-only copy of the browser schema\n */\n public getSchema(): Readonly<BrowserSchema> {\n return Object.freeze({ ...this.schema });\n }\n}\n\n/**\n * Factory function for creating query builders\n * @param browser - The SQL browser type to create a builder for\n * @returns A new CookieQueryBuilder instance\n */\nexport function createQueryBuilder(\n browser: SqlBrowserType,\n): CookieQueryBuilder {\n return new CookieQueryBuilder(browser);\n}\n\n/**\n * Check if a browser uses SQL for cookie storage\n * @param browser - Browser name to check\n * @returns True if the browser uses SQL for cookie storage\n */\nexport function isSqlBrowser(browser: string): browser is SqlBrowserType {\n return browser in BROWSER_SCHEMAS;\n}\n","/**\n * Bun:sqlite adapter implementation\n * Wraps bun:sqlite to provide the SqliteDatabase interface\n */\n\nimport type {\n SqliteDatabase,\n SqliteOptions,\n SqliteStatement,\n} from \"./DatabaseAdapter\";\n\n/**\n * Type definitions for Bun's SQLite API\n * These are the minimal interfaces we need from Bun\n */\ninterface BunSqliteStatement {\n all(...params: unknown[]): unknown[];\n get(...params: unknown[]): unknown | undefined;\n run(...params: unknown[]): void;\n}\n\ninterface BunDatabaseOptions {\n readonly?: boolean;\n create?: boolean;\n}\n\ninterface BunSqliteDB {\n prepare(sql: string): BunSqliteStatement;\n exec(sql: string): void;\n close(): void;\n}\n\ninterface BunDatabaseConstructor {\n new (filepath: string, options?: BunDatabaseOptions): BunSqliteDB;\n}\n\n/**\n * Statement wrapper for Bun:sqlite\n */\nclass BunStatement implements SqliteStatement {\n constructor(private readonly statement: BunSqliteStatement) {}\n\n all(...params: unknown[]): unknown[] {\n return this.statement.all(...params);\n }\n\n get(...params: unknown[]): unknown | undefined {\n return this.statement.get(...params);\n }\n\n run(...params: unknown[]): void {\n this.statement.run(...params);\n }\n}\n\n/**\n * Database adapter for Bun:sqlite\n * Implements the SqliteDatabase interface using Bun's built-in SQLite\n */\nexport class BunSqliteAdapter implements SqliteDatabase {\n private readonly db: BunSqliteDB;\n\n readonly?: boolean;\n\n constructor(filepath: string, options: SqliteOptions = {}) {\n // Guard: this adapter must only run inside Bun.\n // When the bundle is loaded in Node.js the class body is evaluated but\n // require(\"bun:sqlite\") would throw ERR_UNSUPPORTED_ESM_URL_SCHEME.\n if (typeof (globalThis as Record<string, unknown>).Bun === \"undefined\") {\n throw new Error(\n \"BunSqliteAdapter can only be used in a Bun runtime environment\",\n );\n }\n\n // Dynamically require Bun's sqlite module\n // eslint-disable-next-line global-require\n const { Database } = require(\"bun:sqlite\") as {\n Database: BunDatabaseConstructor;\n };\n\n // Bun uses 'Database' constructor from bun:sqlite\n // It handles the filepath directly.\n // Bun's default is create: false (won't create new files), but we pass it\n // explicitly when fileMustExist is true to match better-sqlite3 semantics.\n const dbOptions: BunDatabaseOptions = {\n readonly: options.readonly ?? false,\n ...(options.fileMustExist ? { create: false } : {}),\n };\n this.db = new Database(filepath, dbOptions);\n\n this.readonly = options.readonly ?? false;\n }\n\n prepare(sql: string): SqliteStatement {\n const stmt = this.db.prepare(sql);\n return new BunStatement(stmt);\n }\n\n pragma(pragma: string): unknown {\n // Bun uses exec() for PRAGMA statements instead of pragma()\n // Convert \"key = value\" format to \"PRAGMA key = value\"\n const pragmaSql = `PRAGMA ${pragma}`;\n this.db.exec(pragmaSql);\n return undefined;\n }\n\n close(): void {\n this.db.close();\n }\n}\n","/**\n * better-sqlite3 adapter implementation\n * Wraps better-sqlite3 to provide the SqliteDatabase interface\n */\n\nimport BetterSqlite3 from \"better-sqlite3\";\n\nimport type {\n SqliteDatabase,\n SqliteOptions,\n SqliteStatement,\n} from \"./DatabaseAdapter\";\n\n/**\n * Statement wrapper for better-sqlite3\n */\nclass BetterSqlite3Statement implements SqliteStatement {\n constructor(private readonly statement: BetterSqlite3.Statement) {}\n\n all(...params: unknown[]): unknown[] {\n return this.statement.all(...params);\n }\n\n get(...params: unknown[]): unknown | undefined {\n return this.statement.get(...params);\n }\n\n run(...params: unknown[]): void {\n this.statement.run(...params);\n }\n}\n\n/**\n * Database adapter for better-sqlite3 (Node.js)\n * Implements the SqliteDatabase interface using better-sqlite3\n */\nexport class BetterSqlite3Adapter implements SqliteDatabase {\n private readonly db: BetterSqlite3.Database;\n\n readonly?: boolean;\n\n constructor(filepath: string, options: SqliteOptions = {}) {\n this.db = new BetterSqlite3(filepath, {\n readonly: options.readonly ?? false,\n fileMustExist: options.fileMustExist ?? false,\n });\n\n // Set readonly flag on adapter\n this.readonly = options.readonly ?? false;\n }\n\n prepare(sql: string): SqliteStatement {\n const stmt = this.db.prepare(sql);\n return new BetterSqlite3Statement(stmt);\n }\n\n pragma(pragma: string): unknown {\n return this.db.pragma(pragma);\n }\n\n close(): void {\n this.db.close();\n }\n}\n","import { getErrorDetails } from \"@utils/errorUtils\";\nimport { flatMapAsync } from \"@utils/flatMapAsync\";\nimport { createTaggedLogger } from \"@utils/logHelpers\";\n\nimport type {\n BrowserName,\n CookieQueryStrategy,\n ExportedCookie,\n} from \"../../types/schemas\";\n\n/**\n * A composite strategy that combines multiple cookie query strategies.\n * This class implements the CookieQueryStrategy interface and allows querying cookies\n * from multiple browser-specific strategies simultaneously.\n * @example\n * ```typescript\n * const strategy = new CompositeCookieQueryStrategy([\n * new ChromeCookieQueryStrategy(),\n * new FirefoxCookieQueryStrategy(),\n * new SafariCookieQueryStrategy()\n * ]);\n * const cookies = await strategy.queryCookies('sessionId', 'example.com');\n * ```\n */\nexport class CompositeCookieQueryStrategy implements CookieQueryStrategy {\n private readonly logger = createTaggedLogger(\"CompositeCookieQueryStrategy\");\n\n /**\n * The browser name identifier for this strategy\n * @remarks Always returns 'internal' as this is a composite strategy\n */\n public readonly browserName: BrowserName = \"internal\";\n\n /**\n * Creates a new instance of CompositeCookieQueryStrategy\n * @param strategies - Array of browser-specific strategies to use for querying cookies\n * @remarks\n * - Each strategy in the array should implement the CookieQueryStrategy interface\n * - The order of strategies determines the order of cookie querying\n * - Failed strategies will be gracefully handled and skipped\n * @example\n * ```typescript\n * const strategy = new CompositeCookieQueryStrategy([\n * new ChromeCookieQueryStrategy(),\n * new FirefoxCookieQueryStrategy()\n * ]);\n * ```\n */\n public constructor(private readonly strategies: CookieQueryStrategy[]) {}\n\n /**\n * Handles strategy-specific errors and logs them appropriately\n * @internal\n * @param error - The error that occurred during strategy execution\n * @param strategy - The strategy that failed\n */\n private handleStrategyError(\n error: unknown,\n strategy: CookieQueryStrategy,\n ): void {\n this.logger.error(\"Strategy failed\", {\n ...getErrorDetails(error),\n strategy,\n });\n }\n\n /**\n * Queries cookies using all available strategies in parallel\n * @param name - The name pattern to match cookies against\n * @param domain - The domain pattern to match cookies against\n * @param store - The store pattern to match cookies against\n * @param force - Whether to force operations despite warnings (e.g., locked databases)\n * @returns Promise resolving to combined array of cookies from all strategies\n * @remarks\n * - Failures in individual strategies are logged but don't affect other strategies\n * - Results are combined from all successful strategy queries\n * - Empty arrays are returned for failed strategy queries\n * @example\n * ```typescript\n * const strategy = new CompositeCookieQueryStrategy([\n * new ChromeCookieQueryStrategy(),\n * new FirefoxCookieQueryStrategy()\n * ]);\n * const cookies = await strategy.queryCookies('sessionId', 'example.com');\n * console.log(cookies); // Combined results from all browsers\n * ```\n */\n public async queryCookies(\n name: string,\n domain: string,\n store?: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n try {\n this.logger.info(\"Querying cookies from all strategies\", {\n name,\n domain,\n store,\n force,\n strategyCount: this.strategies.length,\n });\n\n /**\n * Use flatMapAsync to process strategies in sequence while collecting results\n * This approach provides better error isolation than Promise.all\n * Each strategy failure is handled independently\n */\n return await flatMapAsync(\n this.strategies,\n async (strategy) => {\n try {\n return await strategy.queryCookies(name, domain, store, force);\n } catch (error) {\n this.handleStrategyError(error, strategy);\n return [];\n }\n },\n [],\n );\n } catch (error) {\n /**\n * Handle top-level errors that may occur during strategy processing\n * This ensures the function always returns an array, even in catastrophic failure\n */\n this.logger.error(\"Failed to query cookies\", {\n ...getErrorDetails(error),\n });\n return [];\n }\n }\n}\n","/**\n * Asynchronously maps over an array and flattens the result.\n * Similar to Array.prototype.flatMap but for async operations.\n * @param array - The input array to map over\n * @param callback - The async mapping function to apply to each element\n * @param defaultValue - The default value to return if the array is empty\n * @returns A flattened array of results\n * @example\n * // Basic usage with number arrays\n * const numbers = [1, 2, 3];\n * const result = await flatMapAsync(\n * numbers,\n * async (num) => [num, num * 2]\n * );\n * console.log(result); // [1, 2, 2, 4, 3, 6]\n * @example\n * // Error handling with default value\n * const data = ['valid', 'invalid'];\n * const result = await flatMapAsync(\n * data,\n * async (item) => {\n * if (item === 'invalid') throw new Error();\n * return [item.toUpperCase()];\n * },\n * ['DEFAULT']\n * );\n * console.log(result); // ['VALID', 'DEFAULT']\n */\nexport async function flatMapAsync<T, U>(\n array: T[],\n callback: (item: T) => Promise<U[]>,\n defaultValue: U[] = [],\n): Promise<U[]> {\n if (array.length === 0) {\n return defaultValue;\n }\n\n const results = await Promise.all(\n array.map(async (item) => {\n try {\n return await callback(item);\n } catch (_error) {\n return defaultValue;\n }\n }),\n );\n return results.flat();\n}\n","import { getErrorMessage } from \"@utils/errorUtils\";\nimport { getPlatform, isPlatformSupported } from \"@utils/platformUtils\";\nimport { isChromeRunning } from \"@utils/ProcessDetector\";\n\nimport type {\n CookieRow,\n CookieSpec,\n ExportedCookie,\n} from \"../../../types/schemas\";\nimport { chromeTimestampToDate } from \"../../../utils/chromeDates\";\nimport { BaseCookieQueryStrategy } from \"../BaseCookieQueryStrategy\";\nimport { BrowserLockHandler } from \"../BrowserLockHandler\";\nimport type { ChromiumBrowser } from \"../chrome/ChromiumBrowsers\";\nimport { decrypt } from \"../chrome/decrypt\";\nimport { getChromiumPassword } from \"../chrome/getChromiumPassword\";\nimport { CookieQueryBuilder } from \"../sql/CookieQueryBuilder\";\nimport { getGlobalConnectionManager } from \"../sql/DatabaseConnectionManager\";\nimport { getGlobalQueryMonitor } from \"../sql/QueryMonitor\";\n\ninterface DecryptionContext {\n file: string;\n password: string | Buffer;\n browser: string;\n metaVersion?: number;\n}\n\n/**\n * Create an exported cookie object\n * @param domain - Cookie domain\n * @param name - Cookie name\n * @param value - Cookie value\n * @param expiry - Cookie expiry timestamp\n * @param file - Source file path\n * @param browser - Browser name\n * @param decrypted - Whether the cookie was decrypted\n * @returns ExportedCookie object\n */\nexport function createExportedCookie(\n domain: string,\n name: string,\n value: string,\n expiry: number | undefined | null,\n file: string,\n browser: string,\n decrypted: boolean,\n): ExportedCookie {\n return {\n domain,\n name,\n value,\n expiry: chromeTimestampToDate(expiry),\n meta: {\n file,\n browser,\n decrypted,\n },\n };\n}\n\n/**\n * Base strategy for querying cookies from Chromium-based browsers.\n * This abstract class provides shared logic for Chrome, Chromium, Brave, Edge, etc.\n */\nexport abstract class BaseChromiumCookieQueryStrategy extends BaseCookieQueryStrategy {\n protected lockHandler: BrowserLockHandler;\n protected browserDisplayName: string;\n protected browserType: ChromiumBrowser;\n\n /**\n * Creates a new instance of BaseChromiumCookieQueryStrategy\n * @param strategyName - Name of the strategy for logging\n * @param browserName - Display name of the browser\n * @param browserType - The Chromium browser type for password retrieval\n */\n public constructor(\n strategyName: string,\n browserName: string,\n browserType: ChromiumBrowser = \"chrome\",\n ) {\n super(strategyName, \"Chrome\"); // Use \"Chrome\" for base class compatibility\n this.browserDisplayName = browserName;\n this.browserType = browserType;\n this.lockHandler = new BrowserLockHandler(this.logger, \"Chrome\");\n }\n\n /**\n * Batch query cookies for multiple specs\n * Optimized to execute combined SQL queries per database file\n * @param specs - Array of cookie specifications\n * @returns Array of exported cookies\n */\n async batchQueryCookies(specs: CookieSpec[]): Promise<ExportedCookie[]> {\n if (!this.isPlatformSupported()) {\n return [];\n }\n\n const files = this.getCookieFiles();\n if (files.length === 0) {\n this.logger.debug(`No ${this.browserDisplayName} cookie files found`);\n return [];\n }\n\n try {\n const password = await getChromiumPassword(this.browserType);\n const results: ExportedCookie[] = [];\n\n for (const file of files) {\n const fileResults = await this.processBatchFile(file, specs, password);\n results.push(...fileResults);\n }\n\n return results;\n } catch (error) {\n this.logger.error(\n `Failed to get ${this.browserDisplayName} password for batch query`,\n {\n error: this.getErrorMessage(error),\n },\n );\n return [];\n }\n }\n\n /**\n * Process a batch of specs for a single cookie file\n * @param file - Cookie file path\n * @param specs - Array of cookie specifications\n * @param password - Decryption password\n * @returns Array of exported cookies\n */\n protected async processBatchFile(\n file: string,\n specs: CookieSpec[],\n password: string | Buffer,\n ): Promise<ExportedCookie[]> {\n try {\n const connectionManager = getGlobalConnectionManager();\n const monitor = getGlobalQueryMonitor();\n const queryBuilder = new CookieQueryBuilder(\"chrome\");\n\n // Convert CookieSpec to CookieQueryOptions\n const queryOptions = specs.map((spec) => ({\n name: spec.name,\n domain: spec.domain,\n browser: \"chrome\" as const,\n }));\n\n const queryConfig = queryBuilder.buildBatchSelectQuery(queryOptions);\n\n const encryptedCookies = await connectionManager.executeQuery(\n file,\n (db) => {\n const rows = monitor.executeQuery<{\n encrypted_value: Buffer;\n name: string;\n domain: string;\n expiry: number;\n }>(db, queryConfig.sql, queryConfig.params, file);\n\n return rows.map(\n (row): CookieRow => ({\n name: row.name,\n domain: row.domain,\n value: row.encrypted_value,\n expiry: row.expiry,\n }),\n );\n },\n queryConfig.description || queryConfig.sql,\n );\n\n const metaVersion = await this.getMetaVersion(file);\n const context: DecryptionContext = {\n file,\n password,\n browser: this.browserDisplayName,\n metaVersion,\n };\n\n const results = await Promise.allSettled(\n encryptedCookies.map(async (cookie) =>\n this.processCookie(cookie, context),\n ),\n );\n\n return results\n .filter(\n (result): result is PromiseFulfilledResult<ExportedCookie> =>\n result.status === \"fulfilled\",\n )\n .map((result) => result.value);\n } catch (error) {\n this.logger.warn(\n `Error batch processing ${this.browserDisplayName} cookie file ${file}`,\n {\n error: this.getErrorMessage(error),\n file,\n specsCount: specs.length,\n },\n );\n return [];\n }\n }\n\n /**\n * Get cookie file paths for the browser\n * @param store - Optional specific store path\n * @returns Array of cookie file paths\n */\n protected abstract getCookieFilePaths(store?: string): string[];\n\n /**\n * Get the browser-specific display name\n * @returns Browser display name\n */\n protected getBrowserName(): string {\n return this.browserDisplayName;\n }\n\n /**\n * Executes the Chromium-specific query logic\n * @param name - The name pattern to match cookies against\n * @param domain - The domain pattern to match cookies against\n * @param store - Optional path to a specific cookie store file\n * @param force - Whether to force operations despite warnings\n * @returns A promise that resolves to an array of exported cookies\n */\n protected async executeQuery(\n name: string,\n domain: string,\n store?: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n if (!this.isPlatformSupported()) {\n return [];\n }\n\n const files = this.getCookieFiles(store);\n if (files.length === 0) {\n this.logger.debug(`No ${this.browserDisplayName} cookie files found`);\n return [];\n }\n\n try {\n const password = await getChromiumPassword(this.browserType);\n const results: ExportedCookie[] = [];\n\n for (const file of files) {\n const fileResults = await this.processFileWithRetry(\n file,\n name,\n domain,\n password,\n force,\n );\n results.push(...fileResults);\n }\n\n return results;\n } catch (error) {\n this.logger.error(`Failed to get ${this.browserDisplayName} password`, {\n error: this.getErrorMessage(error),\n });\n return [];\n }\n }\n\n /**\n * Check if the current platform is supported\n * @returns True if platform is supported\n */\n protected isPlatformSupported(): boolean {\n if (!isPlatformSupported()) {\n this.logger.warn(\"Platform not supported\", {\n platform: getPlatform(),\n supportedPlatforms: [\"darwin\", \"win32\", \"linux\"],\n });\n return false;\n }\n return true;\n }\n\n /**\n * Get cookie files to process\n * @param store - Optional specific store path\n * @returns Array of file paths\n */\n protected getCookieFiles(store?: string): string[] {\n const cookieFiles = store ?? this.getCookieFilePaths();\n return Array.isArray(cookieFiles) ? cookieFiles : [cookieFiles];\n }\n\n /**\n * Convert error to string message\n * Uses error utilities for safe error extraction.\n * @param error - The error to convert\n * @returns Error message string\n */\n protected getErrorMessage(error: unknown): string {\n return getErrorMessage(error);\n }\n\n /**\n * Process a file with retry logic for lock conflicts\n * @param file - Cookie file path\n * @param name - Cookie name pattern\n * @param domain - Domain pattern\n * @param password - Decryption password\n * @param force - Force processing\n * @returns Array of exported cookies\n */\n private async processFileWithRetry(\n file: string,\n name: string,\n domain: string,\n password: string | Buffer,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n try {\n return await this.processFile(file, name, domain, password);\n } catch (error) {\n const lockResult = await this.handleFileError(\n error,\n file,\n name,\n domain,\n force,\n );\n\n if (lockResult.resolved) {\n return this.retryAfterBrowserClose(\n file,\n name,\n domain,\n password,\n lockResult.shouldRelaunch,\n );\n }\n\n return [];\n }\n }\n\n /**\n * Handle file processing errors\n * @param error - The error that occurred\n * @param file - File path\n * @param name - Cookie name pattern\n * @param domain - Domain pattern\n * @param force - Whether to force operations\n * @returns Lock result indicating if resolved and should relaunch\n */\n private async handleFileError(\n error: unknown,\n file: string,\n name: string,\n domain: string,\n force?: boolean,\n ): Promise<{ resolved: boolean; shouldRelaunch: boolean }> {\n const processes = await isChromeRunning();\n const lockResult = await this.lockHandler.handleBrowserConflict(\n error,\n file,\n processes,\n force !== true,\n );\n\n if (!lockResult.resolved) {\n this.logger.warn(\n `Error reading ${this.browserDisplayName} cookie file ${file}`,\n {\n error: this.getErrorMessage(error),\n file,\n name,\n domain,\n },\n );\n }\n\n return lockResult;\n }\n\n /**\n * Retry after browser close\n * @param file - Cookie file path\n * @param name - Cookie name pattern\n * @param domain - Domain pattern\n * @param password - Decryption password\n * @param shouldRelaunch - Whether to relaunch browser\n * @returns Array of exported cookies\n */\n private async retryAfterBrowserClose(\n file: string,\n name: string,\n domain: string,\n password: string | Buffer,\n shouldRelaunch: boolean,\n ): Promise<ExportedCookie[]> {\n try {\n this.logger.info(\n `Retrying ${this.browserDisplayName} cookie extraction after browser close...`,\n );\n const cookies = await this.processFile(file, name, domain, password);\n this.logger.success(\n `Successfully extracted cookies after closing ${this.browserDisplayName}`,\n );\n\n if (shouldRelaunch) {\n await this.lockHandler.relaunchBrowser();\n }\n\n return cookies;\n } catch (retryError) {\n this.logger.error(\n `Failed to extract cookies even after closing ${this.browserDisplayName}`,\n {\n error: this.getErrorMessage(retryError),\n file,\n },\n );\n\n if (shouldRelaunch) {\n await this.lockHandler.relaunchBrowser();\n }\n\n return [];\n }\n }\n\n /**\n * Process a single cookie file\n * @param file - Cookie file path\n * @param name - Cookie name pattern\n * @param domain - Domain pattern\n * @param password - Decryption password\n * @returns Array of exported cookies\n */\n protected async processFile(\n file: string,\n name: string,\n domain: string,\n password: string | Buffer,\n ): Promise<ExportedCookie[]> {\n try {\n // Use SQL utilities directly instead of getEncryptedChromeCookie\n const connectionManager = getGlobalConnectionManager();\n const monitor = getGlobalQueryMonitor();\n const queryBuilder = new CookieQueryBuilder(\"chrome\");\n\n const queryConfig = queryBuilder.buildSelectQuery({\n name,\n domain,\n browser: \"chrome\",\n });\n\n const encryptedCookies = await connectionManager.executeQuery(\n file,\n (db) => {\n // The CookieQueryBuilder aliases columns, so we get 'domain' not 'host_key'\n const rows = monitor.executeQuery<{\n encrypted_value: Buffer;\n name: string;\n domain: string;\n expiry: number;\n }>(db, queryConfig.sql, queryConfig.params, file);\n\n // Transform to CookieRow format\n return rows.map(\n (row): CookieRow => ({\n name: row.name,\n domain: row.domain,\n value: row.encrypted_value,\n expiry: row.expiry,\n }),\n );\n },\n queryConfig.sql,\n );\n\n const metaVersion = await this.getMetaVersion(file);\n const context: DecryptionContext = {\n file,\n password,\n browser: this.browserDisplayName,\n metaVersion,\n };\n\n const results = await Promise.allSettled(\n encryptedCookies.map(async (cookie) =>\n this.processCookie(cookie, context),\n ),\n );\n\n return results\n .map((result) => (result.status === \"fulfilled\" ? result.value : null))\n .filter((cookie): cookie is ExportedCookie => cookie !== null);\n } catch (error) {\n this.logger.error(\n `Failed to process ${this.browserDisplayName} cookie file`,\n {\n error: this.getErrorMessage(error),\n file,\n name,\n domain,\n },\n );\n return [];\n }\n }\n\n /**\n * Get meta version from Chrome database\n * @param file - Database file path\n * @returns Meta version number\n */\n protected async getMetaVersion(file: string): Promise<number> {\n try {\n const connectionManager = getGlobalConnectionManager();\n const queryBuilder = new CookieQueryBuilder(\"chrome\");\n const metaQuery = queryBuilder.buildMetaQuery(\"version\");\n\n const metaResult = await connectionManager.executeQuery(\n file,\n (db) => {\n const stmt = db.prepare(metaQuery.sql);\n return stmt.get(...metaQuery.params) as { value: string } | undefined;\n },\n \"Get meta version\",\n );\n\n return metaResult ? Number.parseInt(metaResult.value, 10) : 0;\n } catch (error) {\n this.logger.debug(\"Could not retrieve meta version, defaulting to 0\", {\n error: this.getErrorMessage(error),\n });\n return 0;\n }\n }\n\n /**\n * Process a single cookie\n * @param cookie - Cookie row from database\n * @param context - Decryption context\n * @returns Exported cookie\n */\n protected async processCookie(\n cookie: CookieRow,\n context: DecryptionContext,\n ): Promise<ExportedCookie> {\n try {\n const value = Buffer.isBuffer(cookie.value)\n ? cookie.value\n : Buffer.from(String(cookie.value));\n\n const decryptedValue = await decrypt(\n value,\n context.password,\n context.metaVersion,\n );\n\n return createExportedCookie(\n cookie.domain,\n cookie.name,\n decryptedValue,\n cookie.expiry,\n context.file,\n context.browser,\n true,\n );\n } catch (error) {\n this.logger.warn(`Failed to decrypt ${context.browser} cookie`, {\n error: this.getErrorMessage(error),\n });\n\n return createExportedCookie(\n cookie.domain,\n cookie.name,\n cookie.value.toString(\"utf-8\"),\n cookie.expiry,\n context.file,\n context.browser,\n false,\n );\n }\n }\n}\n","import { getErrorMessage } from \"./errorUtils\";\nimport { execSimple } from \"./execSimple\";\nimport { createTaggedLogger } from \"./logHelpers\";\nimport { isWindows, getPlatform } from \"./platformUtils\";\n\nconst logger = createTaggedLogger(\"ProcessDetector\");\n\n/**\n * Parse a process line from ps output\n * @param line - The process line from ps output\n * @param defaultCommand - Default command name if parsing fails\n * @returns ProcessInfo if valid, null otherwise\n */\nfunction parseProcessLine(\n line: string,\n defaultCommand: string,\n): ProcessInfo | null {\n const parts = line.trim().split(/\\s+/);\n if (parts.length < 2) {\n return null;\n }\n\n const pidStr = parts[1];\n if (pidStr === undefined || pidStr === \"\") {\n return null;\n }\n\n const pid = Number.parseInt(pidStr, 10);\n if (Number.isNaN(pid)) {\n return null;\n }\n\n const parsedCommand = parts.slice(10).join(\" \");\n return {\n pid,\n command: parsedCommand !== \"\" ? parsedCommand : defaultCommand,\n details: line.trim(),\n };\n}\n\n/**\n * Parse a process line from Windows tasklist CSV output\n * @param line - Process line from tasklist /FO CSV\n * @param defaultCommand - Default command name if parsing fails\n * @returns ProcessInfo if valid, null otherwise\n */\nfunction parseWindowsProcessLine(\n line: string,\n defaultCommand: string,\n): ProcessInfo | null {\n // Windows tasklist CSV format: \"Image Name\",\"PID\",\"Session Name\",\"Session#\",\"Mem Usage\"\n // Example: \"firefox.exe\",\"1234\",\"Console\",\"1\",\"123,456 K\"\n const parts = line.split(\",\").map((p) => p.replace(/\"/g, \"\").trim());\n if (parts.length < 2) {\n return null;\n }\n\n const pidStr = parts[1];\n if (pidStr === undefined || pidStr === \"\") {\n return null;\n }\n\n const pid = Number.parseInt(pidStr, 10);\n if (Number.isNaN(pid)) {\n return null;\n }\n\n return {\n pid,\n command: parts[0] ?? defaultCommand,\n details: line.trim(),\n };\n}\n\n/**\n * Information about a detected process\n */\nexport interface ProcessInfo {\n /** Process ID */\n pid: number;\n /** Process name/command */\n command: string;\n /** Full process details */\n details: string;\n}\n\n/**\n * Generic browser process detection\n * @param browserName - Name of the browser to detect\n * @param grepPattern - Pattern to grep for in ps output\n * @returns Promise that resolves to array of process information\n */\nasync function detectBrowserProcesses(\n browserName: string,\n grepPattern: string,\n): Promise<ProcessInfo[]> {\n try {\n let command: string;\n\n if (isWindows()) {\n // On Windows, use tasklist or wmic to find processes\n // Map common browser names to Windows process names\n const windowsProcessMap: Record<string, string> = {\n firefox: \"firefox.exe\",\n chrome: \"chrome.exe\",\n \"google chrome\": \"chrome.exe\",\n chromium: \"chromium.exe\",\n safari: \"safari.exe\", // Won't exist on Windows but included for consistency\n edge: \"msedge.exe\",\n };\n\n const processName =\n windowsProcessMap[browserName.toLowerCase()] ??\n windowsProcessMap[grepPattern.toLowerCase()] ??\n `${browserName.toLowerCase()}.exe`;\n\n // Use tasklist which is available on all Windows versions\n command = `tasklist /FI \"IMAGENAME eq ${processName}\" /FO CSV | findstr /i \"${processName}\"`;\n } else {\n // Unix-like systems (macOS, Linux)\n command = `ps aux | grep -i '${grepPattern}' | grep -v grep`;\n }\n\n const { stdout } = await execSimple(command);\n\n if (!stdout || stdout.trim() === \"\") {\n return [];\n }\n\n const processes: ProcessInfo[] = [];\n const lines = stdout.split(\"\\n\").filter((line) => line.trim() !== \"\");\n\n for (const line of lines) {\n const processInfo = isWindows()\n ? parseWindowsProcessLine(line, browserName.toLowerCase())\n : parseProcessLine(line, browserName.toLowerCase());\n if (processInfo) {\n processes.push(processInfo);\n }\n }\n\n logger.debug(`${browserName} process detection completed`, {\n processCount: processes.length,\n processes: processes.map((p) => ({ pid: p.pid, command: p.command })),\n platform: getPlatform(),\n });\n\n return processes;\n } catch (error) {\n logger.debug(`Failed to detect ${browserName} processes`, {\n error: getErrorMessage(error),\n platform: getPlatform(),\n });\n return [];\n }\n}\n\n/**\n * Check if Firefox browser is currently running\n * @returns Promise that resolves to array of Firefox process information\n * @example\n * ```typescript\n * const firefoxProcesses = await isFirefoxRunning();\n * if (firefoxProcesses.length > 0) {\n * console.log('Firefox is running, consider closing it for reliable cookie access');\n * }\n * ```\n */\nexport async function isFirefoxRunning(): Promise<ProcessInfo[]> {\n return detectBrowserProcesses(\"Firefox\", \"firefox\");\n}\n\n/**\n * Check if Chrome browser is currently running\n * @returns Promise that resolves to array of Chrome process information\n */\nexport async function isChromeRunning(): Promise<ProcessInfo[]> {\n return detectBrowserProcesses(\"Chrome\", \"google chrome\\\\|chromium\");\n}\n\n/**\n * Check if Safari browser is currently running\n * @returns Promise that resolves to array of Safari process information\n */\nexport async function isSafariRunning(): Promise<ProcessInfo[]> {\n return detectBrowserProcesses(\n \"Safari\",\n \"/Applications/Safari.app/Contents/MacOS/Safari\",\n );\n}\n\n/**\n * Get user-friendly advice for browser conflicts\n * @param browserName - Name of the browser\n * @param processes - Array of detected processes\n * @returns User-friendly message with advice\n */\nexport function getBrowserConflictAdvice(\n browserName: string,\n processes: ProcessInfo[],\n): string {\n if (processes.length === 0) {\n return \"\";\n }\n\n const processCount = processes.length;\n const browserDisplayName =\n browserName.charAt(0).toUpperCase() + browserName.slice(1);\n\n return `${browserDisplayName} is currently running (${processCount} process${processCount > 1 ? \"es\" : \"\"} detected). For reliable cookie access, consider closing ${browserDisplayName} and trying again. Alternatively, use the --force flag to attempt access despite the lock.`;\n}\n","/**\n * Chrome date conversion utilities\n *\n * Chrome/Chromium stores timestamps as microseconds since 1601-01-01 00:00:00 UTC\n * JavaScript Date uses milliseconds since 1970-01-01 00:00:00 UTC\n */\n\n/**\n * The number of seconds between Chrome epoch (1601-01-01) and Unix epoch (1970-01-01)\n * This is 369 years worth of seconds\n */\nexport const CHROME_EPOCH_OFFSET_SECONDS = 11644473600;\n\n/**\n * Microseconds per second\n */\nexport const MICROSECONDS_PER_SECOND = 1000000;\n\n/**\n * Milliseconds per second\n */\nexport const MILLISECONDS_PER_SECOND = 1000;\n\n/**\n * Converts a Chrome timestamp to a JavaScript Date object\n * @param chromeTimestamp - Microseconds since 1601-01-01 00:00:00 UTC\n * @returns JavaScript Date object or \"Infinity\" for session cookies, undefined for null/undefined\n */\nexport function chromeTimestampToDate(\n chromeTimestamp: number | undefined | null,\n): Date | \"Infinity\" | undefined {\n // Handle null or undefined\n if (chromeTimestamp === null || chromeTimestamp === undefined) {\n return undefined;\n }\n\n // Handle invalid numbers\n if (typeof chromeTimestamp !== \"number\" || Number.isNaN(chromeTimestamp)) {\n return undefined;\n }\n\n // Chrome uses 0 for session cookies\n if (chromeTimestamp <= 0) {\n return \"Infinity\";\n }\n\n // Convert Chrome timestamp to Unix timestamp\n const unixTimestampSeconds =\n chromeTimestamp / MICROSECONDS_PER_SECOND - CHROME_EPOCH_OFFSET_SECONDS;\n\n // Sanity check: Unix timestamp should be positive and reasonable\n // Max date: year 3000 (32503680000 seconds since Unix epoch)\n if (unixTimestampSeconds < 0 || unixTimestampSeconds > 32503680000) {\n // Treat unreasonable dates as session cookies\n return \"Infinity\";\n }\n\n // Convert to milliseconds for JavaScript Date\n return new Date(unixTimestampSeconds * MILLISECONDS_PER_SECOND);\n}\n\n/**\n * Converts a JavaScript Date to a Chrome timestamp\n * @param date - JavaScript Date object\n * @returns Microseconds since 1601-01-01 00:00:00 UTC\n */\nexport function dateToChromeTimestamp(date: Date): number {\n if (!(date instanceof Date) || Number.isNaN(date.getTime())) {\n return 0; // Session cookie\n }\n\n // Get Unix timestamp in seconds\n const unixTimestampSeconds = date.getTime() / MILLISECONDS_PER_SECOND;\n\n // Convert to Chrome timestamp\n const chromeTimestampSeconds =\n unixTimestampSeconds + CHROME_EPOCH_OFFSET_SECONDS;\n\n // Convert to microseconds\n return chromeTimestampSeconds * MICROSECONDS_PER_SECOND;\n}\n\n/**\n * Checks if a Chrome timestamp represents a session cookie\n * @param chromeTimestamp - Microseconds since 1601-01-01 00:00:00 UTC\n * @returns True if this is a session cookie (no expiry)\n */\nexport function isChromeSessionCookie(\n chromeTimestamp: number | undefined | null,\n): boolean {\n return (\n chromeTimestamp === null ||\n chromeTimestamp === undefined ||\n chromeTimestamp === 0 ||\n (typeof chromeTimestamp === \"number\" && chromeTimestamp <= 0) ||\n // Far future dates (like year 4000) are treated as session cookies by Chrome\n (typeof chromeTimestamp === \"number\" &&\n chromeTimestamp >= 64092211200 * MICROSECONDS_PER_SECOND)\n );\n}\n\n/**\n * Formats a Chrome timestamp for display\n * @param chromeTimestamp - Microseconds since 1601-01-01 00:00:00 UTC\n * @returns Human-readable string representation\n */\nexport function formatChromeTimestamp(\n chromeTimestamp: number | undefined | null,\n): string {\n if (isChromeSessionCookie(chromeTimestamp)) {\n return \"Session\";\n }\n\n const date = chromeTimestampToDate(chromeTimestamp);\n\n if (date === undefined) {\n return \"Session\";\n }\n\n if (date === \"Infinity\") {\n return \"Session\";\n }\n\n return date.toISOString();\n}\n","import { getErrorDetails } from \"@utils/errorUtils\";\nimport { createTaggedLogger } from \"@utils/logHelpers\";\n\nimport type {\n BrowserName,\n CookieQueryStrategy,\n ExportedCookie,\n} from \"../../types/schemas\";\n\n// Create a simple fallback logger for tests\nconst fallbackLogger = {\n info: () => {},\n warn: () => {},\n error: () => {},\n debug: () => {},\n success: () => {},\n fatal: () => {},\n log: () => {},\n};\n\n/**\n * Base class for cookie query strategies.\n * Provides common functionality and standardized error handling for browser-specific implementations.\n * @implements {CookieQueryStrategy}\n * @abstract\n */\nexport abstract class BaseCookieQueryStrategy implements CookieQueryStrategy {\n /**\n * Logger instance for this strategy\n * @protected\n */\n protected readonly logger;\n\n /**\n * Creates a new instance of BaseCookieQueryStrategy\n * @param strategyName - The name of the strategy for logging purposes\n * @param browserName - The name of the browser this strategy is for\n */\n public constructor(\n strategyName: string,\n public readonly browserName: BrowserName,\n ) {\n const taggedLogger = createTaggedLogger(strategyName);\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, @typescript-eslint/strict-boolean-expressions\n this.logger = taggedLogger || fallbackLogger;\n }\n\n /**\n * Queries cookies from the browser's cookie store\n * @param name - The name pattern to match cookies against\n * @param domain - The domain pattern to match cookies against\n * @param store - Optional path to a specific cookie store file\n * @param force - Whether to force operations despite warnings (e.g., locked databases)\n * @returns A promise that resolves to an array of exported cookies\n */\n public async queryCookies(\n name: string,\n domain: string,\n store?: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n try {\n this.logger.info(\"Querying cookies\", { name, domain, store, force });\n return await this.executeQuery(name, domain, store, force);\n } catch (error) {\n const errorDetails = getErrorDetails(error);\n this.logger.error(\"Failed to query cookies\", {\n ...errorDetails,\n browser: this.browserName,\n strategy: this.constructor.name,\n name,\n domain,\n store,\n force,\n });\n return [];\n }\n }\n\n /**\n * Executes the browser-specific query logic\n * @abstract\n * @param name - The name pattern to match cookies against\n * @param domain - The domain pattern to match cookies against\n * @param store - Optional path to a specific cookie store file\n * @param force - Whether to force operations despite warnings (e.g., locked databases)\n * @returns A promise that resolves to an array of exported cookies\n * @protected\n */\n protected abstract executeQuery(\n name: string,\n domain: string,\n store?: string,\n force?: boolean,\n ): Promise<ExportedCookie[]>;\n}\n","import { exec } from \"node:child_process\";\nimport readline from \"node:readline\";\nimport { promisify } from \"node:util\";\n\nimport type { BrowserName } from \"../types/schemas\";\n\nimport { createTaggedLogger } from \"./logHelpers\";\nimport { isMacOS } from \"./platformUtils\";\n\n// Re-export BrowserName from schemas for backward compatibility\n/**\n *\n */\nexport type { BrowserName } from \"../types/schemas\";\n\nconst execAsync = promisify(exec);\nconst logger = createTaggedLogger(\"BrowserControl\");\n\n/**\n * Check if the current environment supports interactive prompts\n * @returns True if environment can handle interactive prompts\n */\nfunction isInteractiveEnvironment(): boolean {\n const isCI = process.env.CI === \"true\" || process.env.CI === \"1\";\n const isTest =\n process.env.NODE_ENV === \"test\" || process.env.JEST_WORKER_ID !== undefined;\n const hasTTY = process.stdin.isTTY && process.stdout.isTTY;\n\n return hasTTY && !isCI && !isTest;\n}\n\n/**\n *\n */\nexport interface BrowserControlOptions {\n force?: boolean;\n interactive?: boolean;\n}\n\n/**\n * Map of browser names to their macOS application names\n * Only includes browsers that can be controlled on macOS\n */\nconst BROWSER_APP_NAMES: Partial<Record<BrowserName, string>> = {\n Firefox: \"Firefox\",\n Chrome: \"Google Chrome\",\n Safari: \"Safari\",\n};\n\n/**\n * Check if a browser is running on macOS\n * @param browserName - Name of the browser to check\n * @returns Promise that resolves to true if browser is running\n */\nasync function isBrowserRunningMacOS(\n browserName: BrowserName,\n): Promise<boolean> {\n try {\n const appName = BROWSER_APP_NAMES[browserName];\n if (!appName) {\n logger.debug(\"Browser not supported for macOS control\", { browserName });\n return false;\n }\n const script = `tell application \"System Events\" to (name of processes) contains \"${appName}\"`;\n const { stdout } = await execAsync(`osascript -e '${script}'`);\n return stdout.trim() === \"true\";\n } catch (error) {\n logger.debug(\"Failed to check if browser is running\", {\n browserName,\n error,\n });\n return false;\n }\n}\n\n/**\n * Gracefully quit a browser on macOS\n * @param browserName - Name of the browser to quit\n * @returns Promise that resolves to true if browser was quit successfully\n */\nasync function quitBrowserMacOS(browserName: BrowserName): Promise<boolean> {\n try {\n const appName = BROWSER_APP_NAMES[browserName];\n if (!appName) {\n logger.debug(\"Browser not supported for macOS control\", { browserName });\n return false;\n }\n\n // First, try to quit gracefully\n const quitScript = `tell application \"${appName}\" to quit`;\n await execAsync(`osascript -e '${quitScript}'`);\n\n // Wait a moment for the browser to quit\n await new Promise((resolve) => setTimeout(resolve, 2000));\n\n // Check if it's still running\n const stillRunning = await isBrowserRunningMacOS(browserName);\n if (!stillRunning) {\n logger.info(\"Browser quit successfully\", { browserName });\n return true;\n }\n\n logger.warn(\"Browser did not quit gracefully\", { browserName });\n return false;\n } catch (error) {\n logger.error(\"Failed to quit browser\", { browserName, error });\n return false;\n }\n}\n\n/**\n * Save open tabs in browser before closing (macOS only)\n * This will attempt to save the session so tabs can be restored\n * @param browserName - Name of the browser\n * @returns Promise that resolves when tabs are saved\n */\nasync function saveBrowserSessionMacOS(\n browserName: BrowserName,\n): Promise<void> {\n try {\n const appName = BROWSER_APP_NAMES[browserName];\n if (!appName) {\n logger.debug(\"Browser not supported for macOS control\", { browserName });\n return;\n }\n\n if (browserName === \"Firefox\") {\n // Firefox: Use keyboard shortcut to save session (Cmd+Shift+D to bookmark all tabs)\n const script = `\n tell application \"${appName}\"\n activate\n end tell\n tell application \"System Events\"\n keystroke \"d\" using {command down, shift down}\n delay 0.5\n key code 36\n end tell\n `;\n await execAsync(`osascript -e '${script}'`);\n logger.debug(\"Attempted to save Firefox session\", { browserName });\n } else if (browserName === \"Chrome\") {\n // Chrome will restore tabs automatically if quit gracefully\n logger.debug(\"Chrome will restore tabs automatically\", { browserName });\n } else {\n // Safari will restore tabs if quit gracefully\n logger.debug(\"Safari will restore tabs automatically\", { browserName });\n }\n } catch (error) {\n logger.debug(\"Failed to save browser session\", { browserName, error });\n }\n}\n\n/**\n * Prompt user for confirmation before closing browser\n * @param browserName - Name of the browser\n * @returns Promise that resolves to true if user confirms\n */\nasync function promptUserConfirmation(\n browserName: BrowserName,\n): Promise<boolean> {\n // Check if we're in a TTY-capable environment\n if (!isInteractiveEnvironment()) {\n logger.debug(\"Non-interactive environment detected, skipping prompt\", {\n browserName,\n CI: process.env.CI,\n NODE_ENV: process.env.NODE_ENV,\n JEST_WORKER_ID: process.env.JEST_WORKER_ID,\n stdin_tty: process.stdin.isTTY,\n stdout_tty: process.stdout.isTTY,\n });\n return false;\n }\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n rl.question(\n `\\n⚠️ ${browserName} is currently running and blocking cookie access.\\n` +\n `Would you like to close ${browserName}? Your tabs will be restored when you reopen it. (y/N): `,\n (answer) => {\n rl.close();\n resolve(answer.toLowerCase() === \"y\" || answer.toLowerCase() === \"yes\");\n },\n );\n });\n}\n\n/**\n * Relaunch a browser after it has been closed\n * @param browserName - Name of the browser to relaunch\n * @returns Promise that resolves to true if browser was relaunched\n */\nasync function relaunchBrowserMacOS(\n browserName: BrowserName,\n): Promise<boolean> {\n try {\n const appName = BROWSER_APP_NAMES[browserName];\n\n // Launch the browser\n const launchScript = `tell application \"${appName}\" to activate`;\n await execAsync(`osascript -e '${launchScript}'`);\n\n // Give it a moment to start\n await new Promise((resolve) => setTimeout(resolve, 3000));\n\n // Check if it's running\n const isRunning = await isBrowserRunningMacOS(browserName);\n if (isRunning) {\n logger.info(\"Browser relaunched successfully\", { browserName });\n return true;\n }\n\n logger.warn(\"Browser did not relaunch\", { browserName });\n return false;\n } catch (error) {\n logger.error(\"Failed to relaunch browser\", { browserName, error });\n return false;\n }\n}\n\n/**\n * Attempt to close a browser gracefully\n * @param browserName - Name of the browser to close\n * @param options - Control options\n * @returns Promise that resolves to true if browser was closed\n */\nexport async function closeBrowserGracefully(\n browserName: BrowserName,\n options: BrowserControlOptions = {},\n): Promise<boolean> {\n if (!isMacOS()) {\n logger.debug(\"Browser control only supported on macOS\");\n return false;\n }\n\n try {\n // Check if browser is running\n const isRunning = await isBrowserRunningMacOS(browserName);\n if (!isRunning) {\n logger.debug(\"Browser is not running\", { browserName });\n return true;\n }\n\n // If interactive mode, prompt user\n if (options.interactive === true && options.force !== true) {\n const confirmed = await promptUserConfirmation(browserName);\n if (!confirmed) {\n logger.info(\"User cancelled browser close\", { browserName });\n return false;\n }\n }\n\n // Try to save session first (for browsers that support it)\n await saveBrowserSessionMacOS(browserName);\n\n // Quit the browser\n const success = await quitBrowserMacOS(browserName);\n\n if (success) {\n logger.success(\n `${browserName} closed successfully. Tabs will be restored on next launch.`,\n );\n } else {\n logger.warn(\n `Failed to close ${browserName}. You may need to close it manually.`,\n );\n }\n\n return success;\n } catch (error) {\n logger.error(\"Failed to control browser\", { browserName, error });\n return false;\n }\n}\n\n/**\n * Close browser, perform an action, then relaunch the browser\n * @param browserName - Name of the browser\n * @param action - Action to perform while browser is closed\n * @param options - Control options\n * @returns Promise that resolves to the result of the action\n */\nexport async function closeBrowserForAction<T>(\n browserName: BrowserName,\n action: () => Promise<T>,\n options: BrowserControlOptions = {},\n): Promise<T | null> {\n if (!isMacOS()) {\n logger.debug(\"Browser control only supported on macOS\");\n return null;\n }\n\n let browserWasClosed = false;\n\n try {\n // Check if browser is running\n const wasRunning = await isBrowserRunningMacOS(browserName);\n\n if (wasRunning) {\n // Close the browser\n browserWasClosed = await closeBrowserGracefully(browserName, options);\n\n if (!browserWasClosed) {\n logger.warn(\"Failed to close browser, attempting action anyway\");\n } else {\n // Wait for browser to fully close\n await waitForBrowserToClose(browserName, 5000);\n }\n }\n\n // Perform the action\n const result = await action();\n\n // Relaunch browser if we closed it\n if (wasRunning && browserWasClosed) {\n logger.info(`Relaunching ${browserName}...`);\n const relaunched = await relaunchBrowserMacOS(browserName);\n\n if (relaunched) {\n logger.success(\n `${browserName} has been relaunched with your tabs restored`,\n );\n } else {\n logger.warn(\n `Could not relaunch ${browserName} automatically. Please reopen it manually.`,\n );\n }\n }\n\n return result;\n } catch (error) {\n logger.error(\"Failed during browser action\", { browserName, error });\n\n // Try to relaunch browser if we closed it\n if (browserWasClosed) {\n await relaunchBrowserMacOS(browserName);\n }\n\n return null;\n }\n}\n\n/**\n * Wait for a browser to close\n * @param browserName - Name of the browser\n * @param maxWaitMs - Maximum time to wait in milliseconds\n * @returns Promise that resolves to true if browser closed within timeout\n */\nexport async function waitForBrowserToClose(\n browserName: BrowserName,\n maxWaitMs = 10000,\n): Promise<boolean> {\n if (!isMacOS()) {\n return false;\n }\n\n const startTime = Date.now();\n const checkInterval = 500;\n\n while (Date.now() - startTime < maxWaitMs) {\n const isRunning = await isBrowserRunningMacOS(browserName);\n if (!isRunning) {\n return true;\n }\n await new Promise((resolve) => setTimeout(resolve, checkInterval));\n }\n\n return false;\n}\n","import {\n type BrowserName,\n closeBrowserGracefully,\n waitForBrowserToClose,\n} from \"@utils/BrowserControl\";\nimport {\n getDatabaseErrorType,\n getErrorMessage,\n isError,\n} from \"@utils/errorUtils\";\nimport { detectFileHandles, getFileLockInfo } from \"@utils/FileHandleDetector\";\nimport type { createTaggedLogger } from \"@utils/logHelpers\";\nimport { getBrowserConflictAdvice } from \"@utils/ProcessDetector\";\n\nimport {\n createPlatformBrowserControl,\n type PlatformBrowserControl,\n} from \"./platform/PlatformBrowserControl\";\n\n/**\n * Result of a browser conflict handling operation\n */\nexport interface BrowserLockResult {\n /** Whether the conflict was resolved */\n resolved: boolean;\n /** Whether the browser should be relaunched */\n shouldRelaunch: boolean;\n}\n\n/**\n * Shared handler for browser lock/permission issues\n * Follows DRY principle to avoid duplicating logic across browser strategies\n * Uses Strategy pattern for platform-specific operations\n */\nexport class BrowserLockHandler {\n private readonly platformControl: PlatformBrowserControl;\n\n /**\n * Creates a new BrowserLockHandler instance\n * @param logger - Tagged logger instance for this handler\n * @param browserName - Name of the browser this handler manages\n * @param platformControl - Optional platform control strategy (for testing)\n */\n public constructor(\n private readonly logger: ReturnType<typeof createTaggedLogger>,\n private readonly browserName: BrowserName,\n platformControl?: PlatformBrowserControl,\n ) {\n // Use provided control or create platform-specific one\n this.platformControl = platformControl ?? createPlatformBrowserControl();\n }\n\n /**\n * Handle database lock or permission errors\n * @param error - The error to check\n * @param file - The file that was locked/inaccessible\n * @param processes - Running processes for this browser\n * @param autoClose - Whether to attempt auto-closing the browser\n * @returns Promise that resolves to lock result\n */\n public async handleBrowserConflict(\n error: unknown,\n file: string,\n processes: Array<{ pid: number; command: string }>,\n autoClose = false,\n ): Promise<BrowserLockResult> {\n if (!isError(error)) {\n return { resolved: false, shouldRelaunch: false };\n }\n\n if (!this.isLockError(error)) {\n return { resolved: false, shouldRelaunch: false };\n }\n\n await this.logFileHandleInfo(file, processes);\n return this.handleProcessConflict(file, processes, autoClose);\n }\n\n /**\n * Check if an error indicates a database lock or permission issue\n * @param error - The error to check\n * @returns True if this is a lock-related error\n */\n private isLockError(error: Error): boolean {\n const dbErrorType = getDatabaseErrorType(error);\n return dbErrorType === \"locked\" || dbErrorType === \"permission\";\n }\n\n /**\n * Log detailed file handle information\n * @param file - The file that was locked\n * @param processes - Browser processes detected\n */\n private async logFileHandleInfo(\n file: string,\n processes: Array<{ pid: number; command: string }>,\n ): Promise<void> {\n try {\n const fileHandles = await detectFileHandles(file);\n\n if (fileHandles.length > 0) {\n const lockInfo = await getFileLockInfo(file);\n\n this.logger.debug(\"Database locked by specific processes\", {\n file,\n lockInfo,\n handleCount: fileHandles.length,\n handles: fileHandles.map((h) => ({\n pid: h.pid,\n command: h.command,\n mode: h.mode,\n user: h.user,\n })),\n });\n\n if (processes.length === 0) {\n this.logger.info(\n \"File is locked but no browser processes detected - another tool may be accessing the database\",\n {\n lockingProcesses: fileHandles\n .map((h) => `${h.command} (PID: ${h.pid})`)\n .join(\", \"),\n },\n );\n }\n }\n } catch (handleError) {\n this.logger.debug(\"Could not detect file handles\", {\n error:\n handleError instanceof Error\n ? handleError.message\n : String(handleError),\n });\n }\n }\n\n /**\n * Handle process conflicts and optionally close the browser\n * @param file - The file that was locked\n * @param processes - Browser processes detected\n * @param autoClose - Whether to attempt auto-closing\n * @returns Promise that resolves to lock result\n */\n private async handleProcessConflict(\n file: string,\n processes: Array<{ pid: number; command: string }>,\n autoClose: boolean,\n ): Promise<BrowserLockResult> {\n try {\n if (processes.length > 0) {\n return await this.handleBrowserProcesses(file, processes, autoClose);\n }\n\n this.logger.debug(\n \"Database/file locked but no browser processes detected\",\n {\n file,\n browserName: this.browserName,\n suggestion: \"Another process may be accessing the file\",\n },\n );\n } catch (processError) {\n this.logger.debug(\"Failed to check browser processes\", {\n error:\n processError instanceof Error\n ? processError.message\n : String(processError),\n });\n }\n\n return { resolved: false, shouldRelaunch: false };\n }\n\n /**\n * Handle detected browser processes\n * @param file - The file that was locked\n * @param processes - Browser processes detected\n * @param autoClose - Whether to attempt auto-closing\n * @returns Promise that resolves to lock result\n */\n private async handleBrowserProcesses(\n file: string,\n processes: Array<{ pid: number; command: string }>,\n autoClose: boolean,\n ): Promise<BrowserLockResult> {\n const processesWithDetails = processes.map((p) => ({\n ...p,\n details: `PID: ${p.pid}, Command: ${p.command}`,\n }));\n\n const advice = getBrowserConflictAdvice(\n this.browserName.toLowerCase(),\n processesWithDetails,\n );\n\n this.logger.debug(`${this.browserName} process conflict detected`, {\n file,\n processCount: processes.length,\n advice,\n });\n\n if (autoClose) {\n return this.attemptBrowserClose();\n }\n\n return Promise.resolve({ resolved: false, shouldRelaunch: false });\n }\n\n /**\n * Attempt to close the browser gracefully\n * @returns Promise that resolves to lock result\n */\n private async attemptBrowserClose(): Promise<BrowserLockResult> {\n this.logger.info(`Attempting to close ${this.browserName} gracefully...`);\n\n const closed = await closeBrowserGracefully(this.browserName, {\n interactive: true,\n force: false,\n });\n\n if (closed) {\n await waitForBrowserToClose(this.browserName, 5000);\n return { resolved: true, shouldRelaunch: true };\n }\n\n return { resolved: false, shouldRelaunch: false };\n }\n\n /**\n * Relaunch browser after successful operation\n * @returns Promise that resolves when browser is relaunched\n */\n public async relaunchBrowser(): Promise<void> {\n this.logger.info(`Relaunching ${this.browserName}...`);\n\n try {\n // Check if browser is supported on this platform\n if (!this.platformControl.isBrowserSupported(this.browserName)) {\n this.logger.debug(\n `${this.browserName} is not available on ${this.platformControl.getPlatformName()}`,\n );\n return;\n }\n\n // Use platform-specific strategy to launch browser\n await this.platformControl.launchBrowser(this.browserName);\n\n this.logger.success(\n `${this.browserName} has been relaunched with your tabs restored`,\n );\n } catch (relaunchError) {\n this.logger.debug(\n `Could not relaunch ${this.browserName} automatically`,\n {\n error: getErrorMessage(relaunchError),\n platform: this.platformControl.getPlatformName(),\n },\n );\n }\n }\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nimport { errorMessageContains, getErrorMessage } from \"./errorUtils\";\nimport { createTaggedLogger } from \"./logHelpers\";\nimport { getPlatform, isWindows } from \"./platformUtils\";\n\nconst execFileAsync = promisify(execFile);\nconst logger = createTaggedLogger(\"FileHandleDetector\");\n\n/**\n * Parse a fuser output line into FileHandleInfo\n * @param line - Line from fuser output\n * @returns FileHandleInfo or null if parsing fails\n */\nfunction parseFuserLine(line: string): FileHandleInfo | null {\n const parts = line.trim().split(/\\s+/);\n if (parts.length < 2) {\n return null;\n }\n\n const pidStr = parts[1];\n if (pidStr === undefined || pidStr === \"\") {\n return null;\n }\n\n const pid = Number.parseInt(pidStr, 10);\n if (Number.isNaN(pid)) {\n return null;\n }\n\n const result: FileHandleInfo = {\n pid: pid,\n command: parts[2] ?? \"unknown\",\n };\n\n const user = parts[0];\n if (user !== undefined && user !== \"\") {\n result.user = user;\n }\n\n const mode = parts[3];\n if (mode !== undefined && mode !== \"\") {\n result.mode = mode;\n }\n\n return result;\n}\n\n/**\n * Check if value is a valid process result object\n * @param value - Value to check\n * @returns True if valid process result\n */\nfunction isValidProcessResult(\n value: unknown,\n): value is Record<string, unknown> {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"ProcessId\" in value &&\n \"ProcessName\" in value\n );\n}\n\n/**\n * Parse PowerShell output into FileHandleInfo array\n * @param stdout - PowerShell command output\n * @returns Array of FileHandleInfo\n */\nfunction parsePowerShellOutput(stdout: string): FileHandleInfo[] {\n const handles: FileHandleInfo[] = [];\n\n try {\n const parsed: unknown = JSON.parse(stdout);\n const results = Array.isArray(parsed) ? parsed : [parsed];\n\n for (const result of results) {\n if (!isValidProcessResult(result)) {\n continue;\n }\n\n const processId = result.ProcessId;\n const processName = result.ProcessName;\n\n if (typeof processId === \"string\" && processId !== \"\") {\n handles.push({\n command: typeof processName === \"string\" ? processName : \"unknown\",\n pid: Number.parseInt(processId, 10),\n });\n }\n }\n } catch (parseError) {\n logger.debug(\"Failed to parse PowerShell output\", {\n error: getErrorMessage(parseError),\n });\n }\n\n return handles;\n}\n\n/**\n * Information about a process holding a file handle\n */\nexport interface FileHandleInfo {\n /** Process ID */\n pid: number;\n /** Process name/command */\n command: string;\n /** User running the process */\n user?: string;\n /** File descriptor or handle type */\n fd?: string;\n /** Access mode (read, write, etc.) */\n mode?: string;\n}\n\n/**\n * Detect processes holding handles to a specific file using lsof\n * SECURITY: Uses execFile to prevent shell injection\n * @param filePath - Path to the file to check\n * @returns Array of processes holding handles to the file\n */\nasync function detectWithLsof(filePath: string): Promise<FileHandleInfo[]> {\n try {\n // Use execFile instead of exec to prevent shell injection\n const { stdout } = await execFileAsync(\"lsof\", [filePath], {\n encoding: \"utf8\",\n });\n\n if (!stdout || stdout.trim() === \"\") {\n return [];\n }\n\n const lines = stdout.split(\"\\n\").slice(1); // Skip header\n const handles: FileHandleInfo[] = [];\n\n for (const line of lines) {\n const parts = line.trim().split(/\\s+/);\n const command = parts[0];\n const pidStr = parts[1];\n const user = parts[2];\n const fd = parts[3];\n\n if (\n command !== undefined &&\n command !== \"\" &&\n pidStr !== undefined &&\n pidStr !== \"\" &&\n parts.length >= 4\n ) {\n const pid = Number.parseInt(pidStr, 10);\n if (!Number.isNaN(pid)) {\n const handle: FileHandleInfo = {\n command,\n pid,\n };\n if (user !== undefined && user !== \"\") {\n handle.user = user;\n }\n if (fd !== undefined && fd !== \"\") {\n handle.fd = fd;\n handle.mode = fd.includes(\"w\") ? \"write\" : \"read\";\n }\n handles.push(handle);\n }\n }\n }\n\n logger.debug(\"Detected file handles with lsof\", {\n file: filePath,\n handleCount: handles.length,\n });\n\n return handles;\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n\n // Check if lsof is not found\n if (errorMessageContains(error, \"ENOENT\")) {\n logger.debug(\"lsof not available on this system\");\n } else if (errorMessageContains(error, \"No such file\")) {\n // File doesn't exist - return empty array\n logger.debug(\"File does not exist\", { file: filePath });\n } else {\n logger.debug(\"lsof detection failed\", { error: errorMessage });\n }\n\n return [];\n }\n}\n\n/**\n * Detect processes holding handles to a specific file using fuser\n * SECURITY: Uses execFile to prevent shell injection\n * @param filePath - Path to the file to check\n * @returns Array of processes holding handles to the file\n */\nasync function detectWithFuser(filePath: string): Promise<FileHandleInfo[]> {\n try {\n // fuser outputs to stderr, not stdout\n // Use execFile to prevent shell injection\n const result = await execFileAsync(\"fuser\", [\"-v\", filePath], {\n encoding: \"utf8\",\n });\n\n // fuser writes to stderr even on success\n const output = result.stderr || result.stdout || \"\";\n\n if (output.trim() === \"\") {\n return [];\n }\n\n const handles: FileHandleInfo[] = [];\n const lines = output.split(\"\\n\").slice(1); // Skip header\n\n for (const line of lines) {\n const handle = parseFuserLine(line);\n if (handle) {\n handles.push(handle);\n }\n }\n\n logger.debug(\"Detected file handles with fuser\", {\n file: filePath,\n handleCount: handles.length,\n });\n\n return handles;\n } catch (error) {\n const errorMessage = getErrorMessage(error);\n\n if (errorMessageContains(error, \"ENOENT\")) {\n logger.debug(\"fuser not available on this system\");\n } else {\n logger.debug(\"fuser detection failed\", { error: errorMessage });\n }\n\n return [];\n }\n}\n\n/**\n * Windows-specific handle detection using PowerShell\n * SECURITY: Properly escapes file path for PowerShell\n * @param filePath - Path to the file to check\n * @returns Array of processes holding handles to the file\n */\nasync function detectOnWindows(filePath: string): Promise<FileHandleInfo[]> {\n try {\n // Escape single quotes in the file path for PowerShell\n const escapedPath = filePath.replace(/'/g, \"''\");\n\n // Use Get-Process with error handling\n const psScript = `\n $ErrorActionPreference = 'SilentlyContinue'\n $handles = @()\n \n # Try to find processes with the file open\n Get-Process | ForEach-Object {\n try {\n $proc = $_\n # Check if any modules match the file path\n $modules = $proc.Modules | Where-Object { $_.FileName -eq '${escapedPath}' }\n if ($modules) {\n $handles += [PSCustomObject]@{\n ProcessName = $proc.ProcessName\n ProcessId = $proc.Id\n }\n }\n } catch {\n # Skip processes we can't access\n }\n }\n \n # Also try using Get-CimInstance for better file handle detection\n try {\n $query = \"SELECT * FROM CIM_DataFile WHERE Name='${escapedPath.replace(/\\\\/g, \"\\\\\\\\\")}'\"\n $file = Get-CimInstance -Query $query -ErrorAction SilentlyContinue\n if ($file) {\n $assoc = Get-CimAssociatedInstance -InputObject $file -ResultClassName Win32_Process\n foreach ($proc in $assoc) {\n $handles += [PSCustomObject]@{\n ProcessName = $proc.Name\n ProcessId = $proc.ProcessId\n }\n }\n }\n } catch {\n # WMI query failed, ignore\n }\n \n $handles | ConvertTo-Json -Compress\n `;\n\n const { stdout } = await execFileAsync(\n \"powershell\",\n [\"-NoProfile\", \"-NonInteractive\", \"-Command\", psScript],\n { encoding: \"utf8\", maxBuffer: 1024 * 1024 },\n );\n\n if (!stdout || stdout.trim() === \"\" || stdout.trim() === \"null\") {\n return [];\n }\n\n const handles = parsePowerShellOutput(stdout);\n\n logger.debug(\"Detected file handles with PowerShell\", {\n file: filePath,\n handleCount: handles.length,\n });\n\n return handles;\n } catch (error) {\n logger.debug(\"Windows handle detection failed\", {\n error: getErrorMessage(error),\n });\n return [];\n }\n}\n\n/**\n * Try to detect using handle.exe from Sysinternals (if available)\n * SECURITY: Uses execFile to prevent shell injection\n * @param filePath - Path to the file to check\n * @returns Array of processes holding handles to the file\n */\nasync function detectWithHandleExe(\n filePath: string,\n): Promise<FileHandleInfo[]> {\n try {\n // handle.exe must be in PATH or current directory\n const { stdout } = await execFileAsync(\"handle\", [\"-nobanner\", filePath], {\n encoding: \"utf8\",\n });\n\n if (!stdout || stdout.trim() === \"\") {\n return [];\n }\n\n const handles: FileHandleInfo[] = [];\n const lines = stdout.split(\"\\n\");\n\n for (const line of lines) {\n // Format: process.exe pid: type handle: path\n const match = line.match(\n /^(.+?)\\s+pid:\\s+(\\d+)\\s+type:\\s+(\\w+)\\s+.+:\\s+(.+)$/i,\n );\n if (\n match?.[1] !== undefined &&\n match?.[1] !== \"\" &&\n match?.[2] !== undefined &&\n match?.[2] !== \"\"\n ) {\n const pid = Number.parseInt(match[2], 10);\n if (!Number.isNaN(pid)) {\n const handle: FileHandleInfo = {\n command: match[1],\n pid,\n };\n if (match?.[3] !== undefined && match[3] !== \"\") {\n handle.fd = match[3];\n }\n handle.mode = \"unknown\";\n handles.push(handle);\n }\n }\n }\n\n logger.debug(\"Detected file handles with handle.exe\", {\n file: filePath,\n handleCount: handles.length,\n });\n\n return handles;\n } catch {\n // handle.exe not available, silently fall back\n return [];\n }\n}\n\n/**\n * Detect all processes that have open handles to a specific file\n * @param filePath - Path to the file to check\n * @returns Array of processes holding handles to the file\n */\nexport async function detectFileHandles(\n filePath: string,\n): Promise<FileHandleInfo[]> {\n const os = getPlatform();\n\n logger.debug(\"Detecting file handles\", { file: filePath, platform: os });\n\n if (isWindows()) {\n // Try handle.exe first (most accurate)\n const handles = await detectWithHandleExe(filePath);\n if (handles.length > 0) {\n return handles;\n }\n\n // Fall back to PowerShell\n return detectOnWindows(filePath);\n }\n\n // Unix-like systems: try lsof first\n let handles = await detectWithLsof(filePath);\n\n // Fallback to fuser if lsof didn't work\n if (handles.length === 0) {\n handles = await detectWithFuser(filePath);\n }\n\n if (handles.length > 0) {\n logger.info(\"File has open handles\", {\n file: filePath,\n handleCount: handles.length,\n processes: handles.map((h) => ({\n pid: h.pid,\n command: h.command,\n mode: h.mode,\n })),\n });\n }\n\n return handles;\n}\n\n/**\n * Check if a file is locked by any process\n * @param filePath - Path to the file to check\n * @returns True if file has open handles, false otherwise\n */\nexport async function isFileLocked(filePath: string): Promise<boolean> {\n const handles = await detectFileHandles(filePath);\n return handles.length > 0;\n}\n\n/**\n * Get detailed information about processes locking a file\n * @param filePath - Path to the file to check\n * @returns Human-readable string describing the lock status\n */\nexport async function getFileLockInfo(filePath: string): Promise<string> {\n const handles = await detectFileHandles(filePath);\n\n if (handles.length === 0) {\n return \"File is not locked\";\n }\n\n const processInfo = handles\n .map(\n (h) =>\n `${h.command} (PID: ${h.pid}${h.user !== undefined && h.user !== \"\" ? `, User: ${h.user}` : \"\"}${h.mode !== undefined && h.mode !== \"\" ? `, Mode: ${h.mode}` : \"\"})`,\n )\n .join(\", \");\n\n return `File is locked by ${handles.length} process${handles.length > 1 ? \"es\" : \"\"}: ${processInfo}`;\n}\n","import { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\n\nimport type { BrowserName } from \"@utils/BrowserControl\";\nimport { getPlatform, isWindows, type Platform } from \"@utils/platformUtils\";\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Interface for platform-specific browser control operations\n * Following SOLID principles - Interface Segregation\n */\nexport interface PlatformBrowserControl {\n /**\n * Check if the browser is supported on this platform\n * @param browserName - The name of the browser to check\n * @returns True if the browser is supported on this platform\n */\n isBrowserSupported(browserName: BrowserName): boolean;\n\n /**\n * Get executable names for a browser on this platform\n * @param browserName - The name of the browser\n * @returns Array of executable names for the browser\n */\n getBrowserExecutables(browserName: BrowserName): string[];\n\n /**\n * Launch a browser on this platform\n * @param browserName - The name of the browser to launch\n * @returns Promise that resolves when the browser is launched\n * @throws {Error} When the browser is not supported or cannot be launched\n */\n launchBrowser(browserName: BrowserName): Promise<void>;\n\n /**\n * Get the platform name\n * @returns The name of the current platform\n */\n getPlatformName(): string;\n\n /**\n * Check if a browser is installed\n * @param browserName - The name of the browser to check\n * @returns Promise that resolves to true if the browser is installed\n */\n isBrowserInstalled(browserName: BrowserName): Promise<boolean>;\n}\n\n/**\n * Base implementation with common functionality\n * Following DRY principle\n */\nexport abstract class BasePlatformBrowserControl\n implements PlatformBrowserControl\n{\n protected readonly browserExecutables: Partial<Record<BrowserName, string[]>>;\n\n /**\n * Creates a new instance of BasePlatformBrowserControl\n */\n public constructor() {\n this.browserExecutables = this.initializeBrowserExecutables();\n }\n\n /**\n * Initialize browser executables for this platform\n * @returns Record mapping browser names to their executable names\n */\n protected abstract initializeBrowserExecutables(): Partial<\n Record<BrowserName, string[]>\n >;\n\n public isBrowserSupported(browserName: BrowserName): boolean {\n const executables = this.browserExecutables[browserName];\n return Boolean(executables && executables.length > 0);\n }\n\n public getBrowserExecutables(browserName: BrowserName): string[] {\n return this.browserExecutables[browserName] ?? [];\n }\n\n /**\n * Launch a browser on this platform\n * @param browserName - The name of the browser to launch\n * @returns Promise that resolves when the browser is launched\n * @throws {Error} When the browser is not supported or cannot be launched\n */\n public abstract launchBrowser(browserName: BrowserName): Promise<void>;\n\n /**\n * Get the platform name\n * @returns The name of the current platform\n */\n public abstract getPlatformName(): string;\n\n /**\n * Default implementation to check if browser is installed\n * Can be overridden by platform-specific implementations\n * @param browserName - The name of the browser to check\n * @returns Promise that resolves to true if the browser is installed\n */\n public async isBrowserInstalled(browserName: BrowserName): Promise<boolean> {\n const executables = this.getBrowserExecutables(browserName);\n\n for (const exe of executables) {\n try {\n // Try to check if executable exists using 'which' or 'where'\n const checkCommand = isWindows() ? \"where\" : \"which\";\n await execFileAsync(checkCommand, [exe], { timeout: 1000 });\n return true;\n } catch {\n // Continue checking other executables\n }\n }\n\n return false;\n }\n\n /**\n * Execute command helper with proper escaping\n * @param command - The command to execute\n * @param args - Arguments to pass to the command\n * @returns Promise that resolves when the command completes\n */\n protected async executeCommand(\n command: string,\n args: string[] = [],\n ): Promise<void> {\n try {\n await execFileAsync(command, args, {\n timeout: 5000,\n windowsHide: true,\n });\n } catch (error: unknown) {\n // Log but don't throw - browser may still launch\n if (this.isNodeError(error) && error.code !== \"ENOENT\") {\n console.debug(\n `Browser launch warning: ${BasePlatformBrowserControl.getErrorMessage(error)}`,\n );\n }\n }\n }\n\n /**\n * Helper to check if error is a Node.js error with code property\n * @param error - The error to check\n * @returns True if the error has a code property\n */\n private isNodeError(error: unknown): error is { code: string } {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n typeof (error as { code: unknown }).code === \"string\"\n );\n }\n\n /**\n * Helper to get error message from unknown error\n * @param error - The error to get message from\n * @returns Error message as string\n */\n protected static getErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n if (typeof error === \"string\") {\n return error;\n }\n return String(error);\n }\n}\n\n/**\n * macOS implementation for browser control operations\n * Handles browser launching using AppleScript on macOS systems\n */\nexport class MacOSBrowserControl extends BasePlatformBrowserControl {\n /**\n * Initialize browser executables for macOS platform\n * @returns Record mapping browser names to their executable names on macOS\n */\n protected initializeBrowserExecutables(): Partial<\n Record<BrowserName, string[]>\n > {\n return {\n Firefox: [\"Firefox\"],\n Chrome: [\"Google Chrome\"],\n Safari: [\"Safari\"],\n };\n }\n\n /**\n * Launch a browser on macOS using AppleScript\n * @param browserName - The name of the browser to launch\n * @returns Promise that resolves when the browser is launched\n * @throws {Error} When the browser is not supported on macOS\n */\n public async launchBrowser(browserName: BrowserName): Promise<void> {\n const appNames: Partial<Record<BrowserName, string>> = {\n Firefox: \"Firefox\",\n Chrome: \"Google Chrome\",\n Safari: \"Safari\",\n };\n\n const appName = appNames[browserName];\n if (appName === undefined || appName === \"\") {\n throw new Error(`${browserName} not supported on macOS`);\n }\n\n // Use osascript with proper argument separation to avoid injection\n await this.executeCommand(\"osascript\", [\n \"-e\",\n `tell application \"${appName}\" to activate`,\n ]);\n }\n\n /**\n * Get the platform name for macOS\n * @returns The platform name \"macOS\"\n */\n public getPlatformName(): string {\n return \"macOS\";\n }\n}\n\n/**\n * Windows implementation for browser control operations\n * Handles browser launching using cmd.exe start command on Windows systems\n */\nexport class WindowsBrowserControl extends BasePlatformBrowserControl {\n /**\n * Initialize browser executables for Windows platform\n * @returns Record mapping browser names to their executable names on Windows\n */\n protected initializeBrowserExecutables(): Partial<\n Record<BrowserName, string[]>\n > {\n return {\n Firefox: [\"firefox.exe\", \"Firefox\"],\n Chrome: [\"chrome.exe\", \"Google Chrome\"],\n Safari: [], // Not available on Windows\n };\n }\n\n /**\n * Launch a browser on Windows using cmd.exe start command\n * @param browserName - The name of the browser to launch\n * @returns Promise that resolves when the browser is launched\n * @throws {Error} When the browser is not available or fails to launch\n */\n public async launchBrowser(browserName: BrowserName): Promise<void> {\n const executables = this.getBrowserExecutables(browserName);\n\n if (executables.length === 0) {\n throw new Error(`${browserName} not available on Windows`);\n }\n\n // Try each executable until one works\n for (const exe of executables) {\n if (await this.tryLaunchExecutable(exe)) {\n return; // Success, exit early\n }\n }\n\n throw new Error(`Failed to launch ${browserName} on Windows`);\n }\n\n /**\n * Try to launch a specific executable on Windows\n * @param exe - The executable name to launch\n * @returns Promise that resolves to true if launch was successful\n */\n private async tryLaunchExecutable(exe: string): Promise<boolean> {\n try {\n // Use cmd.exe with /c flag to run start command safely\n await execFileAsync(\"cmd.exe\", [\"/c\", \"start\", \"\", exe], {\n timeout: 5000,\n windowsHide: true,\n });\n return true;\n } catch {\n // Try next executable\n return false;\n }\n }\n\n /**\n * Get the platform name for Windows\n * @returns The platform name \"Windows\"\n */\n public getPlatformName(): string {\n return \"Windows\";\n }\n}\n\n/**\n * Linux implementation for browser control operations\n * Handles browser launching using direct executable calls or xdg-open on Linux systems\n */\nexport class LinuxBrowserControl extends BasePlatformBrowserControl {\n /**\n * Initialize browser executables for Linux platform\n * @returns Record mapping browser names to their executable names on Linux\n */\n protected initializeBrowserExecutables(): Partial<\n Record<BrowserName, string[]>\n > {\n return {\n Firefox: [\"firefox\", \"firefox-bin\"],\n Chrome: [\n \"google-chrome\",\n \"google-chrome-stable\",\n \"chromium\",\n \"chromium-browser\",\n ],\n Safari: [], // Not available on Linux\n };\n }\n\n /**\n * Launch a browser on Linux using direct executable calls or xdg-open fallback\n * @param browserName - The name of the browser to launch\n * @returns Promise that resolves when the browser is launched\n * @throws {Error} When the browser is not available or fails to launch\n */\n public async launchBrowser(browserName: BrowserName): Promise<void> {\n const executables = this.getBrowserExecutables(browserName);\n\n if (executables.length === 0) {\n throw new Error(`${browserName} not available on Linux`);\n }\n\n // Try each possible command\n if (await this.tryLaunchExecutables(executables)) {\n return; // Success\n }\n\n // Fallback to xdg-open if no browser executable worked\n await this.tryXdgOpenFallback(browserName);\n }\n\n /**\n * Try to launch browser executables\n * @param executables - Array of executable names to try\n * @returns Promise that resolves to true if any executable was successful\n */\n private async tryLaunchExecutables(executables: string[]): Promise<boolean> {\n for (const cmd of executables) {\n try {\n // Use direct execution without shell to avoid injection\n await execFileAsync(cmd, [], {\n timeout: 5000,\n });\n return true; // Success\n } catch {}\n }\n return false;\n }\n\n /**\n * Try xdg-open as fallback when direct executables fail\n * @param browserName - The name of the browser that failed to launch\n * @returns Promise that resolves when xdg-open succeeds\n * @throws {Error} When xdg-open also fails\n */\n private async tryXdgOpenFallback(browserName: BrowserName): Promise<void> {\n try {\n await execFileAsync(\"xdg-open\", [\"http://localhost\"], {\n timeout: 5000,\n });\n } catch (error: unknown) {\n throw new Error(\n `Failed to launch ${browserName} on Linux: ${BasePlatformBrowserControl.getErrorMessage(error)}`,\n );\n }\n }\n\n /**\n * Get the platform name for Linux\n * @returns The platform name \"Linux\"\n */\n public getPlatformName(): string {\n return \"Linux\";\n }\n}\n\n/**\n * Factory to create platform-specific browser control\n * Following SOLID - Single Responsibility and Open/Closed principles\n */\nlet platformControlInstance: PlatformBrowserControl | null = null;\n\n/**\n * Creates platform-specific browser control instance\n * @param platformOverride - Optional platform override for testing\n * @returns Platform-specific browser control instance\n * @throws {Error} When platform is not supported\n */\nexport function createPlatformBrowserControl(\n platformOverride?: Platform | NodeJS.Platform,\n): PlatformBrowserControl {\n // Use singleton for efficiency when not overriding\n if (platformControlInstance !== null && platformOverride === undefined) {\n return platformControlInstance;\n }\n\n const currentPlatform = platformOverride ?? getPlatform();\n const control = createControlForPlatform(currentPlatform);\n\n if (platformOverride === undefined) {\n platformControlInstance = control;\n }\n\n return control;\n}\n\n/**\n * Creates the appropriate control instance for the given platform\n * @param platform - The platform to create control for\n * @returns Platform-specific browser control instance\n * @throws {Error} When platform is not supported\n */\nfunction createControlForPlatform(platform: string): PlatformBrowserControl {\n switch (platform) {\n case \"darwin\":\n return new MacOSBrowserControl();\n case \"win32\":\n return new WindowsBrowserControl();\n case \"linux\":\n case \"freebsd\":\n case \"openbsd\":\n return new LinuxBrowserControl();\n default:\n // For any other platform string, try Linux as fallback\n return new LinuxBrowserControl();\n }\n}\n\n/**\n * Clear the singleton instance (useful for testing)\n */\nexport function clearPlatformControlInstance(): void {\n platformControlInstance = null;\n}\n","// External imports\nimport { createDecipheriv, pbkdf2 } from \"node:crypto\";\n\nimport { isMacOS, isWindows } from \"@utils/platformUtils\";\n\n/**\n * Simple memoization utility for caching Buffer operations\n * @param fn - The function to memoize that takes a Buffer and returns a Buffer\n * @param keyFn - Optional function to generate cache keys from Buffer values\n * @returns A memoized version of the input function\n */\nfunction memoizeBuffer(\n fn: (value: Buffer) => Buffer,\n keyFn?: (value: Buffer) => string,\n): (value: Buffer) => Buffer {\n const cache = new Map<string, Buffer>();\n\n return (value: Buffer): Buffer => {\n const key = keyFn ? keyFn(value) : value.toString(\"hex\");\n\n if (cache.has(key)) {\n const cachedResult = cache.get(key);\n if (cachedResult !== undefined) {\n return cachedResult;\n }\n }\n\n const result = fn(value);\n cache.set(key, result);\n return result;\n };\n}\n\nimport { decryptV10Cookie, isV10Cookie } from \"./windows/decryptV10Cookie\";\n\n/**\n * Removes the v10 prefix from the encrypted value if present\n * @param value - The encrypted value\n * @returns The value without the v10 prefix\n */\nconst removeV10Prefix = memoizeBuffer(\n (value: Buffer): Buffer => {\n if (\n value.length >= 3 &&\n value[0] === 0x76 && // 'v'\n value[1] === 0x31 && // '1'\n value[2] === 0x30\n ) {\n // '0'\n return value.slice(3);\n }\n return value;\n },\n (value: Buffer) => value.toString(\"hex\"),\n);\n\n/**\n * Removes PKCS7 padding from the decrypted value\n * @param decrypted - The decrypted buffer\n * @returns The buffer without padding\n */\nconst removePadding = memoizeBuffer(\n (decrypted: Buffer): Buffer => {\n const padding = decrypted[decrypted.length - 1];\n if (padding && padding <= 16) {\n return decrypted.slice(0, -padding);\n }\n return decrypted;\n },\n (decrypted: Buffer) => decrypted.toString(\"hex\"),\n);\n\n/**\n * Extracts the actual value from the decoded string by removing Chrome's prefixes\n * @param decodedString - The decoded string to clean up\n * @returns The cleaned up value\n */\nfunction extractValue(decodedString: string): string {\n // First try to find a UUID pattern which is common in cookies\n const uuidMatch = decodedString.match(\n /([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})/i,\n );\n if (uuidMatch?.[1]) {\n return uuidMatch[1];\n }\n\n // Look for common patterns at the end of the string\n const endPatterns = [\n /([A-Z]{3})$/, // Currency codes (USD, GBP, EUR)\n /([a-z]{2}_[A-Z]{2})$/, // Locale codes (en_US, en_GB)\n /(\\d{3}-\\d{7}-\\d{7})$/, // Amazon session IDs\n ];\n\n for (const pattern of endPatterns) {\n const match = decodedString.match(pattern);\n if (match?.[1]) {\n return match[1];\n }\n }\n\n // Then try other cleanup patterns\n const cleanupPatterns = [\n /.*?0t(.+)$/, // Pattern ending in \"0t\" followed by value\n /.*?1e`(.+)$/, // Pattern ending in \"1e`\" followed by value\n /.*?[`'](.+)$/, // Any backtick or quote followed by value\n /[^\\x20-\\x7E]*([\\x20-\\x7E]+)$/, // Non-printable chars followed by printable chars\n /.*?([a-zA-Z0-9_\\-.]+)$/, // Alphanumeric value at the end\n ];\n\n for (const pattern of cleanupPatterns) {\n const match = decodedString.match(pattern);\n const value = match?.[1] ?? \"\";\n if (value.length > 0) {\n return value;\n }\n }\n return decodedString;\n}\n\n/**\n * Decrypts Chrome's encrypted cookie values\n * @param encryptedValue - The encrypted cookie value as a Buffer\n * @param password - The Chrome encryption password\n * @param metaVersion - Optional meta version for determining decryption behavior\n * @returns A promise that resolves to the decrypted cookie value\n * @throws {Error} If decryption fails\n * @example\n */\nexport async function decrypt(\n encryptedValue: Buffer,\n password: string | Buffer,\n metaVersion?: number,\n): Promise<string> {\n // v10 cookies use AES-GCM on Windows only\n // On macOS, cookies starting with v10 are actually v11 encrypted with a value that starts with \"v10,\"\n // Only treat as v10 cookie if we're on Windows AND it has sufficient length AND password is a Buffer (real scenario)\n if (\n isWindows() &&\n isV10Cookie(encryptedValue) &&\n encryptedValue.length >= 31 &&\n Buffer.isBuffer(password)\n ) {\n return decryptV10Cookie(encryptedValue, password);\n }\n\n // On macOS, cookies that don't start with v10 are considered 'old data' stored as plaintext\n // Ref: https://chromium.googlesource.com/chromium/src/+/refs/heads/main/components/os_crypt/sync/os_crypt_mac.mm\n if (isMacOS()) {\n // Check if this looks like encrypted data (starts with common version prefixes)\n const hasVersionPrefix = encryptedValue\n .slice(0, 3)\n .toString()\n .match(/^v\\d\\d$/);\n if (!hasVersionPrefix) {\n // Not a version prefix - treat as plaintext on macOS\n return Promise.resolve(encryptedValue.toString(\"utf8\"));\n }\n }\n\n // v11 cookies and other encrypted cookies use AES-CBC with PBKDF2\n if (typeof password !== \"string\") {\n throw new Error(\"password must be a string\");\n }\n if (!Buffer.isBuffer(encryptedValue)) {\n throw new Error(\"encryptedData must be a Buffer\");\n }\n\n return new Promise((resolve, reject) => {\n pbkdf2(password, \"saltysalt\", 1003, 16, \"sha1\", (error, key) => {\n try {\n if (error) {\n reject(new Error(`Failed to derive key: ${error.message}`));\n return;\n }\n\n const value = removeV10Prefix(encryptedValue);\n if (value.length % 16 !== 0) {\n reject(new Error(\"Encrypted data length is not a multiple of 16\"));\n return;\n }\n\n // Chrome's encryption parameters\n const iv = Buffer.alloc(16, \" \"); // 16 spaces\n const decipher = createDecipheriv(\"aes-128-cbc\", key, iv);\n decipher.setAutoPadding(false);\n\n // Decrypt the value\n let decrypted: Buffer = decipher.update(value);\n try {\n decipher.final();\n } catch (e) {\n reject(\n new Error(`Failed to finalize decryption: ${(e as Error).message}`),\n );\n return;\n }\n\n decrypted = removePadding(decrypted);\n\n // Skip the first 32 bytes (hash prefix) if meta version >= 24\n // Ref: https://chromium.googlesource.com/chromium/src/+/b02dcebd7cafab92770734dc2bc317bd07f1d891/net/extras/sqlite/sqlite_persistent_cookie_store.cc#223\n const useHashPrefix = (metaVersion ?? 0) >= 24;\n const finalDecrypted =\n useHashPrefix && decrypted.length > 32\n ? decrypted.slice(32)\n : decrypted;\n\n const decodedString = finalDecrypted.toString(\"utf8\");\n resolve(extractValue(decodedString));\n } catch (e) {\n reject(new Error(`Decryption failed: ${(e as Error).message}`));\n }\n });\n });\n}\n","import { createDecipheriv } from \"node:crypto\";\n\n/**\n * Decrypts Chrome v10 encrypted cookies on Windows using AES-256-GCM\n *\n * Chrome v10 cookies use AES-256-GCM encryption with:\n * - 12-byte nonce (96 bits)\n * - 16-byte authentication tag\n * @param encryptedValue - The encrypted cookie value starting with 'v10' prefix\n * @param key - The decrypted master key from DPAPI\n * @returns The decrypted cookie value\n * @throws {Error} If the cookie is not v10 format or decryption fails\n */\nexport function decryptV10Cookie(encryptedValue: Buffer, key: Buffer): string {\n // Check for v10 prefix\n const VERSION_PREFIX = Buffer.from(\"v10\");\n if (!encryptedValue.subarray(0, 3).equals(VERSION_PREFIX)) {\n throw new Error(\"Not a v10 encrypted cookie\");\n }\n\n // Remove the version prefix\n const ciphertext = encryptedValue.subarray(3);\n\n // Extract components\n const NONCE_LENGTH = 12; // 96 bits / 8\n const TAG_LENGTH = 16; // 128 bits / 8\n\n if (ciphertext.length < NONCE_LENGTH + TAG_LENGTH) {\n throw new Error(\"Invalid v10 cookie: too short\");\n }\n\n const nonce = ciphertext.subarray(0, NONCE_LENGTH);\n const encryptedData = ciphertext.subarray(\n NONCE_LENGTH,\n ciphertext.length - TAG_LENGTH,\n );\n const authTag = ciphertext.subarray(ciphertext.length - TAG_LENGTH);\n\n // Decrypt using AES-256-GCM\n const decipher = createDecipheriv(\"aes-256-gcm\", key, nonce);\n decipher.setAuthTag(authTag);\n\n const decrypted = Buffer.concat([\n decipher.update(encryptedData),\n decipher.final(),\n ]);\n\n return decrypted.toString(\"utf8\");\n}\n\n/**\n * Checks if a cookie value is v10 encrypted\n * @param value - The cookie value to check\n * @returns True if the cookie starts with 'v10' prefix\n */\nexport function isV10Cookie(value: Buffer): boolean {\n const VERSION_PREFIX = Buffer.from(\"v10\");\n return value.length >= 3 && value.subarray(0, 3).equals(VERSION_PREFIX);\n}\n","import { assertPlatformSupported, getPlatform } from \"@utils/platformUtils\";\n\nimport { execSimple } from \"../../../utils/execSimple\";\n\nimport type { ChromiumBrowser } from \"./ChromiumBrowsers\";\n\n/**\n * Maps browser types to their keychain service names on macOS\n */\nconst MACOS_KEYCHAIN_SERVICES: Record<ChromiumBrowser, string> = {\n chrome: \"Chrome Safe Storage\",\n chromium: \"Chromium Safe Storage\",\n brave: \"Brave Safe Storage\",\n edge: \"Microsoft Edge Safe Storage\",\n arc: \"Arc Safe Storage\",\n opera: \"Opera Safe Storage\",\n \"opera-gx\": \"Opera Safe Storage\", // Opera GX shares Opera's keychain\n vivaldi: \"Vivaldi Safe Storage\",\n whale: \"Whale Safe Storage\",\n};\n\n/**\n * Gets the Chromium browser Safe Storage password for macOS\n * @param browser - The browser type to get the password for\n * @returns A promise that resolves to the browser's Safe Storage password\n */\nasync function getMacOSPassword(browser: ChromiumBrowser): Promise<string> {\n const service = MACOS_KEYCHAIN_SERVICES[browser];\n if (!service) {\n throw new Error(`Unknown browser type: ${browser}`);\n }\n\n try {\n const command = `security find-generic-password -w -s \"${service}\"`;\n const result = await execSimple(command);\n return result.stdout.trim();\n } catch (error) {\n // Fallback to Chrome if browser-specific key not found\n // This is useful for browsers that share Chrome's encryption\n if (browser !== \"chrome\") {\n const chromeCommand = `security find-generic-password -w -s \"Chrome Safe Storage\"`;\n try {\n const result = await execSimple(chromeCommand);\n return result.stdout.trim();\n } catch {\n // If Chrome fallback also fails, throw original error\n }\n }\n throw new Error(\n `Failed to get ${browser} password from keychain: ${error}`,\n );\n }\n}\n\n/**\n * Gets the Chromium browser password for Windows\n * Windows uses DPAPI which is browser-agnostic\n */\nasync function getWindowsPassword(): Promise<string | Buffer> {\n // Import dynamically to avoid loading on non-Windows platforms\n const { getChromePassword } = await import(\"./windows/getChromePassword\");\n return getChromePassword();\n}\n\n/**\n * Gets the Chromium browser password for Linux\n * Linux typically uses a hardcoded key or libsecret\n */\nasync function getLinuxPassword(): Promise<string> {\n // Import dynamically to avoid loading on non-Linux platforms\n const { getChromePassword } = await import(\"./linux/getChromePassword\");\n return getChromePassword();\n}\n\n/**\n * Gets the Chromium-based browser Safe Storage password for the current platform.\n * This password is used to decrypt cookies stored in the browser's cookie database.\n * Supports macOS (keychain), Windows (DPAPI), and Linux (keyring/libsecret).\n * @param browser - The Chromium-based browser to get the password for\n * @returns A promise that resolves to the browser's Safe Storage password or Buffer\n * @throws {Error} If the password cannot be retrieved or the platform is not supported\n */\nexport async function getChromiumPassword(\n browser: ChromiumBrowser = \"chrome\",\n): Promise<string | Buffer> {\n assertPlatformSupported();\n\n switch (getPlatform()) {\n case \"darwin\": {\n return getMacOSPassword(browser);\n }\n case \"win32\": {\n // Windows uses DPAPI which works for all Chromium browsers\n return getWindowsPassword();\n }\n case \"linux\": {\n // Linux uses a hardcoded key for all Chromium browsers\n return getLinuxPassword();\n }\n default:\n throw new Error(`Platform ${getPlatform()} is not supported`);\n }\n}\n","/**\n * Database adapter abstraction layer\n * Provides a unified interface for SQLite implementations (better-sqlite3 and bun:sqlite)\n */\n\n/**\n * Minimal SQLite statement interface\n * Represents a prepared SQL statement with binding and execution methods\n */\nexport interface SqliteStatement {\n /**\n * Execute prepared statement and return all matching rows\n * @param params - Query parameters to bind\n */\n all(...params: unknown[]): unknown[];\n\n /**\n * Execute prepared statement and return first matching row\n * @param params - Query parameters to bind\n */\n get(...params: unknown[]): unknown | undefined;\n\n /**\n * Execute prepared statement (for INSERT, UPDATE, DELETE)\n * @param params - Query parameters to bind\n */\n run(...params: unknown[]): void;\n}\n\n/**\n * Minimal SQLite database interface\n * Represents a database connection with query preparation and management\n */\nexport interface SqliteDatabase {\n /**\n * Prepare a SQL statement for execution\n * @param sql - SQL query string\n */\n prepare(sql: string): SqliteStatement;\n\n /**\n * Execute a PRAGMA statement\n * @param pragma - PRAGMA string (e.g., \"busy_timeout = 3000\")\n */\n pragma(pragma: string): unknown;\n\n /**\n * Close the database connection\n */\n close(): void;\n\n /**\n * Whether the database is opened in read-only mode\n */\n readonly?: boolean;\n}\n\n/**\n * SQLite database connection options\n */\nexport interface SqliteOptions {\n /**\n * Open database in read-only mode\n */\n readonly?: boolean;\n\n /**\n * Require the database file to exist\n */\n fileMustExist?: boolean;\n}\n\n/**\n * Runtime detection type\n */\nexport type Runtime = \"node\" | \"bun\";\n\n/**\n * Detect the current runtime environment\n * @returns The detected runtime (\"bun\" or \"node\")\n */\nfunction detectRuntime(): Runtime {\n // Check if running in Bun: look for globalThis.Bun\n if (typeof (globalThis as Record<string, unknown>).Bun !== \"undefined\") {\n return \"bun\";\n }\n return \"node\";\n}\n\n/**\n * Create a SQLite database adapter instance\n * Automatically detects the runtime and returns the appropriate adapter\n *\n * @param filepath - Path to the SQLite database file\n * @param options - Database connection options\n * @returns A SqliteDatabase instance compatible with the current runtime\n */\nexport function createSqliteDatabase(\n filepath: string,\n options: SqliteOptions = {},\n): SqliteDatabase {\n const runtime = detectRuntime();\n\n if (runtime === \"bun\") {\n // Dynamically import BunSqliteAdapter only when needed.\n // Wrapped in try/catch: if bun:sqlite is unavailable (e.g. the bundle is\n // evaluated in Node.js where the bun: URL scheme is rejected), fall through\n // to better-sqlite3 rather than throwing ERR_UNSUPPORTED_ESM_URL_SCHEME.\n try {\n const BunSqliteAdapter = require(\"./BunSqliteAdapter\").BunSqliteAdapter;\n return new BunSqliteAdapter(filepath, options);\n } catch {\n // Fall through to better-sqlite3 below\n }\n }\n\n // Default to Node.js with better-sqlite3\n const BetterSqlite3Adapter =\n require(\"./BetterSqlite3Adapter\").BetterSqlite3Adapter;\n return new BetterSqlite3Adapter(filepath, options);\n}\n\n/**\n * Export the current runtime detector for testing and debugging\n */\nexport function getCurrentRuntime(): Runtime {\n return detectRuntime();\n}\n","/**\n * Database connection manager with pooling and performance monitoring\n * Manages SQLite connections efficiently with automatic cleanup and monitoring\n */\n\nimport { EventEmitter } from \"node:events\";\n\nimport {\n createSqliteDatabase,\n type SqliteDatabase,\n} from \"./adapters/DatabaseAdapter\";\nimport { getErrorMessage } from \"@utils/errorUtils\";\nimport { createTaggedLogger, logError } from \"@utils/logHelpers\";\n\nconst logger = createTaggedLogger(\"DatabaseConnectionManager\");\n\n/**\n * Connection pool configuration\n */\nexport interface PoolConfig {\n /** Maximum number of connections in the pool */\n maxConnections?: number;\n /** Connection timeout in milliseconds */\n connectionTimeout?: number;\n /** Idle timeout before closing connection */\n idleTimeout?: number;\n /** Enable performance monitoring */\n enableMonitoring?: boolean;\n /** Retry attempts for locked databases */\n retryAttempts?: number;\n /** Retry delay in milliseconds */\n retryDelay?: number;\n /** Query execution timeout in milliseconds */\n queryTimeout?: number;\n}\n\n/**\n * Database connection metadata\n */\ninterface ConnectionMetadata {\n database: SqliteDatabase;\n filepath: string;\n inUse: boolean;\n lastAccessed: number;\n queryCount: number;\n totalQueryTime: number;\n created: number;\n}\n\n/**\n * Query performance metrics\n */\nexport interface QueryMetrics {\n query: string;\n duration: number;\n rowCount: number;\n filepath: string;\n timestamp: number;\n success: boolean;\n error?: string;\n}\n\n/**\n * Connection pool statistics\n */\nexport interface PoolStatistics {\n totalConnections: number;\n activeConnections: number;\n idleConnections: number;\n totalQueries: number;\n averageQueryTime: number;\n cacheHitRate: number;\n connectionReuse: number;\n}\n\n/**\n * Database connection manager with pooling\n */\nexport class DatabaseConnectionManager extends EventEmitter {\n private readonly connections: Map<string, ConnectionMetadata>;\n private readonly config: Required<PoolConfig>;\n private readonly queryMetrics: QueryMetrics[];\n private lastCleanupTime: number;\n private totalQueries: number;\n private cacheHits: number;\n private connectionReuses: number;\n\n /**\n *\n * @param config\n */\n constructor(config: PoolConfig = {}) {\n super();\n\n this.connections = new Map();\n this.queryMetrics = [];\n this.totalQueries = 0;\n this.cacheHits = 0;\n this.connectionReuses = 0;\n this.lastCleanupTime = Date.now();\n\n this.config = {\n maxConnections: config.maxConnections ?? 5,\n connectionTimeout: config.connectionTimeout ?? 5000,\n idleTimeout: config.idleTimeout ?? 30000,\n enableMonitoring: config.enableMonitoring ?? true,\n retryAttempts: config.retryAttempts ?? 3,\n retryDelay: config.retryDelay ?? 100,\n queryTimeout: config.queryTimeout ?? 3000, // 3 seconds default\n };\n }\n\n /**\n * Get or create a database connection\n * @param filepath\n */\n async getConnection(filepath: string): Promise<SqliteDatabase> {\n // Perform cleanup if needed (every 30 seconds)\n const now = Date.now();\n if (now - this.lastCleanupTime > 30000) {\n this.cleanupIdleConnections();\n this.lastCleanupTime = now;\n }\n\n // Check existing connection\n const existing = this.connections.get(filepath);\n if (existing && !existing.inUse) {\n existing.inUse = true;\n existing.lastAccessed = Date.now();\n this.connectionReuses++;\n\n logger.debug(\"Reusing existing connection\", {\n filepath,\n queryCount: existing.queryCount,\n });\n\n return existing.database;\n }\n\n // Check pool limit\n if (this.connections.size >= this.config.maxConnections) {\n await this.evictLeastRecentlyUsed();\n }\n\n // Create new connection\n return this.createConnection(filepath);\n }\n\n /**\n * Create a new database connection\n * @param filepath - Path to the database file\n * @returns Promise that resolves to a SqliteDatabase connection instance\n */\n private async createConnection(filepath: string): Promise<SqliteDatabase> {\n const startTime = Date.now();\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt < this.config.retryAttempts; attempt++) {\n try {\n const database = createSqliteDatabase(filepath, {\n readonly: true,\n fileMustExist: true,\n });\n\n // Set busy timeout for all queries on this connection\n // This timeout only applies to actual query execution, not connection retries\n database.pragma(`busy_timeout = ${this.config.queryTimeout}`);\n\n const metadata: ConnectionMetadata = {\n database,\n filepath,\n inUse: true,\n lastAccessed: Date.now(),\n queryCount: 0,\n totalQueryTime: 0,\n created: Date.now(),\n };\n\n this.connections.set(filepath, metadata);\n\n const connectionTime = Date.now() - startTime;\n logger.debug(\"Created new connection\", {\n filepath,\n connectionTime,\n attempt: attempt + 1,\n });\n\n this.emit(\"connection:created\", { filepath, connectionTime });\n\n return database;\n } catch (error) {\n lastError = error as Error;\n\n if (this.isDatabaseLocked(error)) {\n logger.warn(\"Database locked, retrying\", {\n filepath,\n attempt: attempt + 1,\n maxAttempts: this.config.retryAttempts,\n });\n\n await this.delay(this.config.retryDelay * 2 ** attempt);\n continue;\n }\n\n throw error;\n }\n }\n\n throw lastError || new Error(`Failed to connect to database: ${filepath}`);\n }\n\n /**\n * Execute a query with the connection manager\n * The connection already has busy_timeout set, so queries will timeout appropriately\n * @param filepath\n * @param queryFn\n * @param queryDescription\n */\n async executeQuery<T>(\n filepath: string,\n queryFn: (db: SqliteDatabase) => T,\n queryDescription?: string,\n ): Promise<T> {\n const startTime = Date.now();\n const connection = await this.getConnection(filepath);\n const metadata = this.connections.get(filepath);\n\n try {\n const result = queryFn(connection);\n const duration = Date.now() - startTime;\n\n if (metadata) {\n metadata.queryCount++;\n metadata.totalQueryTime += duration;\n }\n\n this.totalQueries++;\n this.cacheHits++; // Increment cache hits for successful queries\n\n // Log slow queries at debug level\n if (duration > 100) {\n logger.debug(\"Slow query detected\", {\n query: queryDescription ?? \"Unknown query\",\n duration,\n filepath,\n });\n }\n\n // Record metrics\n if (this.config.enableMonitoring) {\n const metrics: QueryMetrics = {\n query: queryDescription ?? \"Unknown query\",\n duration,\n rowCount: Array.isArray(result) ? result.length : 1,\n filepath,\n timestamp: Date.now(),\n success: true,\n };\n\n this.recordMetrics(metrics);\n }\n\n return result;\n } catch (error) {\n const duration = Date.now() - startTime;\n\n // Increment query count even for failed queries\n this.totalQueries++;\n\n // Record error metrics\n if (this.config.enableMonitoring) {\n const metrics: QueryMetrics = {\n query: queryDescription ?? \"Unknown query\",\n duration,\n rowCount: 0,\n filepath,\n timestamp: Date.now(),\n success: false,\n error: (error as Error).message,\n };\n\n this.recordMetrics(metrics);\n }\n\n throw error;\n } finally {\n // Release connection\n if (metadata) {\n metadata.inUse = false;\n metadata.lastAccessed = Date.now();\n }\n }\n }\n\n /**\n * Release a connection back to the pool\n * @param filepath\n */\n releaseConnection(filepath: string): void {\n const metadata = this.connections.get(filepath);\n if (metadata) {\n metadata.inUse = false;\n metadata.lastAccessed = Date.now();\n logger.debug(\"Released connection\", { filepath });\n }\n }\n\n /**\n * Close a specific connection\n * @param filepath\n */\n closeConnection(filepath: string): void {\n const metadata = this.connections.get(filepath);\n if (metadata) {\n try {\n metadata.database.close();\n this.connections.delete(filepath);\n\n logger.debug(\"Closed connection\", {\n filepath,\n queryCount: metadata.queryCount,\n lifetime: Date.now() - metadata.created,\n });\n\n this.emit(\"connection:closed\", { filepath });\n } catch (error) {\n logError(\"Failed to close connection\", error, { filepath });\n }\n }\n }\n\n /**\n * Close all connections\n */\n closeAll(): void {\n for (const [filepath, metadata] of this.connections) {\n try {\n metadata.database.close();\n logger.debug(\"Closed connection\", { filepath });\n } catch (error) {\n logError(\"Failed to close connection\", error, { filepath });\n }\n }\n\n this.connections.clear();\n\n logger.info(\"Closed all connections\", {\n totalQueries: this.totalQueries,\n connectionReuses: this.connectionReuses,\n });\n }\n\n /**\n * Get pool statistics\n * @returns Pool statistics including connection counts and query metrics\n */\n public getStatistics(): PoolStatistics {\n let totalQueryTime = 0;\n let totalQueryCount = 0;\n let activeConnections = 0;\n\n for (const metadata of this.connections.values()) {\n totalQueryTime += metadata.totalQueryTime;\n totalQueryCount += metadata.queryCount;\n if (metadata.inUse) {\n activeConnections++;\n }\n }\n\n return {\n totalConnections: this.connections.size,\n activeConnections,\n idleConnections: this.connections.size - activeConnections,\n totalQueries: this.totalQueries,\n averageQueryTime:\n totalQueryCount > 0 ? totalQueryTime / totalQueryCount : 0,\n cacheHitRate:\n this.totalQueries > 0 ? this.cacheHits / this.totalQueries : 0,\n connectionReuse: this.connectionReuses,\n };\n }\n\n /**\n * Get recent query metrics\n * @param limit\n */\n getQueryMetrics(limit = 100): QueryMetrics[] {\n return this.queryMetrics.slice(-limit);\n }\n\n /**\n * Clear query metrics\n */\n clearMetrics(): void {\n this.queryMetrics.length = 0;\n }\n\n /**\n * Clean up idle connections\n */\n private cleanupIdleConnections(): void {\n const now = Date.now();\n const toClose: string[] = [];\n\n for (const [filepath, metadata] of this.connections) {\n if (\n !metadata.inUse &&\n now - metadata.lastAccessed > this.config.idleTimeout\n ) {\n toClose.push(filepath);\n }\n }\n\n for (const filepath of toClose) {\n this.closeConnection(filepath);\n }\n\n if (toClose.length > 0) {\n logger.debug(\"Cleaned up idle connections\", { count: toClose.length });\n }\n }\n\n /**\n * Evict least recently used connection\n */\n private async evictLeastRecentlyUsed(): Promise<void> {\n let lruPath: string | null = null;\n let lruTime = Date.now();\n\n for (const [filepath, metadata] of this.connections) {\n if (!metadata.inUse && metadata.lastAccessed < lruTime) {\n lruPath = filepath;\n lruTime = metadata.lastAccessed;\n }\n }\n\n if (lruPath !== null) {\n this.closeConnection(lruPath);\n logger.debug(\"Evicted LRU connection\", { filepath: lruPath });\n } else {\n // All connections are in use, wait a bit\n await this.delay(100);\n }\n }\n\n /**\n * Record query metrics\n * @param metrics\n */\n private recordMetrics(metrics: QueryMetrics): void {\n this.queryMetrics.push(metrics);\n\n // Keep only recent metrics (last 1000)\n if (this.queryMetrics.length > 1000) {\n this.queryMetrics.splice(0, this.queryMetrics.length - 1000);\n }\n\n this.emit(\"query:executed\", metrics);\n }\n\n /**\n * Check if error indicates database lock\n * @param error\n */\n private isDatabaseLocked(error: unknown): boolean {\n const message = getErrorMessage(error).toLowerCase();\n return (\n message.includes(\"database is locked\") ||\n message.includes(\"database locked\") ||\n message.includes(\"sqlite_busy\")\n );\n }\n\n /**\n * Delay helper\n * @param ms\n */\n private async delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n\n/**\n * Global connection manager instance\n */\nlet globalManager: DatabaseConnectionManager | null = null;\n\n/**\n * Process exit handler function\n */\nlet exitHandler: (() => void) | null = null;\n\n/**\n * Get or create global connection manager\n * @param config - Optional pool configuration for the connection manager\n * @returns The global DatabaseConnectionManager instance\n */\nexport function getGlobalConnectionManager(\n config?: PoolConfig,\n): DatabaseConnectionManager {\n if (!globalManager) {\n globalManager = new DatabaseConnectionManager(config);\n\n // Ensure cleanup on process exit (only add once)\n if (!exitHandler) {\n exitHandler = () => {\n if (globalManager) {\n globalManager.closeAll();\n }\n };\n process.on(\"exit\", exitHandler);\n }\n }\n\n return globalManager;\n}\n\n/**\n * Reset global connection manager (mainly for testing)\n */\nexport function resetGlobalConnectionManager(): void {\n if (globalManager) {\n globalManager.closeAll();\n globalManager = null;\n }\n\n // Remove the exit handler to prevent memory leaks in tests\n if (exitHandler) {\n process.removeListener(\"exit\", exitHandler);\n exitHandler = null;\n }\n}\n","/**\n * Query monitoring wrapper for SQL operations\n * Provides clean, type-safe monitoring without monkey-patching\n */\n\nimport type {\n SqliteDatabase,\n SqliteStatement,\n} from \"./adapters/DatabaseAdapter\";\nimport { createTaggedLogger } from \"@utils/logHelpers\";\n\nconst logger = createTaggedLogger(\"QueryMonitor\");\n\n/**\n * Query execution metrics\n */\nexport interface QueryExecution {\n sql: string;\n params: unknown[];\n startTime: number;\n endTime?: number;\n duration?: number;\n rowCount?: number;\n error?: Error;\n filepath?: string;\n}\n\n/**\n * Query monitoring options\n */\nexport interface MonitoringOptions {\n /** Log slow queries (in ms) */\n slowQueryThreshold?: number;\n /** Enable detailed logging */\n verbose?: boolean;\n /** Track query history */\n trackHistory?: boolean;\n /** Maximum history size */\n maxHistorySize?: number;\n}\n\n/**\n * Query monitor for tracking SQL performance\n */\nexport class QueryMonitor {\n private readonly options: Required<MonitoringOptions>;\n private readonly queryHistory: QueryExecution[];\n private totalQueries: number;\n private totalDuration: number;\n private slowQueries: number;\n private errors: number;\n\n /**\n * Creates a new QueryMonitor instance for tracking SQL query performance and metrics.\n * @param options - Configuration options for monitoring behavior\n * @param options.slowQueryThreshold - Milliseconds before a query is considered slow (default: 100ms)\n * @param options.verbose - Whether to log detailed query information (default: false)\n * @param options.trackHistory - Whether to maintain query history (default: true)\n * @param options.maxHistorySize - Maximum number of queries to keep in history (default: 1000)\n */\n public constructor(options: MonitoringOptions = {}) {\n this.options = {\n slowQueryThreshold: options.slowQueryThreshold ?? 100,\n verbose: options.verbose ?? false,\n trackHistory: options.trackHistory ?? true,\n maxHistorySize: options.maxHistorySize ?? 1000,\n };\n\n this.queryHistory = [];\n this.totalQueries = 0;\n this.totalDuration = 0;\n this.slowQueries = 0;\n this.errors = 0;\n }\n\n /**\n * Execute a query with monitoring\n * @param db - Database connection to execute the query on\n * @param sql - SQL query string to execute\n * @param params - Query parameters to bind to the SQL statement\n * @param filepath - Optional file path for tracking purposes\n * @returns Array of query results of type T\n * @throws {Error} if query execution fails\n */\n public executeQuery<T>(\n db: SqliteDatabase,\n sql: string,\n params: unknown[] = [],\n filepath?: string,\n ): T[] {\n const execution: QueryExecution = {\n sql,\n params,\n startTime: Date.now(),\n };\n if (filepath !== undefined) {\n execution.filepath = filepath;\n }\n\n try {\n // Execute the query (timeout is already set on the connection)\n const stmt = db.prepare(sql);\n const result = stmt.all(...params) as T[];\n\n // Record success metrics\n execution.endTime = Date.now();\n execution.duration = execution.endTime - execution.startTime;\n execution.rowCount = result.length;\n\n this.recordExecution(execution);\n\n return result;\n } catch (error) {\n // Record error metrics\n execution.endTime = Date.now();\n execution.duration = execution.endTime - execution.startTime;\n execution.error = error as Error;\n\n this.recordExecution(execution);\n\n throw error;\n }\n }\n\n /**\n * Execute a single row query with monitoring\n * @param db - Database connection to execute the query on\n * @param sql - SQL query string to execute\n * @param params - Query parameters to bind to the SQL statement\n * @param filepath - Optional file path for tracking purposes\n * @returns Single query result of type T, or undefined if no results\n * @throws {Error} if query execution fails\n */\n public executeGet<T>(\n db: SqliteDatabase,\n sql: string,\n params: unknown[] = [],\n filepath?: string,\n ): T | undefined {\n const execution: QueryExecution = {\n sql,\n params,\n startTime: Date.now(),\n };\n if (filepath !== undefined) {\n execution.filepath = filepath;\n }\n\n try {\n // Execute the query (timeout is already set on the connection)\n const stmt = db.prepare(sql);\n const result = stmt.get(...params) as T | undefined;\n\n // Record success metrics\n execution.endTime = Date.now();\n execution.duration = execution.endTime - execution.startTime;\n execution.rowCount = result !== undefined ? 1 : 0;\n\n this.recordExecution(execution);\n\n return result;\n } catch (error) {\n // Record error metrics\n execution.endTime = Date.now();\n execution.duration = execution.endTime - execution.startTime;\n execution.error = error as Error;\n\n this.recordExecution(execution);\n\n throw error;\n }\n }\n\n /**\n * Create a monitored statement wrapper\n * @param db - Database connection to prepare the statement on\n * @param sql - SQL query string to prepare\n * @param filepath - Optional file path for tracking purposes\n * @returns MonitoredStatement instance that wraps the prepared statement\n */\n public prepareStatement<T>(\n db: SqliteDatabase,\n sql: string,\n filepath?: string,\n ): MonitoredStatement<T> {\n const stmt = db.prepare(sql);\n return new MonitoredStatement(stmt, sql, this, filepath);\n }\n\n /**\n * Record query execution\n * @param execution - Query execution metrics to record\n */\n private recordExecution(execution: QueryExecution): void {\n // Update statistics\n this.totalQueries++;\n\n if (execution.duration !== undefined) {\n this.totalDuration += execution.duration;\n\n // Check for slow query\n if (execution.duration > this.options.slowQueryThreshold) {\n this.slowQueries++;\n\n logger.debug(\"Slow query detected\", {\n sql: execution.sql,\n duration: execution.duration,\n rowCount: execution.rowCount,\n filepath: execution.filepath,\n });\n }\n }\n\n if (execution.error) {\n this.errors++;\n\n if (this.options.verbose) {\n logger.error(\"Query failed\", {\n sql: execution.sql,\n error: execution.error.message,\n filepath: execution.filepath,\n });\n }\n } else if (this.options.verbose) {\n logger.debug(\"Query executed\", {\n sql: execution.sql,\n duration: execution.duration,\n rowCount: execution.rowCount,\n });\n }\n\n // Track history\n if (this.options.trackHistory) {\n this.queryHistory.push(execution);\n\n // Trim history if needed\n if (this.queryHistory.length > this.options.maxHistorySize) {\n this.queryHistory.splice(\n 0,\n this.queryHistory.length - this.options.maxHistorySize,\n );\n }\n }\n }\n\n /**\n * Get monitoring statistics\n * @returns Object containing query statistics and metrics\n */\n public getStatistics(): {\n totalQueries: number;\n averageDuration: number;\n slowQueries: number;\n slowQueryRate: number;\n errors: number;\n errorRate: number;\n historySize: number;\n } {\n return {\n totalQueries: this.totalQueries,\n averageDuration:\n this.totalQueries > 0 ? this.totalDuration / this.totalQueries : 0,\n slowQueries: this.slowQueries,\n slowQueryRate:\n this.totalQueries > 0 ? this.slowQueries / this.totalQueries : 0,\n errors: this.errors,\n errorRate: this.totalQueries > 0 ? this.errors / this.totalQueries : 0,\n historySize: this.queryHistory.length,\n };\n }\n\n /**\n * Get query history\n * @param limit - Optional maximum number of recent queries to return\n * @returns Array of query execution records\n */\n public getHistory(limit?: number): QueryExecution[] {\n if (limit !== undefined && limit > 0) {\n return this.queryHistory.slice(-limit);\n }\n return [...this.queryHistory];\n }\n\n /**\n * Clear history\n */\n public clearHistory(): void {\n this.queryHistory.length = 0;\n }\n\n /**\n * Reset all statistics\n */\n public reset(): void {\n this.clearHistory();\n this.totalQueries = 0;\n this.totalDuration = 0;\n this.slowQueries = 0;\n this.errors = 0;\n }\n}\n\n/**\n * Monitored statement wrapper\n */\nexport class MonitoredStatement<T> {\n /**\n * Creates a monitored wrapper around a prepared SQL statement.\n * This wrapper automatically tracks execution metrics for all queries run through it.\n * @param statement - The prepared SQLite statement to monitor\n * @param sql - The SQL query string for logging and debugging\n * @param monitor - The QueryMonitor instance that will track metrics\n * @param filepath - Optional database file path for additional context in logs\n */\n public constructor(\n private readonly statement: SqliteStatement,\n private readonly sql: string,\n private readonly monitor: QueryMonitor,\n private readonly filepath?: string,\n ) {}\n\n /**\n * Execute all with monitoring\n * @param params - Query parameters to bind to the SQL statement\n * @returns Array of query results of type T\n */\n public all(...params: unknown[]): T[] {\n return this.monitor.executeQuery<T>(\n { prepare: () => this.statement } as unknown as SqliteDatabase,\n this.sql,\n params,\n this.filepath,\n );\n }\n\n /**\n * Execute get with monitoring\n * @param params - Query parameters to bind to the SQL statement\n * @returns Single query result of type T, or undefined if no results\n */\n public get(...params: unknown[]): T | undefined {\n return this.monitor.executeGet<T>(\n { prepare: () => this.statement } as unknown as SqliteDatabase,\n this.sql,\n params,\n this.filepath,\n );\n }\n\n /**\n * Get underlying statement\n * @returns The underlying SQLite statement object\n */\n public getStatement(): SqliteStatement {\n return this.statement;\n }\n}\n\n/**\n * Create a global query monitor instance\n */\nlet globalMonitor: QueryMonitor | null = null;\n\n/**\n * Get or create global query monitor\n * @param options - Optional monitoring configuration options\n * @returns The global QueryMonitor instance\n */\nexport function getGlobalQueryMonitor(\n options?: MonitoringOptions,\n): QueryMonitor {\n globalMonitor ??= new QueryMonitor(options);\n return globalMonitor;\n}\n\n/**\n * Reset global query monitor\n */\nexport function resetGlobalQueryMonitor(): void {\n if (globalMonitor) {\n globalMonitor.reset();\n globalMonitor = null;\n }\n}\n","// External imports\nimport { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport fg from \"fast-glob\";\n\n// Internal imports\nimport { createTaggedLogger } from \"../../utils/logHelpers\";\n\nimport { chromeApplicationSupport } from \"./chrome/ChromeApplicationSupport\";\n\nconst logger = createTaggedLogger(\"listChromeProfiles\");\n\n/**\n * Lists all Chrome profile paths that contain cookie files\n * @internal\n * @returns An array of absolute paths to Chrome cookie files\n * @throws {Error} If Chrome's application support directory cannot be accessed\n * @example\n * ```typescript\n * // Get all Chrome cookie file paths\n * const cookiePaths = listChromeProfilePaths();\n * // Returns: [\n * // '/Users/name/Library/Application Support/Chrome/Profile 1/Cookies',\n * // '/Users/name/Library/Application Support/Chrome/Profile 2/Cookies'\n * // ]\n *\n * // Handle errors\n * try {\n * const paths = listChromeProfilePaths();\n * } catch (error) {\n * logger.error('Failed to access Chrome profiles', { error });\n * }\n * ```\n */\nexport function listChromeProfilePaths(): string[] {\n const files: string[] = fg.sync(\"./**/Cookies\", {\n cwd: chromeApplicationSupport,\n absolute: true,\n });\n\n logger.debug(\"Found cookie files:\", files);\n return files;\n}\n\n/**\n * Chrome Local State file structure\n * @internal\n */\ninterface ChromeLocalState {\n profile: {\n info_cache: Record<string, ChromeProfileInfo>;\n };\n}\n\n/**\n * Chrome profile information structure\n * @property {string} name - The name of the profile\n * @property {number} active_time - Unix timestamp of last profile activity\n * @property {string} account_id - Unique identifier for the Chrome profile\n * @property {Record<string, unknown>} accountcapabilities - Account feature flags\n * @property {string} email - User's email address\n * @property {string} full_name - User's full name\n * @property {boolean} is_using_default_avatar - Whether using default profile picture\n * @property {boolean} is_using_default_name - Whether using default profile name\n * @property {string} last_downloaded_gaia_picture_url_with_size - Profile picture URL\n * @property {string} local_auth_credentials - Authentication credentials\n * @property {string} shortcut_name - Profile shortcut name\n * @property {string} user_name - Username associated with profile\n */\ninterface ChromeProfileInfo {\n /** The name of the profile */\n name: string;\n /** Unix timestamp of last profile activity */\n active_time: number;\n /** Unique identifier for the Chrome profile */\n account_id: string;\n /** Account feature flags */\n accountcapabilities: Record<string, unknown>;\n /** User's email address */\n email: string;\n /** User's full name */\n full_name: string;\n /** Whether using default profile picture */\n is_using_default_avatar: boolean;\n /** Whether using default profile name */\n is_using_default_name: boolean;\n /** Profile picture URL */\n last_downloaded_gaia_picture_url_with_size: string;\n /** Authentication credentials */\n local_auth_credentials: string;\n /** Profile shortcut name */\n shortcut_name: string;\n /** Username associated with profile */\n user_name: string;\n}\n\n/**\n * Lists all Chrome profiles and their associated information\n * @internal\n * @returns An array of Chrome profile information objects. Returns empty array if profiles cannot be read\n * @throws {Error} If Chrome's application support directory cannot be accessed\n * @example\n * ```typescript\n * // Get all Chrome profiles\n * const profiles = listChromeProfiles();\n * // Returns: [\n * // {\n * // name: \"Default\",\n * // email: \"user@example.com\",\n * // full_name: \"John Doe\",\n * // ...\n * // },\n * // ...\n * // ]\n *\n * // Handle empty or error case\n * const profiles = listChromeProfiles();\n * if (profiles.length === 0) {\n * logger.warn('No Chrome profiles found');\n * }\n * ```\n */\nexport function listChromeProfiles(): ChromeProfileInfo[] {\n try {\n const localStatePath = join(chromeApplicationSupport, \"Local State\");\n const localState = JSON.parse(\n readFileSync(localStatePath, \"utf8\"),\n ) as ChromeLocalState;\n return Object.values(localState.profile.info_cache);\n } catch (error) {\n logger.debug(\"Failed to access Chrome profiles\", { error });\n return [];\n }\n}\n","import { dirname } from \"node:path\";\n\nimport { BaseChromiumCookieQueryStrategy } from \"../chromium/BaseChromiumCookieQueryStrategy\";\nimport { listChromeProfilePaths } from \"../listChromeProfiles\";\n\n/**\n * Interface representing Chrome profile information from Local State\n */\ninterface ChromeProfileInfo {\n name?: string;\n user_name?: string;\n [key: string]: unknown;\n}\n\n/**\n * Strategy for querying cookies from Chrome browser.\n * This class extends the BaseChromiumCookieQueryStrategy with Chrome-specific logic.\n * @example\n * ```typescript\n * const strategy = new ChromeCookieQueryStrategy();\n * const cookies = await strategy.queryCookies('session', 'example.com');\n * ```\n */\nexport class ChromeCookieQueryStrategy extends BaseChromiumCookieQueryStrategy {\n private readonly profileName?: string;\n\n /**\n * Creates a new instance of ChromeCookieQueryStrategy\n * @param profileName - Optional specific profile name to target\n */\n public constructor(profileName?: string) {\n super(\"ChromeCookieQueryStrategy\", \"Chrome\");\n if (profileName !== undefined) {\n this.profileName = profileName;\n }\n }\n\n /**\n * Get Chrome-specific cookie file paths\n * @param store - Optional specific store path\n * @returns Array of cookie file paths\n */\n protected getCookieFilePaths(store?: string): string[] {\n if (store !== undefined && store !== \"\") {\n return [store];\n }\n\n let paths = listChromeProfilePaths();\n\n // Filter by profile name if specified\n if (this.profileName) {\n // Read Chrome's Local State to map profile names to directories\n try {\n const fs = require(\"node:fs\");\n const path = require(\"node:path\");\n\n // Ensure we have at least one path to determine the Chrome data directory\n if (paths.length === 0) {\n this.logger.warn(\"No Chrome cookie files found\");\n return [];\n }\n\n const firstPath = paths[0];\n if (!firstPath) {\n return [];\n }\n const chromeDataDir = dirname(dirname(firstPath)); // Get Chrome data directory\n const localStatePath = path.join(chromeDataDir, \"Local State\");\n\n if (fs.existsSync(localStatePath)) {\n const localState = JSON.parse(\n fs.readFileSync(localStatePath, \"utf8\"),\n );\n const profileCache = localState.profile?.info_cache || {};\n\n // Find the directory for the given profile name\n let targetDir: string | undefined;\n\n for (const [dir, info] of Object.entries(profileCache)) {\n const profile = info as ChromeProfileInfo;\n if (\n profile.name?.toLowerCase() === this.profileName.toLowerCase()\n ) {\n targetDir = dir;\n break;\n }\n }\n\n // Also check if user passed the directory name directly (e.g., \"Default\" or \"Profile 2\")\n if (!targetDir) {\n for (const dir of Object.keys(profileCache)) {\n if (dir.toLowerCase() === this.profileName.toLowerCase()) {\n targetDir = dir;\n break;\n }\n }\n }\n\n if (targetDir) {\n // Filter paths to only include the target directory\n paths = paths.filter((cookiePath) => {\n const dir = dirname(cookiePath);\n return dir.endsWith(targetDir);\n });\n\n if (paths.length === 0) {\n this.logger.warn(\n `No cookie files found for profile: ${this.profileName} (directory: ${targetDir})`,\n );\n } else {\n this.logger.debug(\n `Found ${paths.length} cookie file(s) for profile: ${this.profileName}`,\n );\n }\n } else {\n this.logger.debug(\"Profile not found in Chrome Local State\", {\n requestedProfile: this.profileName,\n availableProfiles: Object.entries(profileCache).map(\n ([dir, info]) => ({\n directory: dir,\n name: (info as ChromeProfileInfo).name,\n }),\n ),\n });\n\n // Return empty array to avoid querying wrong profile\n return [];\n }\n }\n } catch (error) {\n this.logger.warn(`Failed to read Chrome profile info: ${error}`);\n }\n }\n\n return Array.isArray(paths) ? paths : [paths];\n }\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { assertPlatformSupported, getPlatform } from \"@utils/platformUtils\";\n\n/**\n * Chromium browser configuration and path management\n * Supports Chrome, Chromium, Brave, Edge, Opera, Vivaldi, and Whale browsers\n * across Windows, macOS, and Linux platforms\n */\n\n/**\n * Supported Chromium-based browsers\n */\nexport const CHROMIUM_BASED_BROWSERS = [\n \"chrome\",\n \"chromium\",\n \"brave\",\n \"edge\",\n \"arc\",\n \"opera\",\n \"opera-gx\",\n \"vivaldi\",\n \"whale\",\n] as const;\n\n/**\n * Type representing all supported Chromium-based browsers.\n * This includes Chrome, Edge, Brave, Arc, Opera, and other Chromium derivatives.\n */\nexport type ChromiumBrowser = (typeof CHROMIUM_BASED_BROWSERS)[number];\n\n/**\n * Browser directory configuration for different platforms\n */\ninterface BrowserPaths {\n windows: string;\n macos: string;\n linux: string;\n}\n\n/**\n * Get the browser configuration directory for a specific browser and platform\n * @param browser - The chromium browser type\n * @returns The path to the browser's configuration directory\n * @throws {Error} If the user home directory cannot be determined or platform is unsupported\n */\nexport function getChromiumBrowserPath(browser: ChromiumBrowser): string {\n const home = homedir();\n if (!home) {\n throw new Error(\"Unable to determine user home directory\");\n }\n\n assertPlatformSupported();\n const currentPlatform = getPlatform();\n\n const browserPaths: Record<ChromiumBrowser, BrowserPaths> = {\n chrome: {\n windows: join(home, \"AppData\", \"Local\", \"Google\", \"Chrome\", \"User Data\"),\n macos: join(home, \"Library\", \"Application Support\", \"Google\", \"Chrome\"),\n linux: join(home, \".config\", \"google-chrome\"),\n },\n chromium: {\n windows: join(home, \"AppData\", \"Local\", \"Chromium\", \"User Data\"),\n macos: join(home, \"Library\", \"Application Support\", \"Chromium\"),\n linux: join(home, \".config\", \"chromium\"),\n },\n brave: {\n windows: join(\n home,\n \"AppData\",\n \"Local\",\n \"BraveSoftware\",\n \"Brave-Browser\",\n \"User Data\",\n ),\n macos: join(\n home,\n \"Library\",\n \"Application Support\",\n \"BraveSoftware\",\n \"Brave-Browser\",\n ),\n linux: join(home, \".config\", \"BraveSoftware\", \"Brave-Browser\"),\n },\n edge: {\n windows: join(home, \"AppData\", \"Local\", \"Microsoft\", \"Edge\", \"User Data\"),\n macos: join(home, \"Library\", \"Application Support\", \"Microsoft Edge\"),\n linux: join(home, \".config\", \"microsoft-edge\"),\n },\n arc: {\n windows: join(home, \"AppData\", \"Local\", \"Arc\", \"User Data\"),\n macos: join(home, \"Library\", \"Application Support\", \"Arc\", \"User Data\"),\n linux: join(home, \".config\", \"arc\"),\n },\n opera: {\n windows: join(\n home,\n \"AppData\",\n \"Roaming\",\n \"Opera Software\",\n \"Opera Stable\",\n ),\n macos: join(\n home,\n \"Library\",\n \"Application Support\",\n \"com.operasoftware.Opera\",\n ),\n linux: join(home, \".config\", \"opera\"),\n },\n \"opera-gx\": {\n windows: join(\n home,\n \"AppData\",\n \"Roaming\",\n \"Opera Software\",\n \"Opera GX Stable\",\n ),\n macos: join(\n home,\n \"Library\",\n \"Application Support\",\n \"com.operasoftware.OperaGX\",\n ),\n linux: join(home, \".config\", \"opera-gx\"),\n },\n vivaldi: {\n windows: join(home, \"AppData\", \"Local\", \"Vivaldi\", \"User Data\"),\n macos: join(home, \"Library\", \"Application Support\", \"Vivaldi\"),\n linux: join(home, \".config\", \"vivaldi\"),\n },\n whale: {\n windows: join(\n home,\n \"AppData\",\n \"Local\",\n \"Naver\",\n \"Naver Whale\",\n \"User Data\",\n ),\n macos: join(home, \"Library\", \"Application Support\", \"Naver\", \"Whale\"),\n linux: join(home, \".config\", \"naver-whale\"),\n },\n };\n\n const paths = browserPaths[browser];\n\n switch (currentPlatform) {\n case \"win32\":\n return paths.windows;\n case \"darwin\":\n return paths.macos;\n case \"linux\":\n return paths.linux;\n default:\n throw new Error(`Platform ${currentPlatform} is not supported`);\n }\n}\n\n/**\n * Get all Chromium browser paths for the current platform\n * @returns Record mapping browser names to their configuration directory paths\n */\nexport function getAllChromiumBrowserPaths(): Record<ChromiumBrowser, string> {\n const result: Partial<Record<ChromiumBrowser, string>> = {};\n\n for (const browser of CHROMIUM_BASED_BROWSERS) {\n try {\n result[browser] = getChromiumBrowserPath(browser);\n } catch {\n // Skip browsers that fail (e.g., unsupported platform)\n }\n }\n\n return result as Record<ChromiumBrowser, string>;\n}\n","import fg from \"fast-glob\";\n\nimport {\n type ChromiumBrowser,\n getChromiumBrowserPath,\n} from \"../chrome/ChromiumBrowsers\";\n\nimport { BaseChromiumCookieQueryStrategy } from \"./BaseChromiumCookieQueryStrategy\";\n\n/**\n * Strategy for querying cookies from Chromium-based browsers (Chrome, Brave, Edge, etc.)\n * This class extends the BaseChromiumCookieQueryStrategy with browser-specific path discovery.\n * @example\n * ```typescript\n * const strategy = new ChromiumCookieQueryStrategy('brave');\n * const cookies = await strategy.queryCookies('session', 'example.com');\n * ```\n */\nexport class ChromiumCookieQueryStrategy extends BaseChromiumCookieQueryStrategy {\n private readonly browser: ChromiumBrowser;\n\n /**\n * Creates a new instance of ChromiumCookieQueryStrategy\n * @param browser - The Chromium-based browser to query (chrome, brave, edge, etc.)\n */\n public constructor(browser: ChromiumBrowser = \"chrome\") {\n const browserName = browser.charAt(0).toUpperCase() + browser.slice(1);\n super(`${browserName}CookieQueryStrategy`, browserName, browser);\n this.browser = browser;\n }\n\n /**\n * Get browser-specific cookie file paths\n * @param store - Optional specific store path\n * @returns Array of cookie file paths\n */\n protected getCookieFilePaths(store?: string): string[] {\n if (store !== undefined && store !== \"\") {\n return [store];\n }\n\n try {\n const browserPath = getChromiumBrowserPath(this.browser);\n const files = fg.sync(\"./**/Cookies\", {\n cwd: browserPath,\n absolute: true,\n });\n\n this.logger.debug(\n `Found ${files.length} cookie files for ${this.browser}`,\n );\n\n return files;\n } catch (error) {\n this.logger.warn(`Failed to find ${this.browser} cookie files`, {\n error: this.getErrorMessage(error),\n });\n return [];\n }\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport fg from \"fast-glob\";\n\nimport { getErrorMessage } from \"@utils/errorUtils\";\nimport type { createTaggedLogger } from \"@utils/logHelpers\";\nimport { getPlatform } from \"@utils/platformUtils\";\nimport { isFirefoxRunning } from \"@utils/ProcessDetector\";\n\nimport type { ExportedCookie } from \"../../../types/schemas\";\nimport { BaseCookieQueryStrategy } from \"../BaseCookieQueryStrategy\";\nimport { BrowserLockHandler } from \"../BrowserLockHandler\";\nimport { getGlobalConnectionManager } from \"../sql/DatabaseConnectionManager\";\nimport { getGlobalQueryMonitor } from \"../sql/QueryMonitor\";\n\ninterface FirefoxCookieRow {\n name: string;\n value: string;\n domain: string;\n expiry: number;\n}\n\n/**\n * Find all Firefox cookie database files\n * @param logger - Logger instance for logging messages\n * @returns An array of file paths to Firefox cookie databases\n */\nfunction findFirefoxCookieFiles(\n logger: ReturnType<typeof createTaggedLogger>,\n): string[] {\n const home = homedir();\n if (!home) {\n logger.warn(\"Failed to get home directory\");\n return [];\n }\n\n // Fast path: Check if Firefox profile directories exist before attempting glob\n const platform = getPlatform();\n const profileDirs: string[] = [];\n const patterns: string[] = [];\n\n switch (platform) {\n case \"darwin\":\n profileDirs.push(join(home, \"Library/Application Support/Firefox\"));\n patterns.push(\n join(\n home,\n \"Library/Application Support/Firefox/Profiles/*/cookies.sqlite\",\n ),\n );\n break;\n case \"win32\": {\n // Regular Firefox\n profileDirs.push(join(home, \"AppData\", \"Roaming\", \"Mozilla\", \"Firefox\"));\n patterns.push(\n join(\n home,\n \"AppData\",\n \"Roaming\",\n \"Mozilla\",\n \"Firefox\",\n \"Profiles\",\n \"*\",\n \"cookies.sqlite\",\n ),\n );\n // Firefox Developer Edition\n const devEditionPath = join(\n home,\n \"AppData\",\n \"Roaming\",\n \"Mozilla\",\n \"Firefox Developer Edition\",\n );\n if (existsSync(devEditionPath)) {\n profileDirs.push(devEditionPath);\n patterns.push(join(devEditionPath, \"Profiles\", \"*\", \"cookies.sqlite\"));\n }\n // Firefox ESR (Extended Support Release)\n const esrPath = join(\n home,\n \"AppData\",\n \"Roaming\",\n \"Mozilla\",\n \"Firefox ESR\",\n );\n if (existsSync(esrPath)) {\n profileDirs.push(esrPath);\n patterns.push(join(esrPath, \"Profiles\", \"*\", \"cookies.sqlite\"));\n }\n // Also check Local AppData for some installations\n const localFirefoxPath = join(\n home,\n \"AppData\",\n \"Local\",\n \"Mozilla\",\n \"Firefox\",\n );\n if (existsSync(localFirefoxPath)) {\n profileDirs.push(localFirefoxPath);\n patterns.push(\n join(localFirefoxPath, \"Profiles\", \"*\", \"cookies.sqlite\"),\n );\n }\n break;\n }\n case \"linux\":\n profileDirs.push(join(home, \".mozilla/firefox\"));\n patterns.push(join(home, \".mozilla/firefox/*/cookies.sqlite\"));\n break;\n default:\n logger.debug(\"Unsupported platform for Firefox cookie extraction\", {\n platform,\n });\n return [];\n }\n\n const existingProfileDirs = profileDirs.filter((dir) => existsSync(dir));\n\n if (existingProfileDirs.length === 0) {\n logger.debug(\n \"No Firefox profile directories found - Firefox may not be installed\",\n {\n checked: profileDirs,\n platform,\n },\n );\n return [];\n }\n\n const files: string[] = [];\n for (const pattern of patterns) {\n const matches = fg.sync(pattern);\n files.push(...matches);\n }\n\n logger.debug(\"Found Firefox cookie files\", { files });\n return files;\n}\n\n/**\n * Strategy for querying cookies from Firefox browser.\n * This class extends the BaseCookieQueryStrategy and implements Firefox-specific\n * cookie extraction logic. It searches for cookie databases in standard Firefox\n * profile locations and extracts cookies matching the specified name and domain.\n * @example\n * ```typescript\n * import { FirefoxCookieQueryStrategy } from './FirefoxCookieQueryStrategy';\n *\n * const strategy = new FirefoxCookieQueryStrategy();\n * const cookies = await strategy.queryCookies('sessionid', 'example.com');\n * console.log(cookies);\n * ```\n */\nexport class FirefoxCookieQueryStrategy extends BaseCookieQueryStrategy {\n private readonly lockHandler: BrowserLockHandler;\n\n /**\n * Creates a new instance of FirefoxCookieQueryStrategy\n */\n public constructor() {\n super(\"FirefoxCookieQueryStrategy\", \"Firefox\");\n this.lockHandler = new BrowserLockHandler(this.logger, \"Firefox\");\n }\n\n /**\n * Creates the query parameters for cookie extraction using the new query builder\n * @param name - The cookie name to search for\n * @param domain - The domain pattern to match cookies against\n * @param file - The database file path for metadata\n * @returns Query configuration object\n * @private\n */\n private async createCookieQueryConfig(\n name: string,\n domain: string,\n file: string,\n ): Promise<{\n file: string;\n sql: string;\n params: unknown[];\n rowTransform: (row: FirefoxCookieRow) => ExportedCookie;\n }> {\n // Import the query builder dynamically to avoid circular dependencies\n const { CookieQueryBuilder } = await import(\"../sql/CookieQueryBuilder\");\n const queryBuilder = new CookieQueryBuilder(\"firefox\");\n\n const queryConfig = queryBuilder.buildSelectQuery({\n name,\n domain,\n browser: \"firefox\",\n });\n\n return {\n file,\n sql: queryConfig.sql,\n params: queryConfig.params,\n rowTransform: (row: FirefoxCookieRow): ExportedCookie => ({\n name: row.name,\n value: row.value,\n domain: row.domain,\n expiry: row.expiry > 0 ? new Date(row.expiry * 1000) : \"Infinity\",\n meta: {\n file,\n browser: \"Firefox\",\n decrypted: false,\n },\n }),\n };\n }\n\n /**\n * Handles errors that occur during cookie extraction\n * @param error - The error that occurred\n * @param file - The database file being queried\n * @param force - Whether operations are being forced\n * @param name - The cookie name being searched\n * @param domain - The domain being searched\n * @returns Promise resolving to retry configuration\n * @private\n */\n private async handleCookieExtractionError(\n error: unknown,\n file: string,\n force: boolean | undefined,\n name: string,\n domain: string,\n ): Promise<{ retryAfterClose: boolean; shouldRelaunch: boolean }> {\n const processes = await isFirefoxRunning();\n const lockResult = await this.lockHandler.handleBrowserConflict(\n error,\n file,\n processes,\n force !== true,\n );\n\n if (lockResult.resolved) {\n return {\n retryAfterClose: true,\n shouldRelaunch: lockResult.shouldRelaunch,\n };\n }\n\n this.logExtractError(error, file, name, domain);\n return { retryAfterClose: false, shouldRelaunch: false };\n }\n\n /**\n * Logs cookie extraction errors in a consistent format\n * @param error - The error to log\n * @param file - The file that failed\n * @param name - The cookie name\n * @param domain - The domain\n * @private\n */\n private logExtractError(\n error: unknown,\n file: string,\n name: string,\n domain: string,\n ): void {\n this.logger.debug(`Error reading Firefox cookie file ${file}`, {\n error: getErrorMessage(error),\n file,\n name,\n domain,\n });\n }\n\n /**\n * Performs a retry attempt after browser closure\n * @param queryConfig - The cookie query configuration\n * @param shouldRelaunch - Whether to relaunch the browser after success\n * @returns Promise resolving to extracted cookies\n * @private\n */\n private async performRetryAfterClose(\n queryConfig: Awaited<ReturnType<typeof this.createCookieQueryConfig>>,\n shouldRelaunch: boolean,\n ): Promise<ExportedCookie[]> {\n this.logger.info(\n \"Retrying Firefox cookie extraction after browser close...\",\n );\n\n try {\n const cookies = await this.executeQueryWithNewUtilities(queryConfig);\n this.logger.success(\n \"Successfully extracted cookies after closing Firefox\",\n );\n\n if (shouldRelaunch) {\n await this.lockHandler.relaunchBrowser();\n }\n\n return cookies;\n } catch (retryError) {\n this.logger.error(\n \"Failed to extract cookies even after closing Firefox\",\n {\n error:\n retryError instanceof Error\n ? retryError.message\n : String(retryError),\n file: queryConfig.file,\n },\n );\n\n if (shouldRelaunch) {\n await this.lockHandler.relaunchBrowser();\n }\n\n return [];\n }\n }\n\n /**\n * Processes a single Firefox cookie file for the given parameters\n * @param file - The cookie file to process\n * @param name - The cookie name to search for\n * @param domain - The domain pattern to match\n * @param force - Whether to force operations despite warnings\n * @returns Promise resolving to extracted cookies from this file\n * @private\n */\n private async processCookieFile(\n file: string,\n name: string,\n domain: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n const queryConfig = await this.createCookieQueryConfig(name, domain, file);\n\n try {\n return await this.executeQueryWithNewUtilities(queryConfig);\n } catch (error) {\n const retryConfig = await this.handleCookieExtractionError(\n error,\n file,\n force,\n name,\n domain,\n );\n\n if (retryConfig.retryAfterClose) {\n return this.performRetryAfterClose(\n queryConfig,\n retryConfig.shouldRelaunch,\n );\n }\n\n return [];\n }\n }\n\n /**\n * Execute query using the new SQL utilities\n * @param queryConfig - Query configuration from createCookieQueryConfig\n * @param queryConfig.file\n * @param queryConfig.sql\n * @param queryConfig.params\n * @param queryConfig.rowTransform\n * @returns Promise resolving to exported cookies\n * @private\n */\n private async executeQueryWithNewUtilities(queryConfig: {\n file: string;\n sql: string;\n params: unknown[];\n rowTransform: (row: FirefoxCookieRow) => ExportedCookie;\n }): Promise<ExportedCookie[]> {\n const connectionManager = getGlobalConnectionManager({\n retryAttempts: 1, // Fail fast for Firefox - we have lock handling\n retryDelay: 0, // No delay - let lock handler deal with it\n queryTimeout: 100, // Very short timeout for Firefox to fail fast on locks\n enableMonitoring: true,\n });\n\n const monitor = getGlobalQueryMonitor();\n\n return connectionManager.executeQuery(\n queryConfig.file,\n (db) => {\n // Use the query monitor for tracking\n const rows = monitor.executeQuery<FirefoxCookieRow>(\n db,\n queryConfig.sql,\n queryConfig.params,\n queryConfig.file,\n );\n\n // Apply transformation\n return rows.map(queryConfig.rowTransform);\n },\n queryConfig.sql, // Pass SQL for monitoring\n );\n }\n\n /**\n * Executes the Firefox-specific query logic\n * @param name - The name pattern to match cookies against\n * @param domain - The domain pattern to match cookies against\n * @param store - Optional path to a specific cookie store file\n * @param force - Whether to force operations despite warnings (e.g., locked databases)\n * @returns A promise that resolves to an array of exported cookies\n * @protected\n */\n protected async executeQuery(\n name: string,\n domain: string,\n store?: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n const files = store ?? findFirefoxCookieFiles(this.logger);\n const fileList = Array.isArray(files) ? files : [files];\n\n // Fast path: If no Firefox cookie files found (Firefox not installed),\n // return early to avoid unnecessary database queries and process detection\n if (fileList.length === 0) {\n this.logger.debug(\"No Firefox cookie files to query\");\n return [];\n }\n\n const results: ExportedCookie[] = [];\n\n for (const file of fileList) {\n const cookies = await this.processCookieFile(file, name, domain, force);\n results.push(...cookies);\n }\n\n return results;\n }\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { errorMessageContains, formatErrorForLogging } from \"@utils/errorUtils\";\nimport { isMacOS } from \"@utils/platformUtils\";\nimport { isSafariRunning } from \"@utils/ProcessDetector\";\nimport {\n checkFilePermission,\n handleSafariPermissionError,\n} from \"@utils/SystemPermissions\";\n\nimport type { ExportedCookie } from \"../../../types/schemas\";\nimport { BaseCookieQueryStrategy } from \"../BaseCookieQueryStrategy\";\nimport { BrowserLockHandler } from \"../BrowserLockHandler\";\n\nimport { decodeBinaryCookies } from \"./decodeBinaryCookies\";\n\n/**\n * Strategy for querying cookies from Safari browser.\n * This class extends the BaseCookieQueryStrategy and implements Safari-specific\n * cookie extraction logic.\n */\nexport class SafariCookieQueryStrategy extends BaseCookieQueryStrategy {\n private readonly lockHandler: BrowserLockHandler;\n\n /**\n * Creates a new instance of SafariCookieQueryStrategy\n */\n public constructor() {\n super(\"SafariCookieQueryStrategy\", \"Safari\");\n this.lockHandler = new BrowserLockHandler(this.logger, \"Safari\");\n }\n\n /**\n * Gets the path to Safari's cookie database\n * @param home - The user's home directory\n * @returns Path to the cookie database\n */\n private getCookieDbPath(home: string): string {\n return join(\n home,\n \"Library\",\n \"Containers\",\n \"com.apple.Safari\",\n \"Data\",\n \"Library\",\n \"Cookies\",\n \"Cookies.binarycookies\",\n );\n }\n\n /**\n * Formats the domain by removing leading dot if present\n * @param domain - Domain to format\n * @returns Formatted domain or empty string if domain is invalid\n */\n private formatDomain(domain: string | undefined | null): string {\n if (domain === null || domain === undefined || typeof domain !== \"string\") {\n return \"\";\n }\n return domain.startsWith(\".\") ? domain.slice(1) : domain;\n }\n\n /**\n * Formats the expiry date\n * @param expiry - Expiry timestamp (Unix epoch seconds)\n * @returns Formatted expiry date or \"Infinity\"\n */\n private formatExpiry(\n expiry: number | undefined | null,\n ): Date | \"Infinity\" | undefined {\n // Handle undefined or null - return undefined instead of NaN date\n if (expiry === undefined || expiry === null) {\n return undefined;\n }\n\n if (typeof expiry !== \"number\" || Number.isNaN(expiry) || expiry <= 0) {\n return \"Infinity\";\n }\n\n // Validate timestamp is reasonable (1970-2100 range in seconds)\n const minTimestamp = 0; // 1970-01-01\n const maxTimestamp = 4102444800; // 2100-01-01\n\n if (expiry < minTimestamp || expiry > maxTimestamp) {\n this.logger.warn(\"Invalid expiry timestamp, treating as session cookie\", {\n expiry,\n });\n return \"Infinity\";\n }\n\n return new Date(expiry * 1000);\n }\n\n /**\n * Checks if a flag bit is set\n * @param flags - The flags value\n * @param bit - The bit to check\n * @returns True if the bit is set, false otherwise\n */\n private isFlagSet(flags: number | undefined | null, bit: number): boolean {\n if (typeof flags !== \"number\" || Number.isNaN(flags) || flags <= 0) {\n return false;\n }\n return (flags & bit) === bit;\n }\n\n /**\n * Formats the creation timestamp\n * @param creation - Creation timestamp (Unix epoch seconds)\n * @returns Formatted creation timestamp in milliseconds or undefined\n */\n private formatCreation(\n creation: number | undefined | null,\n ): number | undefined {\n if (\n typeof creation !== \"number\" ||\n Number.isNaN(creation) ||\n creation <= 0\n ) {\n return undefined;\n }\n\n // Validate timestamp is reasonable (1970-2100 range in seconds)\n const minTimestamp = 0; // 1970-01-01\n const maxTimestamp = 4102444800; // 2100-01-01\n\n if (creation < minTimestamp || creation > maxTimestamp) {\n this.logger.warn(\"Invalid creation timestamp, ignoring\", { creation });\n return undefined;\n }\n\n return creation * 1000;\n }\n\n /**\n * Processes a cookie value to ensure it's a string\n * @param value - The cookie value to process\n * @returns The processed value as a string\n */\n private processValue(value: unknown): string {\n if (value === null) {\n return \"null\";\n }\n\n if (value === undefined) {\n return \"undefined\";\n }\n\n if (Buffer.isBuffer(value)) {\n return value.toString();\n }\n\n if (typeof value === \"object\") {\n try {\n return JSON.stringify(value);\n } catch {\n // If JSON.stringify fails (e.g., circular reference), return a placeholder\n return \"[object]\";\n }\n }\n\n // Handle primitives (string, number, boolean, etc.)\n if (typeof value === \"string\") {\n return value;\n }\n\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n\n // Fallback for any other type (should not happen with proper typing)\n return \"[unknown value]\";\n }\n\n /**\n * Decodes cookies from Safari's binary cookie file\n * @param cookieDbPath - Path to the cookie database\n * @param name - Name of the cookie to find\n * @param domain - Domain to filter cookies by\n * @param force - Whether to skip interactive prompts\n * @returns Array of exported cookies\n */\n private async decodeCookies(\n cookieDbPath: string,\n name: string,\n domain: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n try {\n // Check permissions first\n const permissionResult = await this.checkAndHandlePermissions(\n cookieDbPath,\n force,\n );\n if (!permissionResult) {\n return [];\n }\n\n // Decode cookies and process them\n const cookies = decodeBinaryCookies(cookieDbPath);\n return this.processCookies(cookies, name, domain, cookieDbPath);\n } catch (error: unknown) {\n return this.handleDecodingError(error, cookieDbPath, name, domain, force);\n }\n }\n\n /**\n * Check file permissions and handle permission errors\n * @param cookieDbPath - Path to the cookie database\n * @param force - Whether to skip interactive prompts\n * @returns True if permissions are granted, false otherwise\n */\n private async checkAndHandlePermissions(\n cookieDbPath: string,\n force?: boolean,\n ): Promise<boolean> {\n const hasPermission = await checkFilePermission(cookieDbPath);\n if (hasPermission) {\n return true;\n }\n\n this.logger.warn(\"Cannot access Safari cookies due to macOS permissions\", {\n file: cookieDbPath,\n suggestion: \"Terminal application needs Full Disk Access permission\",\n });\n\n // Try to handle the permission error interactively\n const permissionGranted = await handleSafariPermissionError(\n new Error(\"EPERM: operation not permitted\"),\n {\n appName: process.env.TERM_PROGRAM ?? \"Terminal\",\n browserName: \"Safari\",\n interactive: force !== true,\n },\n );\n\n if (!permissionGranted) {\n return false;\n }\n\n // Check again after permission might have been granted\n const stillNoPermission = !(await checkFilePermission(cookieDbPath));\n if (stillNoPermission) {\n this.logger.error(\n \"Still cannot access Safari cookies after permission attempt\",\n {\n file: cookieDbPath,\n advice:\n \"Please restart your terminal application after granting Full Disk Access\",\n },\n );\n return false;\n }\n\n return true;\n }\n\n /**\n * Process and filter cookies based on name and domain criteria\n * @param cookies - Raw cookies from binary file\n * @param name - Name filter\n * @param domain - Domain filter\n * @param cookieDbPath - Path to cookie database for metadata\n * @returns Processed and filtered cookies\n */\n private processCookies(\n cookies: unknown[],\n name: string,\n domain: string,\n cookieDbPath: string,\n ): ExportedCookie[] {\n return cookies\n .filter((cookie) => this.matchesCriteria(cookie, name, domain))\n .map((cookie) => this.mapToExportedCookie(cookie, cookieDbPath));\n }\n\n /**\n * Check if cookie matches the search criteria\n * @param cookie - Raw cookie object\n * @param name - Name filter\n * @param domain - Domain filter\n * @returns True if cookie matches criteria\n */\n private matchesCriteria(\n cookie: unknown,\n name: string,\n domain: string,\n ): boolean {\n // Type guard for cookie object\n if (!this.isCookieObject(cookie)) {\n return false;\n }\n\n const formattedDomain = this.formatDomain(cookie.domain);\n\n // Skip cookies with invalid domains\n if (formattedDomain === \"\") {\n return false;\n }\n\n const nameMatches = name === \"%\" || cookie.name === name;\n const domainMatches = domain === \"%\" || formattedDomain.includes(domain);\n\n return nameMatches && domainMatches;\n }\n\n /**\n * Type guard to check if an object is a valid cookie object\n * @param cookie - Object to check\n * @returns True if object has expected cookie properties\n */\n private isCookieObject(cookie: unknown): cookie is {\n domain?: string;\n name: string;\n value: unknown;\n expiry?: number;\n creation?: number;\n flags?: number;\n path?: string;\n version?: number;\n comment?: string;\n commentURL?: string;\n port?: number;\n } {\n return (\n typeof cookie === \"object\" &&\n cookie !== null &&\n \"name\" in cookie &&\n typeof (cookie as { name: unknown }).name === \"string\"\n );\n }\n\n /**\n * Map raw cookie to ExportedCookie format\n * @param cookie - Raw cookie object\n * @param cookieDbPath - Path to cookie database for metadata\n * @returns Formatted ExportedCookie\n */\n private mapToExportedCookie(\n cookie: unknown,\n cookieDbPath: string,\n ): ExportedCookie {\n // We know it's a cookie object due to prior filtering\n const cookieObj = cookie as {\n domain?: string | null;\n name: string;\n value: unknown;\n expiry?: number | null;\n creation?: number | null;\n flags?: number | null;\n path?: string | null;\n version?: number | null;\n comment?: string | null;\n commentURL?: string | null;\n port?: number | null;\n };\n\n return {\n domain: this.formatDomain(cookieObj.domain),\n name: cookieObj.name,\n value: this.processValue(cookieObj.value),\n expiry: this.formatExpiry(cookieObj.expiry),\n meta: {\n file: cookieDbPath,\n browser: \"Safari\" as const,\n decrypted: false,\n secure: this.isFlagSet(cookieObj.flags, 0x1),\n httpOnly: this.isFlagSet(cookieObj.flags, 0x4),\n path: cookieObj.path ?? undefined,\n version:\n cookieObj.version === undefined ? undefined : cookieObj.version,\n comment: cookieObj.comment ?? undefined,\n commentURL: cookieObj.commentURL ?? undefined,\n port: cookieObj.port === undefined ? undefined : cookieObj.port,\n creation: this.formatCreation(cookieObj.creation),\n },\n };\n }\n\n /**\n * Handle errors that occur during cookie decoding\n * @param error - The error that occurred\n * @param cookieDbPath - Path to the cookie database\n * @param name - Name filter used\n * @param domain - Domain filter used\n * @param force - Whether interactive prompts were skipped\n * @returns Empty array as fallback\n */\n private async handleDecodingError(\n error: unknown,\n cookieDbPath: string,\n name: string,\n domain: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n const isPermissionError =\n errorMessageContains(error, \"EPERM\") ||\n errorMessageContains(error, \"operation not permitted\") ||\n errorMessageContains(error, \"Permission denied\");\n\n if (isPermissionError) {\n await this.handlePermissionError(\n error,\n cookieDbPath,\n name,\n domain,\n force,\n );\n } else {\n this.logDecodingError(error, cookieDbPath, name, domain);\n }\n\n return [];\n }\n\n /**\n * Handle permission-related errors\n * @param error - The error that occurred\n * @param cookieDbPath - Path to the cookie database\n * @param name - Name filter used\n * @param domain - Domain filter used\n * @param force - Whether interactive prompts were skipped\n */\n private async handlePermissionError(\n error: unknown,\n cookieDbPath: string,\n name: string,\n domain: string,\n force?: boolean,\n ): Promise<void> {\n const handled = await handleSafariPermissionError(error as Error, {\n appName: process.env.TERM_PROGRAM ?? \"Terminal\",\n browserName: \"Safari\",\n interactive: force !== true,\n });\n\n if (handled) {\n this.logger.info(\n \"Permission flow completed. Please run the command again after granting access.\",\n );\n } else {\n this.logger.warn(\n `Permission denied accessing Safari cookies at ${cookieDbPath}`,\n formatErrorForLogging(error, {\n file: cookieDbPath,\n name,\n domain,\n advice:\n \"Grant Full Disk Access to your terminal in System Settings > Privacy & Security\",\n }),\n );\n }\n }\n\n /**\n * Log non-permission errors that occur during decoding\n * @param error - The error that occurred\n * @param cookieDbPath - Path to the cookie database\n * @param name - Name filter used\n * @param domain - Domain filter used\n */\n private logDecodingError(\n error: unknown,\n cookieDbPath: string,\n name: string,\n domain: string,\n ): void {\n this.logger.error(\n `Error decoding ${cookieDbPath}`,\n formatErrorForLogging(error, {\n file: cookieDbPath,\n name,\n domain,\n }),\n );\n }\n\n /**\n * Executes the Safari-specific query logic\n * @param name - Name of the cookie to find\n * @param domain - Domain to filter cookies by\n * @param store - Optional store path\n * @param force - Whether to force operations despite warnings (e.g., locked databases)\n * @returns Array of matching cookies, or empty array if none found\n * @protected\n */\n protected async executeQuery(\n name: string,\n domain: string,\n store?: string,\n force?: boolean,\n ): Promise<ExportedCookie[]> {\n // Fast path: Safari only exists on macOS\n if (!isMacOS()) {\n this.logger.debug(\"Safari strategy skipped on non-macOS platform\");\n return [];\n }\n\n try {\n this.logger.info(\"Querying cookies\", { name, domain, store });\n\n // Validate home directory\n const home = homedir();\n if (!this.isValidHomeDirectory(home)) {\n return [];\n }\n\n const cookieDbPath = store ?? this.getCookieDbPath(home);\n const normalizedName = name || \"%\";\n const normalizedDomain = domain || \"%\";\n\n // First attempt to decode cookies\n const firstAttemptResult = await this.attemptDecodeWithLockHandling(\n cookieDbPath,\n normalizedName,\n normalizedDomain,\n force,\n );\n\n if (firstAttemptResult.success) {\n return firstAttemptResult.cookies;\n }\n\n // Handle retry scenario if browser was closed\n if (firstAttemptResult.shouldRetry) {\n return this.retryAfterBrowserClose(\n cookieDbPath,\n normalizedName,\n normalizedDomain,\n force,\n firstAttemptResult.shouldRelaunch,\n );\n }\n\n return [];\n } catch (error: unknown) {\n this.logQueryError(error, name, domain);\n return [];\n }\n }\n\n /**\n * Validate home directory\n * @param home - Home directory path\n * @returns True if valid, false otherwise\n */\n private isValidHomeDirectory(home: string): boolean {\n if (typeof home !== \"string\" || home.length === 0) {\n this.logger.error(\"Failed to get home directory\");\n return false;\n }\n return true;\n }\n\n /**\n * Attempt to decode cookies with lock conflict handling\n * @param cookieDbPath - Path to cookie database\n * @param name - Normalized cookie name filter\n * @param domain - Normalized domain filter\n * @param force - Whether to force operations\n * @returns Result object with success status and data\n */\n private async attemptDecodeWithLockHandling(\n cookieDbPath: string,\n name: string,\n domain: string,\n force?: boolean,\n ): Promise<{\n success: boolean;\n cookies: ExportedCookie[];\n shouldRetry: boolean;\n shouldRelaunch: boolean;\n }> {\n try {\n const cookies = await this.decodeCookies(\n cookieDbPath,\n name,\n domain,\n force,\n );\n return {\n success: true,\n cookies,\n shouldRetry: false,\n shouldRelaunch: false,\n };\n } catch (error: unknown) {\n return this.handleLockConflict(error, cookieDbPath, force);\n }\n }\n\n /**\n * Handle browser lock conflicts\n * @param error - The error that occurred\n * @param cookieDbPath - Path to cookie database\n * @param force - Whether to force operations\n * @returns Result indicating what action to take next\n */\n private async handleLockConflict(\n error: unknown,\n cookieDbPath: string,\n force?: boolean,\n ): Promise<{\n success: boolean;\n cookies: ExportedCookie[];\n shouldRetry: boolean;\n shouldRelaunch: boolean;\n }> {\n if (!this.isLockError(error)) {\n throw error; // Re-throw non-lock errors\n }\n\n const processes = await isSafariRunning();\n const lockResult = await this.lockHandler.handleBrowserConflict(\n error,\n cookieDbPath,\n processes,\n force !== true,\n );\n\n if (lockResult.resolved) {\n return {\n success: false,\n cookies: [],\n shouldRetry: true,\n shouldRelaunch: lockResult.shouldRelaunch,\n };\n }\n\n this.logger.warn(\n \"Safari cookie file locked\",\n formatErrorForLogging(error, {\n file: cookieDbPath,\n advice:\n \"Safari may be accessing the cookie file. Try closing Safari and running again.\",\n }),\n );\n\n return {\n success: false,\n cookies: [],\n shouldRetry: false,\n shouldRelaunch: false,\n };\n }\n\n /**\n * Check if error indicates a lock conflict\n * @param error - Error to check\n * @returns True if this is a lock-related error\n */\n private isLockError(error: unknown): boolean {\n return (\n errorMessageContains(error, \"EPERM\") ||\n errorMessageContains(error, \"operation not permitted\") ||\n errorMessageContains(error, \"Permission denied\") ||\n errorMessageContains(error, \"EBUSY\")\n );\n }\n\n /**\n * Retry cookie extraction after browser was closed\n * @param cookieDbPath - Path to cookie database\n * @param name - Cookie name filter\n * @param domain - Domain filter\n * @param force - Whether to force operations\n * @param shouldRelaunch - Whether browser should be relaunched\n * @returns Cookies or empty array\n */\n private async retryAfterBrowserClose(\n cookieDbPath: string,\n name: string,\n domain: string,\n force?: boolean,\n shouldRelaunch?: boolean,\n ): Promise<ExportedCookie[]> {\n try {\n this.logger.info(\n \"Retrying Safari cookie extraction after browser close...\",\n );\n\n const cookies = await this.decodeCookies(\n cookieDbPath,\n name,\n domain,\n force,\n );\n\n this.logger.success(\n \"Successfully extracted cookies after closing Safari\",\n );\n\n if (shouldRelaunch === true) {\n await this.lockHandler.relaunchBrowser();\n }\n\n return cookies;\n } catch (retryError: unknown) {\n return this.handleRetryFailure(retryError, cookieDbPath, shouldRelaunch);\n }\n }\n\n /**\n * Handle failure during retry attempt\n * @param retryError - Error that occurred during retry\n * @param cookieDbPath - Path to cookie database\n * @param shouldRelaunch - Whether browser should be relaunched\n * @returns Empty array\n */\n private async handleRetryFailure(\n retryError: unknown,\n cookieDbPath: string,\n shouldRelaunch?: boolean,\n ): Promise<ExportedCookie[]> {\n this.logger.error(\n \"Failed to extract cookies even after closing Safari\",\n formatErrorForLogging(retryError, { file: cookieDbPath }),\n );\n\n // Still try to relaunch Safari if needed\n if (shouldRelaunch === true) {\n await this.lockHandler.relaunchBrowser();\n }\n\n return [];\n }\n\n /**\n * Log query errors\n * @param error - The error that occurred\n * @param name - Cookie name filter\n * @param domain - Domain filter\n */\n private logQueryError(error: unknown, name: string, domain: string): void {\n this.logger.error(\n \"Failed to query cookies\",\n formatErrorForLogging(error, { name, domain }),\n );\n }\n}\n","import { exec } from \"node:child_process\";\nimport readline from \"node:readline\";\nimport { promisify } from \"node:util\";\n\nimport { errorMessageContains, getErrorMessage } from \"./errorUtils\";\nimport { createTaggedLogger } from \"./logHelpers\";\nimport { isMacOS } from \"./platformUtils\";\n\nconst execAsync = promisify(exec);\nconst logger = createTaggedLogger(\"SystemPermissions\");\n\n/**\n *\n */\nexport interface PermissionRequestOptions {\n appName: string;\n browserName: string;\n interactive?: boolean;\n}\n\n/**\n * Open System Settings to the Full Disk Access page on macOS\n */\nasync function openFullDiskAccessSettings(): Promise<void> {\n try {\n // Open System Settings directly to Privacy & Security > Full Disk Access\n await execAsync(\n 'open \"x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles\"',\n );\n logger.info(\n \"Opened System Settings > Privacy & Security > Full Disk Access\",\n );\n } catch (_error) {\n // Fallback to general Privacy & Security\n try {\n await execAsync(\n 'open \"x-apple.systempreferences:com.apple.preference.security?Privacy\"',\n );\n logger.info(\"Opened System Settings > Privacy & Security\");\n } catch (_fallbackError) {\n // Last resort: just open System Settings\n await execAsync(\"open -b com.apple.systempreferences\");\n logger.info(\"Opened System Settings\");\n }\n }\n}\n\n/**\n * Check which terminal application is running\n * @returns The name of the terminal application or a fallback message\n */\nfunction getTerminalApp(): string {\n const termProgram = process.env.TERM_PROGRAM;\n\n if (termProgram === \"iTerm.app\") {\n return \"iTerm\";\n }\n if (termProgram === \"Apple_Terminal\") {\n return \"Terminal\";\n }\n if (termProgram === \"vscode\") {\n return \"Visual Studio Code\";\n }\n return termProgram ?? \"your terminal application\";\n}\n\n/**\n * Prompt user to grant permissions\n * @param appName - The name of the application requesting permissions\n * @param browserName - The name of the browser being accessed\n * @returns A promise that resolves to true if user grants permission\n */\nasync function promptForPermissionGrant(\n appName: string,\n browserName: string,\n): Promise<boolean> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n console.log(`\n⚠️ ${browserName} cookie access is blocked by macOS security.\n\nTo grant access, ${appName} needs permission to read ${browserName} data.\n\nWould you like to:\n1. Open System Settings to grant permission (recommended)\n2. Skip ${browserName} cookies for now\n3. Exit\n\nPlease enter your choice (1/2/3): `);\n\n rl.question(\"\", (answer) => {\n rl.close();\n resolve(answer.trim() === \"1\");\n });\n });\n}\n\n/**\n * Handle Safari permission errors with user guidance\n * @param error - The error encountered when accessing Safari cookies\n * @param options - Configuration options for permission requests\n * @returns A promise that resolves to true if permissions should be granted\n */\nexport async function handleSafariPermissionError(\n error: Error,\n options: PermissionRequestOptions,\n): Promise<boolean> {\n if (!isMacOS()) {\n return false;\n }\n\n const isPermissionError =\n errorMessageContains(error, \"eperm\") ||\n errorMessageContains(error, \"operation not permitted\") ||\n errorMessageContains(error, \"permission denied\") ||\n errorMessageContains(error, \"authorization denied\");\n\n if (!isPermissionError) {\n return false;\n }\n\n const terminalApp = options.appName || getTerminalApp();\n\n logger.warn(`${options.browserName} cookie access denied by macOS`, {\n app: terminalApp,\n error: getErrorMessage(error),\n });\n\n if (options.interactive !== false) {\n const shouldOpenSettings = await promptForPermissionGrant(\n terminalApp,\n options.browserName,\n );\n\n if (shouldOpenSettings) {\n await openFullDiskAccessSettings();\n\n console.log(`\n✅ System Settings opened to Privacy & Security\n\nPlease follow these steps:\n1. Look for \"${terminalApp}\" in the list\n2. If not present, click the \"+\" button and add it\n3. Enable the toggle next to \"${terminalApp}\"\n4. You may need to restart ${terminalApp} after granting permission\n5. Then run this command again\n\nPress Enter when you've completed these steps...`);\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n await new Promise<void>((resolve) => {\n rl.question(\"\", () => {\n rl.close();\n resolve();\n });\n });\n\n return true;\n }\n } else {\n logger.info(\n `To grant ${options.browserName} access, add ${terminalApp} to System Settings > Privacy & Security > Full Disk Access`,\n );\n }\n\n return false;\n}\n\n/**\n * Check if we have permission to access a file\n * @param filePath - The path to the file to check permissions for\n * @returns A promise that resolves to true if file is accessible\n */\nexport async function checkFilePermission(filePath: string): Promise<boolean> {\n try {\n const { exec } = await import(\"node:child_process\");\n const { promisify } = await import(\"node:util\");\n const execAsync = promisify(exec);\n\n // Try to read the file\n await execAsync(`cat \"${filePath}\" > /dev/null 2>&1`);\n return true;\n } catch {\n return false;\n }\n}\n","import { Buffer } from \"node:buffer\";\nimport { readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport type { BinaryCookieRow } from \"../../../types/schemas\";\nimport { getErrorMessage } from \"../../../utils/errorUtils\";\nimport { createTaggedLogger, logWarn } from \"../../../utils/logHelpers\";\n\nimport { BinaryCodablePage } from \"./BinaryCodablePage\";\nimport type { BinaryCodableContainer } from \"./interfaces/BinaryCodableContainer\";\n\nconst logger = createTaggedLogger(\"BinaryCodableCookies\");\n\n/**\n * Represents a binary cookies file structure used by Safari\n */\nexport class BinaryCodableCookies {\n /**\n *\n */\n public pages: BinaryCodablePage[];\n /**\n *\n */\n public metadata: Record<string, unknown>;\n private static readonly MAGIC = Buffer.from(\"cook\", \"utf8\");\n private static readonly FOOTER = BigInt(\"0x071720050000004b\");\n private static readonly DEFAULT_COOKIE_PATH = join(\n homedir(),\n \"Library/Containers/com.apple.Safari/Data/Library/Cookies/Cookies.binarycookies\",\n );\n\n /**\n * Creates a new BinaryCookies instance from a buffer\n * @param buffer - The raw binary cookie file data\n */\n public constructor(buffer: Buffer) {\n const container: BinaryCodableContainer = { offset: 0, buffer };\n this.pages = [];\n this.metadata = {};\n this.decode(container);\n }\n\n /**\n * Creates a BinaryCookies instance from a file path\n * @param path - Path to the Safari Cookies.binarycookies file\n * @returns A new BinaryCookies instance\n */\n public static fromFile(path: string): BinaryCodableCookies {\n const buffer = readFileSync(path);\n return new BinaryCodableCookies(buffer);\n }\n\n /**\n * Creates a BinaryCookies instance from the default Safari cookies location\n * @returns A new BinaryCookies instance\n */\n public static fromDefaultPath(): BinaryCodableCookies {\n return BinaryCodableCookies.fromFile(\n BinaryCodableCookies.DEFAULT_COOKIE_PATH,\n );\n }\n\n /**\n * Converts the binary cookie data into a validated array of cookie rows\n * @returns Array of validated cookie objects\n */\n public toCookieRows(): BinaryCookieRow[] {\n const cookies: BinaryCookieRow[] = [];\n\n for (const page of this.pages) {\n try {\n const pageCookies = page.toCookieRows();\n if (Array.isArray(pageCookies)) {\n cookies.push(...pageCookies);\n }\n } catch (error) {\n logWarn(\"BinaryCookies\", \"Error converting page cookies\", {\n error: getErrorMessage(error),\n });\n }\n }\n\n return cookies;\n }\n\n private decode(container: BinaryCodableContainer): void {\n try {\n // Check magic value\n const magic = container.buffer.subarray(\n container.offset,\n container.offset + 4,\n );\n container.offset += 4;\n logger.debug(\"Magic bytes:\", magic.toString());\n if (!magic.equals(BinaryCodableCookies.MAGIC)) {\n throw new Error(\"Missing magic value\");\n }\n\n // Read page count\n const pageCount = container.buffer.readUInt32BE(container.offset);\n logger.debug(\"Page count:\", pageCount);\n container.offset += 4;\n\n // Read page sizes\n const pageSizes: number[] = [];\n for (let i = 0; i < pageCount; i++) {\n const pageSize = container.buffer.readUInt32BE(container.offset);\n pageSizes.push(pageSize);\n logger.debug(`Page ${i} size:`, pageSize);\n container.offset += 4;\n }\n\n // Calculate page offsets\n let currentOffset = container.offset;\n logger.debug(\"Starting page data at offset:\", currentOffset);\n for (const pageSize of pageSizes) {\n try {\n logger.debug(\n \"Reading page at offset:\",\n currentOffset,\n \"with size:\",\n pageSize,\n );\n const pageBuffer = container.buffer.subarray(\n currentOffset,\n currentOffset + pageSize,\n );\n const page = new BinaryCodablePage(pageBuffer);\n this.pages.push(page);\n currentOffset += pageSize;\n } catch (error) {\n logger.warn(\"Error decoding page:\", {\n error: getErrorMessage(error),\n });\n currentOffset += pageSize; // Skip the problematic page\n }\n }\n container.offset = currentOffset;\n\n // Read checksum\n const checksum = container.buffer.readUInt32BE(container.offset);\n logger.debug(\"Checksum:\", checksum.toString(16));\n container.offset += 4;\n\n // Read footer\n const footer = container.buffer.readBigUInt64BE(container.offset);\n logger.debug(\"Footer:\", footer.toString(16));\n container.offset += 8;\n if (footer !== BinaryCodableCookies.FOOTER) {\n logWarn(\"BinaryCookies\", \"Invalid cookie file format: wrong footer\");\n }\n\n // Read metadata plist\n // const plistData = container.buffer.subarray(container.offset);\n // Note: You'll need to implement or use a plist parser library here\n this.metadata = {}; // Placeholder for plist data\n } catch (error) {\n logWarn(\"BinaryCookies\", \"Error decoding binary cookies file\", {\n error: getErrorMessage(error),\n });\n throw error;\n }\n }\n}\n","import type { Buffer } from \"node:buffer\";\n\nimport type { BinaryCookieRow } from \"../../../types/schemas\";\nimport { getErrorMessage } from \"../../../utils/errorUtils\";\nimport { createTaggedLogger, logWarn } from \"../../../utils/logHelpers\";\n\nimport { BinaryCodableCookie } from \"./BinaryCodableCookie\";\nimport type { BinaryCodableContainer } from \"./interfaces/BinaryCodableContainer\";\n\nconst logger = createTaggedLogger(\"BinaryCodablePage\");\n\n/**\n * Represents a page of cookies within the binary cookies file\n */\nexport class BinaryCodablePage {\n /**\n *\n */\n public cookies: BinaryCodableCookie[];\n private static readonly HEADER = 0x00000100;\n private static readonly FOOTER = 0x00000000;\n\n /**\n * Creates a new Page instance from a buffer\n * @param buffer - The raw binary page data\n */\n public constructor(buffer: Buffer) {\n this.cookies = [];\n const container: BinaryCodableContainer = { offset: 0, buffer };\n this.decode(container);\n }\n\n /**\n * Converts the page's cookies into validated cookie rows\n * @returns Array of validated cookie objects\n */\n public toCookieRows(): BinaryCookieRow[] {\n const cookies: BinaryCookieRow[] = [];\n\n for (const cookie of this.cookies) {\n try {\n const cookieRow = cookie.toCookieRow();\n if (cookieRow !== null) {\n cookies.push(cookieRow);\n }\n } catch (error) {\n logWarn(\"BinaryCookies\", \"Error converting cookie\", {\n error: getErrorMessage(error),\n });\n }\n }\n\n return cookies;\n }\n\n private decode(container: BinaryCodableContainer): void {\n // Read page tag (4 bytes)\n const header = container.buffer.readUInt32BE(container.offset);\n logger.debug(\"Page header:\", header.toString(16));\n container.offset += 4;\n if (header !== BinaryCodablePage.HEADER) {\n throw new Error(\"Invalid page header\");\n }\n\n // Read number of cookies (4 bytes)\n const cookieCount = container.buffer.readUInt32LE(container.offset);\n logger.debug(\"Cookie count:\", cookieCount);\n container.offset += 4;\n\n // Store the page start offset for calculating absolute cookie positions\n const pageStart = container.offset - 8;\n logger.debug(\"Page start offset:\", pageStart);\n\n // Read cookie offsets (4 bytes each)\n const cookieOffsets: number[] = [];\n for (let i = 0; i < cookieCount; i++) {\n const cookieOffset = container.buffer.readUInt32LE(container.offset);\n cookieOffsets.push(cookieOffset);\n logger.debug(`Cookie ${i} offset:`, cookieOffset);\n container.offset += 4;\n }\n\n // Read page end marker (4 bytes)\n const footer = container.buffer.readUInt32BE(container.offset);\n logger.debug(\"Page footer:\", footer.toString(16));\n container.offset += 4;\n if (footer !== BinaryCodablePage.FOOTER) {\n throw new Error(\"Invalid page footer\");\n }\n\n // Read cookies at their offsets\n for (let i = 0; i < cookieCount; i++) {\n try {\n const cookieOffset = cookieOffsets[i]!;\n logger.debug(`Reading cookie ${i} at offset:`, cookieOffset);\n\n // Read cookie size from the cookie header\n const cookieSize = container.buffer.readUInt32LE(cookieOffset);\n logger.debug(`Cookie ${i} size:`, cookieSize);\n if (cookieSize < 48) {\n // Minimum cookie size is 48 bytes (header)\n logger.warn(`Invalid cookie size ${cookieSize} at index ${i}`);\n continue;\n }\n\n // Ensure we don't read past the buffer\n if (cookieOffset + cookieSize > container.buffer.length) {\n logger.warn(\n `Cookie size ${cookieSize} at index ${i} would exceed buffer length ${container.buffer.length}`,\n );\n continue;\n }\n\n const cookieBuffer = container.buffer.subarray(\n cookieOffset,\n cookieOffset + cookieSize,\n );\n const cookie = new BinaryCodableCookie(cookieBuffer);\n this.cookies.push(cookie);\n } catch (error) {\n logger.warn(\"Invalid cookie data\", {\n error: getErrorMessage(error),\n });\n }\n }\n }\n}\n","import destr from \"destr\";\nimport { z } from \"zod\";\n\n/**\n * Zod schema for cookie domain validation.\n * Enforces standard cookie domain rules.\n * @example\n * ```typescript\n * // Valid domains\n * CookieDomainSchema.parse(\"example.com\"); // OK\n * CookieDomainSchema.parse(\".example.com\"); // OK - leading dot is valid\n * CookieDomainSchema.parse(\"sub.example.com\"); // OK\n *\n * // Invalid domains\n * CookieDomainSchema.parse(\"\"); // Error: Domain cannot be empty\n * CookieDomainSchema.parse(\"invalid domain\"); // Error: Invalid domain format\n * ```\n */\nexport const CookieDomainSchema = z\n .string()\n .trim()\n .min(1, \"Domain cannot be empty\")\n .refine(\n (domain) =>\n /^\\.?[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(\n domain,\n ),\n \"Invalid domain format\",\n );\n\n/**\n * Zod schema for cookie name validation.\n * Enforces standard cookie name rules according to RFC 6265.\n * @example\n * ```typescript\n * // Valid names\n * CookieNameSchema.parse(\"session\"); // OK\n * CookieNameSchema.parse(\"auth_token\"); // OK\n * CookieNameSchema.parse(\"user-preference\"); // OK\n *\n * // Invalid names\n * CookieNameSchema.parse(\"\"); // Error: Cookie name cannot be empty\n * CookieNameSchema.parse(\"session;\"); // Error: Invalid cookie name format\n * CookieNameSchema.parse(\"my cookie\"); // Error: Invalid cookie name format\n * ```\n */\nexport const CookieNameSchema = z\n .string()\n .trim()\n .min(1, \"Cookie name cannot be empty\")\n .refine(\n (name) => name === \"%\" || /^[!#$%&'()*+\\-.:0-9A-Z ^_`a-z|~]+$/.test(name),\n \"Invalid cookie name format - must contain only valid characters (letters, numbers, and certain symbols) or be '%' for wildcard\",\n );\n\n/**\n * Zod schema for cookie path validation.\n * Enforces standard cookie path rules according to RFC 6265.\n * @example\n * ```typescript\n * // Valid paths\n * CookiePathSchema.parse(\"/\"); // OK\n * CookiePathSchema.parse(\"/api\"); // OK\n * CookiePathSchema.parse(\"/path/to/page\"); // OK\n *\n * // Invalid paths\n * CookiePathSchema.parse(\"\"); // Error: Path cannot be empty\n * CookiePathSchema.parse(\"invalid\"); // Error: Path must start with /\n * CookiePathSchema.parse(\"/path?query\"); // Error: Invalid path format\n * ```\n */\nexport const CookiePathSchema = z\n .string()\n .trim()\n .min(1, \"Path cannot be empty\")\n .refine((path) => path.startsWith(\"/\"), \"Path must start with /\")\n .refine(\n (path) => /^\\/[!#$%&'()*+,\\-./:=@\\w~]*$/.test(path),\n \"Invalid path format - must contain only valid URL path characters\",\n )\n .default(\"/\");\n\n/**\n * Zod schema for cookie value.\n * Attempts to parse JSON values using destr for better readability.\n */\nexport const CookieValueSchema = z\n .string()\n .trim()\n .transform((value) => destr(value))\n .pipe(z.any());\n\n/**\n * Zod schema for Safari binary cookie row.\n * Validates and enforces the structure of cookie data read from Safari's Cookies.binarycookies file.\n * @example\n * ```typescript\n * const cookieData = {\n * name: \"session\",\n * value: \"abc123\",\n * domain: \"example.com\",\n * path: \"/\",\n * expiry: 1735689600,\n * creation: 1672531200,\n * flags: 0x5, // Secure + HTTPOnly\n * };\n * const validCookie = BinaryCookieRowSchema.parse(cookieData);\n * ```\n */\nexport const BinaryCookieRowSchema = z.object({\n name: CookieNameSchema,\n value: CookieValueSchema,\n domain: CookieDomainSchema,\n path: CookiePathSchema,\n expiry: z.number().int(),\n creation: z.number().int(),\n flags: z.number().optional(),\n version: z.number().int().optional(),\n port: z.number().int().optional(),\n comment: z.string().optional(),\n commentURL: z.string().optional(),\n});\n\n/**\n * Type representing a decoded Safari binary cookie.\n * This type is inferred from the BinaryCookieRowSchema and includes all cookie properties.\n * @property name - The name of the cookie (non-empty string)\n * @property value - The value stored in the cookie\n * @property domain - The domain the cookie belongs to (non-empty string)\n * @property path - The path where the cookie is valid (defaults to \"/\")\n * @property expiry - Unix timestamp when the cookie expires\n * @property creation - Unix timestamp when the cookie was created\n * @property flags - Optional bit flags (e.g., Secure, HTTPOnly)\n * @property version - Optional cookie version number\n * @property port - Optional port number restriction\n * @property comment - Optional cookie comment\n * @property commentURL - Optional URL for the cookie's comment\n */\nexport type BinaryCookieRow = z.infer<typeof BinaryCookieRowSchema>;\n\n/**\n * Schema for cookie specification parameters\n * Defines the required fields for identifying a cookie\n * @example\n * ```typescript\n * // Validate a cookie specification\n * const spec = {\n * name: 'session',\n * domain: 'example.com'\n * };\n * const result = CookieSpecSchema.safeParse(spec);\n * if (result.success) {\n * logger.info('Valid cookie spec:', result.data);\n * } else {\n * logger.error('Invalid cookie spec:', result.error);\n * }\n *\n * // Invalid spec (empty name)\n * const invalidSpec = {\n * name: '',\n * domain: 'example.com'\n * };\n * // Throws: \"Cookie name cannot be empty\"\n * CookieSpecSchema.parse(invalidSpec);\n * ```\n */\nexport const CookieSpecSchema = z\n .object({\n name: CookieNameSchema,\n domain: CookieDomainSchema,\n })\n .strict();\n\n/**\n * Type definition for cookie specification\n * Used for specifying which cookie to query\n * @example\n * ```typescript\n * // Basic cookie spec\n * const spec: CookieSpec = {\n * name: 'auth',\n * domain: 'api.example.com'\n * };\n *\n * // Use in function parameters\n * function queryCookie(spec: CookieSpec): Promise<ExportedCookie[]> {\n * return getCookie(spec);\n * }\n *\n * // Array of specs\n * const specs: CookieSpec[] = [\n * { name: 'session', domain: 'app.example.com' },\n * { name: 'theme', domain: 'example.com' }\n * ];\n * ```\n */\nexport type CookieSpec = z.infer<typeof CookieSpecSchema>;\n\n/**\n * Schema for metadata about a cookie\n */\nexport const CookieMetaSchema = z\n .object({\n file: z.string().trim().min(1, \"File path cannot be empty\").optional(),\n browser: z.string().trim().optional(),\n decrypted: z.boolean().optional(),\n secure: z.boolean().optional(),\n httpOnly: z.boolean().optional(),\n path: CookiePathSchema.optional(),\n })\n .catchall(z.unknown());\n\n/**\n * Type definition for cookie metadata\n */\nexport type CookieMeta = z.infer<typeof CookieMetaSchema>;\n\n/**\n * Schema for exported cookie data\n * Represents a cookie with all its properties and metadata\n * @example\n * ```typescript\n * // Validate an exported cookie\n * const cookie = {\n * domain: 'example.com',\n * name: 'session',\n * value: 'abc123',\n * expiry: new Date('2024-12-31'),\n * meta: {\n * file: '/path/to/cookies.db'\n * }\n * };\n * const result = ExportedCookieSchema.safeParse(cookie);\n * if (result.success) {\n * logger.info('Valid cookie:', result.data);\n * } else {\n * logger.error('Invalid cookie:', result.error);\n * }\n *\n * // Cookie with infinite expiry\n * const infiniteCookie = {\n * ...cookie,\n * expiry: \"Infinity\"\n * };\n * ExportedCookieSchema.parse(infiniteCookie); // OK\n * ```\n */\nexport const ExportedCookieSchema = z\n .object({\n domain: CookieDomainSchema,\n name: CookieNameSchema,\n value: CookieValueSchema,\n expiry: z\n .union([\n z.literal(\"Infinity\"),\n z.date(),\n z.number().int().positive(\"Expiry must be a positive number\"),\n ])\n .optional(),\n meta: CookieMetaSchema.optional(),\n })\n .strict();\n\n/**\n * Type definition for exported cookie data\n * Represents the structure of a cookie after it has been retrieved\n * @example\n * ```typescript\n * // Basic exported cookie\n * const cookie: ExportedCookie = {\n * domain: 'example.com',\n * name: 'session',\n * value: 'abc123',\n * expiry: new Date('2024-12-31'),\n * meta: {\n * file: '/path/to/cookies.db'\n * }\n * };\n *\n * // Process exported cookies\n * function processCookies(cookies: ExportedCookie[]): string[] {\n * return cookies.map(cookie => `${cookie.name}=${cookie.value}`);\n * }\n *\n * // Filter expired cookies\n * function filterExpired(cookies: ExportedCookie[]): ExportedCookie[] {\n * const now = new Date();\n * return cookies.filter(cookie =>\n * cookie.expiry === \"Infinity\" ||\n * (cookie.expiry instanceof Date && cookie.expiry > now)\n * );\n * }\n * ```\n */\nexport type ExportedCookie = z.infer<typeof ExportedCookieSchema>;\n\n/**\n * Schema for raw cookie data from browser stores\n */\nexport const CookieRowSchema = z\n .object({\n expiry: z.number().int().optional(),\n domain: CookieDomainSchema,\n name: CookieNameSchema,\n value: z.union([z.string(), z.instanceof(Buffer)]),\n })\n .strict();\n\n/**\n * Type definition for raw cookie data\n */\nexport type CookieRow = z.infer<typeof CookieRowSchema>;\n\n/**\n * Schema for cookie render options\n */\nexport const RenderOptionsSchema = z\n .object({\n format: z.enum([\"merged\", \"grouped\"]).optional(),\n separator: z.string().optional(),\n showFilePaths: z.boolean().optional(),\n })\n .strict();\n\n/**\n * Type definition for render options\n */\nexport type RenderOptions = z.infer<typeof RenderOptionsSchema>;\n\n/**\n * Schema for browser names\n */\nexport const BrowserNameSchema = z.enum([\n \"Chrome\",\n \"Firefox\",\n \"Safari\",\n \"internal\",\n \"unknown\",\n]);\n\n/**\n * Type definition for browser names\n */\nexport type BrowserName = z.infer<typeof BrowserNameSchema>;\n\n/**\n * Type definition for cookie query strategy\n */\nexport type CookieQueryStrategy = {\n browserName: BrowserName;\n queryCookies: (\n domain: string,\n name: string,\n path?: string,\n secure?: boolean,\n ) => Promise<ExportedCookie[]>;\n};\n\n/**\n * Schema for cookie query strategy\n */\nexport const CookieQueryStrategySchema = z\n .object({\n browserName: BrowserNameSchema,\n queryCookies: z.function(),\n })\n .strict();\n\n/**\n * Type representing either a single cookie specification or an array of specifications.\n * Useful when you need to query multiple cookies in a single operation.\n * @example\n * ```typescript\n * // Single cookie spec\n * const single: MultiCookieSpec = {\n * domain: \"example.com\",\n * name: \"sessionId\"\n * };\n *\n * // Multiple cookie specs\n * const multiple: MultiCookieSpec = [\n * { domain: \"example.com\", name: \"sessionId\" },\n * { domain: \"api.example.com\", name: \"authToken\" }\n * ];\n * ```\n */\nexport type MultiCookieSpec = CookieSpec | CookieSpec[];\n\n/**\n * Schema for base cookie query options\n */\nexport const BaseCookieQueryOptionsSchema = z.object({\n /** Maximum number of cookies to return */\n limit: z.number().int().positive().optional(),\n /** Whether to remove expired cookies from results */\n removeExpired: z.boolean().optional(),\n /** Include expired cookies in results */\n includeExpired: z.boolean().optional(),\n /** Storage location override */\n store: z.string().optional(),\n /** Force query even if browser is running */\n force: z.boolean().optional(),\n});\n\n/**\n * Schema for strategy-based cookie query options\n */\nexport const CookieQueryOptionsSchema = BaseCookieQueryOptionsSchema.extend({\n /** Strategy to use for querying cookies */\n strategy: CookieQueryStrategySchema.optional(),\n});\n\n/**\n * Schema for SQL browser types\n */\nexport const SqlBrowserTypeSchema = z.enum([\n \"chrome\",\n \"chromium\",\n \"edge\",\n \"firefox\",\n \"opera\",\n \"brave\",\n \"arc\",\n]);\n\n/**\n * Schema for SQL-specific cookie query options\n */\nexport const SqlCookieQueryOptionsSchema = CookieSpecSchema.extend({\n /** Browser type for SQL queries */\n browser: SqlBrowserTypeSchema,\n /** Enable exact domain matching instead of wildcard */\n exactDomain: z.boolean().optional(),\n /** Enable case-sensitive matching */\n caseSensitive: z.boolean().optional(),\n /** Maximum number of results */\n limit: z.number().int().positive().optional(),\n /** Include expired cookies */\n includeExpired: z.boolean().optional(),\n});\n\n/**\n * Type for base cookie query options\n */\nexport type BaseCookieQueryOptions = z.infer<\n typeof BaseCookieQueryOptionsSchema\n>;\n\n/**\n * Type for strategy-based cookie query options\n */\nexport type CookieQueryOptions<\n T extends CookieQueryStrategy = CookieQueryStrategy,\n> = BaseCookieQueryOptions & {\n strategy?: T;\n};\n\n/**\n * Type for SQL browser types\n */\nexport type SqlBrowserType = z.infer<typeof SqlBrowserTypeSchema>;\n\n/**\n * Type for SQL-specific cookie query options\n */\nexport type SqlCookieQueryOptions = z.infer<typeof SqlCookieQueryOptionsSchema>;\n","import { Buffer } from \"node:buffer\";\n\nimport {\n type BinaryCookieRow,\n BinaryCookieRowSchema,\n} from \"../../../types/schemas\";\nimport { createTaggedLogger } from \"../../../utils/logHelpers\";\n\nimport type { BinaryCodableContainer } from \"./interfaces/BinaryCodableContainer\";\nimport type { BinaryCodableFlags } from \"./interfaces/BinaryCodableFlags\";\nimport type { BinaryCodableOffsets } from \"./interfaces/BinaryCodableOffsets\";\n\nconst logger = createTaggedLogger(\"BinaryCodableCookie\");\n\n/**\n * Represents a single cookie within a page\n * Handles decoding of Safari's binary cookie format\n */\nexport class BinaryCodableCookie {\n /**\n * Cookie version number\n */\n public version = 0;\n\n /**\n * URL the cookie is associated with\n */\n public url = \"\";\n\n /**\n * Port number if specified\n */\n public port?: number;\n\n /**\n * Cookie name\n */\n public name = \"\";\n\n /**\n * Cookie path\n */\n public path = \"\";\n\n /**\n * Cookie value\n */\n public value = \"\";\n\n /**\n * Optional comment\n */\n public comment?: string;\n\n /**\n * Optional comment URL\n */\n public commentURL?: string;\n\n /**\n * Cookie flags (secure, httpOnly, etc.)\n */\n public flags: BinaryCodableFlags = {\n isSecure: false,\n isHTTPOnly: false,\n unknown1: false,\n unknown2: false,\n };\n\n /**\n * Expiration timestamp (Mac epoch seconds)\n */\n public expiration = 0;\n\n /**\n * Creation timestamp (Mac epoch seconds)\n */\n public creation = 0;\n\n /**\n * Creates a new Cookie instance from a buffer\n * @param buffer - The raw binary cookie data\n */\n public constructor(buffer: Buffer) {\n const container: BinaryCodableContainer = { offset: 0, buffer };\n this.decode(container);\n }\n\n /**\n * Decode URL encoded values with multiple passes\n * @param value - The URL encoded string\n * @returns Decoded string\n */\n private decodeUrlValue(value: string): string {\n let processed = value;\n let lastProcessed: string;\n do {\n lastProcessed = processed;\n try {\n processed = decodeURIComponent(processed);\n } catch {\n return lastProcessed;\n }\n } while (processed !== lastProcessed && processed.includes(\"%\"));\n return processed;\n }\n\n /**\n * Decode JWT payload if the value is a valid JWT token\n * @param token - The JWT token string\n * @returns Decoded payload as JSON string or null if invalid\n */\n private decodeJwtPayload(token: string): string | null {\n const parts = token.split(\".\");\n if (parts.length !== 3) {\n return null;\n }\n\n try {\n const payloadPart = parts[1];\n if (!payloadPart) {\n return null;\n }\n const payload = Buffer.from(payloadPart, \"base64\").toString(\"utf8\");\n const parsed = JSON.parse(payload) as Record<string, unknown>;\n return JSON.stringify(parsed);\n } catch {\n return null;\n }\n }\n\n /**\n * Parse JSON value and return formatted JSON string\n * @param value - The JSON string to parse\n * @returns Formatted JSON string or null if invalid\n */\n private parseJsonValue(value: string): string | null {\n try {\n const parsed = JSON.parse(value) as Record<string, unknown>;\n return JSON.stringify(parsed);\n } catch {\n return null;\n }\n }\n\n /**\n * Process cookie value with appropriate decoding\n * @param value - The raw cookie value\n * @returns Processed and decoded value as string\n */\n private processValue(value: unknown): string {\n // Handle non-string values\n const primitiveResult = this.handlePrimitiveValues(value);\n if (primitiveResult !== null) {\n return primitiveResult;\n }\n\n // Must be a string at this point\n const stringValue = value as string;\n\n // First, try URL decoding\n const decoded = this.decodeUrlValue(stringValue);\n\n // Try specialized decoding\n return this.trySpecializedDecoding(decoded);\n }\n\n /**\n * Handle primitive value types (null, undefined, buffer, non-string)\n * @param value - The value to check\n * @returns String representation or null if not a primitive type\n */\n private handlePrimitiveValues(value: unknown): string | null {\n if (value === null) {\n return \"null\";\n }\n\n if (value === undefined) {\n return \"undefined\";\n }\n\n if (Buffer.isBuffer(value)) {\n return value.toString();\n }\n\n if (typeof value !== \"string\") {\n return this.safeStringify(value);\n }\n\n return null; // Not a primitive type\n }\n\n /**\n * Try specialized decoding (JWT, JSON) on the decoded string\n * @param decoded - The URL-decoded string\n * @returns Specialized decoded value or the original decoded string\n */\n private trySpecializedDecoding(decoded: string): string {\n // Try JWT decoding if it looks like a JWT token\n const jwtResult = this.tryJwtDecoding(decoded);\n if (jwtResult !== null) {\n return jwtResult;\n }\n\n // Try JSON parsing if it looks like JSON\n const jsonResult = this.tryJsonDecoding(decoded);\n if (jsonResult !== null) {\n return jsonResult;\n }\n\n return decoded;\n }\n\n /**\n * Try JWT decoding if the value looks like a JWT token\n * @param decoded - The decoded string to check\n * @returns Decoded JWT payload or null if not a JWT or decoding failed\n */\n private tryJwtDecoding(decoded: string): string | null {\n if (decoded.match(/^ey[A-Za-z0-9_-]+\\.ey[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/)) {\n const jwtPayload = this.decodeJwtPayload(decoded);\n if (typeof jwtPayload === \"string\" && jwtPayload.length > 0) {\n return jwtPayload;\n }\n }\n return null;\n }\n\n /**\n * Try JSON decoding if the value looks like JSON\n * @param decoded - The decoded string to check\n * @returns Decoded JSON string or null if not JSON or decoding failed\n */\n private tryJsonDecoding(decoded: string): string | null {\n if (decoded.startsWith(\"{\") || decoded.startsWith(\"[\")) {\n const jsonValue = this.parseJsonValue(decoded);\n if (typeof jsonValue === \"string\" && jsonValue.length > 0) {\n return jsonValue;\n }\n }\n return null;\n }\n\n /**\n * Safely convert unknown value to string\n * @param value - The value to stringify\n * @returns String representation of the value\n */\n private safeStringify(value: unknown): string {\n try {\n if (typeof value === \"object\" && value !== null) {\n // For objects, use JSON.stringify if possible, otherwise use toString\n return JSON.stringify(value);\n }\n return String(value);\n } catch {\n // Fallback to String() if JSON.stringify fails\n return String(value);\n }\n }\n\n /**\n * Validates and converts Mac epoch timestamp to Unix epoch\n * @param macTimestamp - Timestamp in Mac epoch (seconds since 2001-01-01)\n * @returns Unix epoch timestamp or 0 for invalid timestamps\n */\n private convertMacTimestamp(macTimestamp: number): number {\n const macToUnixOffset = 978307200; // Seconds between 1970-01-01 and 2001-01-01\n\n if (macTimestamp <= 0) {\n return macTimestamp;\n }\n\n // Validate timestamp bounds - reasonable range is 0 to ~1 billion seconds (2032)\n const isValid =\n macTimestamp >= 0 &&\n macTimestamp <= 1000000000 &&\n Number.isFinite(macTimestamp);\n\n return isValid ? macTimestamp + macToUnixOffset : 0;\n }\n\n /**\n * Converts the cookie to a validated cookie row\n * @returns Validated cookie row object or null if validation fails\n */\n public toCookieRow(): BinaryCookieRow | null {\n try {\n // Convert flags to number\n const flagsValue = this.convertFlags();\n\n // Extract domain from URL\n const domain =\n this.url.replace(/^https?:\\/\\//, \"\").replace(/\\/.*$/, \"\") || \"uk\";\n\n // Convert timestamps from Mac epoch to Unix epoch with validation\n const expiryUnix = this.convertMacTimestamp(this.expiration);\n const creationUnix = this.convertMacTimestamp(this.creation);\n\n // Create cookie row with converted timestamps\n const cookieRow = BinaryCookieRowSchema.parse({\n name: this.name.replace(/^: /, \"\"), // Remove leading ': ' if present\n value: this.processValue(this.value) || \"\", // Process and ensure value is never undefined\n domain,\n path: this.path || \"/\",\n expiry: expiryUnix,\n creation: creationUnix,\n flags: flagsValue,\n version: this.version,\n port: this.port,\n comment: this.comment,\n commentURL: this.commentURL,\n });\n\n return cookieRow;\n } catch (_error) {\n return null;\n }\n }\n\n /**\n * Read the cookie header information\n * @param container - The binary container\n * @returns Object containing size, port flag, and string offsets\n */\n private readHeader(container: BinaryCodableContainer): {\n size: number;\n hasPort: number;\n offsets: BinaryCodableOffsets;\n } {\n // Cookie size (4 bytes)\n const size = container.buffer.readUInt32LE(container.offset);\n logger.debug(\"Cookie size:\", size);\n container.offset += 4;\n\n // Version (4 bytes)\n const version = container.buffer.readUInt32LE(container.offset);\n logger.debug(\"Cookie version:\", version);\n container.offset += 4;\n\n // Cookie flags (4 bytes)\n const flagsValue = container.buffer.readUInt32LE(container.offset);\n logger.debug(\"Cookie flags:\", flagsValue.toString(2).padStart(8, \"0\"));\n container.offset += 4;\n this.flags = {\n isSecure: (flagsValue & 1) !== 0,\n isHTTPOnly: (flagsValue & 4) !== 0,\n unknown1: (flagsValue & 8) !== 0,\n unknown2: (flagsValue & 16) !== 0,\n };\n\n // Has port (4 bytes)\n const hasPort = container.buffer.readUInt32LE(container.offset);\n logger.debug(\"Has port:\", hasPort);\n container.offset += 4;\n\n // String offsets (24 bytes total)\n const offsets = {\n urlOffset: container.buffer.readUInt32LE(container.offset),\n nameOffset: container.buffer.readUInt32LE(container.offset + 4),\n pathOffset: container.buffer.readUInt32LE(container.offset + 8),\n valueOffset: container.buffer.readUInt32LE(container.offset + 12),\n commentOffset: container.buffer.readUInt32LE(container.offset + 16),\n commentURLOffset: container.buffer.readUInt32LE(container.offset + 20),\n };\n logger.debug(\"String offsets:\", offsets);\n\n return { size, hasPort, offsets };\n }\n\n /**\n * Read expiration and creation timestamps from the container\n * @param container - The binary container\n */\n private readTimestamps(container: BinaryCodableContainer): void {\n // Read expiration time (8 bytes, little-endian double)\n const expirationBuffer = Buffer.alloc(8);\n for (let i = 0; i < 8; i++) {\n expirationBuffer[i] = container.buffer[container.offset + i]!;\n }\n const expiration = expirationBuffer.readDoubleLE(0);\n container.offset += 8;\n\n // Read creation time (8 bytes, little-endian double)\n const creationBuffer = Buffer.alloc(8);\n for (let i = 0; i < 8; i++) {\n creationBuffer[i] = container.buffer[container.offset + i]!;\n }\n const creation = creationBuffer.readDoubleLE(0);\n container.offset += 8;\n\n // Store raw timestamps (seconds since 2001-01-01)\n // For expiration time, 0 means \"session cookie\" (expires when browser closes)\n // For creation time, 0 means \"no creation time recorded\"\n this.expiration = expiration;\n this.creation = creation;\n }\n\n /**\n * Read cookie string fields from the container\n * @param container - The binary container\n * @param size - Total size of the cookie\n * @param offsets - String field offsets\n */\n private readStrings(\n container: BinaryCodableContainer,\n size: number,\n offsets: BinaryCodableOffsets,\n ): void {\n // All offsets are relative to the start of the cookie\n const cookieStart = 0; // Offsets are relative to the cookie buffer start\n logger.debug(\"Reading strings from cookie buffer of size:\", size);\n\n // Read strings in order of their offsets\n const offsetEntries = [\n { field: \"url\", offset: offsets.urlOffset },\n { field: \"name\", offset: offsets.nameOffset },\n { field: \"path\", offset: offsets.pathOffset },\n { field: \"value\", offset: offsets.valueOffset },\n { field: \"comment\", offset: offsets.commentOffset },\n ]\n .filter((entry) => entry.offset > 0)\n .sort((a, b) => a.offset - b.offset);\n\n logger.debug(\n \"Reading strings in order:\",\n offsetEntries.map((e) => e.field),\n );\n\n // Calculate string lengths based on offset differences\n for (let i = 0; i < offsetEntries.length; i++) {\n const entry = offsetEntries[i]!;\n const { field, offset } = entry;\n const nextOffset =\n i < offsetEntries.length - 1 ? offsetEntries[i + 1]!.offset : size;\n const length = nextOffset - offset;\n\n // Read string up to null terminator\n let end = cookieStart + offset;\n while (\n end < cookieStart + offset + length &&\n container.buffer[end] !== 0\n ) {\n end++;\n }\n const value = container.buffer.toString(\n \"utf8\",\n cookieStart + offset,\n end,\n );\n logger.debug(`Read ${field}:`, value);\n\n switch (field) {\n case \"url\":\n this.url = value;\n break;\n case \"name\":\n this.name = value;\n break;\n case \"path\":\n this.path = value;\n break;\n case \"value\":\n this.value = value;\n break;\n case \"comment\":\n this.comment = value;\n break;\n }\n }\n }\n\n /**\n * Decode the cookie from the binary container\n * @param container - The binary container with cookie data\n */\n private decode(container: BinaryCodableContainer): void {\n const { size, hasPort, offsets } = this.readHeader(container);\n\n // Skip past all offsets (24 bytes)\n const baseOffset = container.offset;\n container.offset = baseOffset + 24;\n\n this.readTimestamps(container);\n\n if (hasPort > 0) {\n this.port = container.buffer.readUInt16LE(container.offset);\n container.offset += 2;\n }\n\n // Reset offset for string reading\n container.offset = baseOffset;\n this.readStrings(container, size, offsets);\n }\n\n /**\n * Convert cookie flags to numeric representation\n * @returns Numeric flags value\n */\n private convertFlags(): number {\n return (\n (this.flags.isSecure ? 0x1 : 0) |\n (this.flags.isHTTPOnly ? 0x4 : 0) |\n (this.flags.unknown1 ? 0x8 : 0) |\n (this.flags.unknown2 ? 0x10 : 0)\n );\n }\n}\n","import type { BinaryCookieRow } from \"../../../types/schemas\";\n\nimport { BinaryCodableCookies } from \"./BinaryCodableCookies\";\n\n/**\n * Decodes a Safari binary cookie file into an array of cookie objects.\n * @param cookieDbPath - Path to the Safari Cookies.binarycookies file\n * @returns Array of decoded cookie objects\n * @throws {Error} If the file cannot be read or has invalid format\n */\nexport function decodeBinaryCookies(cookieDbPath: string): BinaryCookieRow[] {\n const cookies = BinaryCodableCookies.fromFile(cookieDbPath);\n return cookies.toCookieRows();\n}\n\n/**\n * Retrieves cookies from Safari's binary cookie store.\n * @returns Array of decoded Safari cookies\n */\nexport function getSafariCookies(): BinaryCookieRow[] {\n const cookies = BinaryCodableCookies.fromDefaultPath();\n return cookies.toCookieRows();\n}\n","import type { CookieSpec, ExportedCookie } from \"../../types/schemas\";\nimport { getErrorMessage } from \"../../utils/errorUtils\";\nimport logger from \"../../utils/logger\";\n\nimport { queryCookies } from \"./queryCookies\";\n\n/**\n * Retrieves browser cookies that match the specified cookie name and domain criteria.\n * This function provides a way to search and filter cookies based on given specifications.\n * @param cookieSpec - The cookie specification containing search criteria\n * @param cookieSpec.name - The name of the cookie to search for\n * @param cookieSpec.domain - (optional) The domain to filter cookies by\n * @returns An array of ExportedCookie objects that match the specification\n * @throws Will catch and handle any errors during cookie querying, logging a warning\n * to the console without throwing to the caller\n * @example\n * ```typescript\n * import { getCookie } from \"@mherod/get-cookie\";\n *\n * // Get all cookies named \"sessionId\"\n * const cookies = await getCookie({ name: \"sessionId\" });\n * // Returns: [{ name: \"sessionId\", value: \"abc123\", domain: \".example.com\", ... }]\n *\n * // Get cookies named \"userPref\" from specific domain\n * const domainCookies = await getCookie({\n * name: \"userPref\",\n * domain: \"example.com\"\n * });\n * // Returns: [{ name: \"userPref\", value: \"darkMode\", domain: \"example.com\", ... }]\n * ```\n */\nexport async function getCookie(\n cookieSpec: CookieSpec,\n): Promise<ExportedCookie[]> {\n try {\n const cookies = await queryCookies(cookieSpec);\n logger.debug(\"Cookies retrieved:\", cookies);\n return cookies;\n } catch (error: unknown) {\n logger.warn(\"Error querying cookies:\", getErrorMessage(error));\n return [];\n }\n}\n\n/**\n * Default export of the getCookie function.\n * @example\n * ```typescript\n * import { getCookie } from \"@mherod/get-cookie\";\n * const authCookies = await getCookie({\n * name: \"auth-token\",\n * domain: \"api.example.com\"\n * });\n * ```\n */\nexport default getCookie;\n","import type { CookieSpec, ExportedCookie } from \"../../types/schemas\";\nimport { ChromeCookieQueryStrategy } from \"../browsers/chrome/ChromeCookieQueryStrategy\";\nimport { FirefoxCookieQueryStrategy } from \"../browsers/firefox/FirefoxCookieQueryStrategy\";\nimport { SafariCookieQueryStrategy } from \"../browsers/safari/SafariCookieQueryStrategy\";\n\n/**\n * Queries cookies from all available browser strategies (Chrome, Firefox, Safari).\n * This function acts as a unified interface to retrieve cookies across different browsers.\n * @param cookieSpec - The cookie specification to query\n * @param cookieSpec.name - The name pattern to match cookies against (can include '%' as wildcard)\n * @param cookieSpec.domain - The domain to match cookies against\n * @returns Promise resolving to array of exported cookies from all available browsers\n * @remarks\n * - Returns empty array if cookieSpec is invalid or missing required fields\n * - Aggregates results from all available browser strategies\n * - Failed browser queries are gracefully handled and excluded from results\n * - Both name and domain fields are required and must be strings\n * @example\n * ```typescript\n * const cookies = await queryCookies({\n * name: 'sessionId',\n * domain: 'example.com'\n * });\n * console.log(cookies); // Array of matching cookies from all browsers\n * ```\n */\nexport async function queryCookies(\n cookieSpec: CookieSpec,\n): Promise<ExportedCookie[]> {\n if (!cookieSpec.name || !cookieSpec.domain) {\n return [];\n }\n\n const { name, domain } = cookieSpec;\n if (typeof name !== \"string\" || typeof domain !== \"string\") {\n return [];\n }\n\n /**\n * Initialize all available browser-specific strategies\n * The order of strategies can affect performance but not functionality\n * Each strategy is responsible for its own error handling\n */\n const strategies = [\n new ChromeCookieQueryStrategy(),\n new FirefoxCookieQueryStrategy(),\n new SafariCookieQueryStrategy(),\n ];\n\n /**\n * Query all strategies in parallel and handle failures gracefully\n * Using Promise.allSettled ensures that failures in one strategy\n * don't prevent results from other strategies\n */\n const results = await Promise.allSettled(\n strategies.map(async (strategy) => strategy.queryCookies(name, domain)),\n );\n\n /**\n * Filter out failed promises and flatten successful results\n * Using PromiseFulfilledResult<ExportedCookie[]> ensures that only successful results are included\n */\n return results\n .filter(\n (result): result is PromiseFulfilledResult<ExportedCookie[]> =>\n result.status === \"fulfilled\",\n )\n .flatMap((result) => result.value);\n}\n\n/**\n * Default export of the queryCookies function.\n * This is the recommended way to import the function for most use cases.\n * @example\n * ```typescript\n * import queryCookies from './queryCookies';\n *\n * // Query cookies with specific name\n * const sessionCookies = await queryCookies({\n * name: 'sessionId',\n * domain: 'example.com'\n * });\n *\n * // Query all cookies for a domain using wildcard\n * const allCookies = await queryCookies({\n * name: '%',\n * domain: 'example.com'\n * });\n * ```\n */\nexport default queryCookies;\n","import type { CookieSpec, ExportedCookie } from \"../../types/schemas\";\nimport { ensureError, getErrorMessage } from \"../../utils/errorUtils\";\nimport logger from \"../../utils/logger\";\n\nimport { batchQueryCookies } from \"./batchQueryCookies\";\nimport { getCookie } from \"./getCookie\";\n\n/**\n * Options for batch cookie retrieval\n */\nexport interface BatchGetCookiesOptions {\n /**\n * Whether to deduplicate cookies across all specs\n * When true, keeps the cookie with the longest value for each unique name+domain combination\n * @default true\n */\n deduplicate?: boolean;\n\n /**\n * Maximum number of concurrent requests\n * @default 10\n */\n concurrency?: number;\n\n /**\n * Whether to continue on errors for individual specs\n * When true, errors for individual specs won't fail the entire batch\n * @default true\n */\n continueOnError?: boolean;\n}\n\n/**\n * Result for a single cookie spec in batch operation\n */\nexport interface BatchCookieResult {\n /**\n * The original spec that was queried\n */\n spec: CookieSpec;\n\n /**\n * The cookies retrieved for this spec\n */\n cookies: ExportedCookie[];\n\n /**\n * Error if the query failed (only when continueOnError is true)\n */\n error?: Error;\n}\n\n/**\n * Retrieves multiple cookie specifications in parallel with intelligent deduplication.\n * This function efficiently fetches cookies for multiple specifications and can optionally\n * deduplicate the results to keep only the most valid cookie for each unique name+domain pair.\n * @param specs - Array of cookie specifications to retrieve\n * @param options - Options for batch retrieval\n * @returns Array of exported cookies, optionally deduplicated\n * @example\n * ```typescript\n * import { batchGetCookies } from \"@mherod/get-cookie\";\n *\n * // Fetch multiple cookies in parallel\n * const cookies = await batchGetCookies([\n * { name: \"auth\", domain: \"api.example.com\" },\n * { name: \"session\", domain: \"example.com\" },\n * { name: \"token\", domain: \"*.example.com\" }\n * ]);\n *\n * // With options\n * const cookies = await batchGetCookies(\n * [\n * { name: \"auth\", domain: \"api.example.com\" },\n * { name: \"session\", domain: \"example.com\" }\n * ],\n * {\n * deduplicate: true, // Keep only the best cookie for each name+domain\n * concurrency: 5, // Limit concurrent requests\n * continueOnError: true // Don't fail entire batch on individual errors\n * }\n * );\n * ```\n */\nexport async function batchGetCookies(\n specs: CookieSpec[],\n options: BatchGetCookiesOptions = {},\n): Promise<ExportedCookie[]> {\n const {\n deduplicate = true,\n concurrency = 10,\n continueOnError = true,\n } = options;\n\n logger.debug(`Batch fetching ${specs.length} cookie specs`, {\n deduplicate,\n concurrency,\n continueOnError,\n });\n\n // Use optimized batch query that combines SQL queries\n let results: ExportedCookie[];\n\n try {\n results = await batchQueryCookies(specs, continueOnError);\n logger.debug(`Batch query returned ${results.length} cookies`);\n } catch (error) {\n // If continueOnError is false and batch query fails, throw the error\n if (!continueOnError) {\n throw error;\n }\n\n // Fall back to individual queries if batch query fails\n logger.warn(\"Batch query failed, falling back to individual queries\", {\n error: getErrorMessage(error),\n });\n\n results = await fallbackToIndividualQueries(\n specs,\n concurrency,\n continueOnError,\n );\n }\n\n // Deduplicate if requested\n if (deduplicate && results.length > 0) {\n const deduped = deduplicateCookies(results);\n logger.debug(`Deduplicated ${results.length} to ${deduped.length}`);\n return deduped;\n }\n\n return results;\n}\n\n/**\n * Retrieves multiple cookie specifications with detailed results for each spec.\n * Unlike `batchGetCookies`, this returns detailed results including any errors\n * that occurred for individual specs.\n * @param specs - Array of cookie specifications to retrieve\n * @param options - Options for batch retrieval\n * @returns Array of batch results with cookies and potential errors\n * @example\n * ```typescript\n * import { batchGetCookiesWithResults } from \"@mherod/get-cookie\";\n *\n * const results = await batchGetCookiesWithResults([\n * { name: \"auth\", domain: \"api.example.com\" },\n * { name: \"session\", domain: \"example.com\" }\n * ]);\n *\n * results.forEach(result => {\n * if (result.error) {\n * console.error(`Failed to get cookies for ${result.spec.name}: ${result.error.message}`);\n * } else {\n * console.log(`Got ${result.cookies.length} cookies for ${result.spec.name}`);\n * }\n * });\n * ```\n */\n/**\n * Process cookies and group them by spec\n * @param specs - Cookie specifications\n * @param allCookies - All retrieved cookies\n * @returns Array of batch results\n */\nfunction groupCookiesBySpec(\n specs: CookieSpec[],\n allCookies: ExportedCookie[],\n): BatchCookieResult[] {\n return specs.map((spec) => {\n const specCookies = allCookies.filter(\n (cookie) => cookie.name === spec.name && cookie.domain === spec.domain,\n );\n return { spec, cookies: specCookies };\n });\n}\n\n/**\n * Process a chunk of specs for detailed results\n * @param chunk - Chunk of specs to process\n * @param continueOnError - Whether to continue on errors\n * @returns Array of batch cookie results\n */\nasync function processChunkWithResults(\n chunk: CookieSpec[],\n continueOnError: boolean,\n): Promise<BatchCookieResult[]> {\n const chunkPromises = chunk.map(async (spec): Promise<BatchCookieResult> => {\n try {\n const cookies = await getCookie(spec);\n return { spec, cookies };\n } catch (error) {\n const err = ensureError(error, \"Failed to fetch cookies\");\n if (!continueOnError) {\n throw err;\n }\n logger.warn(\"Failed to fetch cookies for spec\", {\n spec,\n error: getErrorMessage(err),\n });\n return { spec, cookies: [], error: err };\n }\n });\n\n return Promise.all(chunkPromises);\n}\n\n/**\n * Retrieves multiple cookie specifications with detailed results for each spec\n * @param specs - Array of cookie specifications to retrieve\n * @param options - Options for batch retrieval\n * @returns Array of batch results with cookies and potential errors\n */\nexport async function batchGetCookiesWithResults(\n specs: CookieSpec[],\n options: Omit<BatchGetCookiesOptions, \"deduplicate\"> = {},\n): Promise<BatchCookieResult[]> {\n const { concurrency = 10, continueOnError = true } = options;\n\n logger.debug(`Batch fetching ${specs.length} cookie specs with results`, {\n concurrency,\n continueOnError,\n });\n\n // Try using optimized batch query first\n try {\n const allCookies = await batchQueryCookies(specs, continueOnError);\n return groupCookiesBySpec(specs, allCookies);\n } catch (error) {\n logger.warn(\"Batch query failed, falling back to individual queries\", {\n error: getErrorMessage(error),\n });\n\n // Fall back to individual queries\n const results: BatchCookieResult[] = [];\n\n for (let i = 0; i < specs.length; i += concurrency) {\n const chunk = specs.slice(i, i + concurrency);\n const chunkResults = await processChunkWithResults(\n chunk,\n continueOnError,\n );\n results.push(...chunkResults);\n }\n\n return results;\n }\n}\n\n/**\n * Process a single chunk of cookie specs\n * @param chunk - Array of cookie specs to process\n * @param continueOnError - Whether to continue on errors\n * @returns Object containing results and errors\n */\nasync function processChunk(\n chunk: CookieSpec[],\n continueOnError: boolean,\n): Promise<{\n cookies: ExportedCookie[];\n errors: Array<{ spec: CookieSpec; error: Error }>;\n}> {\n const cookies: ExportedCookie[] = [];\n const errors: Array<{ spec: CookieSpec; error: Error }> = [];\n\n const chunkPromises = chunk.map(async (spec) => {\n try {\n const specCookies = await getCookie(spec);\n return { spec, cookies: specCookies, error: undefined };\n } catch (error) {\n const err = ensureError(error, \"Failed to fetch cookies\");\n if (!continueOnError) {\n throw err;\n }\n logger.warn(\"Failed to fetch cookies for spec\", {\n spec,\n error: getErrorMessage(err),\n });\n return { spec, cookies: [], error: err };\n }\n });\n\n const chunkResults = await Promise.all(chunkPromises);\n\n for (const result of chunkResults) {\n if (result.error) {\n errors.push({ spec: result.spec, error: result.error });\n } else {\n cookies.push(...result.cookies);\n }\n }\n\n return { cookies, errors };\n}\n\n/**\n * Fallback to individual queries when batch query fails\n * @param specs - Array of cookie specifications\n * @param concurrency - Maximum concurrent requests\n * @param continueOnError - Whether to continue on errors\n * @returns Array of exported cookies\n */\nasync function fallbackToIndividualQueries(\n specs: CookieSpec[],\n concurrency: number,\n continueOnError: boolean,\n): Promise<ExportedCookie[]> {\n const results: ExportedCookie[] = [];\n const allErrors: Array<{ spec: CookieSpec; error: Error }> = [];\n\n for (let i = 0; i < specs.length; i += concurrency) {\n const chunk = specs.slice(i, i + concurrency);\n const { cookies, errors } = await processChunk(chunk, continueOnError);\n results.push(...cookies);\n allErrors.push(...errors);\n }\n\n // Log any errors that occurred\n if (allErrors.length > 0) {\n logger.warn(`${allErrors.length} specs failed during batch retrieval`, {\n failedSpecs: allErrors.map((e) => e.spec),\n });\n }\n\n return results;\n}\n\n/**\n * Deduplicates an array of cookies, keeping the most valid value for each unique name+domain pair.\n * Prioritizes cookies with longer values as they are more likely to be valid/complete.\n * @param cookies - Array of cookies to deduplicate\n * @returns Deduplicated array of cookies\n */\nfunction deduplicateCookies(cookies: ExportedCookie[]): ExportedCookie[] {\n const cookieMap = new Map<string, ExportedCookie>();\n\n for (const cookie of cookies) {\n const key = `${cookie.name}:${cookie.domain}`;\n const existing = cookieMap.get(key);\n\n // Keep the cookie with the longest value (most likely to be valid)\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n const existingLength: number = existing?.value.length ?? 0;\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access\n const currentLength: number = cookie.value.length;\n if (!existing || currentLength > existingLength) {\n cookieMap.set(key, cookie);\n }\n }\n\n return Array.from(cookieMap.values());\n}\n\n/**\n * Default export of the batchGetCookies function\n */\nexport default batchGetCookies;\n","import type { CookieSpec, ExportedCookie } from \"../../types/schemas\";\nimport { ensureError, getErrorMessage } from \"../../utils/errorUtils\";\nimport logger from \"../../utils/logger\";\nimport type { BaseCookieQueryStrategy } from \"../browsers/BaseCookieQueryStrategy\";\nimport { ChromeCookieQueryStrategy } from \"../browsers/chrome/ChromeCookieQueryStrategy\";\nimport { FirefoxCookieQueryStrategy } from \"../browsers/firefox/FirefoxCookieQueryStrategy\";\nimport { SafariCookieQueryStrategy } from \"../browsers/safari/SafariCookieQueryStrategy\";\n/**\n * Batch query cookies from browser strategies with optimized SQL queries.\n * This function groups cookie specs and executes combined queries where possible.\n * @param specs - Array of cookie specifications to query\n * @param continueOnError - Whether to continue on errors for individual specs\n * @returns Promise resolving to array of exported cookies\n * @example\n * ```typescript\n * const cookies = await batchQueryCookies([\n * { name: \"auth\", domain: \"example.com\" },\n * { name: \"session\", domain: \"example.com\" },\n * { name: \"token\", domain: \"api.example.com\" }\n * ]);\n * ```\n */\n/**\n * Validate cookie specs\n * @param specs - Array of cookie specifications\n * @returns Array of valid cookie specs\n */\nfunction validateSpecs(specs: CookieSpec[]): CookieSpec[] {\n return specs.filter(\n (spec) =>\n Boolean(spec.name) &&\n Boolean(spec.domain) &&\n typeof spec.name === \"string\" &&\n typeof spec.domain === \"string\",\n );\n}\n\n/**\n * Type guard to check if strategy supports batch queries\n * @param strategy - Cookie query strategy\n * @returns True if strategy supports batch queries\n */\nfunction supportsBatchQueries(\n strategy: BaseCookieQueryStrategy,\n): strategy is BaseCookieQueryStrategy & {\n batchQueryCookies: (specs: CookieSpec[]) => Promise<ExportedCookie[]>;\n} {\n return (\n \"batchQueryCookies\" in strategy &&\n typeof strategy.batchQueryCookies === \"function\"\n );\n}\n\n/**\n * Process individual query results\n * @param results - Promise settlement results\n * @param continueOnError - Whether to continue on errors\n * @returns Object with cookies and errors\n * @throws Error if continueOnError is false and a query fails\n */\nfunction processIndividualResults(\n results: PromiseSettledResult<ExportedCookie[]>[],\n continueOnError: boolean,\n): { cookies: ExportedCookie[]; errors: Error[] } {\n const cookies: ExportedCookie[] = [];\n const errors: Error[] = [];\n\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n cookies.push(...result.value);\n } else if (!continueOnError) {\n throw result.reason;\n } else {\n errors.push(ensureError(result.reason, \"Query failed\"));\n }\n }\n\n return { cookies, errors };\n}\n\n/**\n * Query a single strategy for cookies\n * @param strategy - Cookie query strategy\n * @param validSpecs - Valid cookie specifications\n * @param continueOnError - Whether to continue on errors\n * @returns Object with cookies and errors\n */\nasync function queryStrategy(\n strategy: BaseCookieQueryStrategy,\n validSpecs: CookieSpec[],\n continueOnError: boolean,\n): Promise<{ cookies: ExportedCookie[]; errors: Error[] }> {\n const cookies: ExportedCookie[] = [];\n const errors: Error[] = [];\n\n try {\n if (supportsBatchQueries(strategy)) {\n // Use optimized batch query if available\n const results = await strategy.batchQueryCookies(validSpecs);\n cookies.push(...results);\n } else {\n // Fall back to parallel individual queries\n const results = await Promise.allSettled(\n validSpecs.map(async (spec) =>\n strategy.queryCookies(spec.name, spec.domain),\n ),\n );\n\n const processed = processIndividualResults(results, continueOnError);\n cookies.push(...processed.cookies);\n errors.push(...processed.errors);\n }\n } catch (error) {\n const err = ensureError(\n error,\n `Failed to query ${strategy.constructor.name}`,\n );\n if (!continueOnError) {\n throw err;\n }\n errors.push(err);\n logger.warn(`Strategy ${strategy.constructor.name} failed`, {\n error: getErrorMessage(err),\n });\n }\n\n return { cookies, errors };\n}\n\n/**\n * Batch query cookies from browser strategies with optimized SQL queries\n * @param specs - Array of cookie specifications to query\n * @param continueOnError - Whether to continue on errors for individual specs\n * @returns Promise resolving to array of exported cookies\n */\nexport async function batchQueryCookies(\n specs: CookieSpec[],\n continueOnError = true,\n): Promise<ExportedCookie[]> {\n // Filter out invalid specs\n const validSpecs = validateSpecs(specs);\n\n if (validSpecs.length === 0) {\n return [];\n }\n\n logger.debug(`Batch querying ${validSpecs.length} cookie specs`);\n\n // Initialize strategies\n const strategies = [\n new ChromeCookieQueryStrategy(),\n new FirefoxCookieQueryStrategy(),\n new SafariCookieQueryStrategy(),\n ];\n\n const allResults: ExportedCookie[] = [];\n const allErrors: Error[] = [];\n\n // Query each strategy with all specs\n for (const strategy of strategies) {\n const { cookies, errors } = await queryStrategy(\n strategy,\n validSpecs,\n continueOnError,\n );\n allResults.push(...cookies);\n allErrors.push(...errors);\n }\n\n if (allErrors.length > 0) {\n logger.debug(`${allErrors.length} errors occurred during batch query`);\n }\n\n return allResults;\n}\n"]}