@camstack/core 0.1.10 → 0.1.12

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,"sources":["../src/deps/binary-downloader.ts","../src/deps/ffmpeg-downloader.ts","../src/deps/python-downloader.ts","../src/events/event-bus.ts","../src/download/model-downloader.ts","../src/download/model-download-service.ts","../src/python/python-env-manager.ts","../src/pipeline/pipeline-validator.ts","../src/pipeline/pipeline-runner.ts","../src/process/managed-process.ts","../src/process/process-manager.ts","../src/network/network-quality.ts","../src/repl/repl-engine.ts","../src/agent/agent-registry.ts","../src/agent/task-dispatcher.ts","../src/agent/agent-client.ts","../src/agent/agent-task-runner.ts","../src/agent/pipeline-task-handlers.ts","../src/lifecycle/lifecycle-state-machine.ts","../src/feature/feature-manager.ts","../src/events/system-event-bus.ts","../src/logging/log-ring-buffer.ts","../src/logging/scoped-logger.ts","../src/logging/log-manager.ts","../src/storage/storage-manager.ts","../src/auth/auth-manager.ts","../src/auth/api-key-manager.ts","../src/auth/user-manager.ts","../src/auth/scoped-token-manager.ts","../src/notification/notification-service.ts","../src/notification/toast-service.ts","../src/addon-routes/addon-route-registry.ts","../src/device/device-registry.ts","../src/device/capability-resolver.ts","../src/tls/cert-manager.ts","../src/addon/addon-api-factory.ts","../src/platform/platform-scorer.ts","../src/platform/inference-config-resolver.ts","../src/provider/provider-manager.ts"],"sourcesContent":["import { existsSync, mkdirSync, chmodSync, createWriteStream, unlinkSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { pipeline } from 'node:stream/promises'\nimport { Readable } from 'node:stream'\nimport { execFileSync } from 'node:child_process'\nimport type { IScopedLogger } from '@camstack/types'\n\nexport interface PlatformInfo {\n readonly platform: NodeJS.Platform\n readonly arch: NodeJS.Architecture\n}\n\nexport function getPlatformInfo(): PlatformInfo {\n return {\n platform: process.platform,\n arch: process.arch,\n }\n}\n\nexport function buildBinaryPath(dataDir: string, name: string, platform?: string): string {\n const ext = (platform ?? process.platform) === 'win32' ? '.exe' : ''\n return join(dataDir, 'deps', `${name}${ext}`)\n}\n\n/** Check if a binary exists in PATH */\nexport function findInPath(name: string): string | null {\n try {\n execFileSync(name, ['--version'], { stdio: 'pipe', timeout: 5000 })\n return name\n } catch {\n return null\n }\n}\n\nexport interface DownloadOptions {\n readonly name: string\n readonly url: string\n readonly targetDir: string\n readonly targetName: string\n readonly logger: IScopedLogger\n readonly isArchive?: boolean\n readonly archiveFormat?: 'zip' | 'tar.gz' | 'tar.xz'\n /** Relative path within archive to the binary (e.g., 'ffmpeg-6.1/bin/ffmpeg') */\n readonly archiveInnerPath?: string\n}\n\n/**\n * Download a binary to the target directory.\n * Handles archives (zip, tar.gz, tar.xz) and raw binaries.\n */\nexport async function downloadBinary(opts: DownloadOptions): Promise<string> {\n const { name, url, targetDir, targetName, logger, isArchive, archiveFormat, archiveInnerPath } = opts\n const targetPath = join(targetDir, targetName)\n\n if (existsSync(targetPath)) {\n logger.debug(`${name} binary already exists at ${targetPath}`)\n return targetPath\n }\n\n mkdirSync(targetDir, { recursive: true })\n\n logger.info(`Downloading ${name} from ${url}`)\n const response = await fetch(url, { redirect: 'follow' })\n if (!response.ok || !response.body) {\n throw new Error(`Failed to download ${name}: ${response.status} ${response.statusText}`)\n }\n\n if (isArchive) {\n const ext = archiveFormat ?? 'tar.gz'\n const tmpArchive = join(targetDir, `${name}-download.${ext}`)\n const nodeStream = Readable.fromWeb(response.body as any)\n await pipeline(nodeStream, createWriteStream(tmpArchive))\n\n // Extract\n const tmpExtractDir = join(targetDir, `${name}-extract`)\n mkdirSync(tmpExtractDir, { recursive: true })\n\n if (ext === 'zip') {\n try {\n execFileSync('unzip', ['-o', '-q', tmpArchive, '-d', tmpExtractDir], { stdio: 'pipe' })\n } catch {\n execFileSync('tar', ['-xf', tmpArchive, '-C', tmpExtractDir], { stdio: 'pipe' })\n }\n } else if (ext === 'tar.xz') {\n execFileSync('tar', ['-xJf', tmpArchive, '-C', tmpExtractDir], { stdio: 'pipe' })\n } else {\n execFileSync('tar', ['-xzf', tmpArchive, '-C', tmpExtractDir], { stdio: 'pipe' })\n }\n\n // Copy binary from archive\n if (archiveInnerPath) {\n const { copyFileSync } = await import('node:fs')\n const sourcePath = join(tmpExtractDir, archiveInnerPath)\n if (!existsSync(sourcePath)) {\n throw new Error(`Binary not found in archive at ${archiveInnerPath}`)\n }\n copyFileSync(sourcePath, targetPath)\n }\n\n // Cleanup\n unlinkSync(tmpArchive)\n const { rmSync } = await import('node:fs')\n rmSync(tmpExtractDir, { recursive: true, force: true })\n } else {\n // Direct binary download\n const nodeStream = Readable.fromWeb(response.body as any)\n await pipeline(nodeStream, createWriteStream(targetPath))\n }\n\n chmodSync(targetPath, 0o755)\n logger.info(`${name} downloaded to ${targetPath}`)\n return targetPath\n}\n\n/**\n * Ensure a binary is available. Checks:\n * 1. Target path (already downloaded)\n * 2. System PATH\n * 3. Download from URL\n */\nexport async function ensureBinary(opts: {\n readonly name: string\n readonly targetDir: string\n readonly downloadUrl: string\n readonly logger: IScopedLogger\n readonly isArchive?: boolean\n readonly archiveFormat?: 'zip' | 'tar.gz' | 'tar.xz'\n readonly archiveInnerPath?: string\n}): Promise<string> {\n const ext = process.platform === 'win32' ? '.exe' : ''\n const targetName = `${opts.name}${ext}`\n const targetPath = join(opts.targetDir, targetName)\n\n // 1. Already downloaded\n if (existsSync(targetPath)) {\n opts.logger.debug(`${opts.name} found at ${targetPath}`)\n return targetPath\n }\n\n // 2. System PATH\n const inPath = findInPath(opts.name)\n if (inPath) {\n opts.logger.info(`${opts.name} found in system PATH`)\n return inPath\n }\n\n // 3. Download\n return downloadBinary({\n name: opts.name,\n url: opts.downloadUrl,\n targetDir: opts.targetDir,\n targetName,\n logger: opts.logger,\n isArchive: opts.isArchive,\n archiveFormat: opts.archiveFormat,\n archiveInnerPath: opts.archiveInnerPath,\n })\n}\n","/**\n * Download ffmpeg static build for the current platform.\n *\n * Sources:\n * - Linux: https://johnvansickle.com/ffmpeg/ (static builds)\n * - macOS: https://evermeet.cx/ffmpeg/ or homebrew\n *\n * Using BtbN's GitHub releases as they cover both platforms:\n * https://github.com/BtbN/FFmpeg-Builds/releases\n */\nimport { join } from 'node:path'\nimport type { IScopedLogger } from '@camstack/types'\nimport { ensureBinary } from './binary-downloader.js'\n\nconst FFMPEG_VERSION = '7.1'\n\nexport function getFfmpegDownloadUrl(platform: string, arch: string): string {\n switch (platform) {\n case 'linux': {\n const archMap: Record<string, string> = { x64: 'amd64', arm64: 'arm64' }\n const a = archMap[arch]\n if (!a) throw new Error(`Unsupported Linux architecture: ${arch}`)\n // John Van Sickle static builds — well-tested, widely used\n return `https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-${a}-static.tar.xz`\n }\n case 'darwin': {\n const archMap: Record<string, string> = { arm64: 'arm64', x64: 'amd64' }\n const a = archMap[arch]\n if (!a) throw new Error(`Unsupported macOS architecture: ${arch}`)\n // macOS static builds from osxexperts (maintained, universal builds)\n return `https://www.osxexperts.net/ffmpeg${FFMPEG_VERSION.replace('.', '')}arm.zip`\n }\n default:\n throw new Error(`Unsupported platform: ${platform}`)\n }\n}\n\nexport function getFfmpegArchiveInfo(platform: string): {\n isArchive: boolean\n archiveFormat: 'zip' | 'tar.gz' | 'tar.xz'\n archiveInnerPath: string\n} {\n switch (platform) {\n case 'linux':\n return {\n isArchive: true,\n archiveFormat: 'tar.xz',\n archiveInnerPath: `ffmpeg-${FFMPEG_VERSION}-amd64-static/ffmpeg`,\n }\n case 'darwin':\n return {\n isArchive: true,\n archiveFormat: 'zip',\n archiveInnerPath: 'ffmpeg',\n }\n default:\n throw new Error(`Unsupported platform: ${platform}`)\n }\n}\n\n/**\n * Ensure ffmpeg binary is available.\n * Checks: deps dir → system PATH → download.\n */\nexport async function ensureFfmpeg(dataDir: string, logger: IScopedLogger): Promise<string> {\n const depsDir = join(dataDir, 'deps')\n const platform = process.platform\n const arch = process.arch\n\n const archiveInfo = getFfmpegArchiveInfo(platform)\n\n return ensureBinary({\n name: 'ffmpeg',\n targetDir: depsDir,\n downloadUrl: getFfmpegDownloadUrl(platform, arch),\n logger,\n ...archiveInfo,\n })\n}\n","/**\n * Download portable Python (headless) from bjia56/portable-python.\n *\n * Source: https://github.com/bjia56/portable-python\n *\n * Advantages over python-build-standalone:\n * - macOS universal2 binary (arm64+x86_64 in one)\n * - Lighter (~24-28MB headless zip)\n * - glibc 2.17 minimum (better compat)\n * - Headless variant excludes tkinter/UI (ideal for ML inference)\n *\n * After extraction, the binary is at: python/bin/python3\n */\nimport { join } from 'node:path'\nimport { existsSync, mkdirSync, chmodSync } from 'node:fs'\nimport { execFileSync } from 'node:child_process'\nimport { pipeline } from 'node:stream/promises'\nimport { Readable } from 'node:stream'\nimport { createWriteStream } from 'node:fs'\nimport type { IScopedLogger } from '@camstack/types'\nimport { findInPath } from './binary-downloader.js'\n\nexport const PYTHON_VERSION = '3.12.12'\nconst PP_BASE = `https://github.com/bjia56/portable-python/releases/download/cpython-v${PYTHON_VERSION}-build.0`\n\nexport function getPythonDownloadUrl(platform: string, arch: string): string {\n switch (platform) {\n case 'linux': {\n const archMap: Record<string, string> = { x64: 'x86_64', arm64: 'aarch64' }\n const a = archMap[arch]\n if (!a) throw new Error(`Unsupported Linux architecture for Python: ${arch}`)\n return `${PP_BASE}/python-headless-${PYTHON_VERSION}-linux-${a}.zip`\n }\n case 'darwin': {\n // universal2 covers both arm64 and x86_64\n return `${PP_BASE}/python-headless-${PYTHON_VERSION}-darwin-universal2.zip`\n }\n default:\n throw new Error(`Unsupported platform for portable Python: ${platform}`)\n }\n}\n\n/**\n * Ensure a portable Python is available.\n * Checks: embedded python → system PATH → download portable.\n *\n * Returns the path to the python3 binary.\n */\nexport async function ensurePython(dataDir: string, logger: IScopedLogger): Promise<string | null> {\n const pythonDir = join(dataDir, 'deps', 'python')\n const pythonBin = join(pythonDir, 'bin', 'python3')\n\n // 1. Already downloaded\n if (existsSync(pythonBin)) {\n logger.debug(`Portable Python found at ${pythonBin}`)\n return pythonBin\n }\n\n // 2. System PATH\n for (const name of ['python3', 'python']) {\n const inPath = findInPath(name)\n if (inPath) {\n logger.info(`Python found in system PATH: ${name}`)\n return inPath\n }\n }\n\n // 3. Download portable python\n logger.info(`Downloading portable Python ${PYTHON_VERSION} (headless)...`)\n\n const depsDir = join(dataDir, 'deps')\n mkdirSync(depsDir, { recursive: true })\n\n const url = getPythonDownloadUrl(process.platform, process.arch)\n const tmpArchive = join(depsDir, 'python-download.zip')\n\n logger.info(` Source: ${url}`)\n\n const response = await fetch(url, { redirect: 'follow' })\n if (!response.ok || !response.body) {\n logger.warn(`Failed to download Python: ${response.status} — ML detection will not be available`)\n return null\n }\n\n const nodeStream = Readable.fromWeb(response.body as any)\n await pipeline(nodeStream, createWriteStream(tmpArchive))\n\n // Extract — zip contains a 'python/' directory\n try {\n execFileSync('unzip', ['-o', '-q', tmpArchive, '-d', depsDir], { stdio: 'pipe' })\n } catch {\n // Fallback: some minimal Linux installs don't have unzip\n execFileSync('python3', ['-m', 'zipfile', '-e', tmpArchive, depsDir], { stdio: 'pipe' })\n }\n\n // Cleanup\n const { unlinkSync } = await import('node:fs')\n unlinkSync(tmpArchive)\n\n if (!existsSync(pythonBin)) {\n logger.warn('Python extraction succeeded but binary not found at expected path')\n return null\n }\n\n chmodSync(pythonBin, 0o755)\n logger.info(`Portable Python ${PYTHON_VERSION} installed at ${pythonBin}`)\n return pythonBin\n}\n\n/**\n * Install Python packages into the portable Python environment.\n */\nexport async function installPythonPackages(\n pythonPath: string,\n packages: readonly string[],\n logger: IScopedLogger,\n): Promise<void> {\n if (packages.length === 0) return\n\n logger.info(`Installing Python packages: ${packages.join(', ')}`)\n try {\n execFileSync(pythonPath, ['-m', 'pip', 'install', '--quiet', ...packages], {\n stdio: 'pipe',\n timeout: 300_000, // 5 minutes for large packages like torch\n })\n logger.info('Python packages installed successfully')\n } catch (err) {\n logger.error(`Failed to install Python packages: ${err instanceof Error ? err.message : err}`)\n throw err\n }\n}\n","type EventCallback<T = unknown> = (data: T) => void\n\nexport class EventBus {\n private listeners = new Map<string, Set<EventCallback>>()\n\n on<T = unknown>(event: string, callback: EventCallback<T>): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set())\n const set = this.listeners.get(event)!\n set.add(callback as EventCallback)\n return () => set.delete(callback as EventCallback)\n }\n\n emit<T = unknown>(event: string, data: T): void {\n const set = this.listeners.get(event)\n if (!set) return\n for (const cb of set) {\n try { cb(data) } catch { /* don't let one listener break others */ }\n }\n }\n\n once<T = unknown>(event: string, callback: EventCallback<T>): () => void {\n const unsub = this.on<T>(event, (data) => {\n unsub()\n callback(data)\n })\n return unsub\n }\n\n removeAllListeners(event?: string): void {\n if (event) this.listeners.delete(event)\n else this.listeners.clear()\n }\n\n listenerCount(event: string): number {\n return this.listeners.get(event)?.size ?? 0\n }\n}\n","import type { ModelDownloadOptions, ModelDownloadResult } from '@camstack/types'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { createHash } from 'node:crypto'\n\n/**\n * Download a single file from a URL to a destination path.\n * Uses native fetch() (Node 22+) which handles redirects natively.\n * Streams to disk with optional progress callback.\n * Returns the destination path. Skips download if file already exists.\n */\nexport async function downloadFile(\n url: string,\n destPath: string,\n onProgress?: (downloaded: number, total: number) => void,\n): Promise<string> {\n if (fs.existsSync(destPath)) return destPath\n\n fs.mkdirSync(path.dirname(destPath), { recursive: true })\n\n // Atomic download: write to .downloading tmp, rename on success\n const tmpPath = destPath + '.downloading'\n\n try {\n const response = await fetch(url, {\n redirect: 'follow',\n headers: { 'User-Agent': 'CamStack/1.0' },\n })\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} downloading ${url}`)\n }\n if (!response.body) {\n throw new Error(`No response body from ${url}`)\n }\n\n const total = parseInt(response.headers.get('content-length') ?? '0', 10)\n let downloaded = 0\n\n const fileStream = fs.createWriteStream(tmpPath)\n const reader = response.body.getReader()\n\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n fileStream.write(value)\n downloaded += value.length\n onProgress?.(downloaded, total)\n }\n } finally {\n fileStream.end()\n await new Promise<void>((resolve, reject) => {\n fileStream.on('finish', resolve)\n fileStream.on('error', reject)\n })\n }\n\n fs.renameSync(tmpPath, destPath)\n return destPath\n } catch (err) {\n // Clean up partial download\n try { fs.unlinkSync(tmpPath) } catch { /* ignore */ }\n throw err\n }\n}\n\n/**\n * Fetch JSON from a URL using native fetch().\n */\nexport async function fetchJson(url: string): Promise<unknown> {\n const response = await fetch(url, {\n redirect: 'follow',\n headers: { 'User-Agent': 'CamStack/1.0' },\n })\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} fetching ${url}`)\n }\n return response.json()\n}\n\n/**\n * Download a model with fallback URLs and optional SHA256 verification.\n * Legacy API preserved for backward compatibility -- delegates to downloadFile().\n */\nexport async function downloadModel(options: ModelDownloadOptions): Promise<ModelDownloadResult> {\n const { url, fallbackUrls = [], destDir, filename, expectedSha256, onProgress } = options\n\n const fname = filename ?? url.split('/').pop() ?? 'model.bin'\n const destPath = path.join(destDir, fname)\n\n // Check cache\n if (fs.existsSync(destPath)) {\n return { filePath: destPath, downloadedBytes: 0, fromCache: true }\n }\n\n fs.mkdirSync(destDir, { recursive: true })\n\n const urls = [url, ...fallbackUrls]\n let lastError: Error | null = null\n\n for (const tryUrl of urls) {\n try {\n await downloadFile(tryUrl, destPath, onProgress)\n\n // Verify SHA256 if provided\n if (expectedSha256) {\n const hash = await computeSha256(destPath)\n if (hash !== expectedSha256) {\n fs.unlinkSync(destPath)\n throw new Error(`SHA256 mismatch: expected ${expectedSha256}, got ${hash}`)\n }\n }\n\n const stat = fs.statSync(destPath)\n return { filePath: destPath, downloadedBytes: stat.size, fromCache: false }\n } catch (e) {\n lastError = e as Error\n if (fs.existsSync(destPath)) fs.unlinkSync(destPath)\n }\n }\n\n throw lastError ?? new Error(`Failed to download model from ${url}`)\n}\n\nasync function computeSha256(filePath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const hash = createHash('sha256')\n const stream = fs.createReadStream(filePath)\n stream.on('data', (chunk) => hash.update(chunk))\n stream.on('end', () => resolve(hash.digest('hex')))\n stream.on('error', reject)\n })\n}\n","import type { ModelCatalogEntry, ModelFormat, IAddonModelManager, ModelExtraFile } from '@camstack/types'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { downloadFile, fetchJson } from './model-downloader.js'\n\n/**\n * Unified model download service.\n *\n * Handles downloading model files and extra files (labels, dicts) from a\n * catalog of ModelCatalogEntry items. Supports single-file models and\n * directory bundles (e.g., .mlpackage for CoreML).\n *\n * Addons use this via `context.models.ensure(modelId, format)`.\n */\nexport class ModelDownloadService implements IAddonModelManager {\n private readonly catalog: ReadonlyMap<string, ModelCatalogEntry>\n\n constructor(\n private readonly modelsDir: string,\n catalog: readonly ModelCatalogEntry[],\n private readonly onProgress?: (modelId: string, downloaded: number, total: number) => void,\n ) {\n const map = new Map<string, ModelCatalogEntry>()\n for (const entry of catalog) {\n map.set(entry.id, entry)\n }\n this.catalog = map\n }\n\n /**\n * Ensure a model (and its extra files) is downloaded.\n * Returns the local filesystem path to the model file/directory.\n */\n async ensure(modelId: string, format?: ModelFormat): Promise<string> {\n const entry = this.catalog.get(modelId)\n if (!entry) {\n throw new Error(`ModelDownloadService: unknown model \"${modelId}\"`)\n }\n\n // Resolve format: use provided or pick first available\n const selectedFormat = format ?? this.pickDefaultFormat(entry)\n const formatEntry = entry.formats[selectedFormat]\n if (!formatEntry) {\n throw new Error(\n `ModelDownloadService: model \"${modelId}\" has no ${selectedFormat} format`,\n )\n }\n\n // Download extra files first (labels JSON, dict.txt, etc.)\n await this.ensureExtraFiles(modelId)\n\n // Derive local path from URL\n const modelPath = this.modelFilePath(entry, selectedFormat)\n\n if (fs.existsSync(modelPath)) {\n // Validate directory bundles have required Manifest.json\n if (formatEntry.isDirectory) {\n if (!fs.existsSync(path.join(modelPath, 'Manifest.json'))) {\n fs.rmSync(modelPath, { recursive: true, force: true })\n } else {\n return modelPath\n }\n } else {\n return modelPath\n }\n }\n\n fs.mkdirSync(this.modelsDir, { recursive: true })\n\n if (formatEntry.isDirectory) {\n await this.downloadDirectory(\n formatEntry.url,\n modelPath,\n formatEntry.files,\n modelId,\n )\n } else {\n await downloadFile(\n formatEntry.url,\n modelPath,\n this.onProgress\n ? (downloaded, total) => this.onProgress!(modelId, downloaded, total)\n : undefined,\n )\n }\n\n return modelPath\n }\n\n /**\n * Ensure extra files for a model are downloaded.\n * Returns the local paths of all extra files.\n */\n async ensureExtraFiles(modelId: string): Promise<readonly string[]> {\n const entry = this.catalog.get(modelId)\n if (!entry) {\n throw new Error(`ModelDownloadService: unknown model \"${modelId}\"`)\n }\n\n const extras = entry.extraFiles\n if (!extras || extras.length === 0) return []\n\n const paths: string[] = []\n for (const extra of extras) {\n const destPath = path.join(this.modelsDir, extra.filename)\n await downloadFile(extra.url, destPath)\n paths.push(destPath)\n }\n return paths\n }\n\n /** Absolute path to the shared models directory. */\n getModelsDir(): string {\n return this.modelsDir\n }\n\n /** Check if a model file is already present on disk. */\n isDownloaded(modelId: string, format?: ModelFormat): boolean {\n const entry = this.catalog.get(modelId)\n if (!entry) return false\n\n const selectedFormat = format ?? this.pickDefaultFormat(entry)\n const formatEntry = entry.formats[selectedFormat]\n if (!formatEntry) return false\n\n const modelPath = this.modelFilePath(entry, selectedFormat)\n if (!fs.existsSync(modelPath)) return false\n\n // Validate directory bundles\n if (formatEntry.isDirectory) {\n return fs.existsSync(path.join(modelPath, 'Manifest.json'))\n }\n\n return fs.statSync(modelPath).size > 0\n }\n\n /**\n * Legacy API: download a model by ID (delegates to ensure with default format).\n * Required by IAddonModelManager interface.\n */\n async downloadModel(id: string): Promise<string> {\n return this.ensure(id)\n }\n\n /** Get the catalog entry for a model by ID. */\n getEntry(modelId: string): ModelCatalogEntry | undefined {\n return this.catalog.get(modelId)\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private pickDefaultFormat(entry: ModelCatalogEntry): ModelFormat {\n // Prefer onnx, then others in order\n const priority: ModelFormat[] = ['onnx', 'coreml', 'openvino', 'tflite', 'pt']\n for (const fmt of priority) {\n if (entry.formats[fmt]) return fmt\n }\n // Fallback: first available format\n const first = Object.keys(entry.formats)[0] as ModelFormat | undefined\n if (first) return first\n throw new Error(`ModelDownloadService: model \"${entry.id}\" has no formats`)\n }\n\n private modelFilePath(entry: ModelCatalogEntry, format: ModelFormat): string {\n const formatEntry = entry.formats[format]\n if (!formatEntry) {\n throw new Error(`Model ${entry.id} has no ${format} format`)\n }\n const urlParts = formatEntry.url.split('/')\n const filename = urlParts[urlParts.length - 1] ?? `${entry.id}.${format}`\n return path.join(this.modelsDir, filename)\n }\n\n /**\n * Download a directory bundle (e.g., .mlpackage) from HuggingFace.\n * ATOMIC: downloads to temp dir, renames only on complete success.\n */\n private async downloadDirectory(\n url: string,\n destDir: string,\n knownFiles?: readonly string[],\n modelId?: string,\n ): Promise<void> {\n const match = url.match(/huggingface\\.co\\/([^/]+\\/[^/]+)\\/resolve\\/main\\/(.+)/)\n if (!match) throw new Error(`Cannot parse HuggingFace URL: ${url}`)\n\n const [, repo, dirPath] = match\n\n let filesToDownload: Array<{ relativePath: string; fileUrl: string }>\n\n if (knownFiles && knownFiles.length > 0) {\n filesToDownload = knownFiles.map(f => ({\n relativePath: f,\n fileUrl: `https://huggingface.co/${repo}/resolve/main/${dirPath}/${f}`,\n }))\n } else {\n const hfFiles = await this.listHfFiles(repo!, dirPath!)\n if (hfFiles.length === 0) {\n throw new Error(`No files found in HuggingFace directory: ${dirPath}`)\n }\n filesToDownload = hfFiles.map(f => ({\n relativePath: f.path.substring(dirPath!.length + 1),\n fileUrl: `https://huggingface.co/${repo}/resolve/main/${f.path}`,\n }))\n }\n\n const tmpDir = destDir + '.downloading'\n fs.rmSync(tmpDir, { recursive: true, force: true })\n fs.mkdirSync(tmpDir, { recursive: true })\n\n try {\n for (const file of filesToDownload) {\n const destPath = path.join(tmpDir, file.relativePath)\n fs.mkdirSync(path.dirname(destPath), { recursive: true })\n await downloadFile(file.fileUrl, destPath)\n }\n\n fs.rmSync(destDir, { recursive: true, force: true })\n fs.renameSync(tmpDir, destDir)\n } catch (err) {\n fs.rmSync(tmpDir, { recursive: true, force: true })\n throw err\n }\n }\n\n /** Recursively list all files in a HuggingFace directory via API. */\n private async listHfFiles(\n repo: string,\n dirPath: string,\n ): Promise<Array<{ path: string; size: number }>> {\n const apiUrl = `https://huggingface.co/api/models/${repo}/tree/main/${dirPath}`\n const entries = (await fetchJson(apiUrl)) as any[]\n const files: Array<{ path: string; size: number }> = []\n\n for (const entry of entries) {\n if (entry.type === 'file') {\n files.push({ path: entry.path, size: entry.size ?? entry.lfs?.size ?? 0 })\n } else if (entry.type === 'directory') {\n const subFiles = await this.listHfFiles(repo, entry.path)\n files.push(...subFiles)\n }\n }\n\n return files\n }\n}\n","import type { IPythonEnvironment, PythonProbeResult, PythonEnvReady } from '@camstack/types'\nimport { execFile, spawn } from 'node:child_process'\nimport type { ChildProcess } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\n\nconst execFileAsync = promisify(execFile)\n\nexport class PythonEnvManager implements IPythonEnvironment {\n private venvPath: string\n private cachedProbe: PythonProbeResult | null = null\n\n constructor(private readonly dataDir: string) {\n this.venvPath = path.join(dataDir, '.venv')\n }\n\n async probe(): Promise<PythonProbeResult> {\n if (this.cachedProbe) return this.cachedProbe\n\n // Try python3, then python\n for (const cmd of ['python3', 'python']) {\n try {\n const { stdout } = await execFileAsync(cmd, ['--version'])\n const version = stdout.trim().replace('Python ', '')\n const major = parseInt(version.split('.')[0] ?? '0', 10)\n const minor = parseInt(version.split('.')[1] ?? '0', 10)\n\n if (major < 3 || (major === 3 && minor < 10)) continue\n\n // Get path\n const { stdout: pathOut } = await execFileAsync(cmd, ['-c', 'import sys; print(sys.executable)'])\n\n this.cachedProbe = {\n available: true,\n version,\n path: pathOut.trim(),\n }\n return this.cachedProbe\n } catch { continue }\n }\n\n this.cachedProbe = { available: false }\n return this.cachedProbe\n }\n\n async ensure(options: { packages: readonly string[] }): Promise<PythonEnvReady> {\n const probe = await this.probe()\n if (!probe.available || !probe.path) {\n throw new Error('Python 3.10+ is required but not found on this system')\n }\n\n // Create venv if needed\n if (!fs.existsSync(path.join(this.venvPath, 'bin', 'python'))) {\n await execFileAsync(probe.path, ['-m', 'venv', this.venvPath])\n }\n\n const venvPython = path.join(this.venvPath, 'bin', 'python')\n\n // Install packages\n if (options.packages.length > 0) {\n await execFileAsync(venvPython, ['-m', 'pip', 'install', '-q', ...options.packages])\n }\n\n return {\n pythonPath: venvPython,\n venvPath: this.venvPath,\n spawn: (script: string, args: readonly string[]) => {\n return spawn(venvPython, [script, ...args])\n },\n }\n }\n\n spawn(script: string, args: readonly string[]): ChildProcess {\n const venvPython = path.join(this.venvPath, 'bin', 'python')\n if (!fs.existsSync(venvPython)) {\n throw new Error('Python venv not initialized. Call ensure() first.')\n }\n return spawn(venvPython, [script, ...args])\n }\n}\n","import type { PipelineConfig, PipelineNode, ValidationIssue, ValidationResult } from '@camstack/types'\nimport { AddonLoader } from '@camstack/kernel'\n\nexport type { ValidationIssue, ValidationResult }\n\nexport class PipelineValidator {\n constructor(private readonly loader: AddonLoader) {}\n\n validate(config: PipelineConfig): ValidationResult {\n const errors: ValidationIssue[] = []\n const warnings: ValidationIssue[] = []\n\n // Validate video pipeline\n for (const node of config.video) {\n this.validateNode(node, errors, warnings, [])\n }\n\n // Validate audio\n if (config.audio) {\n this.validateNode(config.audio, errors, warnings, [])\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n }\n }\n\n private validateNode(\n node: PipelineNode,\n errors: ValidationIssue[],\n warnings: ValidationIssue[],\n ancestors: PipelineNode[],\n ): void {\n // Check addon exists\n if (!this.loader.hasAddon(node.addon)) {\n errors.push({\n step: node.step,\n addon: node.addon,\n message: `Addon \"${node.addon}\" is not registered`,\n severity: 'error',\n })\n return\n }\n\n // Check requiredSteps (from addon manifest)\n const registered = this.loader.getAddon(node.addon)\n if (registered) {\n const manifest = registered.declaration\n // Warn if a node appears at root but its addon has inputClasses\n // (This is a simplified check — full implementation would read manifest.requiredSteps)\n void manifest // reserved for future manifest-driven checks\n }\n\n // Validate children recursively\n if (node.children) {\n for (const child of node.children) {\n this.validateNode(child, errors, warnings, [...ancestors, node])\n }\n }\n }\n}\n","import type {\n FrameInput,\n AudioChunkInput,\n CropInput,\n PipelineConfig,\n PipelineNode,\n PipelineResult,\n StepResult,\n DetectorOutput,\n CropperOutput,\n ClassifierOutput,\n SpatialDetection,\n PipelineSlot,\n ICamstackAddon,\n} from '@camstack/types'\nimport { AddonEngineManager } from '@camstack/kernel'\nimport { randomUUID } from 'node:crypto'\n\nexport class PipelineRunner {\n constructor(\n private readonly engineManager: AddonEngineManager,\n private readonly addonConfigs: Map<string, Record<string, unknown>>, // addonId → global config\n ) {}\n\n async run(frame: FrameInput, config: PipelineConfig): Promise<PipelineResult> {\n const startTime = performance.now()\n const results: StepResult[] = []\n const timings: Record<string, number> = {}\n\n // Execute video pipeline root nodes\n for (const rootNode of config.video) {\n await this.executeNode(rootNode, frame, null, results, timings)\n }\n\n // Execute audio node if present (independent)\n if (config.audio) {\n await this.executeNode(config.audio, frame, null, results, timings)\n }\n\n return {\n results,\n totalMs: performance.now() - startTime,\n timings,\n frameTimestamp: frame.timestamp,\n }\n }\n\n /**\n * Run only the audio classification node on an audio chunk.\n * Used by the audio path in DetectionWiringService (separate from video pipeline).\n */\n async runAudioNode(chunk: AudioChunkInput, audioNode: PipelineNode): Promise<PipelineResult> {\n const startTime = performance.now()\n const results: StepResult[] = []\n const timings: Record<string, number> = {}\n const resultId = randomUUID()\n const stepStart = performance.now()\n\n try {\n const globalConfig = this.addonConfigs.get(audioNode.addon) ?? {}\n const engine = await this.engineManager.getOrCreateEngine(\n audioNode.addon, globalConfig, audioNode.configOverride,\n )\n\n if (!('classifyAudio' in engine) || typeof (engine as unknown as Record<string, unknown>)['classifyAudio'] !== 'function') {\n throw new Error(`Addon \"${audioNode.addon}\" has no classifyAudio method`)\n }\n\n const output = await (engine as unknown as { classifyAudio: (input: AudioChunkInput) => Promise<ClassifierOutput> }).classifyAudio(chunk)\n const stepMs = performance.now() - stepStart\n\n const stepResult: StepResult = {\n addon: audioNode.addon,\n slot: 'classifier',\n output,\n resultId,\n inferenceMs: output.inferenceMs,\n preprocessMs: 0,\n totalMs: stepMs,\n }\n results.push(stepResult)\n timings[audioNode.step] = stepMs\n } catch (error: unknown) {\n const stepMs = performance.now() - stepStart\n const message = error instanceof Error ? error.message : String(error)\n results.push({\n addon: audioNode.addon,\n slot: 'classifier',\n output: { classifications: [], inferenceMs: 0, modelId: '' } as unknown as ClassifierOutput,\n resultId,\n inferenceMs: 0,\n preprocessMs: 0,\n totalMs: stepMs,\n error: {\n code: 'ADDON_ERROR',\n message,\n childrenSkipped: true,\n },\n })\n }\n\n return {\n results,\n totalMs: performance.now() - startTime,\n timings,\n frameTimestamp: chunk.timestamp,\n }\n }\n\n private async executeNode(\n node: PipelineNode,\n frame: FrameInput,\n parentDetection: { det: SpatialDetection; resultId: string } | null,\n results: StepResult[],\n timings: Record<string, number>,\n ): Promise<void> {\n const resultId = randomUUID()\n const stepStart = performance.now()\n\n try {\n // Get or create engine for this addon\n const globalConfig = this.addonConfigs.get(node.addon) ?? {}\n const engine = await this.engineManager.getOrCreateEngine(\n node.addon, globalConfig, node.configOverride,\n )\n\n // Determine slot type and execute\n let output: DetectorOutput | CropperOutput | ClassifierOutput\n\n if (parentDetection) {\n // This is a child node — needs crop input\n const cropInput: CropInput = {\n frame,\n roi: parentDetection.det.bbox,\n parentDetection: parentDetection.det,\n }\n\n // Try cropper first, then classifier, then detector\n if ('crop' in engine && typeof (engine as unknown as Record<string, unknown>)['crop'] === 'function') {\n output = await (engine as unknown as { crop: (input: CropInput) => Promise<CropperOutput> }).crop(cropInput)\n } else if ('classify' in engine && typeof (engine as unknown as Record<string, unknown>)['classify'] === 'function') {\n output = await (engine as unknown as { classify: (input: CropInput) => Promise<ClassifierOutput> }).classify(cropInput)\n } else if ('detect' in engine && typeof (engine as unknown as Record<string, unknown>)['detect'] === 'function') {\n // Detector child (e.g., object-detection triggered by motion)\n output = await (engine as unknown as { detect: (input: FrameInput) => Promise<DetectorOutput> }).detect(frame)\n } else {\n throw new Error(`Addon \"${node.addon}\" has no detect/crop/classify method`)\n }\n } else {\n // Root node — full frame\n if ('detect' in engine && typeof (engine as unknown as Record<string, unknown>)['detect'] === 'function') {\n output = await (engine as unknown as { detect: (input: FrameInput) => Promise<DetectorOutput> }).detect(frame)\n } else if ('classify' in engine && typeof (engine as unknown as Record<string, unknown>)['classify'] === 'function') {\n // Audio classifier at root\n const rootCropInput: CropInput = {\n frame,\n roi: { x: 0, y: 0, w: frame.width, h: frame.height },\n parentDetection: { class: '', originalClass: '', score: 1, bbox: { x: 0, y: 0, w: frame.width, h: frame.height } },\n }\n output = await (engine as unknown as { classify: (input: CropInput) => Promise<ClassifierOutput> }).classify(rootCropInput)\n } else {\n throw new Error(`Addon \"${node.addon}\" has no detect/classify method`)\n }\n }\n\n const stepMs = performance.now() - stepStart\n\n // Determine slot type from output shape\n const slot: PipelineSlot =\n 'detections' in output ? 'detector' :\n 'crops' in output ? 'cropper' :\n 'classifier'\n\n const stepResult: StepResult = {\n addon: node.addon,\n slot,\n output,\n parentResultId: parentDetection?.resultId,\n resultId,\n inferenceMs: output.inferenceMs,\n preprocessMs: 0,\n totalMs: stepMs,\n }\n results.push(stepResult)\n timings[node.step] = stepMs\n\n // Process children\n if (node.children?.length) {\n const detections: readonly SpatialDetection[] =\n 'detections' in output ? output.detections :\n 'crops' in output ? output.crops :\n []\n\n // For each detection, find children with matching inputClasses and execute\n await this.executeChildren(node.children, frame, detections, resultId, results, timings)\n }\n } catch (error: unknown) {\n const stepMs = performance.now() - stepStart\n const message = error instanceof Error ? error.message : String(error)\n results.push({\n addon: node.addon,\n slot: 'detector',\n output: { detections: [], inferenceMs: 0, modelId: '' },\n parentResultId: parentDetection?.resultId,\n resultId,\n inferenceMs: 0,\n preprocessMs: 0,\n totalMs: stepMs,\n error: {\n code: 'ADDON_ERROR',\n message,\n childrenSkipped: true,\n },\n })\n }\n }\n\n private async executeChildren(\n children: readonly PipelineNode[],\n frame: FrameInput,\n parentDetections: readonly SpatialDetection[],\n parentResultId: string,\n results: StepResult[],\n timings: Record<string, number>,\n ): Promise<void> {\n // For each parent detection, run all matching children in parallel\n const promises: Promise<void>[] = []\n\n for (const detection of parentDetections) {\n for (const child of children) {\n // TODO: Check inputClasses matching from addon manifest\n // For now, run all children on all detections (caller configures tree correctly)\n promises.push(\n this.executeNode(child, frame, { det: detection, resultId: parentResultId }, results, timings),\n )\n }\n }\n\n await Promise.allSettled(promises)\n }\n}\n","import { fork, spawn, type ChildProcess } from 'node:child_process'\nimport type { IScopedLogger } from '@camstack/types'\nimport type {\n ProcessConfig,\n ProcessStats,\n ManagedProcessStatus,\n ProcessState,\n ProcessEventEmitter,\n} from './interfaces.js'\n\nconst DEFAULT_MAX_RESTARTS = 10\nconst MAX_BACKOFF_MS = 60_000\nconst GRACEFUL_SHUTDOWN_MS = 5_000\n\nexport class ManagedProcess {\n private childProcess: ChildProcess | null = null\n private _state: ProcessState = 'stopped'\n private _startedAt?: number\n private restartTimer?: ReturnType<typeof setTimeout>\n private _restartCount = 0\n private _lastCrashAt?: number\n private _lastCrashError?: string\n\n constructor(\n private readonly config: ProcessConfig,\n private readonly events: ProcessEventEmitter,\n private readonly logger: IScopedLogger,\n ) {}\n\n get state(): ProcessState {\n return this._state\n }\n\n async start(): Promise<void> {\n this._state = 'starting'\n\n try {\n if (this.config.modulePath) {\n this.childProcess = fork(this.config.modulePath, this.config.args ?? [], {\n env: { ...process.env, ...this.config.env },\n stdio: ['pipe', 'pipe', 'pipe', 'ipc'],\n })\n } else if (this.config.command) {\n this.childProcess = spawn(this.config.command, this.config.args ?? [], {\n env: { ...process.env, ...this.config.env },\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n } else {\n throw new Error('No command or modulePath specified')\n }\n\n this.childProcess.stdout?.on('data', (data: Buffer) => {\n this.logger.debug(data.toString().trim())\n })\n\n this.childProcess.stderr?.on('data', (data: Buffer) => {\n this.logger.warn(data.toString().trim())\n })\n\n this.childProcess.on('exit', (code, signal) => {\n const msg = `Process exited: code=${code}, signal=${signal}`\n\n if (code === 0) {\n this.logger.info(msg)\n this._state = 'stopped'\n } else {\n this._lastCrashAt = Date.now()\n this._lastCrashError = msg\n this.logger.error(msg)\n this._state = 'error'\n\n this.events.emitProcessCrashed(\n this.config.id,\n code,\n signal,\n this._restartCount,\n )\n\n const maxRestarts = this.config.maxRestarts ?? DEFAULT_MAX_RESTARTS\n if (this.config.autoRestart && this._restartCount < maxRestarts) {\n this.scheduleRestart()\n }\n }\n\n this.childProcess = null\n })\n\n this.childProcess.on('error', (err: Error) => {\n this.logger.error(`Process error: ${err.message}`)\n this._lastCrashError = err.message\n this._state = 'error'\n })\n\n this._state = 'running'\n this._startedAt = Date.now()\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n this._state = 'error'\n this._lastCrashError = msg\n throw err\n }\n }\n\n async stop(): Promise<void> {\n if (this.restartTimer) {\n clearTimeout(this.restartTimer)\n this.restartTimer = undefined\n }\n\n if (this._state === 'stopped') {\n return\n }\n\n this._state = 'stopping'\n\n if (this.childProcess && !this.childProcess.killed) {\n this.childProcess.kill('SIGTERM')\n\n await new Promise<void>((resolve) => {\n const timeout = setTimeout(() => {\n if (this.childProcess && !this.childProcess.killed) {\n this.childProcess.kill('SIGKILL')\n }\n resolve()\n }, GRACEFUL_SHUTDOWN_MS)\n\n this.childProcess?.on('exit', () => {\n clearTimeout(timeout)\n resolve()\n })\n })\n }\n\n // The exit handler may have already set state to 'stopped' asynchronously\n const currentState = this._state as string\n if (currentState !== 'stopped') {\n this._state = 'stopped'\n }\n }\n\n getStatus(): ManagedProcessStatus {\n return {\n id: this.config.id,\n label: this.config.label,\n state: this._state,\n pid: this.childProcess?.pid,\n stats: this.childProcess?.pid ? this.getStats() : undefined,\n lastCrashAt: this._lastCrashAt,\n lastCrashError: this._lastCrashError,\n restartCount: this._restartCount,\n nextRestartAt: this.restartTimer ? this.getNextRestartTime() : undefined,\n }\n }\n\n private scheduleRestart(): void {\n this._restartCount++\n const delayMs = Math.min(1000 * Math.pow(2, this._restartCount - 1), MAX_BACKOFF_MS)\n\n this.logger.info(`Scheduling restart #${this._restartCount} in ${delayMs}ms`)\n\n this.events.emitProcessRestartScheduled(\n this.config.id,\n this._restartCount,\n delayMs,\n )\n\n this.restartTimer = setTimeout(async () => {\n this.restartTimer = undefined\n try {\n await this.start()\n this.events.emitProcessRestarted(this.config.id, this._restartCount)\n } catch (err) {\n this.logger.error(`Restart failed: ${err}`)\n }\n }, delayMs)\n }\n\n private getStats(): ProcessStats | undefined {\n if (!this.childProcess?.pid) return undefined\n const uptime = this._startedAt ? Date.now() - this._startedAt : 0\n return {\n pid: this.childProcess.pid,\n cpu: 0,\n memory: 0,\n uptime,\n restartCount: this._restartCount,\n }\n }\n\n private getNextRestartTime(): number | undefined {\n if (!this._lastCrashAt) return undefined\n const delayMs = Math.min(1000 * Math.pow(2, this._restartCount - 1), MAX_BACKOFF_MS)\n return this._lastCrashAt + delayMs\n }\n}\n","import { ManagedProcess } from './managed-process.js'\nimport type {\n ProcessConfig,\n ManagedProcessStatus,\n ProcessEventEmitter,\n ProcessLoggerFactory,\n} from './interfaces.js'\n\nexport class ProcessManager {\n private readonly processes: Map<string, ManagedProcess> = new Map()\n\n constructor(\n private readonly events: ProcessEventEmitter,\n private readonly loggerFactory: ProcessLoggerFactory,\n ) {}\n\n register(config: ProcessConfig): ManagedProcess {\n if (this.processes.has(config.id)) {\n throw new Error(`Process already registered: ${config.id}`)\n }\n\n const logger = this.loggerFactory.createLogger(`process:${config.id}`)\n const managed = new ManagedProcess(config, this.events, logger)\n this.processes.set(config.id, managed)\n return managed\n }\n\n async start(id: string): Promise<void> {\n const p = this.get(id)\n await p.start()\n }\n\n async stop(id: string): Promise<void> {\n const p = this.get(id)\n await p.stop()\n }\n\n async restart(id: string): Promise<void> {\n const p = this.get(id)\n await p.stop()\n await p.start()\n }\n\n get(id: string): ManagedProcess {\n const p = this.processes.get(id)\n if (!p) throw new Error(`Process not found: ${id}`)\n return p\n }\n\n listAll(): readonly ManagedProcessStatus[] {\n return [...this.processes.values()].map((p) => p.getStatus())\n }\n\n async shutdownAll(): Promise<void> {\n const running = [...this.processes.values()].filter(\n (p) => p.getStatus().state === 'running',\n )\n\n await Promise.all(running.map((p) => p.stop()))\n }\n}\n","import type {\n StreamNetworkStats,\n ClientNetworkStats,\n DeviceNetworkStats,\n INetworkQualityTracker,\n} from '@camstack/types'\n\nexport type {\n StreamNetworkStats,\n ClientNetworkStats,\n DeviceNetworkStats,\n INetworkQualityTracker,\n}\n\ninterface MutableStreamStats {\n nominalBitrateKbps: number\n samples: number[]\n peakBitrateKbps: number\n packetLossSamples: number[]\n lastUpdated: number\n}\n\nexport class NetworkQualityTracker implements INetworkQualityTracker {\n private readonly devices = new Map<string, {\n streams: Map<string, MutableStreamStats>\n client: (ClientNetworkStats & { lastUpdated: number }) | null\n }>()\n\n private static readonly MAX_SAMPLES = 30 // ~5 min at 10s reporting interval\n\n reportStreamStats(deviceId: string, streamId: string, bitrateKbps: number, packetLoss?: number): void {\n const device = this.getOrCreateDevice(deviceId)\n let stream = device.streams.get(streamId)\n if (!stream) {\n stream = { nominalBitrateKbps: bitrateKbps, samples: [], peakBitrateKbps: 0, packetLossSamples: [], lastUpdated: 0 }\n device.streams.set(streamId, stream)\n }\n\n stream.samples.push(bitrateKbps)\n if (stream.samples.length > NetworkQualityTracker.MAX_SAMPLES) stream.samples.shift()\n\n stream.peakBitrateKbps = Math.max(stream.peakBitrateKbps, bitrateKbps)\n\n if (packetLoss !== undefined) {\n stream.packetLossSamples.push(packetLoss)\n if (stream.packetLossSamples.length > NetworkQualityTracker.MAX_SAMPLES) stream.packetLossSamples.shift()\n }\n\n stream.lastUpdated = Date.now()\n }\n\n reportClientStats(deviceId: string, stats: Omit<ClientNetworkStats, 'lastUpdated'>): void {\n const device = this.getOrCreateDevice(deviceId)\n device.client = { ...stats, lastUpdated: Date.now() }\n }\n\n getDeviceStats(deviceId: string): DeviceNetworkStats | null {\n const device = this.devices.get(deviceId)\n if (!device) return null\n\n const streams: Record<string, StreamNetworkStats> = {}\n for (const [streamId, s] of device.streams) {\n const avg = (arr: number[]) => arr.length === 0 ? 0 : arr.reduce((a, b) => a + b, 0) / arr.length\n streams[streamId] = {\n nominalBitrateKbps: s.nominalBitrateKbps,\n observedBitrateKbps: Math.round(avg(s.samples)),\n peakBitrateKbps: s.peakBitrateKbps,\n packetLossPercent: Math.round(avg(s.packetLossSamples) * 10) / 10,\n lastUpdated: s.lastUpdated,\n }\n }\n\n return { deviceId, streams, client: device.client ?? undefined }\n }\n\n getAllStats(): readonly DeviceNetworkStats[] {\n const results: DeviceNetworkStats[] = []\n for (const deviceId of this.devices.keys()) {\n const stats = this.getDeviceStats(deviceId)\n if (stats) results.push(stats)\n }\n return results\n }\n\n private getOrCreateDevice(deviceId: string) {\n let device = this.devices.get(deviceId)\n if (!device) {\n device = { streams: new Map(), client: null }\n this.devices.set(deviceId, device)\n }\n return device\n }\n}\n","import * as vm from 'node:vm'\nimport * as util from 'node:util'\nimport type {\n IReplEngine,\n IReplContextProvider,\n ReplSessionContext,\n ReplResult,\n} from './interfaces.js'\n\nconst EXECUTION_TIMEOUT_MS = 5000\nconst COMPLETION_TIMEOUT_MS = 1000\n\nexport class ReplEngine implements IReplEngine {\n constructor(\n private readonly contextProvider: IReplContextProvider,\n ) {}\n\n async execute(code: string, context: ReplSessionContext): Promise<ReplResult> {\n const start = Date.now()\n const sandbox = this.buildSandbox(context)\n\n try {\n const vmContext = vm.createContext(sandbox)\n const script = new vm.Script(code)\n let result = script.runInContext(vmContext, { timeout: EXECUTION_TIMEOUT_MS })\n\n // If result is a Promise, await it with timeout\n if (result && typeof result.then === 'function') {\n result = await Promise.race([\n result,\n new Promise((_, reject) =>\n setTimeout(() => reject(new Error('Async timeout (5s)')), EXECUTION_TIMEOUT_MS),\n ),\n ])\n }\n\n const duration = Date.now() - start\n\n if (result === undefined) {\n return { output: 'undefined', type: 'void', duration }\n }\n\n return {\n output: util.inspect(result, {\n depth: 4,\n colors: false,\n maxArrayLength: 50,\n maxStringLength: 1000,\n }),\n type: 'value',\n duration,\n }\n } catch (err: unknown) {\n // Errors thrown inside vm contexts may not be instanceof Error\n // because they use a different Error constructor from the sandbox\n const message =\n err instanceof Error\n ? err.message\n : typeof err === 'object' && err !== null && 'message' in err\n ? String((err as { message: unknown }).message)\n : String(err)\n return {\n output: message,\n type: 'error',\n duration: Date.now() - start,\n }\n }\n }\n\n async getCompletions(partial: string, context: ReplSessionContext): Promise<string[]> {\n const sandbox = this.buildSandbox(context)\n const keys = Object.keys(sandbox)\n\n if (!partial) return keys\n\n const lastDot = partial.lastIndexOf('.')\n if (lastDot === -1) {\n return keys.filter(k => k.startsWith(partial))\n }\n\n // Object property completion: \"device.get\" -> look up device, return matching keys\n const objPath = partial.substring(0, lastDot)\n const propPrefix = partial.substring(lastDot + 1)\n\n try {\n const vmContext = vm.createContext(sandbox)\n const obj = vm.runInContext(objPath, vmContext, { timeout: COMPLETION_TIMEOUT_MS })\n if (obj && typeof obj === 'object') {\n const proto = Object.getPrototypeOf(obj)\n const objKeys = Object.getOwnPropertyNames(obj)\n .concat(Object.getOwnPropertyNames(proto ?? {}))\n .filter(k => k.startsWith(propPrefix))\n return [...new Set(objKeys)].map(k => `${objPath}.${k}`)\n }\n } catch {\n // Ignore errors during completion\n }\n\n return []\n }\n\n private buildSandbox(context: ReplSessionContext): Record<string, unknown> {\n const base: Record<string, unknown> = {\n console: {\n log: (...args: unknown[]) => util.inspect(args),\n warn: (...args: unknown[]) => util.inspect(args),\n },\n JSON,\n Math,\n Date,\n Array,\n Object,\n String,\n Number,\n Boolean,\n Map,\n Set,\n Promise,\n Buffer,\n // Blocked globals\n setTimeout: undefined,\n setInterval: undefined,\n fetch: undefined,\n require: undefined,\n process: undefined,\n // Merge user-provided variables\n ...context.variables,\n }\n\n switch (context.scope.type) {\n case 'system':\n return { ...base, ...this.contextProvider.getSystemSandbox() }\n\n case 'device':\n return { ...base, ...this.contextProvider.getDeviceSandbox(context.scope.deviceId!) }\n\n case 'provider':\n return { ...base, ...this.contextProvider.getProviderSandbox(context.scope.providerId!) }\n\n case 'addon':\n return { ...base, ...this.contextProvider.getAddonSandbox(context.scope.addonId!) }\n\n default:\n return base\n }\n }\n}\n","import type {\n AgentInfo,\n AgentStatus,\n AgentEntry,\n AgentEventEmitter,\n} from './interfaces.js'\n\nexport class AgentRegistry {\n private readonly agents: Map<string, AgentEntry> = new Map()\n private readonly heartbeatIntervals: Map<string, NodeJS.Timeout> = new Map()\n\n constructor(\n private readonly events: AgentEventEmitter,\n private readonly heartbeatTimeoutMs: number = 30000,\n private readonly heartbeatCheckIntervalMs: number = 10000,\n ) {}\n\n /** Register a new agent */\n registerAgent(info: AgentInfo): void {\n const entry: AgentEntry = {\n info,\n state: 'online',\n connectedSince: Date.now(),\n lastHeartbeat: Date.now(),\n activeTaskCount: 0,\n completedTaskCount: 0,\n failedTaskCount: 0,\n }\n\n this.agents.set(info.id, entry)\n this.startHeartbeatCheck(info.id)\n\n this.events.emitAgentRegistered(info.id, [...info.capabilities])\n }\n\n /** Remove agent */\n unregisterAgent(id: string): void {\n const interval = this.heartbeatIntervals.get(id)\n if (interval) {\n clearInterval(interval)\n this.heartbeatIntervals.delete(id)\n }\n\n this.agents.delete(id)\n this.events.emitAgentUnregistered(id)\n }\n\n /** Update heartbeat timestamp */\n heartbeat(id: string): void {\n const entry = this.agents.get(id)\n if (!entry) return\n\n entry.lastHeartbeat = Date.now()\n\n if (entry.state === 'offline') {\n entry.state = 'online'\n this.events.emitAgentOnline(id)\n }\n }\n\n /** Find agents with a specific capability */\n getAgentsWithCapability(capability: string): readonly AgentEntry[] {\n return [...this.agents.values()].filter(\n (a) => a.state === 'online' && a.info.capabilities.includes(capability),\n )\n }\n\n /** Get best agent for a task (least loaded) */\n selectAgent(capability: string, preferredId?: string): AgentEntry | null {\n const capable = this.getAgentsWithCapability(capability)\n if (capable.length === 0) return null\n\n if (preferredId) {\n const preferred = capable.find((a) => a.info.id === preferredId)\n if (preferred) return preferred\n }\n\n // Least loaded: sort by activeTaskCount ascending\n const sorted = [...capable].sort((a, b) => a.activeTaskCount - b.activeTaskCount)\n return sorted[0] ?? null\n }\n\n /** List all agents with status */\n listAgents(): readonly AgentStatus[] {\n return [...this.agents.values()].map((entry) => ({\n id: entry.info.id,\n name: entry.info.name,\n state: entry.state,\n capabilities: [...entry.info.capabilities],\n lastHeartbeat: entry.lastHeartbeat,\n connectedSince: entry.connectedSince,\n resources: entry.info.resources,\n activeTaskCount: entry.activeTaskCount,\n completedTaskCount: entry.completedTaskCount,\n failedTaskCount: entry.failedTaskCount,\n }))\n }\n\n /** Get single agent */\n getAgent(id: string): AgentEntry | null {\n return this.agents.get(id) ?? null\n }\n\n /** Destroy all heartbeat intervals */\n destroy(): void {\n for (const interval of this.heartbeatIntervals.values()) {\n clearInterval(interval)\n }\n this.heartbeatIntervals.clear()\n }\n\n private startHeartbeatCheck(id: string): void {\n const interval = setInterval(() => {\n const entry = this.agents.get(id)\n if (!entry) return\n\n const elapsed = Date.now() - entry.lastHeartbeat\n if (elapsed > this.heartbeatTimeoutMs && entry.state === 'online') {\n entry.state = 'offline'\n this.events.emitAgentOffline(id)\n }\n }, this.heartbeatCheckIntervalMs)\n\n this.heartbeatIntervals.set(id, interval)\n }\n}\n","import type { AgentRegistry } from './agent-registry.js'\nimport type {\n AgentTask,\n AgentTaskResult,\n AgentEntry,\n TaskDispatchOptions,\n AgentEventEmitter,\n} from './interfaces.js'\n\ninterface PendingTask {\n readonly resolve: (result: AgentTaskResult) => void\n readonly reject: (error: Error) => void\n readonly timeout: NodeJS.Timeout\n}\n\nexport class TaskDispatcher {\n private readonly pendingTasks: Map<string, PendingTask> = new Map()\n private readonly localExecutors: Map<\n string,\n (input: Record<string, unknown>) => Promise<Record<string, unknown>>\n > = new Map()\n\n constructor(\n private readonly agentRegistry: AgentRegistry,\n private readonly events: AgentEventEmitter,\n ) {}\n\n /** Dispatch a task to the best available agent */\n async dispatch(task: AgentTask, options?: TaskDispatchOptions): Promise<AgentTaskResult> {\n const capability = options?.capability ?? task.capability\n const agent = this.agentRegistry.selectAgent(capability, options?.preferredAgent)\n\n if (!agent && !options?.remoteOnly) {\n return this.executeLocally(task)\n }\n\n if (!agent) {\n return {\n taskId: task.id,\n agentId: 'none',\n status: 'error',\n error: 'No agent available',\n durationMs: 0,\n }\n }\n\n return this.sendToAgent(task, agent)\n }\n\n /** Register a local executor for a capability (in-process fallback) */\n registerLocalExecutor(\n capability: string,\n executor: (input: Record<string, unknown>) => Promise<Record<string, unknown>>,\n ): void {\n this.localExecutors.set(capability, executor)\n }\n\n /** Called when an agent returns a result */\n handleTaskResult(result: AgentTaskResult): void {\n const pending = this.pendingTasks.get(result.taskId)\n if (pending) {\n clearTimeout(pending.timeout)\n this.pendingTasks.delete(result.taskId)\n pending.resolve(result)\n }\n\n // Update agent stats\n const agent = this.agentRegistry.getAgent(result.agentId)\n if (agent) {\n agent.activeTaskCount--\n if (result.status === 'success') {\n agent.completedTaskCount++\n } else {\n agent.failedTaskCount++\n }\n }\n }\n\n private async executeLocally(task: AgentTask): Promise<AgentTaskResult> {\n const executor = this.localExecutors.get(task.capability)\n if (!executor) {\n return {\n taskId: task.id,\n agentId: 'local',\n status: 'error',\n error: `No local executor for ${task.capability}`,\n durationMs: 0,\n }\n }\n\n const start = Date.now()\n try {\n const output = await executor(task.input)\n return {\n taskId: task.id,\n agentId: 'local',\n status: 'success',\n output,\n durationMs: Date.now() - start,\n }\n } catch (err) {\n return {\n taskId: task.id,\n agentId: 'local',\n status: 'error',\n error: String(err),\n durationMs: Date.now() - start,\n }\n }\n }\n\n private sendToAgent(task: AgentTask, agent: AgentEntry): Promise<AgentTaskResult> {\n agent.activeTaskCount++\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n this.pendingTasks.delete(task.id)\n agent.activeTaskCount--\n agent.failedTaskCount++\n resolve({\n taskId: task.id,\n agentId: agent.info.id,\n status: 'timeout',\n durationMs: task.timeout,\n error: 'Task timed out',\n })\n }, task.timeout)\n\n this.pendingTasks.set(task.id, { resolve, reject: () => {}, timeout })\n\n this.events.emitTaskDispatched(task.id, agent.info.id, task.capability)\n })\n }\n}\n","import type {\n AgentToHubMessage,\n HubToAgentMessage,\n AgentRegistrationInfo,\n AgentRuntimeStatus,\n} from '@camstack/types'\nimport type { IScopedLogger } from '../logging/scoped-logger.js'\n\nconst RECONNECT_BASE_MS = 1000\nconst RECONNECT_MAX_MS = 30000\nconst HEARTBEAT_INTERVAL_MS = 10_000\n\nexport interface AgentClientConfig {\n readonly hubUrl: string\n readonly token?: string\n readonly logger: IScopedLogger\n readonly registrationInfo: AgentRegistrationInfo\n}\n\nexport type MessageHandler = (msg: HubToAgentMessage) => void\nexport type BinaryHandler = (data: Buffer) => void\nexport type ConnectionHandler = () => void\n\n/**\n * WebSocket client for agent mode. Framework-agnostic (no NestJS).\n * Connects to the hub, sends registration, handles messages,\n * reconnects with exponential backoff.\n */\nexport class AgentClient {\n private ws: import('ws').WebSocket | null = null\n private reconnectAttempt = 0\n private reconnectTimer: NodeJS.Timeout | null = null\n private heartbeatTimer: NodeJS.Timeout | null = null\n private destroyed = false\n\n private readonly messageHandlers: MessageHandler[] = []\n private readonly binaryHandlers: BinaryHandler[] = []\n private readonly connectHandlers: ConnectionHandler[] = []\n private readonly disconnectHandlers: ConnectionHandler[] = []\n\n private readonly logger: IScopedLogger\n private readonly hubUrl: string\n private readonly token?: string\n private readonly registrationInfo: AgentRegistrationInfo\n\n private runtimeStatus: AgentRuntimeStatus = {\n activeCameras: 0,\n cpuPercent: 0,\n memoryPercent: 0,\n fps: {},\n errors: [],\n }\n\n constructor(config: AgentClientConfig) {\n this.hubUrl = config.hubUrl\n this.token = config.token\n this.logger = config.logger\n this.registrationInfo = config.registrationInfo\n }\n\n /** Connect to the hub WebSocket */\n async connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.destroyed = false\n this.doConnect(resolve, reject)\n })\n }\n\n /** Disconnect and stop reconnecting */\n disconnect(): void {\n this.destroyed = true\n this.clearTimers()\n if (this.ws) {\n this.ws.close()\n this.ws = null\n }\n }\n\n /** Send a JSON control message to the hub */\n send(msg: AgentToHubMessage): void {\n if (!this.ws || this.ws.readyState !== 1 /* WebSocket.OPEN */) {\n this.logger.warn('send() called while not connected')\n return\n }\n this.ws.send(JSON.stringify(msg))\n }\n\n /** Send a binary frame to the hub */\n sendBinary(data: Buffer): void {\n if (!this.ws || this.ws.readyState !== 1) {\n return\n }\n this.ws.send(data)\n }\n\n /** Register a handler for JSON messages from hub */\n onMessage(handler: MessageHandler): void {\n this.messageHandlers.push(handler)\n }\n\n /** Register a handler for binary frames from hub */\n onBinaryFrame(handler: BinaryHandler): void {\n this.binaryHandlers.push(handler)\n }\n\n /** Register a handler for successful connection */\n onConnect(handler: ConnectionHandler): void {\n this.connectHandlers.push(handler)\n }\n\n /** Register a handler for disconnection */\n onDisconnect(handler: ConnectionHandler): void {\n this.disconnectHandlers.push(handler)\n }\n\n /** Update the runtime status (used in heartbeat) */\n updateStatus(status: AgentRuntimeStatus): void {\n this.runtimeStatus = status\n }\n\n /** Whether currently connected */\n get connected(): boolean {\n return this.ws?.readyState === 1\n }\n\n private doConnect(\n onConnect?: (value: void) => void,\n onError?: (err: Error) => void,\n ): void {\n if (this.destroyed) return\n\n // Dynamic import ws to keep this file framework-agnostic at the type level\n import('ws').then(({ default: WebSocket }) => {\n if (this.destroyed) return\n\n const url = this.token\n ? `${this.hubUrl}?token=${encodeURIComponent(this.token)}`\n : this.hubUrl\n\n // Accept self-signed certs when connecting over WSS (safe for local LAN)\n const wsOptions = this.hubUrl.startsWith('wss://')\n ? { rejectUnauthorized: false }\n : {}\n\n try {\n this.ws = new WebSocket(url, wsOptions)\n } catch (err) {\n this.scheduleReconnect()\n if (onError) {\n onError(err instanceof Error ? err : new Error(String(err)))\n onError = undefined\n }\n return\n }\n\n this.ws.once('open', () => {\n this.reconnectAttempt = 0\n this.logger.info(`Connected to hub: ${this.hubUrl}`)\n\n // Send registration\n this.send({ type: 'register', info: this.registrationInfo })\n\n // Start heartbeat\n this.startHeartbeat()\n\n for (const h of this.connectHandlers) h()\n\n if (onConnect) {\n onConnect()\n onConnect = undefined\n }\n })\n\n this.ws.on('message', (data: Buffer | string, isBinary: boolean) => {\n const buf = Buffer.isBuffer(data) ? data : Buffer.from(data as unknown as ArrayBuffer)\n if (isBinary) {\n for (const h of this.binaryHandlers) h(buf)\n } else {\n try {\n const msg = JSON.parse(buf.toString()) as HubToAgentMessage\n this.handleBuiltinMessage(msg)\n for (const h of this.messageHandlers) h(msg)\n } catch {\n this.logger.warn('Failed to parse message from hub')\n }\n }\n })\n\n this.ws.once('close', () => {\n this.stopHeartbeat()\n for (const h of this.disconnectHandlers) h()\n if (!this.destroyed) {\n this.logger.warn('Disconnected from hub, scheduling reconnect')\n this.scheduleReconnect()\n }\n })\n\n this.ws.once('error', (err) => {\n this.logger.error('WebSocket error', { message: err.message })\n if (onError) {\n onError(err)\n onError = undefined\n }\n })\n }).catch((err) => {\n this.logger.error('Failed to import ws module', { message: String(err) })\n if (onError) {\n onError(err instanceof Error ? err : new Error(String(err)))\n }\n })\n }\n\n private handleBuiltinMessage(msg: HubToAgentMessage): void {\n if (msg.type === 'ping') {\n this.send({ type: 'pong' })\n }\n }\n\n private scheduleReconnect(): void {\n if (this.destroyed) return\n const delay = Math.min(\n RECONNECT_BASE_MS * Math.pow(2, this.reconnectAttempt),\n RECONNECT_MAX_MS,\n )\n this.reconnectAttempt++\n this.logger.info(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt})`)\n this.reconnectTimer = setTimeout(() => {\n this.doConnect()\n }, delay)\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat()\n this.heartbeatTimer = setInterval(() => {\n this.send({ type: 'heartbeat', status: this.runtimeStatus })\n }, HEARTBEAT_INTERVAL_MS)\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer)\n this.heartbeatTimer = null\n }\n }\n\n private clearTimers(): void {\n this.stopHeartbeat()\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n }\n}\n","import type { ITaskHandler, TaskContext, TaskProgress } from '@camstack/types'\nimport type { IScopedLogger } from '../logging/scoped-logger.js'\nimport type { AgentClient } from './agent-client.js'\n\ninterface RunningTask {\n readonly taskId: string\n readonly taskType: string\n cancelled: boolean\n}\n\n/**\n * Receives task assignments from hub, routes to registered ITaskHandler instances.\n * Maintains handler registry, manages task lifecycle.\n * Framework-agnostic (no NestJS).\n */\nexport class AgentTaskRunner {\n private readonly handlers = new Map<string, ITaskHandler>()\n private readonly runningTasks = new Map<string, RunningTask>()\n private readonly logger: IScopedLogger\n\n constructor(\n private readonly agentId: string,\n private readonly client: AgentClient,\n logger: IScopedLogger,\n ) {\n this.logger = logger.child('TaskRunner')\n }\n\n /** Register a task handler for a given task type */\n registerHandler(handler: ITaskHandler): void {\n if (this.handlers.has(handler.taskType)) {\n this.logger.warn(`Overwriting handler for task type: ${handler.taskType}`)\n }\n this.handlers.set(handler.taskType, handler)\n this.logger.debug(`Registered handler: ${handler.taskType}`)\n }\n\n /** Unregister a task handler */\n unregisterHandler(taskType: string): void {\n this.handlers.delete(taskType)\n }\n\n /** Get all registered task types */\n getTaskTypes(): readonly string[] {\n return [...this.handlers.keys()]\n }\n\n /** Get a handler by task type */\n getHandler(taskType: string): ITaskHandler | undefined {\n return this.handlers.get(taskType)\n }\n\n /**\n * Execute a task dispatched from the hub.\n * Sends result or error back to hub via the AgentClient.\n */\n async executeTask(taskId: string, taskType: string, payload: unknown): Promise<void> {\n const handler = this.handlers.get(taskType)\n if (!handler) {\n this.client.send({\n type: 'task.result',\n taskId,\n success: false,\n error: `No handler registered for task type: ${taskType}`,\n })\n return\n }\n\n const runningTask: RunningTask = { taskId, taskType, cancelled: false }\n this.runningTasks.set(taskId, runningTask)\n\n const context: TaskContext = {\n taskId,\n agentId: this.agentId,\n logger: this.logger.child(taskType),\n reportProgress: (progress: TaskProgress) => {\n this.client.send({ type: 'task.progress', taskId, progress })\n },\n isCancelled: () => runningTask.cancelled,\n }\n\n try {\n const result = await handler.handle(payload, context)\n this.runningTasks.delete(taskId)\n\n if (!runningTask.cancelled) {\n this.client.send({\n type: 'task.result',\n taskId,\n success: true,\n result,\n })\n }\n } catch (err) {\n this.runningTasks.delete(taskId)\n\n this.logger.error(`Task ${taskType} (${taskId}) failed`, {\n message: err instanceof Error ? err.message : String(err),\n })\n\n this.client.send({\n type: 'task.result',\n taskId,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n /** Cancel a running task */\n async cancelTask(taskId: string): Promise<void> {\n const running = this.runningTasks.get(taskId)\n if (!running) return\n\n running.cancelled = true\n\n const handler = this.handlers.get(running.taskType)\n if (handler?.cancel) {\n try {\n await handler.cancel()\n } catch (err) {\n this.logger.error(`Error cancelling task ${taskId}`, {\n message: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n this.runningTasks.delete(taskId)\n }\n\n /** Number of currently running tasks */\n get activeTaskCount(): number {\n return this.runningTasks.size\n }\n\n /** Destroy: cancel all running tasks */\n async destroy(): Promise<void> {\n const taskIds = [...this.runningTasks.keys()]\n for (const taskId of taskIds) {\n await this.cancelTask(taskId)\n }\n this.handlers.clear()\n }\n}\n","import type { ITaskHandler, TaskContext } from '@camstack/types'\n\n/**\n * Stub task handler for pipeline.decode.\n * In the full implementation, this would start a StreamBroker for a camera\n * and send decoded frames to the hub via the AgentClient.\n */\nexport class DecodeTaskHandler implements ITaskHandler {\n readonly taskType = 'pipeline.decode'\n readonly description = 'Decode an RTSP stream and produce JPEG frames'\n\n async handle(payload: unknown, context: TaskContext): Promise<unknown> {\n const { logger } = context\n const config = payload as { cameraId?: string; rtspUrl?: string; fps?: number }\n\n if (!config.cameraId || !config.rtspUrl) {\n throw new Error('pipeline.decode requires cameraId and rtspUrl in payload')\n }\n\n logger.info(`Decode task started: camera=${config.cameraId} url=${config.rtspUrl} fps=${config.fps ?? 1}`)\n\n // Stub: actual implementation would start ffmpeg, produce frames,\n // and send them via the AgentClient's sendBinary method.\n return { status: 'started', cameraId: config.cameraId }\n }\n\n async cancel(): Promise<void> {\n // Stub: stop ffmpeg process\n }\n}\n\n/**\n * Stub task handler for pipeline.detect.\n * In the full implementation, this would receive frames (via binary WS),\n * run them through the detection engine, and send results back.\n */\nexport class DetectTaskHandler implements ITaskHandler {\n readonly taskType = 'pipeline.detect'\n readonly description = 'Run object detection on received frames'\n\n async handle(payload: unknown, context: TaskContext): Promise<unknown> {\n const { logger } = context\n const config = payload as {\n cameraId?: string\n modelId?: string\n runtime?: string\n confidence?: number\n }\n\n if (!config.cameraId) {\n throw new Error('pipeline.detect requires cameraId in payload')\n }\n\n logger.info(`Detect task started: camera=${config.cameraId} model=${config.modelId ?? 'default'} runtime=${config.runtime ?? 'auto'}`)\n\n // Stub: actual implementation would subscribe to binary frame stream,\n // run inference, and send detection results back to hub.\n return { status: 'started', cameraId: config.cameraId }\n }\n\n async cancel(): Promise<void> {\n // Stub: stop detection loop\n }\n}\n\n/**\n * Stub task handler for pipeline.record.\n * In the full implementation, this would start recording an RTSP stream\n * to disk in segments and report segment metadata back to the hub.\n */\nexport class RecordTaskHandler implements ITaskHandler {\n readonly taskType = 'pipeline.record'\n readonly description = 'Record an RTSP stream to disk segments'\n\n async handle(payload: unknown, context: TaskContext): Promise<unknown> {\n const { logger } = context\n const config = payload as { cameraId?: string; rtspUrl?: string; storagePath?: string }\n\n if (!config.cameraId || !config.rtspUrl) {\n throw new Error('pipeline.record requires cameraId and rtspUrl in payload')\n }\n\n logger.info(`Record task started: camera=${config.cameraId} url=${config.rtspUrl}`)\n\n // Stub: actual implementation would start ffmpeg copy-mode recording.\n return { status: 'started', cameraId: config.cameraId }\n }\n\n async cancel(): Promise<void> {\n // Stub: stop recording process\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { IScopedLogger, IEventBus } from '@camstack/types'\n\nexport type ElementState = 'stopped' | 'starting' | 'running' | 'stopping' | 'error' | 'disabled'\n\nexport interface ElementStatus {\n state: ElementState\n error?: string\n startedAt?: number\n stoppedAt?: number\n restartCount: number\n uptime: number\n}\n\nconst VALID_TRANSITIONS: Readonly<Record<ElementState, readonly ElementState[]>> = {\n stopped: ['starting', 'disabled'],\n starting: ['running', 'error', 'stopping'],\n running: ['stopping', 'error'],\n stopping: ['stopped', 'error'],\n error: ['starting', 'stopped', 'disabled'],\n disabled: ['stopped'],\n}\n\nexport class LifecycleStateMachine {\n private _state: ElementState = 'stopped'\n private _error?: string\n private _startedAt?: number\n private _stoppedAt?: number\n private _restartCount = 0\n private _hasStartedOnce = false\n\n constructor(\n private readonly elementId: string,\n private readonly elementType: 'provider' | 'device' | 'addon' | 'process',\n private readonly eventBus: IEventBus,\n private readonly logger: IScopedLogger,\n ) {}\n\n get state(): ElementState {\n return this._state\n }\n\n getStatus(): ElementStatus {\n return {\n state: this._state,\n error: this._error,\n startedAt: this._startedAt,\n stoppedAt: this._stoppedAt,\n restartCount: this._restartCount,\n uptime:\n this._state === 'running' && this._startedAt\n ? Date.now() - this._startedAt\n : 0,\n }\n }\n\n transition(to: ElementState, error?: string): boolean {\n const from = this._state\n\n if (!this.isValidTransition(from, to)) {\n this.logger.warn(`Invalid state transition: ${from} → ${to}`)\n return false\n }\n\n this._state = to\n this._error = error\n\n if (to === 'running') {\n if (this._hasStartedOnce) {\n this._restartCount++\n }\n this._hasStartedOnce = true\n this._startedAt = Date.now()\n this._stoppedAt = undefined\n }\n\n if (to === 'stopped' || to === 'error' || to === 'disabled') {\n this._stoppedAt = Date.now()\n }\n\n this.logger.info(`State: ${from} → ${to}${error ? ` (${error})` : ''}`)\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: this.elementType, id: this.elementId },\n category: `${this.elementType}.state.${to}`,\n data: { from, to, error, elementId: this.elementId },\n })\n\n return true\n }\n\n incrementRestartCount(): void {\n this._restartCount++\n }\n\n private isValidTransition(from: ElementState, to: ElementState): boolean {\n return VALID_TRANSITIONS[from]?.includes(to) ?? false\n }\n}\n","import type { FeatureManifest, FeatureFlag } from '@camstack/types'\n\nexport type { FeatureManifest, FeatureFlag }\n\nexport type FeatureConfigReader = {\n readonly features: FeatureManifest\n}\n\nexport class FeatureManager {\n constructor(private readonly configReader: FeatureConfigReader) {}\n\n isEnabled(flag: FeatureFlag): boolean {\n return this.configReader.features[flag]\n }\n\n getManifest(): FeatureManifest {\n return { ...this.configReader.features }\n }\n}\n","import type {\n EventSource,\n SystemEvent,\n EventFilter,\n IEventBus,\n} from '@camstack/types'\n\nexport type { EventSource, SystemEvent, EventFilter }\n\ninterface Subscriber {\n readonly filter: EventFilter\n readonly callback: (event: SystemEvent) => void\n}\n\nclass EventRingBuffer {\n private readonly buffer: Array<SystemEvent | undefined>\n private head = 0\n private count = 0\n\n constructor(private readonly capacity: number) {\n this.buffer = new Array(capacity)\n }\n\n push(event: SystemEvent): void {\n this.buffer[this.head] = event\n this.head = (this.head + 1) % this.capacity\n if (this.count < this.capacity) {\n this.count++\n }\n }\n\n getAll(): readonly SystemEvent[] {\n const result: SystemEvent[] = []\n for (let i = 0; i < this.count; i++) {\n const index = (this.head - 1 - i + this.capacity) % this.capacity\n result.push(this.buffer[index]!)\n }\n return result\n }\n\n query(filter?: EventFilter, limit?: number): readonly SystemEvent[] {\n let result = [...this.getAll()]\n\n if (filter) {\n result = result.filter((event) => matchesFilter(event, filter))\n }\n\n if (limit !== undefined && limit > 0) {\n return result.slice(0, limit)\n }\n\n return result\n }\n}\n\nfunction matchesCategory(eventCategory: string, filterCategory: string): boolean {\n if (filterCategory.endsWith('.*')) {\n const prefix = filterCategory.slice(0, -2)\n return eventCategory.startsWith(prefix + '.') || eventCategory === prefix\n }\n return eventCategory === filterCategory\n}\n\nfunction matchesFilter(event: SystemEvent, filter: EventFilter): boolean {\n if (filter.category && !matchesCategory(event.category, filter.category)) {\n return false\n }\n\n if (filter.source) {\n if (event.source.type !== filter.source.type || event.source.id !== filter.source.id) {\n return false\n }\n }\n\n if (filter.since && event.timestamp < filter.since) {\n return false\n }\n\n return true\n}\n\nexport class SystemEventBus implements IEventBus {\n private readonly ringBuffer: EventRingBuffer\n private readonly subscribers: Subscriber[] = []\n\n constructor(bufferSize: number = 10000) {\n this.ringBuffer = new EventRingBuffer(bufferSize)\n }\n\n emit(event: SystemEvent): void {\n this.ringBuffer.push(event)\n\n for (const subscriber of this.subscribers) {\n if (matchesFilter(event, subscriber.filter)) {\n subscriber.callback(event)\n }\n }\n }\n\n subscribe(filter: EventFilter, handler: (event: SystemEvent) => void): () => void {\n const subscriber: Subscriber = { filter, callback: handler }\n this.subscribers.push(subscriber)\n\n return () => {\n const index = this.subscribers.indexOf(subscriber)\n if (index !== -1) {\n this.subscribers.splice(index, 1)\n }\n }\n }\n\n getRecent(filter?: EventFilter, limit?: number): readonly SystemEvent[] {\n return this.ringBuffer.query(filter, limit)\n }\n}\n","import type { LogLevel, LogEntry, LogFilter } from '@camstack/types'\n\nexport type { LogLevel, LogEntry, LogFilter }\n\nexport class LogRingBuffer {\n private readonly buffer: Array<LogEntry | undefined>\n private head = 0\n private count = 0\n\n constructor(private readonly capacity: number = 10000) {\n this.buffer = new Array(capacity)\n }\n\n push(entry: LogEntry): void {\n this.buffer[this.head] = entry\n this.head = (this.head + 1) % this.capacity\n if (this.count < this.capacity) {\n this.count++\n }\n }\n\n getAll(): LogEntry[] {\n const result: LogEntry[] = []\n\n for (let i = 0; i < this.count; i++) {\n const index = (this.head - 1 - i + this.capacity) % this.capacity\n result.push(this.buffer[index]!)\n }\n\n return result\n }\n\n query(filter: LogFilter): LogEntry[] {\n const all = this.getAll()\n let result = all\n\n if (filter.scope && filter.scope.length > 0) {\n result = result.filter((entry) => {\n for (let i = 0; i < filter.scope!.length; i++) {\n if (entry.scope[i] !== filter.scope![i]) return false\n }\n return true\n })\n }\n\n if (filter.level) {\n result = result.filter((entry) => entry.level === filter.level)\n }\n\n if (filter.since) {\n result = result.filter((entry) => entry.timestamp >= filter.since!)\n }\n\n if (filter.until) {\n result = result.filter((entry) => entry.timestamp <= filter.until!)\n }\n\n if (filter.limit !== undefined && filter.limit > 0) {\n result = result.slice(0, filter.limit)\n }\n\n return result\n }\n}\n","import type { IScopedLogger } from '@camstack/types'\nimport type { LogEntry, LogLevel } from './log-ring-buffer.js'\n\nexport type { IScopedLogger }\n\nexport class ScopedLogger implements IScopedLogger {\n constructor(\n private readonly scope: string[],\n private readonly writeFn: (entry: LogEntry) => void,\n ) {}\n\n debug(message: string, meta?: Record<string, unknown>): void {\n this.write('debug', message, meta)\n }\n\n info(message: string, meta?: Record<string, unknown>): void {\n this.write('info', message, meta)\n }\n\n warn(message: string, meta?: Record<string, unknown>): void {\n this.write('warn', message, meta)\n }\n\n error(message: string, meta?: Record<string, unknown>): void {\n this.write('error', message, meta)\n }\n\n child(childScope: string): IScopedLogger {\n return new ScopedLogger([...this.scope, childScope], this.writeFn)\n }\n\n private write(level: LogLevel, message: string, meta?: Record<string, unknown>): void {\n const entry: LogEntry = {\n timestamp: new Date(),\n level,\n scope: this.scope,\n message,\n ...(meta !== undefined ? { meta } : {}),\n }\n this.writeFn(entry)\n }\n}\n","import { LogRingBuffer, type LogEntry, type LogFilter } from './log-ring-buffer.js'\nimport { ScopedLogger, type IScopedLogger } from './scoped-logger.js'\n\nexport interface ILogDestination {\n initialize(): Promise<void>\n shutdown(): Promise<void>\n write(entry: LogEntry): void\n query?(filter: LogFilter): Promise<readonly LogEntry[]>\n}\n\nexport class LogManager {\n private readonly ringBuffer: LogRingBuffer\n private readonly destinations: ILogDestination[] = []\n private readonly subscribers = new Map<string, { filter: Partial<LogFilter>; callback: (entry: LogEntry) => void }>()\n\n constructor(bufferSize: number = 10000) {\n this.ringBuffer = new LogRingBuffer(bufferSize)\n }\n\n createLogger(scope: string): IScopedLogger {\n return new ScopedLogger([scope], (entry: LogEntry) => {\n this.ringBuffer.push(entry)\n for (const dest of this.destinations) {\n dest.write(entry)\n }\n // Notify real-time subscribers\n for (const [, sub] of this.subscribers) {\n if (this.matchesFilter(entry, sub.filter)) {\n try { sub.callback(entry) } catch { /* subscriber error — ignore */ }\n }\n }\n })\n }\n\n /** Subscribe to live logs matching a filter. Returns an unsubscribe function. */\n subscribe(filter: Partial<LogFilter>, callback: (entry: LogEntry) => void): () => void {\n const id = Math.random().toString(36).slice(2)\n this.subscribers.set(id, { filter, callback })\n return () => { this.subscribers.delete(id) }\n }\n\n private matchesFilter(entry: LogEntry, filter: Partial<LogFilter>): boolean {\n if (filter.scope && filter.scope.length > 0) {\n const entryScope = entry.scope?.[0] ?? ''\n if (!filter.scope.some(s => entryScope === s || entryScope.startsWith(s))) return false\n }\n if (filter.level) {\n const levels: string[] = ['debug', 'info', 'warn', 'error']\n const minIdx = levels.indexOf(filter.level)\n const entryIdx = levels.indexOf(entry.level)\n if (entryIdx < minIdx) return false\n }\n return true\n }\n\n addDestination(dest: ILogDestination): void {\n this.destinations.push(dest)\n }\n\n removeDestination(dest: ILogDestination): void {\n const index = this.destinations.indexOf(dest)\n if (index !== -1) {\n this.destinations.splice(index, 1)\n }\n }\n\n query(filter: LogFilter): LogEntry[] {\n return this.ringBuffer.query(filter)\n }\n}\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { StorageLocationManager, StorageLocationName } from './storage-location-manager.js'\nimport type {\n IStorageProvider as INewStorageProvider,\n ISettingsBackend,\n} from '@camstack/types'\n\n// Legacy interfaces — still used by consumers during migration\nexport interface IStorageProvider {\n initialize(): Promise<void>\n shutdown(): Promise<void>\n getLocation(name: StorageLocationName): IStorageLocation\n export?(locationName: StorageLocationName): Promise<Buffer>\n import?(locationName: StorageLocationName, data: Buffer): Promise<void>\n}\n\nexport interface QueryFilter {\n where?: Record<string, unknown>\n whereIn?: Record<string, unknown[]>\n whereBetween?: Record<string, [unknown, unknown]>\n orderBy?: { field: string; direction: 'asc' | 'desc' }\n limit?: number\n offset?: number\n}\n\nexport interface StorageRecord {\n collection: string\n id: string\n data: Record<string, unknown>\n}\n\nexport interface IStructuredStorage {\n query(collection: string, filter?: QueryFilter): Promise<readonly StorageRecord[]>\n insert(record: StorageRecord): Promise<StorageRecord>\n update(collection: string, id: string, data: Record<string, unknown>): Promise<StorageRecord>\n delete(collection: string, id: string): Promise<void>\n count(collection: string, filter?: QueryFilter): Promise<number>\n}\n\nexport interface IFileStorage {\n readFile(path: string): Promise<Buffer>\n writeFile(path: string, data: Buffer): Promise<void>\n deleteFile(path: string): Promise<void>\n listFiles(prefix?: string): Promise<readonly string[]>\n getFileUrl(path: string): Promise<string>\n exists(path: string): Promise<boolean>\n}\n\nexport interface IStorageLocation {\n structured?: IStructuredStorage\n files?: IFileStorage\n}\n\n/**\n * StorageManager — bridge between legacy code (getLocation/getLocationPath)\n * and the new capability-based storage system.\n *\n * Legacy consumers call getLocation('addon', namespace) to get structured + file storage.\n * This manager builds the response from:\n * - SettingsBackend (for structured queries) — provided by sqlite-settings addon\n * - LocationManager (for file paths) — set during Phase 2 boot\n */\nexport class StorageManager {\n private legacyProvider: IStorageProvider | null = null\n private locationManager: StorageLocationManager | null = null\n private newStorageProvider: INewStorageProvider | null = null\n private settingsBackend: ISettingsBackend | null = null\n\n /** @deprecated Set by legacy capability consumer — use setNewStorageProvider instead */\n setProvider(provider: IStorageProvider | INewStorageProvider): void {\n // Check if it's the new provider (has 'supportedLocations') or legacy (has 'getLocation')\n if ('getLocation' in provider && typeof (provider as any).getLocation === 'function') {\n this.legacyProvider = provider as IStorageProvider\n } else {\n this.newStorageProvider = provider as INewStorageProvider\n }\n }\n\n setNewStorageProvider(provider: INewStorageProvider): void {\n this.newStorageProvider = provider\n }\n\n setSettingsBackend(backend: ISettingsBackend): void {\n this.settingsBackend = backend\n }\n\n getProvider(): IStorageProvider {\n if (this.legacyProvider) return this.legacyProvider\n if (!this.newStorageProvider && !this.settingsBackend && !this.locationManager) {\n throw new Error('No storage provider configured')\n }\n // Return a shim that wraps new providers\n return this.createLegacyShim()\n }\n\n setLocationManager(manager: StorageLocationManager): void {\n this.locationManager = manager\n }\n\n getLocationManager(): StorageLocationManager {\n if (!this.locationManager) {\n throw new Error('StorageLocationManager not initialized')\n }\n return this.locationManager\n }\n\n async initializeLocations(dataPath: string): Promise<void> {\n const { StorageLocationManager } = await import('./storage-location-manager.js')\n const manager = new StorageLocationManager(dataPath)\n await manager.initializeDefaults()\n this.locationManager = manager\n }\n\n getLocationPath(name: StorageLocationName): string {\n return this.getLocationManager().getBackend(name).basePath\n }\n\n /**\n * Get a storage location with optional namespace scoping.\n * Builds IStorageLocation from settingsBackend (structured) + locationManager (files).\n */\n getLocation(name: StorageLocationName | string, namespace?: string): IStorageLocation {\n if (!this.legacyProvider && !this.newStorageProvider && !this.settingsBackend && !this.locationManager) {\n throw new Error('No storage provider configured')\n }\n // Try legacy provider first\n if (this.legacyProvider) {\n try {\n const LEGACY_MAP: Record<string, string> = { config: 'data', events: 'data', addon: 'data' }\n const mappedName = (LEGACY_MAP[name] ?? name) as StorageLocationName\n const location = this.legacyProvider.getLocation(mappedName)\n return namespace ? this.createNamespacedLocation(location, namespace) : location\n } catch {\n // Fall through to new approach\n }\n }\n\n // Build from new providers\n const location: IStorageLocation = {}\n\n // Structured storage from settingsBackend\n if (this.settingsBackend) {\n const backend = this.settingsBackend\n location.structured = {\n async query(collection: string, filter?: QueryFilter) {\n const results = await backend.query(collection as any, filter)\n return results.map(r => ({ collection, id: r.id, data: r.data }))\n },\n async insert(record: StorageRecord) {\n const id = record.id || (await import('node:crypto')).randomUUID()\n await backend.insert(record.collection as any, { id, data: record.data })\n return { ...record, id }\n },\n async update(collection: string, id: string, data: Record<string, unknown>) {\n await backend.update(collection as any, id, data)\n return { collection, id, data }\n },\n async delete(collection: string, id: string) {\n await backend.delete(collection as any, id)\n },\n async count(collection: string, filter?: QueryFilter) {\n return backend.count(collection as any, filter)\n },\n }\n }\n\n // File storage from locationManager\n if (this.locationManager) {\n const LEGACY_MAP: Record<string, string> = { config: 'data', events: 'data', addon: 'data' }\n const mappedName = (LEGACY_MAP[name] ?? name) as StorageLocationName\n try {\n const basePath = this.locationManager.getBackend(mappedName).basePath\n location.files = {\n async readFile(p: string) { return fs.promises.readFile(path.join(basePath, p)) },\n async writeFile(p: string, data: Buffer) {\n const full = path.join(basePath, p)\n await fs.promises.mkdir(path.dirname(full), { recursive: true })\n await fs.promises.writeFile(full, data)\n },\n async deleteFile(p: string) { await fs.promises.rm(path.join(basePath, p), { force: true }) },\n async listFiles(prefix?: string) {\n const dir = prefix ? path.join(basePath, prefix) : basePath\n try { return (await fs.promises.readdir(dir)).map(f => prefix ? `${prefix}/${f}` : f) } catch { return [] }\n },\n async getFileUrl(p: string) { return path.join(basePath, p) },\n async exists(p: string) { try { await fs.promises.access(path.join(basePath, p)); return true } catch { return false } },\n }\n } catch {\n // Location not available\n }\n }\n\n return namespace ? this.createNamespacedLocation(location, namespace) : location\n }\n\n private createLegacyShim(): IStorageProvider {\n const self = this\n return {\n async initialize() {},\n async shutdown() {},\n getLocation(name: StorageLocationName) { return self.getLocation(name) },\n }\n }\n\n private createNamespacedLocation(location: IStorageLocation, namespace: string): IStorageLocation {\n const prefix = namespace.endsWith('/') ? namespace : `${namespace}/`\n\n return {\n structured: location.structured ? {\n async query(collection: string, filter?: QueryFilter) {\n return location.structured!.query(`${prefix}${collection}`, filter)\n },\n async insert(record: StorageRecord) {\n return location.structured!.insert({ ...record, collection: `${prefix}${record.collection}` })\n },\n async update(collection: string, id: string, data: Record<string, unknown>) {\n return location.structured!.update(`${prefix}${collection}`, id, data)\n },\n async delete(collection: string, id: string) {\n return location.structured!.delete(`${prefix}${collection}`, id)\n },\n async count(collection: string, filter?: QueryFilter) {\n return location.structured!.count(`${prefix}${collection}`, filter)\n },\n } : undefined,\n\n files: location.files ? {\n async readFile(p: string) { return location.files!.readFile(`${prefix}${p}`) },\n async writeFile(p: string, data: Buffer) { return location.files!.writeFile(`${prefix}${p}`, data) },\n async deleteFile(p: string) { return location.files!.deleteFile(`${prefix}${p}`) },\n async listFiles(filePrefix?: string) { return location.files!.listFiles(`${prefix}${filePrefix ?? ''}`) },\n async getFileUrl(p: string) { return location.files!.getFileUrl(`${prefix}${p}`) },\n async exists(p: string) { return location.files!.exists(`${prefix}${p}`) },\n } : undefined,\n }\n }\n}\n","import * as jwt from 'jsonwebtoken'\nimport * as bcrypt from 'bcryptjs'\nimport * as crypto from 'node:crypto'\nimport type { ScopedToken, UserRole, TokenPayload } from '@camstack/types'\nimport type { ScopedTokenManager } from './scoped-token-manager.js'\n\nexport type { UserRole, TokenPayload }\n\nexport type AuthConfigReader = {\n get<T>(path: string): T\n update(section: string, data: Record<string, unknown>): void\n}\n\nexport class AuthManager {\n private readonly jwtSecret: string\n private scopedTokenManager: ScopedTokenManager | null = null\n\n constructor(private readonly config: AuthConfigReader) {\n const configured = this.config.get<string>('auth.jwtSecret')\n if (configured) {\n this.jwtSecret = configured\n } else {\n const secret = crypto.randomBytes(32).toString('hex')\n // Persist directly into config.yaml so it survives restarts\n this.config.update('auth', { jwtSecret: secret })\n console.log('[AuthManager] Generated JWT secret and saved to config.yaml (auth.jwtSecret)')\n this.jwtSecret = secret\n }\n }\n\n signToken(payload: Omit<TokenPayload, 'iat' | 'exp'>): string {\n return jwt.sign({ ...payload }, this.jwtSecret, { expiresIn: '24h' })\n }\n\n verifyToken(token: string): TokenPayload {\n return jwt.verify(token, this.jwtSecret) as TokenPayload\n }\n\n async hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, 10)\n }\n\n async comparePassword(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash)\n }\n\n generateApiKey(): { token: string; hash: string; prefix: string } {\n const token = crypto.randomBytes(32).toString('hex')\n const hash = crypto.createHash('sha256').update(token).digest('hex')\n const prefix = token.slice(0, 8)\n return { token, hash, prefix }\n }\n\n validateApiKey(token: string, storedHash: string): boolean {\n const hash = crypto.createHash('sha256').update(token).digest('hex')\n return hash === storedHash\n }\n\n /**\n * Create a service token for agent/worker authentication.\n * Used when forking workers or when agents register.\n */\n createServiceToken(opts: {\n readonly agentId: string\n readonly role?: string\n readonly expiresIn?: string\n }): string {\n const payload: Record<string, unknown> = {\n userId: opts.agentId,\n username: opts.agentId,\n role: opts.role ?? 'agent',\n type: 'service',\n agentId: opts.agentId,\n allowedProviders: '*',\n allowedDevices: {},\n }\n const expiresIn = (opts.expiresIn ?? '24h') as jwt.SignOptions['expiresIn']\n return jwt.sign(payload as object, this.jwtSecret, { expiresIn })\n }\n\n /**\n * Set the scoped token manager for the auth chain.\n */\n setScopedTokenManager(manager: ScopedTokenManager): void {\n this.scopedTokenManager = manager\n }\n\n /**\n * Validate a scoped token string.\n * Returns the token record if valid, null otherwise.\n */\n async validateScopedToken(rawToken: string): Promise<ScopedToken | null> {\n if (!this.scopedTokenManager) {\n return null\n }\n return this.scopedTokenManager.validate(rawToken)\n }\n\n /**\n * Check whether a scoped token grants access to a given addon/route/capability.\n */\n matchesScopedTokenScope(\n token: ScopedToken,\n addonId?: string,\n routePath?: string,\n capability?: string,\n ): boolean {\n if (!this.scopedTokenManager) {\n return false\n }\n return this.scopedTokenManager.matchesScope(token, addonId, routePath, capability)\n }\n}\n","import * as crypto from 'node:crypto'\nimport type { AuthManager, UserRole } from './auth-manager.js'\nimport type { IStructuredStorage, StorageRecord, QueryFilter } from '../storage/storage-manager.js'\n\nexport interface ApiKeyRecord {\n id: string\n label: string\n role: UserRole\n allowedProviders: string[] | '*'\n allowedDevices: Record<string, string[] | '*'>\n tokenHash: string\n tokenPrefix: string\n createdAt: number\n lastUsedAt?: number\n}\n\ninterface CreateApiKeyInput {\n label: string\n role: UserRole\n allowedProviders?: string[] | '*'\n allowedDevices?: Record<string, string[] | '*'>\n}\n\nconst API_KEYS_COLLECTION = 'api_keys'\n\nexport type ApiKeyStorageAccess = {\n getStructuredStorage(): IStructuredStorage\n}\n\nexport class ApiKeyManager {\n constructor(\n private readonly storageAccess: ApiKeyStorageAccess,\n private readonly auth: AuthManager,\n ) {}\n\n private get structured(): IStructuredStorage {\n return this.storageAccess.getStructuredStorage()\n }\n\n async create(input: CreateApiKeyInput): Promise<{ record: ApiKeyRecord; token: string }> {\n const { token, hash, prefix } = this.auth.generateApiKey()\n const now = Date.now()\n\n const record: ApiKeyRecord = {\n id: crypto.randomUUID(),\n label: input.label,\n role: input.role,\n allowedProviders: input.allowedProviders ?? '*',\n allowedDevices: input.allowedDevices ?? {},\n tokenHash: hash,\n tokenPrefix: prefix,\n createdAt: now,\n }\n\n await this.structured.insert({\n collection: API_KEYS_COLLECTION,\n id: record.id,\n data: record as unknown as Record<string, unknown>,\n })\n\n return { record, token }\n }\n\n async validateToken(token: string): Promise<ApiKeyRecord | null> {\n const allKeys = await this.structured.query(API_KEYS_COLLECTION)\n\n for (const entry of allKeys) {\n const record = entry.data as unknown as ApiKeyRecord\n if (this.auth.validateApiKey(token, record.tokenHash)) {\n const updatedData: Record<string, unknown> = {\n ...record,\n lastUsedAt: Date.now(),\n }\n await this.structured.update(API_KEYS_COLLECTION, record.id, updatedData)\n return { ...record, lastUsedAt: updatedData.lastUsedAt as number }\n }\n }\n\n return null\n }\n\n async listAll(): Promise<Omit<ApiKeyRecord, 'tokenHash'>[]> {\n const results = await this.structured.query(API_KEYS_COLLECTION)\n return results.map((r) => {\n const { tokenHash, ...rest } = r.data as unknown as ApiKeyRecord\n return rest\n })\n }\n\n async revoke(id: string): Promise<void> {\n await this.structured.delete(API_KEYS_COLLECTION, id)\n }\n\n async findById(id: string): Promise<ApiKeyRecord | null> {\n const results = await this.structured.query(API_KEYS_COLLECTION, {\n where: { id },\n })\n\n if (results.length === 0) {\n return null\n }\n\n return results[0]!.data as unknown as ApiKeyRecord\n }\n}\n","import * as crypto from 'node:crypto'\nimport type { AuthManager, UserRole } from './auth-manager.js'\nimport type { IStructuredStorage } from '../storage/storage-manager.js'\nimport type { UserRecord } from '@camstack/types'\n\nexport type { UserRecord }\n\ninterface CreateUserInput {\n username: string\n password: string\n role: UserRole\n allowedProviders?: string[] | '*'\n allowedDevices?: Record<string, string[] | '*'>\n}\n\ntype UpdatableUserFields = Partial<Pick<UserRecord, 'role' | 'allowedProviders' | 'allowedDevices'>>\n\nconst USERS_COLLECTION = 'users'\n\nexport type UserStorageAccess = {\n getStructuredStorage(): IStructuredStorage\n}\n\nexport type UserConfigReader = {\n get<T>(path: string): T\n}\n\nexport class UserManager {\n constructor(\n private readonly storageAccess: UserStorageAccess,\n private readonly auth: AuthManager,\n private readonly config: UserConfigReader,\n ) {}\n\n private get structured(): IStructuredStorage {\n return this.storageAccess.getStructuredStorage()\n }\n\n async create(input: CreateUserInput): Promise<UserRecord> {\n const existing = await this.findByUsername(input.username)\n if (existing) {\n throw new Error(`User with username \"${input.username}\" already exists`)\n }\n\n const passwordHash = await this.auth.hashPassword(input.password)\n const now = Date.now()\n const record: UserRecord = {\n id: crypto.randomUUID(),\n username: input.username,\n passwordHash,\n role: input.role,\n allowedProviders: input.allowedProviders ?? '*',\n allowedDevices: input.allowedDevices ?? {},\n createdAt: now,\n updatedAt: now,\n }\n\n await this.structured.insert({\n collection: USERS_COLLECTION,\n id: record.id,\n data: record as unknown as Record<string, unknown>,\n })\n\n return record\n }\n\n async findByUsername(username: string): Promise<UserRecord | null> {\n const results = await this.structured.query(USERS_COLLECTION, {\n where: { username },\n })\n\n if (results.length === 0) {\n return null\n }\n\n return results[0]!.data as unknown as UserRecord\n }\n\n async findById(id: string): Promise<UserRecord | null> {\n const results = await this.structured.query(USERS_COLLECTION, {\n where: { id },\n })\n\n if (results.length === 0) {\n return null\n }\n\n return results[0]!.data as unknown as UserRecord\n }\n\n async validateCredentials(username: string, password: string): Promise<UserRecord | null> {\n const user = await this.findByUsername(username)\n if (!user) {\n return null\n }\n\n const valid = await this.auth.comparePassword(password, user.passwordHash)\n return valid ? user : null\n }\n\n async listAll(): Promise<Omit<UserRecord, 'passwordHash'>[]> {\n const results = await this.structured.query(USERS_COLLECTION)\n return results.map((r) => {\n const { passwordHash, ...rest } = r.data as unknown as UserRecord\n return rest\n })\n }\n\n async update(id: string, data: UpdatableUserFields): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new Error(`User with id \"${id}\" not found`)\n }\n\n const updatedData: Record<string, unknown> = {\n ...existing,\n ...data,\n updatedAt: Date.now(),\n }\n\n await this.structured.update(USERS_COLLECTION, id, updatedData)\n }\n\n async delete(id: string): Promise<void> {\n await this.structured.delete(USERS_COLLECTION, id)\n }\n\n async resetPassword(id: string, newPassword: string): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new Error(`User with id \"${id}\" not found`)\n }\n\n const passwordHash = await this.auth.hashPassword(newPassword)\n const updatedData: Record<string, unknown> = {\n ...existing,\n passwordHash,\n updatedAt: Date.now(),\n }\n\n await this.structured.update(USERS_COLLECTION, id, updatedData)\n }\n\n async ensureAdminExists(): Promise<void> {\n const adminUsername = this.config.get<string>('auth.adminUsername')\n const adminPassword = this.config.get<string>('auth.adminPassword')\n\n if (!adminUsername || !adminPassword) {\n return\n }\n\n const existing = await this.findByUsername(adminUsername)\n if (existing) {\n return\n }\n\n await this.create({\n username: adminUsername,\n password: adminPassword,\n role: 'super_admin',\n allowedProviders: '*',\n allowedDevices: {},\n })\n }\n}\n","import * as crypto from 'node:crypto'\nimport type { ScopedToken, TokenScope } from '@camstack/types'\nimport type { IStructuredStorage, StorageRecord } from '../storage/storage-manager.js'\n\nconst TOKENS_COLLECTION = 'scoped_tokens'\nconst TOKEN_PREFIX = 'cst_'\n\n/**\n * Manages scoped API tokens with restricted addon/route/capability access.\n * Framework-agnostic — dependencies injected via constructor.\n */\nexport class ScopedTokenManager {\n constructor(private readonly storage: IStructuredStorage) {}\n\n /**\n * Create a new scoped token. Returns the raw token string (shown once)\n * and the stored record (with hash, not the raw token).\n */\n async create(\n userId: string,\n name: string,\n scopes: TokenScope[],\n expiresAt?: number,\n ): Promise<{ token: string; record: ScopedToken }> {\n const rawHex = crypto.randomBytes(32).toString('hex')\n const rawToken = `${TOKEN_PREFIX}${rawHex}`\n const tokenHash = crypto.createHash('sha256').update(rawToken).digest('hex')\n const tokenPrefix = rawToken.slice(0, 12)\n\n const record: ScopedToken = {\n id: crypto.randomUUID(),\n userId,\n name,\n tokenHash,\n tokenPrefix,\n scopes: scopes.map((s) => ({ ...s })),\n expiresAt,\n lastUsedAt: undefined,\n createdAt: Date.now(),\n }\n\n await this.storage.insert({\n collection: TOKENS_COLLECTION,\n id: record.id,\n data: record as unknown as Record<string, unknown>,\n })\n\n return { token: rawToken, record }\n }\n\n /**\n * Validate a raw token string. Returns the token record if valid, null otherwise.\n */\n async validate(rawToken: string): Promise<ScopedToken | null> {\n if (!rawToken.startsWith(TOKEN_PREFIX)) {\n return null\n }\n\n const tokenHash = crypto.createHash('sha256').update(rawToken).digest('hex')\n const results = await this.storage.query(TOKENS_COLLECTION, {\n where: { tokenHash },\n })\n\n if (results.length === 0) {\n return null\n }\n\n const record = results[0]!.data as unknown as ScopedToken\n if (record.expiresAt !== undefined && record.expiresAt !== null && Date.now() > record.expiresAt) {\n return null\n }\n\n // Update last used timestamp (fire and forget)\n this.updateLastUsed(record.id).catch(() => {})\n\n return record\n }\n\n /**\n * Check whether a token's scopes grant access to the given addon, route, or capability.\n */\n matchesScope(\n token: ScopedToken,\n addonId?: string,\n routePath?: string,\n capability?: string,\n ): boolean {\n for (const scope of token.scopes) {\n switch (scope.type) {\n case 'addon':\n if (addonId && scope.target === addonId) return true\n break\n case 'route-prefix':\n if (routePath && routePath.startsWith(scope.target)) return true\n break\n case 'capability':\n if (capability && scope.target === capability) return true\n break\n }\n }\n return false\n }\n\n /**\n * Revoke a token by ID.\n */\n async revoke(tokenId: string): Promise<void> {\n await this.storage.delete(TOKENS_COLLECTION, tokenId)\n }\n\n /**\n * List all tokens for a user (without exposing the raw token).\n */\n async listForUser(userId: string): Promise<ScopedToken[]> {\n const results = await this.storage.query(TOKENS_COLLECTION, {\n where: { userId },\n })\n return results.map((r: StorageRecord) => r.data as unknown as ScopedToken)\n }\n\n /**\n * Update the lastUsedAt timestamp for a token.\n */\n async updateLastUsed(tokenId: string): Promise<void> {\n const results = await this.storage.query(TOKENS_COLLECTION, {\n where: { id: tokenId },\n })\n if (results.length === 0) return\n\n const existing = results[0]!.data as unknown as ScopedToken\n await this.storage.update(TOKENS_COLLECTION, tokenId, {\n ...existing,\n lastUsedAt: Date.now(),\n } as unknown as Record<string, unknown>)\n }\n}\n","import type { INotificationOutput, Notification } from '@camstack/types'\nimport type { IScopedLogger } from '../logging/scoped-logger.js'\nimport type { CapabilityRegistry } from '@camstack/kernel'\n\n/**\n * Central notification service that routes notifications to configured outputs.\n * Framework-agnostic — dependencies injected via constructor.\n *\n * Outputs are resolved from the CapabilityRegistry's 'notification-output'\n * collection on each call (proxy pattern). Falls back to a local map\n * when no registry is provided (backward compat).\n */\nexport class NotificationService {\n private readonly localOutputs = new Map<string, INotificationOutput>()\n private readonly routing = new Map<string, string[]>()\n private readonly rateLimits = new Map<string, number>()\n private readonly lastSent = new Map<string, number>()\n private registry: CapabilityRegistry | null = null\n\n constructor(private readonly logger: IScopedLogger) {}\n\n /** Set the registry for live output lookup. Called once during boot. */\n setRegistry(registry: CapabilityRegistry): void {\n this.registry = registry\n }\n\n /** Resolve all outputs — prefers registry, falls back to local map */\n private get outputs(): ReadonlyMap<string, INotificationOutput> {\n if (this.registry) {\n const collection = this.registry.getCollection<INotificationOutput>('notification-output')\n const map = new Map<string, INotificationOutput>()\n for (const output of collection) {\n map.set(output.id, output)\n }\n return map\n }\n return this.localOutputs\n }\n\n /** @deprecated Use registry-based resolution. Kept for backward compat only. */\n addOutput(output: INotificationOutput): void {\n this.localOutputs.set(output.id, output)\n this.logger.info(`Notification output added: ${output.name} (${output.id})`)\n }\n\n /** @deprecated Use registry-based resolution. Kept for backward compat only. */\n removeOutput(id: string): void {\n this.localOutputs.delete(id)\n this.logger.info(`Notification output removed: ${id}`)\n }\n\n setRouting(category: string, outputIds: string[]): void {\n this.routing.set(category, [...outputIds])\n }\n\n setRateLimit(category: string, minIntervalMs: number): void {\n this.rateLimits.set(category, minIntervalMs)\n }\n\n async notify(notification: Notification): Promise<void> {\n const { category, deviceId } = notification\n\n // Rate limit check\n const rateLimitKey = deviceId ? `${category}:${deviceId}` : category\n const minInterval = this.rateLimits.get(category) ?? 0\n if (minInterval > 0) {\n const last = this.lastSent.get(rateLimitKey) ?? 0\n if (notification.timestamp - last < minInterval) {\n this.logger.debug(`Rate limited: ${rateLimitKey}`)\n return\n }\n }\n\n // Determine target outputs\n const targetIds = this.routing.get(category) ?? this.routing.get('*') ?? []\n if (targetIds.length === 0) {\n this.logger.debug(`No routing configured for category \"${category}\"`)\n return\n }\n\n const currentOutputs = this.outputs\n\n // Update last-sent timestamp\n this.lastSent.set(rateLimitKey, notification.timestamp)\n\n // Send to all targets in parallel with error isolation\n await Promise.allSettled(\n targetIds\n .map((id) => currentOutputs.get(id))\n .filter((output): output is INotificationOutput => output !== undefined)\n .map(async (output) => {\n try {\n await output.send(notification)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n this.logger.error(`Notification output \"${output.id}\" failed: ${msg}`)\n }\n }),\n )\n\n return undefined\n }\n\n getOutputs(): ReadonlyArray<{ id: string; name: string; icon: string }> {\n return Array.from(this.outputs.values()).map(({ id, name, icon }) => ({ id, name, icon }))\n }\n\n getRouting(): ReadonlyMap<string, string[]> {\n return this.routing\n }\n\n getOutput(id: string): INotificationOutput | undefined {\n return this.outputs.get(id)\n }\n}\n","import type { Toast } from '@camstack/types'\n\nexport type Unsubscribe = () => void\n\ninterface ListenerEntry {\n readonly userId: string\n readonly callback: (toast: Toast) => void\n}\n\n/**\n * Service for broadcasting toast notifications to connected UI clients.\n * Framework-agnostic — integrates with tRPC subscriptions via subscribe().\n */\nexport class ToastService {\n private readonly listeners = new Map<string, ListenerEntry>()\n\n /**\n * Subscribe to toast events for a specific user.\n * Returns an unsubscribe function.\n */\n subscribe(connectionId: string, userId: string, callback: (toast: Toast) => void): Unsubscribe {\n this.listeners.set(connectionId, { userId, callback })\n return () => {\n this.listeners.delete(connectionId)\n }\n }\n\n /**\n * Broadcast a toast to all connected clients.\n */\n broadcast(toast: Toast): void {\n for (const entry of this.listeners.values()) {\n entry.callback(toast)\n }\n }\n\n /**\n * Send a toast to a specific user's connections only.\n */\n sendToUser(userId: string, toast: Toast): void {\n for (const entry of this.listeners.values()) {\n if (entry.userId === userId) {\n entry.callback(toast)\n }\n }\n }\n}\n","import type { IAddonHttpRoute, IAddonRouteProvider } from '@camstack/types'\n\ninterface RouteMatch {\n readonly route: IAddonHttpRoute\n readonly addonId: string\n readonly params: Record<string, string>\n}\n\ninterface RegisteredRoute {\n readonly addonId: string\n readonly route: IAddonHttpRoute\n /** Full path including /addon/{addonId}/ prefix */\n readonly fullPath: string\n}\n\n/**\n * Registry for dynamic HTTP routes registered by addons.\n * Framework-agnostic — the server HTTP layer queries this registry to dispatch requests.\n */\nexport class AddonRouteRegistry {\n private readonly routes = new Map<string, RegisteredRoute[]>()\n\n /**\n * Register all routes from an addon's route provider.\n */\n registerRoutes(addonId: string, provider: IAddonRouteProvider): void {\n const addonRoutes = provider.getRoutes()\n const registered: RegisteredRoute[] = addonRoutes.map((route) => {\n const normalizedPath = route.path.startsWith('/') ? route.path : `/${route.path}`\n return {\n addonId,\n route,\n fullPath: `/addon/${addonId}${normalizedPath}`,\n }\n })\n this.routes.set(addonId, registered)\n }\n\n /**\n * Unregister all routes for an addon.\n */\n unregisterRoutes(addonId: string): void {\n this.routes.delete(addonId)\n }\n\n /**\n * Match an incoming request method + path to a registered route.\n * Supports simple path parameters (e.g., /items/:id).\n */\n matchRoute(method: string, path: string): RouteMatch | null {\n const normalizedMethod = method.toUpperCase()\n\n for (const registeredRoutes of this.routes.values()) {\n for (const entry of registeredRoutes) {\n if (entry.route.method !== normalizedMethod) continue\n\n const params = matchPath(entry.fullPath, path)\n if (params !== null) {\n return {\n route: entry.route,\n addonId: entry.addonId,\n params,\n }\n }\n }\n }\n\n return null\n }\n\n /**\n * List all registered routes across all addons.\n */\n listRoutes(): ReadonlyArray<{ addonId: string; method: string; path: string; access: string; description?: string }> {\n const result: Array<{ addonId: string; method: string; path: string; access: string; description?: string }> = []\n for (const registeredRoutes of this.routes.values()) {\n for (const entry of registeredRoutes) {\n result.push({\n addonId: entry.addonId,\n method: entry.route.method,\n path: entry.fullPath,\n access: entry.route.access,\n description: entry.route.description,\n })\n }\n }\n return result\n }\n}\n\n/**\n * Match a route pattern against an actual path.\n * Supports :param segments (e.g., /addon/:addonId/items/:id).\n * Returns extracted params or null if no match.\n */\nfunction matchPath(pattern: string, path: string): Record<string, string> | null {\n const patternParts = pattern.split('/').filter(Boolean)\n const pathParts = path.split('/').filter(Boolean)\n\n if (patternParts.length !== pathParts.length) {\n return null\n }\n\n const params: Record<string, string> = {}\n\n for (let i = 0; i < patternParts.length; i++) {\n const patternPart = patternParts[i]!\n const pathPart = pathParts[i]!\n\n if (patternPart.startsWith(':')) {\n params[patternPart.slice(1)] = pathPart\n } else if (patternPart !== pathPart) {\n return null\n }\n }\n\n return params\n}\n","import { randomUUID } from 'node:crypto'\nimport type { IScopedLogger, IEventBus, LoggerFactory } from '@camstack/types'\n\nexport interface IRegisteredDevice {\n readonly id: string\n readonly name: string\n readonly providerId: string\n readonly capabilities: readonly string[]\n}\n\nexport class DeviceRegistry<T extends IRegisteredDevice = IRegisteredDevice> {\n private readonly devices = new Map<string, T>()\n private readonly logger: IScopedLogger\n\n constructor(\n private readonly eventBus: IEventBus,\n loggingService: LoggerFactory,\n ) {\n this.logger = loggingService.createLogger('device-registry')\n }\n\n registerDevice(device: T): void {\n this.devices.set(device.id, device)\n this.logger.info(`Device registered: ${device.id} (${device.name})`)\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'core', id: 'device-registry' },\n category: 'device.registered',\n data: { deviceId: device.id, name: device.name, providerId: device.providerId },\n })\n }\n\n unregisterDevice(id: string): void {\n const device = this.devices.get(id)\n if (!device) {\n return\n }\n\n this.devices.delete(id)\n this.logger.info(`Device unregistered: ${id}`)\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'core', id: 'device-registry' },\n category: 'device.unregistered',\n data: { deviceId: id },\n })\n }\n\n getDevice(id: string): T | null {\n return this.devices.get(id) ?? null\n }\n\n listDevices(): T[] {\n return Array.from(this.devices.values())\n }\n\n getDevicesByProvider(providerId: string): T[] {\n return Array.from(this.devices.values()).filter(\n (device) => device.providerId === providerId,\n )\n }\n\n getDevicesWithCapability(cap: string): T[] {\n return Array.from(this.devices.values()).filter((device) =>\n device.capabilities.includes(cap),\n )\n }\n\n registerProviderDevices(providerId: string, devices: readonly T[]): void {\n for (const device of devices) {\n this.registerDevice(device)\n }\n this.logger.info(`Bulk registered ${devices.length} devices for provider ${providerId}`)\n }\n\n unregisterProviderDevices(providerId: string): void {\n const providerDevices = this.getDevicesByProvider(providerId)\n for (const device of providerDevices) {\n this.unregisterDevice(device.id)\n }\n this.logger.info(`Bulk unregistered ${providerDevices.length} devices for provider ${providerId}`)\n }\n}\n","export interface IDeviceCapability {\n kind: string\n}\n\nexport interface CapabilityBinding {\n source: 'native' | 'addon' | 'disabled'\n addonId?: string\n config?: Record<string, unknown>\n}\n\nexport interface IResolvableDevice {\n readonly id: string\n readonly capabilities: string[]\n getCapability<T extends IDeviceCapability>(cap: string): T | null\n}\n\nexport interface IAddonRegistryAccess {\n getAddon(addonId: string): unknown | null\n}\n\nexport class CapabilityResolver {\n private readonly bindings = new Map<\n string,\n Partial<Record<string, CapabilityBinding>>\n >()\n\n constructor(\n private readonly addonRegistry: IAddonRegistryAccess,\n ) {}\n\n resolve<T extends IDeviceCapability>(\n device: IResolvableDevice,\n cap: string,\n ): T | null {\n const deviceBindings = this.bindings.get(device.id)\n const binding = deviceBindings?.[cap]\n\n if (binding) {\n if (binding.source === 'disabled') {\n return null\n }\n\n if (binding.source === 'addon' && binding.addonId) {\n const addon = this.addonRegistry.getAddon(binding.addonId)\n if (addon && typeof (addon as any).getCapabilityForDevice === 'function') {\n return (\n (addon as any).getCapabilityForDevice(device, cap, binding.config) ?? null\n )\n }\n return null\n }\n }\n\n // native or no explicit binding -- delegate to device\n return device.getCapability<T>(cap)\n }\n\n setBinding(\n deviceId: string,\n cap: string,\n binding: CapabilityBinding,\n ): void {\n const existing = this.bindings.get(deviceId) ?? {}\n this.bindings.set(deviceId, { ...existing, [cap]: binding })\n }\n\n removeBinding(deviceId: string, cap: string): void {\n const existing = this.bindings.get(deviceId)\n if (!existing) {\n return\n }\n const updated = { ...existing }\n delete updated[cap]\n this.bindings.set(deviceId, updated)\n }\n\n getBindings(\n deviceId: string,\n ): Partial<Record<string, CapabilityBinding>> {\n return this.bindings.get(deviceId) ?? {}\n }\n\n getEffectiveCapabilities(device: IResolvableDevice): string[] {\n const deviceBindings = this.bindings.get(device.id) ?? {}\n\n const result: string[] = []\n\n // Include native capabilities that are not disabled\n for (const cap of device.capabilities) {\n const binding = deviceBindings[cap]\n if (!binding || binding.source !== 'disabled') {\n result.push(cap)\n }\n }\n\n // Include addon-bound capabilities not already in the native list\n for (const [cap, binding] of Object.entries(deviceBindings)) {\n if (\n binding && binding.source === 'addon' &&\n !device.capabilities.includes(cap)\n ) {\n result.push(cap)\n }\n }\n\n return result\n }\n}\n","import { X509Certificate } from 'node:crypto'\nimport { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport * as os from 'node:os'\n\nconst execFileAsync = promisify(execFile)\n\nexport interface TlsCertPair {\n readonly cert: Buffer\n readonly key: Buffer\n}\n\nexport interface EnsureTlsResult {\n readonly certPath: string\n readonly keyPath: string\n readonly generated: boolean\n}\n\nexport interface CertOptions {\n /** Common Name for the cert (default: 'camstack.local') */\n readonly commonName?: string\n /** Validity in days (default: 825 — max for browsers) */\n readonly validDays?: number\n /** Additional SANs (DNS names or IPs) */\n readonly extraSans?: readonly string[]\n}\n\n/**\n * Ensure a self-signed TLS certificate exists in the given directory.\n * Generates one if missing. Returns paths to cert and key files.\n */\nexport async function ensureTlsCert(\n dataDir: string,\n options?: CertOptions,\n): Promise<EnsureTlsResult> {\n const tlsDir = join(dataDir, 'tls')\n const certPath = join(tlsDir, 'camstack.crt')\n const keyPath = join(tlsDir, 'camstack.key')\n\n // Already exists — reuse\n if (existsSync(certPath) && existsSync(keyPath)) {\n try {\n const certPem = readFileSync(certPath)\n const x509 = new X509Certificate(certPem)\n const validTo = new Date(x509.validTo)\n if (validTo > new Date()) {\n return { certPath, keyPath, generated: false }\n }\n // Expired — regenerate below\n } catch {\n // Corrupted — regenerate below\n }\n }\n\n mkdirSync(tlsDir, { recursive: true })\n\n const cn = options?.commonName ?? 'camstack.local'\n const validDays = options?.validDays ?? 825\n\n // Collect SANs: localhost, 127.0.0.1, all local IPs, hostname\n const sanDns = new Set<string>(['localhost', cn, os.hostname()])\n const sanIps = new Set<string>(['127.0.0.1', '::1'])\n\n // Add all local network IPs\n const interfaces = os.networkInterfaces()\n for (const addrs of Object.values(interfaces)) {\n if (!addrs) continue\n for (const addr of addrs) {\n if (!addr.internal) {\n sanIps.add(addr.address)\n }\n }\n }\n\n // Add extra SANs\n for (const san of options?.extraSans ?? []) {\n if (san.match(/^\\d+\\.\\d+\\.\\d+\\.\\d+$/) || san.includes(':')) {\n sanIps.add(san)\n } else {\n sanDns.add(san)\n }\n }\n\n // Build SAN string for openssl\n const sanParts: string[] = []\n for (const dns of sanDns) {\n sanParts.push(`DNS:${dns}`)\n }\n for (const ip of sanIps) {\n sanParts.push(`IP:${ip}`)\n }\n const sanString = sanParts.join(',')\n\n // Generate self-signed certificate using openssl CLI\n await execFileAsync('openssl', [\n 'req', '-x509',\n '-newkey', 'rsa:2048',\n '-keyout', keyPath,\n '-out', certPath,\n '-days', String(validDays),\n '-nodes',\n '-subj', `/CN=${cn}`,\n '-addext', `subjectAltName=${sanString}`,\n ])\n\n // Set restrictive permissions on the key file\n const { chmod } = await import('node:fs/promises')\n await chmod(keyPath, 0o600)\n\n return { certPath, keyPath, generated: true }\n}\n\n/**\n * Load TLS cert+key from files. Returns Buffers suitable for Node.js TLS options.\n */\nexport function loadTlsCert(certPath: string, keyPath: string): TlsCertPair {\n return {\n cert: readFileSync(certPath),\n key: readFileSync(keyPath),\n }\n}\n","/**\n * Factory for creating tRPC clients for addons.\n *\n * Two modes:\n * - Direct caller (in-process): zero overhead, uses createCallerFactory\n * - WSS client (worker/agent): real WebSocket connection to the server\n */\n\nexport interface DirectCallerOptions {\n /** The tRPC router instance (from buildAppRouter) */\n readonly router: unknown\n /** Context for the caller (user identity, etc.) */\n readonly context: { readonly user: { readonly id: string; readonly username: string; readonly role: string } }\n}\n\nexport interface WssClientOptions {\n /** WebSocket URL (e.g., wss://localhost:4443/trpc) */\n readonly url: string\n /** Auth token for the connection */\n readonly token: string\n}\n\nexport class AddonApiFactory {\n /**\n * Build a WSS URL from host and port.\n */\n buildWssUrl(host: string, port: number): string {\n return `wss://${host}:${port}/trpc`\n }\n\n /**\n * Create a direct caller -- calls tRPC procedures directly in-process.\n * Zero network overhead. Used for in-process addons and dev mode.\n *\n * @param options.router - The tRPC router from buildAppRouter()\n * @param options.context - The auth context (service account)\n * @returns A tRPC caller that can be used as context.api\n */\n async createDirectCaller(options: DirectCallerOptions): Promise<unknown> {\n const { initTRPC } = await import('@trpc/server')\n const t = initTRPC.create()\n const callerFactory = t.createCallerFactory(options.router as never)\n return callerFactory(options.context as never)\n }\n\n /**\n * Create a WSS tRPC client -- connects to the server via WebSocket.\n * Used for forked workers and remote agents.\n *\n * @param options.url - WSS URL (e.g., wss://localhost:4443/trpc)\n * @param options.token - Bearer token for authentication\n * @returns A tRPC client that can be used as context.api\n */\n async createWssClient(options: WssClientOptions): Promise<{ readonly client: unknown; readonly close: () => void }> {\n const { createTRPCClient, createWSClient, wsLink } = await import('@trpc/client')\n\n const wsClient = createWSClient({\n url: options.url,\n connectionParams: () => ({ token: options.token }),\n })\n\n const client = createTRPCClient({\n links: [wsLink({ client: wsClient })],\n })\n\n return {\n client,\n close: () => wsClient.close(),\n }\n }\n}\n","import * as os from 'node:os'\nimport { execFileSync } from 'node:child_process'\nimport type { HardwareInfo, GpuInfo, NpuInfo, PlatformScore, PlatformCapabilities } from '@camstack/types'\n\n/**\n * Get reliable \"available\" RAM in MB, cross-platform.\n * os.freemem() is unreliable on macOS (reports ~200MB on a 36GB system).\n * Uses systeminformation when available, falls back to native commands.\n */\nasync function getAvailableRAM_MB(): Promise<number> {\n try {\n const si = await import('systeminformation')\n const mem = await si.mem()\n return Math.round(mem.available / 1024 / 1024)\n } catch {\n // Fallback: platform-specific\n const platform = os.platform()\n try {\n if (platform === 'darwin') {\n // Parse vm_stat: (free + inactive + purgeable) * pageSize\n const output = execFileSync('vm_stat', { encoding: 'utf8', timeout: 3000 })\n const pageSize = parseInt(output.match(/page size of (\\d+)/)?.[1] ?? '16384')\n const free = parseInt(output.match(/Pages free:\\s+(\\d+)/)?.[1] ?? '0')\n const inactive = parseInt(output.match(/Pages inactive:\\s+(\\d+)/)?.[1] ?? '0')\n const purgeable = parseInt(output.match(/Pages purgeable:\\s+(\\d+)/)?.[1] ?? '0')\n return Math.round((free + inactive + purgeable) * pageSize / 1024 / 1024)\n } else if (platform === 'linux') {\n // Parse /proc/meminfo: MemAvailable\n const { readFileSync } = await import('node:fs')\n const meminfo = readFileSync('/proc/meminfo', 'utf8')\n const match = meminfo.match(/MemAvailable:\\s+(\\d+)\\s+kB/)\n if (match) return Math.round(parseInt(match[1]!) / 1024)\n }\n } catch { /* ignore */ }\n // Ultimate fallback: total RAM (conservative but safe)\n return Math.round(os.totalmem() / 1024 / 1024)\n }\n}\n\nexport class PlatformScorer {\n private cached: PlatformCapabilities | null = null\n\n /** Probe hardware + runtimes and score all backend combos. Cached after first call. */\n async probe(): Promise<PlatformCapabilities> {\n if (this.cached) return this.cached\n\n const start = Date.now()\n console.log('[PlatformScorer] Probing hardware...')\n const hardware = await this.probeHardware()\n console.log(`[PlatformScorer] Hardware: ${hardware.platform}/${hardware.arch}, ${hardware.cpuModel} (${hardware.cpuCores} cores), RAM ${Math.round(hardware.totalRAM_MB / 1024)}GB`)\n if (hardware.gpu) console.log(`[PlatformScorer] GPU: ${hardware.gpu.name}`)\n if (hardware.npu) console.log(`[PlatformScorer] NPU: ${hardware.npu.type}`)\n\n console.log('[PlatformScorer] Probing Node.js backends...')\n const nodeBackends = await this.probeNodeBackends()\n console.log(`[PlatformScorer] Node backends: ${nodeBackends.map(b => b.id).join(', ')}`)\n\n console.log('[PlatformScorer] Probing Python backends...')\n const pythonInfo = this.probePythonBackends()\n if (pythonInfo.pythonPath) {\n console.log(`[PlatformScorer] Python: ${pythonInfo.pythonPath} → ${pythonInfo.backends.filter(b => b.available).map(b => b.id).join(', ') || 'no backends'}`)\n } else {\n console.log('[PlatformScorer] Python: not found')\n }\n\n const scores = this.scoreBackends(hardware, nodeBackends, pythonInfo.backends)\n const bestScore = scores.find(s => s.available) ?? scores[scores.length - 1]!\n\n const elapsed = Date.now() - start\n console.log(`[PlatformScorer] Scoring complete in ${elapsed}ms — ${scores.length} combos`)\n console.log(`[PlatformScorer] Best: ${bestScore.runtime}/${bestScore.backend} (${bestScore.format}) — ${bestScore.reason} [score: ${bestScore.score}]`)\n for (const s of scores) {\n console.log(`[PlatformScorer] ${s.available ? '✓' : '✗'} ${s.runtime}/${s.backend} (${s.format}) — score ${s.score} — ${s.reason}`)\n }\n\n this.cached = {\n hardware,\n scores,\n bestScore,\n pythonPath: pythonInfo.pythonPath,\n }\n return this.cached\n }\n\n async probeHardware(): Promise<HardwareInfo> {\n const platform = os.platform() as HardwareInfo['platform']\n const arch = os.arch() as HardwareInfo['arch']\n const cpus = os.cpus()\n const cpuModel = cpus[0]?.model ?? 'unknown'\n const cpuCores = cpus.length\n const totalRAM_MB = Math.round(os.totalmem() / 1024 / 1024)\n const availableRAM_MB = await getAvailableRAM_MB()\n console.log(`[PlatformScorer] RAM: total=${totalRAM_MB}MB, available=${availableRAM_MB}MB (via systeminformation)`)\n\n let gpu: GpuInfo | null = null\n let npu: NpuInfo | null = null\n\n // macOS Apple Silicon\n if (platform === 'darwin' && arch === 'arm64') {\n gpu = { type: 'apple', name: 'Apple Silicon GPU' }\n npu = { type: 'apple-ane' }\n }\n\n // Linux NVIDIA\n if (platform === 'linux') {\n try {\n const output = execFileSync('nvidia-smi', ['--query-gpu=name,memory.total', '--format=csv,noheader'], {\n encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'],\n }).trim()\n if (output) {\n const [name, mem] = output.split(',').map(s => s.trim())\n gpu = {\n type: 'nvidia',\n name: name ?? 'NVIDIA GPU',\n memoryMB: parseInt(mem ?? '0'),\n }\n }\n } catch { /* no NVIDIA GPU */ }\n }\n\n return { platform, arch, cpuModel, cpuCores, totalRAM_MB, availableRAM_MB, gpu, npu }\n }\n\n private async probeNodeBackends(): Promise<Array<{ id: string; available: boolean }>> {\n const backends: Array<{ id: string; available: boolean }> = [\n { id: 'cpu', available: true },\n ]\n\n try {\n const ort = await import('onnxruntime-node') as any\n const providers: string[] = ort.InferenceSession?.getAvailableProviders?.() ?? []\n for (const p of providers) {\n const n = p.toLowerCase().replace('executionprovider', '')\n if (n === 'coreml') backends.push({ id: 'coreml', available: true })\n else if (n === 'cuda') backends.push({ id: 'cuda', available: true })\n else if (n === 'tensorrt') backends.push({ id: 'tensorrt', available: true })\n }\n } catch { /* onnxruntime not available */ }\n\n // macOS always has CoreML potential\n if (os.platform() === 'darwin' && !backends.some(b => b.id === 'coreml')) {\n backends.push({ id: 'coreml', available: true })\n }\n\n return backends\n }\n\n private probePythonBackends(): { pythonPath: string | null; backends: Array<{ id: string; format: string; available: boolean }> } {\n let pythonPath: string | null = null\n for (const cmd of ['python3', 'python']) {\n try {\n execFileSync(cmd, ['--version'], { timeout: 5000, stdio: 'pipe' })\n pythonPath = cmd\n break\n } catch { /* not found */ }\n }\n\n if (!pythonPath) return { pythonPath: null, backends: [] }\n\n const checks: Array<[string, string, string]> = [\n // [pythonModule, backendId, modelFormat]\n ['coremltools', 'coreml', 'coreml'],\n ['openvino.runtime', 'openvino', 'openvino'],\n ['torch', 'pytorch', 'onnx'],\n ['onnxruntime', 'onnx-py', 'onnx'],\n ]\n\n const backends: Array<{ id: string; format: string; available: boolean }> = []\n for (const [mod, id, format] of checks) {\n let available = false\n const probeStart = Date.now()\n try {\n execFileSync(pythonPath, ['-c', `import ${mod}`], { timeout: 30000, stdio: 'ignore' })\n available = true\n } catch { /* module not installed */ }\n const probeMs = Date.now() - probeStart\n console.log(`[PlatformScorer] Python ${mod}: ${available ? '✓' : '✗'} (${probeMs}ms)`)\n\n // Always show CoreML on macOS even if not installed\n if (id === 'coreml' && os.platform() === 'darwin') {\n backends.push({ id, format, available })\n } else if (available) {\n backends.push({ id, format, available })\n }\n }\n\n return { pythonPath, backends }\n }\n\n private scoreBackends(\n hardware: HardwareInfo,\n nodeBackends: Array<{ id: string; available: boolean }>,\n pythonBackends: Array<{ id: string; format: string; available: boolean }>,\n ): PlatformScore[] {\n const scores: PlatformScore[] = []\n\n // macOS Apple Silicon\n if (hardware.platform === 'darwin' && hardware.arch === 'arm64') {\n const pyCoreMl = pythonBackends.find(b => b.id === 'coreml')\n if (pyCoreMl) {\n scores.push({ runtime: 'python', backend: 'coreml', format: 'coreml', score: 95, reason: 'Apple Neural Engine (Python CoreML)', available: pyCoreMl.available })\n }\n const nodeCoreMl = nodeBackends.find(b => b.id === 'coreml')\n if (nodeCoreMl) {\n scores.push({ runtime: 'node', backend: 'coreml', format: 'onnx', score: 90, reason: 'CoreML via ONNX Runtime', available: nodeCoreMl.available })\n }\n }\n\n // NVIDIA\n if (hardware.gpu?.type === 'nvidia') {\n const tensorrt = nodeBackends.find(b => b.id === 'tensorrt')\n if (tensorrt) scores.push({ runtime: 'node', backend: 'tensorrt', format: 'onnx', score: 95, reason: 'NVIDIA TensorRT', available: true })\n const cuda = nodeBackends.find(b => b.id === 'cuda')\n if (cuda) scores.push({ runtime: 'node', backend: 'cuda', format: 'onnx', score: 85, reason: 'NVIDIA CUDA', available: true })\n }\n\n // Intel OpenVINO\n const openvino = pythonBackends.find(b => b.id === 'openvino')\n if (openvino) {\n const score = hardware.npu?.type === 'intel-npu' ? 90 : 80\n scores.push({ runtime: 'python', backend: 'openvino', format: 'openvino', score, reason: 'Intel OpenVINO', available: openvino.available })\n }\n\n // CPU fallbacks\n scores.push({ runtime: 'node', backend: 'cpu', format: 'onnx', score: 50, reason: 'CPU (ONNX Runtime Node)', available: true })\n const pyOnnx = pythonBackends.find(b => b.id === 'onnx-py')\n if (pyOnnx) {\n scores.push({ runtime: 'python', backend: 'cpu', format: 'onnx', score: 45, reason: 'CPU (Python ONNX)', available: pyOnnx.available })\n }\n\n return scores.sort((a, b) => b.score - a.score)\n }\n}\n","import type { PlatformScore, HardwareInfo, ModelRequirement, ResolvedInferenceConfig } from '@camstack/types'\n\nexport class InferenceConfigResolver {\n constructor(\n private readonly scores: readonly PlatformScore[],\n private readonly hardware: HardwareInfo,\n ) {}\n\n /**\n * Compute accuracy/backend weights based on available system RAM.\n * availableRAM_MB is now sourced from systeminformation (reliable cross-platform),\n * not os.freemem() which is broken on macOS.\n *\n * - > 16 GB available: prefer larger, more accurate models (accuracy 0.6, backend 0.4)\n * - > 8 GB available: balanced (accuracy 0.5, backend 0.5)\n * - <= 8 GB available: prefer speed (accuracy 0.4, backend 0.6)\n */\n private getWeights(): { accuracyWeight: number; backendWeight: number } {\n const ramMB = this.hardware.availableRAM_MB\n if (ramMB > 16_384) return { accuracyWeight: 0.6, backendWeight: 0.4 }\n if (ramMB > 8_192) return { accuracyWeight: 0.5, backendWeight: 0.5 }\n return { accuracyWeight: 0.4, backendWeight: 0.6 }\n }\n\n /**\n * Given an addon's model requirements, pick the best model + runtime + backend.\n *\n * Algorithm:\n * 1. Filter models by available RAM (minRAM_MB < 25% of available RAM)\n * 2. For each remaining model, find the best platform score whose format\n * is available in the model's formats\n * 3. Pick the model with the highest combined score using RAM-adaptive weights:\n * - High RAM (>16 GB): accuracy × 0.6 + backend × 0.4 (prefer accuracy)\n * - Mid RAM (>8 GB): accuracy × 0.5 + backend × 0.5 (balanced)\n * - Low RAM (<=8 GB): accuracy × 0.4 + backend × 0.6 (prefer speed)\n */\n resolve(requirements: readonly ModelRequirement[]): ResolvedInferenceConfig {\n if (requirements.length === 0) {\n return { modelId: '', runtime: 'node', backend: 'cpu', format: 'onnx', reason: 'No models declared' }\n }\n\n // Budget: 25% of available RAM (now reliable via systeminformation)\n const ramBudget = this.hardware.availableRAM_MB * 0.25\n const { accuracyWeight, backendWeight } = this.getWeights()\n\n console.log(`[InferenceConfigResolver] availableRAM: ${this.hardware.availableRAM_MB}MB, budget: ${Math.round(ramBudget)}MB, weights: accuracy=${accuracyWeight}, backend=${backendWeight}`)\n\n // Filter models that fit in memory\n const fits = requirements.filter(m => m.minRAM_MB < ramBudget)\n const candidates = fits.length > 0 ? fits : [requirements[0]!] // fallback to first/smallest\n\n console.log(`[InferenceConfigResolver] ${candidates.length}/${requirements.length} models fit RAM budget`)\n\n // For each model, find best compatible platform score\n let bestCombo: { model: ModelRequirement; score: PlatformScore; combined: number } | null = null\n\n for (const model of candidates) {\n for (const score of this.scores) {\n if (!score.available) continue\n if (!model.formats.includes(score.format)) continue\n\n const combined = model.accuracyScore * accuracyWeight + score.score * backendWeight\n\n if (!bestCombo || combined > bestCombo.combined) {\n console.log(`[InferenceConfigResolver] New best: ${model.modelId} (accuracy=${model.accuracyScore}) + ${score.backend}/${score.format} (score=${score.score}) → combined=${Math.round(combined)}`)\n bestCombo = { model, score, combined }\n }\n }\n }\n\n if (!bestCombo) {\n return {\n modelId: candidates[0]!.modelId,\n runtime: 'node',\n backend: 'cpu',\n format: 'onnx',\n reason: 'No compatible backend — CPU fallback',\n }\n }\n\n return {\n modelId: bestCombo.model.modelId,\n runtime: bestCombo.score.runtime,\n backend: bestCombo.score.backend,\n format: bestCombo.score.format,\n reason: `${bestCombo.model.name} on ${bestCombo.score.reason} (score: ${Math.round(bestCombo.combined)})`,\n }\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { IScopedLogger, IEventBus, LoggerFactory, ProviderListItem } from '@camstack/types'\nimport { LifecycleStateMachine, type ElementStatus } from '../lifecycle/lifecycle-state-machine.js'\n\n/** Minimal device registry interface for provider management */\nexport type ProviderDeviceRegistry = {\n registerProviderDevices(providerId: string, devices: readonly IRegistrableDevice[]): void\n unregisterProviderDevices(providerId: string): void\n}\n\nexport interface IRegistrableDevice {\n readonly id: string\n readonly name: string\n readonly providerId: string\n readonly capabilities: readonly string[]\n}\n\nexport interface ProviderStatus {\n connected: boolean\n error?: string\n deviceCount: number\n}\n\nexport interface LiveEvent {\n type: string\n camera: string\n timestamp: number\n data: Record<string, unknown>\n}\n\nexport interface IManagedProvider {\n readonly id: string\n readonly type: string\n readonly name: string\n start(): Promise<void>\n stop(): Promise<void>\n getStatus(): ProviderStatus\n getDevices(): readonly IRegistrableDevice[]\n subscribeLiveEvents(callback: (event: LiveEvent) => void): () => void\n}\n\ninterface ProviderEntry<P extends IManagedProvider> {\n readonly provider: P\n readonly lifecycle: LifecycleStateMachine\n started: boolean\n unsubscribe?: () => void\n}\n\nexport type { ProviderListItem }\n\nexport class ProviderManager<P extends IManagedProvider = IManagedProvider> {\n private readonly providers = new Map<string, ProviderEntry<P>>()\n private readonly logger: IScopedLogger\n\n constructor(\n private readonly deviceRegistry: ProviderDeviceRegistry,\n private readonly eventBus: IEventBus,\n private readonly loggingService: LoggerFactory,\n ) {\n this.logger = loggingService.createLogger('provider-manager')\n }\n\n registerProvider(provider: P): void {\n const providerLogger = this.loggingService.createLogger(`provider:${provider.id}`)\n const lifecycle = new LifecycleStateMachine(\n provider.id,\n 'provider',\n this.eventBus,\n providerLogger,\n )\n this.providers.set(provider.id, { provider, lifecycle, started: false })\n this.logger.info(`Provider registered: ${provider.id} (${provider.name})`)\n }\n\n async startProvider(id: string): Promise<void> {\n const entry = this.providers.get(id)\n if (!entry) {\n throw new Error(`Provider \"${id}\" is not registered`)\n }\n\n if (entry.lifecycle.state === 'disabled') {\n throw new Error(`Provider \"${id}\" is disabled`)\n }\n\n entry.lifecycle.transition('starting')\n\n try {\n await entry.provider.start()\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err)\n entry.lifecycle.transition('error', message)\n throw err\n }\n\n entry.lifecycle.transition('running')\n\n const devices = entry.provider.getDevices()\n this.deviceRegistry.registerProviderDevices(id, devices)\n\n const unsubscribe = entry.provider.subscribeLiveEvents((event: LiveEvent) => {\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'provider', id },\n category: `provider.${event.type}`,\n data: event.data,\n })\n })\n\n entry.started = true\n entry.unsubscribe = unsubscribe\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'core', id: 'provider-manager' },\n category: 'provider.started',\n data: { providerId: id },\n })\n\n this.logger.info(`Provider started: ${id}`)\n }\n\n async stopProvider(id: string): Promise<void> {\n const entry = this.providers.get(id)\n if (!entry) {\n throw new Error(`Provider \"${id}\" is not registered`)\n }\n\n entry.lifecycle.transition('stopping')\n\n if (entry.unsubscribe) {\n entry.unsubscribe()\n entry.unsubscribe = undefined\n }\n\n this.deviceRegistry.unregisterProviderDevices(id)\n\n await entry.provider.stop()\n entry.started = false\n\n entry.lifecycle.transition('stopped')\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'core', id: 'provider-manager' },\n category: 'provider.stopped',\n data: { providerId: id },\n })\n\n this.logger.info(`Provider stopped: ${id}`)\n }\n\n async disableProvider(id: string): Promise<void> {\n const entry = this.providers.get(id)\n if (!entry) {\n throw new Error(`Provider \"${id}\" is not registered`)\n }\n\n if (entry.lifecycle.state === 'running' || entry.started) {\n await this.stopProvider(id)\n }\n\n entry.lifecycle.transition('disabled')\n this.logger.info(`Provider disabled: ${id}`)\n }\n\n async enableProvider(id: string): Promise<void> {\n const entry = this.providers.get(id)\n if (!entry) {\n throw new Error(`Provider \"${id}\" is not registered`)\n }\n\n if (entry.lifecycle.state !== 'disabled') {\n throw new Error(`Provider \"${id}\" is not disabled`)\n }\n\n entry.lifecycle.transition('stopped')\n this.logger.info(`Provider enabled: ${id}`)\n }\n\n async restartProvider(id: string): Promise<void> {\n await this.stopProvider(id)\n await this.startProvider(id)\n }\n\n getProvider(id: string): P | null {\n const entry = this.providers.get(id)\n return entry?.provider ?? null\n }\n\n getProviderStatus(id: string): ElementStatus | null {\n const entry = this.providers.get(id)\n return entry?.lifecycle.getStatus() ?? null\n }\n\n listProviders(): readonly ProviderListItem[] {\n return Array.from(this.providers.values()).map((entry) => ({\n id: entry.provider.id,\n type: entry.provider.type,\n name: entry.provider.name,\n status: entry.provider.getStatus(),\n started: entry.started,\n lifecycle: entry.lifecycle.getStatus(),\n }))\n }\n\n async shutdownAll(): Promise<void> {\n const startedIds = Array.from(this.providers.entries())\n .filter(([, entry]) => entry.started)\n .map(([id]) => id)\n\n for (const id of startedIds) {\n await this.stopProvider(id)\n }\n\n this.logger.info(`All providers shut down (${startedIds.length} stopped)`)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAAY,WAAW,WAAW,mBAAmB,kBAAkB;AAChF,SAAS,YAAY;AACrB,SAAS,gBAAgB;AACzB,SAAS,gBAAgB;AACzB,SAAS,oBAAoB;AAQtB,SAAS,kBAAgC;AAC9C,SAAO;AAAA,IACL,UAAU,QAAQ;AAAA,IAClB,MAAM,QAAQ;AAAA,EAChB;AACF;AAEO,SAAS,gBAAgB,SAAiB,MAAcA,WAA2B;AACxF,QAAM,OAAOA,aAAY,QAAQ,cAAc,UAAU,SAAS;AAClE,SAAO,KAAK,SAAS,QAAQ,GAAG,IAAI,GAAG,GAAG,EAAE;AAC9C;AAGO,SAAS,WAAW,MAA6B;AACtD,MAAI;AACF,iBAAa,MAAM,CAAC,WAAW,GAAG,EAAE,OAAO,QAAQ,SAAS,IAAK,CAAC;AAClE,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAkBA,eAAsB,eAAe,MAAwC;AAC3E,QAAM,EAAE,MAAM,KAAK,WAAW,YAAY,QAAQ,WAAW,eAAe,iBAAiB,IAAI;AACjG,QAAM,aAAa,KAAK,WAAW,UAAU;AAE7C,MAAI,WAAW,UAAU,GAAG;AAC1B,WAAO,MAAM,GAAG,IAAI,6BAA6B,UAAU,EAAE;AAC7D,WAAO;AAAA,EACT;AAEA,YAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAExC,SAAO,KAAK,eAAe,IAAI,SAAS,GAAG,EAAE;AAC7C,QAAM,WAAW,MAAM,MAAM,KAAK,EAAE,UAAU,SAAS,CAAC;AACxD,MAAI,CAAC,SAAS,MAAM,CAAC,SAAS,MAAM;AAClC,UAAM,IAAI,MAAM,sBAAsB,IAAI,KAAK,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,EACzF;AAEA,MAAI,WAAW;AACb,UAAM,MAAM,iBAAiB;AAC7B,UAAM,aAAa,KAAK,WAAW,GAAG,IAAI,aAAa,GAAG,EAAE;AAC5D,UAAM,aAAa,SAAS,QAAQ,SAAS,IAAW;AACxD,UAAM,SAAS,YAAY,kBAAkB,UAAU,CAAC;AAGxD,UAAM,gBAAgB,KAAK,WAAW,GAAG,IAAI,UAAU;AACvD,cAAU,eAAe,EAAE,WAAW,KAAK,CAAC;AAE5C,QAAI,QAAQ,OAAO;AACjB,UAAI;AACF,qBAAa,SAAS,CAAC,MAAM,MAAM,YAAY,MAAM,aAAa,GAAG,EAAE,OAAO,OAAO,CAAC;AAAA,MACxF,QAAQ;AACN,qBAAa,OAAO,CAAC,OAAO,YAAY,MAAM,aAAa,GAAG,EAAE,OAAO,OAAO,CAAC;AAAA,MACjF;AAAA,IACF,WAAW,QAAQ,UAAU;AAC3B,mBAAa,OAAO,CAAC,QAAQ,YAAY,MAAM,aAAa,GAAG,EAAE,OAAO,OAAO,CAAC;AAAA,IAClF,OAAO;AACL,mBAAa,OAAO,CAAC,QAAQ,YAAY,MAAM,aAAa,GAAG,EAAE,OAAO,OAAO,CAAC;AAAA,IAClF;AAGA,QAAI,kBAAkB;AACpB,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,IAAS;AAC/C,YAAM,aAAa,KAAK,eAAe,gBAAgB;AACvD,UAAI,CAAC,WAAW,UAAU,GAAG;AAC3B,cAAM,IAAI,MAAM,kCAAkC,gBAAgB,EAAE;AAAA,MACtE;AACA,mBAAa,YAAY,UAAU;AAAA,IACrC;AAGA,eAAW,UAAU;AACrB,UAAM,EAAE,QAAAC,QAAO,IAAI,MAAM,OAAO,IAAS;AACzC,IAAAA,QAAO,eAAe,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EACxD,OAAO;AAEL,UAAM,aAAa,SAAS,QAAQ,SAAS,IAAW;AACxD,UAAM,SAAS,YAAY,kBAAkB,UAAU,CAAC;AAAA,EAC1D;AAEA,YAAU,YAAY,GAAK;AAC3B,SAAO,KAAK,GAAG,IAAI,kBAAkB,UAAU,EAAE;AACjD,SAAO;AACT;AAQA,eAAsB,aAAa,MAQf;AAClB,QAAM,MAAM,QAAQ,aAAa,UAAU,SAAS;AACpD,QAAM,aAAa,GAAG,KAAK,IAAI,GAAG,GAAG;AACrC,QAAM,aAAa,KAAK,KAAK,WAAW,UAAU;AAGlD,MAAI,WAAW,UAAU,GAAG;AAC1B,SAAK,OAAO,MAAM,GAAG,KAAK,IAAI,aAAa,UAAU,EAAE;AACvD,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,WAAW,KAAK,IAAI;AACnC,MAAI,QAAQ;AACV,SAAK,OAAO,KAAK,GAAG,KAAK,IAAI,uBAAuB;AACpD,WAAO;AAAA,EACT;AAGA,SAAO,eAAe;AAAA,IACpB,MAAM,KAAK;AAAA,IACX,KAAK,KAAK;AAAA,IACV,WAAW,KAAK;AAAA,IAChB;AAAA,IACA,QAAQ,KAAK;AAAA,IACb,WAAW,KAAK;AAAA,IAChB,eAAe,KAAK;AAAA,IACpB,kBAAkB,KAAK;AAAA,EACzB,CAAC;AACH;;;ACnJA,SAAS,QAAAC,aAAY;AAIrB,IAAM,iBAAiB;AAEhB,SAAS,qBAAqBC,WAAkBC,OAAsB;AAC3E,UAAQD,WAAU;AAAA,IAChB,KAAK,SAAS;AACZ,YAAM,UAAkC,EAAE,KAAK,SAAS,OAAO,QAAQ;AACvE,YAAM,IAAI,QAAQC,KAAI;AACtB,UAAI,CAAC,EAAG,OAAM,IAAI,MAAM,mCAAmCA,KAAI,EAAE;AAEjE,aAAO,4DAA4D,CAAC;AAAA,IACtE;AAAA,IACA,KAAK,UAAU;AACb,YAAM,UAAkC,EAAE,OAAO,SAAS,KAAK,QAAQ;AACvE,YAAM,IAAI,QAAQA,KAAI;AACtB,UAAI,CAAC,EAAG,OAAM,IAAI,MAAM,mCAAmCA,KAAI,EAAE;AAEjE,aAAO,oCAAoC,eAAe,QAAQ,KAAK,EAAE,CAAC;AAAA,IAC5E;AAAA,IACA;AACE,YAAM,IAAI,MAAM,yBAAyBD,SAAQ,EAAE;AAAA,EACvD;AACF;AAEO,SAAS,qBAAqBA,WAInC;AACA,UAAQA,WAAU;AAAA,IAChB,KAAK;AACH,aAAO;AAAA,QACL,WAAW;AAAA,QACX,eAAe;AAAA,QACf,kBAAkB,UAAU,cAAc;AAAA,MAC5C;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,WAAW;AAAA,QACX,eAAe;AAAA,QACf,kBAAkB;AAAA,MACpB;AAAA,IACF;AACE,YAAM,IAAI,MAAM,yBAAyBA,SAAQ,EAAE;AAAA,EACvD;AACF;AAMA,eAAsB,aAAa,SAAiB,QAAwC;AAC1F,QAAM,UAAUE,MAAK,SAAS,MAAM;AACpC,QAAMF,YAAW,QAAQ;AACzB,QAAMC,QAAO,QAAQ;AAErB,QAAM,cAAc,qBAAqBD,SAAQ;AAEjD,SAAO,aAAa;AAAA,IAClB,MAAM;AAAA,IACN,WAAW;AAAA,IACX,aAAa,qBAAqBA,WAAUC,KAAI;AAAA,IAChD;AAAA,IACA,GAAG;AAAA,EACL,CAAC;AACH;;;ACjEA,SAAS,QAAAE,aAAY;AACrB,SAAS,cAAAC,aAAY,aAAAC,YAAW,aAAAC,kBAAiB;AACjD,SAAS,gBAAAC,qBAAoB;AAC7B,SAAS,YAAAC,iBAAgB;AACzB,SAAS,YAAAC,iBAAgB;AACzB,SAAS,qBAAAC,0BAAyB;AAI3B,IAAM,iBAAiB;AAC9B,IAAM,UAAU,wEAAwE,cAAc;AAE/F,SAAS,qBAAqBC,WAAkBC,OAAsB;AAC3E,UAAQD,WAAU;AAAA,IAChB,KAAK,SAAS;AACZ,YAAM,UAAkC,EAAE,KAAK,UAAU,OAAO,UAAU;AAC1E,YAAM,IAAI,QAAQC,KAAI;AACtB,UAAI,CAAC,EAAG,OAAM,IAAI,MAAM,8CAA8CA,KAAI,EAAE;AAC5E,aAAO,GAAG,OAAO,oBAAoB,cAAc,UAAU,CAAC;AAAA,IAChE;AAAA,IACA,KAAK,UAAU;AAEb,aAAO,GAAG,OAAO,oBAAoB,cAAc;AAAA,IACrD;AAAA,IACA;AACE,YAAM,IAAI,MAAM,6CAA6CD,SAAQ,EAAE;AAAA,EAC3E;AACF;AAQA,eAAsB,aAAa,SAAiB,QAA+C;AACjG,QAAM,YAAYE,MAAK,SAAS,QAAQ,QAAQ;AAChD,QAAM,YAAYA,MAAK,WAAW,OAAO,SAAS;AAGlD,MAAIC,YAAW,SAAS,GAAG;AACzB,WAAO,MAAM,4BAA4B,SAAS,EAAE;AACpD,WAAO;AAAA,EACT;AAGA,aAAW,QAAQ,CAAC,WAAW,QAAQ,GAAG;AACxC,UAAM,SAAS,WAAW,IAAI;AAC9B,QAAI,QAAQ;AACV,aAAO,KAAK,gCAAgC,IAAI,EAAE;AAClD,aAAO;AAAA,IACT;AAAA,EACF;AAGA,SAAO,KAAK,+BAA+B,cAAc,gBAAgB;AAEzE,QAAM,UAAUD,MAAK,SAAS,MAAM;AACpC,EAAAE,WAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAEtC,QAAM,MAAM,qBAAqB,QAAQ,UAAU,QAAQ,IAAI;AAC/D,QAAM,aAAaF,MAAK,SAAS,qBAAqB;AAEtD,SAAO,KAAK,aAAa,GAAG,EAAE;AAE9B,QAAM,WAAW,MAAM,MAAM,KAAK,EAAE,UAAU,SAAS,CAAC;AACxD,MAAI,CAAC,SAAS,MAAM,CAAC,SAAS,MAAM;AAClC,WAAO,KAAK,8BAA8B,SAAS,MAAM,4CAAuC;AAChG,WAAO;AAAA,EACT;AAEA,QAAM,aAAaG,UAAS,QAAQ,SAAS,IAAW;AACxD,QAAMC,UAAS,YAAYC,mBAAkB,UAAU,CAAC;AAGxD,MAAI;AACF,IAAAC,cAAa,SAAS,CAAC,MAAM,MAAM,YAAY,MAAM,OAAO,GAAG,EAAE,OAAO,OAAO,CAAC;AAAA,EAClF,QAAQ;AAEN,IAAAA,cAAa,WAAW,CAAC,MAAM,WAAW,MAAM,YAAY,OAAO,GAAG,EAAE,OAAO,OAAO,CAAC;AAAA,EACzF;AAGA,QAAM,EAAE,YAAAC,YAAW,IAAI,MAAM,OAAO,IAAS;AAC7C,EAAAA,YAAW,UAAU;AAErB,MAAI,CAACN,YAAW,SAAS,GAAG;AAC1B,WAAO,KAAK,mEAAmE;AAC/E,WAAO;AAAA,EACT;AAEA,EAAAO,WAAU,WAAW,GAAK;AAC1B,SAAO,KAAK,mBAAmB,cAAc,iBAAiB,SAAS,EAAE;AACzE,SAAO;AACT;AAKA,eAAsB,sBACpB,YACA,UACA,QACe;AACf,MAAI,SAAS,WAAW,EAAG;AAE3B,SAAO,KAAK,+BAA+B,SAAS,KAAK,IAAI,CAAC,EAAE;AAChE,MAAI;AACF,IAAAF,cAAa,YAAY,CAAC,MAAM,OAAO,WAAW,WAAW,GAAG,QAAQ,GAAG;AAAA,MACzE,OAAO;AAAA,MACP,SAAS;AAAA;AAAA,IACX,CAAC;AACD,WAAO,KAAK,wCAAwC;AAAA,EACtD,SAAS,KAAK;AACZ,WAAO,MAAM,sCAAsC,eAAe,QAAQ,IAAI,UAAU,GAAG,EAAE;AAC7F,UAAM;AAAA,EACR;AACF;;;AChIO,IAAM,WAAN,MAAe;AAAA,EACZ,YAAY,oBAAI,IAAgC;AAAA,EAExD,GAAgB,OAAe,UAAwC;AACrE,QAAI,CAAC,KAAK,UAAU,IAAI,KAAK,EAAG,MAAK,UAAU,IAAI,OAAO,oBAAI,IAAI,CAAC;AACnE,UAAM,MAAM,KAAK,UAAU,IAAI,KAAK;AACpC,QAAI,IAAI,QAAyB;AACjC,WAAO,MAAM,IAAI,OAAO,QAAyB;AAAA,EACnD;AAAA,EAEA,KAAkB,OAAe,MAAe;AAC9C,UAAM,MAAM,KAAK,UAAU,IAAI,KAAK;AACpC,QAAI,CAAC,IAAK;AACV,eAAW,MAAM,KAAK;AACpB,UAAI;AAAE,WAAG,IAAI;AAAA,MAAE,QAAQ;AAAA,MAA4C;AAAA,IACrE;AAAA,EACF;AAAA,EAEA,KAAkB,OAAe,UAAwC;AACvE,UAAM,QAAQ,KAAK,GAAM,OAAO,CAAC,SAAS;AACxC,YAAM;AACN,eAAS,IAAI;AAAA,IACf,CAAC;AACD,WAAO;AAAA,EACT;AAAA,EAEA,mBAAmB,OAAsB;AACvC,QAAI,MAAO,MAAK,UAAU,OAAO,KAAK;AAAA,QACjC,MAAK,UAAU,MAAM;AAAA,EAC5B;AAAA,EAEA,cAAc,OAAuB;AACnC,WAAO,KAAK,UAAU,IAAI,KAAK,GAAG,QAAQ;AAAA,EAC5C;AACF;;;ACnCA,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,SAAS,kBAAkB;AAQ3B,eAAsB,aACpB,KACA,UACA,YACiB;AACjB,MAAO,cAAW,QAAQ,EAAG,QAAO;AAEpC,EAAG,aAAe,aAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAGxD,QAAM,UAAU,WAAW;AAE3B,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,UAAU;AAAA,MACV,SAAS,EAAE,cAAc,eAAe;AAAA,IAC1C,CAAC;AACD,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,gBAAgB,GAAG,EAAE;AAAA,IAC9D;AACA,QAAI,CAAC,SAAS,MAAM;AAClB,YAAM,IAAI,MAAM,yBAAyB,GAAG,EAAE;AAAA,IAChD;AAEA,UAAM,QAAQ,SAAS,SAAS,QAAQ,IAAI,gBAAgB,KAAK,KAAK,EAAE;AACxE,QAAI,aAAa;AAEjB,UAAM,aAAgB,qBAAkB,OAAO;AAC/C,UAAM,SAAS,SAAS,KAAK,UAAU;AAEvC,QAAI;AACF,iBAAS;AACP,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AACV,mBAAW,MAAM,KAAK;AACtB,sBAAc,MAAM;AACpB,qBAAa,YAAY,KAAK;AAAA,MAChC;AAAA,IACF,UAAE;AACA,iBAAW,IAAI;AACf,YAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,mBAAW,GAAG,UAAU,OAAO;AAC/B,mBAAW,GAAG,SAAS,MAAM;AAAA,MAC/B,CAAC;AAAA,IACH;AAEA,IAAG,cAAW,SAAS,QAAQ;AAC/B,WAAO;AAAA,EACT,SAAS,KAAK;AAEZ,QAAI;AAAE,MAAG,cAAW,OAAO;AAAA,IAAE,QAAQ;AAAA,IAAe;AACpD,UAAM;AAAA,EACR;AACF;AAKA,eAAsB,UAAU,KAA+B;AAC7D,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,UAAU;AAAA,IACV,SAAS,EAAE,cAAc,eAAe;AAAA,EAC1C,CAAC;AACD,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,aAAa,GAAG,EAAE;AAAA,EAC3D;AACA,SAAO,SAAS,KAAK;AACvB;AAMA,eAAsB,cAAc,SAA6D;AAC/F,QAAM,EAAE,KAAK,eAAe,CAAC,GAAG,SAAS,UAAU,gBAAgB,WAAW,IAAI;AAElF,QAAM,QAAQ,YAAY,IAAI,MAAM,GAAG,EAAE,IAAI,KAAK;AAClD,QAAM,WAAgB,UAAK,SAAS,KAAK;AAGzC,MAAO,cAAW,QAAQ,GAAG;AAC3B,WAAO,EAAE,UAAU,UAAU,iBAAiB,GAAG,WAAW,KAAK;AAAA,EACnE;AAEA,EAAG,aAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAEzC,QAAM,OAAO,CAAC,KAAK,GAAG,YAAY;AAClC,MAAI,YAA0B;AAE9B,aAAW,UAAU,MAAM;AACzB,QAAI;AACF,YAAM,aAAa,QAAQ,UAAU,UAAU;AAG/C,UAAI,gBAAgB;AAClB,cAAMG,QAAO,MAAM,cAAc,QAAQ;AACzC,YAAIA,UAAS,gBAAgB;AAC3B,UAAG,cAAW,QAAQ;AACtB,gBAAM,IAAI,MAAM,6BAA6B,cAAc,SAASA,KAAI,EAAE;AAAA,QAC5E;AAAA,MACF;AAEA,YAAM,OAAU,YAAS,QAAQ;AACjC,aAAO,EAAE,UAAU,UAAU,iBAAiB,KAAK,MAAM,WAAW,MAAM;AAAA,IAC5E,SAAS,GAAG;AACV,kBAAY;AACZ,UAAO,cAAW,QAAQ,EAAG,CAAG,cAAW,QAAQ;AAAA,IACrD;AAAA,EACF;AAEA,QAAM,aAAa,IAAI,MAAM,iCAAiC,GAAG,EAAE;AACrE;AAEA,eAAe,cAAc,UAAmC;AAC9D,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAMA,QAAO,WAAW,QAAQ;AAChC,UAAM,SAAY,oBAAiB,QAAQ;AAC3C,WAAO,GAAG,QAAQ,CAAC,UAAUA,MAAK,OAAO,KAAK,CAAC;AAC/C,WAAO,GAAG,OAAO,MAAM,QAAQA,MAAK,OAAO,KAAK,CAAC,CAAC;AAClD,WAAO,GAAG,SAAS,MAAM;AAAA,EAC3B,CAAC;AACH;;;ACnIA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AAYf,IAAM,uBAAN,MAAyD;AAAA,EAG9D,YACmB,WACjB,SACiB,YACjB;AAHiB;AAEA;AAEjB,UAAM,MAAM,oBAAI,IAA+B;AAC/C,eAAW,SAAS,SAAS;AAC3B,UAAI,IAAI,MAAM,IAAI,KAAK;AAAA,IACzB;AACA,SAAK,UAAU;AAAA,EACjB;AAAA,EAZiB;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBjB,MAAM,OAAO,SAAiB,QAAuC;AACnE,UAAM,QAAQ,KAAK,QAAQ,IAAI,OAAO;AACtC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,wCAAwC,OAAO,GAAG;AAAA,IACpE;AAGA,UAAM,iBAAiB,UAAU,KAAK,kBAAkB,KAAK;AAC7D,UAAM,cAAc,MAAM,QAAQ,cAAc;AAChD,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI;AAAA,QACR,gCAAgC,OAAO,YAAY,cAAc;AAAA,MACnE;AAAA,IACF;AAGA,UAAM,KAAK,iBAAiB,OAAO;AAGnC,UAAM,YAAY,KAAK,cAAc,OAAO,cAAc;AAE1D,QAAO,eAAW,SAAS,GAAG;AAE5B,UAAI,YAAY,aAAa;AAC3B,YAAI,CAAI,eAAgB,WAAK,WAAW,eAAe,CAAC,GAAG;AACzD,UAAG,WAAO,WAAW,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,QACvD,OAAO;AACL,iBAAO;AAAA,QACT;AAAA,MACF,OAAO;AACL,eAAO;AAAA,MACT;AAAA,IACF;AAEA,IAAG,cAAU,KAAK,WAAW,EAAE,WAAW,KAAK,CAAC;AAEhD,QAAI,YAAY,aAAa;AAC3B,YAAM,KAAK;AAAA,QACT,YAAY;AAAA,QACZ;AAAA,QACA,YAAY;AAAA,QACZ;AAAA,MACF;AAAA,IACF,OAAO;AACL,YAAM;AAAA,QACJ,YAAY;AAAA,QACZ;AAAA,QACA,KAAK,aACD,CAAC,YAAY,UAAU,KAAK,WAAY,SAAS,YAAY,KAAK,IAClE;AAAA,MACN;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,iBAAiB,SAA6C;AAClE,UAAM,QAAQ,KAAK,QAAQ,IAAI,OAAO;AACtC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,wCAAwC,OAAO,GAAG;AAAA,IACpE;AAEA,UAAM,SAAS,MAAM;AACrB,QAAI,CAAC,UAAU,OAAO,WAAW,EAAG,QAAO,CAAC;AAE5C,UAAM,QAAkB,CAAC;AACzB,eAAW,SAAS,QAAQ;AAC1B,YAAM,WAAgB,WAAK,KAAK,WAAW,MAAM,QAAQ;AACzD,YAAM,aAAa,MAAM,KAAK,QAAQ;AACtC,YAAM,KAAK,QAAQ;AAAA,IACrB;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,eAAuB;AACrB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,aAAa,SAAiB,QAA+B;AAC3D,UAAM,QAAQ,KAAK,QAAQ,IAAI,OAAO;AACtC,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,iBAAiB,UAAU,KAAK,kBAAkB,KAAK;AAC7D,UAAM,cAAc,MAAM,QAAQ,cAAc;AAChD,QAAI,CAAC,YAAa,QAAO;AAEzB,UAAM,YAAY,KAAK,cAAc,OAAO,cAAc;AAC1D,QAAI,CAAI,eAAW,SAAS,EAAG,QAAO;AAGtC,QAAI,YAAY,aAAa;AAC3B,aAAU,eAAgB,WAAK,WAAW,eAAe,CAAC;AAAA,IAC5D;AAEA,WAAU,aAAS,SAAS,EAAE,OAAO;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAc,IAA6B;AAC/C,WAAO,KAAK,OAAO,EAAE;AAAA,EACvB;AAAA;AAAA,EAGA,SAAS,SAAgD;AACvD,WAAO,KAAK,QAAQ,IAAI,OAAO;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB,OAAuC;AAE/D,UAAM,WAA0B,CAAC,QAAQ,UAAU,YAAY,UAAU,IAAI;AAC7E,eAAW,OAAO,UAAU;AAC1B,UAAI,MAAM,QAAQ,GAAG,EAAG,QAAO;AAAA,IACjC;AAEA,UAAM,QAAQ,OAAO,KAAK,MAAM,OAAO,EAAE,CAAC;AAC1C,QAAI,MAAO,QAAO;AAClB,UAAM,IAAI,MAAM,gCAAgC,MAAM,EAAE,kBAAkB;AAAA,EAC5E;AAAA,EAEQ,cAAc,OAA0B,QAA6B;AAC3E,UAAM,cAAc,MAAM,QAAQ,MAAM;AACxC,QAAI,CAAC,aAAa;AAChB,YAAM,IAAI,MAAM,SAAS,MAAM,EAAE,WAAW,MAAM,SAAS;AAAA,IAC7D;AACA,UAAM,WAAW,YAAY,IAAI,MAAM,GAAG;AAC1C,UAAM,WAAW,SAAS,SAAS,SAAS,CAAC,KAAK,GAAG,MAAM,EAAE,IAAI,MAAM;AACvE,WAAY,WAAK,KAAK,WAAW,QAAQ;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,kBACZ,KACA,SACA,YACA,SACe;AACf,UAAM,QAAQ,IAAI,MAAM,sDAAsD;AAC9E,QAAI,CAAC,MAAO,OAAM,IAAI,MAAM,iCAAiC,GAAG,EAAE;AAElE,UAAM,CAAC,EAAE,MAAM,OAAO,IAAI;AAE1B,QAAI;AAEJ,QAAI,cAAc,WAAW,SAAS,GAAG;AACvC,wBAAkB,WAAW,IAAI,QAAM;AAAA,QACrC,cAAc;AAAA,QACd,SAAS,0BAA0B,IAAI,iBAAiB,OAAO,IAAI,CAAC;AAAA,MACtE,EAAE;AAAA,IACJ,OAAO;AACL,YAAM,UAAU,MAAM,KAAK,YAAY,MAAO,OAAQ;AACtD,UAAI,QAAQ,WAAW,GAAG;AACxB,cAAM,IAAI,MAAM,4CAA4C,OAAO,EAAE;AAAA,MACvE;AACA,wBAAkB,QAAQ,IAAI,QAAM;AAAA,QAClC,cAAc,EAAE,KAAK,UAAU,QAAS,SAAS,CAAC;AAAA,QAClD,SAAS,0BAA0B,IAAI,iBAAiB,EAAE,IAAI;AAAA,MAChE,EAAE;AAAA,IACJ;AAEA,UAAM,SAAS,UAAU;AACzB,IAAG,WAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAClD,IAAG,cAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AAExC,QAAI;AACF,iBAAW,QAAQ,iBAAiB;AAClC,cAAM,WAAgB,WAAK,QAAQ,KAAK,YAAY;AACpD,QAAG,cAAe,cAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AACxD,cAAM,aAAa,KAAK,SAAS,QAAQ;AAAA,MAC3C;AAEA,MAAG,WAAO,SAAS,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACnD,MAAG,eAAW,QAAQ,OAAO;AAAA,IAC/B,SAAS,KAAK;AACZ,MAAG,WAAO,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAClD,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,YACZ,MACA,SACgD;AAChD,UAAM,SAAS,qCAAqC,IAAI,cAAc,OAAO;AAC7E,UAAM,UAAW,MAAM,UAAU,MAAM;AACvC,UAAM,QAA+C,CAAC;AAEtD,eAAW,SAAS,SAAS;AAC3B,UAAI,MAAM,SAAS,QAAQ;AACzB,cAAM,KAAK,EAAE,MAAM,MAAM,MAAM,MAAM,MAAM,QAAQ,MAAM,KAAK,QAAQ,EAAE,CAAC;AAAA,MAC3E,WAAW,MAAM,SAAS,aAAa;AACrC,cAAM,WAAW,MAAM,KAAK,YAAY,MAAM,MAAM,IAAI;AACxD,cAAM,KAAK,GAAG,QAAQ;AAAA,MACxB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;ACtPA,SAAS,UAAU,aAAa;AAEhC,SAAS,iBAAiB;AAC1B,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AAEtB,IAAM,gBAAgB,UAAU,QAAQ;AAEjC,IAAM,mBAAN,MAAqD;AAAA,EAI1D,YAA6B,SAAiB;AAAjB;AAC3B,SAAK,WAAgB,WAAK,SAAS,OAAO;AAAA,EAC5C;AAAA,EALQ;AAAA,EACA,cAAwC;AAAA,EAMhD,MAAM,QAAoC;AACxC,QAAI,KAAK,YAAa,QAAO,KAAK;AAGlC,eAAW,OAAO,CAAC,WAAW,QAAQ,GAAG;AACvC,UAAI;AACF,cAAM,EAAE,OAAO,IAAI,MAAM,cAAc,KAAK,CAAC,WAAW,CAAC;AACzD,cAAM,UAAU,OAAO,KAAK,EAAE,QAAQ,WAAW,EAAE;AACnD,cAAM,QAAQ,SAAS,QAAQ,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE;AACvD,cAAM,QAAQ,SAAS,QAAQ,MAAM,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE;AAEvD,YAAI,QAAQ,KAAM,UAAU,KAAK,QAAQ,GAAK;AAG9C,cAAM,EAAE,QAAQ,QAAQ,IAAI,MAAM,cAAc,KAAK,CAAC,MAAM,mCAAmC,CAAC;AAEhG,aAAK,cAAc;AAAA,UACjB,WAAW;AAAA,UACX;AAAA,UACA,MAAM,QAAQ,KAAK;AAAA,QACrB;AACA,eAAO,KAAK;AAAA,MACd,QAAQ;AAAE;AAAA,MAAS;AAAA,IACrB;AAEA,SAAK,cAAc,EAAE,WAAW,MAAM;AACtC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,OAAO,SAAmE;AAC9E,UAAM,QAAQ,MAAM,KAAK,MAAM;AAC/B,QAAI,CAAC,MAAM,aAAa,CAAC,MAAM,MAAM;AACnC,YAAM,IAAI,MAAM,uDAAuD;AAAA,IACzE;AAGA,QAAI,CAAI,eAAgB,WAAK,KAAK,UAAU,OAAO,QAAQ,CAAC,GAAG;AAC7D,YAAM,cAAc,MAAM,MAAM,CAAC,MAAM,QAAQ,KAAK,QAAQ,CAAC;AAAA,IAC/D;AAEA,UAAM,aAAkB,WAAK,KAAK,UAAU,OAAO,QAAQ;AAG3D,QAAI,QAAQ,SAAS,SAAS,GAAG;AAC/B,YAAM,cAAc,YAAY,CAAC,MAAM,OAAO,WAAW,MAAM,GAAG,QAAQ,QAAQ,CAAC;AAAA,IACrF;AAEA,WAAO;AAAA,MACL,YAAY;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,OAAO,CAAC,QAAgB,SAA4B;AAClD,eAAO,MAAM,YAAY,CAAC,QAAQ,GAAG,IAAI,CAAC;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,QAAgB,MAAuC;AAC3D,UAAM,aAAkB,WAAK,KAAK,UAAU,OAAO,QAAQ;AAC3D,QAAI,CAAI,eAAW,UAAU,GAAG;AAC9B,YAAM,IAAI,MAAM,mDAAmD;AAAA,IACrE;AACA,WAAO,MAAM,YAAY,CAAC,QAAQ,GAAG,IAAI,CAAC;AAAA,EAC5C;AACF;;;AC3EO,IAAM,oBAAN,MAAwB;AAAA,EAC7B,YAA6B,QAAqB;AAArB;AAAA,EAAsB;AAAA,EAEnD,SAAS,QAA0C;AACjD,UAAM,SAA4B,CAAC;AACnC,UAAM,WAA8B,CAAC;AAGrC,eAAW,QAAQ,OAAO,OAAO;AAC/B,WAAK,aAAa,MAAM,QAAQ,UAAU,CAAC,CAAC;AAAA,IAC9C;AAGA,QAAI,OAAO,OAAO;AAChB,WAAK,aAAa,OAAO,OAAO,QAAQ,UAAU,CAAC,CAAC;AAAA,IACtD;AAEA,WAAO;AAAA,MACL,OAAO,OAAO,WAAW;AAAA,MACzB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,aACN,MACA,QACA,UACA,WACM;AAEN,QAAI,CAAC,KAAK,OAAO,SAAS,KAAK,KAAK,GAAG;AACrC,aAAO,KAAK;AAAA,QACV,MAAM,KAAK;AAAA,QACX,OAAO,KAAK;AAAA,QACZ,SAAS,UAAU,KAAK,KAAK;AAAA,QAC7B,UAAU;AAAA,MACZ,CAAC;AACD;AAAA,IACF;AAGA,UAAM,aAAa,KAAK,OAAO,SAAS,KAAK,KAAK;AAClD,QAAI,YAAY;AACd,YAAM,WAAW,WAAW;AAG5B,WAAK;AAAA,IACP;AAGA,QAAI,KAAK,UAAU;AACjB,iBAAW,SAAS,KAAK,UAAU;AACjC,aAAK,aAAa,OAAO,QAAQ,UAAU,CAAC,GAAG,WAAW,IAAI,CAAC;AAAA,MACjE;AAAA,IACF;AAAA,EACF;AACF;;;AC9CA,SAAS,kBAAkB;AAEpB,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YACmB,eACA,cACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAEH,MAAM,IAAI,OAAmB,QAAiD;AAC5E,UAAM,YAAY,YAAY,IAAI;AAClC,UAAM,UAAwB,CAAC;AAC/B,UAAM,UAAkC,CAAC;AAGzC,eAAW,YAAY,OAAO,OAAO;AACnC,YAAM,KAAK,YAAY,UAAU,OAAO,MAAM,SAAS,OAAO;AAAA,IAChE;AAGA,QAAI,OAAO,OAAO;AAChB,YAAM,KAAK,YAAY,OAAO,OAAO,OAAO,MAAM,SAAS,OAAO;AAAA,IACpE;AAEA,WAAO;AAAA,MACL;AAAA,MACA,SAAS,YAAY,IAAI,IAAI;AAAA,MAC7B;AAAA,MACA,gBAAgB,MAAM;AAAA,IACxB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAAa,OAAwB,WAAkD;AAC3F,UAAM,YAAY,YAAY,IAAI;AAClC,UAAM,UAAwB,CAAC;AAC/B,UAAM,UAAkC,CAAC;AACzC,UAAM,WAAW,WAAW;AAC5B,UAAM,YAAY,YAAY,IAAI;AAElC,QAAI;AACF,YAAM,eAAe,KAAK,aAAa,IAAI,UAAU,KAAK,KAAK,CAAC;AAChE,YAAM,SAAS,MAAM,KAAK,cAAc;AAAA,QACtC,UAAU;AAAA,QAAO;AAAA,QAAc,UAAU;AAAA,MAC3C;AAEA,UAAI,EAAE,mBAAmB,WAAW,OAAQ,OAA8C,eAAe,MAAM,YAAY;AACzH,cAAM,IAAI,MAAM,UAAU,UAAU,KAAK,+BAA+B;AAAA,MAC1E;AAEA,YAAM,SAAS,MAAO,OAA+F,cAAc,KAAK;AACxI,YAAM,SAAS,YAAY,IAAI,IAAI;AAEnC,YAAM,aAAyB;AAAA,QAC7B,OAAO,UAAU;AAAA,QACjB,MAAM;AAAA,QACN;AAAA,QACA;AAAA,QACA,aAAa,OAAO;AAAA,QACpB,cAAc;AAAA,QACd,SAAS;AAAA,MACX;AACA,cAAQ,KAAK,UAAU;AACvB,cAAQ,UAAU,IAAI,IAAI;AAAA,IAC5B,SAAS,OAAgB;AACvB,YAAM,SAAS,YAAY,IAAI,IAAI;AACnC,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,cAAQ,KAAK;AAAA,QACX,OAAO,UAAU;AAAA,QACjB,MAAM;AAAA,QACN,QAAQ,EAAE,iBAAiB,CAAC,GAAG,aAAa,GAAG,SAAS,GAAG;AAAA,QAC3D;AAAA,QACA,aAAa;AAAA,QACb,cAAc;AAAA,QACd,SAAS;AAAA,QACT,OAAO;AAAA,UACL,MAAM;AAAA,UACN;AAAA,UACA,iBAAiB;AAAA,QACnB;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL;AAAA,MACA,SAAS,YAAY,IAAI,IAAI;AAAA,MAC7B;AAAA,MACA,gBAAgB,MAAM;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAc,YACZ,MACA,OACA,iBACA,SACA,SACe;AACf,UAAM,WAAW,WAAW;AAC5B,UAAM,YAAY,YAAY,IAAI;AAElC,QAAI;AAEF,YAAM,eAAe,KAAK,aAAa,IAAI,KAAK,KAAK,KAAK,CAAC;AAC3D,YAAM,SAAS,MAAM,KAAK,cAAc;AAAA,QACtC,KAAK;AAAA,QAAO;AAAA,QAAc,KAAK;AAAA,MACjC;AAGA,UAAI;AAEJ,UAAI,iBAAiB;AAEnB,cAAM,YAAuB;AAAA,UAC3B;AAAA,UACA,KAAK,gBAAgB,IAAI;AAAA,UACzB,iBAAiB,gBAAgB;AAAA,QACnC;AAGA,YAAI,UAAU,UAAU,OAAQ,OAA8C,MAAM,MAAM,YAAY;AACpG,mBAAS,MAAO,OAA6E,KAAK,SAAS;AAAA,QAC7G,WAAW,cAAc,UAAU,OAAQ,OAA8C,UAAU,MAAM,YAAY;AACnH,mBAAS,MAAO,OAAoF,SAAS,SAAS;AAAA,QACxH,WAAW,YAAY,UAAU,OAAQ,OAA8C,QAAQ,MAAM,YAAY;AAE/G,mBAAS,MAAO,OAAiF,OAAO,KAAK;AAAA,QAC/G,OAAO;AACL,gBAAM,IAAI,MAAM,UAAU,KAAK,KAAK,sCAAsC;AAAA,QAC5E;AAAA,MACF,OAAO;AAEL,YAAI,YAAY,UAAU,OAAQ,OAA8C,QAAQ,MAAM,YAAY;AACxG,mBAAS,MAAO,OAAiF,OAAO,KAAK;AAAA,QAC/G,WAAW,cAAc,UAAU,OAAQ,OAA8C,UAAU,MAAM,YAAY;AAEnH,gBAAM,gBAA2B;AAAA,YAC/B;AAAA,YACA,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,MAAM,OAAO,GAAG,MAAM,OAAO;AAAA,YACnD,iBAAiB,EAAE,OAAO,IAAI,eAAe,IAAI,OAAO,GAAG,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,MAAM,OAAO,GAAG,MAAM,OAAO,EAAE;AAAA,UACnH;AACA,mBAAS,MAAO,OAAoF,SAAS,aAAa;AAAA,QAC5H,OAAO;AACL,gBAAM,IAAI,MAAM,UAAU,KAAK,KAAK,iCAAiC;AAAA,QACvE;AAAA,MACF;AAEA,YAAM,SAAS,YAAY,IAAI,IAAI;AAGnC,YAAM,OACJ,gBAAgB,SAAS,aACzB,WAAW,SAAS,YACpB;AAEF,YAAM,aAAyB;AAAA,QAC7B,OAAO,KAAK;AAAA,QACZ;AAAA,QACA;AAAA,QACA,gBAAgB,iBAAiB;AAAA,QACjC;AAAA,QACA,aAAa,OAAO;AAAA,QACpB,cAAc;AAAA,QACd,SAAS;AAAA,MACX;AACA,cAAQ,KAAK,UAAU;AACvB,cAAQ,KAAK,IAAI,IAAI;AAGrB,UAAI,KAAK,UAAU,QAAQ;AACzB,cAAM,aACJ,gBAAgB,SAAS,OAAO,aAChC,WAAW,SAAS,OAAO,QAC3B,CAAC;AAGH,cAAM,KAAK,gBAAgB,KAAK,UAAU,OAAO,YAAY,UAAU,SAAS,OAAO;AAAA,MACzF;AAAA,IACF,SAAS,OAAgB;AACvB,YAAM,SAAS,YAAY,IAAI,IAAI;AACnC,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,cAAQ,KAAK;AAAA,QACX,OAAO,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,QAAQ,EAAE,YAAY,CAAC,GAAG,aAAa,GAAG,SAAS,GAAG;AAAA,QACtD,gBAAgB,iBAAiB;AAAA,QACjC;AAAA,QACA,aAAa;AAAA,QACb,cAAc;AAAA,QACd,SAAS;AAAA,QACT,OAAO;AAAA,UACL,MAAM;AAAA,UACN;AAAA,UACA,iBAAiB;AAAA,QACnB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,MAAc,gBACZ,UACA,OACA,kBACA,gBACA,SACA,SACe;AAEf,UAAMC,YAA4B,CAAC;AAEnC,eAAW,aAAa,kBAAkB;AACxC,iBAAW,SAAS,UAAU;AAG5B,QAAAA,UAAS;AAAA,UACP,KAAK,YAAY,OAAO,OAAO,EAAE,KAAK,WAAW,UAAU,eAAe,GAAG,SAAS,OAAO;AAAA,QAC/F;AAAA,MACF;AAAA,IACF;AAEA,UAAM,QAAQ,WAAWA,SAAQ;AAAA,EACnC;AACF;;;AChPA,SAAS,MAAM,SAAAC,cAAgC;AAU/C,IAAM,uBAAuB;AAC7B,IAAM,iBAAiB;AACvB,IAAM,uBAAuB;AAEtB,IAAM,iBAAN,MAAqB;AAAA,EAS1B,YACmB,QACA,QACA,QACjB;AAHiB;AACA;AACA;AAAA,EAChB;AAAA,EAZK,eAAoC;AAAA,EACpC,SAAuB;AAAA,EACvB;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB;AAAA,EACA;AAAA,EAQR,IAAI,QAAsB;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,SAAS;AAEd,QAAI;AACF,UAAI,KAAK,OAAO,YAAY;AAC1B,aAAK,eAAe,KAAK,KAAK,OAAO,YAAY,KAAK,OAAO,QAAQ,CAAC,GAAG;AAAA,UACvE,KAAK,EAAE,GAAG,QAAQ,KAAK,GAAG,KAAK,OAAO,IAAI;AAAA,UAC1C,OAAO,CAAC,QAAQ,QAAQ,QAAQ,KAAK;AAAA,QACvC,CAAC;AAAA,MACH,WAAW,KAAK,OAAO,SAAS;AAC9B,aAAK,eAAeA,OAAM,KAAK,OAAO,SAAS,KAAK,OAAO,QAAQ,CAAC,GAAG;AAAA,UACrE,KAAK,EAAE,GAAG,QAAQ,KAAK,GAAG,KAAK,OAAO,IAAI;AAAA,UAC1C,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,QAChC,CAAC;AAAA,MACH,OAAO;AACL,cAAM,IAAI,MAAM,oCAAoC;AAAA,MACtD;AAEA,WAAK,aAAa,QAAQ,GAAG,QAAQ,CAAC,SAAiB;AACrD,aAAK,OAAO,MAAM,KAAK,SAAS,EAAE,KAAK,CAAC;AAAA,MAC1C,CAAC;AAED,WAAK,aAAa,QAAQ,GAAG,QAAQ,CAAC,SAAiB;AACrD,aAAK,OAAO,KAAK,KAAK,SAAS,EAAE,KAAK,CAAC;AAAA,MACzC,CAAC;AAED,WAAK,aAAa,GAAG,QAAQ,CAAC,MAAM,WAAW;AAC7C,cAAM,MAAM,wBAAwB,IAAI,YAAY,MAAM;AAE1D,YAAI,SAAS,GAAG;AACd,eAAK,OAAO,KAAK,GAAG;AACpB,eAAK,SAAS;AAAA,QAChB,OAAO;AACL,eAAK,eAAe,KAAK,IAAI;AAC7B,eAAK,kBAAkB;AACvB,eAAK,OAAO,MAAM,GAAG;AACrB,eAAK,SAAS;AAEd,eAAK,OAAO;AAAA,YACV,KAAK,OAAO;AAAA,YACZ;AAAA,YACA;AAAA,YACA,KAAK;AAAA,UACP;AAEA,gBAAM,cAAc,KAAK,OAAO,eAAe;AAC/C,cAAI,KAAK,OAAO,eAAe,KAAK,gBAAgB,aAAa;AAC/D,iBAAK,gBAAgB;AAAA,UACvB;AAAA,QACF;AAEA,aAAK,eAAe;AAAA,MACtB,CAAC;AAED,WAAK,aAAa,GAAG,SAAS,CAAC,QAAe;AAC5C,aAAK,OAAO,MAAM,kBAAkB,IAAI,OAAO,EAAE;AACjD,aAAK,kBAAkB,IAAI;AAC3B,aAAK,SAAS;AAAA,MAChB,CAAC;AAED,WAAK,SAAS;AACd,WAAK,aAAa,KAAK,IAAI;AAAA,IAC7B,SAAS,KAAK;AACZ,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,WAAK,SAAS;AACd,WAAK,kBAAkB;AACvB,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI,KAAK,cAAc;AACrB,mBAAa,KAAK,YAAY;AAC9B,WAAK,eAAe;AAAA,IACtB;AAEA,QAAI,KAAK,WAAW,WAAW;AAC7B;AAAA,IACF;AAEA,SAAK,SAAS;AAEd,QAAI,KAAK,gBAAgB,CAAC,KAAK,aAAa,QAAQ;AAClD,WAAK,aAAa,KAAK,SAAS;AAEhC,YAAM,IAAI,QAAc,CAAC,YAAY;AACnC,cAAM,UAAU,WAAW,MAAM;AAC/B,cAAI,KAAK,gBAAgB,CAAC,KAAK,aAAa,QAAQ;AAClD,iBAAK,aAAa,KAAK,SAAS;AAAA,UAClC;AACA,kBAAQ;AAAA,QACV,GAAG,oBAAoB;AAEvB,aAAK,cAAc,GAAG,QAAQ,MAAM;AAClC,uBAAa,OAAO;AACpB,kBAAQ;AAAA,QACV,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAGA,UAAM,eAAe,KAAK;AAC1B,QAAI,iBAAiB,WAAW;AAC9B,WAAK,SAAS;AAAA,IAChB;AAAA,EACF;AAAA,EAEA,YAAkC;AAChC,WAAO;AAAA,MACL,IAAI,KAAK,OAAO;AAAA,MAChB,OAAO,KAAK,OAAO;AAAA,MACnB,OAAO,KAAK;AAAA,MACZ,KAAK,KAAK,cAAc;AAAA,MACxB,OAAO,KAAK,cAAc,MAAM,KAAK,SAAS,IAAI;AAAA,MAClD,aAAa,KAAK;AAAA,MAClB,gBAAgB,KAAK;AAAA,MACrB,cAAc,KAAK;AAAA,MACnB,eAAe,KAAK,eAAe,KAAK,mBAAmB,IAAI;AAAA,IACjE;AAAA,EACF;AAAA,EAEQ,kBAAwB;AAC9B,SAAK;AACL,UAAM,UAAU,KAAK,IAAI,MAAO,KAAK,IAAI,GAAG,KAAK,gBAAgB,CAAC,GAAG,cAAc;AAEnF,SAAK,OAAO,KAAK,uBAAuB,KAAK,aAAa,OAAO,OAAO,IAAI;AAE5E,SAAK,OAAO;AAAA,MACV,KAAK,OAAO;AAAA,MACZ,KAAK;AAAA,MACL;AAAA,IACF;AAEA,SAAK,eAAe,WAAW,YAAY;AACzC,WAAK,eAAe;AACpB,UAAI;AACF,cAAM,KAAK,MAAM;AACjB,aAAK,OAAO,qBAAqB,KAAK,OAAO,IAAI,KAAK,aAAa;AAAA,MACrE,SAAS,KAAK;AACZ,aAAK,OAAO,MAAM,mBAAmB,GAAG,EAAE;AAAA,MAC5C;AAAA,IACF,GAAG,OAAO;AAAA,EACZ;AAAA,EAEQ,WAAqC;AAC3C,QAAI,CAAC,KAAK,cAAc,IAAK,QAAO;AACpC,UAAM,SAAS,KAAK,aAAa,KAAK,IAAI,IAAI,KAAK,aAAa;AAChE,WAAO;AAAA,MACL,KAAK,KAAK,aAAa;AAAA,MACvB,KAAK;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA,cAAc,KAAK;AAAA,IACrB;AAAA,EACF;AAAA,EAEQ,qBAAyC;AAC/C,QAAI,CAAC,KAAK,aAAc,QAAO;AAC/B,UAAM,UAAU,KAAK,IAAI,MAAO,KAAK,IAAI,GAAG,KAAK,gBAAgB,CAAC,GAAG,cAAc;AACnF,WAAO,KAAK,eAAe;AAAA,EAC7B;AACF;;;AC1LO,IAAM,iBAAN,MAAqB;AAAA,EAG1B,YACmB,QACA,eACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EALc,YAAyC,oBAAI,IAAI;AAAA,EAOlE,SAAS,QAAuC;AAC9C,QAAI,KAAK,UAAU,IAAI,OAAO,EAAE,GAAG;AACjC,YAAM,IAAI,MAAM,+BAA+B,OAAO,EAAE,EAAE;AAAA,IAC5D;AAEA,UAAM,SAAS,KAAK,cAAc,aAAa,WAAW,OAAO,EAAE,EAAE;AACrE,UAAM,UAAU,IAAI,eAAe,QAAQ,KAAK,QAAQ,MAAM;AAC9D,SAAK,UAAU,IAAI,OAAO,IAAI,OAAO;AACrC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,MAAM,IAA2B;AACrC,UAAM,IAAI,KAAK,IAAI,EAAE;AACrB,UAAM,EAAE,MAAM;AAAA,EAChB;AAAA,EAEA,MAAM,KAAK,IAA2B;AACpC,UAAM,IAAI,KAAK,IAAI,EAAE;AACrB,UAAM,EAAE,KAAK;AAAA,EACf;AAAA,EAEA,MAAM,QAAQ,IAA2B;AACvC,UAAM,IAAI,KAAK,IAAI,EAAE;AACrB,UAAM,EAAE,KAAK;AACb,UAAM,EAAE,MAAM;AAAA,EAChB;AAAA,EAEA,IAAI,IAA4B;AAC9B,UAAM,IAAI,KAAK,UAAU,IAAI,EAAE;AAC/B,QAAI,CAAC,EAAG,OAAM,IAAI,MAAM,sBAAsB,EAAE,EAAE;AAClD,WAAO;AAAA,EACT;AAAA,EAEA,UAA2C;AACzC,WAAO,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC;AAAA,EAC9D;AAAA,EAEA,MAAM,cAA6B;AACjC,UAAM,UAAU,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,EAAE;AAAA,MAC3C,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU;AAAA,IACjC;AAEA,UAAM,QAAQ,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AAAA,EAChD;AACF;;;ACtCO,IAAM,wBAAN,MAAM,uBAAwD;AAAA,EAClD,UAAU,oBAAI,IAG5B;AAAA,EAEH,OAAwB,cAAc;AAAA;AAAA,EAEtC,kBAAkB,UAAkB,UAAkB,aAAqB,YAA2B;AACpG,UAAM,SAAS,KAAK,kBAAkB,QAAQ;AAC9C,QAAI,SAAS,OAAO,QAAQ,IAAI,QAAQ;AACxC,QAAI,CAAC,QAAQ;AACX,eAAS,EAAE,oBAAoB,aAAa,SAAS,CAAC,GAAG,iBAAiB,GAAG,mBAAmB,CAAC,GAAG,aAAa,EAAE;AACnH,aAAO,QAAQ,IAAI,UAAU,MAAM;AAAA,IACrC;AAEA,WAAO,QAAQ,KAAK,WAAW;AAC/B,QAAI,OAAO,QAAQ,SAAS,uBAAsB,YAAa,QAAO,QAAQ,MAAM;AAEpF,WAAO,kBAAkB,KAAK,IAAI,OAAO,iBAAiB,WAAW;AAErE,QAAI,eAAe,QAAW;AAC5B,aAAO,kBAAkB,KAAK,UAAU;AACxC,UAAI,OAAO,kBAAkB,SAAS,uBAAsB,YAAa,QAAO,kBAAkB,MAAM;AAAA,IAC1G;AAEA,WAAO,cAAc,KAAK,IAAI;AAAA,EAChC;AAAA,EAEA,kBAAkB,UAAkB,OAAsD;AACxF,UAAM,SAAS,KAAK,kBAAkB,QAAQ;AAC9C,WAAO,SAAS,EAAE,GAAG,OAAO,aAAa,KAAK,IAAI,EAAE;AAAA,EACtD;AAAA,EAEA,eAAe,UAA6C;AAC1D,UAAM,SAAS,KAAK,QAAQ,IAAI,QAAQ;AACxC,QAAI,CAAC,OAAQ,QAAO;AAEpB,UAAM,UAA8C,CAAC;AACrD,eAAW,CAAC,UAAU,CAAC,KAAK,OAAO,SAAS;AAC1C,YAAM,MAAM,CAAC,QAAkB,IAAI,WAAW,IAAI,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,IAAI;AAC3F,cAAQ,QAAQ,IAAI;AAAA,QAClB,oBAAoB,EAAE;AAAA,QACtB,qBAAqB,KAAK,MAAM,IAAI,EAAE,OAAO,CAAC;AAAA,QAC9C,iBAAiB,EAAE;AAAA,QACnB,mBAAmB,KAAK,MAAM,IAAI,EAAE,iBAAiB,IAAI,EAAE,IAAI;AAAA,QAC/D,aAAa,EAAE;AAAA,MACjB;AAAA,IACF;AAEA,WAAO,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,OAAU;AAAA,EACjE;AAAA,EAEA,cAA6C;AAC3C,UAAM,UAAgC,CAAC;AACvC,eAAW,YAAY,KAAK,QAAQ,KAAK,GAAG;AAC1C,YAAM,QAAQ,KAAK,eAAe,QAAQ;AAC1C,UAAI,MAAO,SAAQ,KAAK,KAAK;AAAA,IAC/B;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,kBAAkB,UAAkB;AAC1C,QAAI,SAAS,KAAK,QAAQ,IAAI,QAAQ;AACtC,QAAI,CAAC,QAAQ;AACX,eAAS,EAAE,SAAS,oBAAI,IAAI,GAAG,QAAQ,KAAK;AAC5C,WAAK,QAAQ,IAAI,UAAU,MAAM;AAAA,IACnC;AACA,WAAO;AAAA,EACT;AACF;;;AC5FA,YAAY,QAAQ;AACpB,YAAY,UAAU;AAQtB,IAAM,uBAAuB;AAC7B,IAAM,wBAAwB;AAEvB,IAAM,aAAN,MAAwC;AAAA,EAC7C,YACmB,iBACjB;AADiB;AAAA,EAChB;AAAA,EAEH,MAAM,QAAQ,MAAc,SAAkD;AAC5E,UAAM,QAAQ,KAAK,IAAI;AACvB,UAAM,UAAU,KAAK,aAAa,OAAO;AAEzC,QAAI;AACF,YAAM,YAAe,iBAAc,OAAO;AAC1C,YAAM,SAAS,IAAO,UAAO,IAAI;AACjC,UAAI,SAAS,OAAO,aAAa,WAAW,EAAE,SAAS,qBAAqB,CAAC;AAG7E,UAAI,UAAU,OAAO,OAAO,SAAS,YAAY;AAC/C,iBAAS,MAAM,QAAQ,KAAK;AAAA,UAC1B;AAAA,UACA,IAAI;AAAA,YAAQ,CAAC,GAAG,WACd,WAAW,MAAM,OAAO,IAAI,MAAM,oBAAoB,CAAC,GAAG,oBAAoB;AAAA,UAChF;AAAA,QACF,CAAC;AAAA,MACH;AAEA,YAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,UAAI,WAAW,QAAW;AACxB,eAAO,EAAE,QAAQ,aAAa,MAAM,QAAQ,SAAS;AAAA,MACvD;AAEA,aAAO;AAAA,QACL,QAAa,aAAQ,QAAQ;AAAA,UAC3B,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,gBAAgB;AAAA,UAChB,iBAAiB;AAAA,QACnB,CAAC;AAAA,QACD,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACF,SAAS,KAAc;AAGrB,YAAM,UACJ,eAAe,QACX,IAAI,UACJ,OAAO,QAAQ,YAAY,QAAQ,QAAQ,aAAa,MACtD,OAAQ,IAA6B,OAAO,IAC5C,OAAO,GAAG;AAClB,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,UAAU,KAAK,IAAI,IAAI;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,eAAe,SAAiB,SAAgD;AACpF,UAAM,UAAU,KAAK,aAAa,OAAO;AACzC,UAAM,OAAO,OAAO,KAAK,OAAO;AAEhC,QAAI,CAAC,QAAS,QAAO;AAErB,UAAM,UAAU,QAAQ,YAAY,GAAG;AACvC,QAAI,YAAY,IAAI;AAClB,aAAO,KAAK,OAAO,OAAK,EAAE,WAAW,OAAO,CAAC;AAAA,IAC/C;AAGA,UAAM,UAAU,QAAQ,UAAU,GAAG,OAAO;AAC5C,UAAM,aAAa,QAAQ,UAAU,UAAU,CAAC;AAEhD,QAAI;AACF,YAAM,YAAe,iBAAc,OAAO;AAC1C,YAAM,MAAS,gBAAa,SAAS,WAAW,EAAE,SAAS,sBAAsB,CAAC;AAClF,UAAI,OAAO,OAAO,QAAQ,UAAU;AAClC,cAAM,QAAQ,OAAO,eAAe,GAAG;AACvC,cAAM,UAAU,OAAO,oBAAoB,GAAG,EAC3C,OAAO,OAAO,oBAAoB,SAAS,CAAC,CAAC,CAAC,EAC9C,OAAO,OAAK,EAAE,WAAW,UAAU,CAAC;AACvC,eAAO,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,EAAE,IAAI,OAAK,GAAG,OAAO,IAAI,CAAC,EAAE;AAAA,MACzD;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,WAAO,CAAC;AAAA,EACV;AAAA,EAEQ,aAAa,SAAsD;AACzE,UAAM,OAAgC;AAAA,MACpC,SAAS;AAAA,QACP,KAAK,IAAI,SAAyB,aAAQ,IAAI;AAAA,QAC9C,MAAM,IAAI,SAAyB,aAAQ,IAAI;AAAA,MACjD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAEA,YAAY;AAAA,MACZ,aAAa;AAAA,MACb,OAAO;AAAA,MACP,SAAS;AAAA,MACT,SAAS;AAAA;AAAA,MAET,GAAG,QAAQ;AAAA,IACb;AAEA,YAAQ,QAAQ,MAAM,MAAM;AAAA,MAC1B,KAAK;AACH,eAAO,EAAE,GAAG,MAAM,GAAG,KAAK,gBAAgB,iBAAiB,EAAE;AAAA,MAE/D,KAAK;AACH,eAAO,EAAE,GAAG,MAAM,GAAG,KAAK,gBAAgB,iBAAiB,QAAQ,MAAM,QAAS,EAAE;AAAA,MAEtF,KAAK;AACH,eAAO,EAAE,GAAG,MAAM,GAAG,KAAK,gBAAgB,mBAAmB,QAAQ,MAAM,UAAW,EAAE;AAAA,MAE1F,KAAK;AACH,eAAO,EAAE,GAAG,MAAM,GAAG,KAAK,gBAAgB,gBAAgB,QAAQ,MAAM,OAAQ,EAAE;AAAA,MAEpF;AACE,eAAO;AAAA,IACX;AAAA,EACF;AACF;;;AC3IO,IAAM,gBAAN,MAAoB;AAAA,EAIzB,YACmB,QACA,qBAA6B,KAC7B,2BAAmC,KACpD;AAHiB;AACA;AACA;AAAA,EAChB;AAAA,EAPc,SAAkC,oBAAI,IAAI;AAAA,EAC1C,qBAAkD,oBAAI,IAAI;AAAA;AAAA,EAS3E,cAAc,MAAuB;AACnC,UAAM,QAAoB;AAAA,MACxB;AAAA,MACA,OAAO;AAAA,MACP,gBAAgB,KAAK,IAAI;AAAA,MACzB,eAAe,KAAK,IAAI;AAAA,MACxB,iBAAiB;AAAA,MACjB,oBAAoB;AAAA,MACpB,iBAAiB;AAAA,IACnB;AAEA,SAAK,OAAO,IAAI,KAAK,IAAI,KAAK;AAC9B,SAAK,oBAAoB,KAAK,EAAE;AAEhC,SAAK,OAAO,oBAAoB,KAAK,IAAI,CAAC,GAAG,KAAK,YAAY,CAAC;AAAA,EACjE;AAAA;AAAA,EAGA,gBAAgB,IAAkB;AAChC,UAAM,WAAW,KAAK,mBAAmB,IAAI,EAAE;AAC/C,QAAI,UAAU;AACZ,oBAAc,QAAQ;AACtB,WAAK,mBAAmB,OAAO,EAAE;AAAA,IACnC;AAEA,SAAK,OAAO,OAAO,EAAE;AACrB,SAAK,OAAO,sBAAsB,EAAE;AAAA,EACtC;AAAA;AAAA,EAGA,UAAU,IAAkB;AAC1B,UAAM,QAAQ,KAAK,OAAO,IAAI,EAAE;AAChC,QAAI,CAAC,MAAO;AAEZ,UAAM,gBAAgB,KAAK,IAAI;AAE/B,QAAI,MAAM,UAAU,WAAW;AAC7B,YAAM,QAAQ;AACd,WAAK,OAAO,gBAAgB,EAAE;AAAA,IAChC;AAAA,EACF;AAAA;AAAA,EAGA,wBAAwB,YAA2C;AACjE,WAAO,CAAC,GAAG,KAAK,OAAO,OAAO,CAAC,EAAE;AAAA,MAC/B,CAAC,MAAM,EAAE,UAAU,YAAY,EAAE,KAAK,aAAa,SAAS,UAAU;AAAA,IACxE;AAAA,EACF;AAAA;AAAA,EAGA,YAAY,YAAoB,aAAyC;AACvE,UAAM,UAAU,KAAK,wBAAwB,UAAU;AACvD,QAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAI,aAAa;AACf,YAAM,YAAY,QAAQ,KAAK,CAAC,MAAM,EAAE,KAAK,OAAO,WAAW;AAC/D,UAAI,UAAW,QAAO;AAAA,IACxB;AAGA,UAAM,SAAS,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,kBAAkB,EAAE,eAAe;AAChF,WAAO,OAAO,CAAC,KAAK;AAAA,EACtB;AAAA;AAAA,EAGA,aAAqC;AACnC,WAAO,CAAC,GAAG,KAAK,OAAO,OAAO,CAAC,EAAE,IAAI,CAAC,WAAW;AAAA,MAC/C,IAAI,MAAM,KAAK;AAAA,MACf,MAAM,MAAM,KAAK;AAAA,MACjB,OAAO,MAAM;AAAA,MACb,cAAc,CAAC,GAAG,MAAM,KAAK,YAAY;AAAA,MACzC,eAAe,MAAM;AAAA,MACrB,gBAAgB,MAAM;AAAA,MACtB,WAAW,MAAM,KAAK;AAAA,MACtB,iBAAiB,MAAM;AAAA,MACvB,oBAAoB,MAAM;AAAA,MAC1B,iBAAiB,MAAM;AAAA,IACzB,EAAE;AAAA,EACJ;AAAA;AAAA,EAGA,SAAS,IAA+B;AACtC,WAAO,KAAK,OAAO,IAAI,EAAE,KAAK;AAAA,EAChC;AAAA;AAAA,EAGA,UAAgB;AACd,eAAW,YAAY,KAAK,mBAAmB,OAAO,GAAG;AACvD,oBAAc,QAAQ;AAAA,IACxB;AACA,SAAK,mBAAmB,MAAM;AAAA,EAChC;AAAA,EAEQ,oBAAoB,IAAkB;AAC5C,UAAM,WAAW,YAAY,MAAM;AACjC,YAAM,QAAQ,KAAK,OAAO,IAAI,EAAE;AAChC,UAAI,CAAC,MAAO;AAEZ,YAAM,UAAU,KAAK,IAAI,IAAI,MAAM;AACnC,UAAI,UAAU,KAAK,sBAAsB,MAAM,UAAU,UAAU;AACjE,cAAM,QAAQ;AACd,aAAK,OAAO,iBAAiB,EAAE;AAAA,MACjC;AAAA,IACF,GAAG,KAAK,wBAAwB;AAEhC,SAAK,mBAAmB,IAAI,IAAI,QAAQ;AAAA,EAC1C;AACF;;;AC9GO,IAAM,iBAAN,MAAqB;AAAA,EAO1B,YACmB,eACA,QACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EATc,eAAyC,oBAAI,IAAI;AAAA,EACjD,iBAGb,oBAAI,IAAI;AAAA;AAAA,EAQZ,MAAM,SAAS,MAAiB,SAAyD;AACvF,UAAM,aAAa,SAAS,cAAc,KAAK;AAC/C,UAAM,QAAQ,KAAK,cAAc,YAAY,YAAY,SAAS,cAAc;AAEhF,QAAI,CAAC,SAAS,CAAC,SAAS,YAAY;AAClC,aAAO,KAAK,eAAe,IAAI;AAAA,IACjC;AAEA,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,YAAY;AAAA,MACd;AAAA,IACF;AAEA,WAAO,KAAK,YAAY,MAAM,KAAK;AAAA,EACrC;AAAA;AAAA,EAGA,sBACE,YACA,UACM;AACN,SAAK,eAAe,IAAI,YAAY,QAAQ;AAAA,EAC9C;AAAA;AAAA,EAGA,iBAAiB,QAA+B;AAC9C,UAAM,UAAU,KAAK,aAAa,IAAI,OAAO,MAAM;AACnD,QAAI,SAAS;AACX,mBAAa,QAAQ,OAAO;AAC5B,WAAK,aAAa,OAAO,OAAO,MAAM;AACtC,cAAQ,QAAQ,MAAM;AAAA,IACxB;AAGA,UAAM,QAAQ,KAAK,cAAc,SAAS,OAAO,OAAO;AACxD,QAAI,OAAO;AACT,YAAM;AACN,UAAI,OAAO,WAAW,WAAW;AAC/B,cAAM;AAAA,MACR,OAAO;AACL,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,eAAe,MAA2C;AACtE,UAAM,WAAW,KAAK,eAAe,IAAI,KAAK,UAAU;AACxD,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,OAAO,yBAAyB,KAAK,UAAU;AAAA,QAC/C,YAAY;AAAA,MACd;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,IAAI;AACvB,QAAI;AACF,YAAM,SAAS,MAAM,SAAS,KAAK,KAAK;AACxC,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,SAAS;AAAA,QACT,QAAQ;AAAA,QACR;AAAA,QACA,YAAY,KAAK,IAAI,IAAI;AAAA,MAC3B;AAAA,IACF,SAAS,KAAK;AACZ,aAAO;AAAA,QACL,QAAQ,KAAK;AAAA,QACb,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,OAAO,OAAO,GAAG;AAAA,QACjB,YAAY,KAAK,IAAI,IAAI;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,YAAY,MAAiB,OAA6C;AAChF,UAAM;AAEN,WAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,YAAM,UAAU,WAAW,MAAM;AAC/B,aAAK,aAAa,OAAO,KAAK,EAAE;AAChC,cAAM;AACN,cAAM;AACN,gBAAQ;AAAA,UACN,QAAQ,KAAK;AAAA,UACb,SAAS,MAAM,KAAK;AAAA,UACpB,QAAQ;AAAA,UACR,YAAY,KAAK;AAAA,UACjB,OAAO;AAAA,QACT,CAAC;AAAA,MACH,GAAG,KAAK,OAAO;AAEf,WAAK,aAAa,IAAI,KAAK,IAAI,EAAE,SAAS,QAAQ,MAAM;AAAA,MAAC,GAAG,QAAQ,CAAC;AAErE,WAAK,OAAO,mBAAmB,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,UAAU;AAAA,IACxE,CAAC;AAAA,EACH;AACF;;;AC7HA,IAAM,oBAAoB;AAC1B,IAAM,mBAAmB;AACzB,IAAM,wBAAwB;AAkBvB,IAAM,cAAN,MAAkB;AAAA,EACf,KAAoC;AAAA,EACpC,mBAAmB;AAAA,EACnB,iBAAwC;AAAA,EACxC,iBAAwC;AAAA,EACxC,YAAY;AAAA,EAEH,kBAAoC,CAAC;AAAA,EACrC,iBAAkC,CAAC;AAAA,EACnC,kBAAuC,CAAC;AAAA,EACxC,qBAA0C,CAAC;AAAA,EAE3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,gBAAoC;AAAA,IAC1C,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,KAAK,CAAC;AAAA,IACN,QAAQ,CAAC;AAAA,EACX;AAAA,EAEA,YAAY,QAA2B;AACrC,SAAK,SAAS,OAAO;AACrB,SAAK,QAAQ,OAAO;AACpB,SAAK,SAAS,OAAO;AACrB,SAAK,mBAAmB,OAAO;AAAA,EACjC;AAAA;AAAA,EAGA,MAAM,UAAyB;AAC7B,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAK,YAAY;AACjB,WAAK,UAAU,SAAS,MAAM;AAAA,IAChC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,aAAmB;AACjB,SAAK,YAAY;AACjB,SAAK,YAAY;AACjB,QAAI,KAAK,IAAI;AACX,WAAK,GAAG,MAAM;AACd,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA;AAAA,EAGA,KAAK,KAA8B;AACjC,QAAI,CAAC,KAAK,MAAM,KAAK,GAAG,eAAe,GAAwB;AAC7D,WAAK,OAAO,KAAK,mCAAmC;AACpD;AAAA,IACF;AACA,SAAK,GAAG,KAAK,KAAK,UAAU,GAAG,CAAC;AAAA,EAClC;AAAA;AAAA,EAGA,WAAW,MAAoB;AAC7B,QAAI,CAAC,KAAK,MAAM,KAAK,GAAG,eAAe,GAAG;AACxC;AAAA,IACF;AACA,SAAK,GAAG,KAAK,IAAI;AAAA,EACnB;AAAA;AAAA,EAGA,UAAU,SAA+B;AACvC,SAAK,gBAAgB,KAAK,OAAO;AAAA,EACnC;AAAA;AAAA,EAGA,cAAc,SAA8B;AAC1C,SAAK,eAAe,KAAK,OAAO;AAAA,EAClC;AAAA;AAAA,EAGA,UAAU,SAAkC;AAC1C,SAAK,gBAAgB,KAAK,OAAO;AAAA,EACnC;AAAA;AAAA,EAGA,aAAa,SAAkC;AAC7C,SAAK,mBAAmB,KAAK,OAAO;AAAA,EACtC;AAAA;AAAA,EAGA,aAAa,QAAkC;AAC7C,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA,EAGA,IAAI,YAAqB;AACvB,WAAO,KAAK,IAAI,eAAe;AAAA,EACjC;AAAA,EAEQ,UACN,WACA,SACM;AACN,QAAI,KAAK,UAAW;AAGpB,WAAO,IAAI,EAAE,KAAK,CAAC,EAAE,SAAS,UAAU,MAAM;AAC5C,UAAI,KAAK,UAAW;AAEpB,YAAM,MAAM,KAAK,QACb,GAAG,KAAK,MAAM,UAAU,mBAAmB,KAAK,KAAK,CAAC,KACtD,KAAK;AAGT,YAAM,YAAY,KAAK,OAAO,WAAW,QAAQ,IAC7C,EAAE,oBAAoB,MAAM,IAC5B,CAAC;AAEL,UAAI;AACF,aAAK,KAAK,IAAI,UAAU,KAAK,SAAS;AAAA,MACxC,SAAS,KAAK;AACZ,aAAK,kBAAkB;AACvB,YAAI,SAAS;AACX,kBAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAC3D,oBAAU;AAAA,QACZ;AACA;AAAA,MACF;AAEA,WAAK,GAAG,KAAK,QAAQ,MAAM;AACzB,aAAK,mBAAmB;AACxB,aAAK,OAAO,KAAK,qBAAqB,KAAK,MAAM,EAAE;AAGnD,aAAK,KAAK,EAAE,MAAM,YAAY,MAAM,KAAK,iBAAiB,CAAC;AAG3D,aAAK,eAAe;AAEpB,mBAAW,KAAK,KAAK,gBAAiB,GAAE;AAExC,YAAI,WAAW;AACb,oBAAU;AACV,sBAAY;AAAA,QACd;AAAA,MACF,CAAC;AAED,WAAK,GAAG,GAAG,WAAW,CAAC,MAAuB,aAAsB;AAClE,cAAM,MAAM,OAAO,SAAS,IAAI,IAAI,OAAO,OAAO,KAAK,IAA8B;AACrF,YAAI,UAAU;AACZ,qBAAW,KAAK,KAAK,eAAgB,GAAE,GAAG;AAAA,QAC5C,OAAO;AACL,cAAI;AACF,kBAAM,MAAM,KAAK,MAAM,IAAI,SAAS,CAAC;AACrC,iBAAK,qBAAqB,GAAG;AAC7B,uBAAW,KAAK,KAAK,gBAAiB,GAAE,GAAG;AAAA,UAC7C,QAAQ;AACN,iBAAK,OAAO,KAAK,kCAAkC;AAAA,UACrD;AAAA,QACF;AAAA,MACF,CAAC;AAED,WAAK,GAAG,KAAK,SAAS,MAAM;AAC1B,aAAK,cAAc;AACnB,mBAAW,KAAK,KAAK,mBAAoB,GAAE;AAC3C,YAAI,CAAC,KAAK,WAAW;AACnB,eAAK,OAAO,KAAK,6CAA6C;AAC9D,eAAK,kBAAkB;AAAA,QACzB;AAAA,MACF,CAAC;AAED,WAAK,GAAG,KAAK,SAAS,CAAC,QAAQ;AAC7B,aAAK,OAAO,MAAM,mBAAmB,EAAE,SAAS,IAAI,QAAQ,CAAC;AAC7D,YAAI,SAAS;AACX,kBAAQ,GAAG;AACX,oBAAU;AAAA,QACZ;AAAA,MACF,CAAC;AAAA,IACH,CAAC,EAAE,MAAM,CAAC,QAAQ;AAChB,WAAK,OAAO,MAAM,8BAA8B,EAAE,SAAS,OAAO,GAAG,EAAE,CAAC;AACxE,UAAI,SAAS;AACX,gBAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC;AAAA,MAC7D;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,qBAAqB,KAA8B;AACzD,QAAI,IAAI,SAAS,QAAQ;AACvB,WAAK,KAAK,EAAE,MAAM,OAAO,CAAC;AAAA,IAC5B;AAAA,EACF;AAAA,EAEQ,oBAA0B;AAChC,QAAI,KAAK,UAAW;AACpB,UAAM,QAAQ,KAAK;AAAA,MACjB,oBAAoB,KAAK,IAAI,GAAG,KAAK,gBAAgB;AAAA,MACrD;AAAA,IACF;AACA,SAAK;AACL,SAAK,OAAO,KAAK,mBAAmB,KAAK,eAAe,KAAK,gBAAgB,GAAG;AAChF,SAAK,iBAAiB,WAAW,MAAM;AACrC,WAAK,UAAU;AAAA,IACjB,GAAG,KAAK;AAAA,EACV;AAAA,EAEQ,iBAAuB;AAC7B,SAAK,cAAc;AACnB,SAAK,iBAAiB,YAAY,MAAM;AACtC,WAAK,KAAK,EAAE,MAAM,aAAa,QAAQ,KAAK,cAAc,CAAC;AAAA,IAC7D,GAAG,qBAAqB;AAAA,EAC1B;AAAA,EAEQ,gBAAsB;AAC5B,QAAI,KAAK,gBAAgB;AACvB,oBAAc,KAAK,cAAc;AACjC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,cAAoB;AAC1B,SAAK,cAAc;AACnB,QAAI,KAAK,gBAAgB;AACvB,mBAAa,KAAK,cAAc;AAChC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AACF;;;AC7OO,IAAM,kBAAN,MAAsB;AAAA,EAK3B,YACmB,SACA,QACjB,QACA;AAHiB;AACA;AAGjB,SAAK,SAAS,OAAO,MAAM,YAAY;AAAA,EACzC;AAAA,EAViB,WAAW,oBAAI,IAA0B;AAAA,EACzC,eAAe,oBAAI,IAAyB;AAAA,EAC5C;AAAA;AAAA,EAWjB,gBAAgB,SAA6B;AAC3C,QAAI,KAAK,SAAS,IAAI,QAAQ,QAAQ,GAAG;AACvC,WAAK,OAAO,KAAK,sCAAsC,QAAQ,QAAQ,EAAE;AAAA,IAC3E;AACA,SAAK,SAAS,IAAI,QAAQ,UAAU,OAAO;AAC3C,SAAK,OAAO,MAAM,uBAAuB,QAAQ,QAAQ,EAAE;AAAA,EAC7D;AAAA;AAAA,EAGA,kBAAkB,UAAwB;AACxC,SAAK,SAAS,OAAO,QAAQ;AAAA,EAC/B;AAAA;AAAA,EAGA,eAAkC;AAChC,WAAO,CAAC,GAAG,KAAK,SAAS,KAAK,CAAC;AAAA,EACjC;AAAA;AAAA,EAGA,WAAW,UAA4C;AACrD,WAAO,KAAK,SAAS,IAAI,QAAQ;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAY,QAAgB,UAAkB,SAAiC;AACnF,UAAM,UAAU,KAAK,SAAS,IAAI,QAAQ;AAC1C,QAAI,CAAC,SAAS;AACZ,WAAK,OAAO,KAAK;AAAA,QACf,MAAM;AAAA,QACN;AAAA,QACA,SAAS;AAAA,QACT,OAAO,wCAAwC,QAAQ;AAAA,MACzD,CAAC;AACD;AAAA,IACF;AAEA,UAAM,cAA2B,EAAE,QAAQ,UAAU,WAAW,MAAM;AACtE,SAAK,aAAa,IAAI,QAAQ,WAAW;AAEzC,UAAM,UAAuB;AAAA,MAC3B;AAAA,MACA,SAAS,KAAK;AAAA,MACd,QAAQ,KAAK,OAAO,MAAM,QAAQ;AAAA,MAClC,gBAAgB,CAAC,aAA2B;AAC1C,aAAK,OAAO,KAAK,EAAE,MAAM,iBAAiB,QAAQ,SAAS,CAAC;AAAA,MAC9D;AAAA,MACA,aAAa,MAAM,YAAY;AAAA,IACjC;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,QAAQ,OAAO,SAAS,OAAO;AACpD,WAAK,aAAa,OAAO,MAAM;AAE/B,UAAI,CAAC,YAAY,WAAW;AAC1B,aAAK,OAAO,KAAK;AAAA,UACf,MAAM;AAAA,UACN;AAAA,UACA,SAAS;AAAA,UACT;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAK;AACZ,WAAK,aAAa,OAAO,MAAM;AAE/B,WAAK,OAAO,MAAM,QAAQ,QAAQ,KAAK,MAAM,YAAY;AAAA,QACvD,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MAC1D,CAAC;AAED,WAAK,OAAO,KAAK;AAAA,QACf,MAAM;AAAA,QACN;AAAA,QACA,SAAS;AAAA,QACT,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,WAAW,QAA+B;AAC9C,UAAM,UAAU,KAAK,aAAa,IAAI,MAAM;AAC5C,QAAI,CAAC,QAAS;AAEd,YAAQ,YAAY;AAEpB,UAAM,UAAU,KAAK,SAAS,IAAI,QAAQ,QAAQ;AAClD,QAAI,SAAS,QAAQ;AACnB,UAAI;AACF,cAAM,QAAQ,OAAO;AAAA,MACvB,SAAS,KAAK;AACZ,aAAK,OAAO,MAAM,yBAAyB,MAAM,IAAI;AAAA,UACnD,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QAC1D,CAAC;AAAA,MACH;AAAA,IACF;AAEA,SAAK,aAAa,OAAO,MAAM;AAAA,EACjC;AAAA;AAAA,EAGA,IAAI,kBAA0B;AAC5B,WAAO,KAAK,aAAa;AAAA,EAC3B;AAAA;AAAA,EAGA,MAAM,UAAyB;AAC7B,UAAM,UAAU,CAAC,GAAG,KAAK,aAAa,KAAK,CAAC;AAC5C,eAAW,UAAU,SAAS;AAC5B,YAAM,KAAK,WAAW,MAAM;AAAA,IAC9B;AACA,SAAK,SAAS,MAAM;AAAA,EACtB;AACF;;;ACxIO,IAAM,oBAAN,MAAgD;AAAA,EAC5C,WAAW;AAAA,EACX,cAAc;AAAA,EAEvB,MAAM,OAAO,SAAkB,SAAwC;AACrE,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,SAAS;AAEf,QAAI,CAAC,OAAO,YAAY,CAAC,OAAO,SAAS;AACvC,YAAM,IAAI,MAAM,0DAA0D;AAAA,IAC5E;AAEA,WAAO,KAAK,+BAA+B,OAAO,QAAQ,QAAQ,OAAO,OAAO,QAAQ,OAAO,OAAO,CAAC,EAAE;AAIzG,WAAO,EAAE,QAAQ,WAAW,UAAU,OAAO,SAAS;AAAA,EACxD;AAAA,EAEA,MAAM,SAAwB;AAAA,EAE9B;AACF;AAOO,IAAM,oBAAN,MAAgD;AAAA,EAC5C,WAAW;AAAA,EACX,cAAc;AAAA,EAEvB,MAAM,OAAO,SAAkB,SAAwC;AACrE,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,SAAS;AAOf,QAAI,CAAC,OAAO,UAAU;AACpB,YAAM,IAAI,MAAM,8CAA8C;AAAA,IAChE;AAEA,WAAO,KAAK,+BAA+B,OAAO,QAAQ,UAAU,OAAO,WAAW,SAAS,YAAY,OAAO,WAAW,MAAM,EAAE;AAIrI,WAAO,EAAE,QAAQ,WAAW,UAAU,OAAO,SAAS;AAAA,EACxD;AAAA,EAEA,MAAM,SAAwB;AAAA,EAE9B;AACF;AAOO,IAAM,oBAAN,MAAgD;AAAA,EAC5C,WAAW;AAAA,EACX,cAAc;AAAA,EAEvB,MAAM,OAAO,SAAkB,SAAwC;AACrE,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,SAAS;AAEf,QAAI,CAAC,OAAO,YAAY,CAAC,OAAO,SAAS;AACvC,YAAM,IAAI,MAAM,0DAA0D;AAAA,IAC5E;AAEA,WAAO,KAAK,+BAA+B,OAAO,QAAQ,QAAQ,OAAO,OAAO,EAAE;AAGlF,WAAO,EAAE,QAAQ,WAAW,UAAU,OAAO,SAAS;AAAA,EACxD;AAAA,EAEA,MAAM,SAAwB;AAAA,EAE9B;AACF;;;AC3FA,SAAS,cAAAC,mBAAkB;AAc3B,IAAM,oBAA6E;AAAA,EACjF,SAAS,CAAC,YAAY,UAAU;AAAA,EAChC,UAAU,CAAC,WAAW,SAAS,UAAU;AAAA,EACzC,SAAS,CAAC,YAAY,OAAO;AAAA,EAC7B,UAAU,CAAC,WAAW,OAAO;AAAA,EAC7B,OAAO,CAAC,YAAY,WAAW,UAAU;AAAA,EACzC,UAAU,CAAC,SAAS;AACtB;AAEO,IAAM,wBAAN,MAA4B;AAAA,EAQjC,YACmB,WACA,aACA,UACA,QACjB;AAJiB;AACA;AACA;AACA;AAAA,EAChB;AAAA,EAZK,SAAuB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAS1B,IAAI,QAAsB;AACxB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,YAA2B;AACzB,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK;AAAA,MAChB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,QACE,KAAK,WAAW,aAAa,KAAK,aAC9B,KAAK,IAAI,IAAI,KAAK,aAClB;AAAA,IACR;AAAA,EACF;AAAA,EAEA,WAAW,IAAkB,OAAyB;AACpD,UAAM,OAAO,KAAK;AAElB,QAAI,CAAC,KAAK,kBAAkB,MAAM,EAAE,GAAG;AACrC,WAAK,OAAO,KAAK,6BAA6B,IAAI,WAAM,EAAE,EAAE;AAC5D,aAAO;AAAA,IACT;AAEA,SAAK,SAAS;AACd,SAAK,SAAS;AAEd,QAAI,OAAO,WAAW;AACpB,UAAI,KAAK,iBAAiB;AACxB,aAAK;AAAA,MACP;AACA,WAAK,kBAAkB;AACvB,WAAK,aAAa,KAAK,IAAI;AAC3B,WAAK,aAAa;AAAA,IACpB;AAEA,QAAI,OAAO,aAAa,OAAO,WAAW,OAAO,YAAY;AAC3D,WAAK,aAAa,KAAK,IAAI;AAAA,IAC7B;AAEA,SAAK,OAAO,KAAK,UAAU,IAAI,WAAM,EAAE,GAAG,QAAQ,KAAK,KAAK,MAAM,EAAE,EAAE;AAEtE,SAAK,SAAS,KAAK;AAAA,MACjB,IAAIA,YAAW;AAAA,MACf,WAAW,oBAAI,KAAK;AAAA,MACpB,QAAQ,EAAE,MAAM,KAAK,aAAa,IAAI,KAAK,UAAU;AAAA,MACrD,UAAU,GAAG,KAAK,WAAW,UAAU,EAAE;AAAA,MACzC,MAAM,EAAE,MAAM,IAAI,OAAO,WAAW,KAAK,UAAU;AAAA,IACrD,CAAC;AAED,WAAO;AAAA,EACT;AAAA,EAEA,wBAA8B;AAC5B,SAAK;AAAA,EACP;AAAA,EAEQ,kBAAkB,MAAoB,IAA2B;AACvE,WAAO,kBAAkB,IAAI,GAAG,SAAS,EAAE,KAAK;AAAA,EAClD;AACF;;;AC5FO,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YAA6B,cAAmC;AAAnC;AAAA,EAAoC;AAAA,EAEjE,UAAU,MAA4B;AACpC,WAAO,KAAK,aAAa,SAAS,IAAI;AAAA,EACxC;AAAA,EAEA,cAA+B;AAC7B,WAAO,EAAE,GAAG,KAAK,aAAa,SAAS;AAAA,EACzC;AACF;;;ACJA,IAAM,kBAAN,MAAsB;AAAA,EAKpB,YAA6B,UAAkB;AAAlB;AAC3B,SAAK,SAAS,IAAI,MAAM,QAAQ;AAAA,EAClC;AAAA,EANiB;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EAMhB,KAAK,OAA0B;AAC7B,SAAK,OAAO,KAAK,IAAI,IAAI;AACzB,SAAK,QAAQ,KAAK,OAAO,KAAK,KAAK;AACnC,QAAI,KAAK,QAAQ,KAAK,UAAU;AAC9B,WAAK;AAAA,IACP;AAAA,EACF;AAAA,EAEA,SAAiC;AAC/B,UAAM,SAAwB,CAAC;AAC/B,aAAS,IAAI,GAAG,IAAI,KAAK,OAAO,KAAK;AACnC,YAAM,SAAS,KAAK,OAAO,IAAI,IAAI,KAAK,YAAY,KAAK;AACzD,aAAO,KAAK,KAAK,OAAO,KAAK,CAAE;AAAA,IACjC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAsB,OAAwC;AAClE,QAAI,SAAS,CAAC,GAAG,KAAK,OAAO,CAAC;AAE9B,QAAI,QAAQ;AACV,eAAS,OAAO,OAAO,CAAC,UAAU,cAAc,OAAO,MAAM,CAAC;AAAA,IAChE;AAEA,QAAI,UAAU,UAAa,QAAQ,GAAG;AACpC,aAAO,OAAO,MAAM,GAAG,KAAK;AAAA,IAC9B;AAEA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,gBAAgB,eAAuB,gBAAiC;AAC/E,MAAI,eAAe,SAAS,IAAI,GAAG;AACjC,UAAM,SAAS,eAAe,MAAM,GAAG,EAAE;AACzC,WAAO,cAAc,WAAW,SAAS,GAAG,KAAK,kBAAkB;AAAA,EACrE;AACA,SAAO,kBAAkB;AAC3B;AAEA,SAAS,cAAc,OAAoB,QAA8B;AACvE,MAAI,OAAO,YAAY,CAAC,gBAAgB,MAAM,UAAU,OAAO,QAAQ,GAAG;AACxE,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,QAAQ;AACjB,QAAI,MAAM,OAAO,SAAS,OAAO,OAAO,QAAQ,MAAM,OAAO,OAAO,OAAO,OAAO,IAAI;AACpF,aAAO;AAAA,IACT;AAAA,EACF;AAEA,MAAI,OAAO,SAAS,MAAM,YAAY,OAAO,OAAO;AAClD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,IAAM,iBAAN,MAA0C;AAAA,EAC9B;AAAA,EACA,cAA4B,CAAC;AAAA,EAE9C,YAAY,aAAqB,KAAO;AACtC,SAAK,aAAa,IAAI,gBAAgB,UAAU;AAAA,EAClD;AAAA,EAEA,KAAK,OAA0B;AAC7B,SAAK,WAAW,KAAK,KAAK;AAE1B,eAAW,cAAc,KAAK,aAAa;AACzC,UAAI,cAAc,OAAO,WAAW,MAAM,GAAG;AAC3C,mBAAW,SAAS,KAAK;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAAA,EAEA,UAAU,QAAqB,SAAmD;AAChF,UAAM,aAAyB,EAAE,QAAQ,UAAU,QAAQ;AAC3D,SAAK,YAAY,KAAK,UAAU;AAEhC,WAAO,MAAM;AACX,YAAM,QAAQ,KAAK,YAAY,QAAQ,UAAU;AACjD,UAAI,UAAU,IAAI;AAChB,aAAK,YAAY,OAAO,OAAO,CAAC;AAAA,MAClC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,UAAU,QAAsB,OAAwC;AACtE,WAAO,KAAK,WAAW,MAAM,QAAQ,KAAK;AAAA,EAC5C;AACF;;;AC9GO,IAAM,gBAAN,MAAoB;AAAA,EAKzB,YAA6B,WAAmB,KAAO;AAA1B;AAC3B,SAAK,SAAS,IAAI,MAAM,QAAQ;AAAA,EAClC;AAAA,EANiB;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EAMhB,KAAK,OAAuB;AAC1B,SAAK,OAAO,KAAK,IAAI,IAAI;AACzB,SAAK,QAAQ,KAAK,OAAO,KAAK,KAAK;AACnC,QAAI,KAAK,QAAQ,KAAK,UAAU;AAC9B,WAAK;AAAA,IACP;AAAA,EACF;AAAA,EAEA,SAAqB;AACnB,UAAM,SAAqB,CAAC;AAE5B,aAAS,IAAI,GAAG,IAAI,KAAK,OAAO,KAAK;AACnC,YAAM,SAAS,KAAK,OAAO,IAAI,IAAI,KAAK,YAAY,KAAK;AACzD,aAAO,KAAK,KAAK,OAAO,KAAK,CAAE;AAAA,IACjC;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAA+B;AACnC,UAAM,MAAM,KAAK,OAAO;AACxB,QAAI,SAAS;AAEb,QAAI,OAAO,SAAS,OAAO,MAAM,SAAS,GAAG;AAC3C,eAAS,OAAO,OAAO,CAAC,UAAU;AAChC,iBAAS,IAAI,GAAG,IAAI,OAAO,MAAO,QAAQ,KAAK;AAC7C,cAAI,MAAM,MAAM,CAAC,MAAM,OAAO,MAAO,CAAC,EAAG,QAAO;AAAA,QAClD;AACA,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAEA,QAAI,OAAO,OAAO;AAChB,eAAS,OAAO,OAAO,CAAC,UAAU,MAAM,UAAU,OAAO,KAAK;AAAA,IAChE;AAEA,QAAI,OAAO,OAAO;AAChB,eAAS,OAAO,OAAO,CAAC,UAAU,MAAM,aAAa,OAAO,KAAM;AAAA,IACpE;AAEA,QAAI,OAAO,OAAO;AAChB,eAAS,OAAO,OAAO,CAAC,UAAU,MAAM,aAAa,OAAO,KAAM;AAAA,IACpE;AAEA,QAAI,OAAO,UAAU,UAAa,OAAO,QAAQ,GAAG;AAClD,eAAS,OAAO,MAAM,GAAG,OAAO,KAAK;AAAA,IACvC;AAEA,WAAO;AAAA,EACT;AACF;;;AC1DO,IAAM,eAAN,MAAM,cAAsC;AAAA,EACjD,YACmB,OACA,SACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAEH,MAAM,SAAiB,MAAsC;AAC3D,SAAK,MAAM,SAAS,SAAS,IAAI;AAAA,EACnC;AAAA,EAEA,KAAK,SAAiB,MAAsC;AAC1D,SAAK,MAAM,QAAQ,SAAS,IAAI;AAAA,EAClC;AAAA,EAEA,KAAK,SAAiB,MAAsC;AAC1D,SAAK,MAAM,QAAQ,SAAS,IAAI;AAAA,EAClC;AAAA,EAEA,MAAM,SAAiB,MAAsC;AAC3D,SAAK,MAAM,SAAS,SAAS,IAAI;AAAA,EACnC;AAAA,EAEA,MAAM,YAAmC;AACvC,WAAO,IAAI,cAAa,CAAC,GAAG,KAAK,OAAO,UAAU,GAAG,KAAK,OAAO;AAAA,EACnE;AAAA,EAEQ,MAAM,OAAiB,SAAiB,MAAsC;AACpF,UAAM,QAAkB;AAAA,MACtB,WAAW,oBAAI,KAAK;AAAA,MACpB;AAAA,MACA,OAAO,KAAK;AAAA,MACZ;AAAA,MACA,GAAI,SAAS,SAAY,EAAE,KAAK,IAAI,CAAC;AAAA,IACvC;AACA,SAAK,QAAQ,KAAK;AAAA,EACpB;AACF;;;AC/BO,IAAM,aAAN,MAAiB;AAAA,EACL;AAAA,EACA,eAAkC,CAAC;AAAA,EACnC,cAAc,oBAAI,IAAiF;AAAA,EAEpH,YAAY,aAAqB,KAAO;AACtC,SAAK,aAAa,IAAI,cAAc,UAAU;AAAA,EAChD;AAAA,EAEA,aAAa,OAA8B;AACzC,WAAO,IAAI,aAAa,CAAC,KAAK,GAAG,CAAC,UAAoB;AACpD,WAAK,WAAW,KAAK,KAAK;AAC1B,iBAAW,QAAQ,KAAK,cAAc;AACpC,aAAK,MAAM,KAAK;AAAA,MAClB;AAEA,iBAAW,CAAC,EAAE,GAAG,KAAK,KAAK,aAAa;AACtC,YAAI,KAAK,cAAc,OAAO,IAAI,MAAM,GAAG;AACzC,cAAI;AAAE,gBAAI,SAAS,KAAK;AAAA,UAAE,QAAQ;AAAA,UAAkC;AAAA,QACtE;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,UAAU,QAA4B,UAAiD;AACrF,UAAM,KAAK,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC;AAC7C,SAAK,YAAY,IAAI,IAAI,EAAE,QAAQ,SAAS,CAAC;AAC7C,WAAO,MAAM;AAAE,WAAK,YAAY,OAAO,EAAE;AAAA,IAAE;AAAA,EAC7C;AAAA,EAEQ,cAAc,OAAiB,QAAqC;AAC1E,QAAI,OAAO,SAAS,OAAO,MAAM,SAAS,GAAG;AAC3C,YAAM,aAAa,MAAM,QAAQ,CAAC,KAAK;AACvC,UAAI,CAAC,OAAO,MAAM,KAAK,OAAK,eAAe,KAAK,WAAW,WAAW,CAAC,CAAC,EAAG,QAAO;AAAA,IACpF;AACA,QAAI,OAAO,OAAO;AAChB,YAAM,SAAmB,CAAC,SAAS,QAAQ,QAAQ,OAAO;AAC1D,YAAM,SAAS,OAAO,QAAQ,OAAO,KAAK;AAC1C,YAAM,WAAW,OAAO,QAAQ,MAAM,KAAK;AAC3C,UAAI,WAAW,OAAQ,QAAO;AAAA,IAChC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,MAA6B;AAC1C,SAAK,aAAa,KAAK,IAAI;AAAA,EAC7B;AAAA,EAEA,kBAAkB,MAA6B;AAC7C,UAAM,QAAQ,KAAK,aAAa,QAAQ,IAAI;AAC5C,QAAI,UAAU,IAAI;AAChB,WAAK,aAAa,OAAO,OAAO,CAAC;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,MAAM,QAA+B;AACnC,WAAO,KAAK,WAAW,MAAM,MAAM;AAAA,EACrC;AACF;;;ACrEA,YAAYC,SAAQ;AACpB,YAAYC,WAAU;AA8Df,IAAM,iBAAN,MAAqB;AAAA,EAClB,iBAA0C;AAAA,EAC1C,kBAAiD;AAAA,EACjD,qBAAiD;AAAA,EACjD,kBAA2C;AAAA;AAAA,EAGnD,YAAY,UAAwD;AAElE,QAAI,iBAAiB,YAAY,OAAQ,SAAiB,gBAAgB,YAAY;AACpF,WAAK,iBAAiB;AAAA,IACxB,OAAO;AACL,WAAK,qBAAqB;AAAA,IAC5B;AAAA,EACF;AAAA,EAEA,sBAAsB,UAAqC;AACzD,SAAK,qBAAqB;AAAA,EAC5B;AAAA,EAEA,mBAAmB,SAAiC;AAClD,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEA,cAAgC;AAC9B,QAAI,KAAK,eAAgB,QAAO,KAAK;AACrC,QAAI,CAAC,KAAK,sBAAsB,CAAC,KAAK,mBAAmB,CAAC,KAAK,iBAAiB;AAC9E,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAEA,WAAO,KAAK,iBAAiB;AAAA,EAC/B;AAAA,EAEA,mBAAmB,SAAuC;AACxD,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEA,qBAA6C;AAC3C,QAAI,CAAC,KAAK,iBAAiB;AACzB,YAAM,IAAI,MAAM,wCAAwC;AAAA,IAC1D;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,oBAAoB,UAAiC;AACzD,UAAM,EAAE,wBAAAC,wBAAuB,IAAI,MAAM,OAAO,yCAA+B;AAC/E,UAAM,UAAU,IAAIA,wBAAuB,QAAQ;AACnD,UAAM,QAAQ,mBAAmB;AACjC,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEA,gBAAgB,MAAmC;AACjD,WAAO,KAAK,mBAAmB,EAAE,WAAW,IAAI,EAAE;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,MAAoC,WAAsC;AACpF,QAAI,CAAC,KAAK,kBAAkB,CAAC,KAAK,sBAAsB,CAAC,KAAK,mBAAmB,CAAC,KAAK,iBAAiB;AACtG,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAEA,QAAI,KAAK,gBAAgB;AACvB,UAAI;AACF,cAAM,aAAqC,EAAE,QAAQ,QAAQ,QAAQ,QAAQ,OAAO,OAAO;AAC3F,cAAM,aAAc,WAAW,IAAI,KAAK;AACxC,cAAMC,YAAW,KAAK,eAAe,YAAY,UAAU;AAC3D,eAAO,YAAY,KAAK,yBAAyBA,WAAU,SAAS,IAAIA;AAAA,MAC1E,QAAQ;AAAA,MAER;AAAA,IACF;AAGA,UAAM,WAA6B,CAAC;AAGpC,QAAI,KAAK,iBAAiB;AACxB,YAAM,UAAU,KAAK;AACrB,eAAS,aAAa;AAAA,QACpB,MAAM,MAAM,YAAoB,QAAsB;AACpD,gBAAM,UAAU,MAAM,QAAQ,MAAM,YAAmB,MAAM;AAC7D,iBAAO,QAAQ,IAAI,QAAM,EAAE,YAAY,IAAI,EAAE,IAAI,MAAM,EAAE,KAAK,EAAE;AAAA,QAClE;AAAA,QACA,MAAM,OAAO,QAAuB;AAClC,gBAAM,KAAK,OAAO,OAAO,MAAM,OAAO,QAAa,GAAG,WAAW;AACjE,gBAAM,QAAQ,OAAO,OAAO,YAAmB,EAAE,IAAI,MAAM,OAAO,KAAK,CAAC;AACxE,iBAAO,EAAE,GAAG,QAAQ,GAAG;AAAA,QACzB;AAAA,QACA,MAAM,OAAO,YAAoB,IAAY,MAA+B;AAC1E,gBAAM,QAAQ,OAAO,YAAmB,IAAI,IAAI;AAChD,iBAAO,EAAE,YAAY,IAAI,KAAK;AAAA,QAChC;AAAA,QACA,MAAM,OAAO,YAAoB,IAAY;AAC3C,gBAAM,QAAQ,OAAO,YAAmB,EAAE;AAAA,QAC5C;AAAA,QACA,MAAM,MAAM,YAAoB,QAAsB;AACpD,iBAAO,QAAQ,MAAM,YAAmB,MAAM;AAAA,QAChD;AAAA,MACF;AAAA,IACF;AAGA,QAAI,KAAK,iBAAiB;AACxB,YAAM,aAAqC,EAAE,QAAQ,QAAQ,QAAQ,QAAQ,OAAO,OAAO;AAC3F,YAAM,aAAc,WAAW,IAAI,KAAK;AACxC,UAAI;AACF,cAAM,WAAW,KAAK,gBAAgB,WAAW,UAAU,EAAE;AAC7D,iBAAS,QAAQ;AAAA,UACf,MAAM,SAAS,GAAW;AAAE,mBAAU,aAAS,SAAc,WAAK,UAAU,CAAC,CAAC;AAAA,UAAE;AAAA,UAChF,MAAM,UAAU,GAAW,MAAc;AACvC,kBAAM,OAAY,WAAK,UAAU,CAAC;AAClC,kBAAS,aAAS,MAAW,cAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC/D,kBAAS,aAAS,UAAU,MAAM,IAAI;AAAA,UACxC;AAAA,UACA,MAAM,WAAW,GAAW;AAAE,kBAAS,aAAS,GAAQ,WAAK,UAAU,CAAC,GAAG,EAAE,OAAO,KAAK,CAAC;AAAA,UAAE;AAAA,UAC5F,MAAM,UAAU,QAAiB;AAC/B,kBAAM,MAAM,SAAc,WAAK,UAAU,MAAM,IAAI;AACnD,gBAAI;AAAE,sBAAQ,MAAS,aAAS,QAAQ,GAAG,GAAG,IAAI,OAAK,SAAS,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC;AAAA,YAAE,QAAQ;AAAE,qBAAO,CAAC;AAAA,YAAE;AAAA,UAC5G;AAAA,UACA,MAAM,WAAW,GAAW;AAAE,mBAAY,WAAK,UAAU,CAAC;AAAA,UAAE;AAAA,UAC5D,MAAM,OAAO,GAAW;AAAE,gBAAI;AAAE,oBAAS,aAAS,OAAY,WAAK,UAAU,CAAC,CAAC;AAAG,qBAAO;AAAA,YAAK,QAAQ;AAAE,qBAAO;AAAA,YAAM;AAAA,UAAE;AAAA,QACzH;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,WAAO,YAAY,KAAK,yBAAyB,UAAU,SAAS,IAAI;AAAA,EAC1E;AAAA,EAEQ,mBAAqC;AAC3C,UAAM,OAAO;AACb,WAAO;AAAA,MACL,MAAM,aAAa;AAAA,MAAC;AAAA,MACpB,MAAM,WAAW;AAAA,MAAC;AAAA,MAClB,YAAY,MAA2B;AAAE,eAAO,KAAK,YAAY,IAAI;AAAA,MAAE;AAAA,IACzE;AAAA,EACF;AAAA,EAEQ,yBAAyB,UAA4B,WAAqC;AAChG,UAAM,SAAS,UAAU,SAAS,GAAG,IAAI,YAAY,GAAG,SAAS;AAEjE,WAAO;AAAA,MACL,YAAY,SAAS,aAAa;AAAA,QAChC,MAAM,MAAM,YAAoB,QAAsB;AACpD,iBAAO,SAAS,WAAY,MAAM,GAAG,MAAM,GAAG,UAAU,IAAI,MAAM;AAAA,QACpE;AAAA,QACA,MAAM,OAAO,QAAuB;AAClC,iBAAO,SAAS,WAAY,OAAO,EAAE,GAAG,QAAQ,YAAY,GAAG,MAAM,GAAG,OAAO,UAAU,GAAG,CAAC;AAAA,QAC/F;AAAA,QACA,MAAM,OAAO,YAAoB,IAAY,MAA+B;AAC1E,iBAAO,SAAS,WAAY,OAAO,GAAG,MAAM,GAAG,UAAU,IAAI,IAAI,IAAI;AAAA,QACvE;AAAA,QACA,MAAM,OAAO,YAAoB,IAAY;AAC3C,iBAAO,SAAS,WAAY,OAAO,GAAG,MAAM,GAAG,UAAU,IAAI,EAAE;AAAA,QACjE;AAAA,QACA,MAAM,MAAM,YAAoB,QAAsB;AACpD,iBAAO,SAAS,WAAY,MAAM,GAAG,MAAM,GAAG,UAAU,IAAI,MAAM;AAAA,QACpE;AAAA,MACF,IAAI;AAAA,MAEJ,OAAO,SAAS,QAAQ;AAAA,QACtB,MAAM,SAAS,GAAW;AAAE,iBAAO,SAAS,MAAO,SAAS,GAAG,MAAM,GAAG,CAAC,EAAE;AAAA,QAAE;AAAA,QAC7E,MAAM,UAAU,GAAW,MAAc;AAAE,iBAAO,SAAS,MAAO,UAAU,GAAG,MAAM,GAAG,CAAC,IAAI,IAAI;AAAA,QAAE;AAAA,QACnG,MAAM,WAAW,GAAW;AAAE,iBAAO,SAAS,MAAO,WAAW,GAAG,MAAM,GAAG,CAAC,EAAE;AAAA,QAAE;AAAA,QACjF,MAAM,UAAU,YAAqB;AAAE,iBAAO,SAAS,MAAO,UAAU,GAAG,MAAM,GAAG,cAAc,EAAE,EAAE;AAAA,QAAE;AAAA,QACxG,MAAM,WAAW,GAAW;AAAE,iBAAO,SAAS,MAAO,WAAW,GAAG,MAAM,GAAG,CAAC,EAAE;AAAA,QAAE;AAAA,QACjF,MAAM,OAAO,GAAW;AAAE,iBAAO,SAAS,MAAO,OAAO,GAAG,MAAM,GAAG,CAAC,EAAE;AAAA,QAAE;AAAA,MAC3E,IAAI;AAAA,IACN;AAAA,EACF;AACF;;;AC7OA,YAAY,SAAS;AACrB,YAAY,YAAY;AACxB,YAAY,YAAY;AAWjB,IAAM,cAAN,MAAkB;AAAA,EAIvB,YAA6B,QAA0B;AAA1B;AAC3B,UAAM,aAAa,KAAK,OAAO,IAAY,gBAAgB;AAC3D,QAAI,YAAY;AACd,WAAK,YAAY;AAAA,IACnB,OAAO;AACL,YAAM,SAAgB,mBAAY,EAAE,EAAE,SAAS,KAAK;AAEpD,WAAK,OAAO,OAAO,QAAQ,EAAE,WAAW,OAAO,CAAC;AAChD,cAAQ,IAAI,8EAA8E;AAC1F,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA,EAdiB;AAAA,EACT,qBAAgD;AAAA,EAexD,UAAU,SAAoD;AAC5D,WAAW,SAAK,EAAE,GAAG,QAAQ,GAAG,KAAK,WAAW,EAAE,WAAW,MAAM,CAAC;AAAA,EACtE;AAAA,EAEA,YAAY,OAA6B;AACvC,WAAW,WAAO,OAAO,KAAK,SAAS;AAAA,EACzC;AAAA,EAEA,MAAM,aAAa,UAAmC;AACpD,WAAc,YAAK,UAAU,EAAE;AAAA,EACjC;AAAA,EAEA,MAAM,gBAAgB,UAAkBC,OAAgC;AACtE,WAAc,eAAQ,UAAUA,KAAI;AAAA,EACtC;AAAA,EAEA,iBAAkE;AAChE,UAAM,QAAe,mBAAY,EAAE,EAAE,SAAS,KAAK;AACnD,UAAMA,QAAc,kBAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AACnE,UAAM,SAAS,MAAM,MAAM,GAAG,CAAC;AAC/B,WAAO,EAAE,OAAO,MAAAA,OAAM,OAAO;AAAA,EAC/B;AAAA,EAEA,eAAe,OAAe,YAA6B;AACzD,UAAMA,QAAc,kBAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AACnE,WAAOA,UAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,mBAAmB,MAIR;AACT,UAAM,UAAmC;AAAA,MACvC,QAAQ,KAAK;AAAA,MACb,UAAU,KAAK;AAAA,MACf,MAAM,KAAK,QAAQ;AAAA,MACnB,MAAM;AAAA,MACN,SAAS,KAAK;AAAA,MACd,kBAAkB;AAAA,MAClB,gBAAgB,CAAC;AAAA,IACnB;AACA,UAAM,YAAa,KAAK,aAAa;AACrC,WAAW,SAAK,SAAmB,KAAK,WAAW,EAAE,UAAU,CAAC;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,SAAmC;AACvD,SAAK,qBAAqB;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,oBAAoB,UAA+C;AACvE,QAAI,CAAC,KAAK,oBAAoB;AAC5B,aAAO;AAAA,IACT;AACA,WAAO,KAAK,mBAAmB,SAAS,QAAQ;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,wBACE,OACA,SACA,WACA,YACS;AACT,QAAI,CAAC,KAAK,oBAAoB;AAC5B,aAAO;AAAA,IACT;AACA,WAAO,KAAK,mBAAmB,aAAa,OAAO,SAAS,WAAW,UAAU;AAAA,EACnF;AACF;;;AChHA,YAAYC,aAAY;AAuBxB,IAAM,sBAAsB;AAMrB,IAAM,gBAAN,MAAoB;AAAA,EACzB,YACmB,eACA,MACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAEH,IAAY,aAAiC;AAC3C,WAAO,KAAK,cAAc,qBAAqB;AAAA,EACjD;AAAA,EAEA,MAAM,OAAO,OAA4E;AACvF,UAAM,EAAE,OAAO,MAAAC,OAAM,OAAO,IAAI,KAAK,KAAK,eAAe;AACzD,UAAM,MAAM,KAAK,IAAI;AAErB,UAAM,SAAuB;AAAA,MAC3B,IAAW,mBAAW;AAAA,MACtB,OAAO,MAAM;AAAA,MACb,MAAM,MAAM;AAAA,MACZ,kBAAkB,MAAM,oBAAoB;AAAA,MAC5C,gBAAgB,MAAM,kBAAkB,CAAC;AAAA,MACzC,WAAWA;AAAA,MACX,aAAa;AAAA,MACb,WAAW;AAAA,IACb;AAEA,UAAM,KAAK,WAAW,OAAO;AAAA,MAC3B,YAAY;AAAA,MACZ,IAAI,OAAO;AAAA,MACX,MAAM;AAAA,IACR,CAAC;AAED,WAAO,EAAE,QAAQ,MAAM;AAAA,EACzB;AAAA,EAEA,MAAM,cAAc,OAA6C;AAC/D,UAAM,UAAU,MAAM,KAAK,WAAW,MAAM,mBAAmB;AAE/D,eAAW,SAAS,SAAS;AAC3B,YAAM,SAAS,MAAM;AACrB,UAAI,KAAK,KAAK,eAAe,OAAO,OAAO,SAAS,GAAG;AACrD,cAAM,cAAuC;AAAA,UAC3C,GAAG;AAAA,UACH,YAAY,KAAK,IAAI;AAAA,QACvB;AACA,cAAM,KAAK,WAAW,OAAO,qBAAqB,OAAO,IAAI,WAAW;AACxE,eAAO,EAAE,GAAG,QAAQ,YAAY,YAAY,WAAqB;AAAA,MACnE;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAsD;AAC1D,UAAM,UAAU,MAAM,KAAK,WAAW,MAAM,mBAAmB;AAC/D,WAAO,QAAQ,IAAI,CAAC,MAAM;AACxB,YAAM,EAAE,WAAW,GAAG,KAAK,IAAI,EAAE;AACjC,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAO,IAA2B;AACtC,UAAM,KAAK,WAAW,OAAO,qBAAqB,EAAE;AAAA,EACtD;AAAA,EAEA,MAAM,SAAS,IAA0C;AACvD,UAAM,UAAU,MAAM,KAAK,WAAW,MAAM,qBAAqB;AAAA,MAC/D,OAAO,EAAE,GAAG;AAAA,IACd,CAAC;AAED,QAAI,QAAQ,WAAW,GAAG;AACxB,aAAO;AAAA,IACT;AAEA,WAAO,QAAQ,CAAC,EAAG;AAAA,EACrB;AACF;;;ACxGA,YAAYC,aAAY;AAiBxB,IAAM,mBAAmB;AAUlB,IAAM,cAAN,MAAkB;AAAA,EACvB,YACmB,eACA,MACA,QACjB;AAHiB;AACA;AACA;AAAA,EAChB;AAAA,EAEH,IAAY,aAAiC;AAC3C,WAAO,KAAK,cAAc,qBAAqB;AAAA,EACjD;AAAA,EAEA,MAAM,OAAO,OAA6C;AACxD,UAAM,WAAW,MAAM,KAAK,eAAe,MAAM,QAAQ;AACzD,QAAI,UAAU;AACZ,YAAM,IAAI,MAAM,uBAAuB,MAAM,QAAQ,kBAAkB;AAAA,IACzE;AAEA,UAAM,eAAe,MAAM,KAAK,KAAK,aAAa,MAAM,QAAQ;AAChE,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,SAAqB;AAAA,MACzB,IAAW,mBAAW;AAAA,MACtB,UAAU,MAAM;AAAA,MAChB;AAAA,MACA,MAAM,MAAM;AAAA,MACZ,kBAAkB,MAAM,oBAAoB;AAAA,MAC5C,gBAAgB,MAAM,kBAAkB,CAAC;AAAA,MACzC,WAAW;AAAA,MACX,WAAW;AAAA,IACb;AAEA,UAAM,KAAK,WAAW,OAAO;AAAA,MAC3B,YAAY;AAAA,MACZ,IAAI,OAAO;AAAA,MACX,MAAM;AAAA,IACR,CAAC;AAED,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,eAAe,UAA8C;AACjE,UAAM,UAAU,MAAM,KAAK,WAAW,MAAM,kBAAkB;AAAA,MAC5D,OAAO,EAAE,SAAS;AAAA,IACpB,CAAC;AAED,QAAI,QAAQ,WAAW,GAAG;AACxB,aAAO;AAAA,IACT;AAEA,WAAO,QAAQ,CAAC,EAAG;AAAA,EACrB;AAAA,EAEA,MAAM,SAAS,IAAwC;AACrD,UAAM,UAAU,MAAM,KAAK,WAAW,MAAM,kBAAkB;AAAA,MAC5D,OAAO,EAAE,GAAG;AAAA,IACd,CAAC;AAED,QAAI,QAAQ,WAAW,GAAG;AACxB,aAAO;AAAA,IACT;AAEA,WAAO,QAAQ,CAAC,EAAG;AAAA,EACrB;AAAA,EAEA,MAAM,oBAAoB,UAAkB,UAA8C;AACxF,UAAM,OAAO,MAAM,KAAK,eAAe,QAAQ;AAC/C,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,IACT;AAEA,UAAM,QAAQ,MAAM,KAAK,KAAK,gBAAgB,UAAU,KAAK,YAAY;AACzE,WAAO,QAAQ,OAAO;AAAA,EACxB;AAAA,EAEA,MAAM,UAAuD;AAC3D,UAAM,UAAU,MAAM,KAAK,WAAW,MAAM,gBAAgB;AAC5D,WAAO,QAAQ,IAAI,CAAC,MAAM;AACxB,YAAM,EAAE,cAAc,GAAG,KAAK,IAAI,EAAE;AACpC,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAO,IAAY,MAA0C;AACjE,UAAM,WAAW,MAAM,KAAK,SAAS,EAAE;AACvC,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,iBAAiB,EAAE,aAAa;AAAA,IAClD;AAEA,UAAM,cAAuC;AAAA,MAC3C,GAAG;AAAA,MACH,GAAG;AAAA,MACH,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,UAAM,KAAK,WAAW,OAAO,kBAAkB,IAAI,WAAW;AAAA,EAChE;AAAA,EAEA,MAAM,OAAO,IAA2B;AACtC,UAAM,KAAK,WAAW,OAAO,kBAAkB,EAAE;AAAA,EACnD;AAAA,EAEA,MAAM,cAAc,IAAY,aAAoC;AAClE,UAAM,WAAW,MAAM,KAAK,SAAS,EAAE;AACvC,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,iBAAiB,EAAE,aAAa;AAAA,IAClD;AAEA,UAAM,eAAe,MAAM,KAAK,KAAK,aAAa,WAAW;AAC7D,UAAM,cAAuC;AAAA,MAC3C,GAAG;AAAA,MACH;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,UAAM,KAAK,WAAW,OAAO,kBAAkB,IAAI,WAAW;AAAA,EAChE;AAAA,EAEA,MAAM,oBAAmC;AACvC,UAAM,gBAAgB,KAAK,OAAO,IAAY,oBAAoB;AAClE,UAAM,gBAAgB,KAAK,OAAO,IAAY,oBAAoB;AAElE,QAAI,CAAC,iBAAiB,CAAC,eAAe;AACpC;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,KAAK,eAAe,aAAa;AACxD,QAAI,UAAU;AACZ;AAAA,IACF;AAEA,UAAM,KAAK,OAAO;AAAA,MAChB,UAAU;AAAA,MACV,UAAU;AAAA,MACV,MAAM;AAAA,MACN,kBAAkB;AAAA,MAClB,gBAAgB,CAAC;AAAA,IACnB,CAAC;AAAA,EACH;AACF;;;ACpKA,YAAYC,aAAY;AAIxB,IAAM,oBAAoB;AAC1B,IAAM,eAAe;AAMd,IAAM,qBAAN,MAAyB;AAAA,EAC9B,YAA6B,SAA6B;AAA7B;AAAA,EAA8B;AAAA;AAAA;AAAA;AAAA;AAAA,EAM3D,MAAM,OACJ,QACA,MACA,QACA,WACiD;AACjD,UAAM,SAAgB,oBAAY,EAAE,EAAE,SAAS,KAAK;AACpD,UAAM,WAAW,GAAG,YAAY,GAAG,MAAM;AACzC,UAAM,YAAmB,mBAAW,QAAQ,EAAE,OAAO,QAAQ,EAAE,OAAO,KAAK;AAC3E,UAAM,cAAc,SAAS,MAAM,GAAG,EAAE;AAExC,UAAM,SAAsB;AAAA,MAC1B,IAAW,mBAAW;AAAA,MACtB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,OAAO,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE;AAAA,MACpC;AAAA,MACA,YAAY;AAAA,MACZ,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,UAAM,KAAK,QAAQ,OAAO;AAAA,MACxB,YAAY;AAAA,MACZ,IAAI,OAAO;AAAA,MACX,MAAM;AAAA,IACR,CAAC;AAED,WAAO,EAAE,OAAO,UAAU,OAAO;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,UAA+C;AAC5D,QAAI,CAAC,SAAS,WAAW,YAAY,GAAG;AACtC,aAAO;AAAA,IACT;AAEA,UAAM,YAAmB,mBAAW,QAAQ,EAAE,OAAO,QAAQ,EAAE,OAAO,KAAK;AAC3E,UAAM,UAAU,MAAM,KAAK,QAAQ,MAAM,mBAAmB;AAAA,MAC1D,OAAO,EAAE,UAAU;AAAA,IACrB,CAAC;AAED,QAAI,QAAQ,WAAW,GAAG;AACxB,aAAO;AAAA,IACT;AAEA,UAAM,SAAS,QAAQ,CAAC,EAAG;AAC3B,QAAI,OAAO,cAAc,UAAa,OAAO,cAAc,QAAQ,KAAK,IAAI,IAAI,OAAO,WAAW;AAChG,aAAO;AAAA,IACT;AAGA,SAAK,eAAe,OAAO,EAAE,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAE7C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,aACE,OACA,SACA,WACA,YACS;AACT,eAAW,SAAS,MAAM,QAAQ;AAChC,cAAQ,MAAM,MAAM;AAAA,QAClB,KAAK;AACH,cAAI,WAAW,MAAM,WAAW,QAAS,QAAO;AAChD;AAAA,QACF,KAAK;AACH,cAAI,aAAa,UAAU,WAAW,MAAM,MAAM,EAAG,QAAO;AAC5D;AAAA,QACF,KAAK;AACH,cAAI,cAAc,MAAM,WAAW,WAAY,QAAO;AACtD;AAAA,MACJ;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,SAAgC;AAC3C,UAAM,KAAK,QAAQ,OAAO,mBAAmB,OAAO;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAY,QAAwC;AACxD,UAAM,UAAU,MAAM,KAAK,QAAQ,MAAM,mBAAmB;AAAA,MAC1D,OAAO,EAAE,OAAO;AAAA,IAClB,CAAC;AACD,WAAO,QAAQ,IAAI,CAAC,MAAqB,EAAE,IAA8B;AAAA,EAC3E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAe,SAAgC;AACnD,UAAM,UAAU,MAAM,KAAK,QAAQ,MAAM,mBAAmB;AAAA,MAC1D,OAAO,EAAE,IAAI,QAAQ;AAAA,IACvB,CAAC;AACD,QAAI,QAAQ,WAAW,EAAG;AAE1B,UAAM,WAAW,QAAQ,CAAC,EAAG;AAC7B,UAAM,KAAK,QAAQ,OAAO,mBAAmB,SAAS;AAAA,MACpD,GAAG;AAAA,MACH,YAAY,KAAK,IAAI;AAAA,IACvB,CAAuC;AAAA,EACzC;AACF;;;AC3HO,IAAM,sBAAN,MAA0B;AAAA,EAO/B,YAA6B,QAAuB;AAAvB;AAAA,EAAwB;AAAA,EANpC,eAAe,oBAAI,IAAiC;AAAA,EACpD,UAAU,oBAAI,IAAsB;AAAA,EACpC,aAAa,oBAAI,IAAoB;AAAA,EACrC,WAAW,oBAAI,IAAoB;AAAA,EAC5C,WAAsC;AAAA;AAAA,EAK9C,YAAY,UAAoC;AAC9C,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA,EAGA,IAAY,UAAoD;AAC9D,QAAI,KAAK,UAAU;AACjB,YAAM,aAAa,KAAK,SAAS,cAAmC,qBAAqB;AACzF,YAAM,MAAM,oBAAI,IAAiC;AACjD,iBAAW,UAAU,YAAY;AAC/B,YAAI,IAAI,OAAO,IAAI,MAAM;AAAA,MAC3B;AACA,aAAO;AAAA,IACT;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,UAAU,QAAmC;AAC3C,SAAK,aAAa,IAAI,OAAO,IAAI,MAAM;AACvC,SAAK,OAAO,KAAK,8BAA8B,OAAO,IAAI,KAAK,OAAO,EAAE,GAAG;AAAA,EAC7E;AAAA;AAAA,EAGA,aAAa,IAAkB;AAC7B,SAAK,aAAa,OAAO,EAAE;AAC3B,SAAK,OAAO,KAAK,gCAAgC,EAAE,EAAE;AAAA,EACvD;AAAA,EAEA,WAAW,UAAkB,WAA2B;AACtD,SAAK,QAAQ,IAAI,UAAU,CAAC,GAAG,SAAS,CAAC;AAAA,EAC3C;AAAA,EAEA,aAAa,UAAkB,eAA6B;AAC1D,SAAK,WAAW,IAAI,UAAU,aAAa;AAAA,EAC7C;AAAA,EAEA,MAAM,OAAO,cAA2C;AACtD,UAAM,EAAE,UAAU,SAAS,IAAI;AAG/B,UAAM,eAAe,WAAW,GAAG,QAAQ,IAAI,QAAQ,KAAK;AAC5D,UAAM,cAAc,KAAK,WAAW,IAAI,QAAQ,KAAK;AACrD,QAAI,cAAc,GAAG;AACnB,YAAM,OAAO,KAAK,SAAS,IAAI,YAAY,KAAK;AAChD,UAAI,aAAa,YAAY,OAAO,aAAa;AAC/C,aAAK,OAAO,MAAM,iBAAiB,YAAY,EAAE;AACjD;AAAA,MACF;AAAA,IACF;AAGA,UAAM,YAAY,KAAK,QAAQ,IAAI,QAAQ,KAAK,KAAK,QAAQ,IAAI,GAAG,KAAK,CAAC;AAC1E,QAAI,UAAU,WAAW,GAAG;AAC1B,WAAK,OAAO,MAAM,uCAAuC,QAAQ,GAAG;AACpE;AAAA,IACF;AAEA,UAAM,iBAAiB,KAAK;AAG5B,SAAK,SAAS,IAAI,cAAc,aAAa,SAAS;AAGtD,UAAM,QAAQ;AAAA,MACZ,UACG,IAAI,CAAC,OAAO,eAAe,IAAI,EAAE,CAAC,EAClC,OAAO,CAAC,WAA0C,WAAW,MAAS,EACtE,IAAI,OAAO,WAAW;AACrB,YAAI;AACF,gBAAM,OAAO,KAAK,YAAY;AAAA,QAChC,SAAS,KAAK;AACZ,gBAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,eAAK,OAAO,MAAM,wBAAwB,OAAO,EAAE,aAAa,GAAG,EAAE;AAAA,QACvE;AAAA,MACF,CAAC;AAAA,IACL;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,aAAwE;AACtE,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,MAAM,KAAK,OAAO,EAAE,IAAI,MAAM,KAAK,EAAE;AAAA,EAC3F;AAAA,EAEA,aAA4C;AAC1C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,UAAU,IAA6C;AACrD,WAAO,KAAK,QAAQ,IAAI,EAAE;AAAA,EAC5B;AACF;;;ACrGO,IAAM,eAAN,MAAmB;AAAA,EACP,YAAY,oBAAI,IAA2B;AAAA;AAAA;AAAA;AAAA;AAAA,EAM5D,UAAU,cAAsB,QAAgB,UAA+C;AAC7F,SAAK,UAAU,IAAI,cAAc,EAAE,QAAQ,SAAS,CAAC;AACrD,WAAO,MAAM;AACX,WAAK,UAAU,OAAO,YAAY;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,OAAoB;AAC5B,eAAW,SAAS,KAAK,UAAU,OAAO,GAAG;AAC3C,YAAM,SAAS,KAAK;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,QAAgB,OAAoB;AAC7C,eAAW,SAAS,KAAK,UAAU,OAAO,GAAG;AAC3C,UAAI,MAAM,WAAW,QAAQ;AAC3B,cAAM,SAAS,KAAK;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AACF;;;AC3BO,IAAM,qBAAN,MAAyB;AAAA,EACb,SAAS,oBAAI,IAA+B;AAAA;AAAA;AAAA;AAAA,EAK7D,eAAe,SAAiB,UAAqC;AACnE,UAAM,cAAc,SAAS,UAAU;AACvC,UAAM,aAAgC,YAAY,IAAI,CAAC,UAAU;AAC/D,YAAM,iBAAiB,MAAM,KAAK,WAAW,GAAG,IAAI,MAAM,OAAO,IAAI,MAAM,IAAI;AAC/E,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,UAAU,UAAU,OAAO,GAAG,cAAc;AAAA,MAC9C;AAAA,IACF,CAAC;AACD,SAAK,OAAO,IAAI,SAAS,UAAU;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,SAAuB;AACtC,SAAK,OAAO,OAAO,OAAO;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,QAAgBC,OAAiC;AAC1D,UAAM,mBAAmB,OAAO,YAAY;AAE5C,eAAW,oBAAoB,KAAK,OAAO,OAAO,GAAG;AACnD,iBAAW,SAAS,kBAAkB;AACpC,YAAI,MAAM,MAAM,WAAW,iBAAkB;AAE7C,cAAM,SAAS,UAAU,MAAM,UAAUA,KAAI;AAC7C,YAAI,WAAW,MAAM;AACnB,iBAAO;AAAA,YACL,OAAO,MAAM;AAAA,YACb,SAAS,MAAM;AAAA,YACf;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,aAAqH;AACnH,UAAM,SAAyG,CAAC;AAChH,eAAW,oBAAoB,KAAK,OAAO,OAAO,GAAG;AACnD,iBAAW,SAAS,kBAAkB;AACpC,eAAO,KAAK;AAAA,UACV,SAAS,MAAM;AAAA,UACf,QAAQ,MAAM,MAAM;AAAA,UACpB,MAAM,MAAM;AAAA,UACZ,QAAQ,MAAM,MAAM;AAAA,UACpB,aAAa,MAAM,MAAM;AAAA,QAC3B,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAOA,SAAS,UAAU,SAAiBA,OAA6C;AAC/E,QAAM,eAAe,QAAQ,MAAM,GAAG,EAAE,OAAO,OAAO;AACtD,QAAM,YAAYA,MAAK,MAAM,GAAG,EAAE,OAAO,OAAO;AAEhD,MAAI,aAAa,WAAW,UAAU,QAAQ;AAC5C,WAAO;AAAA,EACT;AAEA,QAAM,SAAiC,CAAC;AAExC,WAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,UAAM,cAAc,aAAa,CAAC;AAClC,UAAM,WAAW,UAAU,CAAC;AAE5B,QAAI,YAAY,WAAW,GAAG,GAAG;AAC/B,aAAO,YAAY,MAAM,CAAC,CAAC,IAAI;AAAA,IACjC,WAAW,gBAAgB,UAAU;AACnC,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;;;ACrHA,SAAS,cAAAC,mBAAkB;AAUpB,IAAM,iBAAN,MAAsE;AAAA,EAI3E,YACmB,UACjB,gBACA;AAFiB;AAGjB,SAAK,SAAS,eAAe,aAAa,iBAAiB;AAAA,EAC7D;AAAA,EARiB,UAAU,oBAAI,IAAe;AAAA,EAC7B;AAAA,EASjB,eAAe,QAAiB;AAC9B,SAAK,QAAQ,IAAI,OAAO,IAAI,MAAM;AAClC,SAAK,OAAO,KAAK,sBAAsB,OAAO,EAAE,KAAK,OAAO,IAAI,GAAG;AAEnE,SAAK,SAAS,KAAK;AAAA,MACjB,IAAIA,YAAW;AAAA,MACf,WAAW,oBAAI,KAAK;AAAA,MACpB,QAAQ,EAAE,MAAM,QAAQ,IAAI,kBAAkB;AAAA,MAC9C,UAAU;AAAA,MACV,MAAM,EAAE,UAAU,OAAO,IAAI,MAAM,OAAO,MAAM,YAAY,OAAO,WAAW;AAAA,IAChF,CAAC;AAAA,EACH;AAAA,EAEA,iBAAiB,IAAkB;AACjC,UAAM,SAAS,KAAK,QAAQ,IAAI,EAAE;AAClC,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AAEA,SAAK,QAAQ,OAAO,EAAE;AACtB,SAAK,OAAO,KAAK,wBAAwB,EAAE,EAAE;AAE7C,SAAK,SAAS,KAAK;AAAA,MACjB,IAAIA,YAAW;AAAA,MACf,WAAW,oBAAI,KAAK;AAAA,MACpB,QAAQ,EAAE,MAAM,QAAQ,IAAI,kBAAkB;AAAA,MAC9C,UAAU;AAAA,MACV,MAAM,EAAE,UAAU,GAAG;AAAA,IACvB,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,IAAsB;AAC9B,WAAO,KAAK,QAAQ,IAAI,EAAE,KAAK;AAAA,EACjC;AAAA,EAEA,cAAmB;AACjB,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC;AAAA,EACzC;AAAA,EAEA,qBAAqB,YAAyB;AAC5C,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE;AAAA,MACvC,CAAC,WAAW,OAAO,eAAe;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,yBAAyB,KAAkB;AACzC,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE;AAAA,MAAO,CAAC,WAC/C,OAAO,aAAa,SAAS,GAAG;AAAA,IAClC;AAAA,EACF;AAAA,EAEA,wBAAwB,YAAoB,SAA6B;AACvE,eAAW,UAAU,SAAS;AAC5B,WAAK,eAAe,MAAM;AAAA,IAC5B;AACA,SAAK,OAAO,KAAK,mBAAmB,QAAQ,MAAM,yBAAyB,UAAU,EAAE;AAAA,EACzF;AAAA,EAEA,0BAA0B,YAA0B;AAClD,UAAM,kBAAkB,KAAK,qBAAqB,UAAU;AAC5D,eAAW,UAAU,iBAAiB;AACpC,WAAK,iBAAiB,OAAO,EAAE;AAAA,IACjC;AACA,SAAK,OAAO,KAAK,qBAAqB,gBAAgB,MAAM,yBAAyB,UAAU,EAAE;AAAA,EACnG;AACF;;;AClEO,IAAM,qBAAN,MAAyB;AAAA,EAM9B,YACmB,eACjB;AADiB;AAAA,EAChB;AAAA,EAPc,WAAW,oBAAI,IAG9B;AAAA,EAMF,QACE,QACA,KACU;AACV,UAAM,iBAAiB,KAAK,SAAS,IAAI,OAAO,EAAE;AAClD,UAAM,UAAU,iBAAiB,GAAG;AAEpC,QAAI,SAAS;AACX,UAAI,QAAQ,WAAW,YAAY;AACjC,eAAO;AAAA,MACT;AAEA,UAAI,QAAQ,WAAW,WAAW,QAAQ,SAAS;AACjD,cAAM,QAAQ,KAAK,cAAc,SAAS,QAAQ,OAAO;AACzD,YAAI,SAAS,OAAQ,MAAc,2BAA2B,YAAY;AACxE,iBACG,MAAc,uBAAuB,QAAQ,KAAK,QAAQ,MAAM,KAAK;AAAA,QAE1E;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAGA,WAAO,OAAO,cAAiB,GAAG;AAAA,EACpC;AAAA,EAEA,WACE,UACA,KACA,SACM;AACN,UAAM,WAAW,KAAK,SAAS,IAAI,QAAQ,KAAK,CAAC;AACjD,SAAK,SAAS,IAAI,UAAU,EAAE,GAAG,UAAU,CAAC,GAAG,GAAG,QAAQ,CAAC;AAAA,EAC7D;AAAA,EAEA,cAAc,UAAkB,KAAmB;AACjD,UAAM,WAAW,KAAK,SAAS,IAAI,QAAQ;AAC3C,QAAI,CAAC,UAAU;AACb;AAAA,IACF;AACA,UAAM,UAAU,EAAE,GAAG,SAAS;AAC9B,WAAO,QAAQ,GAAG;AAClB,SAAK,SAAS,IAAI,UAAU,OAAO;AAAA,EACrC;AAAA,EAEA,YACE,UAC4C;AAC5C,WAAO,KAAK,SAAS,IAAI,QAAQ,KAAK,CAAC;AAAA,EACzC;AAAA,EAEA,yBAAyB,QAAqC;AAC5D,UAAM,iBAAiB,KAAK,SAAS,IAAI,OAAO,EAAE,KAAK,CAAC;AAExD,UAAM,SAAmB,CAAC;AAG1B,eAAW,OAAO,OAAO,cAAc;AACrC,YAAM,UAAU,eAAe,GAAG;AAClC,UAAI,CAAC,WAAW,QAAQ,WAAW,YAAY;AAC7C,eAAO,KAAK,GAAG;AAAA,MACjB;AAAA,IACF;AAGA,eAAW,CAAC,KAAK,OAAO,KAAK,OAAO,QAAQ,cAAc,GAAG;AAC3D,UACE,WAAW,QAAQ,WAAW,WAC9B,CAAC,OAAO,aAAa,SAAS,GAAG,GACjC;AACA,eAAO,KAAK,GAAG;AAAA,MACjB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;AC3GA,SAAS,uBAAuB;AAChC,SAAS,YAAAC,iBAAgB;AACzB,SAAS,aAAAC,kBAAiB;AAC1B,SAAS,cAAAC,aAAY,aAAAC,YAAW,oBAAmC;AACnE,SAAS,QAAAC,aAAY;AACrB,YAAY,QAAQ;AAEpB,IAAMC,iBAAgBJ,WAAUD,SAAQ;AA0BxC,eAAsB,cACpB,SACA,SAC0B;AAC1B,QAAM,SAASI,MAAK,SAAS,KAAK;AAClC,QAAM,WAAWA,MAAK,QAAQ,cAAc;AAC5C,QAAM,UAAUA,MAAK,QAAQ,cAAc;AAG3C,MAAIF,YAAW,QAAQ,KAAKA,YAAW,OAAO,GAAG;AAC/C,QAAI;AACF,YAAM,UAAU,aAAa,QAAQ;AACrC,YAAM,OAAO,IAAI,gBAAgB,OAAO;AACxC,YAAM,UAAU,IAAI,KAAK,KAAK,OAAO;AACrC,UAAI,UAAU,oBAAI,KAAK,GAAG;AACxB,eAAO,EAAE,UAAU,SAAS,WAAW,MAAM;AAAA,MAC/C;AAAA,IAEF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,EAAAC,WAAU,QAAQ,EAAE,WAAW,KAAK,CAAC;AAErC,QAAM,KAAK,SAAS,cAAc;AAClC,QAAM,YAAY,SAAS,aAAa;AAGxC,QAAM,SAAS,oBAAI,IAAY,CAAC,aAAa,IAAO,YAAS,CAAC,CAAC;AAC/D,QAAM,SAAS,oBAAI,IAAY,CAAC,aAAa,KAAK,CAAC;AAGnD,QAAM,aAAgB,qBAAkB;AACxC,aAAW,SAAS,OAAO,OAAO,UAAU,GAAG;AAC7C,QAAI,CAAC,MAAO;AACZ,eAAW,QAAQ,OAAO;AACxB,UAAI,CAAC,KAAK,UAAU;AAClB,eAAO,IAAI,KAAK,OAAO;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAGA,aAAW,OAAO,SAAS,aAAa,CAAC,GAAG;AAC1C,QAAI,IAAI,MAAM,sBAAsB,KAAK,IAAI,SAAS,GAAG,GAAG;AAC1D,aAAO,IAAI,GAAG;AAAA,IAChB,OAAO;AACL,aAAO,IAAI,GAAG;AAAA,IAChB;AAAA,EACF;AAGA,QAAM,WAAqB,CAAC;AAC5B,aAAW,OAAO,QAAQ;AACxB,aAAS,KAAK,OAAO,GAAG,EAAE;AAAA,EAC5B;AACA,aAAW,MAAM,QAAQ;AACvB,aAAS,KAAK,MAAM,EAAE,EAAE;AAAA,EAC1B;AACA,QAAM,YAAY,SAAS,KAAK,GAAG;AAGnC,QAAME,eAAc,WAAW;AAAA,IAC7B;AAAA,IAAO;AAAA,IACP;AAAA,IAAW;AAAA,IACX;AAAA,IAAW;AAAA,IACX;AAAA,IAAQ;AAAA,IACR;AAAA,IAAS,OAAO,SAAS;AAAA,IACzB;AAAA,IACA;AAAA,IAAS,OAAO,EAAE;AAAA,IAClB;AAAA,IAAW,kBAAkB,SAAS;AAAA,EACxC,CAAC;AAGD,QAAM,EAAE,MAAM,IAAI,MAAM,OAAO,aAAkB;AACjD,QAAM,MAAM,SAAS,GAAK;AAE1B,SAAO,EAAE,UAAU,SAAS,WAAW,KAAK;AAC9C;AAKO,SAAS,YAAY,UAAkB,SAA8B;AAC1E,SAAO;AAAA,IACL,MAAM,aAAa,QAAQ;AAAA,IAC3B,KAAK,aAAa,OAAO;AAAA,EAC3B;AACF;;;ACpGO,IAAM,kBAAN,MAAsB;AAAA;AAAA;AAAA;AAAA,EAI3B,YAAY,MAAc,MAAsB;AAC9C,WAAO,SAAS,IAAI,IAAI,IAAI;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,mBAAmB,SAAgD;AACvE,UAAM,EAAE,SAAS,IAAI,MAAM,OAAO,cAAc;AAChD,UAAM,IAAI,SAAS,OAAO;AAC1B,UAAM,gBAAgB,EAAE,oBAAoB,QAAQ,MAAe;AACnE,WAAO,cAAc,QAAQ,OAAgB;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,gBAAgB,SAA8F;AAClH,UAAM,EAAE,kBAAkB,gBAAgB,OAAO,IAAI,MAAM,OAAO,qBAAc;AAEhF,UAAM,WAAW,eAAe;AAAA,MAC9B,KAAK,QAAQ;AAAA,MACb,kBAAkB,OAAO,EAAE,OAAO,QAAQ,MAAM;AAAA,IAClD,CAAC;AAED,UAAM,SAAS,iBAAiB;AAAA,MAC9B,OAAO,CAAC,OAAO,EAAE,QAAQ,SAAS,CAAC,CAAC;AAAA,IACtC,CAAC;AAED,WAAO;AAAA,MACL;AAAA,MACA,OAAO,MAAM,SAAS,MAAM;AAAA,IAC9B;AAAA,EACF;AACF;;;ACtEA,YAAYC,SAAQ;AACpB,SAAS,gBAAAC,qBAAoB;AAQ7B,eAAe,qBAAsC;AACnD,MAAI;AACF,UAAM,KAAK,MAAM,OAAO,mBAAmB;AAC3C,UAAM,MAAM,MAAM,GAAG,IAAI;AACzB,WAAO,KAAK,MAAM,IAAI,YAAY,OAAO,IAAI;AAAA,EAC/C,QAAQ;AAEN,UAAMC,YAAc,aAAS;AAC7B,QAAI;AACF,UAAIA,cAAa,UAAU;AAEzB,cAAM,SAASD,cAAa,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAK,CAAC;AAC1E,cAAM,WAAW,SAAS,OAAO,MAAM,oBAAoB,IAAI,CAAC,KAAK,OAAO;AAC5E,cAAM,OAAO,SAAS,OAAO,MAAM,qBAAqB,IAAI,CAAC,KAAK,GAAG;AACrE,cAAM,WAAW,SAAS,OAAO,MAAM,yBAAyB,IAAI,CAAC,KAAK,GAAG;AAC7E,cAAM,YAAY,SAAS,OAAO,MAAM,0BAA0B,IAAI,CAAC,KAAK,GAAG;AAC/E,eAAO,KAAK,OAAO,OAAO,WAAW,aAAa,WAAW,OAAO,IAAI;AAAA,MAC1E,WAAWC,cAAa,SAAS;AAE/B,cAAM,EAAE,cAAAC,cAAa,IAAI,MAAM,OAAO,IAAS;AAC/C,cAAM,UAAUA,cAAa,iBAAiB,MAAM;AACpD,cAAM,QAAQ,QAAQ,MAAM,4BAA4B;AACxD,YAAI,MAAO,QAAO,KAAK,MAAM,SAAS,MAAM,CAAC,CAAE,IAAI,IAAI;AAAA,MACzD;AAAA,IACF,QAAQ;AAAA,IAAe;AAEvB,WAAO,KAAK,MAAS,aAAS,IAAI,OAAO,IAAI;AAAA,EAC/C;AACF;AAEO,IAAM,iBAAN,MAAqB;AAAA,EAClB,SAAsC;AAAA;AAAA,EAG9C,MAAM,QAAuC;AAC3C,QAAI,KAAK,OAAQ,QAAO,KAAK;AAE7B,UAAM,QAAQ,KAAK,IAAI;AACvB,YAAQ,IAAI,sCAAsC;AAClD,UAAM,WAAW,MAAM,KAAK,cAAc;AAC1C,YAAQ,IAAI,8BAA8B,SAAS,QAAQ,IAAI,SAAS,IAAI,KAAK,SAAS,QAAQ,KAAK,SAAS,QAAQ,gBAAgB,KAAK,MAAM,SAAS,cAAc,IAAI,CAAC,IAAI;AACnL,QAAI,SAAS,IAAK,SAAQ,IAAI,yBAAyB,SAAS,IAAI,IAAI,EAAE;AAC1E,QAAI,SAAS,IAAK,SAAQ,IAAI,yBAAyB,SAAS,IAAI,IAAI,EAAE;AAE1E,YAAQ,IAAI,8CAA8C;AAC1D,UAAM,eAAe,MAAM,KAAK,kBAAkB;AAClD,YAAQ,IAAI,mCAAmC,aAAa,IAAI,OAAK,EAAE,EAAE,EAAE,KAAK,IAAI,CAAC,EAAE;AAEvF,YAAQ,IAAI,6CAA6C;AACzD,UAAM,aAAa,KAAK,oBAAoB;AAC5C,QAAI,WAAW,YAAY;AACzB,cAAQ,IAAI,4BAA4B,WAAW,UAAU,WAAM,WAAW,SAAS,OAAO,OAAK,EAAE,SAAS,EAAE,IAAI,OAAK,EAAE,EAAE,EAAE,KAAK,IAAI,KAAK,aAAa,EAAE;AAAA,IAC9J,OAAO;AACL,cAAQ,IAAI,oCAAoC;AAAA,IAClD;AAEA,UAAM,SAAS,KAAK,cAAc,UAAU,cAAc,WAAW,QAAQ;AAC7E,UAAM,YAAY,OAAO,KAAK,OAAK,EAAE,SAAS,KAAK,OAAO,OAAO,SAAS,CAAC;AAE3E,UAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,YAAQ,IAAI,wCAAwC,OAAO,aAAQ,OAAO,MAAM,SAAS;AACzF,YAAQ,IAAI,0BAA0B,UAAU,OAAO,IAAI,UAAU,OAAO,KAAK,UAAU,MAAM,YAAO,UAAU,MAAM,YAAY,UAAU,KAAK,GAAG;AACtJ,eAAW,KAAK,QAAQ;AACtB,cAAQ,IAAI,sBAAsB,EAAE,YAAY,WAAM,QAAG,IAAI,EAAE,OAAO,IAAI,EAAE,OAAO,KAAK,EAAE,MAAM,kBAAa,EAAE,KAAK,WAAM,EAAE,MAAM,EAAE;AAAA,IACtI;AAEA,SAAK,SAAS;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,WAAW;AAAA,IACzB;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,gBAAuC;AAC3C,UAAMD,YAAc,aAAS;AAC7B,UAAME,QAAU,SAAK;AACrB,UAAMC,QAAU,SAAK;AACrB,UAAM,WAAWA,MAAK,CAAC,GAAG,SAAS;AACnC,UAAM,WAAWA,MAAK;AACtB,UAAM,cAAc,KAAK,MAAS,aAAS,IAAI,OAAO,IAAI;AAC1D,UAAM,kBAAkB,MAAM,mBAAmB;AACjD,YAAQ,IAAI,+BAA+B,WAAW,iBAAiB,eAAe,4BAA4B;AAElH,QAAI,MAAsB;AAC1B,QAAI,MAAsB;AAG1B,QAAIH,cAAa,YAAYE,UAAS,SAAS;AAC7C,YAAM,EAAE,MAAM,SAAS,MAAM,oBAAoB;AACjD,YAAM,EAAE,MAAM,YAAY;AAAA,IAC5B;AAGA,QAAIF,cAAa,SAAS;AACxB,UAAI;AACF,cAAM,SAASD,cAAa,cAAc,CAAC,iCAAiC,uBAAuB,GAAG;AAAA,UACpG,UAAU;AAAA,UAAQ,SAAS;AAAA,UAAM,OAAO,CAAC,QAAQ,QAAQ,MAAM;AAAA,QACjE,CAAC,EAAE,KAAK;AACR,YAAI,QAAQ;AACV,gBAAM,CAAC,MAAM,GAAG,IAAI,OAAO,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,KAAK,CAAC;AACvD,gBAAM;AAAA,YACJ,MAAM;AAAA,YACN,MAAM,QAAQ;AAAA,YACd,UAAU,SAAS,OAAO,GAAG;AAAA,UAC/B;AAAA,QACF;AAAA,MACF,QAAQ;AAAA,MAAsB;AAAA,IAChC;AAEA,WAAO,EAAE,UAAAC,WAAU,MAAAE,OAAM,UAAU,UAAU,aAAa,iBAAiB,KAAK,IAAI;AAAA,EACtF;AAAA,EAEA,MAAc,oBAAwE;AACpF,UAAM,WAAsD;AAAA,MAC1D,EAAE,IAAI,OAAO,WAAW,KAAK;AAAA,IAC/B;AAEA,QAAI;AACF,YAAM,MAAM,MAAM,OAAO,kBAAkB;AAC3C,YAAM,YAAsB,IAAI,kBAAkB,wBAAwB,KAAK,CAAC;AAChF,iBAAW,KAAK,WAAW;AACzB,cAAM,IAAI,EAAE,YAAY,EAAE,QAAQ,qBAAqB,EAAE;AACzD,YAAI,MAAM,SAAU,UAAS,KAAK,EAAE,IAAI,UAAU,WAAW,KAAK,CAAC;AAAA,iBAC1D,MAAM,OAAQ,UAAS,KAAK,EAAE,IAAI,QAAQ,WAAW,KAAK,CAAC;AAAA,iBAC3D,MAAM,WAAY,UAAS,KAAK,EAAE,IAAI,YAAY,WAAW,KAAK,CAAC;AAAA,MAC9E;AAAA,IACF,QAAQ;AAAA,IAAkC;AAG1C,QAAO,aAAS,MAAM,YAAY,CAAC,SAAS,KAAK,OAAK,EAAE,OAAO,QAAQ,GAAG;AACxE,eAAS,KAAK,EAAE,IAAI,UAAU,WAAW,KAAK,CAAC;AAAA,IACjD;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,sBAA0H;AAChI,QAAI,aAA4B;AAChC,eAAW,OAAO,CAAC,WAAW,QAAQ,GAAG;AACvC,UAAI;AACF,QAAAH,cAAa,KAAK,CAAC,WAAW,GAAG,EAAE,SAAS,KAAM,OAAO,OAAO,CAAC;AACjE,qBAAa;AACb;AAAA,MACF,QAAQ;AAAA,MAAkB;AAAA,IAC5B;AAEA,QAAI,CAAC,WAAY,QAAO,EAAE,YAAY,MAAM,UAAU,CAAC,EAAE;AAEzD,UAAM,SAA0C;AAAA;AAAA,MAE9C,CAAC,eAAe,UAAU,QAAQ;AAAA,MAClC,CAAC,oBAAoB,YAAY,UAAU;AAAA,MAC3C,CAAC,SAAS,WAAW,MAAM;AAAA,MAC3B,CAAC,eAAe,WAAW,MAAM;AAAA,IACnC;AAEA,UAAM,WAAsE,CAAC;AAC7E,eAAW,CAAC,KAAK,IAAI,MAAM,KAAK,QAAQ;AACtC,UAAI,YAAY;AAChB,YAAM,aAAa,KAAK,IAAI;AAC5B,UAAI;AACF,QAAAA,cAAa,YAAY,CAAC,MAAM,UAAU,GAAG,EAAE,GAAG,EAAE,SAAS,KAAO,OAAO,SAAS,CAAC;AACrF,oBAAY;AAAA,MACd,QAAQ;AAAA,MAA6B;AACrC,YAAM,UAAU,KAAK,IAAI,IAAI;AAC7B,cAAQ,IAAI,6BAA6B,GAAG,KAAK,YAAY,WAAM,QAAG,KAAK,OAAO,KAAK;AAGvF,UAAI,OAAO,YAAe,aAAS,MAAM,UAAU;AACjD,iBAAS,KAAK,EAAE,IAAI,QAAQ,UAAU,CAAC;AAAA,MACzC,WAAW,WAAW;AACpB,iBAAS,KAAK,EAAE,IAAI,QAAQ,UAAU,CAAC;AAAA,MACzC;AAAA,IACF;AAEA,WAAO,EAAE,YAAY,SAAS;AAAA,EAChC;AAAA,EAEQ,cACN,UACA,cACA,gBACiB;AACjB,UAAM,SAA0B,CAAC;AAGjC,QAAI,SAAS,aAAa,YAAY,SAAS,SAAS,SAAS;AAC/D,YAAM,WAAW,eAAe,KAAK,OAAK,EAAE,OAAO,QAAQ;AAC3D,UAAI,UAAU;AACZ,eAAO,KAAK,EAAE,SAAS,UAAU,SAAS,UAAU,QAAQ,UAAU,OAAO,IAAI,QAAQ,uCAAuC,WAAW,SAAS,UAAU,CAAC;AAAA,MACjK;AACA,YAAM,aAAa,aAAa,KAAK,OAAK,EAAE,OAAO,QAAQ;AAC3D,UAAI,YAAY;AACd,eAAO,KAAK,EAAE,SAAS,QAAQ,SAAS,UAAU,QAAQ,QAAQ,OAAO,IAAI,QAAQ,2BAA2B,WAAW,WAAW,UAAU,CAAC;AAAA,MACnJ;AAAA,IACF;AAGA,QAAI,SAAS,KAAK,SAAS,UAAU;AACnC,YAAM,WAAW,aAAa,KAAK,OAAK,EAAE,OAAO,UAAU;AAC3D,UAAI,SAAU,QAAO,KAAK,EAAE,SAAS,QAAQ,SAAS,YAAY,QAAQ,QAAQ,OAAO,IAAI,QAAQ,mBAAmB,WAAW,KAAK,CAAC;AACzI,YAAM,OAAO,aAAa,KAAK,OAAK,EAAE,OAAO,MAAM;AACnD,UAAI,KAAM,QAAO,KAAK,EAAE,SAAS,QAAQ,SAAS,QAAQ,QAAQ,QAAQ,OAAO,IAAI,QAAQ,eAAe,WAAW,KAAK,CAAC;AAAA,IAC/H;AAGA,UAAM,WAAW,eAAe,KAAK,OAAK,EAAE,OAAO,UAAU;AAC7D,QAAI,UAAU;AACZ,YAAM,QAAQ,SAAS,KAAK,SAAS,cAAc,KAAK;AACxD,aAAO,KAAK,EAAE,SAAS,UAAU,SAAS,YAAY,QAAQ,YAAY,OAAO,QAAQ,kBAAkB,WAAW,SAAS,UAAU,CAAC;AAAA,IAC5I;AAGA,WAAO,KAAK,EAAE,SAAS,QAAQ,SAAS,OAAO,QAAQ,QAAQ,OAAO,IAAI,QAAQ,2BAA2B,WAAW,KAAK,CAAC;AAC9H,UAAM,SAAS,eAAe,KAAK,OAAK,EAAE,OAAO,SAAS;AAC1D,QAAI,QAAQ;AACV,aAAO,KAAK,EAAE,SAAS,UAAU,SAAS,OAAO,QAAQ,QAAQ,OAAO,IAAI,QAAQ,qBAAqB,WAAW,OAAO,UAAU,CAAC;AAAA,IACxI;AAEA,WAAO,OAAO,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAAA,EAChD;AACF;;;ACtOO,IAAM,0BAAN,MAA8B;AAAA,EACnC,YACmB,QACA,UACjB;AAFiB;AACA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWK,aAAgE;AACtE,UAAM,QAAQ,KAAK,SAAS;AAC5B,QAAI,QAAQ,MAAQ,QAAO,EAAE,gBAAgB,KAAK,eAAe,IAAI;AACrE,QAAI,QAAQ,KAAO,QAAO,EAAE,gBAAgB,KAAK,eAAe,IAAI;AACpE,WAAO,EAAE,gBAAgB,KAAK,eAAe,IAAI;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,QAAQ,cAAoE;AAC1E,QAAI,aAAa,WAAW,GAAG;AAC7B,aAAO,EAAE,SAAS,IAAI,SAAS,QAAQ,SAAS,OAAO,QAAQ,QAAQ,QAAQ,qBAAqB;AAAA,IACtG;AAGA,UAAM,YAAY,KAAK,SAAS,kBAAkB;AAClD,UAAM,EAAE,gBAAgB,cAAc,IAAI,KAAK,WAAW;AAE1D,YAAQ,IAAI,2CAA2C,KAAK,SAAS,eAAe,eAAe,KAAK,MAAM,SAAS,CAAC,yBAAyB,cAAc,aAAa,aAAa,EAAE;AAG3L,UAAM,OAAO,aAAa,OAAO,OAAK,EAAE,YAAY,SAAS;AAC7D,UAAM,aAAa,KAAK,SAAS,IAAI,OAAO,CAAC,aAAa,CAAC,CAAE;AAE7D,YAAQ,IAAI,6BAA6B,WAAW,MAAM,IAAI,aAAa,MAAM,wBAAwB;AAGzG,QAAI,YAAwF;AAE5F,eAAW,SAAS,YAAY;AAC9B,iBAAW,SAAS,KAAK,QAAQ;AAC/B,YAAI,CAAC,MAAM,UAAW;AACtB,YAAI,CAAC,MAAM,QAAQ,SAAS,MAAM,MAAM,EAAG;AAE3C,cAAM,WAAW,MAAM,gBAAgB,iBAAiB,MAAM,QAAQ;AAEtE,YAAI,CAAC,aAAa,WAAW,UAAU,UAAU;AAC/C,kBAAQ,IAAI,uCAAuC,MAAM,OAAO,cAAc,MAAM,aAAa,OAAO,MAAM,OAAO,IAAI,MAAM,MAAM,WAAW,MAAM,KAAK,qBAAgB,KAAK,MAAM,QAAQ,CAAC,EAAE;AACjM,sBAAY,EAAE,OAAO,OAAO,SAAS;AAAA,QACvC;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,WAAW;AACd,aAAO;AAAA,QACL,SAAS,WAAW,CAAC,EAAG;AAAA,QACxB,SAAS;AAAA,QACT,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS,UAAU,MAAM;AAAA,MACzB,SAAS,UAAU,MAAM;AAAA,MACzB,SAAS,UAAU,MAAM;AAAA,MACzB,QAAQ,UAAU,MAAM;AAAA,MACxB,QAAQ,GAAG,UAAU,MAAM,IAAI,OAAO,UAAU,MAAM,MAAM,YAAY,KAAK,MAAM,UAAU,QAAQ,CAAC;AAAA,IACxG;AAAA,EACF;AACF;;;ACxFA,SAAS,cAAAK,mBAAkB;AAkDpB,IAAM,kBAAN,MAAqE;AAAA,EAI1E,YACmB,gBACA,UACA,gBACjB;AAHiB;AACA;AACA;AAEjB,SAAK,SAAS,eAAe,aAAa,kBAAkB;AAAA,EAC9D;AAAA,EATiB,YAAY,oBAAI,IAA8B;AAAA,EAC9C;AAAA,EAUjB,iBAAiB,UAAmB;AAClC,UAAM,iBAAiB,KAAK,eAAe,aAAa,YAAY,SAAS,EAAE,EAAE;AACjF,UAAM,YAAY,IAAI;AAAA,MACpB,SAAS;AAAA,MACT;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF;AACA,SAAK,UAAU,IAAI,SAAS,IAAI,EAAE,UAAU,WAAW,SAAS,MAAM,CAAC;AACvE,SAAK,OAAO,KAAK,wBAAwB,SAAS,EAAE,KAAK,SAAS,IAAI,GAAG;AAAA,EAC3E;AAAA,EAEA,MAAM,cAAc,IAA2B;AAC7C,UAAM,QAAQ,KAAK,UAAU,IAAI,EAAE;AACnC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,aAAa,EAAE,qBAAqB;AAAA,IACtD;AAEA,QAAI,MAAM,UAAU,UAAU,YAAY;AACxC,YAAM,IAAI,MAAM,aAAa,EAAE,eAAe;AAAA,IAChD;AAEA,UAAM,UAAU,WAAW,UAAU;AAErC,QAAI;AACF,YAAM,MAAM,SAAS,MAAM;AAAA,IAC7B,SAAS,KAAc;AACrB,YAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,YAAM,UAAU,WAAW,SAAS,OAAO;AAC3C,YAAM;AAAA,IACR;AAEA,UAAM,UAAU,WAAW,SAAS;AAEpC,UAAM,UAAU,MAAM,SAAS,WAAW;AAC1C,SAAK,eAAe,wBAAwB,IAAI,OAAO;AAEvD,UAAM,cAAc,MAAM,SAAS,oBAAoB,CAAC,UAAqB;AAC3E,WAAK,SAAS,KAAK;AAAA,QACjB,IAAIC,YAAW;AAAA,QACf,WAAW,oBAAI,KAAK;AAAA,QACpB,QAAQ,EAAE,MAAM,YAAY,GAAG;AAAA,QAC/B,UAAU,YAAY,MAAM,IAAI;AAAA,QAChC,MAAM,MAAM;AAAA,MACd,CAAC;AAAA,IACH,CAAC;AAED,UAAM,UAAU;AAChB,UAAM,cAAc;AAEpB,SAAK,SAAS,KAAK;AAAA,MACjB,IAAIA,YAAW;AAAA,MACf,WAAW,oBAAI,KAAK;AAAA,MACpB,QAAQ,EAAE,MAAM,QAAQ,IAAI,mBAAmB;AAAA,MAC/C,UAAU;AAAA,MACV,MAAM,EAAE,YAAY,GAAG;AAAA,IACzB,CAAC;AAED,SAAK,OAAO,KAAK,qBAAqB,EAAE,EAAE;AAAA,EAC5C;AAAA,EAEA,MAAM,aAAa,IAA2B;AAC5C,UAAM,QAAQ,KAAK,UAAU,IAAI,EAAE;AACnC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,aAAa,EAAE,qBAAqB;AAAA,IACtD;AAEA,UAAM,UAAU,WAAW,UAAU;AAErC,QAAI,MAAM,aAAa;AACrB,YAAM,YAAY;AAClB,YAAM,cAAc;AAAA,IACtB;AAEA,SAAK,eAAe,0BAA0B,EAAE;AAEhD,UAAM,MAAM,SAAS,KAAK;AAC1B,UAAM,UAAU;AAEhB,UAAM,UAAU,WAAW,SAAS;AAEpC,SAAK,SAAS,KAAK;AAAA,MACjB,IAAIA,YAAW;AAAA,MACf,WAAW,oBAAI,KAAK;AAAA,MACpB,QAAQ,EAAE,MAAM,QAAQ,IAAI,mBAAmB;AAAA,MAC/C,UAAU;AAAA,MACV,MAAM,EAAE,YAAY,GAAG;AAAA,IACzB,CAAC;AAED,SAAK,OAAO,KAAK,qBAAqB,EAAE,EAAE;AAAA,EAC5C;AAAA,EAEA,MAAM,gBAAgB,IAA2B;AAC/C,UAAM,QAAQ,KAAK,UAAU,IAAI,EAAE;AACnC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,aAAa,EAAE,qBAAqB;AAAA,IACtD;AAEA,QAAI,MAAM,UAAU,UAAU,aAAa,MAAM,SAAS;AACxD,YAAM,KAAK,aAAa,EAAE;AAAA,IAC5B;AAEA,UAAM,UAAU,WAAW,UAAU;AACrC,SAAK,OAAO,KAAK,sBAAsB,EAAE,EAAE;AAAA,EAC7C;AAAA,EAEA,MAAM,eAAe,IAA2B;AAC9C,UAAM,QAAQ,KAAK,UAAU,IAAI,EAAE;AACnC,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,aAAa,EAAE,qBAAqB;AAAA,IACtD;AAEA,QAAI,MAAM,UAAU,UAAU,YAAY;AACxC,YAAM,IAAI,MAAM,aAAa,EAAE,mBAAmB;AAAA,IACpD;AAEA,UAAM,UAAU,WAAW,SAAS;AACpC,SAAK,OAAO,KAAK,qBAAqB,EAAE,EAAE;AAAA,EAC5C;AAAA,EAEA,MAAM,gBAAgB,IAA2B;AAC/C,UAAM,KAAK,aAAa,EAAE;AAC1B,UAAM,KAAK,cAAc,EAAE;AAAA,EAC7B;AAAA,EAEA,YAAY,IAAsB;AAChC,UAAM,QAAQ,KAAK,UAAU,IAAI,EAAE;AACnC,WAAO,OAAO,YAAY;AAAA,EAC5B;AAAA,EAEA,kBAAkB,IAAkC;AAClD,UAAM,QAAQ,KAAK,UAAU,IAAI,EAAE;AACnC,WAAO,OAAO,UAAU,UAAU,KAAK;AAAA,EACzC;AAAA,EAEA,gBAA6C;AAC3C,WAAO,MAAM,KAAK,KAAK,UAAU,OAAO,CAAC,EAAE,IAAI,CAAC,WAAW;AAAA,MACzD,IAAI,MAAM,SAAS;AAAA,MACnB,MAAM,MAAM,SAAS;AAAA,MACrB,MAAM,MAAM,SAAS;AAAA,MACrB,QAAQ,MAAM,SAAS,UAAU;AAAA,MACjC,SAAS,MAAM;AAAA,MACf,WAAW,MAAM,UAAU,UAAU;AAAA,IACvC,EAAE;AAAA,EACJ;AAAA,EAEA,MAAM,cAA6B;AACjC,UAAM,aAAa,MAAM,KAAK,KAAK,UAAU,QAAQ,CAAC,EACnD,OAAO,CAAC,CAAC,EAAE,KAAK,MAAM,MAAM,OAAO,EACnC,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE;AAEnB,eAAW,MAAM,YAAY;AAC3B,YAAM,KAAK,aAAa,EAAE;AAAA,IAC5B;AAEA,SAAK,OAAO,KAAK,4BAA4B,WAAW,MAAM,WAAW;AAAA,EAC3E;AACF;","names":["platform","rmSync","join","platform","arch","join","join","existsSync","mkdirSync","chmodSync","execFileSync","pipeline","Readable","createWriteStream","platform","arch","join","existsSync","mkdirSync","Readable","pipeline","createWriteStream","execFileSync","unlinkSync","chmodSync","hash","fs","path","fs","path","promises","spawn","randomUUID","fs","path","StorageLocationManager","location","hash","crypto","hash","crypto","crypto","path","randomUUID","execFile","promisify","existsSync","mkdirSync","join","execFileAsync","os","execFileSync","platform","readFileSync","arch","cpus","randomUUID","randomUUID"]}
1
+ {"version":3,"sources":["../src/deps/binary-downloader.ts","../src/deps/ffmpeg-downloader.ts","../src/deps/python-downloader.ts","../src/events/event-bus.ts","../src/download/model-downloader.ts","../src/download/model-download-service.ts","../src/python/python-env-manager.ts","../src/pipeline/pipeline-validator.ts","../src/pipeline/pipeline-runner.ts","../src/process/managed-process.ts","../src/process/process-manager.ts","../src/network/network-quality.ts","../src/repl/repl-engine.ts","../src/agent/agent-registry.ts","../src/agent/task-dispatcher.ts","../src/agent/agent-client.ts","../src/agent/agent-task-runner.ts","../src/agent/pipeline-task-handlers.ts","../src/lifecycle/lifecycle-state-machine.ts","../src/feature/feature-manager.ts","../src/events/system-event-bus.ts","../src/logging/log-ring-buffer.ts","../src/logging/scoped-logger.ts","../src/logging/log-manager.ts","../src/storage/storage-manager.ts","../src/auth/auth-manager.ts","../src/auth/api-key-manager.ts","../src/auth/user-manager.ts","../src/auth/scoped-token-manager.ts","../src/notification/notification-service.ts","../src/notification/toast-service.ts","../src/addon-routes/addon-route-registry.ts","../src/device/device-registry.ts","../src/device/capability-resolver.ts","../src/tls/cert-manager.ts","../src/addon/addon-api-factory.ts","../src/platform/platform-scorer.ts","../src/platform/inference-config-resolver.ts","../src/provider/provider-manager.ts"],"sourcesContent":["import { existsSync, mkdirSync, chmodSync, createWriteStream, unlinkSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { pipeline } from 'node:stream/promises'\nimport { Readable } from 'node:stream'\nimport { execFileSync } from 'node:child_process'\nimport type { IScopedLogger } from '@camstack/types'\n\nexport interface PlatformInfo {\n readonly platform: NodeJS.Platform\n readonly arch: NodeJS.Architecture\n}\n\nexport function getPlatformInfo(): PlatformInfo {\n return {\n platform: process.platform,\n arch: process.arch,\n }\n}\n\nexport function buildBinaryPath(dataDir: string, name: string, platform?: string): string {\n const ext = (platform ?? process.platform) === 'win32' ? '.exe' : ''\n return join(dataDir, 'deps', `${name}${ext}`)\n}\n\n/** Check if a binary exists in PATH */\nexport function findInPath(name: string): string | null {\n try {\n execFileSync(name, ['--version'], { stdio: 'pipe', timeout: 5000 })\n return name\n } catch {\n return null\n }\n}\n\nexport interface DownloadOptions {\n readonly name: string\n readonly url: string\n readonly targetDir: string\n readonly targetName: string\n readonly logger: IScopedLogger\n readonly isArchive?: boolean\n readonly archiveFormat?: 'zip' | 'tar.gz' | 'tar.xz'\n /** Relative path within archive to the binary (e.g., 'ffmpeg-6.1/bin/ffmpeg') */\n readonly archiveInnerPath?: string\n}\n\n/**\n * Download a binary to the target directory.\n * Handles archives (zip, tar.gz, tar.xz) and raw binaries.\n */\nexport async function downloadBinary(opts: DownloadOptions): Promise<string> {\n const { name, url, targetDir, targetName, logger, isArchive, archiveFormat, archiveInnerPath } = opts\n const targetPath = join(targetDir, targetName)\n\n if (existsSync(targetPath)) {\n logger.debug(`${name} binary already exists at ${targetPath}`)\n return targetPath\n }\n\n mkdirSync(targetDir, { recursive: true })\n\n logger.info(`Downloading ${name} from ${url}`)\n const response = await fetch(url, { redirect: 'follow' })\n if (!response.ok || !response.body) {\n throw new Error(`Failed to download ${name}: ${response.status} ${response.statusText}`)\n }\n\n if (isArchive) {\n const ext = archiveFormat ?? 'tar.gz'\n const tmpArchive = join(targetDir, `${name}-download.${ext}`)\n const nodeStream = Readable.fromWeb(response.body as any)\n await pipeline(nodeStream, createWriteStream(tmpArchive))\n\n // Extract\n const tmpExtractDir = join(targetDir, `${name}-extract`)\n mkdirSync(tmpExtractDir, { recursive: true })\n\n if (ext === 'zip') {\n try {\n execFileSync('unzip', ['-o', '-q', tmpArchive, '-d', tmpExtractDir], { stdio: 'pipe' })\n } catch {\n execFileSync('tar', ['-xf', tmpArchive, '-C', tmpExtractDir], { stdio: 'pipe' })\n }\n } else if (ext === 'tar.xz') {\n execFileSync('tar', ['-xJf', tmpArchive, '-C', tmpExtractDir], { stdio: 'pipe' })\n } else {\n execFileSync('tar', ['-xzf', tmpArchive, '-C', tmpExtractDir], { stdio: 'pipe' })\n }\n\n // Copy binary from archive\n if (archiveInnerPath) {\n const { copyFileSync } = await import('node:fs')\n const sourcePath = join(tmpExtractDir, archiveInnerPath)\n if (!existsSync(sourcePath)) {\n throw new Error(`Binary not found in archive at ${archiveInnerPath}`)\n }\n copyFileSync(sourcePath, targetPath)\n }\n\n // Cleanup\n unlinkSync(tmpArchive)\n const { rmSync } = await import('node:fs')\n rmSync(tmpExtractDir, { recursive: true, force: true })\n } else {\n // Direct binary download\n const nodeStream = Readable.fromWeb(response.body as any)\n await pipeline(nodeStream, createWriteStream(targetPath))\n }\n\n chmodSync(targetPath, 0o755)\n logger.info(`${name} downloaded to ${targetPath}`)\n return targetPath\n}\n\n/**\n * Ensure a binary is available. Checks:\n * 1. Target path (already downloaded)\n * 2. System PATH\n * 3. Download from URL\n */\nexport async function ensureBinary(opts: {\n readonly name: string\n readonly targetDir: string\n readonly downloadUrl: string\n readonly logger: IScopedLogger\n readonly isArchive?: boolean\n readonly archiveFormat?: 'zip' | 'tar.gz' | 'tar.xz'\n readonly archiveInnerPath?: string\n}): Promise<string> {\n const ext = process.platform === 'win32' ? '.exe' : ''\n const targetName = `${opts.name}${ext}`\n const targetPath = join(opts.targetDir, targetName)\n\n // 1. Already downloaded\n if (existsSync(targetPath)) {\n opts.logger.debug(`${opts.name} found at ${targetPath}`)\n return targetPath\n }\n\n // 2. System PATH\n const inPath = findInPath(opts.name)\n if (inPath) {\n opts.logger.info(`${opts.name} found in system PATH`)\n return inPath\n }\n\n // 3. Download\n return downloadBinary({\n name: opts.name,\n url: opts.downloadUrl,\n targetDir: opts.targetDir,\n targetName,\n logger: opts.logger,\n isArchive: opts.isArchive,\n archiveFormat: opts.archiveFormat,\n archiveInnerPath: opts.archiveInnerPath,\n })\n}\n","/**\n * Download ffmpeg static build for the current platform.\n *\n * Sources:\n * - Linux: https://johnvansickle.com/ffmpeg/ (static builds)\n * - macOS: https://evermeet.cx/ffmpeg/ or homebrew\n *\n * Using BtbN's GitHub releases as they cover both platforms:\n * https://github.com/BtbN/FFmpeg-Builds/releases\n */\nimport { join } from 'node:path'\nimport type { IScopedLogger } from '@camstack/types'\nimport { ensureBinary } from './binary-downloader.js'\n\nconst FFMPEG_VERSION = '7.1'\n\nexport function getFfmpegDownloadUrl(platform: string, arch: string): string {\n switch (platform) {\n case 'linux': {\n const archMap: Record<string, string> = { x64: 'amd64', arm64: 'arm64' }\n const a = archMap[arch]\n if (!a) throw new Error(`Unsupported Linux architecture: ${arch}`)\n // John Van Sickle static builds — well-tested, widely used\n return `https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-${a}-static.tar.xz`\n }\n case 'darwin': {\n const archMap: Record<string, string> = { arm64: 'arm64', x64: 'amd64' }\n const a = archMap[arch]\n if (!a) throw new Error(`Unsupported macOS architecture: ${arch}`)\n // macOS static builds from osxexperts (maintained, universal builds)\n return `https://www.osxexperts.net/ffmpeg${FFMPEG_VERSION.replace('.', '')}arm.zip`\n }\n default:\n throw new Error(`Unsupported platform: ${platform}`)\n }\n}\n\nexport function getFfmpegArchiveInfo(platform: string): {\n isArchive: boolean\n archiveFormat: 'zip' | 'tar.gz' | 'tar.xz'\n archiveInnerPath: string\n} {\n switch (platform) {\n case 'linux':\n return {\n isArchive: true,\n archiveFormat: 'tar.xz',\n archiveInnerPath: `ffmpeg-${FFMPEG_VERSION}-amd64-static/ffmpeg`,\n }\n case 'darwin':\n return {\n isArchive: true,\n archiveFormat: 'zip',\n archiveInnerPath: 'ffmpeg',\n }\n default:\n throw new Error(`Unsupported platform: ${platform}`)\n }\n}\n\n/**\n * Ensure ffmpeg binary is available.\n * Checks: deps dir → system PATH → download.\n */\nexport async function ensureFfmpeg(dataDir: string, logger: IScopedLogger): Promise<string> {\n const depsDir = join(dataDir, 'deps')\n const platform = process.platform\n const arch = process.arch\n\n const archiveInfo = getFfmpegArchiveInfo(platform)\n\n return ensureBinary({\n name: 'ffmpeg',\n targetDir: depsDir,\n downloadUrl: getFfmpegDownloadUrl(platform, arch),\n logger,\n ...archiveInfo,\n })\n}\n","/**\n * Download portable Python (headless) from bjia56/portable-python.\n *\n * Source: https://github.com/bjia56/portable-python\n *\n * Advantages over python-build-standalone:\n * - macOS universal2 binary (arm64+x86_64 in one)\n * - Lighter (~24-28MB headless zip)\n * - glibc 2.17 minimum (better compat)\n * - Headless variant excludes tkinter/UI (ideal for ML inference)\n *\n * After extraction, the binary is at: python/bin/python3\n */\nimport { join } from 'node:path'\nimport { existsSync, mkdirSync, chmodSync } from 'node:fs'\nimport { execFileSync } from 'node:child_process'\nimport { pipeline } from 'node:stream/promises'\nimport { Readable } from 'node:stream'\nimport { createWriteStream } from 'node:fs'\nimport type { IScopedLogger } from '@camstack/types'\nimport { findInPath } from './binary-downloader.js'\n\nexport const PYTHON_VERSION = '3.12.12'\nconst PP_BASE = `https://github.com/bjia56/portable-python/releases/download/cpython-v${PYTHON_VERSION}-build.0`\n\nexport function getPythonDownloadUrl(platform: string, arch: string): string {\n switch (platform) {\n case 'linux': {\n const archMap: Record<string, string> = { x64: 'x86_64', arm64: 'aarch64' }\n const a = archMap[arch]\n if (!a) throw new Error(`Unsupported Linux architecture for Python: ${arch}`)\n return `${PP_BASE}/python-headless-${PYTHON_VERSION}-linux-${a}.zip`\n }\n case 'darwin': {\n // universal2 covers both arm64 and x86_64\n return `${PP_BASE}/python-headless-${PYTHON_VERSION}-darwin-universal2.zip`\n }\n default:\n throw new Error(`Unsupported platform for portable Python: ${platform}`)\n }\n}\n\n/**\n * Ensure a portable Python is available.\n * Checks: embedded python → system PATH → download portable.\n *\n * Returns the path to the python3 binary.\n */\nexport async function ensurePython(dataDir: string, logger: IScopedLogger): Promise<string | null> {\n const pythonDir = join(dataDir, 'deps', 'python')\n const pythonBin = join(pythonDir, 'bin', 'python3')\n\n // 1. Already downloaded\n if (existsSync(pythonBin)) {\n logger.debug(`Portable Python found at ${pythonBin}`)\n return pythonBin\n }\n\n // 2. System PATH\n for (const name of ['python3', 'python']) {\n const inPath = findInPath(name)\n if (inPath) {\n logger.info(`Python found in system PATH: ${name}`)\n return inPath\n }\n }\n\n // 3. Download portable python\n logger.info(`Downloading portable Python ${PYTHON_VERSION} (headless)...`)\n\n const depsDir = join(dataDir, 'deps')\n mkdirSync(depsDir, { recursive: true })\n\n const url = getPythonDownloadUrl(process.platform, process.arch)\n const tmpArchive = join(depsDir, 'python-download.zip')\n\n logger.info(` Source: ${url}`)\n\n const response = await fetch(url, { redirect: 'follow' })\n if (!response.ok || !response.body) {\n logger.warn(`Failed to download Python: ${response.status} — ML detection will not be available`)\n return null\n }\n\n const nodeStream = Readable.fromWeb(response.body as any)\n await pipeline(nodeStream, createWriteStream(tmpArchive))\n\n // Extract — zip contains a 'python/' directory\n try {\n execFileSync('unzip', ['-o', '-q', tmpArchive, '-d', depsDir], { stdio: 'pipe' })\n } catch {\n // Fallback: some minimal Linux installs don't have unzip\n execFileSync('python3', ['-m', 'zipfile', '-e', tmpArchive, depsDir], { stdio: 'pipe' })\n }\n\n // Cleanup\n const { unlinkSync } = await import('node:fs')\n unlinkSync(tmpArchive)\n\n if (!existsSync(pythonBin)) {\n logger.warn('Python extraction succeeded but binary not found at expected path')\n return null\n }\n\n chmodSync(pythonBin, 0o755)\n logger.info(`Portable Python ${PYTHON_VERSION} installed at ${pythonBin}`)\n return pythonBin\n}\n\n/**\n * Install Python packages into the portable Python environment.\n */\nexport async function installPythonPackages(\n pythonPath: string,\n packages: readonly string[],\n logger: IScopedLogger,\n): Promise<void> {\n if (packages.length === 0) return\n\n logger.info(`Installing Python packages: ${packages.join(', ')}`)\n try {\n execFileSync(pythonPath, ['-m', 'pip', 'install', '--quiet', ...packages], {\n stdio: 'pipe',\n timeout: 300_000, // 5 minutes for large packages like torch\n })\n logger.info('Python packages installed successfully')\n } catch (err) {\n logger.error(`Failed to install Python packages: ${err instanceof Error ? err.message : err}`)\n throw err\n }\n}\n","type EventCallback<T = unknown> = (data: T) => void\n\nexport class EventBus {\n private listeners = new Map<string, Set<EventCallback>>()\n\n on<T = unknown>(event: string, callback: EventCallback<T>): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set())\n const set = this.listeners.get(event)!\n set.add(callback as EventCallback)\n return () => set.delete(callback as EventCallback)\n }\n\n emit<T = unknown>(event: string, data: T): void {\n const set = this.listeners.get(event)\n if (!set) return\n for (const cb of set) {\n try { cb(data) } catch { /* don't let one listener break others */ }\n }\n }\n\n once<T = unknown>(event: string, callback: EventCallback<T>): () => void {\n const unsub = this.on<T>(event, (data) => {\n unsub()\n callback(data)\n })\n return unsub\n }\n\n removeAllListeners(event?: string): void {\n if (event) this.listeners.delete(event)\n else this.listeners.clear()\n }\n\n listenerCount(event: string): number {\n return this.listeners.get(event)?.size ?? 0\n }\n}\n","import type { ModelDownloadOptions, ModelDownloadResult } from '@camstack/types'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { createHash } from 'node:crypto'\n\n/** Build fetch headers, including HF auth token for huggingface.co URLs */\nfunction buildHeaders(url: string): Record<string, string> {\n const headers: Record<string, string> = { 'User-Agent': 'CamStack/1.0' }\n const hfToken = process.env['HF_TOKEN'] ?? process.env['HUGGING_FACE_HUB_TOKEN']\n if (hfToken && url.includes('huggingface.co')) {\n headers['Authorization'] = `Bearer ${hfToken}`\n }\n return headers\n}\n\n/**\n * Download a single file from a URL to a destination path.\n * Uses native fetch() (Node 22+) which handles redirects natively.\n * Streams to disk with optional progress callback.\n * Returns the destination path. Skips download if file already exists.\n */\nexport async function downloadFile(\n url: string,\n destPath: string,\n onProgress?: (downloaded: number, total: number) => void,\n): Promise<string> {\n if (fs.existsSync(destPath)) return destPath\n\n fs.mkdirSync(path.dirname(destPath), { recursive: true })\n\n // Atomic download: write to .downloading tmp, rename on success\n const tmpPath = destPath + '.downloading'\n\n try {\n const response = await fetch(url, {\n redirect: 'follow',\n headers: buildHeaders(url),\n })\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} downloading ${url}`)\n }\n if (!response.body) {\n throw new Error(`No response body from ${url}`)\n }\n\n const total = parseInt(response.headers.get('content-length') ?? '0', 10)\n let downloaded = 0\n\n const fileStream = fs.createWriteStream(tmpPath)\n const reader = response.body.getReader()\n\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n fileStream.write(value)\n downloaded += value.length\n onProgress?.(downloaded, total)\n }\n } finally {\n fileStream.end()\n await new Promise<void>((resolve, reject) => {\n fileStream.on('finish', resolve)\n fileStream.on('error', reject)\n })\n }\n\n fs.renameSync(tmpPath, destPath)\n return destPath\n } catch (err) {\n // Clean up partial download\n try { fs.unlinkSync(tmpPath) } catch { /* ignore */ }\n throw err\n }\n}\n\n/**\n * Fetch JSON from a URL using native fetch().\n */\nexport async function fetchJson(url: string): Promise<unknown> {\n const response = await fetch(url, {\n redirect: 'follow',\n headers: buildHeaders(url),\n })\n if (!response.ok) {\n throw new Error(`HTTP ${response.status} fetching ${url}`)\n }\n return response.json()\n}\n\n/**\n * Download a model with fallback URLs and optional SHA256 verification.\n * Legacy API preserved for backward compatibility -- delegates to downloadFile().\n */\nexport async function downloadModel(options: ModelDownloadOptions): Promise<ModelDownloadResult> {\n const { url, fallbackUrls = [], destDir, filename, expectedSha256, onProgress } = options\n\n const fname = filename ?? url.split('/').pop() ?? 'model.bin'\n const destPath = path.join(destDir, fname)\n\n // Check cache\n if (fs.existsSync(destPath)) {\n return { filePath: destPath, downloadedBytes: 0, fromCache: true }\n }\n\n fs.mkdirSync(destDir, { recursive: true })\n\n const urls = [url, ...fallbackUrls]\n let lastError: Error | null = null\n\n for (const tryUrl of urls) {\n try {\n await downloadFile(tryUrl, destPath, onProgress)\n\n // Verify SHA256 if provided\n if (expectedSha256) {\n const hash = await computeSha256(destPath)\n if (hash !== expectedSha256) {\n fs.unlinkSync(destPath)\n throw new Error(`SHA256 mismatch: expected ${expectedSha256}, got ${hash}`)\n }\n }\n\n const stat = fs.statSync(destPath)\n return { filePath: destPath, downloadedBytes: stat.size, fromCache: false }\n } catch (e) {\n lastError = e as Error\n if (fs.existsSync(destPath)) fs.unlinkSync(destPath)\n }\n }\n\n throw lastError ?? new Error(`Failed to download model from ${url}`)\n}\n\nasync function computeSha256(filePath: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const hash = createHash('sha256')\n const stream = fs.createReadStream(filePath)\n stream.on('data', (chunk) => hash.update(chunk))\n stream.on('end', () => resolve(hash.digest('hex')))\n stream.on('error', reject)\n })\n}\n","import type { ModelCatalogEntry, ModelFormat, IAddonModelManager, ModelExtraFile } from '@camstack/types'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { downloadFile, fetchJson } from './model-downloader.js'\n\n/**\n * Unified model download service.\n *\n * Handles downloading model files and extra files (labels, dicts) from a\n * catalog of ModelCatalogEntry items. Supports single-file models and\n * directory bundles (e.g., .mlpackage for CoreML).\n *\n * Addons use this via `context.models.ensure(modelId, format)`.\n */\nexport class ModelDownloadService implements IAddonModelManager {\n private readonly catalog: ReadonlyMap<string, ModelCatalogEntry>\n\n constructor(\n private readonly modelsDir: string,\n catalog: readonly ModelCatalogEntry[],\n private readonly onProgress?: (modelId: string, downloaded: number, total: number) => void,\n ) {\n const map = new Map<string, ModelCatalogEntry>()\n for (const entry of catalog) {\n map.set(entry.id, entry)\n }\n this.catalog = map\n }\n\n /**\n * Ensure a model (and its extra files) is downloaded.\n * Returns the local filesystem path to the model file/directory.\n */\n async ensure(modelId: string, format?: ModelFormat): Promise<string> {\n const entry = this.catalog.get(modelId)\n if (!entry) {\n throw new Error(`ModelDownloadService: unknown model \"${modelId}\"`)\n }\n\n // Resolve format: use provided or pick first available\n const selectedFormat = format ?? this.pickDefaultFormat(entry)\n const formatEntry = entry.formats[selectedFormat]\n if (!formatEntry) {\n throw new Error(\n `ModelDownloadService: model \"${modelId}\" has no ${selectedFormat} format`,\n )\n }\n\n // Download extra files first (labels JSON, dict.txt, etc.)\n await this.ensureExtraFiles(modelId)\n\n // Derive local path from URL\n const modelPath = this.modelFilePath(entry, selectedFormat)\n\n if (fs.existsSync(modelPath)) {\n // Validate directory bundles have required Manifest.json\n if (formatEntry.isDirectory) {\n if (!fs.existsSync(path.join(modelPath, 'Manifest.json'))) {\n fs.rmSync(modelPath, { recursive: true, force: true })\n } else {\n return modelPath\n }\n } else {\n return modelPath\n }\n }\n\n fs.mkdirSync(this.modelsDir, { recursive: true })\n\n if (formatEntry.isDirectory) {\n await this.downloadDirectory(\n formatEntry.url,\n modelPath,\n formatEntry.files,\n modelId,\n )\n } else {\n await downloadFile(\n formatEntry.url,\n modelPath,\n this.onProgress\n ? (downloaded, total) => this.onProgress!(modelId, downloaded, total)\n : undefined,\n )\n }\n\n return modelPath\n }\n\n /**\n * Ensure extra files for a model are downloaded.\n * Returns the local paths of all extra files.\n */\n async ensureExtraFiles(modelId: string): Promise<readonly string[]> {\n const entry = this.catalog.get(modelId)\n if (!entry) {\n throw new Error(`ModelDownloadService: unknown model \"${modelId}\"`)\n }\n\n const extras = entry.extraFiles\n if (!extras || extras.length === 0) return []\n\n const paths: string[] = []\n for (const extra of extras) {\n const destPath = path.join(this.modelsDir, extra.filename)\n await downloadFile(extra.url, destPath)\n paths.push(destPath)\n }\n return paths\n }\n\n /** Absolute path to the shared models directory. */\n getModelsDir(): string {\n return this.modelsDir\n }\n\n /** Check if a model file is already present on disk. */\n isDownloaded(modelId: string, format?: ModelFormat): boolean {\n const entry = this.catalog.get(modelId)\n if (!entry) return false\n\n const selectedFormat = format ?? this.pickDefaultFormat(entry)\n const formatEntry = entry.formats[selectedFormat]\n if (!formatEntry) return false\n\n const modelPath = this.modelFilePath(entry, selectedFormat)\n if (!fs.existsSync(modelPath)) return false\n\n // Validate directory bundles\n if (formatEntry.isDirectory) {\n return fs.existsSync(path.join(modelPath, 'Manifest.json'))\n }\n\n return fs.statSync(modelPath).size > 0\n }\n\n /**\n * Legacy API: download a model by ID (delegates to ensure with default format).\n * Required by IAddonModelManager interface.\n */\n async downloadModel(id: string): Promise<string> {\n return this.ensure(id)\n }\n\n /** Get the catalog entry for a model by ID. */\n getEntry(modelId: string): ModelCatalogEntry | undefined {\n return this.catalog.get(modelId)\n }\n\n // ---------------------------------------------------------------------------\n // Private helpers\n // ---------------------------------------------------------------------------\n\n private pickDefaultFormat(entry: ModelCatalogEntry): ModelFormat {\n // Prefer onnx, then others in order\n const priority: ModelFormat[] = ['onnx', 'coreml', 'openvino', 'tflite', 'pt']\n for (const fmt of priority) {\n if (entry.formats[fmt]) return fmt\n }\n // Fallback: first available format\n const first = Object.keys(entry.formats)[0] as ModelFormat | undefined\n if (first) return first\n throw new Error(`ModelDownloadService: model \"${entry.id}\" has no formats`)\n }\n\n private modelFilePath(entry: ModelCatalogEntry, format: ModelFormat): string {\n const formatEntry = entry.formats[format]\n if (!formatEntry) {\n throw new Error(`Model ${entry.id} has no ${format} format`)\n }\n const urlParts = formatEntry.url.split('/')\n const filename = urlParts[urlParts.length - 1] ?? `${entry.id}.${format}`\n return path.join(this.modelsDir, filename)\n }\n\n /**\n * Download a directory bundle (e.g., .mlpackage) from HuggingFace.\n * ATOMIC: downloads to temp dir, renames only on complete success.\n */\n private async downloadDirectory(\n url: string,\n destDir: string,\n knownFiles?: readonly string[],\n modelId?: string,\n ): Promise<void> {\n const match = url.match(/huggingface\\.co\\/([^/]+\\/[^/]+)\\/resolve\\/main\\/(.+)/)\n if (!match) throw new Error(`Cannot parse HuggingFace URL: ${url}`)\n\n const [, repo, dirPath] = match\n\n let filesToDownload: Array<{ relativePath: string; fileUrl: string }>\n\n if (knownFiles && knownFiles.length > 0) {\n filesToDownload = knownFiles.map(f => ({\n relativePath: f,\n fileUrl: `https://huggingface.co/${repo}/resolve/main/${dirPath}/${f}`,\n }))\n } else {\n const hfFiles = await this.listHfFiles(repo!, dirPath!)\n if (hfFiles.length === 0) {\n throw new Error(`No files found in HuggingFace directory: ${dirPath}`)\n }\n filesToDownload = hfFiles.map(f => ({\n relativePath: f.path.substring(dirPath!.length + 1),\n fileUrl: `https://huggingface.co/${repo}/resolve/main/${f.path}`,\n }))\n }\n\n const tmpDir = destDir + '.downloading'\n fs.rmSync(tmpDir, { recursive: true, force: true })\n fs.mkdirSync(tmpDir, { recursive: true })\n\n try {\n for (const file of filesToDownload) {\n const destPath = path.join(tmpDir, file.relativePath)\n fs.mkdirSync(path.dirname(destPath), { recursive: true })\n await downloadFile(file.fileUrl, destPath)\n }\n\n fs.rmSync(destDir, { recursive: true, force: true })\n fs.renameSync(tmpDir, destDir)\n } catch (err) {\n fs.rmSync(tmpDir, { recursive: true, force: true })\n throw err\n }\n }\n\n /** Recursively list all files in a HuggingFace directory via API. */\n private async listHfFiles(\n repo: string,\n dirPath: string,\n ): Promise<Array<{ path: string; size: number }>> {\n const apiUrl = `https://huggingface.co/api/models/${repo}/tree/main/${dirPath}`\n const entries = (await fetchJson(apiUrl)) as any[]\n const files: Array<{ path: string; size: number }> = []\n\n for (const entry of entries) {\n if (entry.type === 'file') {\n files.push({ path: entry.path, size: entry.size ?? entry.lfs?.size ?? 0 })\n } else if (entry.type === 'directory') {\n const subFiles = await this.listHfFiles(repo, entry.path)\n files.push(...subFiles)\n }\n }\n\n return files\n }\n}\n","import type { IPythonEnvironment, PythonProbeResult, PythonEnvReady } from '@camstack/types'\nimport { execFile, spawn } from 'node:child_process'\nimport type { ChildProcess } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\n\nconst execFileAsync = promisify(execFile)\n\nexport class PythonEnvManager implements IPythonEnvironment {\n private venvPath: string\n private cachedProbe: PythonProbeResult | null = null\n\n constructor(private readonly dataDir: string) {\n this.venvPath = path.join(dataDir, '.venv')\n }\n\n async probe(): Promise<PythonProbeResult> {\n if (this.cachedProbe) return this.cachedProbe\n\n // Try python3, then python\n for (const cmd of ['python3', 'python']) {\n try {\n const { stdout } = await execFileAsync(cmd, ['--version'])\n const version = stdout.trim().replace('Python ', '')\n const major = parseInt(version.split('.')[0] ?? '0', 10)\n const minor = parseInt(version.split('.')[1] ?? '0', 10)\n\n if (major < 3 || (major === 3 && minor < 10)) continue\n\n // Get path\n const { stdout: pathOut } = await execFileAsync(cmd, ['-c', 'import sys; print(sys.executable)'])\n\n this.cachedProbe = {\n available: true,\n version,\n path: pathOut.trim(),\n }\n return this.cachedProbe\n } catch { continue }\n }\n\n this.cachedProbe = { available: false }\n return this.cachedProbe\n }\n\n async ensure(options: { packages: readonly string[] }): Promise<PythonEnvReady> {\n const probe = await this.probe()\n if (!probe.available || !probe.path) {\n throw new Error('Python 3.10+ is required but not found on this system')\n }\n\n // Create venv if needed\n if (!fs.existsSync(path.join(this.venvPath, 'bin', 'python'))) {\n await execFileAsync(probe.path, ['-m', 'venv', this.venvPath])\n }\n\n const venvPython = path.join(this.venvPath, 'bin', 'python')\n\n // Install packages\n if (options.packages.length > 0) {\n await execFileAsync(venvPython, ['-m', 'pip', 'install', '-q', ...options.packages])\n }\n\n return {\n pythonPath: venvPython,\n venvPath: this.venvPath,\n spawn: (script: string, args: readonly string[]) => {\n return spawn(venvPython, [script, ...args])\n },\n }\n }\n\n spawn(script: string, args: readonly string[]): ChildProcess {\n const venvPython = path.join(this.venvPath, 'bin', 'python')\n if (!fs.existsSync(venvPython)) {\n throw new Error('Python venv not initialized. Call ensure() first.')\n }\n return spawn(venvPython, [script, ...args])\n }\n}\n","import type { PipelineConfig, PipelineNode, ValidationIssue, ValidationResult } from '@camstack/types'\nimport { AddonLoader } from '@camstack/kernel'\n\nexport type { ValidationIssue, ValidationResult }\n\nexport class PipelineValidator {\n constructor(private readonly loader: AddonLoader) {}\n\n validate(config: PipelineConfig): ValidationResult {\n const errors: ValidationIssue[] = []\n const warnings: ValidationIssue[] = []\n\n // Validate video pipeline\n for (const node of config.video) {\n this.validateNode(node, errors, warnings, [])\n }\n\n // Validate audio\n if (config.audio) {\n this.validateNode(config.audio, errors, warnings, [])\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n }\n }\n\n private validateNode(\n node: PipelineNode,\n errors: ValidationIssue[],\n warnings: ValidationIssue[],\n ancestors: PipelineNode[],\n ): void {\n // Check addon exists\n if (!this.loader.hasAddon(node.addon)) {\n errors.push({\n step: node.step,\n addon: node.addon,\n message: `Addon \"${node.addon}\" is not registered`,\n severity: 'error',\n })\n return\n }\n\n // Check requiredSteps (from addon manifest)\n const registered = this.loader.getAddon(node.addon)\n if (registered) {\n const manifest = registered.declaration\n // Warn if a node appears at root but its addon has inputClasses\n // (This is a simplified check — full implementation would read manifest.requiredSteps)\n void manifest // reserved for future manifest-driven checks\n }\n\n // Validate children recursively\n if (node.children) {\n for (const child of node.children) {\n this.validateNode(child, errors, warnings, [...ancestors, node])\n }\n }\n }\n}\n","import type {\n FrameInput,\n AudioChunkInput,\n CropInput,\n PipelineConfig,\n PipelineNode,\n PipelineResult,\n StepResult,\n DetectorOutput,\n CropperOutput,\n ClassifierOutput,\n SpatialDetection,\n PipelineSlot,\n ICamstackAddon,\n} from '@camstack/types'\nimport { AddonEngineManager } from '@camstack/kernel'\nimport { randomUUID } from 'node:crypto'\n\nexport class PipelineRunner {\n constructor(\n private readonly engineManager: AddonEngineManager,\n private readonly addonConfigs: Map<string, Record<string, unknown>>, // addonId → global config\n ) {}\n\n async run(frame: FrameInput, config: PipelineConfig): Promise<PipelineResult> {\n const startTime = performance.now()\n const results: StepResult[] = []\n const timings: Record<string, number> = {}\n\n // Execute video pipeline root nodes\n for (const rootNode of config.video) {\n await this.executeNode(rootNode, frame, null, results, timings)\n }\n\n // Execute audio node if present (independent)\n if (config.audio) {\n await this.executeNode(config.audio, frame, null, results, timings)\n }\n\n return {\n results,\n totalMs: performance.now() - startTime,\n timings,\n frameTimestamp: frame.timestamp,\n }\n }\n\n /**\n * Run only the audio classification node on an audio chunk.\n * Used by the audio path in DetectionWiringService (separate from video pipeline).\n */\n async runAudioNode(chunk: AudioChunkInput, audioNode: PipelineNode): Promise<PipelineResult> {\n const startTime = performance.now()\n const results: StepResult[] = []\n const timings: Record<string, number> = {}\n const resultId = randomUUID()\n const stepStart = performance.now()\n\n try {\n const globalConfig = this.addonConfigs.get(audioNode.addon) ?? {}\n const engine = await this.engineManager.getOrCreateEngine(\n audioNode.addon, globalConfig, audioNode.configOverride,\n )\n\n if (!('classifyAudio' in engine) || typeof (engine as unknown as Record<string, unknown>)['classifyAudio'] !== 'function') {\n throw new Error(`Addon \"${audioNode.addon}\" has no classifyAudio method`)\n }\n\n const output = await (engine as unknown as { classifyAudio: (input: AudioChunkInput) => Promise<ClassifierOutput> }).classifyAudio(chunk)\n const stepMs = performance.now() - stepStart\n\n const stepResult: StepResult = {\n addon: audioNode.addon,\n slot: 'classifier',\n output,\n resultId,\n inferenceMs: output.inferenceMs,\n preprocessMs: 0,\n totalMs: stepMs,\n }\n results.push(stepResult)\n timings[audioNode.step] = stepMs\n } catch (error: unknown) {\n const stepMs = performance.now() - stepStart\n const message = error instanceof Error ? error.message : String(error)\n results.push({\n addon: audioNode.addon,\n slot: 'classifier',\n output: { classifications: [], inferenceMs: 0, modelId: '' } as unknown as ClassifierOutput,\n resultId,\n inferenceMs: 0,\n preprocessMs: 0,\n totalMs: stepMs,\n error: {\n code: 'ADDON_ERROR',\n message,\n childrenSkipped: true,\n },\n })\n }\n\n return {\n results,\n totalMs: performance.now() - startTime,\n timings,\n frameTimestamp: chunk.timestamp,\n }\n }\n\n private async executeNode(\n node: PipelineNode,\n frame: FrameInput,\n parentDetection: { det: SpatialDetection; resultId: string } | null,\n results: StepResult[],\n timings: Record<string, number>,\n ): Promise<void> {\n const resultId = randomUUID()\n const stepStart = performance.now()\n\n try {\n // Get or create engine for this addon\n const globalConfig = this.addonConfigs.get(node.addon) ?? {}\n const engine = await this.engineManager.getOrCreateEngine(\n node.addon, globalConfig, node.configOverride,\n )\n\n // Determine slot type and execute\n let output: DetectorOutput | CropperOutput | ClassifierOutput\n\n if (parentDetection) {\n // This is a child node — needs crop input\n const cropInput: CropInput = {\n frame,\n roi: parentDetection.det.bbox,\n parentDetection: parentDetection.det,\n }\n\n // Try cropper first, then classifier, then detector\n if ('crop' in engine && typeof (engine as unknown as Record<string, unknown>)['crop'] === 'function') {\n output = await (engine as unknown as { crop: (input: CropInput) => Promise<CropperOutput> }).crop(cropInput)\n } else if ('classify' in engine && typeof (engine as unknown as Record<string, unknown>)['classify'] === 'function') {\n output = await (engine as unknown as { classify: (input: CropInput) => Promise<ClassifierOutput> }).classify(cropInput)\n } else if ('detect' in engine && typeof (engine as unknown as Record<string, unknown>)['detect'] === 'function') {\n // Detector child (e.g., object-detection triggered by motion)\n output = await (engine as unknown as { detect: (input: FrameInput) => Promise<DetectorOutput> }).detect(frame)\n } else {\n throw new Error(`Addon \"${node.addon}\" has no detect/crop/classify method`)\n }\n } else {\n // Root node — full frame\n if ('detect' in engine && typeof (engine as unknown as Record<string, unknown>)['detect'] === 'function') {\n output = await (engine as unknown as { detect: (input: FrameInput) => Promise<DetectorOutput> }).detect(frame)\n } else if ('classify' in engine && typeof (engine as unknown as Record<string, unknown>)['classify'] === 'function') {\n // Audio classifier at root\n const rootCropInput: CropInput = {\n frame,\n roi: { x: 0, y: 0, w: frame.width, h: frame.height },\n parentDetection: { class: '', originalClass: '', score: 1, bbox: { x: 0, y: 0, w: frame.width, h: frame.height } },\n }\n output = await (engine as unknown as { classify: (input: CropInput) => Promise<ClassifierOutput> }).classify(rootCropInput)\n } else {\n throw new Error(`Addon \"${node.addon}\" has no detect/classify method`)\n }\n }\n\n const stepMs = performance.now() - stepStart\n\n // Determine slot type from output shape\n const slot: PipelineSlot =\n 'detections' in output ? 'detector' :\n 'crops' in output ? 'cropper' :\n 'classifier'\n\n const stepResult: StepResult = {\n addon: node.addon,\n slot,\n output,\n parentResultId: parentDetection?.resultId,\n resultId,\n inferenceMs: output.inferenceMs,\n preprocessMs: 0,\n totalMs: stepMs,\n }\n results.push(stepResult)\n timings[node.step] = stepMs\n\n // Process children\n if (node.children?.length) {\n const detections: readonly SpatialDetection[] =\n 'detections' in output ? output.detections :\n 'crops' in output ? output.crops :\n []\n\n // For each detection, find children with matching inputClasses and execute\n await this.executeChildren(node.children, frame, detections, resultId, results, timings)\n }\n } catch (error: unknown) {\n const stepMs = performance.now() - stepStart\n const message = error instanceof Error ? error.message : String(error)\n results.push({\n addon: node.addon,\n slot: 'detector',\n output: { detections: [], inferenceMs: 0, modelId: '' },\n parentResultId: parentDetection?.resultId,\n resultId,\n inferenceMs: 0,\n preprocessMs: 0,\n totalMs: stepMs,\n error: {\n code: 'ADDON_ERROR',\n message,\n childrenSkipped: true,\n },\n })\n }\n }\n\n private async executeChildren(\n children: readonly PipelineNode[],\n frame: FrameInput,\n parentDetections: readonly SpatialDetection[],\n parentResultId: string,\n results: StepResult[],\n timings: Record<string, number>,\n ): Promise<void> {\n // For each parent detection, run all matching children in parallel\n const promises: Promise<void>[] = []\n\n for (const detection of parentDetections) {\n for (const child of children) {\n // TODO: Check inputClasses matching from addon manifest\n // For now, run all children on all detections (caller configures tree correctly)\n promises.push(\n this.executeNode(child, frame, { det: detection, resultId: parentResultId }, results, timings),\n )\n }\n }\n\n await Promise.allSettled(promises)\n }\n}\n","import { fork, spawn, type ChildProcess } from 'node:child_process'\nimport type { IScopedLogger } from '@camstack/types'\nimport type {\n ProcessConfig,\n ProcessStats,\n ManagedProcessStatus,\n ProcessState,\n ProcessEventEmitter,\n} from './interfaces.js'\n\nconst DEFAULT_MAX_RESTARTS = 10\nconst MAX_BACKOFF_MS = 60_000\nconst GRACEFUL_SHUTDOWN_MS = 5_000\n\nexport class ManagedProcess {\n private childProcess: ChildProcess | null = null\n private _state: ProcessState = 'stopped'\n private _startedAt?: number\n private restartTimer?: ReturnType<typeof setTimeout>\n private _restartCount = 0\n private _lastCrashAt?: number\n private _lastCrashError?: string\n\n constructor(\n private readonly config: ProcessConfig,\n private readonly events: ProcessEventEmitter,\n private readonly logger: IScopedLogger,\n ) {}\n\n get state(): ProcessState {\n return this._state\n }\n\n async start(): Promise<void> {\n this._state = 'starting'\n\n try {\n if (this.config.modulePath) {\n this.childProcess = fork(this.config.modulePath, this.config.args ?? [], {\n env: { ...process.env, ...this.config.env },\n stdio: ['pipe', 'pipe', 'pipe', 'ipc'],\n })\n } else if (this.config.command) {\n this.childProcess = spawn(this.config.command, this.config.args ?? [], {\n env: { ...process.env, ...this.config.env },\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n } else {\n throw new Error('No command or modulePath specified')\n }\n\n this.childProcess.stdout?.on('data', (data: Buffer) => {\n this.logger.debug(data.toString().trim())\n })\n\n this.childProcess.stderr?.on('data', (data: Buffer) => {\n this.logger.warn(data.toString().trim())\n })\n\n this.childProcess.on('exit', (code, signal) => {\n const msg = `Process exited: code=${code}, signal=${signal}`\n\n if (code === 0) {\n this.logger.info(msg)\n this._state = 'stopped'\n } else {\n this._lastCrashAt = Date.now()\n this._lastCrashError = msg\n this.logger.error(msg)\n this._state = 'error'\n\n this.events.emitProcessCrashed(\n this.config.id,\n code,\n signal,\n this._restartCount,\n )\n\n const maxRestarts = this.config.maxRestarts ?? DEFAULT_MAX_RESTARTS\n if (this.config.autoRestart && this._restartCount < maxRestarts) {\n this.scheduleRestart()\n }\n }\n\n this.childProcess = null\n })\n\n this.childProcess.on('error', (err: Error) => {\n this.logger.error(`Process error: ${err.message}`)\n this._lastCrashError = err.message\n this._state = 'error'\n })\n\n this._state = 'running'\n this._startedAt = Date.now()\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n this._state = 'error'\n this._lastCrashError = msg\n throw err\n }\n }\n\n async stop(): Promise<void> {\n if (this.restartTimer) {\n clearTimeout(this.restartTimer)\n this.restartTimer = undefined\n }\n\n if (this._state === 'stopped') {\n return\n }\n\n this._state = 'stopping'\n\n if (this.childProcess && !this.childProcess.killed) {\n this.childProcess.kill('SIGTERM')\n\n await new Promise<void>((resolve) => {\n const timeout = setTimeout(() => {\n if (this.childProcess && !this.childProcess.killed) {\n this.childProcess.kill('SIGKILL')\n }\n resolve()\n }, GRACEFUL_SHUTDOWN_MS)\n\n this.childProcess?.on('exit', () => {\n clearTimeout(timeout)\n resolve()\n })\n })\n }\n\n // The exit handler may have already set state to 'stopped' asynchronously\n const currentState = this._state as string\n if (currentState !== 'stopped') {\n this._state = 'stopped'\n }\n }\n\n getStatus(): ManagedProcessStatus {\n return {\n id: this.config.id,\n label: this.config.label,\n state: this._state,\n pid: this.childProcess?.pid,\n stats: this.childProcess?.pid ? this.getStats() : undefined,\n lastCrashAt: this._lastCrashAt,\n lastCrashError: this._lastCrashError,\n restartCount: this._restartCount,\n nextRestartAt: this.restartTimer ? this.getNextRestartTime() : undefined,\n }\n }\n\n private scheduleRestart(): void {\n this._restartCount++\n const delayMs = Math.min(1000 * Math.pow(2, this._restartCount - 1), MAX_BACKOFF_MS)\n\n this.logger.info(`Scheduling restart #${this._restartCount} in ${delayMs}ms`)\n\n this.events.emitProcessRestartScheduled(\n this.config.id,\n this._restartCount,\n delayMs,\n )\n\n this.restartTimer = setTimeout(async () => {\n this.restartTimer = undefined\n try {\n await this.start()\n this.events.emitProcessRestarted(this.config.id, this._restartCount)\n } catch (err) {\n this.logger.error(`Restart failed: ${err}`)\n }\n }, delayMs)\n }\n\n private getStats(): ProcessStats | undefined {\n if (!this.childProcess?.pid) return undefined\n const uptime = this._startedAt ? Date.now() - this._startedAt : 0\n return {\n pid: this.childProcess.pid,\n cpu: 0,\n memory: 0,\n uptime,\n restartCount: this._restartCount,\n }\n }\n\n private getNextRestartTime(): number | undefined {\n if (!this._lastCrashAt) return undefined\n const delayMs = Math.min(1000 * Math.pow(2, this._restartCount - 1), MAX_BACKOFF_MS)\n return this._lastCrashAt + delayMs\n }\n}\n","import { ManagedProcess } from './managed-process.js'\nimport type {\n ProcessConfig,\n ManagedProcessStatus,\n ProcessEventEmitter,\n ProcessLoggerFactory,\n} from './interfaces.js'\n\nexport class ProcessManager {\n private readonly processes: Map<string, ManagedProcess> = new Map()\n\n constructor(\n private readonly events: ProcessEventEmitter,\n private readonly loggerFactory: ProcessLoggerFactory,\n ) {}\n\n register(config: ProcessConfig): ManagedProcess {\n if (this.processes.has(config.id)) {\n throw new Error(`Process already registered: ${config.id}`)\n }\n\n const logger = this.loggerFactory.createLogger(`process:${config.id}`)\n const managed = new ManagedProcess(config, this.events, logger)\n this.processes.set(config.id, managed)\n return managed\n }\n\n async start(id: string): Promise<void> {\n const p = this.get(id)\n await p.start()\n }\n\n async stop(id: string): Promise<void> {\n const p = this.get(id)\n await p.stop()\n }\n\n async restart(id: string): Promise<void> {\n const p = this.get(id)\n await p.stop()\n await p.start()\n }\n\n get(id: string): ManagedProcess {\n const p = this.processes.get(id)\n if (!p) throw new Error(`Process not found: ${id}`)\n return p\n }\n\n listAll(): readonly ManagedProcessStatus[] {\n return [...this.processes.values()].map((p) => p.getStatus())\n }\n\n async shutdownAll(): Promise<void> {\n const running = [...this.processes.values()].filter(\n (p) => p.getStatus().state === 'running',\n )\n\n await Promise.all(running.map((p) => p.stop()))\n }\n}\n","import type {\n StreamNetworkStats,\n ClientNetworkStats,\n DeviceNetworkStats,\n INetworkQualityTracker,\n} from '@camstack/types'\n\nexport type {\n StreamNetworkStats,\n ClientNetworkStats,\n DeviceNetworkStats,\n INetworkQualityTracker,\n}\n\ninterface MutableStreamStats {\n nominalBitrateKbps: number\n samples: number[]\n peakBitrateKbps: number\n packetLossSamples: number[]\n lastUpdated: number\n}\n\nexport class NetworkQualityTracker implements INetworkQualityTracker {\n private readonly devices = new Map<string, {\n streams: Map<string, MutableStreamStats>\n client: (ClientNetworkStats & { lastUpdated: number }) | null\n }>()\n\n private static readonly MAX_SAMPLES = 30 // ~5 min at 10s reporting interval\n\n reportStreamStats(deviceId: string, streamId: string, bitrateKbps: number, packetLoss?: number): void {\n const device = this.getOrCreateDevice(deviceId)\n let stream = device.streams.get(streamId)\n if (!stream) {\n stream = { nominalBitrateKbps: bitrateKbps, samples: [], peakBitrateKbps: 0, packetLossSamples: [], lastUpdated: 0 }\n device.streams.set(streamId, stream)\n }\n\n stream.samples.push(bitrateKbps)\n if (stream.samples.length > NetworkQualityTracker.MAX_SAMPLES) stream.samples.shift()\n\n stream.peakBitrateKbps = Math.max(stream.peakBitrateKbps, bitrateKbps)\n\n if (packetLoss !== undefined) {\n stream.packetLossSamples.push(packetLoss)\n if (stream.packetLossSamples.length > NetworkQualityTracker.MAX_SAMPLES) stream.packetLossSamples.shift()\n }\n\n stream.lastUpdated = Date.now()\n }\n\n reportClientStats(deviceId: string, stats: Omit<ClientNetworkStats, 'lastUpdated'>): void {\n const device = this.getOrCreateDevice(deviceId)\n device.client = { ...stats, lastUpdated: Date.now() }\n }\n\n getDeviceStats(deviceId: string): DeviceNetworkStats | null {\n const device = this.devices.get(deviceId)\n if (!device) return null\n\n const streams: Record<string, StreamNetworkStats> = {}\n for (const [streamId, s] of device.streams) {\n const avg = (arr: number[]) => arr.length === 0 ? 0 : arr.reduce((a, b) => a + b, 0) / arr.length\n streams[streamId] = {\n nominalBitrateKbps: s.nominalBitrateKbps,\n observedBitrateKbps: Math.round(avg(s.samples)),\n peakBitrateKbps: s.peakBitrateKbps,\n packetLossPercent: Math.round(avg(s.packetLossSamples) * 10) / 10,\n lastUpdated: s.lastUpdated,\n }\n }\n\n return { deviceId, streams, client: device.client ?? undefined }\n }\n\n getAllStats(): readonly DeviceNetworkStats[] {\n const results: DeviceNetworkStats[] = []\n for (const deviceId of this.devices.keys()) {\n const stats = this.getDeviceStats(deviceId)\n if (stats) results.push(stats)\n }\n return results\n }\n\n private getOrCreateDevice(deviceId: string) {\n let device = this.devices.get(deviceId)\n if (!device) {\n device = { streams: new Map(), client: null }\n this.devices.set(deviceId, device)\n }\n return device\n }\n}\n","import * as vm from 'node:vm'\nimport * as util from 'node:util'\nimport type {\n IReplEngine,\n IReplContextProvider,\n ReplSessionContext,\n ReplResult,\n} from './interfaces.js'\n\nconst EXECUTION_TIMEOUT_MS = 5000\nconst COMPLETION_TIMEOUT_MS = 1000\n\nexport class ReplEngine implements IReplEngine {\n constructor(\n private readonly contextProvider: IReplContextProvider,\n ) {}\n\n async execute(code: string, context: ReplSessionContext): Promise<ReplResult> {\n const start = Date.now()\n const sandbox = this.buildSandbox(context)\n\n try {\n const vmContext = vm.createContext(sandbox)\n const script = new vm.Script(code)\n let result = script.runInContext(vmContext, { timeout: EXECUTION_TIMEOUT_MS })\n\n // If result is a Promise, await it with timeout\n if (result && typeof result.then === 'function') {\n result = await Promise.race([\n result,\n new Promise((_, reject) =>\n setTimeout(() => reject(new Error('Async timeout (5s)')), EXECUTION_TIMEOUT_MS),\n ),\n ])\n }\n\n const duration = Date.now() - start\n\n if (result === undefined) {\n return { output: 'undefined', type: 'void', duration }\n }\n\n return {\n output: util.inspect(result, {\n depth: 4,\n colors: false,\n maxArrayLength: 50,\n maxStringLength: 1000,\n }),\n type: 'value',\n duration,\n }\n } catch (err: unknown) {\n // Errors thrown inside vm contexts may not be instanceof Error\n // because they use a different Error constructor from the sandbox\n const message =\n err instanceof Error\n ? err.message\n : typeof err === 'object' && err !== null && 'message' in err\n ? String((err as { message: unknown }).message)\n : String(err)\n return {\n output: message,\n type: 'error',\n duration: Date.now() - start,\n }\n }\n }\n\n async getCompletions(partial: string, context: ReplSessionContext): Promise<string[]> {\n const sandbox = this.buildSandbox(context)\n const keys = Object.keys(sandbox)\n\n if (!partial) return keys\n\n const lastDot = partial.lastIndexOf('.')\n if (lastDot === -1) {\n return keys.filter(k => k.startsWith(partial))\n }\n\n // Object property completion: \"device.get\" -> look up device, return matching keys\n const objPath = partial.substring(0, lastDot)\n const propPrefix = partial.substring(lastDot + 1)\n\n try {\n const vmContext = vm.createContext(sandbox)\n const obj = vm.runInContext(objPath, vmContext, { timeout: COMPLETION_TIMEOUT_MS })\n if (obj && typeof obj === 'object') {\n const proto = Object.getPrototypeOf(obj)\n const objKeys = Object.getOwnPropertyNames(obj)\n .concat(Object.getOwnPropertyNames(proto ?? {}))\n .filter(k => k.startsWith(propPrefix))\n return [...new Set(objKeys)].map(k => `${objPath}.${k}`)\n }\n } catch {\n // Ignore errors during completion\n }\n\n return []\n }\n\n private buildSandbox(context: ReplSessionContext): Record<string, unknown> {\n const base: Record<string, unknown> = {\n console: {\n log: (...args: unknown[]) => util.inspect(args),\n warn: (...args: unknown[]) => util.inspect(args),\n },\n JSON,\n Math,\n Date,\n Array,\n Object,\n String,\n Number,\n Boolean,\n Map,\n Set,\n Promise,\n Buffer,\n // Blocked globals\n setTimeout: undefined,\n setInterval: undefined,\n fetch: undefined,\n require: undefined,\n process: undefined,\n // Merge user-provided variables\n ...context.variables,\n }\n\n switch (context.scope.type) {\n case 'system':\n return { ...base, ...this.contextProvider.getSystemSandbox() }\n\n case 'device':\n return { ...base, ...this.contextProvider.getDeviceSandbox(context.scope.deviceId!) }\n\n case 'provider':\n return { ...base, ...this.contextProvider.getProviderSandbox(context.scope.providerId!) }\n\n case 'addon':\n return { ...base, ...this.contextProvider.getAddonSandbox(context.scope.addonId!) }\n\n default:\n return base\n }\n }\n}\n","import type {\n AgentInfo,\n AgentStatus,\n AgentEntry,\n AgentEventEmitter,\n} from './interfaces.js'\n\nexport class AgentRegistry {\n private readonly agents: Map<string, AgentEntry> = new Map()\n private readonly heartbeatIntervals: Map<string, NodeJS.Timeout> = new Map()\n\n constructor(\n private readonly events: AgentEventEmitter,\n private readonly heartbeatTimeoutMs: number = 30000,\n private readonly heartbeatCheckIntervalMs: number = 10000,\n ) {}\n\n /** Register a new agent */\n registerAgent(info: AgentInfo): void {\n const entry: AgentEntry = {\n info,\n state: 'online',\n connectedSince: Date.now(),\n lastHeartbeat: Date.now(),\n activeTaskCount: 0,\n completedTaskCount: 0,\n failedTaskCount: 0,\n }\n\n this.agents.set(info.id, entry)\n this.startHeartbeatCheck(info.id)\n\n this.events.emitAgentRegistered(info.id, [...info.capabilities])\n }\n\n /** Remove agent */\n unregisterAgent(id: string): void {\n const interval = this.heartbeatIntervals.get(id)\n if (interval) {\n clearInterval(interval)\n this.heartbeatIntervals.delete(id)\n }\n\n this.agents.delete(id)\n this.events.emitAgentUnregistered(id)\n }\n\n /** Update heartbeat timestamp */\n heartbeat(id: string): void {\n const entry = this.agents.get(id)\n if (!entry) return\n\n entry.lastHeartbeat = Date.now()\n\n if (entry.state === 'offline') {\n entry.state = 'online'\n this.events.emitAgentOnline(id)\n }\n }\n\n /** Find agents with a specific capability */\n getAgentsWithCapability(capability: string): readonly AgentEntry[] {\n return [...this.agents.values()].filter(\n (a) => a.state === 'online' && a.info.capabilities.includes(capability),\n )\n }\n\n /** Get best agent for a task (least loaded) */\n selectAgent(capability: string, preferredId?: string): AgentEntry | null {\n const capable = this.getAgentsWithCapability(capability)\n if (capable.length === 0) return null\n\n if (preferredId) {\n const preferred = capable.find((a) => a.info.id === preferredId)\n if (preferred) return preferred\n }\n\n // Least loaded: sort by activeTaskCount ascending\n const sorted = [...capable].sort((a, b) => a.activeTaskCount - b.activeTaskCount)\n return sorted[0] ?? null\n }\n\n /** List all agents with status */\n listAgents(): readonly AgentStatus[] {\n return [...this.agents.values()].map((entry) => ({\n id: entry.info.id,\n name: entry.info.name,\n state: entry.state,\n capabilities: [...entry.info.capabilities],\n lastHeartbeat: entry.lastHeartbeat,\n connectedSince: entry.connectedSince,\n resources: entry.info.resources,\n activeTaskCount: entry.activeTaskCount,\n completedTaskCount: entry.completedTaskCount,\n failedTaskCount: entry.failedTaskCount,\n }))\n }\n\n /** Get single agent */\n getAgent(id: string): AgentEntry | null {\n return this.agents.get(id) ?? null\n }\n\n /** Destroy all heartbeat intervals */\n destroy(): void {\n for (const interval of this.heartbeatIntervals.values()) {\n clearInterval(interval)\n }\n this.heartbeatIntervals.clear()\n }\n\n private startHeartbeatCheck(id: string): void {\n const interval = setInterval(() => {\n const entry = this.agents.get(id)\n if (!entry) return\n\n const elapsed = Date.now() - entry.lastHeartbeat\n if (elapsed > this.heartbeatTimeoutMs && entry.state === 'online') {\n entry.state = 'offline'\n this.events.emitAgentOffline(id)\n }\n }, this.heartbeatCheckIntervalMs)\n\n this.heartbeatIntervals.set(id, interval)\n }\n}\n","import type { AgentRegistry } from './agent-registry.js'\nimport type {\n AgentTask,\n AgentTaskResult,\n AgentEntry,\n TaskDispatchOptions,\n AgentEventEmitter,\n} from './interfaces.js'\n\ninterface PendingTask {\n readonly resolve: (result: AgentTaskResult) => void\n readonly reject: (error: Error) => void\n readonly timeout: NodeJS.Timeout\n}\n\nexport class TaskDispatcher {\n private readonly pendingTasks: Map<string, PendingTask> = new Map()\n private readonly localExecutors: Map<\n string,\n (input: Record<string, unknown>) => Promise<Record<string, unknown>>\n > = new Map()\n\n constructor(\n private readonly agentRegistry: AgentRegistry,\n private readonly events: AgentEventEmitter,\n ) {}\n\n /** Dispatch a task to the best available agent */\n async dispatch(task: AgentTask, options?: TaskDispatchOptions): Promise<AgentTaskResult> {\n const capability = options?.capability ?? task.capability\n const agent = this.agentRegistry.selectAgent(capability, options?.preferredAgent)\n\n if (!agent && !options?.remoteOnly) {\n return this.executeLocally(task)\n }\n\n if (!agent) {\n return {\n taskId: task.id,\n agentId: 'none',\n status: 'error',\n error: 'No agent available',\n durationMs: 0,\n }\n }\n\n return this.sendToAgent(task, agent)\n }\n\n /** Register a local executor for a capability (in-process fallback) */\n registerLocalExecutor(\n capability: string,\n executor: (input: Record<string, unknown>) => Promise<Record<string, unknown>>,\n ): void {\n this.localExecutors.set(capability, executor)\n }\n\n /** Called when an agent returns a result */\n handleTaskResult(result: AgentTaskResult): void {\n const pending = this.pendingTasks.get(result.taskId)\n if (pending) {\n clearTimeout(pending.timeout)\n this.pendingTasks.delete(result.taskId)\n pending.resolve(result)\n }\n\n // Update agent stats\n const agent = this.agentRegistry.getAgent(result.agentId)\n if (agent) {\n agent.activeTaskCount--\n if (result.status === 'success') {\n agent.completedTaskCount++\n } else {\n agent.failedTaskCount++\n }\n }\n }\n\n private async executeLocally(task: AgentTask): Promise<AgentTaskResult> {\n const executor = this.localExecutors.get(task.capability)\n if (!executor) {\n return {\n taskId: task.id,\n agentId: 'local',\n status: 'error',\n error: `No local executor for ${task.capability}`,\n durationMs: 0,\n }\n }\n\n const start = Date.now()\n try {\n const output = await executor(task.input)\n return {\n taskId: task.id,\n agentId: 'local',\n status: 'success',\n output,\n durationMs: Date.now() - start,\n }\n } catch (err) {\n return {\n taskId: task.id,\n agentId: 'local',\n status: 'error',\n error: String(err),\n durationMs: Date.now() - start,\n }\n }\n }\n\n private sendToAgent(task: AgentTask, agent: AgentEntry): Promise<AgentTaskResult> {\n agent.activeTaskCount++\n\n return new Promise((resolve) => {\n const timeout = setTimeout(() => {\n this.pendingTasks.delete(task.id)\n agent.activeTaskCount--\n agent.failedTaskCount++\n resolve({\n taskId: task.id,\n agentId: agent.info.id,\n status: 'timeout',\n durationMs: task.timeout,\n error: 'Task timed out',\n })\n }, task.timeout)\n\n this.pendingTasks.set(task.id, { resolve, reject: () => {}, timeout })\n\n this.events.emitTaskDispatched(task.id, agent.info.id, task.capability)\n })\n }\n}\n","import type {\n AgentToHubMessage,\n HubToAgentMessage,\n AgentRegistrationInfo,\n AgentRuntimeStatus,\n} from '@camstack/types'\nimport type { IScopedLogger } from '../logging/scoped-logger.js'\n\nconst RECONNECT_BASE_MS = 1000\nconst RECONNECT_MAX_MS = 30000\nconst HEARTBEAT_INTERVAL_MS = 10_000\n\nexport interface AgentClientConfig {\n readonly hubUrl: string\n readonly token?: string\n readonly logger: IScopedLogger\n readonly registrationInfo: AgentRegistrationInfo\n}\n\nexport type MessageHandler = (msg: HubToAgentMessage) => void\nexport type BinaryHandler = (data: Buffer) => void\nexport type ConnectionHandler = () => void\n\n/**\n * WebSocket client for agent mode. Framework-agnostic (no NestJS).\n * Connects to the hub, sends registration, handles messages,\n * reconnects with exponential backoff.\n */\nexport class AgentClient {\n private ws: import('ws').WebSocket | null = null\n private reconnectAttempt = 0\n private reconnectTimer: NodeJS.Timeout | null = null\n private heartbeatTimer: NodeJS.Timeout | null = null\n private destroyed = false\n\n private readonly messageHandlers: MessageHandler[] = []\n private readonly binaryHandlers: BinaryHandler[] = []\n private readonly connectHandlers: ConnectionHandler[] = []\n private readonly disconnectHandlers: ConnectionHandler[] = []\n\n private readonly logger: IScopedLogger\n private readonly hubUrl: string\n private readonly token?: string\n private readonly registrationInfo: AgentRegistrationInfo\n\n private runtimeStatus: AgentRuntimeStatus = {\n activeCameras: 0,\n cpuPercent: 0,\n memoryPercent: 0,\n fps: {},\n errors: [],\n }\n\n constructor(config: AgentClientConfig) {\n this.hubUrl = config.hubUrl\n this.token = config.token\n this.logger = config.logger\n this.registrationInfo = config.registrationInfo\n }\n\n /** Connect to the hub WebSocket */\n async connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.destroyed = false\n this.doConnect(resolve, reject)\n })\n }\n\n /** Disconnect and stop reconnecting */\n disconnect(): void {\n this.destroyed = true\n this.clearTimers()\n if (this.ws) {\n this.ws.close()\n this.ws = null\n }\n }\n\n /** Send a JSON control message to the hub */\n send(msg: AgentToHubMessage): void {\n if (!this.ws || this.ws.readyState !== 1 /* WebSocket.OPEN */) {\n this.logger.warn('send() called while not connected')\n return\n }\n this.ws.send(JSON.stringify(msg))\n }\n\n /** Send a binary frame to the hub */\n sendBinary(data: Buffer): void {\n if (!this.ws || this.ws.readyState !== 1) {\n return\n }\n this.ws.send(data)\n }\n\n /** Register a handler for JSON messages from hub */\n onMessage(handler: MessageHandler): void {\n this.messageHandlers.push(handler)\n }\n\n /** Register a handler for binary frames from hub */\n onBinaryFrame(handler: BinaryHandler): void {\n this.binaryHandlers.push(handler)\n }\n\n /** Register a handler for successful connection */\n onConnect(handler: ConnectionHandler): void {\n this.connectHandlers.push(handler)\n }\n\n /** Register a handler for disconnection */\n onDisconnect(handler: ConnectionHandler): void {\n this.disconnectHandlers.push(handler)\n }\n\n /** Update the runtime status (used in heartbeat) */\n updateStatus(status: AgentRuntimeStatus): void {\n this.runtimeStatus = status\n }\n\n /** Whether currently connected */\n get connected(): boolean {\n return this.ws?.readyState === 1\n }\n\n private doConnect(\n onConnect?: (value: void) => void,\n onError?: (err: Error) => void,\n ): void {\n if (this.destroyed) return\n\n // Dynamic import ws to keep this file framework-agnostic at the type level\n import('ws').then(({ default: WebSocket }) => {\n if (this.destroyed) return\n\n const url = this.token\n ? `${this.hubUrl}?token=${encodeURIComponent(this.token)}`\n : this.hubUrl\n\n // Accept self-signed certs when connecting over WSS (safe for local LAN)\n const wsOptions = this.hubUrl.startsWith('wss://')\n ? { rejectUnauthorized: false }\n : {}\n\n try {\n this.ws = new WebSocket(url, wsOptions)\n } catch (err) {\n this.scheduleReconnect()\n if (onError) {\n onError(err instanceof Error ? err : new Error(String(err)))\n onError = undefined\n }\n return\n }\n\n this.ws.once('open', () => {\n this.reconnectAttempt = 0\n this.logger.info(`Connected to hub: ${this.hubUrl}`)\n\n // Send registration\n this.send({ type: 'register', info: this.registrationInfo })\n\n // Start heartbeat\n this.startHeartbeat()\n\n for (const h of this.connectHandlers) h()\n\n if (onConnect) {\n onConnect()\n onConnect = undefined\n }\n })\n\n this.ws.on('message', (data: Buffer | string, isBinary: boolean) => {\n const buf = Buffer.isBuffer(data) ? data : Buffer.from(data as unknown as ArrayBuffer)\n if (isBinary) {\n for (const h of this.binaryHandlers) h(buf)\n } else {\n try {\n const msg = JSON.parse(buf.toString()) as HubToAgentMessage\n this.handleBuiltinMessage(msg)\n for (const h of this.messageHandlers) h(msg)\n } catch {\n this.logger.warn('Failed to parse message from hub')\n }\n }\n })\n\n this.ws.once('close', () => {\n this.stopHeartbeat()\n for (const h of this.disconnectHandlers) h()\n if (!this.destroyed) {\n this.logger.warn('Disconnected from hub, scheduling reconnect')\n this.scheduleReconnect()\n }\n })\n\n this.ws.once('error', (err) => {\n this.logger.error('WebSocket error', { message: err.message })\n if (onError) {\n onError(err)\n onError = undefined\n }\n })\n }).catch((err) => {\n this.logger.error('Failed to import ws module', { message: String(err) })\n if (onError) {\n onError(err instanceof Error ? err : new Error(String(err)))\n }\n })\n }\n\n private handleBuiltinMessage(msg: HubToAgentMessage): void {\n if (msg.type === 'ping') {\n this.send({ type: 'pong' })\n }\n }\n\n private scheduleReconnect(): void {\n if (this.destroyed) return\n const delay = Math.min(\n RECONNECT_BASE_MS * Math.pow(2, this.reconnectAttempt),\n RECONNECT_MAX_MS,\n )\n this.reconnectAttempt++\n this.logger.info(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempt})`)\n this.reconnectTimer = setTimeout(() => {\n this.doConnect()\n }, delay)\n }\n\n private startHeartbeat(): void {\n this.stopHeartbeat()\n this.heartbeatTimer = setInterval(() => {\n this.send({ type: 'heartbeat', status: this.runtimeStatus })\n }, HEARTBEAT_INTERVAL_MS)\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer)\n this.heartbeatTimer = null\n }\n }\n\n private clearTimers(): void {\n this.stopHeartbeat()\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer)\n this.reconnectTimer = null\n }\n }\n}\n","import type { ITaskHandler, TaskContext, TaskProgress } from '@camstack/types'\nimport type { IScopedLogger } from '../logging/scoped-logger.js'\nimport type { AgentClient } from './agent-client.js'\n\ninterface RunningTask {\n readonly taskId: string\n readonly taskType: string\n cancelled: boolean\n}\n\n/**\n * Receives task assignments from hub, routes to registered ITaskHandler instances.\n * Maintains handler registry, manages task lifecycle.\n * Framework-agnostic (no NestJS).\n */\nexport class AgentTaskRunner {\n private readonly handlers = new Map<string, ITaskHandler>()\n private readonly runningTasks = new Map<string, RunningTask>()\n private readonly logger: IScopedLogger\n\n constructor(\n private readonly agentId: string,\n private readonly client: AgentClient,\n logger: IScopedLogger,\n ) {\n this.logger = logger.child('TaskRunner')\n }\n\n /** Register a task handler for a given task type */\n registerHandler(handler: ITaskHandler): void {\n if (this.handlers.has(handler.taskType)) {\n this.logger.warn(`Overwriting handler for task type: ${handler.taskType}`)\n }\n this.handlers.set(handler.taskType, handler)\n this.logger.debug(`Registered handler: ${handler.taskType}`)\n }\n\n /** Unregister a task handler */\n unregisterHandler(taskType: string): void {\n this.handlers.delete(taskType)\n }\n\n /** Get all registered task types */\n getTaskTypes(): readonly string[] {\n return [...this.handlers.keys()]\n }\n\n /** Get a handler by task type */\n getHandler(taskType: string): ITaskHandler | undefined {\n return this.handlers.get(taskType)\n }\n\n /**\n * Execute a task dispatched from the hub.\n * Sends result or error back to hub via the AgentClient.\n */\n async executeTask(taskId: string, taskType: string, payload: unknown): Promise<void> {\n const handler = this.handlers.get(taskType)\n if (!handler) {\n this.client.send({\n type: 'task.result',\n taskId,\n success: false,\n error: `No handler registered for task type: ${taskType}`,\n })\n return\n }\n\n const runningTask: RunningTask = { taskId, taskType, cancelled: false }\n this.runningTasks.set(taskId, runningTask)\n\n const context: TaskContext = {\n taskId,\n agentId: this.agentId,\n logger: this.logger.child(taskType),\n reportProgress: (progress: TaskProgress) => {\n this.client.send({ type: 'task.progress', taskId, progress })\n },\n isCancelled: () => runningTask.cancelled,\n }\n\n try {\n const result = await handler.handle(payload, context)\n this.runningTasks.delete(taskId)\n\n if (!runningTask.cancelled) {\n this.client.send({\n type: 'task.result',\n taskId,\n success: true,\n result,\n })\n }\n } catch (err) {\n this.runningTasks.delete(taskId)\n\n this.logger.error(`Task ${taskType} (${taskId}) failed`, {\n message: err instanceof Error ? err.message : String(err),\n })\n\n this.client.send({\n type: 'task.result',\n taskId,\n success: false,\n error: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n /** Cancel a running task */\n async cancelTask(taskId: string): Promise<void> {\n const running = this.runningTasks.get(taskId)\n if (!running) return\n\n running.cancelled = true\n\n const handler = this.handlers.get(running.taskType)\n if (handler?.cancel) {\n try {\n await handler.cancel()\n } catch (err) {\n this.logger.error(`Error cancelling task ${taskId}`, {\n message: err instanceof Error ? err.message : String(err),\n })\n }\n }\n\n this.runningTasks.delete(taskId)\n }\n\n /** Number of currently running tasks */\n get activeTaskCount(): number {\n return this.runningTasks.size\n }\n\n /** Destroy: cancel all running tasks */\n async destroy(): Promise<void> {\n const taskIds = [...this.runningTasks.keys()]\n for (const taskId of taskIds) {\n await this.cancelTask(taskId)\n }\n this.handlers.clear()\n }\n}\n","import type { ITaskHandler, TaskContext } from '@camstack/types'\n\n/**\n * Stub task handler for pipeline.decode.\n * In the full implementation, this would start a StreamBroker for a camera\n * and send decoded frames to the hub via the AgentClient.\n */\nexport class DecodeTaskHandler implements ITaskHandler {\n readonly taskType = 'pipeline.decode'\n readonly description = 'Decode an RTSP stream and produce JPEG frames'\n\n async handle(payload: unknown, context: TaskContext): Promise<unknown> {\n const { logger } = context\n const config = payload as { cameraId?: string; rtspUrl?: string; fps?: number }\n\n if (!config.cameraId || !config.rtspUrl) {\n throw new Error('pipeline.decode requires cameraId and rtspUrl in payload')\n }\n\n logger.info(`Decode task started: camera=${config.cameraId} url=${config.rtspUrl} fps=${config.fps ?? 1}`)\n\n // Stub: actual implementation would start ffmpeg, produce frames,\n // and send them via the AgentClient's sendBinary method.\n return { status: 'started', cameraId: config.cameraId }\n }\n\n async cancel(): Promise<void> {\n // Stub: stop ffmpeg process\n }\n}\n\n/**\n * Stub task handler for pipeline.detect.\n * In the full implementation, this would receive frames (via binary WS),\n * run them through the detection engine, and send results back.\n */\nexport class DetectTaskHandler implements ITaskHandler {\n readonly taskType = 'pipeline.detect'\n readonly description = 'Run object detection on received frames'\n\n async handle(payload: unknown, context: TaskContext): Promise<unknown> {\n const { logger } = context\n const config = payload as {\n cameraId?: string\n modelId?: string\n runtime?: string\n confidence?: number\n }\n\n if (!config.cameraId) {\n throw new Error('pipeline.detect requires cameraId in payload')\n }\n\n logger.info(`Detect task started: camera=${config.cameraId} model=${config.modelId ?? 'default'} runtime=${config.runtime ?? 'auto'}`)\n\n // Stub: actual implementation would subscribe to binary frame stream,\n // run inference, and send detection results back to hub.\n return { status: 'started', cameraId: config.cameraId }\n }\n\n async cancel(): Promise<void> {\n // Stub: stop detection loop\n }\n}\n\n/**\n * Stub task handler for pipeline.record.\n * In the full implementation, this would start recording an RTSP stream\n * to disk in segments and report segment metadata back to the hub.\n */\nexport class RecordTaskHandler implements ITaskHandler {\n readonly taskType = 'pipeline.record'\n readonly description = 'Record an RTSP stream to disk segments'\n\n async handle(payload: unknown, context: TaskContext): Promise<unknown> {\n const { logger } = context\n const config = payload as { cameraId?: string; rtspUrl?: string; storagePath?: string }\n\n if (!config.cameraId || !config.rtspUrl) {\n throw new Error('pipeline.record requires cameraId and rtspUrl in payload')\n }\n\n logger.info(`Record task started: camera=${config.cameraId} url=${config.rtspUrl}`)\n\n // Stub: actual implementation would start ffmpeg copy-mode recording.\n return { status: 'started', cameraId: config.cameraId }\n }\n\n async cancel(): Promise<void> {\n // Stub: stop recording process\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { IScopedLogger, IEventBus } from '@camstack/types'\n\nexport type ElementState = 'stopped' | 'starting' | 'running' | 'stopping' | 'error' | 'disabled'\n\nexport interface ElementStatus {\n state: ElementState\n error?: string\n startedAt?: number\n stoppedAt?: number\n restartCount: number\n uptime: number\n}\n\nconst VALID_TRANSITIONS: Readonly<Record<ElementState, readonly ElementState[]>> = {\n stopped: ['starting', 'disabled'],\n starting: ['running', 'error', 'stopping'],\n running: ['stopping', 'error'],\n stopping: ['stopped', 'error'],\n error: ['starting', 'stopped', 'disabled'],\n disabled: ['stopped'],\n}\n\nexport class LifecycleStateMachine {\n private _state: ElementState = 'stopped'\n private _error?: string\n private _startedAt?: number\n private _stoppedAt?: number\n private _restartCount = 0\n private _hasStartedOnce = false\n\n constructor(\n private readonly elementId: string,\n private readonly elementType: 'provider' | 'device' | 'addon' | 'process',\n private readonly eventBus: IEventBus,\n private readonly logger: IScopedLogger,\n ) {}\n\n get state(): ElementState {\n return this._state\n }\n\n getStatus(): ElementStatus {\n return {\n state: this._state,\n error: this._error,\n startedAt: this._startedAt,\n stoppedAt: this._stoppedAt,\n restartCount: this._restartCount,\n uptime:\n this._state === 'running' && this._startedAt\n ? Date.now() - this._startedAt\n : 0,\n }\n }\n\n transition(to: ElementState, error?: string): boolean {\n const from = this._state\n\n if (!this.isValidTransition(from, to)) {\n this.logger.warn(`Invalid state transition: ${from} → ${to}`)\n return false\n }\n\n this._state = to\n this._error = error\n\n if (to === 'running') {\n if (this._hasStartedOnce) {\n this._restartCount++\n }\n this._hasStartedOnce = true\n this._startedAt = Date.now()\n this._stoppedAt = undefined\n }\n\n if (to === 'stopped' || to === 'error' || to === 'disabled') {\n this._stoppedAt = Date.now()\n }\n\n this.logger.info(`State: ${from} → ${to}${error ? ` (${error})` : ''}`)\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: this.elementType, id: this.elementId },\n category: `${this.elementType}.state.${to}`,\n data: { from, to, error, elementId: this.elementId },\n })\n\n return true\n }\n\n incrementRestartCount(): void {\n this._restartCount++\n }\n\n private isValidTransition(from: ElementState, to: ElementState): boolean {\n return VALID_TRANSITIONS[from]?.includes(to) ?? false\n }\n}\n","import type { FeatureManifest, FeatureFlag } from '@camstack/types'\n\nexport type { FeatureManifest, FeatureFlag }\n\nexport type FeatureConfigReader = {\n readonly features: FeatureManifest\n}\n\nexport class FeatureManager {\n constructor(private readonly configReader: FeatureConfigReader) {}\n\n isEnabled(flag: FeatureFlag): boolean {\n return this.configReader.features[flag]\n }\n\n getManifest(): FeatureManifest {\n return { ...this.configReader.features }\n }\n}\n","import type {\n EventSource,\n SystemEvent,\n EventFilter,\n IEventBus,\n} from '@camstack/types'\n\nexport type { EventSource, SystemEvent, EventFilter }\n\ninterface Subscriber {\n readonly filter: EventFilter\n readonly callback: (event: SystemEvent) => void\n}\n\nclass EventRingBuffer {\n private readonly buffer: Array<SystemEvent | undefined>\n private head = 0\n private count = 0\n\n constructor(private readonly capacity: number) {\n this.buffer = new Array(capacity)\n }\n\n push(event: SystemEvent): void {\n this.buffer[this.head] = event\n this.head = (this.head + 1) % this.capacity\n if (this.count < this.capacity) {\n this.count++\n }\n }\n\n getAll(): readonly SystemEvent[] {\n const result: SystemEvent[] = []\n for (let i = 0; i < this.count; i++) {\n const index = (this.head - 1 - i + this.capacity) % this.capacity\n result.push(this.buffer[index]!)\n }\n return result\n }\n\n query(filter?: EventFilter, limit?: number): readonly SystemEvent[] {\n let result = [...this.getAll()]\n\n if (filter) {\n result = result.filter((event) => matchesFilter(event, filter))\n }\n\n if (limit !== undefined && limit > 0) {\n return result.slice(0, limit)\n }\n\n return result\n }\n}\n\nfunction matchesCategory(eventCategory: string, filterCategory: string): boolean {\n if (filterCategory.endsWith('.*')) {\n const prefix = filterCategory.slice(0, -2)\n return eventCategory.startsWith(prefix + '.') || eventCategory === prefix\n }\n return eventCategory === filterCategory\n}\n\nfunction matchesFilter(event: SystemEvent, filter: EventFilter): boolean {\n if (filter.category && !matchesCategory(event.category, filter.category)) {\n return false\n }\n\n if (filter.source) {\n if (event.source.type !== filter.source.type || event.source.id !== filter.source.id) {\n return false\n }\n }\n\n if (filter.since && event.timestamp < filter.since) {\n return false\n }\n\n return true\n}\n\nexport class SystemEventBus implements IEventBus {\n private readonly ringBuffer: EventRingBuffer\n private readonly subscribers: Subscriber[] = []\n\n constructor(bufferSize: number = 10000) {\n this.ringBuffer = new EventRingBuffer(bufferSize)\n }\n\n emit(event: SystemEvent): void {\n this.ringBuffer.push(event)\n\n for (const subscriber of this.subscribers) {\n if (matchesFilter(event, subscriber.filter)) {\n queueMicrotask(() => {\n try {\n subscriber.callback(event)\n } catch (err) {\n console.error(`[EventBus] Subscriber error for ${event.category}:`, err)\n }\n })\n }\n }\n }\n\n subscribe(filter: EventFilter, handler: (event: SystemEvent) => void): () => void {\n const subscriber: Subscriber = { filter, callback: handler }\n this.subscribers.push(subscriber)\n\n return () => {\n const index = this.subscribers.indexOf(subscriber)\n if (index !== -1) {\n this.subscribers.splice(index, 1)\n }\n }\n }\n\n getRecent(filter?: EventFilter, limit?: number): readonly SystemEvent[] {\n return this.ringBuffer.query(filter, limit)\n }\n}\n","import type { LogLevel, LogEntry, LogFilter } from '@camstack/types'\n\nexport type { LogLevel, LogEntry, LogFilter }\n\nexport class LogRingBuffer {\n private readonly buffer: Array<LogEntry | undefined>\n private head = 0\n private count = 0\n\n constructor(private readonly capacity: number = 10000) {\n this.buffer = new Array(capacity)\n }\n\n push(entry: LogEntry): void {\n this.buffer[this.head] = entry\n this.head = (this.head + 1) % this.capacity\n if (this.count < this.capacity) {\n this.count++\n }\n }\n\n getAll(): LogEntry[] {\n const result: LogEntry[] = []\n\n for (let i = 0; i < this.count; i++) {\n const index = (this.head - 1 - i + this.capacity) % this.capacity\n result.push(this.buffer[index]!)\n }\n\n return result\n }\n\n query(filter: LogFilter): LogEntry[] {\n const all = this.getAll()\n let result = all\n\n if (filter.scope && filter.scope.length > 0) {\n result = result.filter((entry) => {\n for (let i = 0; i < filter.scope!.length; i++) {\n if (entry.scope[i] !== filter.scope![i]) return false\n }\n return true\n })\n }\n\n if (filter.level) {\n result = result.filter((entry) => entry.level === filter.level)\n }\n\n if (filter.since) {\n result = result.filter((entry) => entry.timestamp >= filter.since!)\n }\n\n if (filter.until) {\n result = result.filter((entry) => entry.timestamp <= filter.until!)\n }\n\n if (filter.limit !== undefined && filter.limit > 0) {\n result = result.slice(0, filter.limit)\n }\n\n return result\n }\n}\n","import type { IScopedLogger } from '@camstack/types'\nimport type { LogEntry, LogLevel } from './log-ring-buffer.js'\n\nexport type { IScopedLogger }\n\nexport class ScopedLogger implements IScopedLogger {\n constructor(\n private readonly scope: string[],\n private readonly writeFn: (entry: LogEntry) => void,\n ) {}\n\n debug(message: string, meta?: Record<string, unknown>): void {\n this.write('debug', message, meta)\n }\n\n info(message: string, meta?: Record<string, unknown>): void {\n this.write('info', message, meta)\n }\n\n warn(message: string, meta?: Record<string, unknown>): void {\n this.write('warn', message, meta)\n }\n\n error(message: string, meta?: Record<string, unknown>): void {\n this.write('error', message, meta)\n }\n\n child(childScope: string): IScopedLogger {\n return new ScopedLogger([...this.scope, childScope], this.writeFn)\n }\n\n private write(level: LogLevel, message: string, meta?: Record<string, unknown>): void {\n const entry: LogEntry = {\n timestamp: new Date(),\n level,\n scope: this.scope,\n message,\n ...(meta !== undefined ? { meta } : {}),\n }\n this.writeFn(entry)\n }\n}\n","import { LogRingBuffer, type LogEntry, type LogFilter } from './log-ring-buffer.js'\nimport { ScopedLogger, type IScopedLogger } from './scoped-logger.js'\n\nexport interface ILogDestination {\n initialize(): Promise<void>\n shutdown(): Promise<void>\n write(entry: LogEntry): void\n query?(filter: LogFilter): Promise<readonly LogEntry[]>\n}\n\nexport class LogManager {\n private readonly ringBuffer: LogRingBuffer\n private readonly destinations: ILogDestination[] = []\n private readonly subscribers = new Map<string, { filter: Partial<LogFilter>; callback: (entry: LogEntry) => void }>()\n\n constructor(bufferSize: number = 10000) {\n this.ringBuffer = new LogRingBuffer(bufferSize)\n }\n\n createLogger(scope: string): IScopedLogger {\n return new ScopedLogger([scope], (entry: LogEntry) => {\n this.ringBuffer.push(entry)\n for (const dest of this.destinations) {\n dest.write(entry)\n }\n // Notify real-time subscribers\n for (const [, sub] of this.subscribers) {\n if (this.matchesFilter(entry, sub.filter)) {\n try { sub.callback(entry) } catch { /* subscriber error — ignore */ }\n }\n }\n })\n }\n\n /** Subscribe to live logs matching a filter. Returns an unsubscribe function. */\n subscribe(filter: Partial<LogFilter>, callback: (entry: LogEntry) => void): () => void {\n const id = Math.random().toString(36).slice(2)\n this.subscribers.set(id, { filter, callback })\n return () => { this.subscribers.delete(id) }\n }\n\n private matchesFilter(entry: LogEntry, filter: Partial<LogFilter>): boolean {\n if (filter.scope && filter.scope.length > 0) {\n const entryScope = entry.scope?.[0] ?? ''\n if (!filter.scope.some(s => entryScope === s || entryScope.startsWith(s))) return false\n }\n if (filter.level) {\n const levels: string[] = ['debug', 'info', 'warn', 'error']\n const minIdx = levels.indexOf(filter.level)\n const entryIdx = levels.indexOf(entry.level)\n if (entryIdx < minIdx) return false\n }\n return true\n }\n\n addDestination(dest: ILogDestination): void {\n this.destinations.push(dest)\n }\n\n removeDestination(dest: ILogDestination): void {\n const index = this.destinations.indexOf(dest)\n if (index !== -1) {\n this.destinations.splice(index, 1)\n }\n }\n\n query(filter: LogFilter): LogEntry[] {\n return this.ringBuffer.query(filter)\n }\n}\n","import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { StorageLocationManager, StorageLocationName } from './storage-location-manager.js'\nimport type {\n IStorageProvider as INewStorageProvider,\n ISettingsBackend,\n} from '@camstack/types'\n\n// Legacy interfaces — still used by consumers during migration\nexport interface IStorageProvider {\n initialize(): Promise<void>\n shutdown(): Promise<void>\n getLocation(name: StorageLocationName): IStorageLocation\n export?(locationName: StorageLocationName): Promise<Buffer>\n import?(locationName: StorageLocationName, data: Buffer): Promise<void>\n}\n\nexport interface QueryFilter {\n where?: Record<string, unknown>\n whereIn?: Record<string, unknown[]>\n whereBetween?: Record<string, [unknown, unknown]>\n orderBy?: { field: string; direction: 'asc' | 'desc' }\n limit?: number\n offset?: number\n}\n\nexport interface StorageRecord {\n collection: string\n id: string\n data: Record<string, unknown>\n}\n\nexport interface IStructuredStorage {\n query(collection: string, filter?: QueryFilter): Promise<readonly StorageRecord[]>\n insert(record: StorageRecord): Promise<StorageRecord>\n update(collection: string, id: string, data: Record<string, unknown>): Promise<StorageRecord>\n delete(collection: string, id: string): Promise<void>\n count(collection: string, filter?: QueryFilter): Promise<number>\n}\n\nexport interface IFileStorage {\n readFile(path: string): Promise<Buffer>\n writeFile(path: string, data: Buffer): Promise<void>\n deleteFile(path: string): Promise<void>\n listFiles(prefix?: string): Promise<readonly string[]>\n getFileUrl(path: string): Promise<string>\n exists(path: string): Promise<boolean>\n}\n\nexport interface IStorageLocation {\n structured?: IStructuredStorage\n files?: IFileStorage\n}\n\n/**\n * StorageManager — bridge between legacy code (getLocation/getLocationPath)\n * and the new capability-based storage system.\n *\n * Legacy consumers call getLocation('addon', namespace) to get structured + file storage.\n * This manager builds the response from:\n * - SettingsBackend (for structured queries) — provided by sqlite-settings addon\n * - LocationManager (for file paths) — set during Phase 2 boot\n */\nexport class StorageManager {\n private legacyProvider: IStorageProvider | null = null\n private locationManager: StorageLocationManager | null = null\n private newStorageProvider: INewStorageProvider | null = null\n private settingsBackend: ISettingsBackend | null = null\n\n /** @deprecated Set by legacy capability consumer — use setNewStorageProvider instead */\n setProvider(provider: IStorageProvider | INewStorageProvider): void {\n // Check if it's the new provider (has 'supportedLocations') or legacy (has 'getLocation')\n if ('getLocation' in provider && typeof (provider as any).getLocation === 'function') {\n this.legacyProvider = provider as IStorageProvider\n } else {\n this.newStorageProvider = provider as INewStorageProvider\n }\n }\n\n setNewStorageProvider(provider: INewStorageProvider): void {\n this.newStorageProvider = provider\n }\n\n setSettingsBackend(backend: ISettingsBackend): void {\n this.settingsBackend = backend\n }\n\n getProvider(): IStorageProvider {\n if (this.legacyProvider) return this.legacyProvider\n if (!this.newStorageProvider && !this.settingsBackend && !this.locationManager) {\n throw new Error('No storage provider configured')\n }\n // Return a shim that wraps new providers\n return this.createLegacyShim()\n }\n\n setLocationManager(manager: StorageLocationManager): void {\n this.locationManager = manager\n }\n\n getLocationManager(): StorageLocationManager {\n if (!this.locationManager) {\n throw new Error('StorageLocationManager not initialized')\n }\n return this.locationManager\n }\n\n async initializeLocations(dataPath: string): Promise<void> {\n const { StorageLocationManager } = await import('./storage-location-manager.js')\n const manager = new StorageLocationManager(dataPath)\n await manager.initializeDefaults()\n this.locationManager = manager\n }\n\n getLocationPath(name: StorageLocationName): string {\n return this.getLocationManager().getBackend(name).basePath\n }\n\n /**\n * Get a storage location with optional namespace scoping.\n * Builds IStorageLocation from settingsBackend (structured) + locationManager (files).\n */\n getLocation(name: StorageLocationName | string, namespace?: string): IStorageLocation {\n if (!this.legacyProvider && !this.newStorageProvider && !this.settingsBackend && !this.locationManager) {\n throw new Error('No storage provider configured')\n }\n // Try legacy provider first\n if (this.legacyProvider) {\n try {\n const LEGACY_MAP: Record<string, string> = { config: 'data', events: 'data', addon: 'data' }\n const mappedName = (LEGACY_MAP[name] ?? name) as StorageLocationName\n const location = this.legacyProvider.getLocation(mappedName)\n return namespace ? this.createNamespacedLocation(location, namespace) : location\n } catch {\n // Fall through to new approach\n }\n }\n\n // Build from new providers\n const location: IStorageLocation = {}\n\n // Structured storage from settingsBackend\n if (this.settingsBackend) {\n const backend = this.settingsBackend\n location.structured = {\n async query(collection: string, filter?: QueryFilter) {\n const results = await backend.query(collection as any, filter)\n return results.map(r => ({ collection, id: r.id, data: r.data }))\n },\n async insert(record: StorageRecord) {\n const id = record.id || (await import('node:crypto')).randomUUID()\n await backend.insert(record.collection as any, { id, data: record.data })\n return { ...record, id }\n },\n async update(collection: string, id: string, data: Record<string, unknown>) {\n await backend.update(collection as any, id, data)\n return { collection, id, data }\n },\n async delete(collection: string, id: string) {\n await backend.delete(collection as any, id)\n },\n async count(collection: string, filter?: QueryFilter) {\n return backend.count(collection as any, filter)\n },\n }\n }\n\n // File storage from locationManager\n if (this.locationManager) {\n const LEGACY_MAP: Record<string, string> = { config: 'data', events: 'data', addon: 'data' }\n const mappedName = (LEGACY_MAP[name] ?? name) as StorageLocationName\n try {\n const basePath = this.locationManager.getBackend(mappedName).basePath\n location.files = {\n async readFile(p: string) { return fs.promises.readFile(path.join(basePath, p)) },\n async writeFile(p: string, data: Buffer) {\n const full = path.join(basePath, p)\n await fs.promises.mkdir(path.dirname(full), { recursive: true })\n await fs.promises.writeFile(full, data)\n },\n async deleteFile(p: string) { await fs.promises.rm(path.join(basePath, p), { force: true }) },\n async listFiles(prefix?: string) {\n const dir = prefix ? path.join(basePath, prefix) : basePath\n try { return (await fs.promises.readdir(dir)).map(f => prefix ? `${prefix}/${f}` : f) } catch { return [] }\n },\n async getFileUrl(p: string) { return path.join(basePath, p) },\n async exists(p: string) { try { await fs.promises.access(path.join(basePath, p)); return true } catch { return false } },\n }\n } catch {\n // Location not available\n }\n }\n\n return namespace ? this.createNamespacedLocation(location, namespace) : location\n }\n\n private createLegacyShim(): IStorageProvider {\n const self = this\n return {\n async initialize() {},\n async shutdown() {},\n getLocation(name: StorageLocationName) { return self.getLocation(name) },\n }\n }\n\n private createNamespacedLocation(location: IStorageLocation, namespace: string): IStorageLocation {\n const prefix = namespace.endsWith('/') ? namespace : `${namespace}/`\n\n return {\n structured: location.structured ? {\n async query(collection: string, filter?: QueryFilter) {\n return location.structured!.query(`${prefix}${collection}`, filter)\n },\n async insert(record: StorageRecord) {\n return location.structured!.insert({ ...record, collection: `${prefix}${record.collection}` })\n },\n async update(collection: string, id: string, data: Record<string, unknown>) {\n return location.structured!.update(`${prefix}${collection}`, id, data)\n },\n async delete(collection: string, id: string) {\n return location.structured!.delete(`${prefix}${collection}`, id)\n },\n async count(collection: string, filter?: QueryFilter) {\n return location.structured!.count(`${prefix}${collection}`, filter)\n },\n } : undefined,\n\n files: location.files ? {\n async readFile(p: string) { return location.files!.readFile(`${prefix}${p}`) },\n async writeFile(p: string, data: Buffer) { return location.files!.writeFile(`${prefix}${p}`, data) },\n async deleteFile(p: string) { return location.files!.deleteFile(`${prefix}${p}`) },\n async listFiles(filePrefix?: string) { return location.files!.listFiles(`${prefix}${filePrefix ?? ''}`) },\n async getFileUrl(p: string) { return location.files!.getFileUrl(`${prefix}${p}`) },\n async exists(p: string) { return location.files!.exists(`${prefix}${p}`) },\n } : undefined,\n }\n }\n}\n","import * as jwt from 'jsonwebtoken'\nimport * as bcrypt from 'bcryptjs'\nimport * as crypto from 'node:crypto'\nimport type { ScopedToken, UserRole, TokenPayload } from '@camstack/types'\nimport type { ScopedTokenManager } from './scoped-token-manager.js'\n\nexport type { UserRole, TokenPayload }\n\nexport type AuthConfigReader = {\n get<T>(path: string): T\n update(section: string, data: Record<string, unknown>): void\n}\n\nexport class AuthManager {\n private readonly jwtSecret: string\n private scopedTokenManager: ScopedTokenManager | null = null\n\n constructor(private readonly config: AuthConfigReader) {\n const configured = this.config.get<string>('auth.jwtSecret')\n if (configured) {\n this.jwtSecret = configured\n } else {\n const secret = crypto.randomBytes(32).toString('hex')\n // Persist directly into config.yaml so it survives restarts\n this.config.update('auth', { jwtSecret: secret })\n console.log('[AuthManager] Generated JWT secret and saved to config.yaml (auth.jwtSecret)')\n this.jwtSecret = secret\n }\n }\n\n signToken(payload: Omit<TokenPayload, 'iat' | 'exp'>): string {\n return jwt.sign({ ...payload }, this.jwtSecret, { expiresIn: '24h' })\n }\n\n verifyToken(token: string): TokenPayload {\n return jwt.verify(token, this.jwtSecret) as TokenPayload\n }\n\n async hashPassword(password: string): Promise<string> {\n return bcrypt.hash(password, 10)\n }\n\n async comparePassword(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash)\n }\n\n generateApiKey(): { token: string; hash: string; prefix: string } {\n const token = crypto.randomBytes(32).toString('hex')\n const hash = crypto.createHash('sha256').update(token).digest('hex')\n const prefix = token.slice(0, 8)\n return { token, hash, prefix }\n }\n\n validateApiKey(token: string, storedHash: string): boolean {\n const hash = crypto.createHash('sha256').update(token).digest('hex')\n return hash === storedHash\n }\n\n /**\n * Create a service token for agent/worker authentication.\n * Used when forking workers or when agents register.\n */\n createServiceToken(opts: {\n readonly agentId: string\n readonly role?: string\n readonly expiresIn?: string\n }): string {\n const payload: Record<string, unknown> = {\n userId: opts.agentId,\n username: opts.agentId,\n role: opts.role ?? 'agent',\n type: 'service',\n agentId: opts.agentId,\n allowedProviders: '*',\n allowedDevices: {},\n }\n const expiresIn = (opts.expiresIn ?? '24h') as jwt.SignOptions['expiresIn']\n return jwt.sign(payload as object, this.jwtSecret, { expiresIn })\n }\n\n /**\n * Set the scoped token manager for the auth chain.\n */\n setScopedTokenManager(manager: ScopedTokenManager): void {\n this.scopedTokenManager = manager\n }\n\n /**\n * Validate a scoped token string.\n * Returns the token record if valid, null otherwise.\n */\n async validateScopedToken(rawToken: string): Promise<ScopedToken | null> {\n if (!this.scopedTokenManager) {\n return null\n }\n return this.scopedTokenManager.validate(rawToken)\n }\n\n /**\n * Check whether a scoped token grants access to a given addon/route/capability.\n */\n matchesScopedTokenScope(\n token: ScopedToken,\n addonId?: string,\n routePath?: string,\n capability?: string,\n ): boolean {\n if (!this.scopedTokenManager) {\n return false\n }\n return this.scopedTokenManager.matchesScope(token, addonId, routePath, capability)\n }\n}\n","import * as crypto from 'node:crypto'\nimport type { AuthManager, UserRole } from './auth-manager.js'\nimport type { IStructuredStorage, StorageRecord, QueryFilter } from '../storage/storage-manager.js'\n\nexport interface ApiKeyRecord {\n id: string\n label: string\n role: UserRole\n allowedProviders: string[] | '*'\n allowedDevices: Record<string, string[] | '*'>\n tokenHash: string\n tokenPrefix: string\n createdAt: number\n lastUsedAt?: number\n}\n\ninterface CreateApiKeyInput {\n label: string\n role: UserRole\n allowedProviders?: string[] | '*'\n allowedDevices?: Record<string, string[] | '*'>\n}\n\nconst API_KEYS_COLLECTION = 'api_keys'\n\nexport type ApiKeyStorageAccess = {\n getStructuredStorage(): IStructuredStorage\n}\n\nexport class ApiKeyManager {\n constructor(\n private readonly storageAccess: ApiKeyStorageAccess,\n private readonly auth: AuthManager,\n ) {}\n\n private get structured(): IStructuredStorage {\n return this.storageAccess.getStructuredStorage()\n }\n\n async create(input: CreateApiKeyInput): Promise<{ record: ApiKeyRecord; token: string }> {\n const { token, hash, prefix } = this.auth.generateApiKey()\n const now = Date.now()\n\n const record: ApiKeyRecord = {\n id: crypto.randomUUID(),\n label: input.label,\n role: input.role,\n allowedProviders: input.allowedProviders ?? '*',\n allowedDevices: input.allowedDevices ?? {},\n tokenHash: hash,\n tokenPrefix: prefix,\n createdAt: now,\n }\n\n await this.structured.insert({\n collection: API_KEYS_COLLECTION,\n id: record.id,\n data: record as unknown as Record<string, unknown>,\n })\n\n return { record, token }\n }\n\n async validateToken(token: string): Promise<ApiKeyRecord | null> {\n const allKeys = await this.structured.query(API_KEYS_COLLECTION)\n\n for (const entry of allKeys) {\n const record = entry.data as unknown as ApiKeyRecord\n if (this.auth.validateApiKey(token, record.tokenHash)) {\n const updatedData: Record<string, unknown> = {\n ...record,\n lastUsedAt: Date.now(),\n }\n await this.structured.update(API_KEYS_COLLECTION, record.id, updatedData)\n return { ...record, lastUsedAt: updatedData.lastUsedAt as number }\n }\n }\n\n return null\n }\n\n async listAll(): Promise<Omit<ApiKeyRecord, 'tokenHash'>[]> {\n const results = await this.structured.query(API_KEYS_COLLECTION)\n return results.map((r) => {\n const { tokenHash, ...rest } = r.data as unknown as ApiKeyRecord\n return rest\n })\n }\n\n async revoke(id: string): Promise<void> {\n await this.structured.delete(API_KEYS_COLLECTION, id)\n }\n\n async findById(id: string): Promise<ApiKeyRecord | null> {\n const results = await this.structured.query(API_KEYS_COLLECTION, {\n where: { id },\n })\n\n if (results.length === 0) {\n return null\n }\n\n return results[0]!.data as unknown as ApiKeyRecord\n }\n}\n","import * as crypto from 'node:crypto'\nimport type { AuthManager, UserRole } from './auth-manager.js'\nimport type { IStructuredStorage } from '../storage/storage-manager.js'\nimport type { UserRecord } from '@camstack/types'\n\nexport type { UserRecord }\n\ninterface CreateUserInput {\n username: string\n password: string\n role: UserRole\n allowedProviders?: string[] | '*'\n allowedDevices?: Record<string, string[] | '*'>\n}\n\ntype UpdatableUserFields = Partial<Pick<UserRecord, 'role' | 'allowedProviders' | 'allowedDevices'>>\n\nconst USERS_COLLECTION = 'users'\n\nexport type UserStorageAccess = {\n getStructuredStorage(): IStructuredStorage\n}\n\nexport type UserConfigReader = {\n get<T>(path: string): T\n}\n\nexport class UserManager {\n constructor(\n private readonly storageAccess: UserStorageAccess,\n private readonly auth: AuthManager,\n private readonly config: UserConfigReader,\n ) {}\n\n private get structured(): IStructuredStorage {\n return this.storageAccess.getStructuredStorage()\n }\n\n async create(input: CreateUserInput): Promise<UserRecord> {\n const existing = await this.findByUsername(input.username)\n if (existing) {\n throw new Error(`User with username \"${input.username}\" already exists`)\n }\n\n const passwordHash = await this.auth.hashPassword(input.password)\n const now = Date.now()\n const record: UserRecord = {\n id: crypto.randomUUID(),\n username: input.username,\n passwordHash,\n role: input.role,\n allowedProviders: input.allowedProviders ?? '*',\n allowedDevices: input.allowedDevices ?? {},\n createdAt: now,\n updatedAt: now,\n }\n\n await this.structured.insert({\n collection: USERS_COLLECTION,\n id: record.id,\n data: record as unknown as Record<string, unknown>,\n })\n\n return record\n }\n\n async findByUsername(username: string): Promise<UserRecord | null> {\n const results = await this.structured.query(USERS_COLLECTION, {\n where: { username },\n })\n\n if (results.length === 0) {\n return null\n }\n\n return results[0]!.data as unknown as UserRecord\n }\n\n async findById(id: string): Promise<UserRecord | null> {\n const results = await this.structured.query(USERS_COLLECTION, {\n where: { id },\n })\n\n if (results.length === 0) {\n return null\n }\n\n return results[0]!.data as unknown as UserRecord\n }\n\n async validateCredentials(username: string, password: string): Promise<UserRecord | null> {\n const user = await this.findByUsername(username)\n if (!user) {\n return null\n }\n\n const valid = await this.auth.comparePassword(password, user.passwordHash)\n return valid ? user : null\n }\n\n async listAll(): Promise<Omit<UserRecord, 'passwordHash'>[]> {\n const results = await this.structured.query(USERS_COLLECTION)\n return results.map((r) => {\n const { passwordHash, ...rest } = r.data as unknown as UserRecord\n return rest\n })\n }\n\n async update(id: string, data: UpdatableUserFields): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new Error(`User with id \"${id}\" not found`)\n }\n\n const updatedData: Record<string, unknown> = {\n ...existing,\n ...data,\n updatedAt: Date.now(),\n }\n\n await this.structured.update(USERS_COLLECTION, id, updatedData)\n }\n\n async delete(id: string): Promise<void> {\n await this.structured.delete(USERS_COLLECTION, id)\n }\n\n async resetPassword(id: string, newPassword: string): Promise<void> {\n const existing = await this.findById(id)\n if (!existing) {\n throw new Error(`User with id \"${id}\" not found`)\n }\n\n const passwordHash = await this.auth.hashPassword(newPassword)\n const updatedData: Record<string, unknown> = {\n ...existing,\n passwordHash,\n updatedAt: Date.now(),\n }\n\n await this.structured.update(USERS_COLLECTION, id, updatedData)\n }\n\n async ensureAdminExists(): Promise<void> {\n const adminUsername = this.config.get<string>('auth.adminUsername')\n const adminPassword = this.config.get<string>('auth.adminPassword')\n\n if (!adminUsername || !adminPassword) {\n return\n }\n\n const existing = await this.findByUsername(adminUsername)\n if (existing) {\n return\n }\n\n await this.create({\n username: adminUsername,\n password: adminPassword,\n role: 'super_admin',\n allowedProviders: '*',\n allowedDevices: {},\n })\n }\n}\n","import * as crypto from 'node:crypto'\nimport type { ScopedToken, TokenScope } from '@camstack/types'\nimport type { IStructuredStorage, StorageRecord } from '../storage/storage-manager.js'\n\nconst TOKENS_COLLECTION = 'scoped_tokens'\nconst TOKEN_PREFIX = 'cst_'\n\n/**\n * Manages scoped API tokens with restricted addon/route/capability access.\n * Framework-agnostic — dependencies injected via constructor.\n */\nexport class ScopedTokenManager {\n constructor(private readonly storage: IStructuredStorage) {}\n\n /**\n * Create a new scoped token. Returns the raw token string (shown once)\n * and the stored record (with hash, not the raw token).\n */\n async create(\n userId: string,\n name: string,\n scopes: TokenScope[],\n expiresAt?: number,\n ): Promise<{ token: string; record: ScopedToken }> {\n const rawHex = crypto.randomBytes(32).toString('hex')\n const rawToken = `${TOKEN_PREFIX}${rawHex}`\n const tokenHash = crypto.createHash('sha256').update(rawToken).digest('hex')\n const tokenPrefix = rawToken.slice(0, 12)\n\n const record: ScopedToken = {\n id: crypto.randomUUID(),\n userId,\n name,\n tokenHash,\n tokenPrefix,\n scopes: scopes.map((s) => ({ ...s })),\n expiresAt,\n lastUsedAt: undefined,\n createdAt: Date.now(),\n }\n\n await this.storage.insert({\n collection: TOKENS_COLLECTION,\n id: record.id,\n data: record as unknown as Record<string, unknown>,\n })\n\n return { token: rawToken, record }\n }\n\n /**\n * Validate a raw token string. Returns the token record if valid, null otherwise.\n */\n async validate(rawToken: string): Promise<ScopedToken | null> {\n if (!rawToken.startsWith(TOKEN_PREFIX)) {\n return null\n }\n\n const tokenHash = crypto.createHash('sha256').update(rawToken).digest('hex')\n const results = await this.storage.query(TOKENS_COLLECTION, {\n where: { tokenHash },\n })\n\n if (results.length === 0) {\n return null\n }\n\n const record = results[0]!.data as unknown as ScopedToken\n if (record.expiresAt !== undefined && record.expiresAt !== null && Date.now() > record.expiresAt) {\n return null\n }\n\n // Update last used timestamp (fire and forget)\n this.updateLastUsed(record.id).catch(() => {})\n\n return record\n }\n\n /**\n * Check whether a token's scopes grant access to the given addon, route, or capability.\n */\n matchesScope(\n token: ScopedToken,\n addonId?: string,\n routePath?: string,\n capability?: string,\n ): boolean {\n for (const scope of token.scopes) {\n switch (scope.type) {\n case 'addon':\n if (addonId && scope.target === addonId) return true\n break\n case 'route-prefix':\n if (routePath && routePath.startsWith(scope.target)) return true\n break\n case 'capability':\n if (capability && scope.target === capability) return true\n break\n }\n }\n return false\n }\n\n /**\n * Revoke a token by ID.\n */\n async revoke(tokenId: string): Promise<void> {\n await this.storage.delete(TOKENS_COLLECTION, tokenId)\n }\n\n /**\n * List all tokens for a user (without exposing the raw token).\n */\n async listForUser(userId: string): Promise<ScopedToken[]> {\n const results = await this.storage.query(TOKENS_COLLECTION, {\n where: { userId },\n })\n return results.map((r: StorageRecord) => r.data as unknown as ScopedToken)\n }\n\n /**\n * Update the lastUsedAt timestamp for a token.\n */\n async updateLastUsed(tokenId: string): Promise<void> {\n const results = await this.storage.query(TOKENS_COLLECTION, {\n where: { id: tokenId },\n })\n if (results.length === 0) return\n\n const existing = results[0]!.data as unknown as ScopedToken\n await this.storage.update(TOKENS_COLLECTION, tokenId, {\n ...existing,\n lastUsedAt: Date.now(),\n } as unknown as Record<string, unknown>)\n }\n}\n","import type { INotificationOutput, Notification } from '@camstack/types'\nimport type { IScopedLogger } from '../logging/scoped-logger.js'\nimport type { CapabilityRegistry } from '@camstack/kernel'\n\n/**\n * Central notification service that routes notifications to configured outputs.\n * Framework-agnostic — dependencies injected via constructor.\n *\n * Outputs are resolved from the CapabilityRegistry's 'notification-output'\n * collection on each call (proxy pattern). Falls back to a local map\n * when no registry is provided (backward compat).\n */\nexport class NotificationService {\n private readonly localOutputs = new Map<string, INotificationOutput>()\n private readonly routing = new Map<string, string[]>()\n private readonly rateLimits = new Map<string, number>()\n private readonly lastSent = new Map<string, number>()\n private registry: CapabilityRegistry | null = null\n\n constructor(private readonly logger: IScopedLogger) {}\n\n /** Set the registry for live output lookup. Called once during boot. */\n setRegistry(registry: CapabilityRegistry): void {\n this.registry = registry\n }\n\n /** Resolve all outputs — prefers registry, falls back to local map */\n private get outputs(): ReadonlyMap<string, INotificationOutput> {\n if (this.registry) {\n const collection = this.registry.getCollection<INotificationOutput>('notification-output')\n const map = new Map<string, INotificationOutput>()\n for (const output of collection) {\n map.set(output.id, output)\n }\n return map\n }\n return this.localOutputs\n }\n\n /** @deprecated Use registry-based resolution. Kept for backward compat only. */\n addOutput(output: INotificationOutput): void {\n this.localOutputs.set(output.id, output)\n this.logger.info(`Notification output added: ${output.name} (${output.id})`)\n }\n\n /** @deprecated Use registry-based resolution. Kept for backward compat only. */\n removeOutput(id: string): void {\n this.localOutputs.delete(id)\n this.logger.info(`Notification output removed: ${id}`)\n }\n\n setRouting(category: string, outputIds: string[]): void {\n this.routing.set(category, [...outputIds])\n }\n\n setRateLimit(category: string, minIntervalMs: number): void {\n this.rateLimits.set(category, minIntervalMs)\n }\n\n async notify(notification: Notification): Promise<void> {\n const { category, deviceId } = notification\n\n // Rate limit check\n const rateLimitKey = deviceId ? `${category}:${deviceId}` : category\n const minInterval = this.rateLimits.get(category) ?? 0\n if (minInterval > 0) {\n const last = this.lastSent.get(rateLimitKey) ?? 0\n if (notification.timestamp - last < minInterval) {\n this.logger.debug(`Rate limited: ${rateLimitKey}`)\n return\n }\n }\n\n // Determine target outputs\n const targetIds = this.routing.get(category) ?? this.routing.get('*') ?? []\n if (targetIds.length === 0) {\n this.logger.debug(`No routing configured for category \"${category}\"`)\n return\n }\n\n const currentOutputs = this.outputs\n\n // Update last-sent timestamp\n this.lastSent.set(rateLimitKey, notification.timestamp)\n\n // Send to all targets in parallel with error isolation\n await Promise.allSettled(\n targetIds\n .map((id) => currentOutputs.get(id))\n .filter((output): output is INotificationOutput => output !== undefined)\n .map(async (output) => {\n try {\n await output.send(notification)\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n this.logger.error(`Notification output \"${output.id}\" failed: ${msg}`)\n }\n }),\n )\n\n return undefined\n }\n\n getOutputs(): ReadonlyArray<{ id: string; name: string; icon: string }> {\n return Array.from(this.outputs.values()).map(({ id, name, icon }) => ({ id, name, icon }))\n }\n\n getRouting(): ReadonlyMap<string, string[]> {\n return this.routing\n }\n\n getOutput(id: string): INotificationOutput | undefined {\n return this.outputs.get(id)\n }\n}\n","import type { Toast } from '@camstack/types'\n\nexport type Unsubscribe = () => void\n\ninterface ListenerEntry {\n readonly userId: string\n readonly callback: (toast: Toast) => void\n}\n\n/**\n * Service for broadcasting toast notifications to connected UI clients.\n * Framework-agnostic — integrates with tRPC subscriptions via subscribe().\n */\nexport class ToastService {\n private readonly listeners = new Map<string, ListenerEntry>()\n\n /**\n * Subscribe to toast events for a specific user.\n * Returns an unsubscribe function.\n */\n subscribe(connectionId: string, userId: string, callback: (toast: Toast) => void): Unsubscribe {\n this.listeners.set(connectionId, { userId, callback })\n return () => {\n this.listeners.delete(connectionId)\n }\n }\n\n /**\n * Broadcast a toast to all connected clients.\n */\n broadcast(toast: Toast): void {\n for (const entry of this.listeners.values()) {\n entry.callback(toast)\n }\n }\n\n /**\n * Send a toast to a specific user's connections only.\n */\n sendToUser(userId: string, toast: Toast): void {\n for (const entry of this.listeners.values()) {\n if (entry.userId === userId) {\n entry.callback(toast)\n }\n }\n }\n}\n","import type { IAddonHttpRoute, IAddonRouteProvider } from '@camstack/types'\n\ninterface RouteMatch {\n readonly route: IAddonHttpRoute\n readonly addonId: string\n readonly params: Record<string, string>\n}\n\ninterface RegisteredRoute {\n readonly addonId: string\n readonly route: IAddonHttpRoute\n /** Full path including /addon/{addonId}/ prefix */\n readonly fullPath: string\n}\n\n/**\n * Registry for dynamic HTTP routes registered by addons.\n * Framework-agnostic — the server HTTP layer queries this registry to dispatch requests.\n */\nexport class AddonRouteRegistry {\n private readonly routes = new Map<string, RegisteredRoute[]>()\n\n /**\n * Register all routes from an addon's route provider.\n */\n registerRoutes(addonId: string, provider: IAddonRouteProvider): void {\n const addonRoutes = provider.getRoutes()\n const registered: RegisteredRoute[] = addonRoutes.map((route) => {\n const normalizedPath = route.path.startsWith('/') ? route.path : `/${route.path}`\n return {\n addonId,\n route,\n fullPath: `/addon/${addonId}${normalizedPath}`,\n }\n })\n this.routes.set(addonId, registered)\n }\n\n /**\n * Unregister all routes for an addon.\n */\n unregisterRoutes(addonId: string): void {\n this.routes.delete(addonId)\n }\n\n /**\n * Match an incoming request method + path to a registered route.\n * Supports simple path parameters (e.g., /items/:id).\n */\n matchRoute(method: string, path: string): RouteMatch | null {\n const normalizedMethod = method.toUpperCase()\n\n for (const registeredRoutes of this.routes.values()) {\n for (const entry of registeredRoutes) {\n if (entry.route.method !== normalizedMethod) continue\n\n const params = matchPath(entry.fullPath, path)\n if (params !== null) {\n return {\n route: entry.route,\n addonId: entry.addonId,\n params,\n }\n }\n }\n }\n\n return null\n }\n\n /**\n * List all registered routes across all addons.\n */\n listRoutes(): ReadonlyArray<{ addonId: string; method: string; path: string; access: string; description?: string }> {\n const result: Array<{ addonId: string; method: string; path: string; access: string; description?: string }> = []\n for (const registeredRoutes of this.routes.values()) {\n for (const entry of registeredRoutes) {\n result.push({\n addonId: entry.addonId,\n method: entry.route.method,\n path: entry.fullPath,\n access: entry.route.access,\n description: entry.route.description,\n })\n }\n }\n return result\n }\n}\n\n/**\n * Match a route pattern against an actual path.\n * Supports :param segments (e.g., /addon/:addonId/items/:id).\n * Returns extracted params or null if no match.\n */\nfunction matchPath(pattern: string, path: string): Record<string, string> | null {\n const patternParts = pattern.split('/').filter(Boolean)\n const pathParts = path.split('/').filter(Boolean)\n\n if (patternParts.length !== pathParts.length) {\n return null\n }\n\n const params: Record<string, string> = {}\n\n for (let i = 0; i < patternParts.length; i++) {\n const patternPart = patternParts[i]!\n const pathPart = pathParts[i]!\n\n if (patternPart.startsWith(':')) {\n params[patternPart.slice(1)] = pathPart\n } else if (patternPart !== pathPart) {\n return null\n }\n }\n\n return params\n}\n","import { randomUUID } from 'node:crypto'\nimport type { IScopedLogger, IEventBus, LoggerFactory } from '@camstack/types'\n\nexport interface IRegisteredDevice {\n readonly id: string\n readonly name: string\n readonly providerId: string\n readonly capabilities: readonly string[]\n}\n\nexport class DeviceRegistry<T extends IRegisteredDevice = IRegisteredDevice> {\n private readonly devices = new Map<string, T>()\n private readonly logger: IScopedLogger\n\n constructor(\n private readonly eventBus: IEventBus,\n loggingService: LoggerFactory,\n ) {\n this.logger = loggingService.createLogger('device-registry')\n }\n\n registerDevice(device: T): void {\n this.devices.set(device.id, device)\n this.logger.info(`Device registered: ${device.id} (${device.name})`)\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'core', id: 'device-registry' },\n category: 'device.registered',\n data: { deviceId: device.id, name: device.name, providerId: device.providerId },\n })\n }\n\n unregisterDevice(id: string): void {\n const device = this.devices.get(id)\n if (!device) {\n return\n }\n\n this.devices.delete(id)\n this.logger.info(`Device unregistered: ${id}`)\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'core', id: 'device-registry' },\n category: 'device.unregistered',\n data: { deviceId: id },\n })\n }\n\n getDevice(id: string): T | null {\n return this.devices.get(id) ?? null\n }\n\n listDevices(): T[] {\n return Array.from(this.devices.values())\n }\n\n getDevicesByProvider(providerId: string): T[] {\n return Array.from(this.devices.values()).filter(\n (device) => device.providerId === providerId,\n )\n }\n\n getDevicesWithCapability(cap: string): T[] {\n return Array.from(this.devices.values()).filter((device) =>\n device.capabilities.includes(cap),\n )\n }\n\n registerProviderDevices(providerId: string, devices: readonly T[]): void {\n for (const device of devices) {\n this.registerDevice(device)\n }\n this.logger.info(`Bulk registered ${devices.length} devices for provider ${providerId}`)\n }\n\n unregisterProviderDevices(providerId: string): void {\n const providerDevices = this.getDevicesByProvider(providerId)\n for (const device of providerDevices) {\n this.unregisterDevice(device.id)\n }\n this.logger.info(`Bulk unregistered ${providerDevices.length} devices for provider ${providerId}`)\n }\n}\n","export interface IDeviceCapability {\n kind: string\n}\n\nexport interface CapabilityBinding {\n source: 'native' | 'addon' | 'disabled'\n addonId?: string\n config?: Record<string, unknown>\n}\n\nexport interface IResolvableDevice {\n readonly id: string\n readonly capabilities: string[]\n getCapability<T extends IDeviceCapability>(cap: string): T | null\n}\n\nexport interface IAddonRegistryAccess {\n getAddon(addonId: string): unknown | null\n}\n\nexport class CapabilityResolver {\n private readonly bindings = new Map<\n string,\n Partial<Record<string, CapabilityBinding>>\n >()\n\n constructor(\n private readonly addonRegistry: IAddonRegistryAccess,\n ) {}\n\n resolve<T extends IDeviceCapability>(\n device: IResolvableDevice,\n cap: string,\n ): T | null {\n const deviceBindings = this.bindings.get(device.id)\n const binding = deviceBindings?.[cap]\n\n if (binding) {\n if (binding.source === 'disabled') {\n return null\n }\n\n if (binding.source === 'addon' && binding.addonId) {\n const addon = this.addonRegistry.getAddon(binding.addonId)\n if (addon && typeof (addon as any).getCapabilityForDevice === 'function') {\n return (\n (addon as any).getCapabilityForDevice(device, cap, binding.config) ?? null\n )\n }\n return null\n }\n }\n\n // native or no explicit binding -- delegate to device\n return device.getCapability<T>(cap)\n }\n\n setBinding(\n deviceId: string,\n cap: string,\n binding: CapabilityBinding,\n ): void {\n const existing = this.bindings.get(deviceId) ?? {}\n this.bindings.set(deviceId, { ...existing, [cap]: binding })\n }\n\n removeBinding(deviceId: string, cap: string): void {\n const existing = this.bindings.get(deviceId)\n if (!existing) {\n return\n }\n const updated = { ...existing }\n delete updated[cap]\n this.bindings.set(deviceId, updated)\n }\n\n getBindings(\n deviceId: string,\n ): Partial<Record<string, CapabilityBinding>> {\n return this.bindings.get(deviceId) ?? {}\n }\n\n getEffectiveCapabilities(device: IResolvableDevice): string[] {\n const deviceBindings = this.bindings.get(device.id) ?? {}\n\n const result: string[] = []\n\n // Include native capabilities that are not disabled\n for (const cap of device.capabilities) {\n const binding = deviceBindings[cap]\n if (!binding || binding.source !== 'disabled') {\n result.push(cap)\n }\n }\n\n // Include addon-bound capabilities not already in the native list\n for (const [cap, binding] of Object.entries(deviceBindings)) {\n if (\n binding && binding.source === 'addon' &&\n !device.capabilities.includes(cap)\n ) {\n result.push(cap)\n }\n }\n\n return result\n }\n}\n","import { X509Certificate } from 'node:crypto'\nimport { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport * as os from 'node:os'\n\nconst execFileAsync = promisify(execFile)\n\nexport interface TlsCertPair {\n readonly cert: Buffer\n readonly key: Buffer\n}\n\nexport interface EnsureTlsResult {\n readonly certPath: string\n readonly keyPath: string\n readonly generated: boolean\n}\n\nexport interface CertOptions {\n /** Common Name for the cert (default: 'camstack.local') */\n readonly commonName?: string\n /** Validity in days (default: 825 — max for browsers) */\n readonly validDays?: number\n /** Additional SANs (DNS names or IPs) */\n readonly extraSans?: readonly string[]\n}\n\n/**\n * Ensure a self-signed TLS certificate exists in the given directory.\n * Generates one if missing. Returns paths to cert and key files.\n */\nexport async function ensureTlsCert(\n dataDir: string,\n options?: CertOptions,\n): Promise<EnsureTlsResult> {\n const tlsDir = join(dataDir, 'tls')\n const certPath = join(tlsDir, 'camstack.crt')\n const keyPath = join(tlsDir, 'camstack.key')\n\n // Already exists — reuse\n if (existsSync(certPath) && existsSync(keyPath)) {\n try {\n const certPem = readFileSync(certPath)\n const x509 = new X509Certificate(certPem)\n const validTo = new Date(x509.validTo)\n if (validTo > new Date()) {\n return { certPath, keyPath, generated: false }\n }\n // Expired — regenerate below\n } catch {\n // Corrupted — regenerate below\n }\n }\n\n mkdirSync(tlsDir, { recursive: true })\n\n const cn = options?.commonName ?? 'camstack.local'\n const validDays = options?.validDays ?? 825\n\n // Collect SANs: localhost, 127.0.0.1, all local IPs, hostname\n const sanDns = new Set<string>(['localhost', cn, os.hostname()])\n const sanIps = new Set<string>(['127.0.0.1', '::1'])\n\n // Add all local network IPs\n const interfaces = os.networkInterfaces()\n for (const addrs of Object.values(interfaces)) {\n if (!addrs) continue\n for (const addr of addrs) {\n if (!addr.internal) {\n sanIps.add(addr.address)\n }\n }\n }\n\n // Add extra SANs\n for (const san of options?.extraSans ?? []) {\n if (san.match(/^\\d+\\.\\d+\\.\\d+\\.\\d+$/) || san.includes(':')) {\n sanIps.add(san)\n } else {\n sanDns.add(san)\n }\n }\n\n // Build SAN string for openssl\n const sanParts: string[] = []\n for (const dns of sanDns) {\n sanParts.push(`DNS:${dns}`)\n }\n for (const ip of sanIps) {\n sanParts.push(`IP:${ip}`)\n }\n const sanString = sanParts.join(',')\n\n // Generate self-signed certificate using openssl CLI\n await execFileAsync('openssl', [\n 'req', '-x509',\n '-newkey', 'rsa:2048',\n '-keyout', keyPath,\n '-out', certPath,\n '-days', String(validDays),\n '-nodes',\n '-subj', `/CN=${cn}`,\n '-addext', `subjectAltName=${sanString}`,\n ])\n\n // Set restrictive permissions on the key file\n const { chmod } = await import('node:fs/promises')\n await chmod(keyPath, 0o600)\n\n return { certPath, keyPath, generated: true }\n}\n\n/**\n * Load TLS cert+key from files. Returns Buffers suitable for Node.js TLS options.\n */\nexport function loadTlsCert(certPath: string, keyPath: string): TlsCertPair {\n return {\n cert: readFileSync(certPath),\n key: readFileSync(keyPath),\n }\n}\n","/**\n * Factory for creating tRPC clients for addons.\n *\n * Two modes:\n * - Direct caller (in-process): zero overhead, uses createCallerFactory\n * - WSS client (worker/agent): real WebSocket connection to the server\n */\n\nexport interface DirectCallerOptions {\n /** The tRPC router instance (from buildAppRouter) */\n readonly router: unknown\n /** Context for the caller (user identity, etc.) */\n readonly context: { readonly user: { readonly id: string; readonly username: string; readonly role: string } }\n}\n\nexport interface WssClientOptions {\n /** WebSocket URL (e.g., wss://localhost:4443/trpc) */\n readonly url: string\n /** Auth token for the connection */\n readonly token: string\n}\n\nexport class AddonApiFactory {\n /**\n * Build a WSS URL from host and port.\n */\n buildWssUrl(host: string, port: number): string {\n return `wss://${host}:${port}/trpc`\n }\n\n /**\n * Create a direct caller -- calls tRPC procedures directly in-process.\n * Zero network overhead. Used for in-process addons and dev mode.\n *\n * @param options.router - The tRPC router from buildAppRouter()\n * @param options.context - The auth context (service account)\n * @returns A tRPC caller that can be used as context.api\n */\n async createDirectCaller(options: DirectCallerOptions): Promise<unknown> {\n const { initTRPC } = await import('@trpc/server')\n const t = initTRPC.create()\n const callerFactory = t.createCallerFactory(options.router as never)\n return callerFactory(options.context as never)\n }\n\n /**\n * Create a WSS tRPC client -- connects to the server via WebSocket.\n * Used for forked workers and remote agents.\n *\n * @param options.url - WSS URL (e.g., wss://localhost:4443/trpc)\n * @param options.token - Bearer token for authentication\n * @returns A tRPC client that can be used as context.api\n */\n async createWssClient(options: WssClientOptions): Promise<{ readonly client: unknown; readonly close: () => void }> {\n const { createTRPCClient, createWSClient, wsLink } = await import('@trpc/client')\n\n const wsClient = createWSClient({\n url: options.url,\n connectionParams: () => ({ token: options.token }),\n })\n\n const client = createTRPCClient({\n links: [wsLink({ client: wsClient })],\n })\n\n return {\n client,\n close: () => wsClient.close(),\n }\n }\n}\n","import * as os from 'node:os'\nimport { execFileSync } from 'node:child_process'\nimport type { HardwareInfo, GpuInfo, NpuInfo, PlatformScore, PlatformCapabilities } from '@camstack/types'\n\n/**\n * Get reliable \"available\" RAM in MB, cross-platform.\n * os.freemem() is unreliable on macOS (reports ~200MB on a 36GB system).\n * Uses systeminformation when available, falls back to native commands.\n */\nasync function getAvailableRAM_MB(): Promise<number> {\n try {\n const si = await import('systeminformation')\n const mem = await si.mem()\n return Math.round(mem.available / 1024 / 1024)\n } catch {\n // Fallback: platform-specific\n const platform = os.platform()\n try {\n if (platform === 'darwin') {\n // Parse vm_stat: (free + inactive + purgeable) * pageSize\n const output = execFileSync('vm_stat', { encoding: 'utf8', timeout: 3000 })\n const pageSize = parseInt(output.match(/page size of (\\d+)/)?.[1] ?? '16384')\n const free = parseInt(output.match(/Pages free:\\s+(\\d+)/)?.[1] ?? '0')\n const inactive = parseInt(output.match(/Pages inactive:\\s+(\\d+)/)?.[1] ?? '0')\n const purgeable = parseInt(output.match(/Pages purgeable:\\s+(\\d+)/)?.[1] ?? '0')\n return Math.round((free + inactive + purgeable) * pageSize / 1024 / 1024)\n } else if (platform === 'linux') {\n // Parse /proc/meminfo: MemAvailable\n const { readFileSync } = await import('node:fs')\n const meminfo = readFileSync('/proc/meminfo', 'utf8')\n const match = meminfo.match(/MemAvailable:\\s+(\\d+)\\s+kB/)\n if (match) return Math.round(parseInt(match[1]!) / 1024)\n }\n } catch { /* ignore */ }\n // Ultimate fallback: total RAM (conservative but safe)\n return Math.round(os.totalmem() / 1024 / 1024)\n }\n}\n\nexport class PlatformScorer {\n private cached: PlatformCapabilities | null = null\n\n /** Probe hardware + runtimes and score all backend combos. Cached after first call. */\n async probe(): Promise<PlatformCapabilities> {\n if (this.cached) return this.cached\n\n const start = Date.now()\n console.log('[PlatformScorer] Probing hardware...')\n const hardware = await this.probeHardware()\n console.log(`[PlatformScorer] Hardware: ${hardware.platform}/${hardware.arch}, ${hardware.cpuModel} (${hardware.cpuCores} cores), RAM ${Math.round(hardware.totalRAM_MB / 1024)}GB`)\n if (hardware.gpu) console.log(`[PlatformScorer] GPU: ${hardware.gpu.name}`)\n if (hardware.npu) console.log(`[PlatformScorer] NPU: ${hardware.npu.type}`)\n\n console.log('[PlatformScorer] Probing Node.js backends...')\n const nodeBackends = await this.probeNodeBackends()\n console.log(`[PlatformScorer] Node backends: ${nodeBackends.map(b => b.id).join(', ')}`)\n\n console.log('[PlatformScorer] Probing Python backends...')\n const pythonInfo = this.probePythonBackends()\n if (pythonInfo.pythonPath) {\n console.log(`[PlatformScorer] Python: ${pythonInfo.pythonPath} → ${pythonInfo.backends.filter(b => b.available).map(b => b.id).join(', ') || 'no backends'}`)\n } else {\n console.log('[PlatformScorer] Python: not found')\n }\n\n const scores = this.scoreBackends(hardware, nodeBackends, pythonInfo.backends)\n const bestScore = scores.find(s => s.available) ?? scores[scores.length - 1]!\n\n const elapsed = Date.now() - start\n console.log(`[PlatformScorer] Scoring complete in ${elapsed}ms — ${scores.length} combos`)\n console.log(`[PlatformScorer] Best: ${bestScore.runtime}/${bestScore.backend} (${bestScore.format}) — ${bestScore.reason} [score: ${bestScore.score}]`)\n for (const s of scores) {\n console.log(`[PlatformScorer] ${s.available ? '✓' : '✗'} ${s.runtime}/${s.backend} (${s.format}) — score ${s.score} — ${s.reason}`)\n }\n\n this.cached = {\n hardware,\n scores,\n bestScore,\n pythonPath: pythonInfo.pythonPath,\n }\n return this.cached\n }\n\n async probeHardware(): Promise<HardwareInfo> {\n const platform = os.platform() as HardwareInfo['platform']\n const arch = os.arch() as HardwareInfo['arch']\n const cpus = os.cpus()\n const cpuModel = cpus[0]?.model ?? 'unknown'\n const cpuCores = cpus.length\n const totalRAM_MB = Math.round(os.totalmem() / 1024 / 1024)\n const availableRAM_MB = await getAvailableRAM_MB()\n console.log(`[PlatformScorer] RAM: total=${totalRAM_MB}MB, available=${availableRAM_MB}MB (via systeminformation)`)\n\n let gpu: GpuInfo | null = null\n let npu: NpuInfo | null = null\n\n // macOS Apple Silicon\n if (platform === 'darwin' && arch === 'arm64') {\n gpu = { type: 'apple', name: 'Apple Silicon GPU' }\n npu = { type: 'apple-ane' }\n }\n\n // Linux NVIDIA\n if (platform === 'linux') {\n try {\n const output = execFileSync('nvidia-smi', ['--query-gpu=name,memory.total', '--format=csv,noheader'], {\n encoding: 'utf8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'],\n }).trim()\n if (output) {\n const [name, mem] = output.split(',').map(s => s.trim())\n gpu = {\n type: 'nvidia',\n name: name ?? 'NVIDIA GPU',\n memoryMB: parseInt(mem ?? '0'),\n }\n }\n } catch { /* no NVIDIA GPU */ }\n }\n\n return { platform, arch, cpuModel, cpuCores, totalRAM_MB, availableRAM_MB, gpu, npu }\n }\n\n private async probeNodeBackends(): Promise<Array<{ id: string; available: boolean }>> {\n const backends: Array<{ id: string; available: boolean }> = [\n { id: 'cpu', available: true },\n ]\n\n try {\n const ort = await import('onnxruntime-node') as any\n const providers: string[] = ort.InferenceSession?.getAvailableProviders?.() ?? []\n for (const p of providers) {\n const n = p.toLowerCase().replace('executionprovider', '')\n if (n === 'coreml') backends.push({ id: 'coreml', available: true })\n else if (n === 'cuda') backends.push({ id: 'cuda', available: true })\n else if (n === 'tensorrt') backends.push({ id: 'tensorrt', available: true })\n }\n } catch { /* onnxruntime not available */ }\n\n // macOS always has CoreML potential\n if (os.platform() === 'darwin' && !backends.some(b => b.id === 'coreml')) {\n backends.push({ id: 'coreml', available: true })\n }\n\n return backends\n }\n\n private probePythonBackends(): { pythonPath: string | null; backends: Array<{ id: string; format: string; available: boolean }> } {\n let pythonPath: string | null = null\n for (const cmd of ['python3', 'python']) {\n try {\n execFileSync(cmd, ['--version'], { timeout: 5000, stdio: 'pipe' })\n pythonPath = cmd\n break\n } catch { /* not found */ }\n }\n\n if (!pythonPath) return { pythonPath: null, backends: [] }\n\n const checks: Array<[string, string, string]> = [\n // [pythonModule, backendId, modelFormat]\n ['coremltools', 'coreml', 'coreml'],\n ['openvino.runtime', 'openvino', 'openvino'],\n ['torch', 'pytorch', 'onnx'],\n ['onnxruntime', 'onnx-py', 'onnx'],\n ]\n\n const backends: Array<{ id: string; format: string; available: boolean }> = []\n for (const [mod, id, format] of checks) {\n let available = false\n const probeStart = Date.now()\n try {\n execFileSync(pythonPath, ['-c', `import ${mod}`], { timeout: 30000, stdio: 'ignore' })\n available = true\n } catch { /* module not installed */ }\n const probeMs = Date.now() - probeStart\n console.log(`[PlatformScorer] Python ${mod}: ${available ? '✓' : '✗'} (${probeMs}ms)`)\n\n // Always show CoreML on macOS even if not installed\n if (id === 'coreml' && os.platform() === 'darwin') {\n backends.push({ id, format, available })\n } else if (available) {\n backends.push({ id, format, available })\n }\n }\n\n return { pythonPath, backends }\n }\n\n private scoreBackends(\n hardware: HardwareInfo,\n nodeBackends: Array<{ id: string; available: boolean }>,\n pythonBackends: Array<{ id: string; format: string; available: boolean }>,\n ): PlatformScore[] {\n const scores: PlatformScore[] = []\n\n // macOS Apple Silicon\n if (hardware.platform === 'darwin' && hardware.arch === 'arm64') {\n const pyCoreMl = pythonBackends.find(b => b.id === 'coreml')\n if (pyCoreMl) {\n scores.push({ runtime: 'python', backend: 'coreml', format: 'coreml', score: 95, reason: 'Apple Neural Engine (Python CoreML)', available: pyCoreMl.available })\n }\n const nodeCoreMl = nodeBackends.find(b => b.id === 'coreml')\n if (nodeCoreMl) {\n scores.push({ runtime: 'node', backend: 'coreml', format: 'onnx', score: 90, reason: 'CoreML via ONNX Runtime', available: nodeCoreMl.available })\n }\n }\n\n // NVIDIA\n if (hardware.gpu?.type === 'nvidia') {\n const tensorrt = nodeBackends.find(b => b.id === 'tensorrt')\n if (tensorrt) scores.push({ runtime: 'node', backend: 'tensorrt', format: 'onnx', score: 95, reason: 'NVIDIA TensorRT', available: true })\n const cuda = nodeBackends.find(b => b.id === 'cuda')\n if (cuda) scores.push({ runtime: 'node', backend: 'cuda', format: 'onnx', score: 85, reason: 'NVIDIA CUDA', available: true })\n }\n\n // Intel OpenVINO\n const openvino = pythonBackends.find(b => b.id === 'openvino')\n if (openvino) {\n const score = hardware.npu?.type === 'intel-npu' ? 90 : 80\n scores.push({ runtime: 'python', backend: 'openvino', format: 'openvino', score, reason: 'Intel OpenVINO', available: openvino.available })\n }\n\n // CPU fallbacks\n scores.push({ runtime: 'node', backend: 'cpu', format: 'onnx', score: 50, reason: 'CPU (ONNX Runtime Node)', available: true })\n const pyOnnx = pythonBackends.find(b => b.id === 'onnx-py')\n if (pyOnnx) {\n scores.push({ runtime: 'python', backend: 'cpu', format: 'onnx', score: 45, reason: 'CPU (Python ONNX)', available: pyOnnx.available })\n }\n\n return scores.sort((a, b) => b.score - a.score)\n }\n}\n","import type { PlatformScore, HardwareInfo, ModelRequirement, ResolvedInferenceConfig } from '@camstack/types'\n\nexport class InferenceConfigResolver {\n constructor(\n private readonly scores: readonly PlatformScore[],\n private readonly hardware: HardwareInfo,\n ) {}\n\n /**\n * Compute accuracy/backend weights based on available system RAM.\n * availableRAM_MB is now sourced from systeminformation (reliable cross-platform),\n * not os.freemem() which is broken on macOS.\n *\n * - > 16 GB available: prefer larger, more accurate models (accuracy 0.6, backend 0.4)\n * - > 8 GB available: balanced (accuracy 0.5, backend 0.5)\n * - <= 8 GB available: prefer speed (accuracy 0.4, backend 0.6)\n */\n private getWeights(): { accuracyWeight: number; backendWeight: number } {\n const ramMB = this.hardware.availableRAM_MB\n if (ramMB > 16_384) return { accuracyWeight: 0.6, backendWeight: 0.4 }\n if (ramMB > 8_192) return { accuracyWeight: 0.5, backendWeight: 0.5 }\n return { accuracyWeight: 0.4, backendWeight: 0.6 }\n }\n\n /**\n * Given an addon's model requirements, pick the best model + runtime + backend.\n *\n * Algorithm:\n * 1. Filter models by available RAM (minRAM_MB < 25% of available RAM)\n * 2. For each remaining model, find the best platform score whose format\n * is available in the model's formats\n * 3. Pick the model with the highest combined score using RAM-adaptive weights:\n * - High RAM (>16 GB): accuracy × 0.6 + backend × 0.4 (prefer accuracy)\n * - Mid RAM (>8 GB): accuracy × 0.5 + backend × 0.5 (balanced)\n * - Low RAM (<=8 GB): accuracy × 0.4 + backend × 0.6 (prefer speed)\n */\n resolve(requirements: readonly ModelRequirement[]): ResolvedInferenceConfig {\n if (requirements.length === 0) {\n return { modelId: '', runtime: 'node', backend: 'cpu', format: 'onnx', reason: 'No models declared' }\n }\n\n // Budget: 25% of available RAM (now reliable via systeminformation)\n const ramBudget = this.hardware.availableRAM_MB * 0.25\n const { accuracyWeight, backendWeight } = this.getWeights()\n\n console.log(`[InferenceConfigResolver] availableRAM: ${this.hardware.availableRAM_MB}MB, budget: ${Math.round(ramBudget)}MB, weights: accuracy=${accuracyWeight}, backend=${backendWeight}`)\n\n // Filter models that fit in memory\n const fits = requirements.filter(m => m.minRAM_MB < ramBudget)\n const candidates = fits.length > 0 ? fits : [requirements[0]!] // fallback to first/smallest\n\n console.log(`[InferenceConfigResolver] ${candidates.length}/${requirements.length} models fit RAM budget`)\n\n // For each model, find best compatible platform score\n let bestCombo: { model: ModelRequirement; score: PlatformScore; combined: number } | null = null\n\n for (const model of candidates) {\n for (const score of this.scores) {\n if (!score.available) continue\n if (!model.formats.includes(score.format)) continue\n\n const combined = model.accuracyScore * accuracyWeight + score.score * backendWeight\n\n if (!bestCombo || combined > bestCombo.combined) {\n console.log(`[InferenceConfigResolver] New best: ${model.modelId} (accuracy=${model.accuracyScore}) + ${score.backend}/${score.format} (score=${score.score}) → combined=${Math.round(combined)}`)\n bestCombo = { model, score, combined }\n }\n }\n }\n\n if (!bestCombo) {\n return {\n modelId: candidates[0]!.modelId,\n runtime: 'node',\n backend: 'cpu',\n format: 'onnx',\n reason: 'No compatible backend — CPU fallback',\n }\n }\n\n return {\n modelId: bestCombo.model.modelId,\n runtime: bestCombo.score.runtime,\n backend: bestCombo.score.backend,\n format: bestCombo.score.format,\n reason: `${bestCombo.model.name} on ${bestCombo.score.reason} (score: ${Math.round(bestCombo.combined)})`,\n }\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { IScopedLogger, IEventBus, LoggerFactory, ProviderListItem } from '@camstack/types'\nimport { LifecycleStateMachine, type ElementStatus } from '../lifecycle/lifecycle-state-machine.js'\n\n/** Minimal device registry interface for provider management */\nexport type ProviderDeviceRegistry = {\n registerProviderDevices(providerId: string, devices: readonly IRegistrableDevice[]): void\n unregisterProviderDevices(providerId: string): void\n}\n\nexport interface IRegistrableDevice {\n readonly id: string\n readonly name: string\n readonly providerId: string\n readonly capabilities: readonly string[]\n}\n\nexport interface ProviderStatus {\n connected: boolean\n error?: string\n deviceCount: number\n}\n\nexport interface LiveEvent {\n type: string\n camera: string\n timestamp: number\n data: Record<string, unknown>\n}\n\nexport interface IManagedProvider {\n readonly id: string\n readonly type: string\n readonly name: string\n start(): Promise<void>\n stop(): Promise<void>\n getStatus(): ProviderStatus\n getDevices(): readonly IRegistrableDevice[]\n subscribeLiveEvents(callback: (event: LiveEvent) => void): () => void\n}\n\ninterface ProviderEntry<P extends IManagedProvider> {\n readonly provider: P\n readonly lifecycle: LifecycleStateMachine\n started: boolean\n unsubscribe?: () => void\n}\n\nexport type { ProviderListItem }\n\nexport class ProviderManager<P extends IManagedProvider = IManagedProvider> {\n private readonly providers = new Map<string, ProviderEntry<P>>()\n private readonly logger: IScopedLogger\n\n constructor(\n private readonly deviceRegistry: ProviderDeviceRegistry,\n private readonly eventBus: IEventBus,\n private readonly loggingService: LoggerFactory,\n ) {\n this.logger = loggingService.createLogger('provider-manager')\n }\n\n registerProvider(provider: P): void {\n const providerLogger = this.loggingService.createLogger(`provider:${provider.id}`)\n const lifecycle = new LifecycleStateMachine(\n provider.id,\n 'provider',\n this.eventBus,\n providerLogger,\n )\n this.providers.set(provider.id, { provider, lifecycle, started: false })\n this.logger.info(`Provider registered: ${provider.id} (${provider.name})`)\n }\n\n async startProvider(id: string): Promise<void> {\n const entry = this.providers.get(id)\n if (!entry) {\n throw new Error(`Provider \"${id}\" is not registered`)\n }\n\n if (entry.lifecycle.state === 'disabled') {\n throw new Error(`Provider \"${id}\" is disabled`)\n }\n\n entry.lifecycle.transition('starting')\n\n try {\n await entry.provider.start()\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err)\n entry.lifecycle.transition('error', message)\n throw err\n }\n\n entry.lifecycle.transition('running')\n\n const devices = entry.provider.getDevices()\n this.deviceRegistry.registerProviderDevices(id, devices)\n\n const unsubscribe = entry.provider.subscribeLiveEvents((event: LiveEvent) => {\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'provider', id },\n category: `provider.${event.type}`,\n data: event.data,\n })\n })\n\n entry.started = true\n entry.unsubscribe = unsubscribe\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'core', id: 'provider-manager' },\n category: 'provider.started',\n data: { providerId: id },\n })\n\n this.logger.info(`Provider started: ${id}`)\n }\n\n async stopProvider(id: string): Promise<void> {\n const entry = this.providers.get(id)\n if (!entry) {\n throw new Error(`Provider \"${id}\" is not registered`)\n }\n\n entry.lifecycle.transition('stopping')\n\n if (entry.unsubscribe) {\n entry.unsubscribe()\n entry.unsubscribe = undefined\n }\n\n this.deviceRegistry.unregisterProviderDevices(id)\n\n await entry.provider.stop()\n entry.started = false\n\n entry.lifecycle.transition('stopped')\n\n this.eventBus.emit({\n id: randomUUID(),\n timestamp: new Date(),\n source: { type: 'core', id: 'provider-manager' },\n category: 'provider.stopped',\n data: { providerId: id },\n })\n\n this.logger.info(`Provider stopped: ${id}`)\n }\n\n async disableProvider(id: string): Promise<void> {\n const entry = this.providers.get(id)\n if (!entry) {\n throw new Error(`Provider \"${id}\" is not registered`)\n }\n\n if (entry.lifecycle.state === 'running' || entry.started) {\n await this.stopProvider(id)\n }\n\n entry.lifecycle.transition('disabled')\n this.logger.info(`Provider disabled: ${id}`)\n }\n\n async enableProvider(id: string): Promise<void> {\n const entry = this.providers.get(id)\n if (!entry) {\n throw new Error(`Provider \"${id}\" is not registered`)\n }\n\n if (entry.lifecycle.state !== 'disabled') {\n throw new Error(`Provider \"${id}\" is not disabled`)\n }\n\n entry.lifecycle.transition('stopped')\n this.logger.info(`Provider enabled: ${id}`)\n }\n\n async restartProvider(id: string): Promise<void> {\n await this.stopProvider(id)\n await this.startProvider(id)\n }\n\n getProvider(id: string): P | null {\n const entry = this.providers.get(id)\n return entry?.provider ?? null\n }\n\n getProviderStatus(id: string): ElementStatus | null {\n const entry = this.providers.get(id)\n return entry?.lifecycle.getStatus() ?? null\n }\n\n listProviders(): readonly ProviderListItem[] {\n return Array.from(this.providers.values()).map((entry) => ({\n id: entry.provider.id,\n type: entry.provider.type,\n name: entry.provider.name,\n status: entry.provider.getStatus(),\n started: entry.started,\n lifecycle: entry.lifecycle.getStatus(),\n }))\n }\n\n async shutdownAll(): Promise<void> {\n const startedIds = Array.from(this.providers.entries())\n .filter(([, entry]) => entry.started)\n .map(([id]) => id)\n\n for (const id of startedIds) {\n await this.stopProvider(id)\n }\n\n this.logger.info(`All providers shut down (${startedIds.length} stopped)`)\n }\n}\n"],"mappings":"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","names":["platform","rmSync","join","platform","arch","join","join","existsSync","mkdirSync","chmodSync","execFileSync","pipeline","Readable","createWriteStream","platform","arch","join","existsSync","mkdirSync","Readable","pipeline","createWriteStream","execFileSync","unlinkSync","chmodSync","hash","fs","path","fs","path","promises","spawn","randomUUID","fs","path","StorageLocationManager","location","hash","crypto","hash","crypto","crypto","path","randomUUID","execFile","promisify","existsSync","mkdirSync","join","execFileAsync","os","execFileSync","platform","readFileSync","arch","cpus","randomUUID","randomUUID"]}