everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
1 lines • 23.5 kB
Source Map (JSON)
{"version":3,"file":"dev-session.mjs","names":[],"sources":["../src/dev-session.ts"],"sourcesContent":["import { Clock, DateTime, Deferred, Effect, Exit, Layer } from \"effect\";\nimport { probePortBindable } from \"./app\";\nimport {\n createDevRenderer,\n type DevProcessState,\n type DevRendererHandle,\n} from \"./components/dev-render\";\nimport { createLogPipeline, isDebug, type LogEvent, resolveLogLevel } from \"./dev-log-pipeline\";\nimport { createDevLogger, formatLogLine } from \"./dev-logs\";\nimport { getProcessEnv } from \"./env/process-env\";\nimport { ShellEnvLive } from \"./env/project-env\";\nimport { ownerOfPort } from \"./infra/port-ownership\";\nimport {\n getProcessStates,\n makeDevProcess,\n type ProcessCallbacks,\n type ProcessHandle,\n} from \"./orchestrator\";\nimport { reapGroup } from \"./process-kill\";\nimport {\n isPidAlive,\n readRegistry,\n registerStandalone,\n unregisterPid,\n updateChildPids,\n writeRegistry,\n} from \"./process-registry\";\nimport {\n type AppOrchestrator,\n DevGeneratedEnvLive,\n DevRuntimeConfig,\n DevRuntimeConfigLive,\n isAuthMirrorPluginEntry,\n type ServiceDescriptor,\n ServiceDescriptorMap,\n ServiceDescriptorMapLive,\n} from \"./service-descriptor\";\nimport type { RuntimeConfig } from \"./types\";\n\nconst adoptOrphanedChildren = (configDir: string): void => {\n try {\n const entries = readRegistry().filter(\n (entry) => entry.pid > 1 && entry.configDir === configDir && !isPidAlive(entry.pid),\n );\n if (entries.length === 0) return;\n const reaped: number[] = [];\n for (const entry of entries) {\n for (const childPid of entry.childPids ?? []) {\n if (childPid === process.pid) continue;\n if (isPidAlive(childPid)) {\n reapGroup(childPid);\n reaped.push(childPid);\n }\n }\n }\n if (reaped.length > 0) {\n console.error(\n `[Dev] Reaped ${reaped.length} orphaned child process(es) from dead session(s): ${reaped.join(\", \")}`,\n );\n }\n const deadPids = new Set(entries.map((entry) => entry.pid));\n writeRegistry(readRegistry().filter((entry) => !deadPids.has(entry.pid)));\n } catch {\n // best-effort; registry hygiene is non-critical for the running session\n }\n};\n\nconst isInteractiveSupported = (): boolean => {\n return process.stdin.isTTY === true && process.stdout.isTTY === true;\n};\n\nconst STARTUP_ORDER = [\"ui\", \"auth\", \"api\", \"plugin\", \"host-build\", \"host\"];\n\nconst sortByOrder = (packages: string[]): string[] => {\n return [...packages].sort((a, b) => {\n const aIdx = a.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(a);\n const bIdx = b.startsWith(\"plugin:\")\n ? STARTUP_ORDER.indexOf(\"plugin\")\n : STARTUP_ORDER.indexOf(b);\n if (aIdx === -1 && bIdx === -1) return 0;\n if (aIdx === -1) return 1;\n if (bIdx === -1) return -1;\n return aIdx - bIdx;\n });\n};\n\nexport interface DevSessionControls {\n requestShutdown: () => void;\n emergencyKill: () => void;\n requestShutdownEscalating: () => void;\n forceExit: () => void;\n restoreView: () => void;\n rearmForceExitTimer: () => void;\n}\n\nexport const runDevSession = (\n configDir: string,\n orchestrator: AppOrchestrator,\n onShutdownReady?: (controls: DevSessionControls) => void,\n) =>\n Effect.gen(function* () {\n adoptOrphanedChildren(configDir);\n const services = yield* ServiceDescriptorMap;\n const runtimeConfig = yield* DevRuntimeConfig;\n const orderedPackages = sortByOrder(orchestrator.packages);\n const initialProcesses: DevProcessState[] = getProcessStates(\n orderedPackages,\n services,\n orchestrator.port,\n );\n\n if (isDebug(getProcessEnv(\"DEBUG\"))) {\n yield* Effect.logError(\n `[DEBUG session] orchestrator.packages: ${orchestrator.packages.join(\", \")}`,\n );\n yield* Effect.logError(`[DEBUG session] orderedPackages: ${orderedPackages.join(\", \")}`);\n yield* Effect.logError(`[DEBUG session] services keys: ${[...services.keys()].join(\", \")}`);\n yield* Effect.logError(\n `[DEBUG session] initialProcesses: ${initialProcesses.map((p) => `${p.name}=${p.source}`).join(\", \")}`,\n );\n }\n\n const logger = yield* Effect.promise(() =>\n createDevLogger(configDir, orchestrator.description),\n );\n\n const shutdown = yield* Deferred.make<void>();\n\n const effectContext = yield* Effect.context();\n const controls: DevSessionControls = {\n requestShutdown: () => {\n void Effect.runPromiseWith(effectContext)(Deferred.succeed(shutdown, undefined));\n },\n emergencyKill: () => {},\n requestShutdownEscalating: () => {},\n forceExit: () => {},\n restoreView: () => {},\n rearmForceExitTimer: () => {},\n };\n\n onShutdownReady?.(controls);\n\n const isWorkspaceChild = getProcessEnv(\"BOS_WORKSPACE_CHILD\") === \"1\";\n let ownedPorts: number[] = [];\n if (!isWorkspaceChild) {\n const regPorts: Record<string, number> = {};\n const addPort = (key: string, value: number | undefined | null) => {\n if (value != null) regPorts[key] = value;\n };\n addPort(\"host\", runtimeConfig.host.port);\n addPort(\"api\", runtimeConfig.api.port);\n addPort(\"ui\", runtimeConfig.ui.port);\n addPort(\"auth\", runtimeConfig.auth?.port);\n if (runtimeConfig.plugins) {\n for (const [id, plugin] of Object.entries(runtimeConfig.plugins)) {\n if (!isAuthMirrorPluginEntry(runtimeConfig.auth, id, plugin)) {\n addPort(`plugin:${id}`, plugin.port);\n }\n addPort(`plugin-ui:${id}`, plugin.ui?.port);\n }\n }\n registerStandalone({\n pid: process.pid,\n configDir,\n ports: regPorts,\n startedAt: yield* Clock.currentTimeMillis,\n description: orchestrator.description,\n });\n ownedPorts = Object.values(regPorts);\n }\n\n let view: DevRendererHandle | null = null;\n let shouldExportLogs = false;\n\n const logLevel = resolveLogLevel();\n const allLogs: LogEvent[] = [];\n const pipeline = createLogPipeline({\n level: logLevel,\n sinks: {\n display: (event) => {\n view?.addLog(event.source, event.line, event.level === \"error\");\n },\n file: (event) => {\n if (orchestrator.noLogs) return;\n void logger.write(event);\n },\n export: (event) => {\n allLogs.push(event);\n },\n },\n });\n\n const useInteractive = isInteractiveSupported() && orchestrator.interactive !== false;\n view = createDevRenderer(\n initialProcesses,\n orchestrator.description,\n orchestrator.env,\n () => controls.requestShutdownEscalating(),\n () => {\n shouldExportLogs = true;\n controls.requestShutdownEscalating();\n },\n { interactive: useInteractive, onForceExit: () => controls.forceExit() },\n );\n controls.restoreView = () => {\n if (useInteractive) view?.unmount();\n };\n\n const callbacks: ProcessCallbacks = {\n onStatus: (name, status, message) => {\n view?.updateProcess(name, status, message);\n },\n onLog: (name, line, isError) => {\n pipeline.ingest({ source: name, line, isError });\n },\n };\n\n const spawned: ProcessHandle[] = [];\n\n controls.emergencyKill = () => {\n for (const handle of spawned) {\n if (handle.pid === undefined) continue;\n reapGroup(handle.pid);\n }\n };\n\n yield* Effect.addFinalizer(() =>\n Effect.gen(function* () {\n controls.rearmForceExitTimer();\n\n yield* Effect.forEach(spawned, (h) => h.kill.pipe(Effect.ignore), {\n concurrency: \"unbounded\",\n });\n\n yield* Effect.sleep(\"200 millis\");\n\n for (const port of ownedPorts) {\n const bindable = yield* probePortBindable(port);\n if (!bindable) {\n const owner = yield* ownerOfPort(port);\n yield* Effect.logError(\n `[Dev] Port ${port} still bound after teardown${\n owner\n ? ` — pid ${owner.pid} (${owner.command})`\n : \" — owner unknown (lsof unavailable)\"\n }`,\n );\n }\n }\n\n if (!isWorkspaceChild) {\n yield* Effect.sync(() => {\n try {\n unregisterPid(process.pid);\n } catch {\n // best-effort; pruneDead cleans stale entries on next ps/kill\n }\n });\n }\n\n pipeline.flush();\n\n view?.unmount();\n\n if (shouldExportLogs) {\n const now = yield* Clock.currentTimeMillis;\n const startedMs = allLogs[0]?.timestamp || now;\n yield* Effect.log(\"\");\n yield* Effect.log(\"═\".repeat(70));\n yield* Effect.log(` SESSION LOGS: ${orchestrator.description}`);\n yield* Effect.log(` Started: ${DateTime.formatIso(DateTime.makeUnsafe(startedMs))}`);\n yield* Effect.log(` Filtered entries: ${allLogs.length} (level: ${logLevel})`);\n yield* Effect.log(\"═\".repeat(70));\n yield* Effect.log(\"\");\n for (const event of allLogs) {\n yield* Effect.log(formatLogLine(event));\n }\n yield* Effect.log(\"\");\n yield* Effect.log(\"═\".repeat(70));\n yield* Effect.log(` Full logs saved to: ${logger.logFile}`);\n yield* Effect.log(\"═\".repeat(70));\n yield* Effect.log(\"\");\n }\n }),\n );\n\n const startProcess = (pkg: string) => {\n const portOverride = pkg === \"host\" ? orchestrator.port : undefined;\n return makeDevProcess(pkg, callbacks, portOverride).pipe(\n Effect.tap((handle) => Effect.sync(() => spawned.push(handle))),\n Effect.flatMap((handle) =>\n Effect.acquireRelease(Effect.succeed(handle), () => handle.kill.pipe(Effect.ignore)),\n ),\n Effect.tapError((err) =>\n Effect.sync(() => {\n callbacks.onLog(pkg, `Failed to start: ${String(err)}`, true);\n callbacks.onStatus(pkg, \"error\");\n }),\n ),\n Effect.orElseSucceed(\n () =>\n ({\n name: pkg,\n pid: undefined,\n kill: Effect.void,\n waitForReady: Effect.void,\n waitForExit: Effect.never,\n }) satisfies ProcessHandle,\n ),\n );\n };\n\n const startGroup = (packages: string[]) =>\n Effect.forEach(packages, startProcess, { concurrency: \"unbounded\" });\n\n const awaitReady = (pkg: string, handle: ProcessHandle) =>\n handle.waitForReady.pipe(\n Effect.timeout(\"120 seconds\"),\n Effect.catch((err) =>\n Effect.sync(() => {\n callbacks.onLog(\n pkg,\n `Timed out or failed: ${err instanceof Error ? err.message : String(err)}`,\n true,\n );\n }),\n ),\n );\n\n const nonHostPackages = orderedPackages.filter((pkg) => pkg !== \"host\");\n const hostPackages = orderedPackages.filter((pkg) => pkg === \"host\");\n\n const startupPhase = Effect.gen(function* () {\n const nonHostHandles = yield* startGroup(nonHostPackages);\n\n yield* Effect.forEach(\n nonHostHandles.map((handle, index) => ({\n handle,\n pkg: nonHostPackages[index] ?? handle.name,\n })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n const hostHandles = yield* startGroup(hostPackages);\n\n yield* Effect.forEach(\n hostHandles.map((handle, index) => ({\n handle,\n pkg: hostPackages[index] ?? handle.name,\n })),\n ({ handle, pkg }) => awaitReady(pkg, handle),\n { concurrency: \"unbounded\" },\n );\n\n return { nonHostHandles, hostHandles };\n });\n\n const startup = yield* Effect.raceFirst(\n startupPhase,\n Deferred.await(shutdown).pipe(Effect.as(null)),\n );\n\n if (startup === null) return;\n\n const allHandles = [...startup.nonHostHandles, ...startup.hostHandles];\n\n const childPids = allHandles\n .map((handle) => Number(handle.pid))\n .filter((pid) => Number.isFinite(pid) && pid > 1 && pid !== process.pid);\n\n if (!isWorkspaceChild && childPids.length > 0) {\n yield* Effect.sync(() => {\n try {\n updateChildPids(process.pid, childPids);\n } catch {\n // best-effort; registry hygiene is non-critical for the running session\n }\n });\n }\n\n yield* Deferred.await(shutdown);\n });\n\nconst runApp = (\n configDir: string,\n orchestrator: AppOrchestrator,\n services: Map<string, ServiceDescriptor>,\n runtimeConfig: RuntimeConfig,\n envGenerated: Record<string, string>,\n shellEnv: Record<string, string>,\n) => {\n let controls: DevSessionControls | null = null;\n let signalCount = 0;\n let forceExitTimer: ReturnType<typeof setTimeout> | null = null;\n\n const forceExit = () => {\n controls?.restoreView();\n console.log(\"\\n[Dev] Force exit\");\n controls?.emergencyKill();\n process.exit(0);\n };\n\n // Orphan watch: when the wrapper chain above this process dies (playwright\n // tree-kills its webServer with SIGKILL — no signal handler runs, detached\n // group escapes), this orchestrator is reparented. Detect that and reap the\n // whole service tree — the alternatives are zombie port squatters that\n // poison the next run. Covers shell aborts (Ctrl+C killing only the\n // wrapper) the same way.\n const initialPpid = process.ppid;\n const orphanWatch = setInterval(() => {\n if (process.ppid !== initialPpid) {\n console.error(\"\\n[Dev] Parent process died — force exiting (orphaned service tree)\");\n forceExit();\n }\n }, 200);\n orphanWatch.unref?.();\n\n const requestShutdownEscalating = () => {\n signalCount++;\n if (signalCount > 1) {\n forceExit();\n return;\n }\n controls?.restoreView();\n console.log(\"\\n[Dev] Shutting down...\");\n forceExitTimer = setTimeout(forceExit, 5000);\n forceExitTimer.unref?.();\n controls?.requestShutdown();\n };\n const handleSignal = requestShutdownEscalating;\n\n const program = Effect.scoped(\n runDevSession(configDir, orchestrator, (sessionControls) => {\n controls = sessionControls;\n sessionControls.requestShutdownEscalating = requestShutdownEscalating;\n sessionControls.rearmForceExitTimer = () => {\n if (forceExitTimer) clearTimeout(forceExitTimer);\n forceExitTimer = setTimeout(forceExit, 5000);\n forceExitTimer.unref?.();\n };\n sessionControls.forceExit = forceExit;\n }),\n ).pipe(\n Effect.provide(\n Layer.mergeAll(\n ServiceDescriptorMapLive(services),\n DevRuntimeConfigLive(runtimeConfig),\n DevGeneratedEnvLive(envGenerated),\n ShellEnvLive(shellEnv),\n ),\n ),\n Effect.catchDefect((defect) =>\n Effect.logError(\"[Dev] Unhandled defect in orchestrator:\", defect).pipe(\n Effect.andThen(Effect.die(defect)),\n ),\n ),\n );\n\n process.on(\"SIGINT\", handleSignal);\n process.on(\"SIGTERM\", handleSignal);\n\n void Effect.runPromiseExit(program)\n .then((exit) => {\n clearInterval(orphanWatch);\n if (forceExitTimer) clearTimeout(forceExitTimer);\n process.exit(Exit.isSuccess(exit) ? 0 : 1);\n })\n .catch((error: unknown) => {\n clearInterval(orphanWatch);\n if (forceExitTimer) clearTimeout(forceExitTimer);\n console.error(\"[Dev] Failed to observe application exit:\", error);\n process.exit(1);\n });\n};\n\nexport const devApp = runApp;\n\nexport const startApp = runApp;\n"],"mappings":";;;;;;;;;;;;;;AAuCA,MAAM,yBAAyB,cAA4B;CACzD,IAAI;EACF,MAAM,UAAU,aAAa,CAAC,CAAC,QAC5B,UAAU,MAAM,MAAM,KAAK,MAAM,cAAc,aAAa,CAAC,WAAW,MAAM,GAAG,CACpF;EACA,IAAI,QAAQ,WAAW,GAAG;EAC1B,MAAM,SAAmB,CAAC;EAC1B,KAAK,MAAM,SAAS,SAClB,KAAK,MAAM,YAAY,MAAM,aAAa,CAAC,GAAG;GAC5C,IAAI,aAAa,QAAQ,KAAK;GAC9B,IAAI,WAAW,QAAQ,GAAG;IACxB,UAAU,QAAQ;IAClB,OAAO,KAAK,QAAQ;GACtB;EACF;EAEF,IAAI,OAAO,SAAS,GAClB,QAAQ,MACN,gBAAgB,OAAO,OAAO,oDAAoD,OAAO,KAAK,IAAI,GACpG;EAEF,MAAM,WAAW,IAAI,IAAI,QAAQ,KAAK,UAAU,MAAM,GAAG,CAAC;EAC1D,cAAc,aAAa,CAAC,CAAC,QAAQ,UAAU,CAAC,SAAS,IAAI,MAAM,GAAG,CAAC,CAAC;CAC1E,QAAQ,CAER;AACF;AAEA,MAAM,+BAAwC;CAC5C,OAAO,QAAQ,MAAM,UAAU,QAAQ,QAAQ,OAAO,UAAU;AAClE;AAEA,MAAM,gBAAgB;CAAC;CAAM;CAAQ;CAAO;CAAU;CAAc;AAAM;AAE1E,MAAM,eAAe,aAAiC;CACpD,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,MAAM,GAAG,MAAM;EAClC,MAAM,OAAO,EAAE,WAAW,SAAS,IAC/B,cAAc,QAAQ,QAAQ,IAC9B,cAAc,QAAQ,CAAC;EAC3B,MAAM,OAAO,EAAE,WAAW,SAAS,IAC/B,cAAc,QAAQ,QAAQ,IAC9B,cAAc,QAAQ,CAAC;EAC3B,IAAI,SAAS,MAAM,SAAS,IAAI,OAAO;EACvC,IAAI,SAAS,IAAI,OAAO;EACxB,IAAI,SAAS,IAAI,OAAO;EACxB,OAAO,OAAO;CAChB,CAAC;AACH;AAWA,MAAa,iBACX,WACA,cACA,oBAEA,OAAO,IAAI,aAAa;CACtB,sBAAsB,SAAS;CAC/B,MAAM,WAAW,OAAO;CACxB,MAAM,gBAAgB,OAAO;CAC7B,MAAM,kBAAkB,YAAY,aAAa,QAAQ;CACzD,MAAM,mBAAsC,iBAC1C,iBACA,UACA,aAAa,IACf;CAEA,IAAI,QAAQ,cAAc,OAAO,CAAC,GAAG;EACnC,OAAO,OAAO,SACZ,0CAA0C,aAAa,SAAS,KAAK,IAAI,GAC3E;EACA,OAAO,OAAO,SAAS,oCAAoC,gBAAgB,KAAK,IAAI,GAAG;EACvF,OAAO,OAAO,SAAS,kCAAkC,CAAC,GAAG,SAAS,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG;EAC1F,OAAO,OAAO,SACZ,qCAAqC,iBAAiB,KAAK,MAAM,GAAG,EAAE,KAAK,GAAG,EAAE,QAAQ,CAAC,CAAC,KAAK,IAAI,GACrG;CACF;CAEA,MAAM,SAAS,OAAO,OAAO,cAC3B,gBAAgB,WAAW,aAAa,WAAW,CACrD;CAEA,MAAM,WAAW,OAAO,SAAS,KAAW;CAE5C,MAAM,gBAAgB,OAAO,OAAO,QAAQ;CAC5C,MAAM,WAA+B;EACnC,uBAAuB;GACrB,AAAK,OAAO,eAAe,aAAa,CAAC,CAAC,SAAS,QAAQ,UAAU,MAAS,CAAC;EACjF;EACA,qBAAqB,CAAC;EACtB,iCAAiC,CAAC;EAClC,iBAAiB,CAAC;EAClB,mBAAmB,CAAC;EACpB,2BAA2B,CAAC;CAC9B;CAEA,kBAAkB,QAAQ;CAE1B,MAAM,mBAAmB,cAAc,qBAAqB,MAAM;CAClE,IAAI,aAAuB,CAAC;CAC5B,IAAI,CAAC,kBAAkB;EACrB,MAAM,WAAmC,CAAC;EAC1C,MAAM,WAAW,KAAa,UAAqC;GACjE,IAAI,SAAS,MAAM,SAAS,OAAO;EACrC;EACA,QAAQ,QAAQ,cAAc,KAAK,IAAI;EACvC,QAAQ,OAAO,cAAc,IAAI,IAAI;EACrC,QAAQ,MAAM,cAAc,GAAG,IAAI;EACnC,QAAQ,QAAQ,cAAc,MAAM,IAAI;EACxC,IAAI,cAAc,SAChB,KAAK,MAAM,CAAC,IAAI,WAAW,OAAO,QAAQ,cAAc,OAAO,GAAG;GAChE,IAAI,CAAC,wBAAwB,cAAc,MAAM,IAAI,MAAM,GACzD,QAAQ,UAAU,MAAM,OAAO,IAAI;GAErC,QAAQ,aAAa,MAAM,OAAO,IAAI,IAAI;EAC5C;EAEF,mBAAmB;GACjB,KAAK,QAAQ;GACb;GACA,OAAO;GACP,WAAW,OAAO,MAAM;GACxB,aAAa,aAAa;EAC5B,CAAC;EACD,aAAa,OAAO,OAAO,QAAQ;CACrC;CAEA,IAAI,OAAiC;CACrC,IAAI,mBAAmB;CAEvB,MAAM,WAAW,gBAAgB;CACjC,MAAM,UAAsB,CAAC;CAC7B,MAAM,WAAW,kBAAkB;EACjC,OAAO;EACP,OAAO;GACL,UAAU,UAAU;IAClB,MAAM,OAAO,MAAM,QAAQ,MAAM,MAAM,MAAM,UAAU,OAAO;GAChE;GACA,OAAO,UAAU;IACf,IAAI,aAAa,QAAQ;IACzB,AAAK,OAAO,MAAM,KAAK;GACzB;GACA,SAAS,UAAU;IACjB,QAAQ,KAAK,KAAK;GACpB;EACF;CACF,CAAC;CAED,MAAM,iBAAiB,uBAAuB,KAAK,aAAa,gBAAgB;CAChF,OAAO,kBACL,kBACA,aAAa,aACb,aAAa,WACP,SAAS,0BAA0B,SACnC;EACJ,mBAAmB;EACnB,SAAS,0BAA0B;CACrC,GACA;EAAE,aAAa;EAAgB,mBAAmB,SAAS,UAAU;CAAE,CACzE;CACA,SAAS,oBAAoB;EAC3B,IAAI,gBAAgB,MAAM,QAAQ;CACpC;CAEA,MAAM,YAA8B;EAClC,WAAW,MAAM,QAAQ,YAAY;GACnC,MAAM,cAAc,MAAM,QAAQ,OAAO;EAC3C;EACA,QAAQ,MAAM,MAAM,YAAY;GAC9B,SAAS,OAAO;IAAE,QAAQ;IAAM;IAAM;GAAQ,CAAC;EACjD;CACF;CAEA,MAAM,UAA2B,CAAC;CAElC,SAAS,sBAAsB;EAC7B,KAAK,MAAM,UAAU,SAAS;GAC5B,IAAI,OAAO,QAAQ,QAAW;GAC9B,UAAU,OAAO,GAAG;EACtB;CACF;CAEA,OAAO,OAAO,mBACZ,OAAO,IAAI,aAAa;EACtB,SAAS,oBAAoB;EAE7B,OAAO,OAAO,QAAQ,UAAU,MAAM,EAAE,KAAK,KAAK,OAAO,MAAM,GAAG,EAChE,aAAa,YACf,CAAC;EAED,OAAO,OAAO,MAAM,YAAY;EAEhC,KAAK,MAAM,QAAQ,YAEjB,IAAI,EAAC,OADmB,kBAAkB,IAAI,IAC/B;GACb,MAAM,QAAQ,OAAO,YAAY,IAAI;GACrC,OAAO,OAAO,SACZ,cAAc,KAAK,6BACjB,QACI,UAAU,MAAM,IAAI,IAAI,MAAM,QAAQ,KACtC,uCAER;EACF;EAGF,IAAI,CAAC,kBACH,OAAO,OAAO,WAAW;GACvB,IAAI;IACF,cAAc,QAAQ,GAAG;GAC3B,QAAQ,CAER;EACF,CAAC;EAGH,SAAS,MAAM;EAEf,MAAM,QAAQ;EAEd,IAAI,kBAAkB;GACpB,MAAM,MAAM,OAAO,MAAM;GACzB,MAAM,YAAY,QAAQ,EAAE,EAAE,aAAa;GAC3C,OAAO,OAAO,IAAI,EAAE;GACpB,OAAO,OAAO,IAAI,IAAI,OAAO,EAAE,CAAC;GAChC,OAAO,OAAO,IAAI,mBAAmB,aAAa,aAAa;GAC/D,OAAO,OAAO,IAAI,cAAc,SAAS,UAAU,SAAS,WAAW,SAAS,CAAC,GAAG;GACpF,OAAO,OAAO,IAAI,uBAAuB,QAAQ,OAAO,WAAW,SAAS,EAAE;GAC9E,OAAO,OAAO,IAAI,IAAI,OAAO,EAAE,CAAC;GAChC,OAAO,OAAO,IAAI,EAAE;GACpB,KAAK,MAAM,SAAS,SAClB,OAAO,OAAO,IAAI,cAAc,KAAK,CAAC;GAExC,OAAO,OAAO,IAAI,EAAE;GACpB,OAAO,OAAO,IAAI,IAAI,OAAO,EAAE,CAAC;GAChC,OAAO,OAAO,IAAI,yBAAyB,OAAO,SAAS;GAC3D,OAAO,OAAO,IAAI,IAAI,OAAO,EAAE,CAAC;GAChC,OAAO,OAAO,IAAI,EAAE;EACtB;CACF,CAAC,CACH;CAEA,MAAM,gBAAgB,QAAgB;EACpC,MAAM,eAAe,QAAQ,SAAS,aAAa,OAAO;EAC1D,OAAO,eAAe,KAAK,WAAW,YAAY,CAAC,CAAC,KAClD,OAAO,KAAK,WAAW,OAAO,WAAW,QAAQ,KAAK,MAAM,CAAC,CAAC,GAC9D,OAAO,SAAS,WACd,OAAO,eAAe,OAAO,QAAQ,MAAM,SAAS,OAAO,KAAK,KAAK,OAAO,MAAM,CAAC,CACrF,GACA,OAAO,UAAU,QACf,OAAO,WAAW;GAChB,UAAU,MAAM,KAAK,oBAAoB,OAAO,GAAG,KAAK,IAAI;GAC5D,UAAU,SAAS,KAAK,OAAO;EACjC,CAAC,CACH,GACA,OAAO,qBAEF;GACC,MAAM;GACN,KAAK;GACL,MAAM,OAAO;GACb,cAAc,OAAO;GACrB,aAAa,OAAO;EACtB,EACJ,CACF;CACF;CAEA,MAAM,cAAc,aAClB,OAAO,QAAQ,UAAU,cAAc,EAAE,aAAa,YAAY,CAAC;CAErE,MAAM,cAAc,KAAa,WAC/B,OAAO,aAAa,KAClB,OAAO,QAAQ,aAAa,GAC5B,OAAO,OAAO,QACZ,OAAO,WAAW;EAChB,UAAU,MACR,KACA,wBAAwB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,KACvE,IACF;CACF,CAAC,CACH,CACF;CAEF,MAAM,kBAAkB,gBAAgB,QAAQ,QAAQ,QAAQ,MAAM;CACtE,MAAM,eAAe,gBAAgB,QAAQ,QAAQ,QAAQ,MAAM;CAEnE,MAAM,eAAe,OAAO,IAAI,aAAa;EAC3C,MAAM,iBAAiB,OAAO,WAAW,eAAe;EAExD,OAAO,OAAO,QACZ,eAAe,KAAK,QAAQ,WAAW;GACrC;GACA,KAAK,gBAAgB,UAAU,OAAO;EACxC,EAAE,IACD,EAAE,QAAQ,UAAU,WAAW,KAAK,MAAM,GAC3C,EAAE,aAAa,YAAY,CAC7B;EAEA,MAAM,cAAc,OAAO,WAAW,YAAY;EAElD,OAAO,OAAO,QACZ,YAAY,KAAK,QAAQ,WAAW;GAClC;GACA,KAAK,aAAa,UAAU,OAAO;EACrC,EAAE,IACD,EAAE,QAAQ,UAAU,WAAW,KAAK,MAAM,GAC3C,EAAE,aAAa,YAAY,CAC7B;EAEA,OAAO;GAAE;GAAgB;EAAY;CACvC,CAAC;CAED,MAAM,UAAU,OAAO,OAAO,UAC5B,cACA,SAAS,MAAM,QAAQ,CAAC,CAAC,KAAK,OAAO,GAAG,IAAI,CAAC,CAC/C;CAEA,IAAI,YAAY,MAAM;CAItB,MAAM,YAAY,CAFE,GAAG,QAAQ,gBAAgB,GAAG,QAAQ,WAE/B,CAAC,CACzB,KAAK,WAAW,OAAO,OAAO,GAAG,CAAC,CAAC,CACnC,QAAQ,QAAQ,OAAO,SAAS,GAAG,KAAK,MAAM,KAAK,QAAQ,QAAQ,GAAG;CAEzE,IAAI,CAAC,oBAAoB,UAAU,SAAS,GAC1C,OAAO,OAAO,WAAW;EACvB,IAAI;GACF,gBAAgB,QAAQ,KAAK,SAAS;EACxC,QAAQ,CAER;CACF,CAAC;CAGH,OAAO,SAAS,MAAM,QAAQ;AAChC,CAAC;AAEH,MAAM,UACJ,WACA,cACA,UACA,eACA,cACA,aACG;CACH,IAAI,WAAsC;CAC1C,IAAI,cAAc;CAClB,IAAI,iBAAuD;CAE3D,MAAM,kBAAkB;EACtB,UAAU,YAAY;EACtB,QAAQ,IAAI,oBAAoB;EAChC,UAAU,cAAc;EACxB,QAAQ,KAAK,CAAC;CAChB;CAQA,MAAM,cAAc,QAAQ;CAC5B,MAAM,cAAc,kBAAkB;EACpC,IAAI,QAAQ,SAAS,aAAa;GAChC,QAAQ,MAAM,qEAAqE;GACnF,UAAU;EACZ;CACF,GAAG,GAAG;CACN,YAAY,QAAQ;CAEpB,MAAM,kCAAkC;EACtC;EACA,IAAI,cAAc,GAAG;GACnB,UAAU;GACV;EACF;EACA,UAAU,YAAY;EACtB,QAAQ,IAAI,0BAA0B;EACtC,iBAAiB,WAAW,WAAW,GAAI;EAC3C,eAAe,QAAQ;EACvB,UAAU,gBAAgB;CAC5B;CACA,MAAM,eAAe;CAErB,MAAM,UAAU,OAAO,OACrB,cAAc,WAAW,eAAe,oBAAoB;EAC1D,WAAW;EACX,gBAAgB,4BAA4B;EAC5C,gBAAgB,4BAA4B;GAC1C,IAAI,gBAAgB,aAAa,cAAc;GAC/C,iBAAiB,WAAW,WAAW,GAAI;GAC3C,eAAe,QAAQ;EACzB;EACA,gBAAgB,YAAY;CAC9B,CAAC,CACH,CAAC,CAAC,KACA,OAAO,QACL,MAAM,SACJ,yBAAyB,QAAQ,GACjC,qBAAqB,aAAa,GAClC,oBAAoB,YAAY,GAChC,aAAa,QAAQ,CACvB,CACF,GACA,OAAO,aAAa,WAClB,OAAO,SAAS,2CAA2C,MAAM,CAAC,CAAC,KACjE,OAAO,QAAQ,OAAO,IAAI,MAAM,CAAC,CACnC,CACF,CACF;CAEA,QAAQ,GAAG,UAAU,YAAY;CACjC,QAAQ,GAAG,WAAW,YAAY;CAElC,AAAK,OAAO,eAAe,OAAO,CAAC,CAChC,MAAM,SAAS;EACd,cAAc,WAAW;EACzB,IAAI,gBAAgB,aAAa,cAAc;EAC/C,QAAQ,KAAK,KAAK,UAAU,IAAI,IAAI,IAAI,CAAC;CAC3C,CAAC,CAAC,CACD,OAAO,UAAmB;EACzB,cAAc,WAAW;EACzB,IAAI,gBAAgB,aAAa,cAAc;EAC/C,QAAQ,MAAM,6CAA6C,KAAK;EAChE,QAAQ,KAAK,CAAC;CAChB,CAAC;AACL;AAEA,MAAa,SAAS;AAEtB,MAAa,WAAW"}