@open-wa/wa-automate 5.3.0 → 5.4.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"cli-runtime-BGz4DzHq.d.cts","names":["ClientFacade"],"sources":["../src/server/hono-server.ts","../src/cli-runtime.ts"],"mappings":";;;;;cAGa,iBAAiB;EAC5B,YAAY,QAAQ;;;;UCcL;EACb,QAAQ;EACR,QAAQA;EACR,QAAQ;EACR,QAAQA;EACR;;UA8La;EACb;EACA;EACA;EACA;EACA,cAAc;EACd;EACA;;iBA+GY,aAAa,kBAAyC;iBAgPhD,MAAM,aAAY,gBAAiC,QAAQ;iBA+M3D,KAAK,kBAAyC,QAAQ"}
1
+ {"version":3,"file":"cli-runtime-BGz4DzHq.d.cts","names":["ClientFacade"],"sources":["../src/server/hono-server.ts","../src/cli-runtime.ts"],"mappings":";;;;;cAGa,iBAAiB;EAC5B,YAAY,QAAQ;;;;UCcL;EACb,QAAQ;EACR,QAAQA;EACR,QAAQ;EACR,QAAQA;EACR;;UA8La;EACb;EACA;EACA;EACA;EACA,cAAc;EACd;EACA;;iBA+GY,aAAa,kBAAyC;iBA+OhD,MAAM,aAAY,gBAAiC,QAAQ;iBAgN3D,KAAK,kBAAyC,QAAQ"}
@@ -21,9 +21,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  }) : target, mod));
22
22
  //#endregion
23
23
  let _open_wa_api = require("@open-wa/api");
24
- let node_path = require("node:path");
25
24
  let qrcode_terminal = require("qrcode-terminal");
26
25
  qrcode_terminal = __toESM(qrcode_terminal, 1);
26
+ let node_path = require("node:path");
27
27
  let _open_wa_core = require("@open-wa/core");
28
28
  let _open_wa_client = require("@open-wa/client");
29
29
  let _open_wa_driver_lightpanda = require("@open-wa/driver-lightpanda");
@@ -364,7 +364,6 @@ function parseCliArgs(argv = process.argv.slice(2)) {
364
364
  if (argv.includes("--aggressive-garbage-collection")) cliOverrides.aggressiveGarbageCollection = true;
365
365
  if (argv.includes("--no-dashboard")) cliOverrides.dashboard = false;
366
366
  if (argv.includes("--ephemeral")) cliOverrides.ephemeral = true;
367
- if (argv.includes("--legacy-data-dir-auth")) cliOverrides.legacyDataDirAuth = true;
368
367
  if (argv.includes("--sandbox-chats")) cliOverrides.sandboxChats = true;
369
368
  const sandboxIsolation = getVal(argv, "--sandbox-isolation");
370
369
  if (sandboxIsolation) {
@@ -596,11 +595,12 @@ async function start(parsedArgs = parseCliArgs()) {
596
595
  driver,
597
596
  deleteSessionDataOnLogout: config.deleteSessionDataOnLogout,
598
597
  killClientOnLogout: config.killClientOnLogout,
599
- legacyDataDirAuth: config.legacyDataDirAuth,
600
598
  sessionDataPath: config.sessionDataPath,
601
599
  sessionData: config.sessionData,
602
600
  skipSessionSave: config.skipSessionSave,
603
601
  sessionDataBucketAuth: config.sessionDataBucketAuth,
602
+ sessionDataEncryptionKey: config.sessionDataEncryptionKey,
603
+ sessionDataEncryptionKeyFile: config.sessionDataEncryptionKeyFile,
604
604
  s3Sync: config.s3Sync,
605
605
  debug: config.logLevel === "debug" || verbose || config.logConsole,
606
606
  headless: config.headless,
@@ -745,7 +745,7 @@ async function start(parsedArgs = parseCliArgs()) {
745
745
  }
746
746
  async function main(argv = process.argv.slice(2)) {
747
747
  if (argv[0] === "init") {
748
- const { initProject } = await Promise.resolve().then(() => require("./init-CTh6gc8w.cjs"));
748
+ const { initProject } = await Promise.resolve().then(() => require("./init-k_0bazOu.cjs"));
749
749
  await initProject(argv.slice(1));
750
750
  return;
751
751
  }
@@ -858,4 +858,4 @@ Object.defineProperty(exports, "start", {
858
858
  }
859
859
  });
860
860
 
861
- //# sourceMappingURL=cli-runtime-BHx1nVhT.cjs.map
861
+ //# sourceMappingURL=cli-runtime-BKwXzp9V.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-runtime-BKwXzp9V.cjs","names":["ApiServer","eventRegistry","resolve","existsSync","readFileSync","dirname","defaultChatSandboxPolicy","LightpandaDriver","PuppeteerDriver","resolveConfig","makeNodeExecutionSandbox","createClient","observeBrowserProcessMemory","ClientFacade","fileURLToPath"],"sources":["../src/server/hono-server.ts","../src/cli/output-sink.ts","../src/cli-runtime.ts"],"sourcesContent":["import { ApiServer, createApiServer as createSharedApiServer } from '@open-wa/api';\nimport type { Config } from '@open-wa/config';\n\nexport class WAServer extends ApiServer {\n constructor(config: Config) {\n super({ config });\n }\n}\n\nexport function createApiServer(config: Config) {\n return createSharedApiServer(config);\n}\n","import qrcode from 'qrcode-terminal';\n\nexport type CliOutputLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface CliOutputEntry {\n level: CliOutputLevel;\n message: string;\n meta?: Record<string, unknown>;\n}\n\nexport interface CliStatusUpdate {\n phase:\n | 'boot'\n | 'config.resolved'\n | 'server.starting'\n | 'server.started'\n | 'client.starting'\n | 'launch.auth'\n | 'launch.helpers'\n | 'launch.patch'\n | 'launch.license'\n | 'launch.finalize'\n | 'auth.qr'\n | 'client.ready'\n | 'shutdown.starting'\n | 'shutdown.complete'\n | 'error';\n detail?: string;\n sessionId?: string;\n}\n\nexport interface CliQrPayload {\n qr: string;\n sessionId: string;\n}\n\nexport interface CliOutputSink {\n write(entry: CliOutputEntry): void;\n status(update: CliStatusUpdate): void;\n qr(payload: CliQrPayload): void;\n}\n\nfunction writeToConsole(level: CliOutputLevel, message: string): void {\n if (level === 'warn') {\n console.warn(message);\n return;\n }\n\n if (level === 'error') {\n console.error(message);\n return;\n }\n\n console.log(message);\n}\n\nexport function createConsoleOutputSink(): CliOutputSink {\n return {\n write(entry) {\n writeToConsole(entry.level, entry.message);\n },\n status() {\n // Status updates are semantic signals for richer presenters.\n },\n qr(payload) {\n qrcode.generate(payload.qr, { small: true }, (terminalQrCode) => {\n console.log(`WhatsApp login: ${payload.sessionId}\\n${terminalQrCode}`);\n });\n },\n };\n}\n\nlet activeSink: CliOutputSink = createConsoleOutputSink();\n\nexport function getCliOutputSink(): CliOutputSink {\n return activeSink;\n}\n\nexport function setCliOutputSink(sink: CliOutputSink): void {\n activeSink = sink;\n}\n\nexport function resetCliOutputSink(): void {\n activeSink = createConsoleOutputSink();\n}\n","import { createClient } from '@open-wa/core';\nimport { Client as ClientFacade } from '@open-wa/client';\nimport { LightpandaDriver } from '@open-wa/driver-lightpanda';\nimport { PuppeteerDriver } from '@open-wa/driver-puppeteer';\nimport { eventRegistry } from '@open-wa/schema';\nimport { WAServer } from './server/hono-server';\nimport { resolveConfig, type PartialConfig, type Config, type TrackedConfig } from '@open-wa/config';\nimport { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { getCliOutputSink, type CliOutputSink } from './cli/output-sink';\nimport {\n defaultChatSandboxPolicy,\n type ChatSandboxPolicy,\n type SandboxIsolation,\n} from '@open-wa/runtime-core';\nimport { makeNodeExecutionSandbox, observeBrowserProcessMemory } from '@open-wa/runtime-node';\n\nexport interface CliRuntimeResult {\n server: WAServer;\n client: ClientFacade;\n config: Config;\n events: ClientFacade['events'];\n dispose(): void;\n}\n\ninterface RuntimeEventPublisher {\n publish(eventName: string, payload: any): void;\n}\n\nfunction bridgeRuntimeEvents(\n openwaClient: Awaited<ReturnType<typeof createClient>>,\n publishRuntimeEvent: (eventName: string, payload: any) => void,\n): () => void {\n if (typeof openwaClient.events.onAny === 'function' && typeof openwaClient.events.offAny === 'function') {\n openwaClient.events.onAny(publishRuntimeEvent);\n return () => openwaClient.events.offAny(publishRuntimeEvent);\n }\n\n const unsubscribers: Array<() => void> = [];\n const bridgedEvents = new Set(eventRegistry.getAll().map((def) => def.meta.eventName));\n\n bridgedEvents.forEach((eventName) => {\n const handler = (payload: any) => publishRuntimeEvent(eventName, payload);\n openwaClient.events.on(eventName as never, handler);\n unsubscribers.push(() => openwaClient.events.off(eventName as never, handler));\n });\n\n return () => {\n unsubscribers.forEach((unsubscribe) => unsubscribe());\n };\n}\n\nfunction attachLaunchNarration(\n openwaClient: Awaited<ReturnType<typeof createClient>>,\n sink: CliOutputSink,\n sessionId: string,\n): () => void {\n const unsubscribers: Array<() => void> = [];\n const on = (event: string, handler: (...args: any[]) => void) => {\n openwaClient.events.on(event as never, handler);\n unsubscribers.push(() => openwaClient.events.off(event as never, handler));\n };\n\n on('launch.auth.check.before', (event: any) => {\n sink.status({ phase: 'launch.auth', sessionId, detail: `Authenticating (timeout=${event?.details?.timeoutMs ?? '∞'}ms)` });\n });\n\n on('launch.auth.check.after', (event: any) => {\n sink.write({ level: 'info', message: `Auth detected via ${event?.details?.method ?? 'unknown'} (${event?.details?.isAuthenticated ? 'authenticated' : 'not-authenticated'})` });\n });\n\n on('launch.helper.pre_api.before', (event: any) => {\n sink.status({ phase: 'launch.helpers', sessionId, detail: event?.details?.mode === 'scripts' ? 'Injecting pre-API helper assets...' : 'Pre-API helpers already present' });\n });\n\n on('launch.helper.pre_api.after', (event: any) => {\n sink.write({ level: 'info', message: `Pre-API helper phase complete (${event?.details?.mode ?? 'unknown'})` });\n });\n\n on('internal_launch_progress', (event: any) => {\n const prefix = (event?.value || event?.value === 0) ? `${event.value}% ` : '';\n if (event?.text) sink.write({ level: 'info', message: `${prefix}${event.text}`.trim() });\n });\n\n on('critical_internal_message', (event: any) => {\n sink.write({ level: 'warn', message: `Internal launch message: ${event?.text ?? event?.value ?? 'unknown'}` });\n });\n\n on('launch.patch.init.before', (event: any) => {\n if (event?.details?.phase === 'preload') {\n sink.status({ phase: 'launch.patch', sessionId, detail: 'Downloading patches from CDN...' });\n }\n });\n\n on('launch.patch.init.after', (event: any) => {\n if (event?.details?.phase === 'preload') {\n const source = event?.details?.source ?? 'unknown';\n const tag = event?.details?.tag ? ` tag=${event.details.tag}` : '';\n const available = Array.isArray(event?.details?.available) ? event.details.available.length : 0;\n const durationMs = event?.durationMs;\n const durationStr = durationMs ? ` in ${(durationMs / 1000).toFixed(2)}s` : '';\n sink.write({ level: 'info', message: `Downloaded patches${durationStr} (source=${source}, available=${available}${tag})` });\n }\n });\n\n on('patch.init.before', (event: any) => {\n if (event?.details?.phase === 'apply') {\n const count = Array.isArray(event?.details?.patchIds) ? event.details.patchIds.length : 0;\n sink.status({ phase: 'launch.patch', sessionId, detail: `Installing patches (${count} queued)` });\n }\n });\n\n on('patch.apply.before', (event: any) => {\n sink.status({ phase: 'launch.patch', sessionId, detail: `Applying patch: ${event?.details?.patchId ?? 'unknown'}` });\n });\n\n on('patch.apply.after', (event: any) => {\n sink.write({\n level: event?.details?.outcome === 'failed' ? 'warn' : 'info',\n message: `Patch ${event?.details?.patchId ?? 'unknown'}: ${event?.details?.outcome ?? (event?.details?.applied ? 'applied' : 'unknown')}${event?.details?.detail ? ` — ${event.details.detail}` : ''}`,\n });\n });\n\n on('patch.init.after', (event: any) => {\n if (event?.details?.phase === 'apply') {\n const applied = Array.isArray(event?.details?.applied) ? event.details.applied : [];\n const outcome = event?.details?.outcome ?? 'unknown';\n const tag = applied.length > 0 ? applied.join(', ') : outcome;\n const durationMs = event?.durationMs;\n const durationStr = durationMs ? ` in ${(durationMs / 1000).toFixed(2)}s` : '';\n sink.write({\n level: event?.details?.blockingFailure ? 'warn' : 'info',\n message: `Patches Installed${durationStr}: ${tag}`,\n });\n }\n });\n\n on('launch.patch.integrity.before', () => {\n sink.status({ phase: 'launch.patch', sessionId, detail: 'Validating patched runtime...' });\n });\n\n on('launch.patch.integrity.after', (event: any) => {\n sink.write({ level: event?.details?.usable ? 'info' : 'warn', message: `Patched runtime validation: ${event?.details?.usable ? 'usable' : 'failed'}${event?.details?.failureReason ? ` (${event.details.failureReason})` : ''}` });\n });\n\n on('launch.license.check.before', (event: any) => {\n sink.status({ phase: 'launch.license', sessionId, detail: `Checking license (${event?.details?.source ?? 'local'})` });\n });\n\n on('launch.license.check.after', (event: any) => {\n sink.write({ level: event?.details?.blockingFailure ? 'warn' : 'info', message: `License check: ${event?.details?.status ?? 'unknown'}${event?.details?.detail ? ` — ${event.details.detail}` : ''}` });\n });\n\n on('license.inject.before', () => {\n sink.status({ phase: 'launch.license', sessionId, detail: 'Injecting license payload...' });\n });\n\n on('license.inject.after', (event: any) => {\n sink.write({ level: event?.details?.success ? 'info' : 'warn', message: `License inject: ${event?.details?.success ? 'success' : 'failed'}${event?.details?.status ? ` (${event.details.status})` : ''}${event?.details?.detail ? ` — ${event.details.detail}` : ''}` });\n });\n\n on('launch.auth.qr.generated', (event: any) => {\n const qrIndex = event?.details?.qrIndex ?? '?';\n sink.status({ phase: 'launch.auth', sessionId, detail: `QR code generated (#${qrIndex})` });\n });\n\n on('launch.client.finalize.before', (event: any) => {\n sink.status({ phase: 'launch.finalize', sessionId, detail: `Finalizing session (${event?.details?.validationStage ?? 'unknown'})` });\n });\n\n on('launch.client.finalize.after', (event: any) => {\n sink.write({ level: event?.details?.success ? 'info' : 'warn', message: `Finalize: ${event?.details?.outcome ?? 'unknown'}${event?.details?.detail ? ` — ${event.details.detail}` : ''}` });\n });\n\n on('error', (event: any) => {\n const scope = event?.scope ?? 'unknown';\n const msg = event?.error?.message ?? String(event?.error ?? 'unknown error');\n const fatal = event?.fatal ? ' [FATAL]' : '';\n sink.write({ level: 'error', message: `${fatal} ${scope}: ${msg}`.trim() });\n });\n\n return () => {\n unsubscribers.forEach((unsubscribe) => unsubscribe());\n };\n}\n\nconst CHROME_CACHE_FILE = resolve(process.cwd(), '.open-wa', 'chrome-executable-path.json');\n\ninterface ChromePathCacheRecord {\n executablePath?: string;\n updatedAt?: string;\n}\n\ninterface ExecutablePathResolution {\n executablePath?: string;\n source:\n | 'config'\n | 'cache'\n | 'chrome_installation'\n | 'driver_default'\n | 'lightpanda_config'\n | 'lightpanda_sdk_default';\n warning?: string;\n}\n\ninterface DriverSelection {\n driver: PuppeteerDriver | LightpandaDriver;\n engineLabel: 'Puppeteer' | 'Lightpanda';\n executableResolution: ExecutablePathResolution;\n preferLocalChrome: boolean;\n}\n\nexport interface ParsedCliArgs {\n procName: string;\n pm2: boolean;\n forwardedArgs: string[];\n configPath?: string;\n cliOverrides: PartialConfig;\n verbose: boolean;\n unsupportedWarnings: string[];\n}\n\nexport function getChromeCacheFilePath(): string {\n return CHROME_CACHE_FILE;\n}\n\nexport function readChromePathCache(cacheFilePath: string = getChromeCacheFilePath()): ChromePathCacheRecord | undefined {\n if (!existsSync(cacheFilePath)) {\n return undefined;\n }\n\n try {\n const raw = JSON.parse(readFileSync(cacheFilePath, 'utf8')) as ChromePathCacheRecord;\n if (!raw || typeof raw !== 'object') {\n return undefined;\n }\n\n return {\n executablePath: typeof raw.executablePath === 'string' ? raw.executablePath : undefined,\n updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt : undefined,\n };\n } catch {\n return undefined;\n }\n}\n\nexport function writeChromePathCache(executablePath: string, cacheFilePath: string = getChromeCacheFilePath()): void {\n mkdirSync(dirname(cacheFilePath), { recursive: true });\n writeFileSync(cacheFilePath, JSON.stringify({ executablePath, updatedAt: new Date().toISOString() }, null, 2), 'utf8');\n}\n\nexport function clearChromePathCache(cacheFilePath: string = getChromeCacheFilePath()): void {\n if (existsSync(cacheFilePath)) {\n rmSync(cacheFilePath, { force: true });\n }\n}\n\nexport function isUsableExecutablePath(executablePath?: string): executablePath is string {\n return !!executablePath && existsSync(executablePath);\n}\n\nfunction getExplicitUseChromePreference(rawConfigs?: TrackedConfig['rawConfigs']): boolean | undefined {\n const explicitConfigSources = [\n rawConfigs?.file,\n rawConfigs?.env,\n rawConfigs?.cli,\n rawConfigs?.programmatic,\n ];\n\n for (let index = explicitConfigSources.length - 1; index >= 0; index -= 1) {\n const source = explicitConfigSources[index];\n if (source?.useChrome !== undefined) {\n return source.useChrome;\n }\n }\n\n return undefined;\n}\n\nexport function shouldPreferLocalChrome(config: Config, rawConfigs?: TrackedConfig['rawConfigs']): boolean {\n if (config.useLightpanda) {\n return false;\n }\n\n if (config.executablePath) {\n return false;\n }\n\n const explicitUseChrome = getExplicitUseChromePreference(rawConfigs);\n if (explicitUseChrome !== undefined) {\n return explicitUseChrome;\n }\n\n return true;\n}\n\nfunction getVal(argv: string[], flag: string): string | undefined {\n const index = argv.findIndex(arg => arg === flag);\n return index !== -1 ? argv[index + 1] : undefined;\n}\n\nfunction parseSandboxIsolation(value: string): SandboxIsolation {\n switch (value) {\n case 'worker':\n case 'process':\n case 'container':\n return value;\n default:\n throw new Error(`Invalid --sandbox-isolation value: ${value}`);\n }\n}\n\nexport function resolveChatSandboxPolicy(config: Config['sandboxChats']): ChatSandboxPolicy | undefined {\n if (!config) return undefined;\n\n const overrides = typeof config === 'object'\n ? config as Partial<Omit<ChatSandboxPolicy, 'chats'>>\n : {};\n return {\n ...defaultChatSandboxPolicy,\n ...overrides,\n chats: true,\n networkAllowlist: [...(overrides.networkAllowlist ?? defaultChatSandboxPolicy.networkAllowlist)],\n env: overrides.env === 'none' || overrides.env === undefined\n ? overrides.env ?? defaultChatSandboxPolicy.env\n : [...overrides.env],\n capabilities: [...(overrides.capabilities ?? defaultChatSandboxPolicy.capabilities)],\n };\n}\n\nexport function parseCliArgs(argv: string[] = process.argv.slice(2)): ParsedCliArgs {\n const cliOverrides: PartialConfig = {};\n const unsupportedWarnings: string[] = [];\n let verbose = false;\n let configPath: string | undefined;\n\n const sessionId = getVal(argv, '--session-id');\n if (sessionId) cliOverrides.sessionId = sessionId;\n\n const portValue = getVal(argv, '--port') || getVal(argv, '-p');\n if (portValue) cliOverrides.port = parseInt(portValue, 10);\n\n const host = getVal(argv, '--host') || getVal(argv, '-h');\n if (host) cliOverrides.host = host;\n\n const apiKey = getVal(argv, '--api-key') || getVal(argv, '--key') || getVal(argv, '-k');\n if (apiKey) cliOverrides.apiKey = apiKey;\n\n const logLevel = getVal(argv, '--log-level');\n if (logLevel) cliOverrides.logLevel = logLevel;\n\n if (argv.includes('--no-ezqr')) cliOverrides.ezqr = false;\n if (argv.includes('--headful')) cliOverrides.headless = false;\n if (argv.includes('--headless')) cliOverrides.headless = true;\n if (argv.includes('--use-chrome')) cliOverrides.useChrome = true;\n if (argv.includes('--use-lightpanda')) cliOverrides.useLightpanda = true;\n if (argv.includes('--log-console')) cliOverrides.logConsole = true;\n if (argv.includes('--aggressive-garbage-collection')) cliOverrides.aggressiveGarbageCollection = true;\n if (argv.includes('--no-dashboard')) cliOverrides.dashboard = false;\n if (argv.includes('--ephemeral')) cliOverrides.ephemeral = true;\n if (argv.includes('--sandbox-chats')) cliOverrides.sandboxChats = true;\n\n const sandboxIsolation = getVal(argv, '--sandbox-isolation');\n if (sandboxIsolation) {\n const { chats: _chats, ...sandboxDefaults } = defaultChatSandboxPolicy;\n cliOverrides.sandboxChats = {\n ...sandboxDefaults,\n isolation: parseSandboxIsolation(sandboxIsolation),\n networkAllowlist: [...defaultChatSandboxPolicy.networkAllowlist],\n env: defaultChatSandboxPolicy.env === 'none'\n ? 'none'\n : [...defaultChatSandboxPolicy.env],\n capabilities: [...defaultChatSandboxPolicy.capabilities],\n };\n }\n\n const qrTimeout = getVal(argv, '--qr-timeout');\n if (qrTimeout) cliOverrides.qrTimeout = parseInt(qrTimeout, 10);\n\n const dashboardPort = getVal(argv, '--dashboard-port');\n if (dashboardPort) cliOverrides.dashboardPort = parseInt(dashboardPort, 10);\n\n const licenseKey = getVal(argv, '--license-key') || getVal(argv, '-l');\n if (licenseKey) cliOverrides.licenseKey = licenseKey;\n\n const webhook = getVal(argv, '--webhook') || getVal(argv, '-w');\n if (webhook) cliOverrides.webhook = webhook;\n\n const proxyHost = getVal(argv, '--proxy-host');\n if (proxyHost) cliOverrides.proxyHost = proxyHost;\n\n const proxyToken = getVal(argv, '--proxy-token');\n if (proxyToken) cliOverrides.proxyToken = proxyToken;\n\n const readyWebhook = getVal(argv, '--ready-webhook');\n if (readyWebhook) unsupportedWarnings.push(`--ready-webhook was provided (${readyWebhook}) but ready-webhook delivery is not yet wired in v5 CLI.`);\n\n if (argv.includes('-v') || argv.includes('--verbose')) {\n verbose = true;\n cliOverrides.disableSpins = true;\n cliOverrides.logConsole = true;\n cliOverrides.logLevel = cliOverrides.logLevel || 'debug';\n }\n\n if (argv.includes('--stats')) {\n unsupportedWarnings.push('--stats was provided but swagger-stats parity is not restored; v5 only exposes the compatibility redirect/deprecation route.');\n }\n\n if (argv.includes('--generate-api-docs')) {\n unsupportedWarnings.push('--generate-api-docs was provided; runtime docs are always served from the shared API layer and no separate collection generation step currently runs at CLI boot.');\n }\n\n if (argv.includes('--tunnel')) {\n unsupportedWarnings.push('--tunnel was provided but tunnel setup parity is not yet restored in the v5 CLI.');\n }\n\n if (argv.includes('--chatwoot-url') || argv.includes('--twilio-webhook') || argv.includes('--bot-press-url')) {\n unsupportedWarnings.push('Legacy integration flags (Chatwoot/Twilio/BotPress) were provided but are not yet wired into the v5 CLI boot path.');\n }\n\n if (argv.includes('--use-session-id-in-path') && sessionId) {\n cliOverrides.sessionId = sessionId;\n }\n\n configPath = getVal(argv, '--config') || getVal(argv, '-c');\n\n const procName = getVal(argv, '--name') || sessionId || '@OPEN-WA EASY API';\n const pm2 = argv.includes('--pm2');\n\n return {\n procName,\n pm2,\n forwardedArgs: argv,\n configPath,\n cliOverrides,\n verbose,\n unsupportedWarnings,\n };\n}\n\nexport async function resolveExecutablePath(\n config: Config,\n options: {\n preferLocalChrome?: boolean;\n cacheFilePath?: string;\n } = {}\n): Promise<ExecutablePathResolution> {\n if (config.executablePath) {\n return {\n executablePath: config.executablePath,\n source: 'config',\n };\n }\n\n const preferLocalChrome = options.preferLocalChrome ?? config.useChrome;\n if (!preferLocalChrome) {\n return {\n source: 'driver_default',\n };\n }\n\n const cacheFilePath = options.cacheFilePath ?? getChromeCacheFilePath();\n const cachedPath = readChromePathCache(cacheFilePath)?.executablePath;\n if (isUsableExecutablePath(cachedPath)) {\n return {\n executablePath: cachedPath,\n source: 'cache',\n };\n }\n\n if (cachedPath) {\n clearChromePathCache(cacheFilePath);\n }\n\n const { Launcher } = await import('chrome-launcher');\n const detectedPath = Launcher.getInstallations().find((installationPath) => isUsableExecutablePath(installationPath));\n\n if (detectedPath) {\n writeChromePathCache(detectedPath, cacheFilePath);\n return {\n executablePath: detectedPath,\n source: 'chrome_installation',\n };\n }\n\n clearChromePathCache(cacheFilePath);\n\n return {\n source: 'driver_default',\n warning: 'Chrome resolution warning: no valid local Chrome installation was found. Falling back to Puppeteer/default driver browser resolution.',\n };\n}\n\nfunction resolveLightpandaExecutablePath(config: Config): ExecutablePathResolution {\n const executablePath = config.lightpanda?.executablePath;\n if (executablePath) {\n return {\n executablePath,\n source: 'lightpanda_config',\n };\n }\n\n return {\n source: 'lightpanda_sdk_default',\n };\n}\n\nasync function selectRuntimeDriver(config: Config, rawConfigs?: TrackedConfig['rawConfigs']): Promise<DriverSelection> {\n if (config.useLightpanda) {\n return {\n driver: new LightpandaDriver(),\n engineLabel: 'Lightpanda',\n executableResolution: resolveLightpandaExecutablePath(config),\n preferLocalChrome: false,\n };\n }\n\n const preferLocalChrome = shouldPreferLocalChrome(config, rawConfigs);\n const executableResolution = await resolveExecutablePath(config, { preferLocalChrome });\n\n return {\n driver: new PuppeteerDriver(),\n engineLabel: 'Puppeteer',\n executableResolution,\n preferLocalChrome,\n };\n}\n\nfunction printStartupSummary(\n config: Config,\n resolution: ExecutablePathResolution,\n preferLocalChrome: boolean,\n engineLabel: DriverSelection['engineLabel'],\n) {\n const host = config.host.includes('http') ? config.host : `http://${config.host}`;\n const sink = getCliOutputSink();\n sink.write({ level: 'info', message: `Easy API session: ${config.sessionId}` });\n sink.write({ level: 'info', message: `Health: ${host}:${config.port}/health` });\n sink.write({ level: 'info', message: `API Explorer: ${host}:${config.port}/api-docs/` });\n sink.write({ level: 'info', message: `Swagger JSON: ${host}:${config.port}/meta/swagger.json` });\n sink.write({ level: 'info', message: `Postman JSON: ${host}:${config.port}/meta/postman.json` });\n sink.write({ level: 'info', message: `Browser mode: ${config.headless ? 'headless' : 'headful'}` });\n sink.write({ level: 'info', message: `Browser engine: ${engineLabel}` });\n if (config.dashboard) {\n sink.write({ level: 'info', message: `Dashboard: ${host}:${config.port}/dashboard/` });\n } else {\n sink.write({ level: 'info', message: 'Dashboard: disabled (--no-dashboard)' });\n }\n if (resolution.source === 'lightpanda_config' && resolution.executablePath) {\n sink.write({ level: 'info', message: `Browser executable: explicit Lightpanda override (${resolution.executablePath})` });\n } else if (resolution.source === 'lightpanda_sdk_default') {\n sink.write({ level: 'info', message: 'Browser executable: Lightpanda SDK managed executable (shared cache/default resolution)' });\n } else if (resolution.source === 'config' && config.executablePath) {\n sink.write({ level: 'info', message: `Browser executable: explicit override (${config.executablePath})` });\n } else if (resolution.source === 'cache') {\n sink.write({ level: 'info', message: `Browser executable: local Chrome from cache (${resolution.executablePath})` });\n } else if (resolution.source === 'chrome_installation') {\n sink.write({ level: 'info', message: `Browser executable: local Chrome detected (${resolution.executablePath})` });\n } else if (preferLocalChrome) {\n sink.write({ level: 'info', message: 'Browser executable: driver default fallback (local Chrome unavailable)' });\n }\n if (config.webhook) {\n sink.write({\n level: 'warn',\n message: `Webhook configured (${config.webhook}) but v5 CLI webhook registration parity is not yet restored.`,\n });\n }\n}\n\nexport async function start(parsedArgs: ParsedCliArgs = parseCliArgs()): Promise<CliRuntimeResult> {\n const { configPath, cliOverrides, verbose, unsupportedWarnings } = parsedArgs;\n const sink = getCliOutputSink();\n\n sink.status({ phase: 'boot' });\n\n const { config, sources, configFilePath, rawConfigs } = await resolveConfig({\n configPath,\n cliOverrides: {\n disableSpins: true,\n apiLifecycle: 'hybrid',\n // Let schema defaults, config files, and WA_HOST/WA_PORT resolve\n // before applying host/port flags actually supplied by the user.\n ...cliOverrides,\n },\n includeRawConfigs: true,\n verbose,\n });\n\n if (verbose) {\n sink.write({ level: 'info', message: `Config sources: ${sources.join(', ')}` });\n if (configFilePath) {\n sink.write({ level: 'info', message: `Config file: ${configFilePath}` });\n }\n }\n\n sink.status({ phase: 'config.resolved', sessionId: config.sessionId });\n\n unsupportedWarnings.forEach((warning) => sink.write({ level: 'warn', message: `Compatibility warning: ${warning}` }));\n\n const driverSelection = await selectRuntimeDriver(config, rawConfigs);\n const { driver, engineLabel, executableResolution, preferLocalChrome } = driverSelection;\n if (executableResolution.warning) {\n sink.write({ level: 'warn', message: executableResolution.warning });\n }\n\n const server = new WAServer(config);\n sink.status({ phase: 'server.starting', sessionId: config.sessionId });\n\n await server.start();\n sink.status({ phase: 'server.started', sessionId: config.sessionId });\n\n printStartupSummary(config, executableResolution, preferLocalChrome, engineLabel);\n\n sink.status({ phase: 'client.starting', sessionId: config.sessionId });\n sink.write({ level: 'info', message: 'Starting WhatsApp Client...' });\n\n const sandboxPolicy = resolveChatSandboxPolicy(config.sandboxChats);\n const executionSandbox = sandboxPolicy\n ? makeNodeExecutionSandbox({ workspacePath: process.cwd() })\n : undefined;\n\n const openwaClient = await createClient({\n sessionId: config.sessionId,\n driver,\n deleteSessionDataOnLogout: config.deleteSessionDataOnLogout,\n killClientOnLogout: config.killClientOnLogout,\n sessionDataPath: config.sessionDataPath,\n sessionData: config.sessionData,\n skipSessionSave: config.skipSessionSave,\n sessionDataBucketAuth: config.sessionDataBucketAuth,\n sessionDataEncryptionKey: config.sessionDataEncryptionKey,\n sessionDataEncryptionKeyFile: config.sessionDataEncryptionKeyFile,\n s3Sync: config.s3Sync,\n debug: config.logLevel === 'debug' || verbose || config.logConsole,\n headless: config.headless,\n qrTimeoutMs: typeof config.qrTimeout === 'number' ? config.qrTimeout * 1000 : undefined,\n authTimeoutMs: typeof config.authTimeout === 'number' ? config.authTimeout * 1000 : undefined,\n executablePath: executableResolution.executablePath,\n browserArgs: config.chromiumArgs,\n browser: config.browser,\n allowDangerousBrowserArgs: config.allowDangerousBrowserArgs,\n userDataDir: config.userDataDir,\n ephemeral: config.ephemeral,\n linkCode: config.linkCode,\n logConsole: config.logConsole,\n logConsoleErrors: config.logConsoleErrors,\n blockCrashLogs: config.blockCrashLogs,\n blockAssets: config.blockAssets,\n safeMode: config.safeMode,\n licenseKey: config.licenseKey as any,\n sandboxPolicy,\n executionSandbox,\n memoryObservation: (observability, getBrowserProcessId) => observeBrowserProcessMemory(\n observability,\n getBrowserProcessId,\n { attributes: { session: config.sessionId } },\n ),\n });\n\n server.setReadinessProvider(() => ({ ...openwaClient.getReadiness(), state: openwaClient.getState() }));\n const detachLaunchNarration = attachLaunchNarration(openwaClient, sink, config.sessionId);\n\n openwaClient.events.on('launch.auth.qr.generated', (event) => {\n const qr = event.details?.qr;\n if (!qr) {\n return;\n }\n\n if (config.qrLogSkip) {\n sink.write({ level: 'info', message: 'New QR Code generated. Not printing in console because qrLogSkip is set to true' });\n } else {\n sink.status({ phase: 'auth.qr', sessionId: config.sessionId, detail: 'QR code generated' });\n sink.qr({ qr, sessionId: config.sessionId });\n }\n\n server.setQR(qr);\n });\n\n openwaClient.events.on('launch.auth.linkCode.generated', (event) => {\n const linkCode = event.details?.linkCode;\n if (!linkCode) {\n return;\n }\n\n sink.status({\n phase: 'launch.auth',\n sessionId: config.sessionId,\n detail: 'Link code generated; enter it on the paired phone',\n });\n sink.write({\n level: 'info',\n message: `Link code (local console only): ${linkCode}`,\n });\n });\n\n const client = new ClientFacade({\n client: openwaClient,\n transport: openwaClient.getTransport(),\n });\n\n server.setClient(client as any);\n\n const runtimeBridgeListeners = new Set<(event: string, value: any) => void>();\n const runtimeEventPublishers: RuntimeEventPublisher[] = [\n {\n publish: (eventName, payload) => {\n runtimeBridgeListeners.forEach((listener) => {\n listener(eventName, payload);\n });\n },\n },\n ];\n\n const publishRuntimeEvent = (eventName: string, payload: any) => {\n runtimeEventPublishers.forEach((publisher) => {\n publisher.publish(eventName, payload);\n });\n };\n\n const detachRuntimeBridge = bridgeRuntimeEvents(openwaClient, publishRuntimeEvent);\n\n // Bridge core events to the socket manager so dashboard clients\n // receive live events when they send register_ev.\n if (typeof server.setEventBridge === 'function') {\n server.setEventBridge({\n onAny: (listener: (event: string, value: any) => void) => {\n runtimeBridgeListeners.add(listener);\n },\n offAny: (listener: (event: string, value: any) => void) => {\n runtimeBridgeListeners.delete(listener);\n },\n });\n }\n\n const handleBrowserInit = async () => {\n const page = openwaClient.getTransport().getPage();\n if (page) {\n await server.setPage(page as any).catch(() => {});\n }\n };\n openwaClient.events.on('launch.browser.init.after', handleBrowserInit);\n\n let disposed = false;\n const dispose = () => {\n if (disposed) return;\n disposed = true;\n detachRuntimeBridge();\n openwaClient.events.off('launch.browser.init.after', handleBrowserInit);\n runtimeBridgeListeners.clear();\n };\n\n try {\n await client.start();\n } catch (startError) {\n const msg = startError instanceof Error ? startError.message : String(startError);\n sink.write({ level: 'error', message: `Bootstrap failed: ${msg}` });\n sink.write({ level: 'warn', message: 'Session kept alive for debugging. Browser page is still open.' });\n sink.write({ level: 'warn', message: 'The server is running — use /health and /api-docs to inspect state.' });\n detachLaunchNarration();\n return { server, client, config, events: openwaClient.events, dispose };\n }\n\n const readiness = openwaClient.getReadiness();\n sink.status({\n phase: 'client.ready',\n sessionId: config.sessionId,\n detail: `status=${readiness.status}, exposureSafe=${readiness.exposureSafe}`,\n });\n sink.write({\n level: 'info',\n message: `WhatsApp Client ready with state: ${client.getState()} (status=${readiness.status}, exposureSafe=${readiness.exposureSafe})`,\n });\n\n detachLaunchNarration();\n return { server, client, config, events: openwaClient.events, dispose };\n}\n\nexport async function main(argv: string[] = process.argv.slice(2)): Promise<CliRuntimeResult | void> {\n if (argv[0] === 'init') {\n const { initProject } = await import('./cli/init');\n await initProject(argv.slice(1));\n return;\n }\n const parsedArgs = parseCliArgs(argv);\n\n if (parsedArgs.pm2) {\n const { spawn } = require('child_process');\n const sink = getCliOutputSink();\n const pm2Command = getPm2Command();\n const pm2SpawnOptions = getPm2SpawnOptions();\n try {\n const pm2 = spawn(pm2Command, ['--version'], pm2SpawnOptions);\n\n await new Promise<void>((resolve, reject) => {\n pm2.on('error', reject);\n pm2.on('exit', (code: number | null) => {\n if (code === 0) {\n resolve();\n return;\n }\n\n reject(new Error(`pm2 probe exited with code ${code ?? 'unknown'}`));\n });\n pm2.stdout.on('data', () => resolve());\n });\n\n const pm2Flags = parsedArgs.forwardedArgs.filter((flag: string) => flag !== '--pm2');\n const cliPath = fileURLToPath(new URL('../dist/cli.cjs', import.meta.url));\n\n spawn(pm2Command, [\n 'start',\n cliPath,\n '--name', parsedArgs.procName,\n '--stop-exit-codes', '88',\n '--',\n ...pm2Flags,\n ], {\n ...pm2SpawnOptions,\n stdio: 'inherit',\n detached: true\n });\n return;\n } catch (error: unknown) {\n if (isCommandNotFoundError(error)) {\n sink.write({ level: 'error', message: 'pm2 not found. Please install with: npm install -g pm2' });\n return;\n }\n throw error;\n }\n }\n\n return await start(parsedArgs);\n}\n\nfunction getPm2Command(): string {\n return process.platform === 'win32' ? 'pm2.cmd' : 'pm2';\n}\n\nfunction getPm2SpawnOptions(): { shell: boolean } {\n return { shell: process.platform === 'win32' };\n}\n\nfunction isCommandNotFoundError(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) {\n return false;\n }\n\n const systemError = error as { code?: unknown; errno?: unknown };\n return systemError.code === 'ENOENT' || systemError.errno === -2;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,IAAa,WAAb,cAA8BA,aAAAA,UAAU;CACtC,YAAY,QAAgB;EAC1B,MAAM,EAAE,OAAO,CAAC;CAClB;AACF;;;ACmCA,SAAS,eAAe,OAAuB,SAAuB;CACpE,IAAI,UAAU,QAAQ;EACpB,QAAQ,KAAK,OAAO;EACpB;CACF;CAEA,IAAI,UAAU,SAAS;EACrB,QAAQ,MAAM,OAAO;EACrB;CACF;CAEA,QAAQ,IAAI,OAAO;AACrB;AAEA,SAAgB,0BAAyC;CACvD,OAAO;EACL,MAAM,OAAO;GACX,eAAe,MAAM,OAAO,MAAM,OAAO;EAC3C;EACA,SAAS,CAET;EACA,GAAG,SAAS;GACV,gBAAA,QAAO,SAAS,QAAQ,IAAI,EAAE,OAAO,KAAK,IAAI,mBAAmB;IAC/D,QAAQ,IAAI,mBAAmB,QAAQ,UAAU,IAAI,gBAAgB;GACvE,CAAC;EACH;CACF;AACF;AAEA,IAAI,aAA4B,wBAAwB;AAExD,SAAgB,mBAAkC;CAChD,OAAO;AACT;AAEA,SAAgB,iBAAiB,MAA2B;CAC1D,aAAa;AACf;AAEA,SAAgB,qBAA2B;CACzC,aAAa,wBAAwB;AACvC;;;ACtDA,SAAS,oBACL,cACA,qBACU;CACV,IAAI,OAAO,aAAa,OAAO,UAAU,cAAc,OAAO,aAAa,OAAO,WAAW,YAAY;EACrG,aAAa,OAAO,MAAM,mBAAmB;EAC7C,aAAa,aAAa,OAAO,OAAO,mBAAmB;CAC/D;CAEA,MAAM,gBAAmC,CAAC;CAG1C,IAF0B,IAAIC,gBAAAA,cAAc,OAAO,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,SAAS,CAExE,CAAC,CAAC,SAAS,cAAc;EACjC,MAAM,WAAW,YAAiB,oBAAoB,WAAW,OAAO;EACxE,aAAa,OAAO,GAAG,WAAoB,OAAO;EAClD,cAAc,WAAW,aAAa,OAAO,IAAI,WAAoB,OAAO,CAAC;CACjF,CAAC;CAED,aAAa;EACT,cAAc,SAAS,gBAAgB,YAAY,CAAC;CACxD;AACJ;AAEA,SAAS,sBACL,cACA,MACA,WACU;CACV,MAAM,gBAAmC,CAAC;CAC1C,MAAM,MAAM,OAAe,YAAsC;EAC7D,aAAa,OAAO,GAAG,OAAgB,OAAO;EAC9C,cAAc,WAAW,aAAa,OAAO,IAAI,OAAgB,OAAO,CAAC;CAC7E;CAEA,GAAG,6BAA6B,UAAe;EAC3C,KAAK,OAAO;GAAE,OAAO;GAAe;GAAW,QAAQ,2BAA2B,OAAO,SAAS,aAAa,IAAI;EAAK,CAAC;CAC7H,CAAC;CAED,GAAG,4BAA4B,UAAe;EAC1C,KAAK,MAAM;GAAE,OAAO;GAAQ,SAAS,qBAAqB,OAAO,SAAS,UAAU,UAAU,IAAI,OAAO,SAAS,kBAAkB,kBAAkB,oBAAoB;EAAG,CAAC;CAClL,CAAC;CAED,GAAG,iCAAiC,UAAe;EAC/C,KAAK,OAAO;GAAE,OAAO;GAAkB;GAAW,QAAQ,OAAO,SAAS,SAAS,YAAY,uCAAuC;EAAkC,CAAC;CAC7K,CAAC;CAED,GAAG,gCAAgC,UAAe;EAC9C,KAAK,MAAM;GAAE,OAAO;GAAQ,SAAS,kCAAkC,OAAO,SAAS,QAAQ,UAAU;EAAG,CAAC;CACjH,CAAC;CAED,GAAG,6BAA6B,UAAe;EAC3C,MAAM,SAAU,OAAO,SAAS,OAAO,UAAU,IAAK,GAAG,MAAM,MAAM,MAAM;EAC3E,IAAI,OAAO,MAAM,KAAK,MAAM;GAAE,OAAO;GAAQ,SAAS,GAAG,SAAS,MAAM,OAAO,KAAK;EAAE,CAAC;CAC3F,CAAC;CAED,GAAG,8BAA8B,UAAe;EAC5C,KAAK,MAAM;GAAE,OAAO;GAAQ,SAAS,4BAA4B,OAAO,QAAQ,OAAO,SAAS;EAAY,CAAC;CACjH,CAAC;CAED,GAAG,6BAA6B,UAAe;EAC3C,IAAI,OAAO,SAAS,UAAU,WAC1B,KAAK,OAAO;GAAE,OAAO;GAAgB;GAAW,QAAQ;EAAkC,CAAC;CAEnG,CAAC;CAED,GAAG,4BAA4B,UAAe;EAC1C,IAAI,OAAO,SAAS,UAAU,WAAW;GACrC,MAAM,SAAS,OAAO,SAAS,UAAU;GACzC,MAAM,MAAM,OAAO,SAAS,MAAM,QAAQ,MAAM,QAAQ,QAAQ;GAChE,MAAM,YAAY,MAAM,QAAQ,OAAO,SAAS,SAAS,IAAI,MAAM,QAAQ,UAAU,SAAS;GAC9F,MAAM,aAAa,OAAO;GAC1B,MAAM,cAAc,aAAa,QAAQ,aAAa,IAAA,CAAM,QAAQ,CAAC,EAAE,KAAK;GAC5E,KAAK,MAAM;IAAE,OAAO;IAAQ,SAAS,qBAAqB,YAAY,WAAW,OAAO,cAAc,YAAY,IAAI;GAAG,CAAC;EAC9H;CACJ,CAAC;CAED,GAAG,sBAAsB,UAAe;EACpC,IAAI,OAAO,SAAS,UAAU,SAAS;GACnC,MAAM,QAAQ,MAAM,QAAQ,OAAO,SAAS,QAAQ,IAAI,MAAM,QAAQ,SAAS,SAAS;GACxF,KAAK,OAAO;IAAE,OAAO;IAAgB;IAAW,QAAQ,uBAAuB,MAAM;GAAU,CAAC;EACpG;CACJ,CAAC;CAED,GAAG,uBAAuB,UAAe;EACrC,KAAK,OAAO;GAAE,OAAO;GAAgB;GAAW,QAAQ,mBAAmB,OAAO,SAAS,WAAW;EAAY,CAAC;CACvH,CAAC;CAED,GAAG,sBAAsB,UAAe;EACpC,KAAK,MAAM;GACP,OAAO,OAAO,SAAS,YAAY,WAAW,SAAS;GACvD,SAAS,SAAS,OAAO,SAAS,WAAW,UAAU,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU,YAAY,aAAa,OAAO,SAAS,SAAS,MAAM,MAAM,QAAQ,WAAW;EACtM,CAAC;CACL,CAAC;CAED,GAAG,qBAAqB,UAAe;EACnC,IAAI,OAAO,SAAS,UAAU,SAAS;GACnC,MAAM,UAAU,MAAM,QAAQ,OAAO,SAAS,OAAO,IAAI,MAAM,QAAQ,UAAU,CAAC;GAClF,MAAM,UAAU,OAAO,SAAS,WAAW;GAC3C,MAAM,MAAM,QAAQ,SAAS,IAAI,QAAQ,KAAK,IAAI,IAAI;GACtD,MAAM,aAAa,OAAO;GAC1B,MAAM,cAAc,aAAa,QAAQ,aAAa,IAAA,CAAM,QAAQ,CAAC,EAAE,KAAK;GAC5E,KAAK,MAAM;IACP,OAAO,OAAO,SAAS,kBAAkB,SAAS;IAClD,SAAS,oBAAoB,YAAY,IAAI;GACjD,CAAC;EACL;CACJ,CAAC;CAED,GAAG,uCAAuC;EACtC,KAAK,OAAO;GAAE,OAAO;GAAgB;GAAW,QAAQ;EAAgC,CAAC;CAC7F,CAAC;CAED,GAAG,iCAAiC,UAAe;EAC/C,KAAK,MAAM;GAAE,OAAO,OAAO,SAAS,SAAS,SAAS;GAAQ,SAAS,+BAA+B,OAAO,SAAS,SAAS,WAAW,WAAW,OAAO,SAAS,gBAAgB,KAAK,MAAM,QAAQ,cAAc,KAAK;EAAK,CAAC;CACrO,CAAC;CAED,GAAG,gCAAgC,UAAe;EAC9C,KAAK,OAAO;GAAE,OAAO;GAAkB;GAAW,QAAQ,qBAAqB,OAAO,SAAS,UAAU,QAAQ;EAAG,CAAC;CACzH,CAAC;CAED,GAAG,+BAA+B,UAAe;EAC7C,KAAK,MAAM;GAAE,OAAO,OAAO,SAAS,kBAAkB,SAAS;GAAQ,SAAS,kBAAkB,OAAO,SAAS,UAAU,YAAY,OAAO,SAAS,SAAS,MAAM,MAAM,QAAQ,WAAW;EAAK,CAAC;CAC1M,CAAC;CAED,GAAG,+BAA+B;EAC9B,KAAK,OAAO;GAAE,OAAO;GAAkB;GAAW,QAAQ;EAA+B,CAAC;CAC9F,CAAC;CAED,GAAG,yBAAyB,UAAe;EACvC,KAAK,MAAM;GAAE,OAAO,OAAO,SAAS,UAAU,SAAS;GAAQ,SAAS,mBAAmB,OAAO,SAAS,UAAU,YAAY,WAAW,OAAO,SAAS,SAAS,KAAK,MAAM,QAAQ,OAAO,KAAK,KAAK,OAAO,SAAS,SAAS,MAAM,MAAM,QAAQ,WAAW;EAAK,CAAC;CAC3Q,CAAC;CAED,GAAG,6BAA6B,UAAe;EAC3C,MAAM,UAAU,OAAO,SAAS,WAAW;EAC3C,KAAK,OAAO;GAAE,OAAO;GAAe;GAAW,QAAQ,uBAAuB,QAAQ;EAAG,CAAC;CAC9F,CAAC;CAED,GAAG,kCAAkC,UAAe;EAChD,KAAK,OAAO;GAAE,OAAO;GAAmB;GAAW,QAAQ,uBAAuB,OAAO,SAAS,mBAAmB,UAAU;EAAG,CAAC;CACvI,CAAC;CAED,GAAG,iCAAiC,UAAe;EAC/C,KAAK,MAAM;GAAE,OAAO,OAAO,SAAS,UAAU,SAAS;GAAQ,SAAS,aAAa,OAAO,SAAS,WAAW,YAAY,OAAO,SAAS,SAAS,MAAM,MAAM,QAAQ,WAAW;EAAK,CAAC;CAC9L,CAAC;CAED,GAAG,UAAU,UAAe;EACxB,MAAM,QAAQ,OAAO,SAAS;EAC9B,MAAM,MAAM,OAAO,OAAO,WAAW,OAAO,OAAO,SAAS,eAAe;EAC3E,MAAM,QAAQ,OAAO,QAAQ,aAAa;EAC1C,KAAK,MAAM;GAAE,OAAO;GAAS,SAAS,GAAG,MAAM,GAAG,MAAM,IAAI,MAAM,KAAK;EAAE,CAAC;CAC9E,CAAC;CAED,aAAa;EACT,cAAc,SAAS,gBAAgB,YAAY,CAAC;CACxD;AACJ;AAEA,MAAM,qBAAA,GAAoBC,UAAAA,QAAAA,CAAQ,QAAQ,IAAI,GAAG,YAAY,6BAA6B;AAoC1F,SAAgB,yBAAiC;CAC7C,OAAO;AACX;AAEA,SAAgB,oBAAoB,gBAAwB,uBAAuB,GAAsC;CACrH,IAAI,EAAA,GAACC,QAAAA,WAAAA,CAAW,aAAa,GACzB;CAGJ,IAAI;EACA,MAAM,MAAM,KAAK,OAAA,GAAMC,QAAAA,aAAAA,CAAa,eAAe,MAAM,CAAC;EAC1D,IAAI,CAAC,OAAO,OAAO,QAAQ,UACvB;EAGJ,OAAO;GACH,gBAAgB,OAAO,IAAI,mBAAmB,WAAW,IAAI,iBAAiB,KAAA;GAC9E,WAAW,OAAO,IAAI,cAAc,WAAW,IAAI,YAAY,KAAA;EACnE;CACJ,QAAQ;EACJ;CACJ;AACJ;AAEA,SAAgB,qBAAqB,gBAAwB,gBAAwB,uBAAuB,GAAS;CACjH,CAAA,GAAA,QAAA,UAAA,EAAA,GAAUC,UAAAA,QAAAA,CAAQ,aAAa,GAAG,EAAE,WAAW,KAAK,CAAC;CACrD,CAAA,GAAA,QAAA,cAAA,CAAc,eAAe,KAAK,UAAU;EAAE;EAAgB,4BAAW,IAAI,KAAK,EAAA,CAAE,YAAY;CAAE,GAAG,MAAM,CAAC,GAAG,MAAM;AACzH;AAEA,SAAgB,qBAAqB,gBAAwB,uBAAuB,GAAS;CACzF,KAAA,GAAIF,QAAAA,WAAAA,CAAW,aAAa,GACxB,CAAA,GAAA,QAAA,OAAA,CAAO,eAAe,EAAE,OAAO,KAAK,CAAC;AAE7C;AAEA,SAAgB,uBAAuB,gBAAmD;CACtF,OAAO,CAAC,CAAC,mBAAA,GAAkBA,QAAAA,WAAAA,CAAW,cAAc;AACxD;AAEA,SAAS,+BAA+B,YAA+D;CACnG,MAAM,wBAAwB;EAC1B,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,YAAY;CAChB;CAEA,KAAK,IAAI,QAAQ,sBAAsB,SAAS,GAAG,SAAS,GAAG,SAAS,GAAG;EACvE,MAAM,SAAS,sBAAsB;EACrC,IAAI,QAAQ,cAAc,KAAA,GACtB,OAAO,OAAO;CAEtB;AAGJ;AAEA,SAAgB,wBAAwB,QAAgB,YAAmD;CACvG,IAAI,OAAO,eACP,OAAO;CAGX,IAAI,OAAO,gBACP,OAAO;CAGX,MAAM,oBAAoB,+BAA+B,UAAU;CACnE,IAAI,sBAAsB,KAAA,GACtB,OAAO;CAGX,OAAO;AACX;AAEA,SAAS,OAAO,MAAgB,MAAkC;CAC9D,MAAM,QAAQ,KAAK,WAAU,QAAO,QAAQ,IAAI;CAChD,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,KAAA;AAC5C;AAEA,SAAS,sBAAsB,OAAiC;CAC5D,QAAQ,OAAR;EACI,KAAK;EACL,KAAK;EACL,KAAK,aACD,OAAO;EACX,SACI,MAAM,IAAI,MAAM,sCAAsC,OAAO;CACrE;AACJ;AAEA,SAAgB,yBAAyB,QAA+D;CACpG,IAAI,CAAC,QAAQ,OAAO,KAAA;CAEpB,MAAM,YAAY,OAAO,WAAW,WAC9B,SACA,CAAC;CACP,OAAO;EACH,GAAGG,sBAAAA;EACH,GAAG;EACH,OAAO;EACP,kBAAkB,CAAC,GAAI,UAAU,oBAAoBA,sBAAAA,yBAAyB,gBAAiB;EAC/F,KAAK,UAAU,QAAQ,UAAU,UAAU,QAAQ,KAAA,IAC7C,UAAU,OAAOA,sBAAAA,yBAAyB,MAC1C,CAAC,GAAG,UAAU,GAAG;EACvB,cAAc,CAAC,GAAI,UAAU,gBAAgBA,sBAAAA,yBAAyB,YAAa;CACvF;AACJ;AAEA,SAAgB,aAAa,OAAiB,QAAQ,KAAK,MAAM,CAAC,GAAkB;CAChF,MAAM,eAA8B,CAAC;CACrC,MAAM,sBAAgC,CAAC;CACvC,IAAI,UAAU;CACd,IAAI;CAEJ,MAAM,YAAY,OAAO,MAAM,cAAc;CAC7C,IAAI,WAAW,aAAa,YAAY;CAExC,MAAM,YAAY,OAAO,MAAM,QAAQ,KAAK,OAAO,MAAM,IAAI;CAC7D,IAAI,WAAW,aAAa,OAAO,SAAS,WAAW,EAAE;CAEzD,MAAM,OAAO,OAAO,MAAM,QAAQ,KAAK,OAAO,MAAM,IAAI;CACxD,IAAI,MAAM,aAAa,OAAO;CAE9B,MAAM,SAAS,OAAO,MAAM,WAAW,KAAK,OAAO,MAAM,OAAO,KAAK,OAAO,MAAM,IAAI;CACtF,IAAI,QAAQ,aAAa,SAAS;CAElC,MAAM,WAAW,OAAO,MAAM,aAAa;CAC3C,IAAI,UAAU,aAAa,WAAW;CAEtC,IAAI,KAAK,SAAS,WAAW,GAAG,aAAa,OAAO;CACpD,IAAI,KAAK,SAAS,WAAW,GAAG,aAAa,WAAW;CACxD,IAAI,KAAK,SAAS,YAAY,GAAG,aAAa,WAAW;CACzD,IAAI,KAAK,SAAS,cAAc,GAAG,aAAa,YAAY;CAC5D,IAAI,KAAK,SAAS,kBAAkB,GAAG,aAAa,gBAAgB;CACpE,IAAI,KAAK,SAAS,eAAe,GAAG,aAAa,aAAa;CAC9D,IAAI,KAAK,SAAS,iCAAiC,GAAG,aAAa,8BAA8B;CACjG,IAAI,KAAK,SAAS,gBAAgB,GAAG,aAAa,YAAY;CAC9D,IAAI,KAAK,SAAS,aAAa,GAAG,aAAa,YAAY;CAC3D,IAAI,KAAK,SAAS,iBAAiB,GAAG,aAAa,eAAe;CAElE,MAAM,mBAAmB,OAAO,MAAM,qBAAqB;CAC3D,IAAI,kBAAkB;EAClB,MAAM,EAAE,OAAO,QAAQ,GAAG,oBAAoBA,sBAAAA;EAC9C,aAAa,eAAe;GACxB,GAAG;GACH,WAAW,sBAAsB,gBAAgB;GACjD,kBAAkB,CAAC,GAAGA,sBAAAA,yBAAyB,gBAAgB;GAC/D,KAAKA,sBAAAA,yBAAyB,QAAQ,SAChC,SACA,CAAC,GAAGA,sBAAAA,yBAAyB,GAAG;GACtC,cAAc,CAAC,GAAGA,sBAAAA,yBAAyB,YAAY;EAC3D;CACJ;CAEA,MAAM,YAAY,OAAO,MAAM,cAAc;CAC7C,IAAI,WAAW,aAAa,YAAY,SAAS,WAAW,EAAE;CAE9D,MAAM,gBAAgB,OAAO,MAAM,kBAAkB;CACrD,IAAI,eAAe,aAAa,gBAAgB,SAAS,eAAe,EAAE;CAE1E,MAAM,aAAa,OAAO,MAAM,eAAe,KAAK,OAAO,MAAM,IAAI;CACrE,IAAI,YAAY,aAAa,aAAa;CAE1C,MAAM,UAAU,OAAO,MAAM,WAAW,KAAK,OAAO,MAAM,IAAI;CAC9D,IAAI,SAAS,aAAa,UAAU;CAEpC,MAAM,YAAY,OAAO,MAAM,cAAc;CAC7C,IAAI,WAAW,aAAa,YAAY;CAExC,MAAM,aAAa,OAAO,MAAM,eAAe;CAC/C,IAAI,YAAY,aAAa,aAAa;CAE1C,MAAM,eAAe,OAAO,MAAM,iBAAiB;CACnD,IAAI,cAAc,oBAAoB,KAAK,iCAAiC,aAAa,yDAAyD;CAElJ,IAAI,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,WAAW,GAAG;EACnD,UAAU;EACV,aAAa,eAAe;EAC5B,aAAa,aAAa;EAC1B,aAAa,WAAW,aAAa,YAAY;CACrD;CAEA,IAAI,KAAK,SAAS,SAAS,GACvB,oBAAoB,KAAK,8HAA8H;CAG3J,IAAI,KAAK,SAAS,qBAAqB,GACnC,oBAAoB,KAAK,mKAAmK;CAGhM,IAAI,KAAK,SAAS,UAAU,GACxB,oBAAoB,KAAK,kFAAkF;CAG/G,IAAI,KAAK,SAAS,gBAAgB,KAAK,KAAK,SAAS,kBAAkB,KAAK,KAAK,SAAS,iBAAiB,GACvG,oBAAoB,KAAK,oHAAoH;CAGjJ,IAAI,KAAK,SAAS,0BAA0B,KAAK,WAC7C,aAAa,YAAY;CAG7B,aAAa,OAAO,MAAM,UAAU,KAAK,OAAO,MAAM,IAAI;CAK1D,OAAO;EACH,UAJa,OAAO,MAAM,QAAQ,KAAK,aAAa;EAKpD,KAJQ,KAAK,SAAS,OAIpB;EACF,eAAe;EACf;EACA;EACA;EACA;CACJ;AACJ;AAEA,eAAsB,sBAClB,QACA,UAGI,CAAC,GAC4B;CACjC,IAAI,OAAO,gBACP,OAAO;EACH,gBAAgB,OAAO;EACvB,QAAQ;CACZ;CAIJ,IAAI,EADsB,QAAQ,qBAAqB,OAAO,YAE1D,OAAO,EACH,QAAQ,iBACZ;CAGJ,MAAM,gBAAgB,QAAQ,iBAAiB,uBAAuB;CACtE,MAAM,aAAa,oBAAoB,aAAa,CAAC,EAAE;CACvD,IAAI,uBAAuB,UAAU,GACjC,OAAO;EACH,gBAAgB;EAChB,QAAQ;CACZ;CAGJ,IAAI,YACA,qBAAqB,aAAa;CAGtC,MAAM,EAAE,aAAa,MAAM,OAAO;CAClC,MAAM,eAAe,SAAS,iBAAiB,CAAC,CAAC,MAAM,qBAAqB,uBAAuB,gBAAgB,CAAC;CAEpH,IAAI,cAAc;EACd,qBAAqB,cAAc,aAAa;EAChD,OAAO;GACH,gBAAgB;GAChB,QAAQ;EACZ;CACJ;CAEA,qBAAqB,aAAa;CAElC,OAAO;EACH,QAAQ;EACR,SAAS;CACb;AACJ;AAEA,SAAS,gCAAgC,QAA0C;CAC/E,MAAM,iBAAiB,OAAO,YAAY;CAC1C,IAAI,gBACA,OAAO;EACH;EACA,QAAQ;CACZ;CAGJ,OAAO,EACH,QAAQ,yBACZ;AACJ;AAEA,eAAe,oBAAoB,QAAgB,YAAoE;CACnH,IAAI,OAAO,eACP,OAAO;EACH,QAAQ,IAAIC,2BAAAA,iBAAiB;EAC7B,aAAa;EACb,sBAAsB,gCAAgC,MAAM;EAC5D,mBAAmB;CACvB;CAGJ,MAAM,oBAAoB,wBAAwB,QAAQ,UAAU;CACpE,MAAM,uBAAuB,MAAM,sBAAsB,QAAQ,EAAE,kBAAkB,CAAC;CAEtF,OAAO;EACH,QAAQ,IAAIC,0BAAAA,gBAAgB;EAC5B,aAAa;EACb;EACA;CACJ;AACJ;AAEA,SAAS,oBACL,QACA,YACA,mBACA,aACF;CACE,MAAM,OAAO,OAAO,KAAK,SAAS,MAAM,IAAI,OAAO,OAAO,UAAU,OAAO;CAC3E,MAAM,OAAO,iBAAiB;CAC9B,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,qBAAqB,OAAO;CAAY,CAAC;CAC9E,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,WAAW,KAAK,GAAG,OAAO,KAAK;CAAS,CAAC;CAC9E,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,iBAAiB,KAAK,GAAG,OAAO,KAAK;CAAY,CAAC;CACvF,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,iBAAiB,KAAK,GAAG,OAAO,KAAK;CAAoB,CAAC;CAC/F,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,iBAAiB,KAAK,GAAG,OAAO,KAAK;CAAoB,CAAC;CAC/F,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,iBAAiB,OAAO,WAAW,aAAa;CAAY,CAAC;CAClG,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,mBAAmB;CAAc,CAAC;CACvE,IAAI,OAAO,WACP,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,cAAc,KAAK,GAAG,OAAO,KAAK;CAAa,CAAC;MAErF,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS;CAAuC,CAAC;CAEjF,IAAI,WAAW,WAAW,uBAAuB,WAAW,gBACxD,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,qDAAqD,WAAW,eAAe;CAAG,CAAC;MACrH,IAAI,WAAW,WAAW,0BAC7B,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS;CAA0F,CAAC;MAC7H,IAAI,WAAW,WAAW,YAAY,OAAO,gBAChD,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,0CAA0C,OAAO,eAAe;CAAG,CAAC;MACtG,IAAI,WAAW,WAAW,SAC7B,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,gDAAgD,WAAW,eAAe;CAAG,CAAC;MAChH,IAAI,WAAW,WAAW,uBAC7B,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,8CAA8C,WAAW,eAAe;CAAG,CAAC;MAC9G,IAAI,mBACP,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS;CAAyE,CAAC;CAEnH,IAAI,OAAO,SACP,KAAK,MAAM;EACP,OAAO;EACP,SAAS,uBAAuB,OAAO,QAAQ;CACnD,CAAC;AAET;AAEA,eAAsB,MAAM,aAA4B,aAAa,GAA8B;CAC/F,MAAM,EAAE,YAAY,cAAc,SAAS,wBAAwB;CACnE,MAAM,OAAO,iBAAiB;CAE9B,KAAK,OAAO,EAAE,OAAO,OAAO,CAAC;CAE7B,MAAM,EAAE,QAAQ,SAAS,gBAAgB,eAAe,OAAA,GAAMC,gBAAAA,cAAAA,CAAc;EACxE;EACA,cAAc;GACV,cAAc;GACd,cAAc;GAGd,GAAG;EACP;EACA,mBAAmB;EACnB;CACJ,CAAC;CAED,IAAI,SAAS;EACT,KAAK,MAAM;GAAE,OAAO;GAAQ,SAAS,mBAAmB,QAAQ,KAAK,IAAI;EAAI,CAAC;EAC9E,IAAI,gBACA,KAAK,MAAM;GAAE,OAAO;GAAQ,SAAS,gBAAgB;EAAiB,CAAC;CAE/E;CAEA,KAAK,OAAO;EAAE,OAAO;EAAmB,WAAW,OAAO;CAAU,CAAC;CAErE,oBAAoB,SAAS,YAAY,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,0BAA0B;CAAU,CAAC,CAAC;CAGpH,MAAM,EAAE,QAAQ,aAAa,sBAAsB,sBAAsB,MAD3C,oBAAoB,QAAQ,UAAU;CAEpE,IAAI,qBAAqB,SACrB,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS,qBAAqB;CAAQ,CAAC;CAGvE,MAAM,SAAS,IAAI,SAAS,MAAM;CAClC,KAAK,OAAO;EAAE,OAAO;EAAmB,WAAW,OAAO;CAAU,CAAC;CAErE,MAAM,OAAO,MAAM;CACnB,KAAK,OAAO;EAAE,OAAO;EAAkB,WAAW,OAAO;CAAU,CAAC;CAEpE,oBAAoB,QAAQ,sBAAsB,mBAAmB,WAAW;CAEhF,KAAK,OAAO;EAAE,OAAO;EAAmB,WAAW,OAAO;CAAU,CAAC;CACrE,KAAK,MAAM;EAAE,OAAO;EAAQ,SAAS;CAA8B,CAAC;CAEpE,MAAM,gBAAgB,yBAAyB,OAAO,YAAY;CAClE,MAAM,mBAAmB,iBAAA,GACnBC,sBAAAA,yBAAAA,CAAyB,EAAE,eAAe,QAAQ,IAAI,EAAE,CAAC,IACzD,KAAA;CAEN,MAAM,eAAe,OAAA,GAAMC,cAAAA,aAAAA,CAAa;EACpC,WAAW,OAAO;EAClB;EACA,2BAA2B,OAAO;EAClC,oBAAoB,OAAO;EAC3B,iBAAiB,OAAO;EACxB,aAAa,OAAO;EACpB,iBAAiB,OAAO;EACxB,uBAAuB,OAAO;EAC9B,0BAA0B,OAAO;EACjC,8BAA8B,OAAO;EACrC,QAAQ,OAAO;EACf,OAAO,OAAO,aAAa,WAAW,WAAW,OAAO;EACxD,UAAU,OAAO;EACjB,aAAa,OAAO,OAAO,cAAc,WAAW,OAAO,YAAY,MAAO,KAAA;EAC9E,eAAe,OAAO,OAAO,gBAAgB,WAAW,OAAO,cAAc,MAAO,KAAA;EACpF,gBAAgB,qBAAqB;EACrC,aAAa,OAAO;EACpB,SAAS,OAAO;EAChB,2BAA2B,OAAO;EAClC,aAAa,OAAO;EACpB,WAAW,OAAO;EAClB,UAAU,OAAO;EACjB,YAAY,OAAO;EACnB,kBAAkB,OAAO;EACzB,gBAAgB,OAAO;EACvB,aAAa,OAAO;EACpB,UAAU,OAAO;EACjB,YAAY,OAAO;EACnB;EACA;EACA,oBAAoB,eAAe,yBAAA,GAAwBC,sBAAAA,4BAAAA,CACvD,eACA,qBACA,EAAE,YAAY,EAAE,SAAS,OAAO,UAAU,EAAE,CAChD;CACJ,CAAC;CAED,OAAO,4BAA4B;EAAE,GAAG,aAAa,aAAa;EAAG,OAAO,aAAa,SAAS;CAAE,EAAE;CACtG,MAAM,wBAAwB,sBAAsB,cAAc,MAAM,OAAO,SAAS;CAExF,aAAa,OAAO,GAAG,6BAA6B,UAAU;EAC1D,MAAM,KAAK,MAAM,SAAS;EAC1B,IAAI,CAAC,IACD;EAGJ,IAAI,OAAO,WACP,KAAK,MAAM;GAAE,OAAO;GAAQ,SAAS;EAAkF,CAAC;OACrH;GACH,KAAK,OAAO;IAAE,OAAO;IAAW,WAAW,OAAO;IAAW,QAAQ;GAAoB,CAAC;GAC1F,KAAK,GAAG;IAAE;IAAI,WAAW,OAAO;GAAU,CAAC;EAC/C;EAEA,OAAO,MAAM,EAAE;CACnB,CAAC;CAED,aAAa,OAAO,GAAG,mCAAmC,UAAU;EAChE,MAAM,WAAW,MAAM,SAAS;EAChC,IAAI,CAAC,UACD;EAGJ,KAAK,OAAO;GACR,OAAO;GACP,WAAW,OAAO;GAClB,QAAQ;EACZ,CAAC;EACD,KAAK,MAAM;GACP,OAAO;GACP,SAAS,mCAAmC;EAChD,CAAC;CACL,CAAC;CAED,MAAM,SAAS,IAAIC,gBAAAA,OAAa;EAC5B,QAAQ;EACR,WAAW,aAAa,aAAa;CACzC,CAAC;CAED,OAAO,UAAU,MAAa;CAE9B,MAAM,yCAAyB,IAAI,IAAyC;CAC5E,MAAM,yBAAkD,CACpD,EACI,UAAU,WAAW,YAAY;EAC7B,uBAAuB,SAAS,aAAa;GACzC,SAAS,WAAW,OAAO;EAC/B,CAAC;CACL,EACJ,CACJ;CAEA,MAAM,uBAAuB,WAAmB,YAAiB;EAC7D,uBAAuB,SAAS,cAAc;GAC1C,UAAU,QAAQ,WAAW,OAAO;EACxC,CAAC;CACL;CAEA,MAAM,sBAAsB,oBAAoB,cAAc,mBAAmB;CAIjF,IAAI,OAAO,OAAO,mBAAmB,YACjC,OAAO,eAAe;EAClB,QAAQ,aAAkD;GACtD,uBAAuB,IAAI,QAAQ;EACvC;EACA,SAAS,aAAkD;GACvD,uBAAuB,OAAO,QAAQ;EAC1C;CACJ,CAAC;CAGL,MAAM,oBAAoB,YAAY;EAClC,MAAM,OAAO,aAAa,aAAa,CAAC,CAAC,QAAQ;EACjD,IAAI,MACA,MAAM,OAAO,QAAQ,IAAW,CAAC,CAAC,YAAY,CAAC,CAAC;CAExD;CACA,aAAa,OAAO,GAAG,6BAA6B,iBAAiB;CAErE,IAAI,WAAW;CACf,MAAM,gBAAgB;EAClB,IAAI,UAAU;EACd,WAAW;EACX,oBAAoB;EACpB,aAAa,OAAO,IAAI,6BAA6B,iBAAiB;EACtE,uBAAuB,MAAM;CACjC;CAEA,IAAI;EACF,MAAM,OAAO,MAAM;CACrB,SAAS,YAAY;EACnB,MAAM,MAAM,sBAAsB,QAAQ,WAAW,UAAU,OAAO,UAAU;EAChF,KAAK,MAAM;GAAE,OAAO;GAAS,SAAS,qBAAqB;EAAM,CAAC;EAClE,KAAK,MAAM;GAAE,OAAO;GAAQ,SAAS;EAAgE,CAAC;EACtG,KAAK,MAAM;GAAE,OAAO;GAAQ,SAAS;EAAsE,CAAC;EAC5G,sBAAsB;EACtB,OAAO;GAAE;GAAQ;GAAQ;GAAQ,QAAQ,aAAa;GAAQ;EAAQ;CACxE;CAEA,MAAM,YAAY,aAAa,aAAa;CAC5C,KAAK,OAAO;EACR,OAAO;EACP,WAAW,OAAO;EAClB,QAAQ,UAAU,UAAU,OAAO,iBAAiB,UAAU;CAClE,CAAC;CACD,KAAK,MAAM;EACP,OAAO;EACP,SAAS,qCAAqC,OAAO,SAAS,EAAE,WAAW,UAAU,OAAO,iBAAiB,UAAU,aAAa;CACxI,CAAC;CAED,sBAAsB;CACtB,OAAO;EAAE;EAAQ;EAAQ;EAAQ,QAAQ,aAAa;EAAQ;CAAQ;AAC1E;AAEA,eAAsB,KAAK,OAAiB,QAAQ,KAAK,MAAM,CAAC,GAAqC;CACjG,IAAI,KAAK,OAAO,QAAQ;EACpB,MAAM,EAAE,gBAAgB,MAAA,QAAA,QAAA,CAAA,CAAA,WAAA,QAAM,qBAAA,CAAA;EAC9B,MAAM,YAAY,KAAK,MAAM,CAAC,CAAC;EAC/B;CACJ;CACA,MAAM,aAAa,aAAa,IAAI;CAEpC,IAAI,WAAW,KAAK;EAChB,MAAM,EAAE,UAAU,QAAQ,eAAe;EACzC,MAAM,OAAO,iBAAiB;EAC9B,MAAM,aAAa,cAAc;EACjC,MAAM,kBAAkB,mBAAmB;EAC3C,IAAI;GACA,MAAM,MAAM,MAAM,YAAY,CAAC,WAAW,GAAG,eAAe;GAE5D,MAAM,IAAI,SAAe,SAAS,WAAW;IACzC,IAAI,GAAG,SAAS,MAAM;IACtB,IAAI,GAAG,SAAS,SAAwB;KACpC,IAAI,SAAS,GAAG;MACZ,QAAQ;MACR;KACJ;KAEA,uBAAO,IAAI,MAAM,8BAA8B,QAAQ,WAAW,CAAC;IACvE,CAAC;IACD,IAAI,OAAO,GAAG,cAAc,QAAQ,CAAC;GACzC,CAAC;GAED,MAAM,WAAW,WAAW,cAAc,QAAQ,SAAiB,SAAS,OAAO;GAGnF,MAAM,YAAY;IACd;KAHYC,GAAAA,SAAAA,cAAAA,CAAc,IAAI,IAAI,mBAAA,QAAA,KAAA,CAAA,CAAA,cAAA,UAAA,CAAA,CAAA,IAAkC,CAI9D;IACN;IAAU,WAAW;IACrB;IAAqB;IACrB;IACA,GAAG;GACP,GAAG;IACC,GAAG;IACH,OAAO;IACP,UAAU;GACd,CAAC;GACD;EACJ,SAAS,OAAgB;GACrB,IAAI,uBAAuB,KAAK,GAAG;IAC/B,KAAK,MAAM;KAAE,OAAO;KAAS,SAAS;IAAyD,CAAC;IAChG;GACJ;GACA,MAAM;EACV;CACJ;CAEA,OAAO,MAAM,MAAM,UAAU;AACjC;AAEA,SAAS,gBAAwB;CAC7B,OAAO,QAAQ,aAAa,UAAU,YAAY;AACtD;AAEA,SAAS,qBAAyC;CAC9C,OAAO,EAAE,OAAO,QAAQ,aAAa,QAAQ;AACjD;AAEA,SAAS,uBAAuB,OAAyB;CACrD,IAAI,OAAO,UAAU,YAAY,UAAU,MACvC,OAAO;CAGX,MAAM,cAAc;CACpB,OAAO,YAAY,SAAS,YAAY,YAAY,UAAU;AAClE"}
package/dist/cli.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const require_cli_runtime = require("./cli-runtime-BHx1nVhT.cjs");
3
+ const require_cli_runtime = require("./cli-runtime-BKwXzp9V.cjs");
4
4
  //#region src/cli.ts
5
5
  if (require.main === module) require_cli_runtime.main().catch((err) => {
6
6
  require_cli_runtime.getCliOutputSink().write({
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_cli_runtime = require("./cli-runtime-BHx1nVhT.cjs");
2
+ const require_cli_runtime = require("./cli-runtime-BKwXzp9V.cjs");
3
3
  let _open_wa_api = require("@open-wa/api");
4
4
  let node_path = require("node:path");
5
5
  let _open_wa_logger = require("@open-wa/logger");
@@ -10,10 +10,66 @@ let _open_wa_driver_lightpanda = require("@open-wa/driver-lightpanda");
10
10
  let _open_wa_driver_puppeteer = require("@open-wa/driver-puppeteer");
11
11
  let _open_wa_config = require("@open-wa/config");
12
12
  let node_fs = require("node:fs");
13
- let node_crypto = require("node:crypto");
14
- let node_os = require("node:os");
13
+ //#region src/server/lifecycle-manager.ts
14
+ var APILifecycleManager = class {
15
+ config;
16
+ server;
17
+ _sessionConnected = false;
18
+ constructor(config) {
19
+ this.config = config;
20
+ }
21
+ async initialize() {
22
+ const sink = require_cli_runtime.getCliOutputSink();
23
+ switch (this.config.apiLifecycle) {
24
+ case "immediate":
25
+ sink.status({
26
+ phase: "server.starting",
27
+ sessionId: this.config.sessionId,
28
+ detail: "Starting full API immediately"
29
+ });
30
+ await this.startFullAPI();
31
+ break;
32
+ case "post-connection":
33
+ this.waitForConnection();
34
+ break;
35
+ case "hybrid":
36
+ sink.status({
37
+ phase: "server.starting",
38
+ sessionId: this.config.sessionId,
39
+ detail: "Starting minimal API (QR only)"
40
+ });
41
+ await this.startMinimalAPI();
42
+ }
43
+ }
44
+ async waitForConnection() {
45
+ require_cli_runtime.getCliOutputSink().write({
46
+ level: "info",
47
+ message: "Waiting for session connection before starting API..."
48
+ });
49
+ }
50
+ async startFullAPI() {
51
+ require_cli_runtime.getCliOutputSink().write({
52
+ level: "info",
53
+ message: "Starting full API immediately..."
54
+ });
55
+ this.server = new require_cli_runtime.WAServer(this.config);
56
+ await this.server.start();
57
+ }
58
+ async startMinimalAPI() {
59
+ require_cli_runtime.getCliOutputSink().write({
60
+ level: "info",
61
+ message: "Starting minimal API (QR only)..."
62
+ });
63
+ this.server = new require_cli_runtime.WAServer(this.config);
64
+ await this.server.start();
65
+ }
66
+ async stop() {
67
+ if (this.server) await this.server.stop();
68
+ }
69
+ };
70
+ //#endregion
15
71
  //#region src/session/SessionArchiveManager.ts
16
- var SessionArchiveManager = class SessionArchiveManager {
72
+ var SessionArchiveManager = class {
17
73
  config;
18
74
  logger = (0, _open_wa_logger.createLogger)({ component: "SessionArchiveManager" });
19
75
  localCompression;
@@ -76,17 +132,6 @@ var SessionArchiveManager = class SessionArchiveManager {
76
132
  if (!this.s3Sync) return null;
77
133
  return this.s3Sync.getDownloadUrl(filename, expiresIn);
78
134
  }
79
- static createFromConfig(config) {
80
- if (!config.legacyDataDirAuth) throw new Error("Profile archives require legacyDataDirAuth: true; compact sessions sync through the client");
81
- if (!config.s3Sync) throw new Error("Session archive management requires s3Sync configuration");
82
- return new SessionArchiveManager({
83
- sessionId: config.sessionId,
84
- dataDir: config.userDataDir || config.sessionDataPath || "./.wwebjs",
85
- s3Config: config.s3Sync,
86
- syncInterval: config.s3Sync.syncInterval,
87
- watchLocalChanges: config.s3Sync.enableLocalCompression !== false
88
- });
89
- }
90
135
  get archivePath() {
91
136
  return (0, node_path.join)((0, node_path.dirname)(this.config.dataDir), `${this.config.sessionId}.data.zst`);
92
137
  }
@@ -101,68 +146,6 @@ var SessionArchiveManager = class SessionArchiveManager {
101
146
  }
102
147
  };
103
148
  //#endregion
104
- //#region src/server/lifecycle-manager.ts
105
- var APILifecycleManager = class {
106
- config;
107
- server;
108
- sessionArchiveManager;
109
- _sessionConnected = false;
110
- constructor(config) {
111
- this.config = config;
112
- if (config.legacyDataDirAuth && config.s3Sync) this.sessionArchiveManager = SessionArchiveManager.createFromConfig(config);
113
- }
114
- async initialize() {
115
- const sink = require_cli_runtime.getCliOutputSink();
116
- switch (this.config.apiLifecycle) {
117
- case "immediate":
118
- sink.status({
119
- phase: "server.starting",
120
- sessionId: this.config.sessionId,
121
- detail: "Starting full API immediately"
122
- });
123
- await this.startFullAPI();
124
- break;
125
- case "post-connection":
126
- this.waitForConnection();
127
- break;
128
- case "hybrid":
129
- sink.status({
130
- phase: "server.starting",
131
- sessionId: this.config.sessionId,
132
- detail: "Starting minimal API (QR only)"
133
- });
134
- await this.startMinimalAPI();
135
- }
136
- if (this.sessionArchiveManager) await this.sessionArchiveManager.start();
137
- }
138
- async waitForConnection() {
139
- require_cli_runtime.getCliOutputSink().write({
140
- level: "info",
141
- message: "Waiting for session connection before starting API..."
142
- });
143
- }
144
- async startFullAPI() {
145
- require_cli_runtime.getCliOutputSink().write({
146
- level: "info",
147
- message: "Starting full API immediately..."
148
- });
149
- this.server = new require_cli_runtime.WAServer(this.config);
150
- await this.server.start();
151
- }
152
- async startMinimalAPI() {
153
- require_cli_runtime.getCliOutputSink().write({
154
- level: "info",
155
- message: "Starting minimal API (QR only)..."
156
- });
157
- this.server = new require_cli_runtime.WAServer(this.config);
158
- await this.server.start();
159
- }
160
- async stop() {
161
- if (this.sessionArchiveManager) await this.sessionArchiveManager.stop();
162
- if (this.server) await this.server.stop();
163
- }
164
- };
165
- //#endregion
166
149
  //#region src/runtime-client.ts
167
150
  function readChromePathCache(cacheFilePath) {
168
151
  try {
@@ -266,11 +249,12 @@ function toCreateClientOptions(config, driverSelection, options = {}) {
266
249
  driver: driverSelection.driver,
267
250
  deleteSessionDataOnLogout: config.deleteSessionDataOnLogout,
268
251
  killClientOnLogout: config.killClientOnLogout,
269
- legacyDataDirAuth: config.legacyDataDirAuth,
270
252
  sessionDataPath: config.sessionDataPath,
271
253
  sessionData: config.sessionData,
272
254
  skipSessionSave: config.skipSessionSave,
273
255
  sessionDataBucketAuth: config.sessionDataBucketAuth,
256
+ sessionDataEncryptionKey: config.sessionDataEncryptionKey,
257
+ sessionDataEncryptionKeyFile: config.sessionDataEncryptionKeyFile,
274
258
  s3Sync: config.s3Sync,
275
259
  debug: options.debug ?? (config.logLevel === "debug" || config.logConsole),
276
260
  headless: config.headless,
@@ -298,26 +282,9 @@ function toCreateClientOptions(config, driverSelection, options = {}) {
298
282
  }
299
283
  };
300
284
  }
301
- /** Private profile storage, stable for this project directory and session name. */
302
- function privateSessionDirectory(sessionId) {
303
- const project = (0, node_crypto.createHash)("sha256").update((0, node_fs.realpathSync)(process.cwd())).digest("hex").slice(0, 24);
304
- const session = (0, node_crypto.createHash)("sha256").update(sessionId).digest("hex").slice(0, 24);
305
- const root = (0, node_path.resolve)((0, node_os.homedir)(), ".open-wa", "sessions");
306
- const directory = (0, node_path.resolve)(root, project, session);
307
- (0, node_fs.mkdirSync)(directory, {
308
- recursive: true,
309
- mode: 448
310
- });
311
- for (const path of [
312
- root,
313
- (0, node_path.dirname)(directory),
314
- directory
315
- ]) (0, node_fs.chmodSync)(path, 448);
316
- return directory;
317
- }
318
285
  /** Start WhatsApp, display QR login when needed, and return a ready messaging client. */
319
286
  async function create(options = {}) {
320
- const { driver, sessionData, sessionDataBucketAuth, s3Sync, ...configOverrides } = options;
287
+ const { driver, sessionData, sessionDataBucketAuth, s3Sync, sessionDataEncryptionKey, sessionDataEncryptionKeyFile, ...configOverrides } = options;
321
288
  const { config, rawConfigs } = await (0, _open_wa_config.resolveConfig)({
322
289
  programmaticOverrides: {
323
290
  qrTimeout: 0,
@@ -335,11 +302,9 @@ async function create(options = {}) {
335
302
  if (driver) coreOptions.driver = driver;
336
303
  coreOptions.sessionData = sessionData;
337
304
  coreOptions.sessionDataBucketAuth = sessionDataBucketAuth;
305
+ coreOptions.sessionDataEncryptionKey = sessionDataEncryptionKey;
306
+ coreOptions.sessionDataEncryptionKeyFile = sessionDataEncryptionKeyFile;
338
307
  coreOptions.s3Sync = s3Sync;
339
- if (config.legacyDataDirAuth && !config.ephemeral && configOverrides.userDataDir === void 0 && configOverrides.sessionDataPath === void 0) {
340
- coreOptions.userDataDir = privateSessionDirectory(config.sessionId);
341
- coreOptions.sessionDataPath = coreOptions.userDataDir;
342
- }
343
308
  const core = await (0, _open_wa_core.createClient)(coreOptions);
344
309
  const sink = require_cli_runtime.getCliOutputSink();
345
310
  const onQr = (event) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["createLogger","LocalSessionCompression","S3SyncManager","join","dirname","getCliOutputSink","WAServer","existsSync","readFileSync","dirname","LightpandaDriver","PuppeteerDriver","createHash","realpathSync","resolve","homedir","resolveConfig","createCoreClient","getCliOutputSink","Client"],"sources":["../src/session/SessionArchiveManager.ts","../src/server/lifecycle-manager.ts","../src/runtime-client.ts"],"sourcesContent":["import { dirname, join } from 'node:path';\nimport type { Config } from '@open-wa/config';\nimport { createLogger } from '@open-wa/logger';\nimport { LocalSessionCompression, S3SyncManager, type S3Config } from '@open-wa/session-sync';\n\nexport interface SessionArchiveManagerConfig {\n sessionId: string;\n dataDir: string;\n s3Config: S3Config;\n syncInterval?: number;\n watchLocalChanges?: boolean;\n}\n\nexport class SessionArchiveManager {\n private readonly logger = createLogger({ component: 'SessionArchiveManager' });\n private localCompression?: LocalSessionCompression;\n private s3Sync?: S3SyncManager;\n private syncTimer?: NodeJS.Timeout;\n private started = false;\n\n constructor(private readonly config: SessionArchiveManagerConfig) {\n this.logger.info('session_archive_manager_initialized', { sessionId: config.sessionId });\n }\n\n async start(): Promise<void> {\n if (this.started) return;\n this.started = true;\n\n this.localCompression = new LocalSessionCompression({\n sessionPath: this.config.dataDir,\n sessionId: this.config.sessionId,\n outputPath: this.archivePath,\n intervalMs: this.config.syncInterval,\n });\n if (this.config.watchLocalChanges !== false) {\n this.localCompression.start();\n this.logger.info('local_session_compression_started');\n }\n\n this.s3Sync = new S3SyncManager(this.config.s3Config);\n this.startPeriodicSync();\n this.logger.info('s3_session_sync_started');\n }\n\n async stop(): Promise<void> {\n if (this.syncTimer) {\n clearInterval(this.syncTimer);\n this.syncTimer = undefined;\n }\n\n this.localCompression?.stop();\n this.localCompression = undefined;\n this.s3Sync = undefined;\n this.started = false;\n this.logger.info('session_archive_manager_stopped');\n }\n\n async backupSession(): Promise<string | null> {\n if (!this.s3Sync || !this.localCompression) {\n this.logger.warn('session_archive_manager_not_started');\n return null;\n }\n\n try {\n await this.localCompression.compress();\n const filename = await this.s3Sync.backupSession(this.archivePath);\n this.logger.info('session_backed_up', { filename });\n return filename;\n } catch (error) {\n this.logger.error('session_backup_failed', { error });\n throw error;\n }\n }\n\n async restoreSession(filename: string): Promise<void> {\n if (!this.s3Sync) {\n throw new Error('Session archive manager is not started');\n }\n\n const restored = await this.s3Sync.restoreSession(filename, this.config.dataDir);\n if (!restored) {\n throw new Error(`Failed to restore session backup: ${filename}`);\n }\n this.logger.info('session_restored', { filename });\n }\n\n async getSessionBackupUrl(filename: string, expiresIn = 3600): Promise<string | null> {\n if (!this.s3Sync) {\n return null;\n }\n\n return this.s3Sync.getDownloadUrl(filename, expiresIn);\n }\n\n static createFromConfig(config: Config): SessionArchiveManager {\n if (!config.legacyDataDirAuth) {\n throw new Error('Profile archives require legacyDataDirAuth: true; compact sessions sync through the client');\n }\n if (!config.s3Sync) {\n throw new Error('Session archive management requires s3Sync configuration');\n }\n\n return new SessionArchiveManager({\n sessionId: config.sessionId,\n dataDir: config.userDataDir || config.sessionDataPath || './.wwebjs',\n s3Config: config.s3Sync,\n syncInterval: config.s3Sync.syncInterval,\n watchLocalChanges: config.s3Sync.enableLocalCompression !== false,\n });\n }\n\n private get archivePath(): string {\n return join(dirname(this.config.dataDir), `${this.config.sessionId}.data.zst`);\n }\n\n private startPeriodicSync(): void {\n if (!this.s3Sync || this.syncTimer) return;\n\n this.syncTimer = setInterval(() => {\n void this.backupSession().catch((error) => {\n this.logger.error('periodic_session_sync_failed', { error });\n });\n }, this.config.syncInterval ?? 600_000);\n this.syncTimer.unref();\n }\n}\n","import { WAServer } from './hono-server';\nimport type { Config } from '@open-wa/config';\nimport { SessionArchiveManager } from '../session/SessionArchiveManager';\nimport { getCliOutputSink } from '../cli/output-sink';\n\nexport class APILifecycleManager {\n private config: Config;\n private server?: WAServer;\n private sessionArchiveManager?: SessionArchiveManager;\n // @ts-ignore\n private _sessionConnected: boolean = false;\n\n constructor(config: Config) {\n this.config = config;\n \n // Compact checkpoints are synced by the client; profile archives are legacy-only.\n if (config.legacyDataDirAuth && config.s3Sync) {\n this.sessionArchiveManager = SessionArchiveManager.createFromConfig(config);\n }\n }\n\n public async initialize(): Promise<void> {\n const sink = getCliOutputSink();\n switch (this.config.apiLifecycle) {\n case 'immediate':\n sink.status({ phase: 'server.starting', sessionId: this.config.sessionId, detail: 'Starting full API immediately' });\n await this.startFullAPI();\n break;\n case 'post-connection':\n this.waitForConnection();\n break;\n case 'hybrid':\n sink.status({ phase: 'server.starting', sessionId: this.config.sessionId, detail: 'Starting minimal API (QR only)' });\n await this.startMinimalAPI();\n break;\n }\n \n // Start session manager after all other initialization\n if (this.sessionArchiveManager) {\n await this.sessionArchiveManager.start();\n }\n }\n\n private async waitForConnection(): Promise<void> {\n getCliOutputSink().write({ level: 'info', message: 'Waiting for session connection before starting API...' });\n // This will be called by the orchestrator or main entry point when session connects\n }\n\n private async startFullAPI(): Promise<void> {\n getCliOutputSink().write({ level: 'info', message: 'Starting full API immediately...' });\n this.server = new WAServer(this.config);\n await this.server.start();\n }\n\n private async startMinimalAPI(): Promise<void> {\n getCliOutputSink().write({ level: 'info', message: 'Starting minimal API (QR only)...' });\n \n // Create server with full config but we might restrict routes in the future\n // For now, hybrid mode just starts the server, but logic inside routes (like sendText)\n // should check if session is connected before execution.\n // In a more advanced implementation, we would only register public routes here.\n \n this.server = new WAServer(this.config);\n await this.server.start();\n }\n \n public async stop(): Promise<void> {\n // Stop session manager first\n if (this.sessionArchiveManager) {\n await this.sessionArchiveManager.stop();\n }\n \n // Then stop server\n if (this.server) {\n await this.server.stop();\n }\n }\n}\n","import { createClient as createCoreClient, type CreateClientOptions, type OpenWAEventMap } from '@open-wa/core';\nimport { Client } from '@open-wa/client';\nimport { resolveConfig, type PartialConfig, type Config, type TrackedConfig } from '@open-wa/config';\nimport { LightpandaDriver } from '@open-wa/driver-lightpanda';\nimport { PuppeteerDriver } from '@open-wa/driver-puppeteer';\nimport { chmodSync, existsSync, mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { homedir } from 'node:os';\nimport { dirname, resolve } from 'node:path';\nimport { getCliOutputSink } from './cli/output-sink';\n\nexport interface ExecutablePathResolution {\n executablePath?: string;\n source:\n | 'config'\n | 'cache'\n | 'chrome_installation'\n | 'driver_default'\n | 'lightpanda_config'\n | 'lightpanda_sdk_default';\n warning?: string;\n}\n\nexport interface DriverSelection {\n driver: PuppeteerDriver | LightpandaDriver;\n engineLabel: 'Puppeteer' | 'Lightpanda';\n executableResolution: ExecutablePathResolution;\n preferLocalChrome: boolean;\n}\n\nfunction readChromePathCache(cacheFilePath: string): { executablePath?: string } | undefined {\n try {\n if (!existsSync(cacheFilePath)) {\n return undefined;\n }\n\n const raw = JSON.parse(readFileSync(cacheFilePath, 'utf8')) as { executablePath?: string };\n if (!raw || typeof raw !== 'object') {\n return undefined;\n }\n\n return {\n executablePath: typeof raw.executablePath === 'string' ? raw.executablePath : undefined,\n };\n } catch {\n return undefined;\n }\n}\n\nfunction writeChromePathCache(executablePath: string, cacheFilePath: string): void {\n mkdirSync(dirname(cacheFilePath), { recursive: true });\n writeFileSync(cacheFilePath, JSON.stringify({ executablePath, updatedAt: new Date().toISOString() }, null, 2), 'utf8');\n}\n\nfunction clearChromePathCache(cacheFilePath: string): void {\n if (existsSync(cacheFilePath)) {\n rmSync(cacheFilePath, { force: true });\n }\n}\n\nfunction isUsableExecutablePath(executablePath?: string): executablePath is string {\n return !!executablePath && existsSync(executablePath);\n}\n\nfunction getExplicitUseChromePreference(rawConfigs?: TrackedConfig['rawConfigs']): boolean | undefined {\n const explicitConfigSources = [\n rawConfigs?.file,\n rawConfigs?.env,\n rawConfigs?.cli,\n rawConfigs?.programmatic,\n ];\n\n for (let index = explicitConfigSources.length - 1; index >= 0; index -= 1) {\n const source = explicitConfigSources[index];\n if (source?.useChrome !== undefined) {\n return source.useChrome;\n }\n }\n\n return undefined;\n}\n\nexport function shouldPreferLocalChrome(\n config: Config,\n rawConfigs?: TrackedConfig['rawConfigs'],\n defaultPreference = true,\n): boolean {\n if (config.useLightpanda) {\n return false;\n }\n\n if (config.executablePath) {\n return false;\n }\n\n const explicitUseChrome = getExplicitUseChromePreference(rawConfigs);\n if (explicitUseChrome !== undefined) {\n return explicitUseChrome;\n }\n\n return defaultPreference;\n}\n\nexport async function resolveExecutablePath(\n config: Config,\n options: {\n preferLocalChrome?: boolean;\n cacheFilePath: string;\n }\n): Promise<ExecutablePathResolution> {\n if (config.executablePath) {\n return {\n executablePath: config.executablePath,\n source: 'config',\n };\n }\n\n const preferLocalChrome = options.preferLocalChrome ?? config.useChrome;\n if (!preferLocalChrome) {\n return {\n source: 'driver_default',\n };\n }\n\n const cachedPath = readChromePathCache(options.cacheFilePath)?.executablePath;\n if (isUsableExecutablePath(cachedPath)) {\n return {\n executablePath: cachedPath,\n source: 'cache',\n };\n }\n\n if (cachedPath) {\n clearChromePathCache(options.cacheFilePath);\n }\n\n const { Launcher } = await import('chrome-launcher');\n const detectedPath = Launcher.getInstallations().find((installationPath) => isUsableExecutablePath(installationPath));\n\n if (detectedPath) {\n writeChromePathCache(detectedPath, options.cacheFilePath);\n return {\n executablePath: detectedPath,\n source: 'chrome_installation',\n };\n }\n\n clearChromePathCache(options.cacheFilePath);\n\n return {\n source: 'driver_default',\n warning: 'Chrome resolution warning: no valid local Chrome installation was found. Falling back to Puppeteer/default driver browser resolution.',\n };\n}\n\nexport function resolveLightpandaExecutablePath(config: Config): ExecutablePathResolution {\n const executablePath = config.lightpanda?.executablePath;\n if (executablePath) {\n return {\n executablePath,\n source: 'lightpanda_config',\n };\n }\n\n return {\n source: 'lightpanda_sdk_default',\n };\n}\n\nexport async function selectRuntimeDriver(\n config: Config,\n options: {\n rawConfigs?: TrackedConfig['rawConfigs'];\n cacheFilePath: string;\n defaultPreferLocalChrome?: boolean;\n }\n): Promise<DriverSelection> {\n if (config.useLightpanda) {\n return {\n driver: new LightpandaDriver(),\n engineLabel: 'Lightpanda',\n executableResolution: resolveLightpandaExecutablePath(config),\n preferLocalChrome: false,\n };\n }\n\n const preferLocalChrome = shouldPreferLocalChrome(config, options.rawConfigs, options.defaultPreferLocalChrome ?? true);\n const executableResolution = await resolveExecutablePath(config, {\n preferLocalChrome,\n cacheFilePath: options.cacheFilePath,\n });\n\n return {\n driver: new PuppeteerDriver(),\n engineLabel: 'Puppeteer',\n executableResolution,\n preferLocalChrome,\n };\n}\n\nexport function toCreateClientOptions(\n config: Config,\n driverSelection: DriverSelection,\n options: {\n debug?: boolean;\n } = {},\n): CreateClientOptions {\n return {\n sessionId: config.sessionId,\n driver: driverSelection.driver,\n deleteSessionDataOnLogout: config.deleteSessionDataOnLogout,\n killClientOnLogout: config.killClientOnLogout,\n legacyDataDirAuth: config.legacyDataDirAuth,\n sessionDataPath: config.sessionDataPath,\n sessionData: config.sessionData,\n skipSessionSave: config.skipSessionSave,\n sessionDataBucketAuth: config.sessionDataBucketAuth,\n s3Sync: config.s3Sync,\n debug: options.debug ?? (config.logLevel === 'debug' || config.logConsole),\n headless: config.headless,\n qrTimeoutMs: typeof config.qrTimeout === 'number' ? config.qrTimeout * 1000 : undefined,\n authTimeoutMs: typeof config.authTimeout === 'number' ? config.authTimeout * 1000 : undefined,\n executablePath: driverSelection.executableResolution.executablePath,\n browserArgs: config.chromiumArgs,\n browser: config.browser,\n allowDangerousBrowserArgs: config.allowDangerousBrowserArgs,\n userDataDir: config.userDataDir,\n ephemeral: config.ephemeral,\n linkCode: config.linkCode,\n qrMax: config.qrMax,\n oorTimeoutMs: config.oorTimeout * 1000,\n logConsole: config.logConsole,\n logConsoleErrors: config.logConsoleErrors,\n blockCrashLogs: config.blockCrashLogs,\n blockAssets: config.blockAssets,\n safeMode: config.safeMode,\n lightpanda: config.useLightpanda ? config.lightpanda : undefined,\n licenseKey: config.licenseKey as any,\n patchConfig: { ghPatch: config.ghPatch, cachedPatch: config.cachedPatch },\n };\n}\n\n/** Options for the ready-to-use messaging client. */\nexport type CreateOptions = Omit<PartialConfig, 's3Sync'> & {\n s3Sync?: Omit<NonNullable<PartialConfig['s3Sync']>, 'region' | 'syncInterval'> & {\n region?: string;\n syncInterval?: number;\n };\n /** Override the default Puppeteer driver. */\n driver?: CreateClientOptions['driver'];\n};\n\n/** Private profile storage, stable for this project directory and session name. */\nfunction privateSessionDirectory(sessionId: string): string {\n const project = createHash('sha256').update(realpathSync(process.cwd())).digest('hex').slice(0, 24);\n const session = createHash('sha256').update(sessionId).digest('hex').slice(0, 24);\n const root = resolve(homedir(), '.open-wa', 'sessions');\n const directory = resolve(root, project, session);\n mkdirSync(directory, { recursive: true, mode: 0o700 });\n // Protect existing directories too; Chromium stores authentication here.\n for (const path of [root, dirname(directory), directory]) chmodSync(path, 0o700);\n return directory;\n}\n\n/** Start WhatsApp, display QR login when needed, and return a ready messaging client. */\nexport async function create(options: CreateOptions = {}): Promise<Client> {\n const { driver, sessionData, sessionDataBucketAuth, s3Sync, ...configOverrides } = options;\n const { config, rawConfigs } = await resolveConfig({\n programmaticOverrides: {\n qrTimeout: 0, ...configOverrides,\n // Session seeds and bucket credentials bypass tracked/debug config.\n },\n skipConfigFile: true,\n skipEnv: true,\n includeRawConfigs: true,\n });\n\n const driverSelection = await selectRuntimeDriver(config, {\n rawConfigs,\n cacheFilePath: resolve(process.cwd(), '.open-wa', 'chrome-executable-path.json'),\n defaultPreferLocalChrome: false,\n });\n\n const coreOptions = toCreateClientOptions(config, driverSelection);\n if (driver) coreOptions.driver = driver;\n coreOptions.sessionData = sessionData;\n coreOptions.sessionDataBucketAuth = sessionDataBucketAuth;\n coreOptions.s3Sync = s3Sync;\n if (config.legacyDataDirAuth && !config.ephemeral && configOverrides.userDataDir === undefined && configOverrides.sessionDataPath === undefined) {\n coreOptions.userDataDir = privateSessionDirectory(config.sessionId);\n coreOptions.sessionDataPath = coreOptions.userDataDir;\n }\n\n const core = await createCoreClient(coreOptions);\n const sink = getCliOutputSink();\n const onQr = (event: OpenWAEventMap['launch.auth.qr.generated']) => {\n if (config.qrLogSkip || !event.details?.qr) return;\n sink.write({ level: 'info', message: 'Open WhatsApp on your sending phone: Linked Devices → Link a Device, then scan this QR code.' });\n sink.qr({ qr: event.details.qr, sessionId: config.sessionId });\n };\n const onLinkCode = (event: OpenWAEventMap['launch.auth.linkCode.generated']) => {\n if (event.details?.linkCode && !config.qrLogSkip) {\n sink.write({ level: 'info', message: `Enter this link code on your sending phone: ${event.details.linkCode}` });\n }\n };\n core.events.on('launch.auth.qr.generated', onQr);\n core.events.on('launch.auth.linkCode.generated', onLinkCode);\n let client: Client | undefined;\n try {\n client = new Client({ client: core, transport: core.getTransport() });\n await client.start();\n if (core.getState() !== 'READY' || !core.getReadiness().exposureSafe) {\n throw new Error('WhatsApp startup finished without a messaging-ready session.');\n }\n return client;\n } catch (error) {\n try {\n if (client) await client.stop('startup-failure');\n else await core.stop('startup-failure');\n } catch {\n // Keep the startup failure as the actionable error.\n }\n throw error;\n } finally {\n core.events.off('launch.auth.qr.generated', onQr);\n core.events.off('launch.auth.linkCode.generated', onLinkCode);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["getCliOutputSink","WAServer","createLogger","LocalSessionCompression","S3SyncManager","join","dirname","existsSync","readFileSync","dirname","LightpandaDriver","PuppeteerDriver","resolveConfig","resolve","createCoreClient","getCliOutputSink","Client"],"sources":["../src/server/lifecycle-manager.ts","../src/session/SessionArchiveManager.ts","../src/runtime-client.ts"],"sourcesContent":["import { WAServer } from './hono-server';\nimport type { Config } from '@open-wa/config';\nimport { getCliOutputSink } from '../cli/output-sink';\n\nexport class APILifecycleManager {\n private config: Config;\n private server?: WAServer;\n // @ts-ignore\n private _sessionConnected: boolean = false;\n\n constructor(config: Config) {\n this.config = config;\n }\n\n public async initialize(): Promise<void> {\n const sink = getCliOutputSink();\n switch (this.config.apiLifecycle) {\n case 'immediate':\n sink.status({ phase: 'server.starting', sessionId: this.config.sessionId, detail: 'Starting full API immediately' });\n await this.startFullAPI();\n break;\n case 'post-connection':\n this.waitForConnection();\n break;\n case 'hybrid':\n sink.status({ phase: 'server.starting', sessionId: this.config.sessionId, detail: 'Starting minimal API (QR only)' });\n await this.startMinimalAPI();\n break;\n }\n }\n\n private async waitForConnection(): Promise<void> {\n getCliOutputSink().write({ level: 'info', message: 'Waiting for session connection before starting API...' });\n // This will be called by the orchestrator or main entry point when session connects\n }\n\n private async startFullAPI(): Promise<void> {\n getCliOutputSink().write({ level: 'info', message: 'Starting full API immediately...' });\n this.server = new WAServer(this.config);\n await this.server.start();\n }\n\n private async startMinimalAPI(): Promise<void> {\n getCliOutputSink().write({ level: 'info', message: 'Starting minimal API (QR only)...' });\n \n // Create server with full config but we might restrict routes in the future\n // For now, hybrid mode just starts the server, but logic inside routes (like sendText)\n // should check if session is connected before execution.\n // In a more advanced implementation, we would only register public routes here.\n \n this.server = new WAServer(this.config);\n await this.server.start();\n }\n \n public async stop(): Promise<void> {\n if (this.server) {\n await this.server.stop();\n }\n }\n}\n","import { dirname, join } from 'node:path';\nimport { createLogger } from '@open-wa/logger';\nimport { LocalSessionCompression, S3SyncManager, type S3Config } from '@open-wa/session-sync';\n\nexport interface SessionArchiveManagerConfig {\n sessionId: string;\n dataDir: string;\n s3Config: S3Config;\n syncInterval?: number;\n watchLocalChanges?: boolean;\n}\n\nexport class SessionArchiveManager {\n private readonly logger = createLogger({ component: 'SessionArchiveManager' });\n private localCompression?: LocalSessionCompression;\n private s3Sync?: S3SyncManager;\n private syncTimer?: NodeJS.Timeout;\n private started = false;\n\n constructor(private readonly config: SessionArchiveManagerConfig) {\n this.logger.info('session_archive_manager_initialized', { sessionId: config.sessionId });\n }\n\n async start(): Promise<void> {\n if (this.started) return;\n this.started = true;\n\n this.localCompression = new LocalSessionCompression({\n sessionPath: this.config.dataDir,\n sessionId: this.config.sessionId,\n outputPath: this.archivePath,\n intervalMs: this.config.syncInterval,\n });\n if (this.config.watchLocalChanges !== false) {\n this.localCompression.start();\n this.logger.info('local_session_compression_started');\n }\n\n this.s3Sync = new S3SyncManager(this.config.s3Config);\n this.startPeriodicSync();\n this.logger.info('s3_session_sync_started');\n }\n\n async stop(): Promise<void> {\n if (this.syncTimer) {\n clearInterval(this.syncTimer);\n this.syncTimer = undefined;\n }\n\n this.localCompression?.stop();\n this.localCompression = undefined;\n this.s3Sync = undefined;\n this.started = false;\n this.logger.info('session_archive_manager_stopped');\n }\n\n async backupSession(): Promise<string | null> {\n if (!this.s3Sync || !this.localCompression) {\n this.logger.warn('session_archive_manager_not_started');\n return null;\n }\n\n try {\n await this.localCompression.compress();\n const filename = await this.s3Sync.backupSession(this.archivePath);\n this.logger.info('session_backed_up', { filename });\n return filename;\n } catch (error) {\n this.logger.error('session_backup_failed', { error });\n throw error;\n }\n }\n\n async restoreSession(filename: string): Promise<void> {\n if (!this.s3Sync) {\n throw new Error('Session archive manager is not started');\n }\n\n const restored = await this.s3Sync.restoreSession(filename, this.config.dataDir);\n if (!restored) {\n throw new Error(`Failed to restore session backup: ${filename}`);\n }\n this.logger.info('session_restored', { filename });\n }\n\n async getSessionBackupUrl(filename: string, expiresIn = 3600): Promise<string | null> {\n if (!this.s3Sync) {\n return null;\n }\n\n return this.s3Sync.getDownloadUrl(filename, expiresIn);\n }\n\n private get archivePath(): string {\n return join(dirname(this.config.dataDir), `${this.config.sessionId}.data.zst`);\n }\n\n private startPeriodicSync(): void {\n if (!this.s3Sync || this.syncTimer) return;\n\n this.syncTimer = setInterval(() => {\n void this.backupSession().catch((error) => {\n this.logger.error('periodic_session_sync_failed', { error });\n });\n }, this.config.syncInterval ?? 600_000);\n this.syncTimer.unref();\n }\n}\n","import { createClient as createCoreClient, type CreateClientOptions, type OpenWAEventMap } from '@open-wa/core';\nimport { Client } from '@open-wa/client';\nimport { resolveConfig, type PartialConfig, type Config, type TrackedConfig } from '@open-wa/config';\nimport { LightpandaDriver } from '@open-wa/driver-lightpanda';\nimport { PuppeteerDriver } from '@open-wa/driver-puppeteer';\nimport { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { getCliOutputSink } from './cli/output-sink';\n\nexport interface ExecutablePathResolution {\n executablePath?: string;\n source:\n | 'config'\n | 'cache'\n | 'chrome_installation'\n | 'driver_default'\n | 'lightpanda_config'\n | 'lightpanda_sdk_default';\n warning?: string;\n}\n\nexport interface DriverSelection {\n driver: PuppeteerDriver | LightpandaDriver;\n engineLabel: 'Puppeteer' | 'Lightpanda';\n executableResolution: ExecutablePathResolution;\n preferLocalChrome: boolean;\n}\n\nfunction readChromePathCache(cacheFilePath: string): { executablePath?: string } | undefined {\n try {\n if (!existsSync(cacheFilePath)) {\n return undefined;\n }\n\n const raw = JSON.parse(readFileSync(cacheFilePath, 'utf8')) as { executablePath?: string };\n if (!raw || typeof raw !== 'object') {\n return undefined;\n }\n\n return {\n executablePath: typeof raw.executablePath === 'string' ? raw.executablePath : undefined,\n };\n } catch {\n return undefined;\n }\n}\n\nfunction writeChromePathCache(executablePath: string, cacheFilePath: string): void {\n mkdirSync(dirname(cacheFilePath), { recursive: true });\n writeFileSync(cacheFilePath, JSON.stringify({ executablePath, updatedAt: new Date().toISOString() }, null, 2), 'utf8');\n}\n\nfunction clearChromePathCache(cacheFilePath: string): void {\n if (existsSync(cacheFilePath)) {\n rmSync(cacheFilePath, { force: true });\n }\n}\n\nfunction isUsableExecutablePath(executablePath?: string): executablePath is string {\n return !!executablePath && existsSync(executablePath);\n}\n\nfunction getExplicitUseChromePreference(rawConfigs?: TrackedConfig['rawConfigs']): boolean | undefined {\n const explicitConfigSources = [\n rawConfigs?.file,\n rawConfigs?.env,\n rawConfigs?.cli,\n rawConfigs?.programmatic,\n ];\n\n for (let index = explicitConfigSources.length - 1; index >= 0; index -= 1) {\n const source = explicitConfigSources[index];\n if (source?.useChrome !== undefined) {\n return source.useChrome;\n }\n }\n\n return undefined;\n}\n\nexport function shouldPreferLocalChrome(\n config: Config,\n rawConfigs?: TrackedConfig['rawConfigs'],\n defaultPreference = true,\n): boolean {\n if (config.useLightpanda) {\n return false;\n }\n\n if (config.executablePath) {\n return false;\n }\n\n const explicitUseChrome = getExplicitUseChromePreference(rawConfigs);\n if (explicitUseChrome !== undefined) {\n return explicitUseChrome;\n }\n\n return defaultPreference;\n}\n\nexport async function resolveExecutablePath(\n config: Config,\n options: {\n preferLocalChrome?: boolean;\n cacheFilePath: string;\n }\n): Promise<ExecutablePathResolution> {\n if (config.executablePath) {\n return {\n executablePath: config.executablePath,\n source: 'config',\n };\n }\n\n const preferLocalChrome = options.preferLocalChrome ?? config.useChrome;\n if (!preferLocalChrome) {\n return {\n source: 'driver_default',\n };\n }\n\n const cachedPath = readChromePathCache(options.cacheFilePath)?.executablePath;\n if (isUsableExecutablePath(cachedPath)) {\n return {\n executablePath: cachedPath,\n source: 'cache',\n };\n }\n\n if (cachedPath) {\n clearChromePathCache(options.cacheFilePath);\n }\n\n const { Launcher } = await import('chrome-launcher');\n const detectedPath = Launcher.getInstallations().find((installationPath) => isUsableExecutablePath(installationPath));\n\n if (detectedPath) {\n writeChromePathCache(detectedPath, options.cacheFilePath);\n return {\n executablePath: detectedPath,\n source: 'chrome_installation',\n };\n }\n\n clearChromePathCache(options.cacheFilePath);\n\n return {\n source: 'driver_default',\n warning: 'Chrome resolution warning: no valid local Chrome installation was found. Falling back to Puppeteer/default driver browser resolution.',\n };\n}\n\nexport function resolveLightpandaExecutablePath(config: Config): ExecutablePathResolution {\n const executablePath = config.lightpanda?.executablePath;\n if (executablePath) {\n return {\n executablePath,\n source: 'lightpanda_config',\n };\n }\n\n return {\n source: 'lightpanda_sdk_default',\n };\n}\n\nexport async function selectRuntimeDriver(\n config: Config,\n options: {\n rawConfigs?: TrackedConfig['rawConfigs'];\n cacheFilePath: string;\n defaultPreferLocalChrome?: boolean;\n }\n): Promise<DriverSelection> {\n if (config.useLightpanda) {\n return {\n driver: new LightpandaDriver(),\n engineLabel: 'Lightpanda',\n executableResolution: resolveLightpandaExecutablePath(config),\n preferLocalChrome: false,\n };\n }\n\n const preferLocalChrome = shouldPreferLocalChrome(config, options.rawConfigs, options.defaultPreferLocalChrome ?? true);\n const executableResolution = await resolveExecutablePath(config, {\n preferLocalChrome,\n cacheFilePath: options.cacheFilePath,\n });\n\n return {\n driver: new PuppeteerDriver(),\n engineLabel: 'Puppeteer',\n executableResolution,\n preferLocalChrome,\n };\n}\n\nexport function toCreateClientOptions(\n config: Config,\n driverSelection: DriverSelection,\n options: {\n debug?: boolean;\n } = {},\n): CreateClientOptions {\n return {\n sessionId: config.sessionId,\n driver: driverSelection.driver,\n deleteSessionDataOnLogout: config.deleteSessionDataOnLogout,\n killClientOnLogout: config.killClientOnLogout,\n sessionDataPath: config.sessionDataPath,\n sessionData: config.sessionData,\n skipSessionSave: config.skipSessionSave,\n sessionDataBucketAuth: config.sessionDataBucketAuth,\n sessionDataEncryptionKey: config.sessionDataEncryptionKey,\n sessionDataEncryptionKeyFile: config.sessionDataEncryptionKeyFile,\n s3Sync: config.s3Sync,\n debug: options.debug ?? (config.logLevel === 'debug' || config.logConsole),\n headless: config.headless,\n qrTimeoutMs: typeof config.qrTimeout === 'number' ? config.qrTimeout * 1000 : undefined,\n authTimeoutMs: typeof config.authTimeout === 'number' ? config.authTimeout * 1000 : undefined,\n executablePath: driverSelection.executableResolution.executablePath,\n browserArgs: config.chromiumArgs,\n browser: config.browser,\n allowDangerousBrowserArgs: config.allowDangerousBrowserArgs,\n userDataDir: config.userDataDir,\n ephemeral: config.ephemeral,\n linkCode: config.linkCode,\n qrMax: config.qrMax,\n oorTimeoutMs: config.oorTimeout * 1000,\n logConsole: config.logConsole,\n logConsoleErrors: config.logConsoleErrors,\n blockCrashLogs: config.blockCrashLogs,\n blockAssets: config.blockAssets,\n safeMode: config.safeMode,\n lightpanda: config.useLightpanda ? config.lightpanda : undefined,\n licenseKey: config.licenseKey as any,\n patchConfig: { ghPatch: config.ghPatch, cachedPatch: config.cachedPatch },\n };\n}\n\n/** Options for the ready-to-use messaging client. */\nexport type CreateOptions = Omit<PartialConfig, 's3Sync'> & {\n s3Sync?: Omit<NonNullable<PartialConfig['s3Sync']>, 'region' | 'syncInterval'> & {\n region?: string;\n syncInterval?: number;\n };\n /** Override the default Puppeteer driver. */\n driver?: CreateClientOptions['driver'];\n};\n\n/** Start WhatsApp, display QR login when needed, and return a ready messaging client. */\nexport async function create(options: CreateOptions = {}): Promise<Client> {\n const { driver, sessionData, sessionDataBucketAuth, s3Sync,\n sessionDataEncryptionKey, sessionDataEncryptionKeyFile, ...configOverrides } = options;\n const { config, rawConfigs } = await resolveConfig({\n programmaticOverrides: {\n qrTimeout: 0, ...configOverrides,\n // Session seeds, encryption keys and bucket credentials bypass tracked/debug config.\n },\n skipConfigFile: true,\n skipEnv: true,\n includeRawConfigs: true,\n });\n\n const driverSelection = await selectRuntimeDriver(config, {\n rawConfigs,\n cacheFilePath: resolve(process.cwd(), '.open-wa', 'chrome-executable-path.json'),\n defaultPreferLocalChrome: false,\n });\n\n const coreOptions = toCreateClientOptions(config, driverSelection);\n if (driver) coreOptions.driver = driver;\n coreOptions.sessionData = sessionData;\n coreOptions.sessionDataBucketAuth = sessionDataBucketAuth;\n coreOptions.sessionDataEncryptionKey = sessionDataEncryptionKey;\n coreOptions.sessionDataEncryptionKeyFile = sessionDataEncryptionKeyFile;\n coreOptions.s3Sync = s3Sync;\n\n const core = await createCoreClient(coreOptions);\n const sink = getCliOutputSink();\n const onQr = (event: OpenWAEventMap['launch.auth.qr.generated']) => {\n if (config.qrLogSkip || !event.details?.qr) return;\n sink.write({ level: 'info', message: 'Open WhatsApp on your sending phone: Linked Devices → Link a Device, then scan this QR code.' });\n sink.qr({ qr: event.details.qr, sessionId: config.sessionId });\n };\n const onLinkCode = (event: OpenWAEventMap['launch.auth.linkCode.generated']) => {\n if (event.details?.linkCode && !config.qrLogSkip) {\n sink.write({ level: 'info', message: `Enter this link code on your sending phone: ${event.details.linkCode}` });\n }\n };\n core.events.on('launch.auth.qr.generated', onQr);\n core.events.on('launch.auth.linkCode.generated', onLinkCode);\n let client: Client | undefined;\n try {\n client = new Client({ client: core, transport: core.getTransport() });\n await client.start();\n if (core.getState() !== 'READY' || !core.getReadiness().exposureSafe) {\n throw new Error('WhatsApp startup finished without a messaging-ready session.');\n }\n return client;\n } catch (error) {\n try {\n if (client) await client.stop('startup-failure');\n else await core.stop('startup-failure');\n } catch {\n // Keep the startup failure as the actionable error.\n }\n throw error;\n } finally {\n core.events.off('launch.auth.qr.generated', onQr);\n core.events.off('launch.auth.linkCode.generated', onLinkCode);\n }\n}\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -11,7 +11,6 @@ export * from "@open-wa/client";
11
11
  export declare class APILifecycleManager {
12
12
  private config;
13
13
  private server?;
14
- private sessionArchiveManager?;
15
14
  private _sessionConnected;
16
15
  constructor(config: Config$1);
17
16
  initialize(): Promise<void>;
@@ -42,7 +41,6 @@ export declare class SessionArchiveManager {
42
41
  backupSession(): Promise<string | null>;
43
42
  restoreSession(filename: string): Promise<void>;
44
43
  getSessionBackupUrl(filename: string, expiresIn?: number): Promise<string | null>;
45
- static createFromConfig(config: Config$1): SessionArchiveManager;
46
44
  private get archivePath();
47
45
  private startPeriodicSync;
48
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":["Config","Config","CreateClientOptions"],"sources":["../src/server/lifecycle-manager.ts","../src/session/SessionArchiveManager.ts","../src/cli/output-sink.ts","../src/runtime-client.ts"],"mappings":";;;;;;;;;;qBAKa;UACD;UACA;UACA;UAEA;EAER,YAAY,QAAQA;EASP,cAAc;UAsBb;UAKA;UAMA;EAYD,QAAQ;;;;UC7DR;EACb;EACA;EACA,UAAU;EACV;EACA;;qBAGS;mBAOoB;mBANZ;UACT;UACA;UACA;UACA;EAER,YAA6B,QAAQ;EAI/B,SAAS;EAoBT,QAAQ;EAaR,iBAAiB;EAiBjB,eAAe,mBAAmB;EAYlC,oBAAoB,kBAAkB,qBAAmB;SAQxD,iBAAiB,QAAQC,WAAS;cAiB7B;UAIJ;;;;KCjHA;UAEK;EACf,OAAO;EACP;EACA,OAAO;;UAGQ;EACf;EAgBA;EACA;;UAGe;EACf;EACA;;UAGe;EACf,MAAM,OAAO;EACb,OAAO,QAAQ;EACf,GAAG,SAAS;;wBAiBE,2BAA2B;wBAkB3B,oBAAoB;wBAIpB,iBAAiB,MAAM;wBAIvB;;;KCiKJ,gBAAgB,KAAK;EAC7B,SAAS,KAAK,YAAY;IACtB;IACA;;EAGJ,SAASC;;wBAgBS,OAAO,UAAS,gBAAqB,QAAQ"}
1
+ {"version":3,"file":"index.d.cts","names":["Config","CreateClientOptions"],"sources":["../src/server/lifecycle-manager.ts","../src/session/SessionArchiveManager.ts","../src/cli/output-sink.ts","../src/runtime-client.ts"],"mappings":";;;;;;;;;;qBAIa;UACD;UACA;UAEA;EAER,YAAY,QAAQA;EAIP,cAAc;UAiBb;UAKA;UAMA;EAYD,QAAQ;;;;UClDR;EACb;EACA;EACA,UAAU;EACV;EACA;;qBAGS;mBAOoB;mBANZ;UACT;UACA;UACA;UACA;EAER,YAA6B,QAAQ;EAI/B,SAAS;EAoBT,QAAQ;EAaR,iBAAiB;EAiBjB,eAAe,mBAAmB;EAYlC,oBAAoB,kBAAkB,qBAAmB;cAQnD;UAIJ;;;;KC/FA;UAEK;EACf,OAAO;EACP;EACA,OAAO;;UAGQ;EACf;EAgBA;EACA;;UAGe;EACf;EACA;;UAGe;EACf,MAAM,OAAO;EACb,OAAO,QAAQ;EACf,GAAG,SAAS;;wBAiBE,2BAA2B;wBAkB3B,oBAAoB;wBAIpB,iBAAiB,MAAM;wBAIvB;;;KCgKJ,gBAAgB,KAAK;EAC7B,SAAS,KAAK,YAAY;IACtB;IACA;;EAGJ,SAASC;;wBAIS,OAAO,UAAS,gBAAqB,QAAQ"}
@@ -1,9 +1,9 @@
1
- const require_cli_runtime = require("./cli-runtime-BHx1nVhT.cjs");
1
+ const require_cli_runtime = require("./cli-runtime-BKwXzp9V.cjs");
2
2
  let node_path = require("node:path");
3
3
  let node_child_process = require("node:child_process");
4
4
  let node_fs_promises = require("node:fs/promises");
5
5
  //#region package.json
6
- var version = "5.3.0";
6
+ var version = "5.4.0";
7
7
  //#endregion
8
8
  //#region src/cli/init.ts
9
9
  const starter = `import { create } from '@open-wa/wa-automate';
@@ -111,4 +111,4 @@ async function initProject(args) {
111
111
  //#endregion
112
112
  exports.initProject = initProject;
113
113
 
114
- //# sourceMappingURL=init-CTh6gc8w.cjs.map
114
+ //# sourceMappingURL=init-k_0bazOu.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"init-CTh6gc8w.cjs","names":["lstat","spawn","getCliOutputSink","resolve","basename","packageJson.version","mkdir","writeFile","unlink"],"sources":["../package.json","../src/cli/init.ts"],"sourcesContent":["","import { spawn } from 'node:child_process';\nimport { lstat, mkdir, unlink, writeFile } from 'node:fs/promises';\nimport { basename, resolve } from 'node:path';\nimport packageJson from '../../package.json';\nimport { getCliOutputSink } from './output-sink';\n\nconst starter = `import { create } from '@open-wa/wa-automate';\n\nconst recipient = 'REPLACE_WITH_RECIPIENT_CHAT_ID';\nconst message = 'Hello from open-wa!';\n\n// Use an existing chat with someone expecting your message.\nif (recipient === 'REPLACE_WITH_RECIPIENT_CHAT_ID') {\n throw new Error('Set recipient to an international phone number followed by @c.us, without + or spaces.');\n}\n\nconst client = await create();\n\ntry {\n await client.sendText(recipient, message);\n console.log('Message submitted. Check the receiving chat.');\n} finally {\n await client.stop();\n}\n`;\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await lstat(path);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;\n throw error;\n }\n}\n\nasync function install(directory: string): Promise<void> {\n const command = process.versions.bun ? process.execPath : 'bun';\n await new Promise<void>((accept, reject) => {\n const child = spawn(command, ['install'], { cwd: directory, stdio: 'inherit' });\n child.once('error', () => reject(new Error('Bun is required to install this project. Install Bun from https://bun.sh, then run bun install in the generated directory.')));\n child.once('exit', (code) => code === 0\n ? accept()\n : reject(new Error('Dependency installation did not finish. The generated files are safe to keep; run bun install in the project to retry.')));\n });\n}\n\n/** Create a Bun/TypeScript application without overwriting existing files. */\nexport async function initProject(args: string[]): Promise<void> {\n const sink = getCliOutputSink();\n if (args.includes('--help') || args.includes('-h')) {\n sink.write({ level: 'info', message: 'Usage: bunx --bun @open-wa/wa-automate init <directory> [--no-install]\\nUse . for the current directory. Existing starter files are never overwritten.' });\n return;\n }\n const positional = args.filter((arg) => !arg.startsWith('-'));\n if (positional.length > 1 || args.some((arg) => arg.startsWith('-') && arg !== '--no-install')) {\n throw new Error('Usage: bunx --bun @open-wa/wa-automate init <directory> [--no-install]');\n }\n const directory = resolve(positional[0] ?? '.');\n const name = basename(directory).toLowerCase().replace(/[^a-z0-9._-]/g, '-').replace(/^[._-]+/, '') || 'my-bot';\n const json = (value: unknown) => `${JSON.stringify(value, null, 2)}\\n`;\n const files: Record<string, string> = {\n 'package.json': json({\n name, version: '0.0.0', private: true, type: 'module',\n scripts: { start: 'bun run index.ts' },\n dependencies: { '@open-wa/wa-automate': packageJson.version },\n devDependencies: { '@types/bun': 'latest' },\n }),\n 'index.ts': starter,\n 'tsconfig.json': json({ compilerOptions: {\n target: 'ESNext', module: 'Preserve', moduleResolution: 'bundler',\n strict: true, noEmit: true, skipLibCheck: true, types: ['bun'],\n } }),\n '.gitignore': '/node_modules/\\n/.open-wa/\\n/_IGNORE_*/\\n/*.data.json\\n.env\\n.env.*\\n',\n };\n const conflicts: string[] = [];\n for (const file of Object.keys(files)) {\n if (await exists(resolve(directory, file))) conflicts.push(file);\n }\n if (conflicts.length) {\n throw new Error(`Cannot initialize ${directory}: ${conflicts.join(', ')} already exist. Use a new directory, or add open-wa to your existing project with bun add @open-wa/wa-automate. No files were changed.`);\n }\n await mkdir(directory, { recursive: true });\n const created: string[] = [];\n try {\n for (const [name, content] of Object.entries(files)) {\n const path = resolve(directory, name);\n await writeFile(path, content, { flag: 'wx' });\n created.push(path);\n }\n } catch (error) {\n await Promise.all(created.map((path) => unlink(path)));\n throw error;\n }\n sink.write({ level: 'info', message: `Created ${directory}. WhatsApp login stays in private storage under your home directory, separate for each project.` });\n if (!args.includes('--no-install')) await install(directory);\n const quotedDirectory = `'${directory.replace(/'/g, \"'\\\\''\")}'`;\n sink.write({ level: 'info', message: `Next:\\n cd ${quotedDirectory}\\n${args.includes('--no-install') ? ' bun install\\n' : ''} Edit the recipient in index.ts\\n bun run start\\n\\nEach run sends one message. Check the receiving chat before retrying an uncertain send.` });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"init-k_0bazOu.cjs","names":["lstat","spawn","getCliOutputSink","resolve","basename","packageJson.version","mkdir","writeFile","unlink"],"sources":["../package.json","../src/cli/init.ts"],"sourcesContent":["","import { spawn } from 'node:child_process';\nimport { lstat, mkdir, unlink, writeFile } from 'node:fs/promises';\nimport { basename, resolve } from 'node:path';\nimport packageJson from '../../package.json';\nimport { getCliOutputSink } from './output-sink';\n\nconst starter = `import { create } from '@open-wa/wa-automate';\n\nconst recipient = 'REPLACE_WITH_RECIPIENT_CHAT_ID';\nconst message = 'Hello from open-wa!';\n\n// Use an existing chat with someone expecting your message.\nif (recipient === 'REPLACE_WITH_RECIPIENT_CHAT_ID') {\n throw new Error('Set recipient to an international phone number followed by @c.us, without + or spaces.');\n}\n\nconst client = await create();\n\ntry {\n await client.sendText(recipient, message);\n console.log('Message submitted. Check the receiving chat.');\n} finally {\n await client.stop();\n}\n`;\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await lstat(path);\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;\n throw error;\n }\n}\n\nasync function install(directory: string): Promise<void> {\n const command = process.versions.bun ? process.execPath : 'bun';\n await new Promise<void>((accept, reject) => {\n const child = spawn(command, ['install'], { cwd: directory, stdio: 'inherit' });\n child.once('error', () => reject(new Error('Bun is required to install this project. Install Bun from https://bun.sh, then run bun install in the generated directory.')));\n child.once('exit', (code) => code === 0\n ? accept()\n : reject(new Error('Dependency installation did not finish. The generated files are safe to keep; run bun install in the project to retry.')));\n });\n}\n\n/** Create a Bun/TypeScript application without overwriting existing files. */\nexport async function initProject(args: string[]): Promise<void> {\n const sink = getCliOutputSink();\n if (args.includes('--help') || args.includes('-h')) {\n sink.write({ level: 'info', message: 'Usage: bunx --bun @open-wa/wa-automate init <directory> [--no-install]\\nUse . for the current directory. Existing starter files are never overwritten.' });\n return;\n }\n const positional = args.filter((arg) => !arg.startsWith('-'));\n if (positional.length > 1 || args.some((arg) => arg.startsWith('-') && arg !== '--no-install')) {\n throw new Error('Usage: bunx --bun @open-wa/wa-automate init <directory> [--no-install]');\n }\n const directory = resolve(positional[0] ?? '.');\n const name = basename(directory).toLowerCase().replace(/[^a-z0-9._-]/g, '-').replace(/^[._-]+/, '') || 'my-bot';\n const json = (value: unknown) => `${JSON.stringify(value, null, 2)}\\n`;\n const files: Record<string, string> = {\n 'package.json': json({\n name, version: '0.0.0', private: true, type: 'module',\n scripts: { start: 'bun run index.ts' },\n dependencies: { '@open-wa/wa-automate': packageJson.version },\n devDependencies: { '@types/bun': 'latest' },\n }),\n 'index.ts': starter,\n 'tsconfig.json': json({ compilerOptions: {\n target: 'ESNext', module: 'Preserve', moduleResolution: 'bundler',\n strict: true, noEmit: true, skipLibCheck: true, types: ['bun'],\n } }),\n '.gitignore': '/node_modules/\\n/.open-wa/\\n/_IGNORE_*/\\n/*.data.json\\n.env\\n.env.*\\n',\n };\n const conflicts: string[] = [];\n for (const file of Object.keys(files)) {\n if (await exists(resolve(directory, file))) conflicts.push(file);\n }\n if (conflicts.length) {\n throw new Error(`Cannot initialize ${directory}: ${conflicts.join(', ')} already exist. Use a new directory, or add open-wa to your existing project with bun add @open-wa/wa-automate. No files were changed.`);\n }\n await mkdir(directory, { recursive: true });\n const created: string[] = [];\n try {\n for (const [name, content] of Object.entries(files)) {\n const path = resolve(directory, name);\n await writeFile(path, content, { flag: 'wx' });\n created.push(path);\n }\n } catch (error) {\n await Promise.all(created.map((path) => unlink(path)));\n throw error;\n }\n sink.write({ level: 'info', message: `Created ${directory}. WhatsApp login stays in private storage under your home directory, separate for each project.` });\n if (!args.includes('--no-install')) await install(directory);\n const quotedDirectory = `'${directory.replace(/'/g, \"'\\\\''\")}'`;\n sink.write({ level: 'info', message: `Next:\\n cd ${quotedDirectory}\\n${args.includes('--no-install') ? ' bun install\\n' : ''} Edit the recipient in index.ts\\n bun run start\\n\\nEach run sends one message. Check the receiving chat before retrying an uncertain send.` });\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@open-wa/wa-automate",
3
3
  "type": "module",
4
- "version": "5.3.0",
4
+ "version": "5.4.0",
5
5
  "description": "WhatsApp automation CLI and API server",
6
6
  "main": "./dist/index.cjs",
7
7
  "types": "./dist/index.d.cts",
@@ -15,17 +15,17 @@
15
15
  "dependencies": {
16
16
  "@elastic/elasticsearch": "^9.5.1",
17
17
  "@hono/node-server": "^2.1.1",
18
- "@open-wa/api": "5.3.0",
19
- "@open-wa/client": "5.3.0",
20
- "@open-wa/config": "5.3.0",
21
- "@open-wa/core": "5.3.0",
22
- "@open-wa/driver-lightpanda": "5.3.0",
23
- "@open-wa/driver-puppeteer": "5.3.0",
24
- "@open-wa/logger": "5.3.0",
18
+ "@open-wa/api": "5.4.0",
19
+ "@open-wa/client": "5.4.0",
20
+ "@open-wa/config": "5.4.0",
21
+ "@open-wa/core": "5.4.0",
22
+ "@open-wa/driver-lightpanda": "5.4.0",
23
+ "@open-wa/driver-puppeteer": "5.4.0",
24
+ "@open-wa/logger": "5.4.0",
25
25
  "@open-wa/runtime-core": "5.0.1",
26
26
  "@open-wa/runtime-node": "5.0.2",
27
- "@open-wa/schema": "5.3.0",
28
- "@open-wa/session-sync": "5.3.0",
27
+ "@open-wa/schema": "5.4.0",
28
+ "@open-wa/session-sync": "5.4.0",
29
29
  "boxen": "^9.0.0",
30
30
  "chrome-launcher": "^1.2.1",
31
31
  "hono": "^4.13.9",
@@ -1 +0,0 @@
1
- {"version":3,"file":"cli-runtime-BHx1nVhT.cjs","names":["ApiServer","eventRegistry","resolve","existsSync","readFileSync","dirname","defaultChatSandboxPolicy","LightpandaDriver","PuppeteerDriver","resolveConfig","makeNodeExecutionSandbox","createClient","observeBrowserProcessMemory","ClientFacade","fileURLToPath"],"sources":["../src/server/hono-server.ts","../src/cli/output-sink.ts","../src/cli-runtime.ts"],"sourcesContent":["import { ApiServer, createApiServer as createSharedApiServer } from '@open-wa/api';\nimport type { Config } from '@open-wa/config';\n\nexport class WAServer extends ApiServer {\n constructor(config: Config) {\n super({ config });\n }\n}\n\nexport function createApiServer(config: Config) {\n return createSharedApiServer(config);\n}\n","import qrcode from 'qrcode-terminal';\n\nexport type CliOutputLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface CliOutputEntry {\n level: CliOutputLevel;\n message: string;\n meta?: Record<string, unknown>;\n}\n\nexport interface CliStatusUpdate {\n phase:\n | 'boot'\n | 'config.resolved'\n | 'server.starting'\n | 'server.started'\n | 'client.starting'\n | 'launch.auth'\n | 'launch.helpers'\n | 'launch.patch'\n | 'launch.license'\n | 'launch.finalize'\n | 'auth.qr'\n | 'client.ready'\n | 'shutdown.starting'\n | 'shutdown.complete'\n | 'error';\n detail?: string;\n sessionId?: string;\n}\n\nexport interface CliQrPayload {\n qr: string;\n sessionId: string;\n}\n\nexport interface CliOutputSink {\n write(entry: CliOutputEntry): void;\n status(update: CliStatusUpdate): void;\n qr(payload: CliQrPayload): void;\n}\n\nfunction writeToConsole(level: CliOutputLevel, message: string): void {\n if (level === 'warn') {\n console.warn(message);\n return;\n }\n\n if (level === 'error') {\n console.error(message);\n return;\n }\n\n console.log(message);\n}\n\nexport function createConsoleOutputSink(): CliOutputSink {\n return {\n write(entry) {\n writeToConsole(entry.level, entry.message);\n },\n status() {\n // Status updates are semantic signals for richer presenters.\n },\n qr(payload) {\n qrcode.generate(payload.qr, { small: true }, (terminalQrCode) => {\n console.log(`WhatsApp login: ${payload.sessionId}\\n${terminalQrCode}`);\n });\n },\n };\n}\n\nlet activeSink: CliOutputSink = createConsoleOutputSink();\n\nexport function getCliOutputSink(): CliOutputSink {\n return activeSink;\n}\n\nexport function setCliOutputSink(sink: CliOutputSink): void {\n activeSink = sink;\n}\n\nexport function resetCliOutputSink(): void {\n activeSink = createConsoleOutputSink();\n}\n","import { createClient } from '@open-wa/core';\nimport { Client as ClientFacade } from '@open-wa/client';\nimport { LightpandaDriver } from '@open-wa/driver-lightpanda';\nimport { PuppeteerDriver } from '@open-wa/driver-puppeteer';\nimport { eventRegistry } from '@open-wa/schema';\nimport { WAServer } from './server/hono-server';\nimport { resolveConfig, type PartialConfig, type Config, type TrackedConfig } from '@open-wa/config';\nimport { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { getCliOutputSink, type CliOutputSink } from './cli/output-sink';\nimport {\n defaultChatSandboxPolicy,\n type ChatSandboxPolicy,\n type SandboxIsolation,\n} from '@open-wa/runtime-core';\nimport { makeNodeExecutionSandbox, observeBrowserProcessMemory } from '@open-wa/runtime-node';\n\nexport interface CliRuntimeResult {\n server: WAServer;\n client: ClientFacade;\n config: Config;\n events: ClientFacade['events'];\n dispose(): void;\n}\n\ninterface RuntimeEventPublisher {\n publish(eventName: string, payload: any): void;\n}\n\nfunction bridgeRuntimeEvents(\n openwaClient: Awaited<ReturnType<typeof createClient>>,\n publishRuntimeEvent: (eventName: string, payload: any) => void,\n): () => void {\n if (typeof openwaClient.events.onAny === 'function' && typeof openwaClient.events.offAny === 'function') {\n openwaClient.events.onAny(publishRuntimeEvent);\n return () => openwaClient.events.offAny(publishRuntimeEvent);\n }\n\n const unsubscribers: Array<() => void> = [];\n const bridgedEvents = new Set(eventRegistry.getAll().map((def) => def.meta.eventName));\n\n bridgedEvents.forEach((eventName) => {\n const handler = (payload: any) => publishRuntimeEvent(eventName, payload);\n openwaClient.events.on(eventName as never, handler);\n unsubscribers.push(() => openwaClient.events.off(eventName as never, handler));\n });\n\n return () => {\n unsubscribers.forEach((unsubscribe) => unsubscribe());\n };\n}\n\nfunction attachLaunchNarration(\n openwaClient: Awaited<ReturnType<typeof createClient>>,\n sink: CliOutputSink,\n sessionId: string,\n): () => void {\n const unsubscribers: Array<() => void> = [];\n const on = (event: string, handler: (...args: any[]) => void) => {\n openwaClient.events.on(event as never, handler);\n unsubscribers.push(() => openwaClient.events.off(event as never, handler));\n };\n\n on('launch.auth.check.before', (event: any) => {\n sink.status({ phase: 'launch.auth', sessionId, detail: `Authenticating (timeout=${event?.details?.timeoutMs ?? '∞'}ms)` });\n });\n\n on('launch.auth.check.after', (event: any) => {\n sink.write({ level: 'info', message: `Auth detected via ${event?.details?.method ?? 'unknown'} (${event?.details?.isAuthenticated ? 'authenticated' : 'not-authenticated'})` });\n });\n\n on('launch.helper.pre_api.before', (event: any) => {\n sink.status({ phase: 'launch.helpers', sessionId, detail: event?.details?.mode === 'scripts' ? 'Injecting pre-API helper assets...' : 'Pre-API helpers already present' });\n });\n\n on('launch.helper.pre_api.after', (event: any) => {\n sink.write({ level: 'info', message: `Pre-API helper phase complete (${event?.details?.mode ?? 'unknown'})` });\n });\n\n on('internal_launch_progress', (event: any) => {\n const prefix = (event?.value || event?.value === 0) ? `${event.value}% ` : '';\n if (event?.text) sink.write({ level: 'info', message: `${prefix}${event.text}`.trim() });\n });\n\n on('critical_internal_message', (event: any) => {\n sink.write({ level: 'warn', message: `Internal launch message: ${event?.text ?? event?.value ?? 'unknown'}` });\n });\n\n on('launch.patch.init.before', (event: any) => {\n if (event?.details?.phase === 'preload') {\n sink.status({ phase: 'launch.patch', sessionId, detail: 'Downloading patches from CDN...' });\n }\n });\n\n on('launch.patch.init.after', (event: any) => {\n if (event?.details?.phase === 'preload') {\n const source = event?.details?.source ?? 'unknown';\n const tag = event?.details?.tag ? ` tag=${event.details.tag}` : '';\n const available = Array.isArray(event?.details?.available) ? event.details.available.length : 0;\n const durationMs = event?.durationMs;\n const durationStr = durationMs ? ` in ${(durationMs / 1000).toFixed(2)}s` : '';\n sink.write({ level: 'info', message: `Downloaded patches${durationStr} (source=${source}, available=${available}${tag})` });\n }\n });\n\n on('patch.init.before', (event: any) => {\n if (event?.details?.phase === 'apply') {\n const count = Array.isArray(event?.details?.patchIds) ? event.details.patchIds.length : 0;\n sink.status({ phase: 'launch.patch', sessionId, detail: `Installing patches (${count} queued)` });\n }\n });\n\n on('patch.apply.before', (event: any) => {\n sink.status({ phase: 'launch.patch', sessionId, detail: `Applying patch: ${event?.details?.patchId ?? 'unknown'}` });\n });\n\n on('patch.apply.after', (event: any) => {\n sink.write({\n level: event?.details?.outcome === 'failed' ? 'warn' : 'info',\n message: `Patch ${event?.details?.patchId ?? 'unknown'}: ${event?.details?.outcome ?? (event?.details?.applied ? 'applied' : 'unknown')}${event?.details?.detail ? ` — ${event.details.detail}` : ''}`,\n });\n });\n\n on('patch.init.after', (event: any) => {\n if (event?.details?.phase === 'apply') {\n const applied = Array.isArray(event?.details?.applied) ? event.details.applied : [];\n const outcome = event?.details?.outcome ?? 'unknown';\n const tag = applied.length > 0 ? applied.join(', ') : outcome;\n const durationMs = event?.durationMs;\n const durationStr = durationMs ? ` in ${(durationMs / 1000).toFixed(2)}s` : '';\n sink.write({\n level: event?.details?.blockingFailure ? 'warn' : 'info',\n message: `Patches Installed${durationStr}: ${tag}`,\n });\n }\n });\n\n on('launch.patch.integrity.before', () => {\n sink.status({ phase: 'launch.patch', sessionId, detail: 'Validating patched runtime...' });\n });\n\n on('launch.patch.integrity.after', (event: any) => {\n sink.write({ level: event?.details?.usable ? 'info' : 'warn', message: `Patched runtime validation: ${event?.details?.usable ? 'usable' : 'failed'}${event?.details?.failureReason ? ` (${event.details.failureReason})` : ''}` });\n });\n\n on('launch.license.check.before', (event: any) => {\n sink.status({ phase: 'launch.license', sessionId, detail: `Checking license (${event?.details?.source ?? 'local'})` });\n });\n\n on('launch.license.check.after', (event: any) => {\n sink.write({ level: event?.details?.blockingFailure ? 'warn' : 'info', message: `License check: ${event?.details?.status ?? 'unknown'}${event?.details?.detail ? ` — ${event.details.detail}` : ''}` });\n });\n\n on('license.inject.before', () => {\n sink.status({ phase: 'launch.license', sessionId, detail: 'Injecting license payload...' });\n });\n\n on('license.inject.after', (event: any) => {\n sink.write({ level: event?.details?.success ? 'info' : 'warn', message: `License inject: ${event?.details?.success ? 'success' : 'failed'}${event?.details?.status ? ` (${event.details.status})` : ''}${event?.details?.detail ? ` — ${event.details.detail}` : ''}` });\n });\n\n on('launch.auth.qr.generated', (event: any) => {\n const qrIndex = event?.details?.qrIndex ?? '?';\n sink.status({ phase: 'launch.auth', sessionId, detail: `QR code generated (#${qrIndex})` });\n });\n\n on('launch.client.finalize.before', (event: any) => {\n sink.status({ phase: 'launch.finalize', sessionId, detail: `Finalizing session (${event?.details?.validationStage ?? 'unknown'})` });\n });\n\n on('launch.client.finalize.after', (event: any) => {\n sink.write({ level: event?.details?.success ? 'info' : 'warn', message: `Finalize: ${event?.details?.outcome ?? 'unknown'}${event?.details?.detail ? ` — ${event.details.detail}` : ''}` });\n });\n\n on('error', (event: any) => {\n const scope = event?.scope ?? 'unknown';\n const msg = event?.error?.message ?? String(event?.error ?? 'unknown error');\n const fatal = event?.fatal ? ' [FATAL]' : '';\n sink.write({ level: 'error', message: `${fatal} ${scope}: ${msg}`.trim() });\n });\n\n return () => {\n unsubscribers.forEach((unsubscribe) => unsubscribe());\n };\n}\n\nconst CHROME_CACHE_FILE = resolve(process.cwd(), '.open-wa', 'chrome-executable-path.json');\n\ninterface ChromePathCacheRecord {\n executablePath?: string;\n updatedAt?: string;\n}\n\ninterface ExecutablePathResolution {\n executablePath?: string;\n source:\n | 'config'\n | 'cache'\n | 'chrome_installation'\n | 'driver_default'\n | 'lightpanda_config'\n | 'lightpanda_sdk_default';\n warning?: string;\n}\n\ninterface DriverSelection {\n driver: PuppeteerDriver | LightpandaDriver;\n engineLabel: 'Puppeteer' | 'Lightpanda';\n executableResolution: ExecutablePathResolution;\n preferLocalChrome: boolean;\n}\n\nexport interface ParsedCliArgs {\n procName: string;\n pm2: boolean;\n forwardedArgs: string[];\n configPath?: string;\n cliOverrides: PartialConfig;\n verbose: boolean;\n unsupportedWarnings: string[];\n}\n\nexport function getChromeCacheFilePath(): string {\n return CHROME_CACHE_FILE;\n}\n\nexport function readChromePathCache(cacheFilePath: string = getChromeCacheFilePath()): ChromePathCacheRecord | undefined {\n if (!existsSync(cacheFilePath)) {\n return undefined;\n }\n\n try {\n const raw = JSON.parse(readFileSync(cacheFilePath, 'utf8')) as ChromePathCacheRecord;\n if (!raw || typeof raw !== 'object') {\n return undefined;\n }\n\n return {\n executablePath: typeof raw.executablePath === 'string' ? raw.executablePath : undefined,\n updatedAt: typeof raw.updatedAt === 'string' ? raw.updatedAt : undefined,\n };\n } catch {\n return undefined;\n }\n}\n\nexport function writeChromePathCache(executablePath: string, cacheFilePath: string = getChromeCacheFilePath()): void {\n mkdirSync(dirname(cacheFilePath), { recursive: true });\n writeFileSync(cacheFilePath, JSON.stringify({ executablePath, updatedAt: new Date().toISOString() }, null, 2), 'utf8');\n}\n\nexport function clearChromePathCache(cacheFilePath: string = getChromeCacheFilePath()): void {\n if (existsSync(cacheFilePath)) {\n rmSync(cacheFilePath, { force: true });\n }\n}\n\nexport function isUsableExecutablePath(executablePath?: string): executablePath is string {\n return !!executablePath && existsSync(executablePath);\n}\n\nfunction getExplicitUseChromePreference(rawConfigs?: TrackedConfig['rawConfigs']): boolean | undefined {\n const explicitConfigSources = [\n rawConfigs?.file,\n rawConfigs?.env,\n rawConfigs?.cli,\n rawConfigs?.programmatic,\n ];\n\n for (let index = explicitConfigSources.length - 1; index >= 0; index -= 1) {\n const source = explicitConfigSources[index];\n if (source?.useChrome !== undefined) {\n return source.useChrome;\n }\n }\n\n return undefined;\n}\n\nexport function shouldPreferLocalChrome(config: Config, rawConfigs?: TrackedConfig['rawConfigs']): boolean {\n if (config.useLightpanda) {\n return false;\n }\n\n if (config.executablePath) {\n return false;\n }\n\n const explicitUseChrome = getExplicitUseChromePreference(rawConfigs);\n if (explicitUseChrome !== undefined) {\n return explicitUseChrome;\n }\n\n return true;\n}\n\nfunction getVal(argv: string[], flag: string): string | undefined {\n const index = argv.findIndex(arg => arg === flag);\n return index !== -1 ? argv[index + 1] : undefined;\n}\n\nfunction parseSandboxIsolation(value: string): SandboxIsolation {\n switch (value) {\n case 'worker':\n case 'process':\n case 'container':\n return value;\n default:\n throw new Error(`Invalid --sandbox-isolation value: ${value}`);\n }\n}\n\nexport function resolveChatSandboxPolicy(config: Config['sandboxChats']): ChatSandboxPolicy | undefined {\n if (!config) return undefined;\n\n const overrides = typeof config === 'object'\n ? config as Partial<Omit<ChatSandboxPolicy, 'chats'>>\n : {};\n return {\n ...defaultChatSandboxPolicy,\n ...overrides,\n chats: true,\n networkAllowlist: [...(overrides.networkAllowlist ?? defaultChatSandboxPolicy.networkAllowlist)],\n env: overrides.env === 'none' || overrides.env === undefined\n ? overrides.env ?? defaultChatSandboxPolicy.env\n : [...overrides.env],\n capabilities: [...(overrides.capabilities ?? defaultChatSandboxPolicy.capabilities)],\n };\n}\n\nexport function parseCliArgs(argv: string[] = process.argv.slice(2)): ParsedCliArgs {\n const cliOverrides: PartialConfig = {};\n const unsupportedWarnings: string[] = [];\n let verbose = false;\n let configPath: string | undefined;\n\n const sessionId = getVal(argv, '--session-id');\n if (sessionId) cliOverrides.sessionId = sessionId;\n\n const portValue = getVal(argv, '--port') || getVal(argv, '-p');\n if (portValue) cliOverrides.port = parseInt(portValue, 10);\n\n const host = getVal(argv, '--host') || getVal(argv, '-h');\n if (host) cliOverrides.host = host;\n\n const apiKey = getVal(argv, '--api-key') || getVal(argv, '--key') || getVal(argv, '-k');\n if (apiKey) cliOverrides.apiKey = apiKey;\n\n const logLevel = getVal(argv, '--log-level');\n if (logLevel) cliOverrides.logLevel = logLevel;\n\n if (argv.includes('--no-ezqr')) cliOverrides.ezqr = false;\n if (argv.includes('--headful')) cliOverrides.headless = false;\n if (argv.includes('--headless')) cliOverrides.headless = true;\n if (argv.includes('--use-chrome')) cliOverrides.useChrome = true;\n if (argv.includes('--use-lightpanda')) cliOverrides.useLightpanda = true;\n if (argv.includes('--log-console')) cliOverrides.logConsole = true;\n if (argv.includes('--aggressive-garbage-collection')) cliOverrides.aggressiveGarbageCollection = true;\n if (argv.includes('--no-dashboard')) cliOverrides.dashboard = false;\n if (argv.includes('--ephemeral')) cliOverrides.ephemeral = true;\n if (argv.includes('--legacy-data-dir-auth')) cliOverrides.legacyDataDirAuth = true;\n if (argv.includes('--sandbox-chats')) cliOverrides.sandboxChats = true;\n\n const sandboxIsolation = getVal(argv, '--sandbox-isolation');\n if (sandboxIsolation) {\n const { chats: _chats, ...sandboxDefaults } = defaultChatSandboxPolicy;\n cliOverrides.sandboxChats = {\n ...sandboxDefaults,\n isolation: parseSandboxIsolation(sandboxIsolation),\n networkAllowlist: [...defaultChatSandboxPolicy.networkAllowlist],\n env: defaultChatSandboxPolicy.env === 'none'\n ? 'none'\n : [...defaultChatSandboxPolicy.env],\n capabilities: [...defaultChatSandboxPolicy.capabilities],\n };\n }\n\n const qrTimeout = getVal(argv, '--qr-timeout');\n if (qrTimeout) cliOverrides.qrTimeout = parseInt(qrTimeout, 10);\n\n const dashboardPort = getVal(argv, '--dashboard-port');\n if (dashboardPort) cliOverrides.dashboardPort = parseInt(dashboardPort, 10);\n\n const licenseKey = getVal(argv, '--license-key') || getVal(argv, '-l');\n if (licenseKey) cliOverrides.licenseKey = licenseKey;\n\n const webhook = getVal(argv, '--webhook') || getVal(argv, '-w');\n if (webhook) cliOverrides.webhook = webhook;\n\n const proxyHost = getVal(argv, '--proxy-host');\n if (proxyHost) cliOverrides.proxyHost = proxyHost;\n\n const proxyToken = getVal(argv, '--proxy-token');\n if (proxyToken) cliOverrides.proxyToken = proxyToken;\n\n const readyWebhook = getVal(argv, '--ready-webhook');\n if (readyWebhook) unsupportedWarnings.push(`--ready-webhook was provided (${readyWebhook}) but ready-webhook delivery is not yet wired in v5 CLI.`);\n\n if (argv.includes('-v') || argv.includes('--verbose')) {\n verbose = true;\n cliOverrides.disableSpins = true;\n cliOverrides.logConsole = true;\n cliOverrides.logLevel = cliOverrides.logLevel || 'debug';\n }\n\n if (argv.includes('--stats')) {\n unsupportedWarnings.push('--stats was provided but swagger-stats parity is not restored; v5 only exposes the compatibility redirect/deprecation route.');\n }\n\n if (argv.includes('--generate-api-docs')) {\n unsupportedWarnings.push('--generate-api-docs was provided; runtime docs are always served from the shared API layer and no separate collection generation step currently runs at CLI boot.');\n }\n\n if (argv.includes('--tunnel')) {\n unsupportedWarnings.push('--tunnel was provided but tunnel setup parity is not yet restored in the v5 CLI.');\n }\n\n if (argv.includes('--chatwoot-url') || argv.includes('--twilio-webhook') || argv.includes('--bot-press-url')) {\n unsupportedWarnings.push('Legacy integration flags (Chatwoot/Twilio/BotPress) were provided but are not yet wired into the v5 CLI boot path.');\n }\n\n if (argv.includes('--use-session-id-in-path') && sessionId) {\n cliOverrides.sessionId = sessionId;\n }\n\n configPath = getVal(argv, '--config') || getVal(argv, '-c');\n\n const procName = getVal(argv, '--name') || sessionId || '@OPEN-WA EASY API';\n const pm2 = argv.includes('--pm2');\n\n return {\n procName,\n pm2,\n forwardedArgs: argv,\n configPath,\n cliOverrides,\n verbose,\n unsupportedWarnings,\n };\n}\n\nexport async function resolveExecutablePath(\n config: Config,\n options: {\n preferLocalChrome?: boolean;\n cacheFilePath?: string;\n } = {}\n): Promise<ExecutablePathResolution> {\n if (config.executablePath) {\n return {\n executablePath: config.executablePath,\n source: 'config',\n };\n }\n\n const preferLocalChrome = options.preferLocalChrome ?? config.useChrome;\n if (!preferLocalChrome) {\n return {\n source: 'driver_default',\n };\n }\n\n const cacheFilePath = options.cacheFilePath ?? getChromeCacheFilePath();\n const cachedPath = readChromePathCache(cacheFilePath)?.executablePath;\n if (isUsableExecutablePath(cachedPath)) {\n return {\n executablePath: cachedPath,\n source: 'cache',\n };\n }\n\n if (cachedPath) {\n clearChromePathCache(cacheFilePath);\n }\n\n const { Launcher } = await import('chrome-launcher');\n const detectedPath = Launcher.getInstallations().find((installationPath) => isUsableExecutablePath(installationPath));\n\n if (detectedPath) {\n writeChromePathCache(detectedPath, cacheFilePath);\n return {\n executablePath: detectedPath,\n source: 'chrome_installation',\n };\n }\n\n clearChromePathCache(cacheFilePath);\n\n return {\n source: 'driver_default',\n warning: 'Chrome resolution warning: no valid local Chrome installation was found. Falling back to Puppeteer/default driver browser resolution.',\n };\n}\n\nfunction resolveLightpandaExecutablePath(config: Config): ExecutablePathResolution {\n const executablePath = config.lightpanda?.executablePath;\n if (executablePath) {\n return {\n executablePath,\n source: 'lightpanda_config',\n };\n }\n\n return {\n source: 'lightpanda_sdk_default',\n };\n}\n\nasync function selectRuntimeDriver(config: Config, rawConfigs?: TrackedConfig['rawConfigs']): Promise<DriverSelection> {\n if (config.useLightpanda) {\n return {\n driver: new LightpandaDriver(),\n engineLabel: 'Lightpanda',\n executableResolution: resolveLightpandaExecutablePath(config),\n preferLocalChrome: false,\n };\n }\n\n const preferLocalChrome = shouldPreferLocalChrome(config, rawConfigs);\n const executableResolution = await resolveExecutablePath(config, { preferLocalChrome });\n\n return {\n driver: new PuppeteerDriver(),\n engineLabel: 'Puppeteer',\n executableResolution,\n preferLocalChrome,\n };\n}\n\nfunction printStartupSummary(\n config: Config,\n resolution: ExecutablePathResolution,\n preferLocalChrome: boolean,\n engineLabel: DriverSelection['engineLabel'],\n) {\n const host = config.host.includes('http') ? config.host : `http://${config.host}`;\n const sink = getCliOutputSink();\n sink.write({ level: 'info', message: `Easy API session: ${config.sessionId}` });\n sink.write({ level: 'info', message: `Health: ${host}:${config.port}/health` });\n sink.write({ level: 'info', message: `API Explorer: ${host}:${config.port}/api-docs/` });\n sink.write({ level: 'info', message: `Swagger JSON: ${host}:${config.port}/meta/swagger.json` });\n sink.write({ level: 'info', message: `Postman JSON: ${host}:${config.port}/meta/postman.json` });\n sink.write({ level: 'info', message: `Browser mode: ${config.headless ? 'headless' : 'headful'}` });\n sink.write({ level: 'info', message: `Browser engine: ${engineLabel}` });\n if (config.dashboard) {\n sink.write({ level: 'info', message: `Dashboard: ${host}:${config.port}/dashboard/` });\n } else {\n sink.write({ level: 'info', message: 'Dashboard: disabled (--no-dashboard)' });\n }\n if (resolution.source === 'lightpanda_config' && resolution.executablePath) {\n sink.write({ level: 'info', message: `Browser executable: explicit Lightpanda override (${resolution.executablePath})` });\n } else if (resolution.source === 'lightpanda_sdk_default') {\n sink.write({ level: 'info', message: 'Browser executable: Lightpanda SDK managed executable (shared cache/default resolution)' });\n } else if (resolution.source === 'config' && config.executablePath) {\n sink.write({ level: 'info', message: `Browser executable: explicit override (${config.executablePath})` });\n } else if (resolution.source === 'cache') {\n sink.write({ level: 'info', message: `Browser executable: local Chrome from cache (${resolution.executablePath})` });\n } else if (resolution.source === 'chrome_installation') {\n sink.write({ level: 'info', message: `Browser executable: local Chrome detected (${resolution.executablePath})` });\n } else if (preferLocalChrome) {\n sink.write({ level: 'info', message: 'Browser executable: driver default fallback (local Chrome unavailable)' });\n }\n if (config.webhook) {\n sink.write({\n level: 'warn',\n message: `Webhook configured (${config.webhook}) but v5 CLI webhook registration parity is not yet restored.`,\n });\n }\n}\n\nexport async function start(parsedArgs: ParsedCliArgs = parseCliArgs()): Promise<CliRuntimeResult> {\n const { configPath, cliOverrides, verbose, unsupportedWarnings } = parsedArgs;\n const sink = getCliOutputSink();\n\n sink.status({ phase: 'boot' });\n\n const { config, sources, configFilePath, rawConfigs } = await resolveConfig({\n configPath,\n cliOverrides: {\n disableSpins: true,\n apiLifecycle: 'hybrid',\n // Let schema defaults, config files, and WA_HOST/WA_PORT resolve\n // before applying host/port flags actually supplied by the user.\n ...cliOverrides,\n },\n includeRawConfigs: true,\n verbose,\n });\n\n if (verbose) {\n sink.write({ level: 'info', message: `Config sources: ${sources.join(', ')}` });\n if (configFilePath) {\n sink.write({ level: 'info', message: `Config file: ${configFilePath}` });\n }\n }\n\n sink.status({ phase: 'config.resolved', sessionId: config.sessionId });\n\n unsupportedWarnings.forEach((warning) => sink.write({ level: 'warn', message: `Compatibility warning: ${warning}` }));\n\n const driverSelection = await selectRuntimeDriver(config, rawConfigs);\n const { driver, engineLabel, executableResolution, preferLocalChrome } = driverSelection;\n if (executableResolution.warning) {\n sink.write({ level: 'warn', message: executableResolution.warning });\n }\n\n const server = new WAServer(config);\n sink.status({ phase: 'server.starting', sessionId: config.sessionId });\n\n await server.start();\n sink.status({ phase: 'server.started', sessionId: config.sessionId });\n\n printStartupSummary(config, executableResolution, preferLocalChrome, engineLabel);\n\n sink.status({ phase: 'client.starting', sessionId: config.sessionId });\n sink.write({ level: 'info', message: 'Starting WhatsApp Client...' });\n\n const sandboxPolicy = resolveChatSandboxPolicy(config.sandboxChats);\n const executionSandbox = sandboxPolicy\n ? makeNodeExecutionSandbox({ workspacePath: process.cwd() })\n : undefined;\n\n const openwaClient = await createClient({\n sessionId: config.sessionId,\n driver,\n deleteSessionDataOnLogout: config.deleteSessionDataOnLogout,\n killClientOnLogout: config.killClientOnLogout,\n legacyDataDirAuth: config.legacyDataDirAuth,\n sessionDataPath: config.sessionDataPath,\n sessionData: config.sessionData,\n skipSessionSave: config.skipSessionSave,\n sessionDataBucketAuth: config.sessionDataBucketAuth,\n s3Sync: config.s3Sync,\n debug: config.logLevel === 'debug' || verbose || config.logConsole,\n headless: config.headless,\n qrTimeoutMs: typeof config.qrTimeout === 'number' ? config.qrTimeout * 1000 : undefined,\n authTimeoutMs: typeof config.authTimeout === 'number' ? config.authTimeout * 1000 : undefined,\n executablePath: executableResolution.executablePath,\n browserArgs: config.chromiumArgs,\n browser: config.browser,\n allowDangerousBrowserArgs: config.allowDangerousBrowserArgs,\n userDataDir: config.userDataDir,\n ephemeral: config.ephemeral,\n linkCode: config.linkCode,\n logConsole: config.logConsole,\n logConsoleErrors: config.logConsoleErrors,\n blockCrashLogs: config.blockCrashLogs,\n blockAssets: config.blockAssets,\n safeMode: config.safeMode,\n licenseKey: config.licenseKey as any,\n sandboxPolicy,\n executionSandbox,\n memoryObservation: (observability, getBrowserProcessId) => observeBrowserProcessMemory(\n observability,\n getBrowserProcessId,\n { attributes: { session: config.sessionId } },\n ),\n });\n\n server.setReadinessProvider(() => ({ ...openwaClient.getReadiness(), state: openwaClient.getState() }));\n const detachLaunchNarration = attachLaunchNarration(openwaClient, sink, config.sessionId);\n\n openwaClient.events.on('launch.auth.qr.generated', (event) => {\n const qr = event.details?.qr;\n if (!qr) {\n return;\n }\n\n if (config.qrLogSkip) {\n sink.write({ level: 'info', message: 'New QR Code generated. Not printing in console because qrLogSkip is set to true' });\n } else {\n sink.status({ phase: 'auth.qr', sessionId: config.sessionId, detail: 'QR code generated' });\n sink.qr({ qr, sessionId: config.sessionId });\n }\n\n server.setQR(qr);\n });\n\n openwaClient.events.on('launch.auth.linkCode.generated', (event) => {\n const linkCode = event.details?.linkCode;\n if (!linkCode) {\n return;\n }\n\n sink.status({\n phase: 'launch.auth',\n sessionId: config.sessionId,\n detail: 'Link code generated; enter it on the paired phone',\n });\n sink.write({\n level: 'info',\n message: `Link code (local console only): ${linkCode}`,\n });\n });\n\n const client = new ClientFacade({\n client: openwaClient,\n transport: openwaClient.getTransport(),\n });\n\n server.setClient(client as any);\n\n const runtimeBridgeListeners = new Set<(event: string, value: any) => void>();\n const runtimeEventPublishers: RuntimeEventPublisher[] = [\n {\n publish: (eventName, payload) => {\n runtimeBridgeListeners.forEach((listener) => {\n listener(eventName, payload);\n });\n },\n },\n ];\n\n const publishRuntimeEvent = (eventName: string, payload: any) => {\n runtimeEventPublishers.forEach((publisher) => {\n publisher.publish(eventName, payload);\n });\n };\n\n const detachRuntimeBridge = bridgeRuntimeEvents(openwaClient, publishRuntimeEvent);\n\n // Bridge core events to the socket manager so dashboard clients\n // receive live events when they send register_ev.\n if (typeof server.setEventBridge === 'function') {\n server.setEventBridge({\n onAny: (listener: (event: string, value: any) => void) => {\n runtimeBridgeListeners.add(listener);\n },\n offAny: (listener: (event: string, value: any) => void) => {\n runtimeBridgeListeners.delete(listener);\n },\n });\n }\n\n const handleBrowserInit = async () => {\n const page = openwaClient.getTransport().getPage();\n if (page) {\n await server.setPage(page as any).catch(() => {});\n }\n };\n openwaClient.events.on('launch.browser.init.after', handleBrowserInit);\n\n let disposed = false;\n const dispose = () => {\n if (disposed) return;\n disposed = true;\n detachRuntimeBridge();\n openwaClient.events.off('launch.browser.init.after', handleBrowserInit);\n runtimeBridgeListeners.clear();\n };\n\n try {\n await client.start();\n } catch (startError) {\n const msg = startError instanceof Error ? startError.message : String(startError);\n sink.write({ level: 'error', message: `Bootstrap failed: ${msg}` });\n sink.write({ level: 'warn', message: 'Session kept alive for debugging. Browser page is still open.' });\n sink.write({ level: 'warn', message: 'The server is running — use /health and /api-docs to inspect state.' });\n detachLaunchNarration();\n return { server, client, config, events: openwaClient.events, dispose };\n }\n\n const readiness = openwaClient.getReadiness();\n sink.status({\n phase: 'client.ready',\n sessionId: config.sessionId,\n detail: `status=${readiness.status}, exposureSafe=${readiness.exposureSafe}`,\n });\n sink.write({\n level: 'info',\n message: `WhatsApp Client ready with state: ${client.getState()} (status=${readiness.status}, exposureSafe=${readiness.exposureSafe})`,\n });\n\n detachLaunchNarration();\n return { server, client, config, events: openwaClient.events, dispose };\n}\n\nexport async function main(argv: string[] = process.argv.slice(2)): Promise<CliRuntimeResult | void> {\n if (argv[0] === 'init') {\n const { initProject } = await import('./cli/init');\n await initProject(argv.slice(1));\n return;\n }\n const parsedArgs = parseCliArgs(argv);\n\n if (parsedArgs.pm2) {\n const { spawn } = require('child_process');\n const sink = getCliOutputSink();\n const pm2Command = getPm2Command();\n const pm2SpawnOptions = getPm2SpawnOptions();\n try {\n const pm2 = spawn(pm2Command, ['--version'], pm2SpawnOptions);\n\n await new Promise<void>((resolve, reject) => {\n pm2.on('error', reject);\n pm2.on('exit', (code: number | null) => {\n if (code === 0) {\n resolve();\n return;\n }\n\n reject(new Error(`pm2 probe exited with code ${code ?? 'unknown'}`));\n });\n pm2.stdout.on('data', () => resolve());\n });\n\n const pm2Flags = parsedArgs.forwardedArgs.filter((flag: string) => flag !== '--pm2');\n const cliPath = fileURLToPath(new URL('../dist/cli.cjs', import.meta.url));\n\n spawn(pm2Command, [\n 'start',\n cliPath,\n '--name', parsedArgs.procName,\n '--stop-exit-codes', '88',\n '--',\n ...pm2Flags,\n ], {\n ...pm2SpawnOptions,\n stdio: 'inherit',\n detached: true\n });\n return;\n } catch (error: unknown) {\n if (isCommandNotFoundError(error)) {\n sink.write({ level: 'error', message: 'pm2 not found. Please install with: npm install -g pm2' });\n return;\n }\n throw error;\n }\n }\n\n return await start(parsedArgs);\n}\n\nfunction getPm2Command(): string {\n return process.platform === 'win32' ? 'pm2.cmd' : 'pm2';\n}\n\nfunction getPm2SpawnOptions(): { shell: boolean } {\n return { shell: process.platform === 'win32' };\n}\n\nfunction isCommandNotFoundError(error: unknown): boolean {\n if (typeof error !== 'object' || error === null) {\n return false;\n }\n\n const systemError = error as { code?: unknown; errno?: unknown };\n return systemError.code === 'ENOENT' || systemError.errno === -2;\n}\n"],"mappings":"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"}