{"version":3,"sources":["../src/cli/index.ts","../src/server/createDevToolsServer.ts","../src/types/protocol.ts","../src/types/snapshot.ts","../src/utils/logger.ts","../src/server/attachWebUi.ts","../src/server/attachWebSocket.ts","../src/utils/ids.ts","../src/server/connectionManager.ts","../src/server/cors.ts","../src/server/deviceRegistry.ts","../src/server/heartbeat.ts","../src/server/messageRouter.ts","../src/server/pendingRefreshStore.ts","../src/server/refreshCoordinator.ts","../src/server/snapshotFileStore.ts","../src/server/projectData.ts","../src/server/deviceExportStorage.ts","../src/server/migrateLegacyActiveDb.ts","../src/server/snapshotStore.ts","../src/server/writeCoordinator.ts","../src/server/writeSessionManager.ts","../src/utils/resolveWebDistPath.ts","../src/cli/openBrowser.ts"],"sourcesContent":["import path from 'node:path';\r\nimport { createDevToolsServer } from '../server/createDevToolsServer';\r\nimport { resolveWebDistPath } from '../utils/resolveWebDistPath';\r\nimport { openBrowser } from './openBrowser';\r\n\r\nfunction resolveCliEntryDir(): string {\r\n  const scriptPath = process.argv[1];\r\n\r\n  if (scriptPath) {\r\n    return path.dirname(path.resolve(scriptPath));\r\n  }\r\n\r\n  return process.cwd();\r\n}\r\n\r\nasync function main(): Promise<void> {\r\n  const port = Number(process.env.DATABASE_DEVTOOLS_PORT ?? process.env.PORT ?? 3847);\r\n  const host = process.env.DATABASE_DEVTOOLS_HOST ?? '0.0.0.0';\r\n  const webDistPath = resolveWebDistPath(resolveCliEntryDir());\r\n\r\n  const server = await createDevToolsServer({\r\n    host,\r\n    port,\r\n    webDistPath,\r\n  });\r\n\r\n  if (server.urls.webUiEnabled) {\r\n    openBrowser(server.urls.httpUrl);\r\n  } else {\r\n    console.warn(\r\n      '[database-devtools] Web UI assets not found. Run `pnpm build` in the monorepo or use `pnpm dev:web` during development.',\r\n    );\r\n  }\r\n}\r\n\r\nmain().catch((error: unknown) => {\r\n  console.error('[database-devtools] Failed to start server:', error);\r\n  process.exit(1);\r\n});\r\n","import express from 'express';\r\nimport { createServer, type Server } from 'node:http';\r\nimport {\r\n  DEFAULT_DEVTOOLS_HOST,\r\n  DEFAULT_DEVTOOLS_PORT,\r\n  DEVICE_SNAPSHOT_API_PATH,\r\n  MAX_SNAPSHOT_BYTES,\r\n  PROJECT_DATABASE_API_PATH,\r\n  PROJECT_DATABASE_META_API_PATH,\r\n  PROJECT_DATABASES_API_PATH,\r\n  PROJECT_DEVICE_EXPORTS_API_PATH,\r\n  buildDevToolsHttpUrl,\r\n  buildDevToolsWsUrl,\r\n} from '../types/protocol';\r\nimport { SNAPSHOT_KIND_HEADER, SNAPSHOT_MIME_HEADER, SNAPSHOT_NAME_HEADER, SQLITE_SNAPSHOT_MIME_TYPE } from '../types/snapshot';\r\nimport { logger } from '../utils/logger';\r\nimport { attachWebUi } from './attachWebUi';\r\nimport { attachWebSocket } from './attachWebSocket';\r\nimport { ConnectionManager } from './connectionManager';\r\nimport { createCorsMiddleware } from './cors';\r\nimport { DeviceRegistry } from './deviceRegistry';\r\nimport { Heartbeat } from './heartbeat';\r\nimport { MessageRouter } from './messageRouter';\r\nimport { PendingRefreshStore } from './pendingRefreshStore';\r\nimport { RefreshCoordinator } from './refreshCoordinator';\r\nimport { SnapshotFileStore } from './snapshotFileStore';\r\nimport { SnapshotStore } from './snapshotStore';\r\nimport { WriteCoordinator } from './writeCoordinator';\r\nimport { WriteSessionManager } from './writeSessionManager';\r\n\r\nexport type DevToolsServerOptions = {\r\n  host?: string;\r\n  port?: number;\r\n  dataDir?: string;\r\n  snapshotPersistence?: boolean;\r\n  webDistPath?: string;\r\n};\r\n\r\nexport type DevToolsServerUrls = {\r\n  httpUrl: string;\r\n  wsUrl: string;\r\n  webUiEnabled: boolean;\r\n};\r\n\r\nexport type DevToolsServer = {\r\n  app: express.Express;\r\n  httpServer: Server;\r\n  connectionManager: ConnectionManager;\r\n  deviceRegistry: DeviceRegistry;\r\n  router: MessageRouter;\r\n  heartbeat: Heartbeat;\r\n  snapshotStore: SnapshotStore;\r\n  snapshotFileStore: SnapshotFileStore;\r\n  pendingRefreshStore: PendingRefreshStore;\r\n  writeSessions: WriteSessionManager;\r\n  refreshCoordinator: RefreshCoordinator;\r\n  writeCoordinator: WriteCoordinator;\r\n  urls: DevToolsServerUrls;\r\n  close: () => Promise<void>;\r\n};\r\n\r\nexport async function createDevToolsServer(\r\n  options: DevToolsServerOptions = {},\r\n): Promise<DevToolsServer> {\r\n  const host = options.host ?? DEFAULT_DEVTOOLS_HOST;\r\n  const port = options.port ?? DEFAULT_DEVTOOLS_PORT;\r\n\r\n  const app = express();\r\n  const connectionManager = new ConnectionManager();\r\n  const deviceRegistry = new DeviceRegistry(connectionManager);\r\n  const router = new MessageRouter(connectionManager, deviceRegistry);\r\n  const heartbeat = new Heartbeat(connectionManager, router);\r\n  const snapshotStore = new SnapshotStore();\r\n  const snapshotFileStore = new SnapshotFileStore({\r\n    dataDir: options.dataDir,\r\n    enabled: options.snapshotPersistence,\r\n  });\r\n  const pendingRefreshStore = new PendingRefreshStore();\r\n  const writeSessions = new WriteSessionManager();\r\n\r\n  const refreshCoordinator = new RefreshCoordinator(\r\n    connectionManager,\r\n    router,\r\n    pendingRefreshStore,\r\n    snapshotStore,\r\n    snapshotFileStore,\r\n  );\r\n  const writeCoordinator = new WriteCoordinator(connectionManager, router, writeSessions);\r\n\r\n  app.use(createCorsMiddleware());\r\n\r\n  app.get('/health', (_request, response) => {\r\n    response.json({ ok: true, ...deviceRegistry.snapshot() });\r\n  });\r\n\r\n  app.post(\r\n    `${DEVICE_SNAPSHOT_API_PATH}/:deviceId/snapshot`,\r\n    express.raw({ type: 'application/octet-stream', limit: MAX_SNAPSHOT_BYTES }),\r\n    async (request, response) => {\r\n      const deviceId = decodeURIComponent(request.params.deviceId);\r\n      const body = request.body;\r\n\r\n      if (!Buffer.isBuffer(body) || body.length === 0) {\r\n        response.status(400).json({ ok: false, error: 'Empty snapshot body' });\r\n        return;\r\n      }\r\n\r\n      const kindHeader = request.header(SNAPSHOT_KIND_HEADER);\r\n      const mimeHeader = request.header(SNAPSHOT_MIME_HEADER);\r\n      const nameHeader = request.header(SNAPSHOT_NAME_HEADER);\r\n\r\n      const result = await refreshCoordinator.handleSnapshotUpload(deviceId, body, {\r\n        kind: typeof kindHeader === 'string' ? kindHeader : undefined,\r\n        mimeType: typeof mimeHeader === 'string' ? mimeHeader : undefined,\r\n        databaseName: typeof nameHeader === 'string' ? nameHeader : undefined,\r\n      });\r\n\r\n      if (!result.ok) {\r\n        response.status(result.code === 'SNAPSHOT_NOT_FOUND' ? 404 : 400).json({\r\n          ok: false,\r\n          error: result.code,\r\n        });\r\n        return;\r\n      }\r\n\r\n      response.status(201).json({ ok: true, deviceId, size: body.byteLength });\r\n    },\r\n  );\r\n\r\n  app.get(`${DEVICE_SNAPSHOT_API_PATH}/:deviceId/snapshot`, async (request, response) => {\r\n    const deviceId = decodeURIComponent(request.params.deviceId);\r\n    const snapshot = await refreshCoordinator.getSnapshotAsync(deviceId);\r\n\r\n    if (!snapshot) {\r\n      response.status(404).json({ ok: false, error: 'SNAPSHOT_NOT_FOUND' });\r\n      return;\r\n    }\r\n\r\n    response\r\n      .status(200)\r\n      .set('Content-Type', 'application/octet-stream')\r\n      .send(snapshot);\r\n  });\r\n\r\n  app.get(PROJECT_DATABASE_META_API_PATH, async (_request, response) => {\r\n    const meta = await snapshotFileStore.getActiveDatabaseMeta();\r\n    response.json(meta);\r\n  });\r\n\r\n  app.get(PROJECT_DATABASES_API_PATH, async (_request, response) => {\r\n    const databases = await snapshotFileStore.listDatabases();\r\n    response.json({ databases });\r\n  });\r\n\r\n  app.get(PROJECT_DEVICE_EXPORTS_API_PATH, async (_request, response) => {\r\n    const devices = await snapshotFileStore.listDeviceExports();\r\n    response.json({ devices });\r\n  });\r\n\r\n  app.get(`${PROJECT_DEVICE_EXPORTS_API_PATH}/:deviceId/database/meta`, async (request, response) => {\r\n    const deviceId = decodeURIComponent(request.params.deviceId);\r\n    const meta = await snapshotFileStore.getDeviceDatabaseMeta(deviceId);\r\n    response.json(meta);\r\n  });\r\n\r\n  app.get(`${PROJECT_DEVICE_EXPORTS_API_PATH}/:deviceId/database`, async (request, response) => {\r\n    const deviceId = decodeURIComponent(request.params.deviceId);\r\n    const meta = await snapshotFileStore.getDeviceDatabaseMeta(deviceId);\r\n\r\n    if (!meta.exists) {\r\n      response.status(404).json({ ok: false, error: 'DEVICE_DATABASE_NOT_FOUND', deviceId });\r\n      return;\r\n    }\r\n\r\n    const bytes = await snapshotFileStore.readDeviceDatabase(deviceId);\r\n\r\n    if (!bytes) {\r\n      response.status(404).json({ ok: false, error: 'DEVICE_DATABASE_NOT_FOUND', deviceId });\r\n      return;\r\n    }\r\n\r\n    response\r\n      .status(200)\r\n      .set('Content-Type', meta.mimeType ?? SQLITE_SNAPSHOT_MIME_TYPE)\r\n      .send(bytes);\r\n  });\r\n\r\n  app.get(PROJECT_DATABASE_API_PATH, async (_request, response) => {\r\n    const meta = await snapshotFileStore.getActiveDatabaseMeta();\r\n\r\n    if (!meta.exists) {\r\n      response.status(404).json({ ok: false, error: 'PROJECT_DATABASE_NOT_FOUND' });\r\n      return;\r\n    }\r\n\r\n    const bytes = await snapshotFileStore.readActiveDatabase();\r\n\r\n    if (!bytes) {\r\n      response.status(404).json({ ok: false, error: 'PROJECT_DATABASE_NOT_FOUND' });\r\n      return;\r\n    }\r\n\r\n    response\r\n      .status(200)\r\n      .set('Content-Type', meta.mimeType ?? SQLITE_SNAPSHOT_MIME_TYPE)\r\n      .send(bytes);\r\n  });\r\n\r\n  if (options.webDistPath) {\r\n    attachWebUi(app, options.webDistPath);\r\n  }\r\n\r\n  const httpServer = createServer(app);\r\n  attachWebSocket(\r\n    httpServer,\r\n    connectionManager,\r\n    router,\r\n    heartbeat,\r\n    refreshCoordinator,\r\n    writeCoordinator,\r\n    { snapshotFileStore },\r\n  );\r\n\r\n  const refreshTimeoutInterval = setInterval(() => {\r\n    refreshCoordinator.checkTimeouts();\r\n    writeCoordinator.checkTimeouts();\r\n  }, 5_000);\r\n\r\n  if (snapshotFileStore.isEnabled()) {\r\n    await snapshotFileStore.listDeviceExports();\r\n  }\r\n\r\n  await new Promise<void>((resolve, reject) => {\r\n    httpServer.once('error', reject);\r\n    httpServer.listen(port, host, () => resolve());\r\n  });\r\n\r\n  const displayHost = host === '0.0.0.0' ? 'localhost' : host;\r\n  const httpUrl = buildDevToolsHttpUrl(displayHost, port);\r\n  const wsUrl = buildDevToolsWsUrl(displayHost, port);\r\n  const webUiEnabled = Boolean(options.webDistPath);\r\n\r\n  logger.serverStarted(httpUrl, wsUrl, webUiEnabled);\r\n\r\n  return {\r\n    app,\r\n    httpServer,\r\n    connectionManager,\r\n    deviceRegistry,\r\n    router,\r\n    heartbeat,\r\n    snapshotStore,\r\n    snapshotFileStore,\r\n    pendingRefreshStore,\r\n    writeSessions,\r\n    refreshCoordinator,\r\n    writeCoordinator,\r\n    urls: {\r\n      httpUrl,\r\n      wsUrl,\r\n      webUiEnabled,\r\n    },\r\n    close: () =>\r\n      new Promise((resolve, reject) => {\r\n        clearInterval(refreshTimeoutInterval);\r\n        heartbeat.stop();\r\n        httpServer.close((error) => {\r\n          if (error) {\r\n            reject(error);\r\n            return;\r\n          }\r\n\r\n          resolve();\r\n        });\r\n      }),\r\n  };\r\n}\r\n","import type { WriteOperation } from './write';\r\n\r\n/** Client and server roles on the WebSocket hub. */\r\nexport const DevToolsRole = {\r\n  MOBILE: 'mobile',\r\n  BROWSER: 'browser',\r\n} as const;\r\n\r\nexport type DevToolsRole = (typeof DevToolsRole)[keyof typeof DevToolsRole];\r\n\r\n/** All wire message type identifiers. */\r\nexport const MessageType = {\r\n  REGISTER: 'register',\r\n  PING: 'ping',\r\n  PONG: 'pong',\r\n  DEVICE_STATUS: 'deviceStatus',\r\n  BROADCAST: 'broadcast',\r\n  REFRESH_REQUEST: 'refreshRequest',\r\n  SNAPSHOT_UPLOAD_REQUESTED: 'snapshotUploadRequested',\r\n  REFRESH_STATUS: 'refreshStatus',\r\n  SNAPSHOT_READY: 'snapshotReady',\r\n  REFRESH_ERROR: 'refreshError',\r\n  EXPORT_SNAPSHOT_REQUEST: 'exportSnapshotRequest',\r\n  EXPORT_SNAPSHOT_ERROR: 'exportSnapshotError',\r\n  BEGIN_TRANSACTION_REQUEST: 'beginTransactionRequest',\r\n  COMMIT_TRANSACTION_REQUEST: 'commitTransactionRequest',\r\n  ROLLBACK_TRANSACTION_REQUEST: 'rollbackTransactionRequest',\r\n  WRITE_REQUEST: 'writeRequest',\r\n  BEGIN_TRANSACTION: 'beginTransaction',\r\n  COMMIT_TRANSACTION: 'commitTransaction',\r\n  ROLLBACK_TRANSACTION: 'rollbackTransaction',\r\n  EXECUTE_WRITE: 'executeWrite',\r\n  TRANSACTION_ACK: 'transactionAck',\r\n  WRITE_ACK: 'writeAck',\r\n  TRANSACTION_STATUS: 'transactionStatus',\r\n  WRITE_RESULT: 'writeResult',\r\n  WRITE_ERROR: 'writeError',\r\n} as const;\r\n\r\nexport type MessageTypeValue = (typeof MessageType)[keyof typeof MessageType];\r\n\r\n/** Shared base for every protocol message. */\r\nexport interface DevToolsMessageBase {\r\n  type: MessageTypeValue;\r\n  timestamp: number;\r\n}\r\n\r\nexport type DeviceMetadata = {\r\n  platform?: string;\r\n  appName?: string;\r\n  [key: string]: string | undefined;\r\n};\r\n\r\n/** Client → Server: register role on connect. */\r\nexport interface RegisterMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.REGISTER;\r\n  role: DevToolsRole;\r\n  deviceId?: string;\r\n  metadata?: DeviceMetadata;\r\n}\r\n\r\n/** Server → Client: heartbeat probe. */\r\nexport interface PingMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.PING;\r\n  pingId: string;\r\n}\r\n\r\n/** Client → Server: heartbeat response. */\r\nexport interface PongMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.PONG;\r\n  pingId: string;\r\n}\r\n\r\nexport type BrowserConnectionInfo = {\r\n  connectionId: string;\r\n  connectedAt: number;\r\n};\r\n\r\nexport type MobileDeviceInfo = {\r\n  deviceId: string;\r\n  connectionId: string;\r\n  connectedAt: number;\r\n  metadata?: DeviceMetadata;\r\n};\r\n\r\nexport type DeviceStatusPayload = {\r\n  browserCount: number;\r\n  mobileCount: number;\r\n  browsers: BrowserConnectionInfo[];\r\n  mobiles: MobileDeviceInfo[];\r\n};\r\n\r\n/** Server → Client: hub snapshot after connect/disconnect. */\r\nexport interface DeviceStatusMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.DEVICE_STATUS;\r\n  payload: DeviceStatusPayload;\r\n}\r\n\r\n/** Server → Client: generic routed envelope for future features. */\r\nexport interface BroadcastMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.BROADCAST;\r\n  payload: unknown;\r\n}\r\n\r\nexport type RefreshType = 'snapshot';\r\n\r\nexport type RefreshState =\r\n  | 'requested'\r\n  | 'exporting'\r\n  | 'uploading'\r\n  | 'ready'\r\n  | 'failed'\r\n  | 'timeout';\r\n\r\n/** @deprecated Use RefreshState */\r\nexport type SyncState = RefreshState;\r\n\r\nexport type RefreshErrorCode =\r\n  | 'DEVICE_OFFLINE'\r\n  | 'REFRESH_IN_PROGRESS'\r\n  | 'EXPORT_FAILED'\r\n  | 'UPLOAD_FAILED'\r\n  | 'TIMEOUT'\r\n  | 'SNAPSHOT_NOT_FOUND'\r\n  | 'INVALID_REQUEST';\r\n\r\n/** @deprecated Use RefreshErrorCode */\r\nexport type SyncErrorCode = RefreshErrorCode;\r\n\r\n/** Browser → Server: request a database snapshot from a mobile device. */\r\nexport interface RefreshRequestMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.REFRESH_REQUEST;\r\n  deviceId: string;\r\n  refreshType: RefreshType;\r\n}\r\n\r\n/** Server → Mobile: export database and upload via REST. */\r\nexport interface SnapshotUploadRequestedMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.SNAPSHOT_UPLOAD_REQUESTED;\r\n  deviceId: string;\r\n  refreshType: RefreshType;\r\n}\r\n\r\n/** Server → Browser: refresh progress update. */\r\nexport interface RefreshStatusMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.REFRESH_STATUS;\r\n  deviceId: string;\r\n  state: RefreshState;\r\n  message?: string;\r\n}\r\n\r\n/** Server → Browser: snapshot uploaded and ready to download. */\r\nexport interface SnapshotReadyMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.SNAPSHOT_READY;\r\n  deviceId: string;\r\n  size: number;\r\n  exportedAt: number;\r\n  kind: string;\r\n  mimeType: string;\r\n  databaseName?: string;\r\n}\r\n\r\n/** Server → Browser: refresh failed. */\r\nexport interface RefreshErrorMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.REFRESH_ERROR;\r\n  deviceId: string;\r\n  code: RefreshErrorCode;\r\n  message: string;\r\n}\r\n\r\n/** Mobile → Server: push database snapshot to the web inspector. */\r\nexport interface ExportSnapshotRequestMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.EXPORT_SNAPSHOT_REQUEST;\r\n  refreshType: RefreshType;\r\n}\r\n\r\n/** Server → Mobile: export request failed before upload. */\r\nexport interface ExportSnapshotErrorMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.EXPORT_SNAPSHOT_ERROR;\r\n  code: RefreshErrorCode;\r\n  message: string;\r\n}\r\n\r\nexport type RefreshInitiator = 'browser' | 'mobile';\r\n\r\nexport type TransactionStatusState =\r\n  | 'idle'\r\n  | 'opening'\r\n  | 'open'\r\n  | 'committing'\r\n  | 'rolling_back'\r\n  | 'failed';\r\n\r\nexport type WriteErrorCode =\r\n  | 'DEVICE_OFFLINE'\r\n  | 'NO_TRANSACTION'\r\n  | 'TRANSACTION_BUSY'\r\n  | 'INVALID_OPERATION'\r\n  | 'WRITE_FAILED'\r\n  | 'ADAPTER_ERROR'\r\n  | 'TIMEOUT';\r\n\r\n/** Browser → Server: open a write transaction on a device. */\r\nexport interface BeginTransactionRequestMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.BEGIN_TRANSACTION_REQUEST;\r\n  transactionId: string;\r\n  deviceId: string;\r\n}\r\n\r\n/** Browser → Server: commit the active transaction. */\r\nexport interface CommitTransactionRequestMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.COMMIT_TRANSACTION_REQUEST;\r\n  transactionId: string;\r\n  deviceId: string;\r\n}\r\n\r\n/** Browser → Server: roll back the active transaction. */\r\nexport interface RollbackTransactionRequestMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.ROLLBACK_TRANSACTION_REQUEST;\r\n  transactionId: string;\r\n  deviceId: string;\r\n}\r\n\r\n/** Browser → Server: execute a structured write inside a transaction. */\r\nexport interface WriteRequestMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.WRITE_REQUEST;\r\n  writeId: string;\r\n  transactionId: string;\r\n  deviceId: string;\r\n  operation: WriteOperation;\r\n}\r\n\r\n/** Server → Mobile: begin a transaction on the live database. */\r\nexport interface BeginTransactionMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.BEGIN_TRANSACTION;\r\n  transactionId: string;\r\n}\r\n\r\n/** Server → Mobile: commit the open transaction. */\r\nexport interface CommitTransactionMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.COMMIT_TRANSACTION;\r\n  transactionId: string;\r\n}\r\n\r\n/** Server → Mobile: roll back the open transaction. */\r\nexport interface RollbackTransactionMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.ROLLBACK_TRANSACTION;\r\n  transactionId: string;\r\n}\r\n\r\n/** Server → Mobile: run a structured write operation. */\r\nexport interface ExecuteWriteMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.EXECUTE_WRITE;\r\n  writeId: string;\r\n  transactionId: string;\r\n  operation: WriteOperation;\r\n}\r\n\r\n/** Mobile → Server: transaction lifecycle acknowledgement. */\r\nexport interface TransactionAckMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.TRANSACTION_ACK;\r\n  transactionId: string;\r\n  action: 'begin' | 'commit' | 'rollback';\r\n  ok: boolean;\r\n  message?: string;\r\n}\r\n\r\n/** Mobile → Server: write operation acknowledgement. */\r\nexport interface WriteAckMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.WRITE_ACK;\r\n  writeId: string;\r\n  transactionId: string;\r\n  ok: boolean;\r\n  rowsAffected?: number;\r\n  message?: string;\r\n}\r\n\r\n/** Server → Browser: transaction state update. */\r\nexport interface TransactionStatusMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.TRANSACTION_STATUS;\r\n  transactionId: string;\r\n  deviceId: string;\r\n  state: TransactionStatusState;\r\n  message?: string;\r\n}\r\n\r\n/** Server → Browser: write succeeded. */\r\nexport interface WriteResultMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.WRITE_RESULT;\r\n  writeId: string;\r\n  transactionId: string;\r\n  rowsAffected: number;\r\n}\r\n\r\n/** Server → Browser: write or transaction failed. */\r\nexport interface WriteErrorMessage extends DevToolsMessageBase {\r\n  type: typeof MessageType.WRITE_ERROR;\r\n  transactionId: string;\r\n  writeId?: string;\r\n  code: WriteErrorCode;\r\n  message: string;\r\n}\r\n\r\nexport type ClientMessage =\r\n  | RegisterMessage\r\n  | PongMessage\r\n  | RefreshRequestMessage\r\n  | ExportSnapshotRequestMessage\r\n  | BeginTransactionRequestMessage\r\n  | CommitTransactionRequestMessage\r\n  | RollbackTransactionRequestMessage\r\n  | WriteRequestMessage\r\n  | TransactionAckMessage\r\n  | WriteAckMessage;\r\n\r\nexport type ServerMessage =\r\n  | PingMessage\r\n  | DeviceStatusMessage\r\n  | BroadcastMessage\r\n  | SnapshotUploadRequestedMessage\r\n  | RefreshStatusMessage\r\n  | SnapshotReadyMessage\r\n  | RefreshErrorMessage\r\n  | ExportSnapshotErrorMessage\r\n  | BeginTransactionMessage\r\n  | CommitTransactionMessage\r\n  | RollbackTransactionMessage\r\n  | ExecuteWriteMessage\r\n  | TransactionStatusMessage\r\n  | WriteResultMessage\r\n  | WriteErrorMessage;\r\n\r\nexport type DevToolsMessage = ClientMessage | ServerMessage;\r\n\r\nexport const DEVTOOLS_WS_PATH = '/ws';\r\n\r\nexport const DEFAULT_DEVTOOLS_PORT = 3847;\r\n\r\nexport const DEFAULT_DEVTOOLS_HOST = '0.0.0.0';\r\n\r\nexport const HEARTBEAT_INTERVAL_MS = 30_000;\r\n\r\nexport const HEARTBEAT_TIMEOUT_MS = 10_000;\r\n\r\nexport const DEVICE_SNAPSHOT_API_PATH = '/api/devices';\r\n\r\nexport const PROJECT_DATABASE_API_PATH = '/api/project/database';\r\n\r\nexport const PROJECT_DATABASE_META_API_PATH = '/api/project/database/meta';\r\n\r\nexport const PROJECT_DATABASES_API_PATH = '/api/project/databases';\r\n\r\nexport const PROJECT_DEVICE_EXPORTS_API_PATH = '/api/project/devices';\r\n\r\n/** @deprecated Use DEVICE_SNAPSHOT_API_PATH */\r\nexport const SNAPSHOT_API_PATH = DEVICE_SNAPSHOT_API_PATH;\r\n\r\nexport const REFRESH_TIMEOUT_MS = 60_000;\r\n\r\n/** @deprecated Use REFRESH_TIMEOUT_MS */\r\nexport const SYNC_TIMEOUT_MS = REFRESH_TIMEOUT_MS;\r\n\r\nexport const WRITE_TRANSACTION_TIMEOUT_MS = 5 * 60 * 1000;\r\n\r\nexport const MAX_SNAPSHOT_BYTES = 50 * 1024 * 1024;\r\n\r\nexport function createMessage<T extends DevToolsMessageBase>(\r\n  message: Omit<T, 'timestamp'>,\r\n): T {\r\n  return { ...message, timestamp: Date.now() } as T;\r\n}\r\n\r\nexport function buildDevToolsHttpUrl(\r\n  host = 'localhost',\r\n  port = DEFAULT_DEVTOOLS_PORT,\r\n): string {\r\n  return `http://${host}:${port}`;\r\n}\r\n\r\nexport function buildDevToolsWsUrl(\r\n  host = 'localhost',\r\n  port = DEFAULT_DEVTOOLS_PORT,\r\n): string {\r\n  return `ws://${host}:${port}${DEVTOOLS_WS_PATH}`;\r\n}\r\n\r\nexport function buildDeviceSnapshotUrl(httpBaseUrl: string, deviceId: string): string {\r\n  const base = httpBaseUrl.replace(/\\/$/, '');\r\n  return `${base}${DEVICE_SNAPSHOT_API_PATH}/${encodeURIComponent(deviceId)}/snapshot`;\r\n}\r\n\r\n/** @deprecated Use buildDeviceSnapshotUrl */\r\nexport function buildSnapshotUrl(httpBaseUrl: string, deviceId: string): string {\r\n  return buildDeviceSnapshotUrl(httpBaseUrl, deviceId);\r\n}\r\n\r\nexport function wsUrlToHttpUrl(wsUrl: string): string {\r\n  const url = new URL(wsUrl);\r\n  url.protocol = url.protocol === 'wss:' ? 'https:' : 'http:';\r\n  url.pathname = '';\r\n  url.search = '';\r\n  url.hash = '';\r\n  return url.toString().replace(/\\/$/, '');\r\n}\r\n\r\nfunction hasMessageType(value: unknown): value is { type: string } {\r\n  return typeof value === 'object' && value !== null && typeof (value as { type: unknown }).type === 'string';\r\n}\r\n\r\nexport function isRegisterMessage(value: unknown): value is RegisterMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.REGISTER) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as RegisterMessage;\r\n  return (\r\n    message.role === DevToolsRole.MOBILE || message.role === DevToolsRole.BROWSER\r\n  );\r\n}\r\n\r\nexport function isPongMessage(value: unknown): value is PongMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.PONG) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as PongMessage;\r\n  return typeof message.pingId === 'string';\r\n}\r\n\r\nexport function isRefreshRequestMessage(value: unknown): value is RefreshRequestMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.REFRESH_REQUEST) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as RefreshRequestMessage;\r\n  return typeof message.deviceId === 'string' && message.refreshType === 'snapshot';\r\n}\r\n\r\nexport function isSnapshotUploadRequestedMessage(\r\n  value: unknown,\r\n): value is SnapshotUploadRequestedMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.SNAPSHOT_UPLOAD_REQUESTED) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as SnapshotUploadRequestedMessage;\r\n  return typeof message.deviceId === 'string' && message.refreshType === 'snapshot';\r\n}\r\n\r\nexport function isRefreshStatusMessage(value: unknown): value is RefreshStatusMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.REFRESH_STATUS) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as RefreshStatusMessage;\r\n  return typeof message.deviceId === 'string' && typeof message.state === 'string';\r\n}\r\n\r\nexport function isSnapshotReadyMessage(value: unknown): value is SnapshotReadyMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.SNAPSHOT_READY) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as SnapshotReadyMessage;\r\n  return (\r\n    typeof message.deviceId === 'string' &&\r\n    typeof message.size === 'number' &&\r\n    typeof message.exportedAt === 'number' &&\r\n    typeof message.kind === 'string' &&\r\n    typeof message.mimeType === 'string'\r\n  );\r\n}\r\n\r\nexport function isRefreshErrorMessage(value: unknown): value is RefreshErrorMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.REFRESH_ERROR) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as RefreshErrorMessage;\r\n  return typeof message.deviceId === 'string' && typeof message.code === 'string';\r\n}\r\n\r\nexport function isExportSnapshotRequestMessage(\r\n  value: unknown,\r\n): value is ExportSnapshotRequestMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.EXPORT_SNAPSHOT_REQUEST) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as ExportSnapshotRequestMessage;\r\n  return message.refreshType === 'snapshot';\r\n}\r\n\r\nexport function isExportSnapshotErrorMessage(\r\n  value: unknown,\r\n): value is ExportSnapshotErrorMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.EXPORT_SNAPSHOT_ERROR) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as ExportSnapshotErrorMessage;\r\n  return typeof message.code === 'string' && typeof message.message === 'string';\r\n}\r\n\r\nexport function isBeginTransactionRequestMessage(\r\n  value: unknown,\r\n): value is BeginTransactionRequestMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.BEGIN_TRANSACTION_REQUEST) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as BeginTransactionRequestMessage;\r\n  return typeof message.transactionId === 'string' && typeof message.deviceId === 'string';\r\n}\r\n\r\nexport function isCommitTransactionRequestMessage(\r\n  value: unknown,\r\n): value is CommitTransactionRequestMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.COMMIT_TRANSACTION_REQUEST) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as CommitTransactionRequestMessage;\r\n  return typeof message.transactionId === 'string' && typeof message.deviceId === 'string';\r\n}\r\n\r\nexport function isRollbackTransactionRequestMessage(\r\n  value: unknown,\r\n): value is RollbackTransactionRequestMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.ROLLBACK_TRANSACTION_REQUEST) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as RollbackTransactionRequestMessage;\r\n  return typeof message.transactionId === 'string' && typeof message.deviceId === 'string';\r\n}\r\n\r\nexport function isWriteRequestMessage(value: unknown): value is WriteRequestMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.WRITE_REQUEST) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as WriteRequestMessage;\r\n  return (\r\n    typeof message.writeId === 'string' &&\r\n    typeof message.transactionId === 'string' &&\r\n    typeof message.deviceId === 'string' &&\r\n    typeof message.operation === 'object' &&\r\n    message.operation !== null\r\n  );\r\n}\r\n\r\nexport function isTransactionAckMessage(value: unknown): value is TransactionAckMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.TRANSACTION_ACK) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as TransactionAckMessage;\r\n  return (\r\n    typeof message.transactionId === 'string' &&\r\n    (message.action === 'begin' || message.action === 'commit' || message.action === 'rollback') &&\r\n    typeof message.ok === 'boolean'\r\n  );\r\n}\r\n\r\nexport function isWriteAckMessage(value: unknown): value is WriteAckMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.WRITE_ACK) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as WriteAckMessage;\r\n  return (\r\n    typeof message.writeId === 'string' &&\r\n    typeof message.transactionId === 'string' &&\r\n    typeof message.ok === 'boolean'\r\n  );\r\n}\r\n\r\nexport function isClientMessage(value: unknown): value is ClientMessage {\r\n  return (\r\n    isRegisterMessage(value) ||\r\n    isPongMessage(value) ||\r\n    isRefreshRequestMessage(value) ||\r\n    isExportSnapshotRequestMessage(value) ||\r\n    isBeginTransactionRequestMessage(value) ||\r\n    isCommitTransactionRequestMessage(value) ||\r\n    isRollbackTransactionRequestMessage(value) ||\r\n    isWriteRequestMessage(value) ||\r\n    isTransactionAckMessage(value) ||\r\n    isWriteAckMessage(value)\r\n  );\r\n}\r\n\r\nexport function isPingMessage(value: unknown): value is PingMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.PING) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as PingMessage;\r\n  return typeof message.pingId === 'string';\r\n}\r\n\r\nexport function isDeviceStatusMessage(value: unknown): value is DeviceStatusMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.DEVICE_STATUS) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as DeviceStatusMessage;\r\n  return typeof message.payload === 'object' && message.payload !== null;\r\n}\r\n\r\nexport function isBroadcastMessage(value: unknown): value is BroadcastMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.BROADCAST) {\r\n    return false;\r\n  }\r\n\r\n  return true;\r\n}\r\n\r\nexport function isBeginTransactionMessage(value: unknown): value is BeginTransactionMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.BEGIN_TRANSACTION) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as BeginTransactionMessage;\r\n  return typeof message.transactionId === 'string';\r\n}\r\n\r\nexport function isCommitTransactionMessage(value: unknown): value is CommitTransactionMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.COMMIT_TRANSACTION) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as CommitTransactionMessage;\r\n  return typeof message.transactionId === 'string';\r\n}\r\n\r\nexport function isRollbackTransactionMessage(value: unknown): value is RollbackTransactionMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.ROLLBACK_TRANSACTION) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as RollbackTransactionMessage;\r\n  return typeof message.transactionId === 'string';\r\n}\r\n\r\nexport function isExecuteWriteMessage(value: unknown): value is ExecuteWriteMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.EXECUTE_WRITE) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as ExecuteWriteMessage;\r\n  return (\r\n    typeof message.writeId === 'string' &&\r\n    typeof message.transactionId === 'string' &&\r\n    typeof message.operation === 'object' &&\r\n    message.operation !== null\r\n  );\r\n}\r\n\r\nexport function isTransactionStatusMessage(value: unknown): value is TransactionStatusMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.TRANSACTION_STATUS) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as TransactionStatusMessage;\r\n  return (\r\n    typeof message.transactionId === 'string' &&\r\n    typeof message.deviceId === 'string' &&\r\n    typeof message.state === 'string'\r\n  );\r\n}\r\n\r\nexport function isWriteResultMessage(value: unknown): value is WriteResultMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.WRITE_RESULT) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as WriteResultMessage;\r\n  return (\r\n    typeof message.writeId === 'string' &&\r\n    typeof message.transactionId === 'string' &&\r\n    typeof message.rowsAffected === 'number'\r\n  );\r\n}\r\n\r\nexport function isWriteErrorMessage(value: unknown): value is WriteErrorMessage {\r\n  if (!hasMessageType(value) || value.type !== MessageType.WRITE_ERROR) {\r\n    return false;\r\n  }\r\n\r\n  const message = value as WriteErrorMessage;\r\n  return typeof message.transactionId === 'string' && typeof message.code === 'string';\r\n}\r\n\r\nexport function isServerMessage(value: unknown): value is ServerMessage {\r\n  return (\r\n    isPingMessage(value) ||\r\n    isDeviceStatusMessage(value) ||\r\n    isBroadcastMessage(value) ||\r\n    isSnapshotUploadRequestedMessage(value) ||\r\n    isRefreshStatusMessage(value) ||\r\n    isSnapshotReadyMessage(value) ||\r\n    isRefreshErrorMessage(value) ||\r\n    isExportSnapshotErrorMessage(value) ||\r\n    isBeginTransactionMessage(value) ||\r\n    isCommitTransactionMessage(value) ||\r\n    isRollbackTransactionMessage(value) ||\r\n    isExecuteWriteMessage(value) ||\r\n    isTransactionStatusMessage(value) ||\r\n    isWriteResultMessage(value) ||\r\n    isWriteErrorMessage(value)\r\n  );\r\n}\r\n","import type { DatabaseKind } from '../types/kind';\r\n\r\nexport const SNAPSHOT_KIND_HEADER = 'x-database-kind';\r\nexport const SNAPSHOT_MIME_HEADER = 'x-snapshot-mime-type';\r\nexport const SNAPSHOT_NAME_HEADER = 'x-database-name';\r\n\r\nexport const SQLITE_SNAPSHOT_MIME_TYPE = 'application/x-sqlite3';\r\n\r\nexport type SnapshotExport = {\r\n  bytes: Uint8Array;\r\n  mimeType: string;\r\n  kind: DatabaseKind;\r\n  exportedAt?: number;\r\n};\r\n","const RESET = '\\x1b[0m';\r\nconst GREEN = '\\x1b[32m';\r\nconst YELLOW = '\\x1b[33m';\r\nconst CYAN = '\\x1b[36m';\r\nconst RED = '\\x1b[31m';\r\nconst DIM = '\\x1b[2m';\r\n\r\nconst PREFIX = `${DIM}[database-devtools]${RESET}`;\r\n\r\nfunction log(color: string, symbol: string, message: string): void {\r\n  console.log(`${PREFIX} ${color}${symbol}${RESET} ${message}`);\r\n}\r\n\r\nexport const logger = {\r\n  browserConnected(connectionId?: string): void {\r\n    const suffix = connectionId ? ` ${DIM}(${connectionId})${RESET}` : '';\r\n    log(GREEN, '✓', `Browser Connected${suffix}`);\r\n  },\r\n\r\n  browserDisconnected(connectionId?: string): void {\r\n    const suffix = connectionId ? ` ${DIM}(${connectionId})${RESET}` : '';\r\n    log(YELLOW, '✓', `Browser Disconnected${suffix}`);\r\n  },\r\n\r\n  mobileConnected(deviceId?: string): void {\r\n    const suffix = deviceId ? ` ${DIM}(deviceId: ${deviceId})${RESET}` : '';\r\n    log(GREEN, '✓', `Mobile Connected${suffix}`);\r\n  },\r\n\r\n  mobileDisconnected(deviceId?: string): void {\r\n    const suffix = deviceId ? ` ${DIM}(deviceId: ${deviceId})${RESET}` : '';\r\n    log(YELLOW, '✓', `Mobile Disconnected${suffix}`);\r\n  },\r\n\r\n  broadcastSent(target?: string): void {\r\n    const suffix = target ? ` ${DIM}→ ${target}${RESET}` : '';\r\n    log(CYAN, '✓', `Broadcast Sent${suffix}`);\r\n  },\r\n\r\n  serverStarted(url: string, wsUrl: string, webUiEnabled = false): void {\r\n    log(GREEN, '✓', `Server started at ${url}`);\r\n    log(GREEN, '✓', `WebSocket endpoint ${wsUrl}`);\r\n\r\n    if (webUiEnabled) {\r\n      log(GREEN, '✓', `Browser UI available at ${url}`);\r\n    }\r\n  },\r\n\r\n  heartbeatTimeout(connectionId: string): void {\r\n    log(RED, '✓', `Heartbeat timeout — removing ${connectionId}`);\r\n  },\r\n\r\n  refreshStarted(deviceId: string): void {\r\n    log(CYAN, '↻', `Refresh started ${DIM}(${deviceId})${RESET}`);\r\n  },\r\n\r\n  refreshUploaded(deviceId: string, bytes: number): void {\r\n    log(GREEN, '↻', `Snapshot uploaded ${DIM}(${deviceId}, ${bytes} bytes)${RESET}`);\r\n  },\r\n\r\n  refreshFailed(deviceId: string, code: string, message: string): void {\r\n    log(RED, '↻', `Refresh failed ${DIM}(${deviceId}: ${code})${RESET} ${message}`);\r\n  },\r\n\r\n  /** @deprecated Use refreshStarted */\r\n  syncStarted(syncId: string, deviceId: string): void {\r\n    this.refreshStarted(deviceId);\r\n  },\r\n\r\n  /** @deprecated Use refreshUploaded */\r\n  syncUploaded(syncId: string, bytes: number): void {\r\n    this.refreshUploaded(syncId, bytes);\r\n  },\r\n\r\n  /** @deprecated Use refreshFailed */\r\n  syncFailed(syncId: string, code: string, message: string): void {\r\n    this.refreshFailed(syncId, code, message);\r\n  },\r\n\r\n  error(message: string): void {\r\n    log(RED, '✗', message);\r\n  },\r\n};\r\n","import { existsSync } from 'node:fs';\r\nimport path from 'node:path';\r\nimport type { Express, Request, Response } from 'express';\r\nimport express from 'express';\r\n\r\nfunction shouldServeSpa(request: Request): boolean {\r\n  if (request.method !== 'GET' && request.method !== 'HEAD') {\r\n    return false;\r\n  }\r\n\r\n  if (request.path.startsWith('/api')) {\r\n    return false;\r\n  }\r\n\r\n  if (request.path === '/health') {\r\n    return false;\r\n  }\r\n\r\n  return true;\r\n}\r\n\r\nexport function attachWebUi(app: Express, webDistPath: string): void {\r\n  const indexPath = path.join(webDistPath, 'index.html');\r\n\r\n  if (!existsSync(indexPath)) {\r\n    return;\r\n  }\r\n\r\n  app.use(\r\n    express.static(webDistPath, {\r\n      index: false,\r\n      setHeaders(response, filePath) {\r\n        if (filePath.endsWith('.wasm')) {\r\n          response.setHeader('Content-Type', 'application/wasm');\r\n        }\r\n      },\r\n    }),\r\n  );\r\n\r\n  app.get('*', (request: Request, response: Response, next) => {\r\n    if (!shouldServeSpa(request)) {\r\n      next();\r\n      return;\r\n    }\r\n\r\n    response.sendFile(indexPath);\r\n  });\r\n}\r\n","import type { Server } from 'node:http';\r\nimport { WebSocketServer, type WebSocket } from 'ws';\r\nimport {\r\n  DEVTOOLS_WS_PATH,\r\n  DevToolsRole,\r\n  isBeginTransactionRequestMessage,\r\n  isCommitTransactionRequestMessage,\r\n  isExportSnapshotRequestMessage,\r\n  isPongMessage,\r\n  isRefreshRequestMessage,\r\n  isRegisterMessage,\r\n  isRollbackTransactionRequestMessage,\r\n  isTransactionAckMessage,\r\n  isWriteAckMessage,\r\n  isWriteRequestMessage,\r\n} from '../types/protocol';\r\nimport { logger } from '../utils/logger';\r\nimport type { ConnectionManager } from './connectionManager';\r\nimport type { Heartbeat } from './heartbeat';\r\nimport type { MessageRouter } from './messageRouter';\r\nimport type { RefreshCoordinator } from './refreshCoordinator';\r\nimport type { SnapshotFileStore } from './snapshotFileStore';\r\nimport type { WriteCoordinator } from './writeCoordinator';\r\n\r\nexport type AttachWebSocketOptions = {\r\n  snapshotFileStore?: SnapshotFileStore;\r\n};\r\n\r\nexport type AttachWebSocketResult = {\r\n  wss: WebSocketServer;\r\n};\r\n\r\nexport function attachWebSocket(\r\n  httpServer: Server,\r\n  connectionManager: ConnectionManager,\r\n  router: MessageRouter,\r\n  heartbeat: Heartbeat,\r\n  refreshCoordinator: RefreshCoordinator,\r\n  writeCoordinator: WriteCoordinator,\r\n  options?: AttachWebSocketOptions,\r\n): AttachWebSocketResult {\r\n  const wss = new WebSocketServer({ server: httpServer, path: DEVTOOLS_WS_PATH });\r\n\r\n  const handleDisconnect = (socket: WebSocket): void => {\r\n    const client = connectionManager.remove(socket);\r\n\r\n    if (!client) {\r\n      return;\r\n    }\r\n\r\n    if (client.role === DevToolsRole.MOBILE) {\r\n      if (client.deviceId) {\r\n        writeCoordinator.rollbackSessionsForDevice(client.deviceId);\r\n      }\r\n\r\n      logger.mobileDisconnected(client.deviceId);\r\n    } else {\r\n      writeCoordinator.rollbackSessionsOnBrowserDisconnect(client.connectionId);\r\n      logger.browserDisconnected(client.connectionId);\r\n    }\r\n\r\n    router.broadcastDeviceStatus();\r\n  };\r\n\r\n  wss.on('connection', (socket: WebSocket) => {\r\n    socket.on('message', (raw) => {\r\n      let parsed: unknown;\r\n\r\n      try {\r\n        parsed = JSON.parse(String(raw));\r\n      } catch {\r\n        return;\r\n      }\r\n\r\n      if (isRegisterMessage(parsed)) {\r\n        const existing = connectionManager.getBySocket(socket);\r\n\r\n        if (existing) {\r\n          return;\r\n        }\r\n\r\n        const client = connectionManager.add({\r\n          socket,\r\n          role: parsed.role,\r\n          deviceId: parsed.deviceId,\r\n          metadata: parsed.metadata,\r\n        });\r\n\r\n        if (client.role === DevToolsRole.MOBILE) {\r\n          logger.mobileConnected(client.deviceId);\r\n\r\n          if (client.deviceId && options?.snapshotFileStore) {\r\n            void options.snapshotFileStore\r\n              .reconcileOnMobileConnect({\r\n                deviceId: client.deviceId,\r\n                bundleId: client.metadata?.bundleId,\r\n              })\r\n              .finally(() => {\r\n                router.broadcastDeviceStatus();\r\n              });\r\n            return;\r\n          }\r\n        } else {\r\n          logger.browserConnected(client.connectionId);\r\n        }\r\n\r\n        router.broadcastDeviceStatus();\r\n        return;\r\n      }\r\n\r\n      if (isPongMessage(parsed)) {\r\n        connectionManager.updateLastPong(socket);\r\n        return;\r\n      }\r\n\r\n      if (isRefreshRequestMessage(parsed)) {\r\n        refreshCoordinator.handleRefreshRequest(socket, parsed);\r\n        return;\r\n      }\r\n\r\n      if (isExportSnapshotRequestMessage(parsed)) {\r\n        refreshCoordinator.handleMobileExportRequest(socket, parsed);\r\n        return;\r\n      }\r\n\r\n      if (isBeginTransactionRequestMessage(parsed)) {\r\n        writeCoordinator.handleBeginTransactionRequest(socket, parsed);\r\n        return;\r\n      }\r\n\r\n      if (isCommitTransactionRequestMessage(parsed)) {\r\n        writeCoordinator.handleCommitTransactionRequest(socket, parsed);\r\n        return;\r\n      }\r\n\r\n      if (isRollbackTransactionRequestMessage(parsed)) {\r\n        writeCoordinator.handleRollbackTransactionRequest(socket, parsed);\r\n        return;\r\n      }\r\n\r\n      if (isWriteRequestMessage(parsed)) {\r\n        writeCoordinator.handleWriteRequest(socket, parsed);\r\n        return;\r\n      }\r\n\r\n      if (isTransactionAckMessage(parsed)) {\r\n        writeCoordinator.handleTransactionAck(parsed);\r\n        return;\r\n      }\r\n\r\n      if (isWriteAckMessage(parsed)) {\r\n        writeCoordinator.handleWriteAck(parsed);\r\n      }\r\n    });\r\n\r\n    socket.on('close', () => {\r\n      handleDisconnect(socket);\r\n    });\r\n\r\n    socket.on('error', () => {\r\n      handleDisconnect(socket);\r\n    });\r\n  });\r\n\r\n  heartbeat.start();\r\n\r\n  return { wss };\r\n}\r\n","export function generateConnectionId(): string {\r\n  return generateUniqueId('conn');\r\n}\r\n\r\nexport function generateDeviceId(): string {\r\n  return generateUniqueId('device');\r\n}\r\n\r\nexport function generatePingId(): string {\r\n  return generateUniqueId('ping');\r\n}\r\n\r\nexport function generateSyncId(): string {\r\n  return generateUniqueId('sync');\r\n}\r\n\r\nexport function generateTransactionId(): string {\r\n  return generateUniqueId('txn');\r\n}\r\n\r\nexport function generateWriteId(): string {\r\n  return generateUniqueId('write');\r\n}\r\n\r\nfunction generateUniqueId(prefix: string): string {\r\n  if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\r\n    return `${prefix}-${crypto.randomUUID()}`;\r\n  }\r\n\r\n  const random = Math.random().toString(36).slice(2, 10);\r\n  return `${prefix}-${Date.now()}-${random}`;\r\n}\r\n","import type { WebSocket } from 'ws';\nimport type { DevToolsRole, DeviceMetadata } from '../types/protocol';\nimport { generateConnectionId } from '../utils/ids';\n\nexport type ConnectedClient = {\n  socket: WebSocket;\n  connectionId: string;\n  role: DevToolsRole;\n  deviceId?: string;\n  metadata?: DeviceMetadata;\n  connectedAt: number;\n  lastPongAt: number;\n};\n\nexport type RegisterClientInput = {\n  socket: WebSocket;\n  role: DevToolsRole;\n  deviceId?: string;\n  metadata?: DeviceMetadata;\n};\n\nexport class ConnectionManager {\n  private readonly clients = new Map<WebSocket, ConnectedClient>();\n\n  add(input: RegisterClientInput): ConnectedClient {\n    const now = Date.now();\n    const client: ConnectedClient = {\n      socket: input.socket,\n      connectionId: generateConnectionId(),\n      role: input.role,\n      deviceId: input.deviceId,\n      metadata: input.metadata,\n      connectedAt: now,\n      lastPongAt: now,\n    };\n\n    this.clients.set(input.socket, client);\n    return client;\n  }\n\n  remove(socket: WebSocket): ConnectedClient | undefined {\n    const client = this.clients.get(socket);\n\n    if (client) {\n      this.clients.delete(socket);\n    }\n\n    return client;\n  }\n\n  getBySocket(socket: WebSocket): ConnectedClient | undefined {\n    return this.clients.get(socket);\n  }\n\n  getByConnectionId(connectionId: string): ConnectedClient | undefined {\n    for (const client of this.clients.values()) {\n      if (client.connectionId === connectionId) {\n        return client;\n      }\n    }\n\n    return undefined;\n  }\n\n  getByDeviceId(deviceId: string): ConnectedClient | undefined {\n    for (const client of this.clients.values()) {\n      if (client.deviceId === deviceId) {\n        return client;\n      }\n    }\n\n    return undefined;\n  }\n\n  getByRole(role: DevToolsRole): ConnectedClient[] {\n    return [...this.clients.values()].filter((client) => client.role === role);\n  }\n\n  updateLastPong(socket: WebSocket): void {\n    const client = this.clients.get(socket);\n\n    if (client) {\n      client.lastPongAt = Date.now();\n    }\n  }\n\n  getAll(): ConnectedClient[] {\n    return [...this.clients.values()];\n  }\n}\n","import type { NextFunction, Request, Response } from 'express';\r\nimport {\r\n  SNAPSHOT_KIND_HEADER,\r\n  SNAPSHOT_MIME_HEADER,\r\n  SNAPSHOT_NAME_HEADER,\r\n} from '../types/snapshot';\r\n\r\nconst ALLOWED_METHODS = 'GET, POST, OPTIONS';\r\n\r\nconst ALLOWED_HEADERS = [\r\n  'Content-Type',\r\n  SNAPSHOT_KIND_HEADER,\r\n  SNAPSHOT_MIME_HEADER,\r\n  SNAPSHOT_NAME_HEADER,\r\n].join(', ');\r\n\r\nexport type CorsOptions = {\r\n  /** Fixed origin, or `*` when request has no Origin header. */\r\n  allowedOrigin?: string;\r\n};\r\n\r\nexport function resolveCorsOrigin(\r\n  requestOrigin: string | undefined,\r\n  configuredOrigin?: string,\r\n): string {\r\n  if (configuredOrigin) {\r\n    return configuredOrigin;\r\n  }\r\n\r\n  if (!requestOrigin) {\r\n    return '*';\r\n  }\r\n\r\n  try {\r\n    const url = new URL(requestOrigin);\r\n    const isLocalDev =\r\n      url.hostname === 'localhost' ||\r\n      url.hostname === '127.0.0.1' ||\r\n      url.hostname === '10.0.2.2';\r\n\r\n    if (isLocalDev) {\r\n      return requestOrigin;\r\n    }\r\n  } catch {\r\n    return '*';\r\n  }\r\n\r\n  return '*';\r\n}\r\n\r\nexport function createCorsMiddleware(options: CorsOptions = {}) {\r\n  const configuredOrigin = options.allowedOrigin ?? process.env.DATABASE_DEVTOOLS_CORS_ORIGIN;\r\n\r\n  return (request: Request, response: Response, next: NextFunction): void => {\r\n    const origin = resolveCorsOrigin(request.header('origin'), configuredOrigin);\r\n\r\n    response.setHeader('Access-Control-Allow-Origin', origin);\r\n    response.setHeader('Access-Control-Allow-Methods', ALLOWED_METHODS);\r\n    response.setHeader('Access-Control-Allow-Headers', ALLOWED_HEADERS);\r\n    response.setHeader('Vary', 'Origin');\r\n\r\n    if (request.method === 'OPTIONS') {\r\n      response.status(204).end();\r\n      return;\r\n    }\r\n\r\n    next();\r\n  };\r\n}\r\n","import type { ConnectionManager } from './connectionManager';\nimport type { DeviceStatusPayload } from '../types/protocol';\nimport { DevToolsRole } from '../types/protocol';\n\nexport class DeviceRegistry {\n  constructor(private readonly connectionManager: ConnectionManager) {}\n\n  snapshot(): DeviceStatusPayload {\n    const browsers = this.connectionManager\n      .getByRole(DevToolsRole.BROWSER)\n      .map((client) => ({\n        connectionId: client.connectionId,\n        connectedAt: client.connectedAt,\n      }));\n\n    const mobiles = this.connectionManager\n      .getByRole(DevToolsRole.MOBILE)\n      .map((client) => ({\n        deviceId: client.deviceId ?? client.connectionId,\n        connectionId: client.connectionId,\n        connectedAt: client.connectedAt,\n        metadata: client.metadata,\n      }));\n\n    return {\n      browserCount: browsers.length,\n      mobileCount: mobiles.length,\n      browsers,\n      mobiles,\n    };\n  }\n}\n","import {\n  createMessage,\n  HEARTBEAT_INTERVAL_MS,\n  HEARTBEAT_TIMEOUT_MS,\n  MessageType,\n  type PingMessage,\n} from '../types/protocol';\nimport { generatePingId } from '../utils/ids';\nimport { logger } from '../utils/logger';\nimport type { ConnectionManager } from './connectionManager';\nimport type { MessageRouter } from './messageRouter';\n\nexport class Heartbeat {\n  private interval: ReturnType<typeof setInterval> | null = null;\n\n  constructor(\n    private readonly connectionManager: ConnectionManager,\n    private readonly router: MessageRouter,\n  ) {}\n\n  start(): void {\n    if (this.interval !== null) {\n      return;\n    }\n\n    this.interval = setInterval(() => {\n      this.pingAll();\n      this.removeStaleConnections();\n    }, HEARTBEAT_INTERVAL_MS);\n  }\n\n  stop(): void {\n    if (this.interval !== null) {\n      clearInterval(this.interval);\n      this.interval = null;\n    }\n  }\n\n  private pingAll(): void {\n    const pingId = generatePingId();\n    const message = createMessage<PingMessage>({\n      type: MessageType.PING,\n      pingId,\n    });\n\n    for (const client of this.connectionManager.getAll()) {\n      this.router.sendToSocket(client.socket, message);\n    }\n  }\n\n  private removeStaleConnections(): void {\n    const now = Date.now();\n\n    for (const client of this.connectionManager.getAll()) {\n      if (now - client.lastPongAt > HEARTBEAT_INTERVAL_MS + HEARTBEAT_TIMEOUT_MS) {\n        logger.heartbeatTimeout(client.connectionId);\n        client.socket.terminate();\n        this.connectionManager.remove(client.socket);\n      }\n    }\n  }\n}\n","import type { WebSocket } from 'ws';\nimport {\n  createMessage,\n  DevToolsRole,\n  MessageType,\n  type BroadcastMessage,\n  type DeviceStatusMessage,\n  type ServerMessage,\n} from '../types/protocol';\nimport { logger } from '../utils/logger';\nimport type { ConnectionManager } from './connectionManager';\nimport type { DeviceRegistry } from './deviceRegistry';\n\nexport type OutboundMessage = ServerMessage;\n\nexport class MessageRouter {\n  constructor(\n    private readonly connectionManager: ConnectionManager,\n    private readonly deviceRegistry: DeviceRegistry,\n  ) {}\n\n  sendToSocket(socket: WebSocket, message: OutboundMessage): void {\n    if (socket.readyState === socket.OPEN) {\n      socket.send(JSON.stringify(message));\n    }\n  }\n\n  sendToBrowser(connectionId: string, message: OutboundMessage): void {\n    const client = this.connectionManager.getByConnectionId(connectionId);\n\n    if (client?.role === DevToolsRole.BROWSER) {\n      this.sendToSocket(client.socket, message);\n    }\n  }\n\n  sendToMobile(deviceId: string, message: OutboundMessage): void {\n    const client = this.connectionManager.getByDeviceId(deviceId);\n\n    if (client?.role === DevToolsRole.MOBILE) {\n      this.sendToSocket(client.socket, message);\n    }\n  }\n\n  broadcastToBrowsers(message: OutboundMessage): void {\n    for (const client of this.connectionManager.getByRole(DevToolsRole.BROWSER)) {\n      this.sendToSocket(client.socket, message);\n    }\n\n    logger.broadcastSent('browsers');\n  }\n\n  broadcastToMobiles(message: OutboundMessage): void {\n    for (const client of this.connectionManager.getByRole(DevToolsRole.MOBILE)) {\n      this.sendToSocket(client.socket, message);\n    }\n\n    logger.broadcastSent('mobiles');\n  }\n\n  broadcastToAll(message: OutboundMessage): void {\n    for (const client of this.connectionManager.getAll()) {\n      this.sendToSocket(client.socket, message);\n    }\n\n    logger.broadcastSent('all');\n  }\n\n  broadcast(message: unknown, target: 'browsers' | 'mobiles' | 'all' = 'all'): void {\n    const broadcastMessage = createMessage<BroadcastMessage>({\n      type: MessageType.BROADCAST,\n      payload: message,\n    });\n\n    if (target === 'browsers') {\n      this.broadcastToBrowsers(broadcastMessage);\n      return;\n    }\n\n    if (target === 'mobiles') {\n      this.broadcastToMobiles(broadcastMessage);\n      return;\n    }\n\n    this.broadcastToAll(broadcastMessage);\n  }\n\n  broadcastDeviceStatus(): void {\n    const message = createMessage<DeviceStatusMessage>({\n      type: MessageType.DEVICE_STATUS,\n      payload: this.deviceRegistry.snapshot(),\n    });\n\n    this.broadcastToAll(message);\n  }\n}\n","import type { RefreshInitiator, RefreshType } from '../types/protocol';\r\nimport { REFRESH_TIMEOUT_MS } from '../types/protocol';\r\n\r\nexport type PendingRefresh = {\r\n  deviceId: string;\r\n  refreshType: RefreshType;\r\n  startedAt: number;\r\n  initiator: RefreshInitiator;\r\n  browserConnectionId?: string;\r\n  notifyAllBrowsers?: boolean;\r\n};\r\n\r\nexport class PendingRefreshStore {\r\n  private readonly pendingByDevice = new Map<string, PendingRefresh>();\r\n\r\n  create(input: PendingRefresh): void {\r\n    this.pendingByDevice.set(input.deviceId, input);\r\n  }\r\n\r\n  get(deviceId: string): PendingRefresh | undefined {\r\n    return this.pendingByDevice.get(deviceId);\r\n  }\r\n\r\n  has(deviceId: string): boolean {\r\n    return this.pendingByDevice.has(deviceId);\r\n  }\r\n\r\n  remove(deviceId: string): void {\r\n    this.pendingByDevice.delete(deviceId);\r\n  }\r\n\r\n  getExpired(now = Date.now()): PendingRefresh[] {\r\n    return [...this.pendingByDevice.values()].filter(\r\n      (pending) => now - pending.startedAt >= REFRESH_TIMEOUT_MS,\r\n    );\r\n  }\r\n}\r\n","import type { WebSocket } from 'ws';\r\nimport {\r\n  createMessage,\r\n  DevToolsRole,\r\n  MessageType,\r\n  type ExportSnapshotErrorMessage,\r\n  type ExportSnapshotRequestMessage,\r\n  type RefreshErrorCode,\r\n  type RefreshErrorMessage,\r\n  type RefreshRequestMessage,\r\n  type RefreshState,\r\n  type RefreshStatusMessage,\r\n  type SnapshotReadyMessage,\r\n  type SnapshotUploadRequestedMessage,\r\n} from '../types/protocol';\r\nimport { logger } from '../utils/logger';\r\nimport type { ConnectionManager } from './connectionManager';\r\nimport type { MessageRouter } from './messageRouter';\r\nimport type { PendingRefreshStore } from './pendingRefreshStore';\r\nimport type { SnapshotFileStore } from './snapshotFileStore';\r\nimport type { SnapshotStore } from './snapshotStore';\r\n\r\nexport class RefreshCoordinator {\r\n  constructor(\r\n    private readonly connectionManager: ConnectionManager,\r\n    private readonly router: MessageRouter,\r\n    private readonly pending: PendingRefreshStore,\r\n    private readonly snapshots: SnapshotStore,\r\n    private readonly snapshotFiles?: SnapshotFileStore,\r\n  ) {}\r\n\r\n  handleRefreshRequest(browserSocket: WebSocket, message: RefreshRequestMessage): void {\r\n    const browser = this.connectionManager.getBySocket(browserSocket);\r\n\r\n    if (!browser || browser.role !== DevToolsRole.BROWSER) {\r\n      return;\r\n    }\r\n\r\n    if (message.refreshType !== 'snapshot') {\r\n      this.sendRefreshError(browser.connectionId, {\r\n        deviceId: message.deviceId,\r\n        code: 'INVALID_REQUEST',\r\n        message: `Unsupported refresh type: ${message.refreshType}`,\r\n      });\r\n      return;\r\n    }\r\n\r\n    const mobile = this.connectionManager.getByDeviceId(message.deviceId);\r\n\r\n    if (!mobile) {\r\n      this.sendRefreshError(browser.connectionId, {\r\n        deviceId: message.deviceId,\r\n        code: 'DEVICE_OFFLINE',\r\n        message: `Device ${message.deviceId} is not connected`,\r\n      });\r\n      return;\r\n    }\r\n\r\n    if (this.pending.has(message.deviceId)) {\r\n      this.sendRefreshError(browser.connectionId, {\r\n        deviceId: message.deviceId,\r\n        code: 'REFRESH_IN_PROGRESS',\r\n        message: 'A refresh is already in progress for this device',\r\n      });\r\n      return;\r\n    }\r\n\r\n    this.pending.create({\r\n      deviceId: message.deviceId,\r\n      initiator: 'browser',\r\n      browserConnectionId: browser.connectionId,\r\n      refreshType: message.refreshType,\r\n      startedAt: Date.now(),\r\n    });\r\n\r\n    logger.refreshStarted(message.deviceId);\r\n\r\n    this.sendRefreshStatus(browser.connectionId, message.deviceId, 'requested');\r\n    this.sendRefreshStatus(browser.connectionId, message.deviceId, 'exporting');\r\n\r\n    this.requestMobileUpload(message.deviceId, message.refreshType);\r\n  }\r\n\r\n  handleMobileExportRequest(mobileSocket: WebSocket, message: ExportSnapshotRequestMessage): void {\r\n    const mobile = this.connectionManager.getBySocket(mobileSocket);\r\n\r\n    if (!mobile || mobile.role !== DevToolsRole.MOBILE || !mobile.deviceId) {\r\n      return;\r\n    }\r\n\r\n    if (message.refreshType !== 'snapshot') {\r\n      this.sendExportSnapshotError(mobileSocket, {\r\n        code: 'INVALID_REQUEST',\r\n        message: `Unsupported refresh type: ${message.refreshType}`,\r\n      });\r\n      return;\r\n    }\r\n\r\n    if (this.pending.has(mobile.deviceId)) {\r\n      this.sendExportSnapshotError(mobileSocket, {\r\n        code: 'REFRESH_IN_PROGRESS',\r\n        message: 'An export is already in progress for this device',\r\n      });\r\n      return;\r\n    }\r\n\r\n    this.pending.create({\r\n      deviceId: mobile.deviceId,\r\n      initiator: 'mobile',\r\n      notifyAllBrowsers: true,\r\n      refreshType: message.refreshType,\r\n      startedAt: Date.now(),\r\n    });\r\n\r\n    logger.refreshStarted(mobile.deviceId);\r\n\r\n    this.requestMobileUpload(mobile.deviceId, message.refreshType);\r\n  }\r\n\r\n  async handleSnapshotUpload(\r\n    deviceId: string,\r\n    body: Buffer,\r\n    metadata?: { kind?: string; mimeType?: string; databaseName?: string },\r\n  ): Promise<{ ok: true; stored: SnapshotReadyMessage } | { ok: false; code: RefreshErrorCode }> {\r\n    const pending = this.pending.get(deviceId);\r\n\r\n    if (!pending) {\r\n      return { ok: false, code: 'SNAPSHOT_NOT_FOUND' };\r\n    }\r\n\r\n    if (pending.browserConnectionId) {\r\n      this.sendRefreshStatus(pending.browserConnectionId, deviceId, 'uploading');\r\n    }\r\n\r\n    const stored = this.snapshots.set(deviceId, body, {\r\n      kind: metadata?.kind ?? 'sqlite',\r\n      mimeType: metadata?.mimeType ?? 'application/x-sqlite3',\r\n      databaseName: metadata?.databaseName,\r\n    });\r\n\r\n    const mobile = this.connectionManager.getByDeviceId(deviceId);\r\n\r\n    await this.snapshotFiles?.persistDeviceSnapshot({\r\n      deviceId,\r\n      bytes: body,\r\n      kind: stored.kind,\r\n      mimeType: stored.mimeType,\r\n      databaseName: stored.databaseName,\r\n      bundleId: mobile?.metadata?.bundleId,\r\n    });\r\n\r\n    logger.refreshUploaded(deviceId, body.byteLength);\r\n\r\n    const readyMessage = createMessage<SnapshotReadyMessage>({\r\n      type: MessageType.SNAPSHOT_READY,\r\n      deviceId,\r\n      size: body.byteLength,\r\n      exportedAt: stored.exportedAt,\r\n      kind: stored.kind,\r\n      mimeType: stored.mimeType,\r\n      ...(stored.databaseName ? { databaseName: stored.databaseName } : {}),\r\n    });\r\n\r\n    if (pending.notifyAllBrowsers) {\r\n      this.router.broadcastToBrowsers(readyMessage);\r\n    } else if (pending.browserConnectionId) {\r\n      this.sendRefreshStatus(pending.browserConnectionId, deviceId, 'ready');\r\n      this.router.sendToBrowser(pending.browserConnectionId, readyMessage);\r\n    }\r\n\r\n    this.pending.remove(deviceId);\r\n\r\n    return { ok: true, stored: readyMessage };\r\n  }\r\n\r\n  getSnapshot(deviceId: string): Buffer | undefined {\r\n    return this.snapshots.getBytes(deviceId);\r\n  }\r\n\r\n  async getSnapshotAsync(deviceId: string): Promise<Buffer | undefined> {\r\n    if (this.snapshotFiles) {\r\n      const fromDisk = await this.snapshotFiles.readDeviceSnapshot(deviceId);\r\n\r\n      if (fromDisk) {\r\n        return fromDisk;\r\n      }\r\n    }\r\n\r\n    return this.snapshots.getBytes(deviceId);\r\n  }\r\n\r\n  checkTimeouts(): void {\r\n    for (const pending of this.pending.getExpired()) {\r\n      if (pending.initiator === 'mobile') {\r\n        this.failMobileExport(\r\n          pending.deviceId,\r\n          'TIMEOUT',\r\n          'Export timed out waiting for device upload',\r\n        );\r\n        continue;\r\n      }\r\n\r\n      if (pending.browserConnectionId) {\r\n        this.failRefresh(\r\n          pending.deviceId,\r\n          pending.browserConnectionId,\r\n          'TIMEOUT',\r\n          'Refresh timed out waiting for device upload',\r\n        );\r\n      } else {\r\n        this.pending.remove(pending.deviceId);\r\n      }\r\n    }\r\n  }\r\n\r\n  private requestMobileUpload(deviceId: string, refreshType: 'snapshot'): void {\r\n    this.router.sendToMobile(\r\n      deviceId,\r\n      createMessage<SnapshotUploadRequestedMessage>({\r\n        type: MessageType.SNAPSHOT_UPLOAD_REQUESTED,\r\n        deviceId,\r\n        refreshType,\r\n      }),\r\n    );\r\n  }\r\n\r\n  private failRefresh(\r\n    deviceId: string,\r\n    browserConnectionId: string,\r\n    code: RefreshErrorCode,\r\n    message: string,\r\n  ): void {\r\n    logger.refreshFailed(deviceId, code, message);\r\n\r\n    this.sendRefreshError(browserConnectionId, {\r\n      deviceId,\r\n      code,\r\n      message,\r\n    });\r\n\r\n    this.pending.remove(deviceId);\r\n  }\r\n\r\n  private failMobileExport(\r\n    deviceId: string,\r\n    code: RefreshErrorCode,\r\n    message: string,\r\n  ): void {\r\n    logger.refreshFailed(deviceId, code, message);\r\n\r\n    const mobile = this.connectionManager.getByDeviceId(deviceId);\r\n\r\n    if (mobile) {\r\n      this.sendExportSnapshotError(mobile.socket, { code, message });\r\n    }\r\n\r\n    const refreshError = createMessage<RefreshErrorMessage>({\r\n      type: MessageType.REFRESH_ERROR,\r\n      deviceId,\r\n      code,\r\n      message,\r\n    });\r\n\r\n    this.router.broadcastToBrowsers(refreshError);\r\n    this.pending.remove(deviceId);\r\n  }\r\n\r\n  private sendRefreshStatus(\r\n    browserConnectionId: string,\r\n    deviceId: string,\r\n    state: RefreshState,\r\n  ): void {\r\n    const statusMessage = createMessage<RefreshStatusMessage>({\r\n      type: MessageType.REFRESH_STATUS,\r\n      deviceId,\r\n      state,\r\n    });\r\n\r\n    this.router.sendToBrowser(browserConnectionId, statusMessage);\r\n  }\r\n\r\n  private sendRefreshError(\r\n    browserConnectionId: string,\r\n    input: {\r\n      deviceId: string;\r\n      code: RefreshErrorCode;\r\n      message: string;\r\n    },\r\n  ): void {\r\n    const message = createMessage<RefreshErrorMessage>({\r\n      type: MessageType.REFRESH_ERROR,\r\n      deviceId: input.deviceId,\r\n      code: input.code,\r\n      message: input.message,\r\n    });\r\n\r\n    this.router.sendToBrowser(browserConnectionId, message);\r\n    logger.refreshFailed(input.deviceId, input.code, input.message);\r\n  }\r\n\r\n  private sendExportSnapshotError(\r\n    mobileSocket: WebSocket,\r\n    input: {\r\n      code: RefreshErrorCode;\r\n      message: string;\r\n    },\r\n  ): void {\r\n    const message = createMessage<ExportSnapshotErrorMessage>({\r\n      type: MessageType.EXPORT_SNAPSHOT_ERROR,\r\n      code: input.code,\r\n      message: input.message,\r\n    });\r\n\r\n    this.router.sendToSocket(mobileSocket, message);\r\n  }\r\n}\r\n","import { mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises';\r\nimport path from 'node:path';\r\nimport { SQLITE_SNAPSHOT_MIME_TYPE } from '../types/snapshot';\r\nimport {\r\n  dedupeListedDeviceExports,\r\n  findManifestEntryByDeviceId,\r\n  reconcileLegacyManifestEntries,\r\n  removedManifestEntries,\r\n  selectDeviceExportEntriesToPrune,\r\n} from './deviceExportStorage';\r\nimport { migrateLegacyActiveDatabase } from './migrateLegacyActiveDb';\r\nimport {\r\n  deviceDatabaseRelativePath,\r\n  deviceLatestRelativePath,\r\n  deviceStorageManifestId,\r\n  deviceStorageRelativePath,\r\n  ensureProjectDirectories,\r\n  isPersistenceEnabled,\r\n  readManifest,\r\n  resolveDataDir,\r\n  resolveDeviceStorageKey,\r\n  resolveProjectPaths,\r\n  sanitizePathSegment,\r\n  upsertManifestEntry,\r\n  writeDefaultProjectConfig,\r\n  writeManifest,\r\n  type DatabaseManifestEntry,\r\n  type PersistDeviceSnapshotInput,\r\n  type PersistDeviceSnapshotResult,\r\n} from './projectData';\r\n\r\nexport type ProjectDatabaseMeta = {\r\n  exists: boolean;\r\n  relativePath?: string;\r\n  absolutePath?: string;\r\n  kind?: string;\r\n  mimeType?: string;\r\n  databaseName?: string;\r\n  size?: number;\r\n  updatedAt?: number;\r\n  source?: DatabaseManifestEntry['source'];\r\n  deviceId?: string;\r\n};\r\n\r\nexport type ListedProjectDatabase = {\r\n  id: string;\r\n  label: string;\r\n  relativePath: string;\r\n  source: DatabaseManifestEntry['source'];\r\n  deviceId?: string;\r\n  bundleId?: string;\r\n  storageKey?: string;\r\n  databaseName?: string;\r\n  size: number;\r\n  updatedAt: number;\r\n};\r\n\r\nexport class SnapshotFileStore {\r\n  private readonly dataDir: string;\r\n  private readonly enabled: boolean;\r\n\r\n  constructor(options?: { dataDir?: string; enabled?: boolean }) {\r\n    this.dataDir = resolveDataDir(options?.dataDir);\r\n    this.enabled = options?.enabled ?? isPersistenceEnabled();\r\n  }\r\n\r\n  getDataDir(): string {\r\n    return this.dataDir;\r\n  }\r\n\r\n  isEnabled(): boolean {\r\n    return this.enabled;\r\n  }\r\n\r\n  async persistDeviceSnapshot(\r\n    input: PersistDeviceSnapshotInput,\r\n  ): Promise<PersistDeviceSnapshotResult | null> {\r\n    if (!this.enabled) {\r\n      return null;\r\n    }\r\n\r\n    await writeDefaultProjectConfig(this.dataDir);\r\n    await ensureProjectDirectories(this.dataDir);\r\n\r\n    const storageKey = resolveDeviceStorageKey({\r\n      bundleId: input.bundleId,\r\n      deviceId: input.deviceId,\r\n    });\r\n    const deviceRelativePath = deviceStorageRelativePath(storageKey);\r\n    const deviceAbsolutePath = path.join(this.dataDir, deviceRelativePath);\r\n    const exportedAt = Date.now();\r\n\r\n    await this.pruneDeviceExports({\r\n      keepStorageKey: storageKey,\r\n      keepDeviceId: input.deviceId,\r\n      bundleId: input.bundleId,\r\n      databaseName: input.databaseName,\r\n    });\r\n\r\n    await mkdir(path.dirname(deviceAbsolutePath), { recursive: true });\r\n    await writeFile(deviceAbsolutePath, input.bytes);\r\n\r\n    const manifest = await readManifest(this.dataDir);\r\n\r\n    const deviceEntry: DatabaseManifestEntry = {\r\n      id: deviceStorageManifestId(storageKey),\r\n      label: input.databaseName ?? `Device ${input.deviceId}`,\r\n      relativePath: deviceRelativePath.replace(/\\\\/g, '/'),\r\n      source: 'device',\r\n      deviceId: input.deviceId,\r\n      bundleId: input.bundleId,\r\n      storageKey,\r\n      kind: input.kind,\r\n      mimeType: input.mimeType,\r\n      databaseName: input.databaseName,\r\n      size: input.bytes.byteLength,\r\n      updatedAt: exportedAt,\r\n    };\r\n\r\n    const nextManifest = upsertManifestEntry(manifest, deviceEntry);\r\n\r\n    await writeManifest(this.dataDir, nextManifest);\r\n\r\n    return {\r\n      deviceRelativePath: deviceRelativePath.replace(/\\\\/g, '/'),\r\n      exportedAt,\r\n      size: input.bytes.byteLength,\r\n    };\r\n  }\r\n\r\n  async reconcileOnMobileConnect(input: {\r\n    deviceId: string;\r\n    bundleId?: string;\r\n  }): Promise<void> {\r\n    if (!this.enabled) {\r\n      return;\r\n    }\r\n\r\n    await this.reconcileLegacyExports(input.deviceId);\r\n\r\n    const storageKey = resolveDeviceStorageKey({\r\n      bundleId: input.bundleId,\r\n      deviceId: input.deviceId,\r\n    });\r\n    const manifest = await readManifest(this.dataDir);\r\n    const canonicalEntry = manifest.entries.find(\r\n      (entry) => entry.source === 'device' && entry.storageKey === storageKey,\r\n    );\r\n\r\n    if (canonicalEntry && canonicalEntry.deviceId !== input.deviceId) {\r\n      const updated = upsertManifestEntry(manifest, {\r\n        ...canonicalEntry,\r\n        deviceId: input.deviceId,\r\n        bundleId: input.bundleId ?? canonicalEntry.bundleId,\r\n        updatedAt: Date.now(),\r\n      });\r\n\r\n      await writeManifest(this.dataDir, updated);\r\n    }\r\n\r\n    await this.pruneDeviceExports({\r\n      keepStorageKey: storageKey,\r\n      keepDeviceId: input.deviceId,\r\n      bundleId: input.bundleId,\r\n      databaseName: canonicalEntry?.databaseName,\r\n    });\r\n  }\r\n\r\n  async readDeviceSnapshot(deviceId: string): Promise<Buffer | undefined> {\r\n    return this.readDeviceDatabase(deviceId);\r\n  }\r\n\r\n  async readDeviceDatabase(deviceId: string): Promise<Buffer | undefined> {\r\n    if (!this.enabled) {\r\n      return undefined;\r\n    }\r\n\r\n    const resolved = await this.resolveDeviceDatabaseFile(deviceId);\r\n\r\n    if (!resolved) {\r\n      return undefined;\r\n    }\r\n\r\n    try {\r\n      return await readFile(resolved.absolutePath);\r\n    } catch {\r\n      return undefined;\r\n    }\r\n  }\r\n\r\n  async getDeviceDatabaseMeta(deviceId: string): Promise<ProjectDatabaseMeta> {\r\n    if (!this.enabled) {\r\n      return { exists: false, deviceId };\r\n    }\r\n\r\n    const resolved = await this.resolveDeviceDatabaseFile(deviceId);\r\n\r\n    if (!resolved) {\r\n      return { exists: false, deviceId };\r\n    }\r\n\r\n    try {\r\n      const fileStat = await stat(resolved.absolutePath);\r\n      const manifest = await readManifest(this.dataDir);\r\n      const entry = manifest.entries.find(\r\n        (item) => item.deviceId === deviceId && item.source === 'device',\r\n      );\r\n\r\n      return {\r\n        exists: true,\r\n        relativePath: resolved.relativePath,\r\n        absolutePath: resolved.absolutePath,\r\n        kind: entry?.kind ?? 'sqlite',\r\n        mimeType: entry?.mimeType ?? SQLITE_SNAPSHOT_MIME_TYPE,\r\n        databaseName: entry?.databaseName ?? path.basename(resolved.absolutePath),\r\n        size: fileStat.size,\r\n        updatedAt: entry?.updatedAt ?? fileStat.mtimeMs,\r\n        source: 'device',\r\n        deviceId,\r\n      };\r\n    } catch {\r\n      return { exists: false, deviceId, relativePath: resolved.relativePath };\r\n    }\r\n  }\r\n\r\n  async listDeviceExports(): Promise<ListedProjectDatabase[]> {\r\n    await this.reconcileLegacyExports();\r\n    const databases = await this.listDatabases();\r\n    const deviceExports = databases.filter((entry) => entry.source === 'device' && entry.deviceId);\r\n    return dedupeListedDeviceExports(deviceExports);\r\n  }\r\n\r\n  private async reconcileLegacyExports(preferredDeviceId?: string): Promise<void> {\r\n    if (!this.enabled) {\r\n      return;\r\n    }\r\n\r\n    await migrateLegacyActiveDatabase(this.dataDir);\r\n\r\n    const manifest = await readManifest(this.dataDir);\r\n    const nextEntries = reconcileLegacyManifestEntries({\r\n      entries: manifest.entries,\r\n      preferredDeviceId,\r\n    });\r\n\r\n    if (nextEntries.length === manifest.entries.length) {\r\n      const sameOrder = nextEntries.every((entry, index) => entry.id === manifest.entries[index]?.id);\r\n\r\n      if (sameOrder) {\r\n        return;\r\n      }\r\n    }\r\n\r\n    const removed = removedManifestEntries(manifest.entries, nextEntries);\r\n\r\n    for (const entry of removed) {\r\n      await this.deleteEntryFiles(entry);\r\n    }\r\n\r\n    await writeManifest(this.dataDir, {\r\n      ...manifest,\r\n      entries: nextEntries,\r\n    });\r\n  }\r\n\r\n  private async pruneDeviceExports(input: {\r\n    keepStorageKey: string;\r\n    keepDeviceId: string;\r\n    bundleId?: string;\r\n    databaseName?: string;\r\n  }): Promise<void> {\r\n    const manifest = await readManifest(this.dataDir);\r\n    const removed = selectDeviceExportEntriesToPrune(manifest.entries, input);\r\n\r\n    if (removed.length === 0) {\r\n      return;\r\n    }\r\n\r\n    for (const entry of removed) {\r\n      await this.deleteEntryFiles(entry);\r\n    }\r\n\r\n    const removedIds = new Set(removed.map((entry) => entry.id));\r\n\r\n    await writeManifest(this.dataDir, {\r\n      ...manifest,\r\n      entries: manifest.entries.filter((entry) => !removedIds.has(entry.id)),\r\n    });\r\n  }\r\n\r\n  private async deleteEntryFiles(entry: DatabaseManifestEntry): Promise<void> {\r\n    const absolutePath = path.join(this.dataDir, entry.relativePath);\r\n\r\n    try {\r\n      await rm(absolutePath, { force: true });\r\n    } catch {\r\n      // ignore missing files\r\n    }\r\n\r\n    try {\r\n      await rm(path.dirname(absolutePath), { recursive: true, force: true });\r\n    } catch {\r\n      // ignore cleanup failures\r\n    }\r\n  }\r\n\r\n  private manifestEntryToListed(entry: DatabaseManifestEntry, fileStat: { size: number }): ListedProjectDatabase {\r\n    return {\r\n      id: entry.id,\r\n      label: entry.label,\r\n      relativePath: entry.relativePath,\r\n      source: entry.source,\r\n      deviceId: entry.deviceId,\r\n      bundleId: entry.bundleId,\r\n      storageKey: entry.storageKey,\r\n      databaseName: entry.databaseName,\r\n      size: fileStat.size,\r\n      updatedAt: entry.updatedAt,\r\n    };\r\n  }\r\n\r\n  private async resolveDeviceDatabaseFile(\r\n    deviceId: string,\r\n  ): Promise<{ relativePath: string; absolutePath: string } | undefined> {\r\n    const manifest = await readManifest(this.dataDir);\r\n    const manifestEntry = findManifestEntryByDeviceId(manifest.entries, deviceId);\r\n\r\n    if (manifestEntry) {\r\n      const absolutePath = path.join(this.dataDir, manifestEntry.relativePath);\r\n\r\n      try {\r\n        await stat(absolutePath);\r\n        return { relativePath: manifestEntry.relativePath, absolutePath };\r\n      } catch {\r\n        // fall through to legacy paths\r\n      }\r\n    }\r\n\r\n    const candidates = [\r\n      deviceDatabaseRelativePath(deviceId),\r\n      deviceLatestRelativePath(deviceId),\r\n    ];\r\n\r\n    for (const relativePath of candidates) {\r\n      const absolutePath = path.join(this.dataDir, relativePath);\r\n\r\n      try {\r\n        await stat(absolutePath);\r\n        return { relativePath, absolutePath };\r\n      } catch {\r\n        // try next candidate\r\n      }\r\n    }\r\n\r\n    if (!manifestEntry) {\r\n      return undefined;\r\n    }\r\n\r\n    const absolutePath = path.join(this.dataDir, manifestEntry.relativePath);\r\n\r\n    try {\r\n      await stat(absolutePath);\r\n      return { relativePath: manifestEntry.relativePath, absolutePath };\r\n    } catch {\r\n      return undefined;\r\n    }\r\n  }\r\n\r\n  /** @deprecated Proxies to the newest device export for backward-compatible API callers. */\r\n  async readActiveDatabase(): Promise<Buffer | undefined> {\r\n    if (!this.enabled) {\r\n      return undefined;\r\n    }\r\n\r\n    const meta = await this.getActiveDatabaseMeta();\r\n\r\n    if (!meta.exists || !meta.deviceId) {\r\n      return undefined;\r\n    }\r\n\r\n    return this.readDeviceDatabase(meta.deviceId);\r\n  }\r\n\r\n  /** @deprecated Proxies to the newest device export for backward-compatible API callers. */\r\n  async getActiveDatabaseMeta(): Promise<ProjectDatabaseMeta> {\r\n    if (!this.enabled) {\r\n      return { exists: false };\r\n    }\r\n\r\n    await migrateLegacyActiveDatabase(this.dataDir);\r\n\r\n    const exports = await this.listDeviceExports();\r\n    const latest = exports[0];\r\n\r\n    if (!latest?.deviceId) {\r\n      return { exists: false };\r\n    }\r\n\r\n    return this.getDeviceDatabaseMeta(latest.deviceId);\r\n  }\r\n\r\n  async listDatabases(): Promise<ListedProjectDatabase[]> {\r\n    if (!this.enabled) {\r\n      return [];\r\n    }\r\n\r\n    await ensureProjectDirectories(this.dataDir);\r\n    await this.reconcileLegacyExports();\r\n\r\n    const manifest = await readManifest(this.dataDir);\r\n    const listed = new Map<string, ListedProjectDatabase>();\r\n\r\n    for (const entry of manifest.entries) {\r\n      if (entry.source === 'active' || entry.id.startsWith('import:')) {\r\n        continue;\r\n      }\r\n\r\n      const absolutePath = path.join(this.dataDir, entry.relativePath);\r\n\r\n      try {\r\n        const fileStat = await stat(absolutePath);\r\n\r\n        listed.set(entry.id, this.manifestEntryToListed(entry, fileStat));\r\n      } catch {\r\n        // Ignore missing files from manifest.\r\n      }\r\n    }\r\n\r\n    return [...listed.values()].sort((left, right) => right.updatedAt - left.updatedAt);\r\n  }\r\n\r\n  async readDatabaseByRelativePath(relativePath: string): Promise<Buffer | undefined> {\r\n    if (!this.enabled) {\r\n      return undefined;\r\n    }\r\n\r\n    const normalized = relativePath.replace(/\\\\/g, '/');\r\n    const absolutePath = path.resolve(this.dataDir, normalized);\r\n    const dataDirResolved = path.resolve(this.dataDir);\r\n\r\n    if (!absolutePath.startsWith(dataDirResolved)) {\r\n      return undefined;\r\n    }\r\n\r\n    if (!normalized.toLowerCase().endsWith('.db')) {\r\n      return undefined;\r\n    }\r\n\r\n    try {\r\n      return await readFile(absolutePath);\r\n    } catch {\r\n      return undefined;\r\n    }\r\n  }\r\n\r\n  getDeviceDirectoryName(deviceId: string): string {\r\n    return sanitizePathSegment(deviceId);\r\n  }\r\n}\r\n","import { mkdir, readFile, writeFile } from 'node:fs/promises';\r\nimport path from 'node:path';\r\n\r\nexport const DEFAULT_DATA_DIR = '.devtools';\r\n\r\n/** @deprecated Legacy single-database path. Removed — use per-device exports instead. */\r\nexport const DEFAULT_DATABASE_RELATIVE_PATH = 'databases/active.db';\r\n\r\nexport type ProjectDevToolsConfig = {\r\n  /** @deprecated No longer used. */\r\n  defaultDatabase?: string;\r\n  deviceSync?: {\r\n    /** @deprecated Ignored — active.db is no longer written. */\r\n    promoteLatestToActive?: boolean;\r\n  };\r\n};\r\n\r\nexport type DatabaseManifestEntry = {\r\n  id: string;\r\n  label: string;\r\n  relativePath: string;\r\n  source: 'active' | 'device';\r\n  deviceId?: string;\r\n  bundleId?: string;\r\n  storageKey?: string;\r\n  kind: string;\r\n  mimeType: string;\r\n  databaseName?: string;\r\n  size: number;\r\n  updatedAt: number;\r\n};\r\n\r\nexport type DatabaseManifest = {\r\n  version: 1;\r\n  /** @deprecated No longer written. */\r\n  activeDatabase?: string;\r\n  entries: DatabaseManifestEntry[];\r\n};\r\n\r\nexport type PersistDeviceSnapshotInput = {\r\n  deviceId: string;\r\n  bytes: Buffer;\r\n  kind: string;\r\n  mimeType: string;\r\n  databaseName?: string;\r\n  bundleId?: string;\r\n};\r\n\r\nexport type PersistDeviceSnapshotResult = {\r\n  deviceRelativePath: string;\r\n  exportedAt: number;\r\n  size: number;\r\n};\r\n\r\nconst DEFAULT_CONFIG: ProjectDevToolsConfig = {\r\n  deviceSync: {\r\n    promoteLatestToActive: false,\r\n  },\r\n};\r\n\r\nexport function resolveDataDir(explicitDir?: string): string {\r\n  const fromEnv = process.env.DATABASE_DEVTOOLS_DATA_DIR?.trim();\r\n\r\n  if (explicitDir?.trim()) {\r\n    return path.resolve(explicitDir.trim());\r\n  }\r\n\r\n  if (fromEnv) {\r\n    return path.resolve(fromEnv);\r\n  }\r\n\r\n  return path.resolve(process.cwd(), DEFAULT_DATA_DIR);\r\n}\r\n\r\nexport function isPersistenceEnabled(): boolean {\r\n  const flag = process.env.DATABASE_DEVTOOLS_SNAPSHOT_PERSIST?.trim().toLowerCase();\r\n\r\n  if (flag === '0' || flag === 'false' || flag === 'off') {\r\n    return false;\r\n  }\r\n\r\n  return true;\r\n}\r\n\r\nexport function sanitizePathSegment(value: string): string {\r\n  return value.replace(/[^a-zA-Z0-9._-]+/g, '_');\r\n}\r\n\r\nexport function resolveProjectPaths(dataDir: string) {\r\n  const databasesDir = path.join(dataDir, 'databases');\r\n  const devicesDir = path.join(databasesDir, 'devices');\r\n  const configPath = path.join(dataDir, 'devtools.json');\r\n  const manifestPath = path.join(dataDir, 'manifest.json');\r\n\r\n  return {\r\n    dataDir,\r\n    databasesDir,\r\n    devicesDir,\r\n    configPath,\r\n    manifestPath,\r\n  };\r\n}\r\n\r\nexport async function ensureProjectDirectories(dataDir: string): Promise<void> {\r\n  const paths = resolveProjectPaths(dataDir);\r\n\r\n  await mkdir(paths.devicesDir, { recursive: true });\r\n}\r\n\r\nexport async function loadProjectConfig(dataDir: string): Promise<ProjectDevToolsConfig> {\r\n  const { configPath } = resolveProjectPaths(dataDir);\r\n\r\n  try {\r\n    const raw = await readFile(configPath, 'utf8');\r\n    const parsed = JSON.parse(raw) as ProjectDevToolsConfig;\r\n\r\n    return {\r\n      ...DEFAULT_CONFIG,\r\n      ...parsed,\r\n      deviceSync: {\r\n        promoteLatestToActive: false,\r\n      },\r\n    };\r\n  } catch {\r\n    return { ...DEFAULT_CONFIG };\r\n  }\r\n}\r\n\r\nexport async function writeDefaultProjectConfig(dataDir: string): Promise<void> {\r\n  const { configPath } = resolveProjectPaths(dataDir);\r\n\r\n  try {\r\n    await readFile(configPath, 'utf8');\r\n  } catch {\r\n    await mkdir(dataDir, { recursive: true });\r\n    await writeFile(configPath, `${JSON.stringify(DEFAULT_CONFIG, null, 2)}\\n`, 'utf8');\r\n  }\r\n}\r\n\r\nexport function resolveActiveDatabasePath(dataDir: string, config: ProjectDevToolsConfig): string {\r\n  const relative = config.defaultDatabase ?? DEFAULT_DATABASE_RELATIVE_PATH;\r\n  return path.join(dataDir, relative);\r\n}\r\n\r\nexport function deviceDatabaseFileName(deviceId: string): string {\r\n  return `Database-${sanitizePathSegment(deviceId)}.db`;\r\n}\r\n\r\nexport const DEVICE_EXPORT_FILE_NAME = 'database.db';\r\n\r\nexport function resolveDeviceStorageKey(input: { bundleId?: string; deviceId: string }): string {\r\n  const bundleId = input.bundleId?.trim();\r\n\r\n  if (bundleId) {\r\n    return sanitizePathSegment(bundleId);\r\n  }\r\n\r\n  return sanitizePathSegment(input.deviceId);\r\n}\r\n\r\nexport function deviceStorageManifestId(storageKey: string): string {\r\n  return `device:${storageKey}`;\r\n}\r\n\r\nexport function deviceStorageRelativePath(storageKey: string): string {\r\n  return path\r\n    .join('databases', 'devices', storageKey, DEVICE_EXPORT_FILE_NAME)\r\n    .replace(/\\\\/g, '/');\r\n}\r\n\r\nexport function deviceDatabaseRelativePath(deviceId: string): string {\r\n  const segment = sanitizePathSegment(deviceId);\r\n  return path\r\n    .join('databases', 'devices', segment, deviceDatabaseFileName(deviceId))\r\n    .replace(/\\\\/g, '/');\r\n}\r\n\r\n/** @deprecated Legacy path — migrated reads still check this location. */\r\nexport function deviceLatestRelativePath(deviceId: string): string {\r\n  return path.join('databases', 'devices', sanitizePathSegment(deviceId), 'latest.db').replace(/\\\\/g, '/');\r\n}\r\n\r\nexport async function readManifest(dataDir: string): Promise<DatabaseManifest> {\r\n  const { manifestPath } = resolveProjectPaths(dataDir);\r\n\r\n  try {\r\n    const raw = await readFile(manifestPath, 'utf8');\r\n    const parsed = JSON.parse(raw) as DatabaseManifest;\r\n\r\n    if (parsed.version !== 1 || !Array.isArray(parsed.entries)) {\r\n      return { version: 1, entries: [] };\r\n    }\r\n\r\n    return parsed;\r\n  } catch {\r\n    return { version: 1, entries: [] };\r\n  }\r\n}\r\n\r\nexport async function writeManifest(dataDir: string, manifest: DatabaseManifest): Promise<void> {\r\n  const { manifestPath } = resolveProjectPaths(dataDir);\r\n\r\n  await mkdir(dataDir, { recursive: true });\r\n  await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\\n`, 'utf8');\r\n}\r\n\r\nexport function upsertManifestEntry(\r\n  manifest: DatabaseManifest,\r\n  entry: DatabaseManifestEntry,\r\n): DatabaseManifest {\r\n  const entries = manifest.entries.filter((item) => item.id !== entry.id);\r\n  entries.push(entry);\r\n\r\n  entries.sort((left, right) => right.updatedAt - left.updatedAt);\r\n\r\n  return {\r\n    version: manifest.version,\r\n    entries,\r\n  };\r\n}\r\n","import type { DatabaseManifestEntry } from './projectData';\r\nimport { deviceStorageManifestId, sanitizePathSegment } from './projectData';\r\n\r\nexport type ListedDeviceExportLike = {\r\n  id: string;\r\n  deviceId?: string;\r\n  bundleId?: string;\r\n  storageKey?: string;\r\n  databaseName?: string;\r\n  updatedAt: number;\r\n};\r\n\r\nexport function deriveStorageKeyFromEntry(entry: DatabaseManifestEntry): string {\r\n  if (entry.storageKey) {\r\n    return entry.storageKey;\r\n  }\r\n\r\n  if (entry.bundleId) {\r\n    return sanitizePathSegment(entry.bundleId);\r\n  }\r\n\r\n  const match = entry.relativePath.match(/databases\\/devices\\/([^/]+)\\//);\r\n\r\n  if (match?.[1]) {\r\n    return match[1];\r\n  }\r\n\r\n  if (entry.deviceId) {\r\n    return sanitizePathSegment(entry.deviceId);\r\n  }\r\n\r\n  return entry.id;\r\n}\r\n\r\nexport function findManifestEntryByDeviceId(\r\n  entries: DatabaseManifestEntry[],\r\n  deviceId: string,\r\n): DatabaseManifestEntry | undefined {\r\n  return entries.find((entry) => entry.source === 'device' && entry.deviceId === deviceId);\r\n}\r\n\r\nexport type PruneDeviceExportsInput = {\r\n  keepStorageKey: string;\r\n  keepDeviceId: string;\r\n  bundleId?: string;\r\n  databaseName?: string;\r\n};\r\n\r\nexport function selectDeviceExportEntriesToPrune(\r\n  entries: DatabaseManifestEntry[],\r\n  keep: PruneDeviceExportsInput,\r\n): DatabaseManifestEntry[] {\r\n  const keepManifestId = deviceStorageManifestId(keep.keepStorageKey);\r\n\r\n  return entries.filter((entry) => {\r\n    if (entry.source !== 'device') {\r\n      return false;\r\n    }\r\n\r\n    if (entry.id === keepManifestId) {\r\n      return false;\r\n    }\r\n\r\n    const entryStorageKey = deriveStorageKeyFromEntry(entry);\r\n\r\n    if (entryStorageKey === keep.keepStorageKey) {\r\n      return true;\r\n    }\r\n\r\n    if (keep.bundleId && entry.bundleId === keep.bundleId) {\r\n      return true;\r\n    }\r\n\r\n    if (\r\n      keep.bundleId &&\r\n      keep.databaseName &&\r\n      !entry.bundleId &&\r\n      entry.databaseName === keep.databaseName\r\n    ) {\r\n      return true;\r\n    }\r\n\r\n    if (\r\n      !keep.bundleId &&\r\n      keep.databaseName &&\r\n      entry.databaseName === keep.databaseName &&\r\n      entry.deviceId !== keep.keepDeviceId\r\n    ) {\r\n      return true;\r\n    }\r\n\r\n    return false;\r\n  });\r\n}\r\n\r\nexport function dedupeListedDeviceExports<T extends ListedDeviceExportLike>(entries: T[]): T[] {\r\n  const byStorageKey = new Map<string, T>();\r\n\r\n  for (const entry of entries) {\r\n    const storageKey = entry.storageKey\r\n      ? entry.storageKey\r\n      : entry.bundleId\r\n        ? sanitizePathSegment(entry.bundleId)\r\n        : entry.deviceId\r\n          ? sanitizePathSegment(entry.deviceId)\r\n          : entry.id;\r\n\r\n    const existing = byStorageKey.get(storageKey);\r\n\r\n    if (!existing || entry.updatedAt > existing.updatedAt) {\r\n      byStorageKey.set(storageKey, entry);\r\n    }\r\n  }\r\n\r\n  return [...byStorageKey.values()].sort((left, right) => right.updatedAt - left.updatedAt);\r\n}\r\n\r\nexport type ReconcileLegacyExportsInput = {\r\n  entries: DatabaseManifestEntry[];\r\n  preferredDeviceId?: string;\r\n};\r\n\r\nexport function reconcileLegacyManifestEntries(\r\n  input: ReconcileLegacyExportsInput,\r\n): DatabaseManifestEntry[] {\r\n  const deviceEntries = input.entries.filter((entry) => entry.source === 'device');\r\n  const otherEntries = input.entries.filter((entry) => entry.source !== 'device');\r\n  const groups = new Map<string, DatabaseManifestEntry[]>();\r\n\r\n  for (const entry of deviceEntries) {\r\n    const groupKey = entry.bundleId\r\n      ? `bundle:${entry.bundleId}`\r\n      : entry.databaseName\r\n        ? `db:${entry.databaseName}`\r\n        : `device:${deriveStorageKeyFromEntry(entry)}`;\r\n\r\n    const group = groups.get(groupKey) ?? [];\r\n    group.push(entry);\r\n    groups.set(groupKey, group);\r\n  }\r\n\r\n  const keptDeviceEntries: DatabaseManifestEntry[] = [];\r\n\r\n  for (const group of groups.values()) {\r\n    if (group.length === 1) {\r\n      keptDeviceEntries.push(group[0]!);\r\n      continue;\r\n    }\r\n\r\n    const preferred = input.preferredDeviceId\r\n      ? group.find((entry) => entry.deviceId === input.preferredDeviceId)\r\n      : undefined;\r\n\r\n    const newest = [...group].sort((left, right) => right.updatedAt - left.updatedAt)[0]!;\r\n    keptDeviceEntries.push(preferred ?? newest);\r\n  }\r\n\r\n  return [...otherEntries, ...keptDeviceEntries].sort((left, right) => right.updatedAt - left.updatedAt);\r\n}\r\n\r\nexport function removedManifestEntries(\r\n  before: DatabaseManifestEntry[],\r\n  after: DatabaseManifestEntry[],\r\n): DatabaseManifestEntry[] {\r\n  const afterIds = new Set(after.map((entry) => entry.id));\r\n  return before.filter((entry) => !afterIds.has(entry.id));\r\n}\r\n","import { readFile, rm, stat, writeFile } from 'node:fs/promises';\r\nimport path from 'node:path';\r\nimport {\r\n  DEFAULT_DATABASE_RELATIVE_PATH,\r\n  readManifest,\r\n  resolveProjectPaths,\r\n  writeManifest,\r\n  type DatabaseManifest,\r\n  type ProjectDevToolsConfig,\r\n} from './projectData';\r\n\r\nconst NORMALIZED_CONFIG: ProjectDevToolsConfig = {\r\n  deviceSync: {\r\n    promoteLatestToActive: false,\r\n  },\r\n};\r\n\r\nexport function stripLegacyActiveManifest(manifest: DatabaseManifest): DatabaseManifest {\r\n  const entries = manifest.entries.filter(\r\n    (entry) =>\r\n      entry.source !== 'active' &&\r\n      entry.id !== 'active' &&\r\n      !entry.id.startsWith('import:'),\r\n  );\r\n\r\n  return {\r\n    version: 1,\r\n    entries,\r\n  };\r\n}\r\n\r\nexport function normalizeProjectConfig(config: ProjectDevToolsConfig): ProjectDevToolsConfig {\r\n  return {\r\n    ...NORMALIZED_CONFIG,\r\n    deviceSync: {\r\n      ...NORMALIZED_CONFIG.deviceSync,\r\n      promoteLatestToActive: false,\r\n    },\r\n  };\r\n}\r\n\r\nexport async function migrateLegacyActiveDatabase(dataDir: string): Promise<boolean> {\r\n  const { configPath } = resolveProjectPaths(dataDir);\r\n  const manifest = await readManifest(dataDir);\r\n  const stripped = stripLegacyActiveManifest(manifest);\r\n  const activeDbPath = path.join(dataDir, DEFAULT_DATABASE_RELATIVE_PATH);\r\n\r\n  let changed =\r\n    stripped.entries.length !== manifest.entries.length || Boolean(manifest.activeDatabase);\r\n\r\n  if (changed) {\r\n    await writeManifest(dataDir, stripped);\r\n  }\r\n\r\n  try {\r\n    await stat(activeDbPath);\r\n    const hasDeviceExports = stripped.entries.some((entry) => entry.source === 'device');\r\n\r\n    if (hasDeviceExports || manifest.entries.some((entry) => entry.source === 'active')) {\r\n      await rm(activeDbPath, { force: true });\r\n      changed = true;\r\n    }\r\n  } catch {\r\n    // active.db not present\r\n  }\r\n\r\n  try {\r\n    const raw = await readFile(configPath, 'utf8');\r\n    const parsed = JSON.parse(raw) as ProjectDevToolsConfig;\r\n\r\n    if (parsed.defaultDatabase || parsed.deviceSync?.promoteLatestToActive) {\r\n      await writeFile(\r\n        configPath,\r\n        `${JSON.stringify(normalizeProjectConfig(parsed), null, 2)}\\n`,\r\n        'utf8',\r\n      );\r\n      changed = true;\r\n    }\r\n  } catch {\r\n    // config will be created on next export\r\n  }\r\n\r\n  const importsDir = path.join(dataDir, 'databases', 'imports');\r\n\r\n  try {\r\n    await stat(importsDir);\r\n    await rm(importsDir, { recursive: true, force: true });\r\n    changed = true;\r\n  } catch {\r\n    // imports directory not present\r\n  }\r\n\r\n  return changed;\r\n}\r\n","export type StoredSnapshot = {\r\n  deviceId: string;\r\n  bytes: Buffer;\r\n  kind: string;\r\n  mimeType: string;\r\n  databaseName?: string;\r\n  exportedAt: number;\r\n};\r\n\r\nexport class SnapshotStore {\r\n  private readonly snapshots = new Map<string, StoredSnapshot>();\r\n\r\n  set(\r\n    deviceId: string,\r\n    bytes: Buffer,\r\n    metadata: { kind: string; mimeType: string; databaseName?: string },\r\n  ): StoredSnapshot {\r\n    const stored: StoredSnapshot = {\r\n      deviceId,\r\n      bytes,\r\n      kind: metadata.kind,\r\n      mimeType: metadata.mimeType,\r\n      databaseName: metadata.databaseName,\r\n      exportedAt: Date.now(),\r\n    };\r\n\r\n    this.snapshots.set(deviceId, stored);\r\n    return stored;\r\n  }\r\n\r\n  get(deviceId: string): StoredSnapshot | undefined {\r\n    return this.snapshots.get(deviceId);\r\n  }\r\n\r\n  getBytes(deviceId: string): Buffer | undefined {\r\n    return this.snapshots.get(deviceId)?.bytes;\r\n  }\r\n}\r\n","import type { WebSocket } from 'ws';\r\nimport {\r\n  createMessage,\r\n  DevToolsRole,\r\n  MessageType,\r\n  type BeginTransactionMessage,\r\n  type BeginTransactionRequestMessage,\r\n  type CommitTransactionMessage,\r\n  type CommitTransactionRequestMessage,\r\n  type ExecuteWriteMessage,\r\n  type RollbackTransactionMessage,\r\n  type RollbackTransactionRequestMessage,\r\n  type TransactionAckMessage,\r\n  type TransactionStatusMessage,\r\n  type WriteAckMessage,\r\n  type WriteErrorCode,\r\n  type WriteErrorMessage,\r\n  type WriteRequestMessage,\r\n  type WriteResultMessage,\r\n} from '../types/protocol';\r\nimport { logger } from '../utils/logger';\r\nimport type { ConnectionManager } from './connectionManager';\r\nimport type { MessageRouter } from './messageRouter';\r\nimport type { WriteSessionManager, WriteSession } from './writeSessionManager';\r\n\r\nexport class WriteCoordinator {\r\n  constructor(\r\n    private readonly connectionManager: ConnectionManager,\r\n    private readonly router: MessageRouter,\r\n    private readonly sessions: WriteSessionManager,\r\n  ) {}\r\n\r\n  handleBeginTransactionRequest(\r\n    browserSocket: WebSocket,\r\n    message: BeginTransactionRequestMessage,\r\n  ): void {\r\n    const browser = this.connectionManager.getBySocket(browserSocket);\r\n\r\n    if (!browser || browser.role !== DevToolsRole.BROWSER) {\r\n      return;\r\n    }\r\n\r\n    const mobile = this.connectionManager.getByDeviceId(message.deviceId);\r\n\r\n    if (!mobile) {\r\n      this.sendWriteError(browser.connectionId, {\r\n        transactionId: message.transactionId,\r\n        code: 'DEVICE_OFFLINE',\r\n        message: `Device ${message.deviceId} is not connected`,\r\n      });\r\n      return;\r\n    }\r\n\r\n    if (this.sessions.getActiveForDevice(message.deviceId)) {\r\n      this.sendWriteError(browser.connectionId, {\r\n        transactionId: message.transactionId,\r\n        code: 'TRANSACTION_BUSY',\r\n        message: 'A transaction is already open for this device',\r\n      });\r\n      return;\r\n    }\r\n\r\n    this.sessions.create({\r\n      transactionId: message.transactionId,\r\n      deviceId: message.deviceId,\r\n      browserConnectionId: browser.connectionId,\r\n    });\r\n\r\n    logger.syncStarted(message.transactionId, message.deviceId);\r\n\r\n    this.router.sendToMobile(\r\n      message.deviceId,\r\n      createMessage<BeginTransactionMessage>({\r\n        type: MessageType.BEGIN_TRANSACTION,\r\n        transactionId: message.transactionId,\r\n      }),\r\n    );\r\n  }\r\n\r\n  handleCommitTransactionRequest(\r\n    browserSocket: WebSocket,\r\n    message: CommitTransactionRequestMessage,\r\n  ): void {\r\n    const browser = this.connectionManager.getBySocket(browserSocket);\r\n    const session = this.sessions.get(message.transactionId);\r\n\r\n    if (!browser || browser.role !== DevToolsRole.BROWSER || !session) {\r\n      return;\r\n    }\r\n\r\n    if (session.browserConnectionId !== browser.connectionId) {\r\n      return;\r\n    }\r\n\r\n    if (session.state !== 'open') {\r\n      this.sendWriteError(browser.connectionId, {\r\n        transactionId: message.transactionId,\r\n        code: 'NO_TRANSACTION',\r\n        message: 'Transaction is not open',\r\n      });\r\n      return;\r\n    }\r\n\r\n    this.sessions.setState(message.transactionId, 'committing');\r\n\r\n    this.router.sendToMobile(\r\n      session.deviceId,\r\n      createMessage<CommitTransactionMessage>({\r\n        type: MessageType.COMMIT_TRANSACTION,\r\n        transactionId: message.transactionId,\r\n      }),\r\n    );\r\n  }\r\n\r\n  handleRollbackTransactionRequest(\r\n    browserSocket: WebSocket,\r\n    message: RollbackTransactionRequestMessage,\r\n  ): void {\r\n    const browser = this.connectionManager.getBySocket(browserSocket);\r\n    const session = this.sessions.get(message.transactionId);\r\n\r\n    if (!browser || browser.role !== DevToolsRole.BROWSER || !session) {\r\n      return;\r\n    }\r\n\r\n    if (session.browserConnectionId !== browser.connectionId) {\r\n      return;\r\n    }\r\n\r\n    if (session.state !== 'open' && session.state !== 'committing') {\r\n      this.sendWriteError(browser.connectionId, {\r\n        transactionId: message.transactionId,\r\n        code: 'NO_TRANSACTION',\r\n        message: 'Transaction is not open',\r\n      });\r\n      return;\r\n    }\r\n\r\n    this.sessions.setState(message.transactionId, 'rolling_back');\r\n\r\n    this.router.sendToMobile(\r\n      session.deviceId,\r\n      createMessage<RollbackTransactionMessage>({\r\n        type: MessageType.ROLLBACK_TRANSACTION,\r\n        transactionId: message.transactionId,\r\n      }),\r\n    );\r\n  }\r\n\r\n  handleWriteRequest(browserSocket: WebSocket, message: WriteRequestMessage): void {\r\n    const browser = this.connectionManager.getBySocket(browserSocket);\r\n    const session = this.sessions.get(message.transactionId);\r\n\r\n    if (!browser || browser.role !== DevToolsRole.BROWSER || !session) {\r\n      return;\r\n    }\r\n\r\n    if (session.browserConnectionId !== browser.connectionId) {\r\n      return;\r\n    }\r\n\r\n    if (session.state !== 'open') {\r\n      this.sendWriteError(browser.connectionId, {\r\n        transactionId: message.transactionId,\r\n        writeId: message.writeId,\r\n        code: 'NO_TRANSACTION',\r\n        message: 'Transaction is not open',\r\n      });\r\n      return;\r\n    }\r\n\r\n    const mobile = this.connectionManager.getByDeviceId(session.deviceId);\r\n\r\n    if (!mobile) {\r\n      this.sendWriteError(browser.connectionId, {\r\n        transactionId: message.transactionId,\r\n        writeId: message.writeId,\r\n        code: 'DEVICE_OFFLINE',\r\n        message: `Device ${session.deviceId} is not connected`,\r\n      });\r\n      return;\r\n    }\r\n\r\n    this.sessions.incrementPendingWrites(message.transactionId);\r\n\r\n    this.router.sendToMobile(\r\n      session.deviceId,\r\n      createMessage<ExecuteWriteMessage>({\r\n        type: MessageType.EXECUTE_WRITE,\r\n        writeId: message.writeId,\r\n        transactionId: message.transactionId,\r\n        operation: message.operation,\r\n      }),\r\n    );\r\n  }\r\n\r\n  handleTransactionAck(message: TransactionAckMessage): void {\r\n    const session = this.sessions.get(message.transactionId);\r\n\r\n    if (!session) {\r\n      return;\r\n    }\r\n\r\n    if (!message.ok) {\r\n      this.sessions.setState(message.transactionId, 'failed');\r\n      this.sendWriteError(session.browserConnectionId, {\r\n        transactionId: message.transactionId,\r\n        code: message.action === 'begin' ? 'ADAPTER_ERROR' : 'WRITE_FAILED',\r\n        message: message.message ?? `Transaction ${message.action} failed`,\r\n      });\r\n      this.sessions.remove(message.transactionId);\r\n      return;\r\n    }\r\n\r\n    if (message.action === 'begin') {\r\n      this.sendTransactionStatus(session.browserConnectionId, {\r\n        transactionId: message.transactionId,\r\n        deviceId: session.deviceId,\r\n        state: 'open',\r\n      });\r\n      return;\r\n    }\r\n\r\n    if (message.action === 'commit') {\r\n      this.sendTransactionStatus(session.browserConnectionId, {\r\n        transactionId: message.transactionId,\r\n        deviceId: session.deviceId,\r\n        state: 'idle',\r\n      });\r\n      this.sessions.remove(message.transactionId);\r\n      return;\r\n    }\r\n\r\n    this.sendTransactionStatus(session.browserConnectionId, {\r\n      transactionId: message.transactionId,\r\n      deviceId: session.deviceId,\r\n      state: 'idle',\r\n      message: message.message,\r\n    });\r\n    this.sessions.remove(message.transactionId);\r\n  }\r\n\r\n  handleWriteAck(message: WriteAckMessage): void {\r\n    const session = this.sessions.get(message.transactionId);\r\n\r\n    if (!session) {\r\n      return;\r\n    }\r\n\r\n    this.sessions.decrementPendingWrites(message.transactionId);\r\n\r\n    if (!message.ok) {\r\n      this.sendWriteError(session.browserConnectionId, {\r\n        transactionId: message.transactionId,\r\n        writeId: message.writeId,\r\n        code: 'WRITE_FAILED',\r\n        message: message.message ?? 'Write operation failed',\r\n      });\r\n      return;\r\n    }\r\n\r\n    this.router.sendToBrowser(\r\n      session.browserConnectionId,\r\n      createMessage<WriteResultMessage>({\r\n        type: MessageType.WRITE_RESULT,\r\n        writeId: message.writeId,\r\n        transactionId: message.transactionId,\r\n        rowsAffected: message.rowsAffected ?? 0,\r\n      }),\r\n    );\r\n  }\r\n\r\n  checkTimeouts(): void {\r\n    for (const session of this.sessions.getExpired()) {\r\n      this.rollbackSession(session, 'TIMEOUT', 'Write transaction timed out');\r\n    }\r\n  }\r\n\r\n  rollbackSessionsOnBrowserDisconnect(browserConnectionId: string): void {\r\n    for (const session of this.sessions.getByBrowserConnectionId(browserConnectionId)) {\r\n      this.rollbackSession(session, 'NO_TRANSACTION', 'Browser disconnected');\r\n    }\r\n  }\r\n\r\n  rollbackSessionsForDevice(deviceId: string): void {\r\n    for (const session of this.sessions.getByDeviceId(deviceId)) {\r\n      this.rollbackSession(session, 'NO_TRANSACTION', 'Device disconnected');\r\n    }\r\n  }\r\n\r\n  private rollbackSession(\r\n    session: WriteSession,\r\n    code: WriteErrorCode,\r\n    message: string,\r\n  ): void {\r\n    logger.syncFailed(session.transactionId, code, message);\r\n\r\n    this.sendWriteError(session.browserConnectionId, {\r\n      transactionId: session.transactionId,\r\n      code,\r\n      message,\r\n    });\r\n\r\n    this.router.sendToMobile(\r\n      session.deviceId,\r\n      createMessage<RollbackTransactionMessage>({\r\n        type: MessageType.ROLLBACK_TRANSACTION,\r\n        transactionId: session.transactionId,\r\n      }),\r\n    );\r\n\r\n    this.sessions.remove(session.transactionId);\r\n  }\r\n\r\n  private sendTransactionStatus(\r\n    browserConnectionId: string,\r\n    payload: Omit<TransactionStatusMessage, 'type' | 'timestamp'>,\r\n  ): void {\r\n    this.router.sendToBrowser(\r\n      browserConnectionId,\r\n      createMessage<TransactionStatusMessage>({\r\n        type: MessageType.TRANSACTION_STATUS,\r\n        ...payload,\r\n      }),\r\n    );\r\n  }\r\n\r\n  private sendWriteError(\r\n    browserConnectionId: string,\r\n    payload: {\r\n      transactionId: string;\r\n      writeId?: string;\r\n      code: WriteErrorCode;\r\n      message: string;\r\n    },\r\n  ): void {\r\n    this.router.sendToBrowser(\r\n      browserConnectionId,\r\n      createMessage<WriteErrorMessage>({\r\n        type: MessageType.WRITE_ERROR,\r\n        ...payload,\r\n      }),\r\n    );\r\n  }\r\n}\r\n","import type { TransactionStatusState } from '../types/protocol';\r\nimport { WRITE_TRANSACTION_TIMEOUT_MS } from '../types/protocol';\r\n\r\nexport type WriteSession = {\r\n  transactionId: string;\r\n  deviceId: string;\r\n  browserConnectionId: string;\r\n  state: TransactionStatusState;\r\n  pendingWrites: number;\r\n  createdAt: number;\r\n};\r\n\r\nexport class WriteSessionManager {\r\n  private readonly sessions = new Map<string, WriteSession>();\r\n  private readonly activeByDevice = new Map<string, string>();\r\n\r\n  create(input: {\r\n    transactionId: string;\r\n    deviceId: string;\r\n    browserConnectionId: string;\r\n  }): WriteSession {\r\n    const session: WriteSession = {\r\n      transactionId: input.transactionId,\r\n      deviceId: input.deviceId,\r\n      browserConnectionId: input.browserConnectionId,\r\n      state: 'opening',\r\n      pendingWrites: 0,\r\n      createdAt: Date.now(),\r\n    };\r\n\r\n    this.sessions.set(input.transactionId, session);\r\n    this.activeByDevice.set(input.deviceId, input.transactionId);\r\n    return session;\r\n  }\r\n\r\n  get(transactionId: string): WriteSession | undefined {\r\n    return this.sessions.get(transactionId);\r\n  }\r\n\r\n  getActiveForDevice(deviceId: string): WriteSession | undefined {\r\n    const transactionId = this.activeByDevice.get(deviceId);\r\n\r\n    if (!transactionId) {\r\n      return undefined;\r\n    }\r\n\r\n    return this.sessions.get(transactionId);\r\n  }\r\n\r\n  setState(transactionId: string, state: TransactionStatusState): WriteSession | undefined {\r\n    const session = this.sessions.get(transactionId);\r\n\r\n    if (!session) {\r\n      return undefined;\r\n    }\r\n\r\n    session.state = state;\r\n    return session;\r\n  }\r\n\r\n  incrementPendingWrites(transactionId: string): WriteSession | undefined {\r\n    const session = this.sessions.get(transactionId);\r\n\r\n    if (!session) {\r\n      return undefined;\r\n    }\r\n\r\n    session.pendingWrites += 1;\r\n    return session;\r\n  }\r\n\r\n  decrementPendingWrites(transactionId: string): WriteSession | undefined {\r\n    const session = this.sessions.get(transactionId);\r\n\r\n    if (!session) {\r\n      return undefined;\r\n    }\r\n\r\n    session.pendingWrites = Math.max(0, session.pendingWrites - 1);\r\n    return session;\r\n  }\r\n\r\n  remove(transactionId: string): void {\r\n    const session = this.sessions.get(transactionId);\r\n\r\n    if (!session) {\r\n      return;\r\n    }\r\n\r\n    if (this.activeByDevice.get(session.deviceId) === transactionId) {\r\n      this.activeByDevice.delete(session.deviceId);\r\n    }\r\n\r\n    this.sessions.delete(transactionId);\r\n  }\r\n\r\n  getExpired(now = Date.now()): WriteSession[] {\r\n    return [...this.sessions.values()].filter((session) => {\r\n      if (session.state === 'idle' || session.state === 'failed') {\r\n        return false;\r\n      }\r\n\r\n      return now - session.createdAt >= WRITE_TRANSACTION_TIMEOUT_MS;\r\n    });\r\n  }\r\n\r\n  getByBrowserConnectionId(browserConnectionId: string): WriteSession[] {\r\n    return [...this.sessions.values()].filter(\r\n      (session) => session.browserConnectionId === browserConnectionId,\r\n    );\r\n  }\r\n\r\n  getByDeviceId(deviceId: string): WriteSession[] {\r\n    return [...this.sessions.values()].filter((session) => session.deviceId === deviceId);\r\n  }\r\n}\r\n","import { existsSync } from 'node:fs';\r\nimport path from 'node:path';\r\n\r\nfunction collectWebDistCandidates(entryDir: string): string[] {\r\n  const candidates: string[] = [];\r\n  const envPath = process.env.DATABASE_DEVTOOLS_WEB_DIST?.trim();\r\n\r\n  if (envPath) {\r\n    candidates.push(path.resolve(envPath));\r\n  }\r\n\r\n  let current = path.resolve(entryDir);\r\n\r\n  for (let depth = 0; depth < 8; depth += 1) {\r\n    candidates.push(path.join(current, 'dist', 'web'));\r\n    candidates.push(path.join(current, 'web'));\r\n\r\n    const parent = path.dirname(current);\r\n\r\n    if (parent === current) {\r\n      break;\r\n    }\r\n\r\n    current = parent;\r\n  }\r\n\r\n  return candidates;\r\n}\r\n\r\nexport function resolveWebDistPath(entryDir: string): string | undefined {\r\n  const seen = new Set<string>();\r\n\r\n  for (const candidate of collectWebDistCandidates(entryDir)) {\r\n    const normalized = path.resolve(candidate);\r\n\r\n    if (seen.has(normalized)) {\r\n      continue;\r\n    }\r\n\r\n    seen.add(normalized);\r\n\r\n    if (existsSync(path.join(normalized, 'index.html'))) {\r\n      return normalized;\r\n    }\r\n  }\r\n\r\n  return undefined;\r\n}\r\n","import { exec } from 'node:child_process';\r\n\r\nexport function openBrowser(url: string): void {\r\n  if (process.env.DATABASE_DEVTOOLS_NO_OPEN === '1') {\r\n    return;\r\n  }\r\n\r\n  const platform = process.platform;\r\n  const command =\r\n    platform === 'win32'\r\n      ? `start \"\" \"${url}\"`\r\n      : platform === 'darwin'\r\n        ? `open \"${url}\"`\r\n        : `xdg-open \"${url}\"`;\r\n\r\n  exec(command, (error) => {\r\n    if (error) {\r\n      console.warn(`[database-devtools] Could not open browser automatically: ${error.message}`);\r\n    }\r\n  });\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,oBAAiB;;;ACAjB,IAAAC,kBAAoB;AACpB,uBAA0C;;;ACEnC,IAAM,eAAe;AAAA,EAC1B,QAAQ;AAAA,EACR,SAAS;AACX;AAKO,IAAM,cAAc;AAAA,EACzB,UAAU;AAAA,EACV,MAAM;AAAA,EACN,MAAM;AAAA,EACN,eAAe;AAAA,EACf,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,2BAA2B;AAAA,EAC3B,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,eAAe;AAAA,EACf,yBAAyB;AAAA,EACzB,uBAAuB;AAAA,EACvB,2BAA2B;AAAA,EAC3B,4BAA4B;AAAA,EAC5B,8BAA8B;AAAA,EAC9B,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,WAAW;AAAA,EACX,oBAAoB;AAAA,EACpB,cAAc;AAAA,EACd,aAAa;AACf;AAySO,IAAM,mBAAmB;AAEzB,IAAM,wBAAwB;AAE9B,IAAM,wBAAwB;AAE9B,IAAM,wBAAwB;AAE9B,IAAM,uBAAuB;AAE7B,IAAM,2BAA2B;AAEjC,IAAM,4BAA4B;AAElC,IAAM,iCAAiC;AAEvC,IAAM,6BAA6B;AAEnC,IAAM,kCAAkC;AAKxC,IAAM,qBAAqB;AAK3B,IAAM,+BAA+B,IAAI,KAAK;AAE9C,IAAM,qBAAqB,KAAK,OAAO;AAEvC,SAAS,cACd,SACG;AACH,SAAO,EAAE,GAAG,SAAS,WAAW,KAAK,IAAI,EAAE;AAC7C;AAEO,SAAS,qBACd,OAAO,aACP,OAAO,uBACC;AACR,SAAO,UAAU,IAAI,IAAI,IAAI;AAC/B;AAEO,SAAS,mBACd,OAAO,aACP,OAAO,uBACC;AACR,SAAO,QAAQ,IAAI,IAAI,IAAI,GAAG,gBAAgB;AAChD;AAqBA,SAAS,eAAe,OAA2C;AACjE,SAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,OAAQ,MAA4B,SAAS;AACrG;AAEO,SAAS,kBAAkB,OAA0C;AAC1E,MAAI,CAAC,eAAe,KAAK,KAAK,MAAM,SAAS,YAAY,UAAU;AACjE,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAChB,SACE,QAAQ,SAAS,aAAa,UAAU,QAAQ,SAAS,aAAa;AAE1E;AAEO,SAAS,cAAc,OAAsC;AAClE,MAAI,CAAC,eAAe,KAAK,KAAK,MAAM,SAAS,YAAY,MAAM;AAC7D,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAChB,SAAO,OAAO,QAAQ,WAAW;AACnC;AAEO,SAAS,wBAAwB,OAAgD;AACtF,MAAI,CAAC,eAAe,KAAK,KAAK,MAAM,SAAS,YAAY,iBAAiB;AACxE,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAChB,SAAO,OAAO,QAAQ,aAAa,YAAY,QAAQ,gBAAgB;AACzE;AA8CO,SAAS,+BACd,OACuC;AACvC,MAAI,CAAC,eAAe,KAAK,KAAK,MAAM,SAAS,YAAY,yBAAyB;AAChF,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAChB,SAAO,QAAQ,gBAAgB;AACjC;AAaO,SAAS,iCACd,OACyC;AACzC,MAAI,CAAC,eAAe,KAAK,KAAK,MAAM,SAAS,YAAY,2BAA2B;AAClF,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAChB,SAAO,OAAO,QAAQ,kBAAkB,YAAY,OAAO,QAAQ,aAAa;AAClF;AAEO,SAAS,kCACd,OAC0C;AAC1C,MAAI,CAAC,eAAe,KAAK,KAAK,MAAM,SAAS,YAAY,4BAA4B;AACnF,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAChB,SAAO,OAAO,QAAQ,kBAAkB,YAAY,OAAO,QAAQ,aAAa;AAClF;AAEO,SAAS,oCACd,OAC4C;AAC5C,MAAI,CAAC,eAAe,KAAK,KAAK,MAAM,SAAS,YAAY,8BAA8B;AACrF,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAChB,SAAO,OAAO,QAAQ,kBAAkB,YAAY,OAAO,QAAQ,aAAa;AAClF;AAEO,SAAS,sBAAsB,OAA8C;AAClF,MAAI,CAAC,eAAe,KAAK,KAAK,MAAM,SAAS,YAAY,eAAe;AACtE,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAChB,SACE,OAAO,QAAQ,YAAY,YAC3B,OAAO,QAAQ,kBAAkB,YACjC,OAAO,QAAQ,aAAa,YAC5B,OAAO,QAAQ,cAAc,YAC7B,QAAQ,cAAc;AAE1B;AAEO,SAAS,wBAAwB,OAAgD;AACtF,MAAI,CAAC,eAAe,KAAK,KAAK,MAAM,SAAS,YAAY,iBAAiB;AACxE,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAChB,SACE,OAAO,QAAQ,kBAAkB,aAChC,QAAQ,WAAW,WAAW,QAAQ,WAAW,YAAY,QAAQ,WAAW,eACjF,OAAO,QAAQ,OAAO;AAE1B;AAEO,SAAS,kBAAkB,OAA0C;AAC1E,MAAI,CAAC,eAAe,KAAK,KAAK,MAAM,SAAS,YAAY,WAAW;AAClE,WAAO;AAAA,EACT;AAEA,QAAM,UAAU;AAChB,SACE,OAAO,QAAQ,YAAY,YAC3B,OAAO,QAAQ,kBAAkB,YACjC,OAAO,QAAQ,OAAO;AAE1B;;;AC9jBO,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAE7B,IAAM,4BAA4B;;;ACNzC,IAAM,QAAQ;AACd,IAAM,QAAQ;AACd,IAAM,SAAS;AACf,IAAM,OAAO;AACb,IAAM,MAAM;AACZ,IAAM,MAAM;AAEZ,IAAM,SAAS,GAAG,GAAG,sBAAsB,KAAK;AAEhD,SAAS,IAAI,OAAe,QAAgB,SAAuB;AACjE,UAAQ,IAAI,GAAG,MAAM,IAAI,KAAK,GAAG,MAAM,GAAG,KAAK,IAAI,OAAO,EAAE;AAC9D;AAEO,IAAM,SAAS;AAAA,EACpB,iBAAiB,cAA6B;AAC5C,UAAM,SAAS,eAAe,IAAI,GAAG,IAAI,YAAY,IAAI,KAAK,KAAK;AACnE,QAAI,OAAO,UAAK,oBAAoB,MAAM,EAAE;AAAA,EAC9C;AAAA,EAEA,oBAAoB,cAA6B;AAC/C,UAAM,SAAS,eAAe,IAAI,GAAG,IAAI,YAAY,IAAI,KAAK,KAAK;AACnE,QAAI,QAAQ,UAAK,uBAAuB,MAAM,EAAE;AAAA,EAClD;AAAA,EAEA,gBAAgB,UAAyB;AACvC,UAAM,SAAS,WAAW,IAAI,GAAG,cAAc,QAAQ,IAAI,KAAK,KAAK;AACrE,QAAI,OAAO,UAAK,mBAAmB,MAAM,EAAE;AAAA,EAC7C;AAAA,EAEA,mBAAmB,UAAyB;AAC1C,UAAM,SAAS,WAAW,IAAI,GAAG,cAAc,QAAQ,IAAI,KAAK,KAAK;AACrE,QAAI,QAAQ,UAAK,sBAAsB,MAAM,EAAE;AAAA,EACjD;AAAA,EAEA,cAAc,QAAuB;AACnC,UAAM,SAAS,SAAS,IAAI,GAAG,UAAK,MAAM,GAAG,KAAK,KAAK;AACvD,QAAI,MAAM,UAAK,iBAAiB,MAAM,EAAE;AAAA,EAC1C;AAAA,EAEA,cAAc,KAAa,OAAe,eAAe,OAAa;AACpE,QAAI,OAAO,UAAK,qBAAqB,GAAG,EAAE;AAC1C,QAAI,OAAO,UAAK,sBAAsB,KAAK,EAAE;AAE7C,QAAI,cAAc;AAChB,UAAI,OAAO,UAAK,2BAA2B,GAAG,EAAE;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,iBAAiB,cAA4B;AAC3C,QAAI,KAAK,UAAK,qCAAgC,YAAY,EAAE;AAAA,EAC9D;AAAA,EAEA,eAAe,UAAwB;AACrC,QAAI,MAAM,UAAK,mBAAmB,GAAG,IAAI,QAAQ,IAAI,KAAK,EAAE;AAAA,EAC9D;AAAA,EAEA,gBAAgB,UAAkB,OAAqB;AACrD,QAAI,OAAO,UAAK,qBAAqB,GAAG,IAAI,QAAQ,KAAK,KAAK,UAAU,KAAK,EAAE;AAAA,EACjF;AAAA,EAEA,cAAc,UAAkB,MAAc,SAAuB;AACnE,QAAI,KAAK,UAAK,kBAAkB,GAAG,IAAI,QAAQ,KAAK,IAAI,IAAI,KAAK,IAAI,OAAO,EAAE;AAAA,EAChF;AAAA;AAAA,EAGA,YAAY,QAAgB,UAAwB;AAClD,SAAK,eAAe,QAAQ;AAAA,EAC9B;AAAA;AAAA,EAGA,aAAa,QAAgB,OAAqB;AAChD,SAAK,gBAAgB,QAAQ,KAAK;AAAA,EACpC;AAAA;AAAA,EAGA,WAAW,QAAgB,MAAc,SAAuB;AAC9D,SAAK,cAAc,QAAQ,MAAM,OAAO;AAAA,EAC1C;AAAA,EAEA,MAAM,SAAuB;AAC3B,QAAI,KAAK,UAAK,OAAO;AAAA,EACvB;AACF;;;AClFA,qBAA2B;AAC3B,uBAAiB;AAEjB,qBAAoB;AAEpB,SAAS,eAAe,SAA2B;AACjD,MAAI,QAAQ,WAAW,SAAS,QAAQ,WAAW,QAAQ;AACzD,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,KAAK,WAAW,MAAM,GAAG;AACnC,WAAO;AAAA,EACT;AAEA,MAAI,QAAQ,SAAS,WAAW;AAC9B,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,YAAY,KAAc,aAA2B;AACnE,QAAM,YAAY,iBAAAC,QAAK,KAAK,aAAa,YAAY;AAErD,MAAI,KAAC,2BAAW,SAAS,GAAG;AAC1B;AAAA,EACF;AAEA,MAAI;AAAA,IACF,eAAAC,QAAQ,OAAO,aAAa;AAAA,MAC1B,OAAO;AAAA,MACP,WAAW,UAAU,UAAU;AAC7B,YAAI,SAAS,SAAS,OAAO,GAAG;AAC9B,mBAAS,UAAU,gBAAgB,kBAAkB;AAAA,QACvD;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAEA,MAAI,IAAI,KAAK,CAAC,SAAkB,UAAoB,SAAS;AAC3D,QAAI,CAAC,eAAe,OAAO,GAAG;AAC5B,WAAK;AACL;AAAA,IACF;AAEA,aAAS,SAAS,SAAS;AAAA,EAC7B,CAAC;AACH;;;AC9CA,gBAAgD;AA+BzC,SAAS,gBACd,YACA,mBACA,QACA,WACA,oBACA,kBACA,SACuB;AACvB,QAAM,MAAM,IAAI,0BAAgB,EAAE,QAAQ,YAAY,MAAM,iBAAiB,CAAC;AAE9E,QAAM,mBAAmB,CAAC,WAA4B;AACpD,UAAM,SAAS,kBAAkB,OAAO,MAAM;AAE9C,QAAI,CAAC,QAAQ;AACX;AAAA,IACF;AAEA,QAAI,OAAO,SAAS,aAAa,QAAQ;AACvC,UAAI,OAAO,UAAU;AACnB,yBAAiB,0BAA0B,OAAO,QAAQ;AAAA,MAC5D;AAEA,aAAO,mBAAmB,OAAO,QAAQ;AAAA,IAC3C,OAAO;AACL,uBAAiB,oCAAoC,OAAO,YAAY;AACxE,aAAO,oBAAoB,OAAO,YAAY;AAAA,IAChD;AAEA,WAAO,sBAAsB;AAAA,EAC/B;AAEA,MAAI,GAAG,cAAc,CAAC,WAAsB;AAC1C,WAAO,GAAG,WAAW,CAAC,QAAQ;AAC5B,UAAI;AAEJ,UAAI;AACF,iBAAS,KAAK,MAAM,OAAO,GAAG,CAAC;AAAA,MACjC,QAAQ;AACN;AAAA,MACF;AAEA,UAAI,kBAAkB,MAAM,GAAG;AAC7B,cAAM,WAAW,kBAAkB,YAAY,MAAM;AAErD,YAAI,UAAU;AACZ;AAAA,QACF;AAEA,cAAM,SAAS,kBAAkB,IAAI;AAAA,UACnC;AAAA,UACA,MAAM,OAAO;AAAA,UACb,UAAU,OAAO;AAAA,UACjB,UAAU,OAAO;AAAA,QACnB,CAAC;AAED,YAAI,OAAO,SAAS,aAAa,QAAQ;AACvC,iBAAO,gBAAgB,OAAO,QAAQ;AAEtC,cAAI,OAAO,YAAY,SAAS,mBAAmB;AACjD,iBAAK,QAAQ,kBACV,yBAAyB;AAAA,cACxB,UAAU,OAAO;AAAA,cACjB,UAAU,OAAO,UAAU;AAAA,YAC7B,CAAC,EACA,QAAQ,MAAM;AACb,qBAAO,sBAAsB;AAAA,YAC/B,CAAC;AACH;AAAA,UACF;AAAA,QACF,OAAO;AACL,iBAAO,iBAAiB,OAAO,YAAY;AAAA,QAC7C;AAEA,eAAO,sBAAsB;AAC7B;AAAA,MACF;AAEA,UAAI,cAAc,MAAM,GAAG;AACzB,0BAAkB,eAAe,MAAM;AACvC;AAAA,MACF;AAEA,UAAI,wBAAwB,MAAM,GAAG;AACnC,2BAAmB,qBAAqB,QAAQ,MAAM;AACtD;AAAA,MACF;AAEA,UAAI,+BAA+B,MAAM,GAAG;AAC1C,2BAAmB,0BAA0B,QAAQ,MAAM;AAC3D;AAAA,MACF;AAEA,UAAI,iCAAiC,MAAM,GAAG;AAC5C,yBAAiB,8BAA8B,QAAQ,MAAM;AAC7D;AAAA,MACF;AAEA,UAAI,kCAAkC,MAAM,GAAG;AAC7C,yBAAiB,+BAA+B,QAAQ,MAAM;AAC9D;AAAA,MACF;AAEA,UAAI,oCAAoC,MAAM,GAAG;AAC/C,yBAAiB,iCAAiC,QAAQ,MAAM;AAChE;AAAA,MACF;AAEA,UAAI,sBAAsB,MAAM,GAAG;AACjC,yBAAiB,mBAAmB,QAAQ,MAAM;AAClD;AAAA,MACF;AAEA,UAAI,wBAAwB,MAAM,GAAG;AACnC,yBAAiB,qBAAqB,MAAM;AAC5C;AAAA,MACF;AAEA,UAAI,kBAAkB,MAAM,GAAG;AAC7B,yBAAiB,eAAe,MAAM;AAAA,MACxC;AAAA,IACF,CAAC;AAED,WAAO,GAAG,SAAS,MAAM;AACvB,uBAAiB,MAAM;AAAA,IACzB,CAAC;AAED,WAAO,GAAG,SAAS,MAAM;AACvB,uBAAiB,MAAM;AAAA,IACzB,CAAC;AAAA,EACH,CAAC;AAED,YAAU,MAAM;AAEhB,SAAO,EAAE,IAAI;AACf;;;ACvKO,SAAS,uBAA+B;AAC7C,SAAO,iBAAiB,MAAM;AAChC;AAMO,SAAS,iBAAyB;AACvC,SAAO,iBAAiB,MAAM;AAChC;AAcA,SAAS,iBAAiB,QAAwB;AAChD,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY;AAC5E,WAAO,GAAG,MAAM,IAAI,OAAO,WAAW,CAAC;AAAA,EACzC;AAEA,QAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE;AACrD,SAAO,GAAG,MAAM,IAAI,KAAK,IAAI,CAAC,IAAI,MAAM;AAC1C;;;ACVO,IAAM,oBAAN,MAAwB;AAAA,EACZ,UAAU,oBAAI,IAAgC;AAAA,EAE/D,IAAI,OAA6C;AAC/C,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,SAA0B;AAAA,MAC9B,QAAQ,MAAM;AAAA,MACd,cAAc,qBAAqB;AAAA,MACnC,MAAM,MAAM;AAAA,MACZ,UAAU,MAAM;AAAA,MAChB,UAAU,MAAM;AAAA,MAChB,aAAa;AAAA,MACb,YAAY;AAAA,IACd;AAEA,SAAK,QAAQ,IAAI,MAAM,QAAQ,MAAM;AACrC,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,QAAgD;AACrD,UAAM,SAAS,KAAK,QAAQ,IAAI,MAAM;AAEtC,QAAI,QAAQ;AACV,WAAK,QAAQ,OAAO,MAAM;AAAA,IAC5B;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,YAAY,QAAgD;AAC1D,WAAO,KAAK,QAAQ,IAAI,MAAM;AAAA,EAChC;AAAA,EAEA,kBAAkB,cAAmD;AACnE,eAAW,UAAU,KAAK,QAAQ,OAAO,GAAG;AAC1C,UAAI,OAAO,iBAAiB,cAAc;AACxC,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,UAA+C;AAC3D,eAAW,UAAU,KAAK,QAAQ,OAAO,GAAG;AAC1C,UAAI,OAAO,aAAa,UAAU;AAChC,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,UAAU,MAAuC;AAC/C,WAAO,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW,OAAO,SAAS,IAAI;AAAA,EAC3E;AAAA,EAEA,eAAe,QAAyB;AACtC,UAAM,SAAS,KAAK,QAAQ,IAAI,MAAM;AAEtC,QAAI,QAAQ;AACV,aAAO,aAAa,KAAK,IAAI;AAAA,IAC/B;AAAA,EACF;AAAA,EAEA,SAA4B;AAC1B,WAAO,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC;AAAA,EAClC;AACF;;;AClFA,IAAM,kBAAkB;AAExB,IAAM,kBAAkB;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,IAAI;AAOJ,SAAS,kBACd,eACA,kBACQ;AACR,MAAI,kBAAkB;AACpB,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,eAAe;AAClB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,MAAM,IAAI,IAAI,aAAa;AACjC,UAAM,aACJ,IAAI,aAAa,eACjB,IAAI,aAAa,eACjB,IAAI,aAAa;AAEnB,QAAI,YAAY;AACd,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,qBAAqB,UAAuB,CAAC,GAAG;AAC9D,QAAM,mBAAmB,QAAQ,iBAAiB,QAAQ,IAAI;AAE9D,SAAO,CAAC,SAAkB,UAAoB,SAA6B;AACzE,UAAM,SAAS,kBAAkB,QAAQ,OAAO,QAAQ,GAAG,gBAAgB;AAE3E,aAAS,UAAU,+BAA+B,MAAM;AACxD,aAAS,UAAU,gCAAgC,eAAe;AAClE,aAAS,UAAU,gCAAgC,eAAe;AAClE,aAAS,UAAU,QAAQ,QAAQ;AAEnC,QAAI,QAAQ,WAAW,WAAW;AAChC,eAAS,OAAO,GAAG,EAAE,IAAI;AACzB;AAAA,IACF;AAEA,SAAK;AAAA,EACP;AACF;;;AChEO,IAAM,iBAAN,MAAqB;AAAA,EAC1B,YAA6B,mBAAsC;AAAtC;AAAA,EAAuC;AAAA,EAAvC;AAAA,EAE7B,WAAgC;AAC9B,UAAM,WAAW,KAAK,kBACnB,UAAU,aAAa,OAAO,EAC9B,IAAI,CAAC,YAAY;AAAA,MAChB,cAAc,OAAO;AAAA,MACrB,aAAa,OAAO;AAAA,IACtB,EAAE;AAEJ,UAAM,UAAU,KAAK,kBAClB,UAAU,aAAa,MAAM,EAC7B,IAAI,CAAC,YAAY;AAAA,MAChB,UAAU,OAAO,YAAY,OAAO;AAAA,MACpC,cAAc,OAAO;AAAA,MACrB,aAAa,OAAO;AAAA,MACpB,UAAU,OAAO;AAAA,IACnB,EAAE;AAEJ,WAAO;AAAA,MACL,cAAc,SAAS;AAAA,MACvB,aAAa,QAAQ;AAAA,MACrB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;;;ACnBO,IAAM,YAAN,MAAgB;AAAA,EAGrB,YACmB,mBACA,QACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAFgB;AAAA,EACA;AAAA,EAJX,WAAkD;AAAA,EAO1D,QAAc;AACZ,QAAI,KAAK,aAAa,MAAM;AAC1B;AAAA,IACF;AAEA,SAAK,WAAW,YAAY,MAAM;AAChC,WAAK,QAAQ;AACb,WAAK,uBAAuB;AAAA,IAC9B,GAAG,qBAAqB;AAAA,EAC1B;AAAA,EAEA,OAAa;AACX,QAAI,KAAK,aAAa,MAAM;AAC1B,oBAAc,KAAK,QAAQ;AAC3B,WAAK,WAAW;AAAA,IAClB;AAAA,EACF;AAAA,EAEQ,UAAgB;AACtB,UAAM,SAAS,eAAe;AAC9B,UAAM,UAAU,cAA2B;AAAA,MACzC,MAAM,YAAY;AAAA,MAClB;AAAA,IACF,CAAC;AAED,eAAW,UAAU,KAAK,kBAAkB,OAAO,GAAG;AACpD,WAAK,OAAO,aAAa,OAAO,QAAQ,OAAO;AAAA,IACjD;AAAA,EACF;AAAA,EAEQ,yBAA+B;AACrC,UAAM,MAAM,KAAK,IAAI;AAErB,eAAW,UAAU,KAAK,kBAAkB,OAAO,GAAG;AACpD,UAAI,MAAM,OAAO,aAAa,wBAAwB,sBAAsB;AAC1E,eAAO,iBAAiB,OAAO,YAAY;AAC3C,eAAO,OAAO,UAAU;AACxB,aAAK,kBAAkB,OAAO,OAAO,MAAM;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AACF;;;AC9CO,IAAM,gBAAN,MAAoB;AAAA,EACzB,YACmB,mBACA,gBACjB;AAFiB;AACA;AAAA,EAChB;AAAA,EAFgB;AAAA,EACA;AAAA,EAGnB,aAAa,QAAmB,SAAgC;AAC9D,QAAI,OAAO,eAAe,OAAO,MAAM;AACrC,aAAO,KAAK,KAAK,UAAU,OAAO,CAAC;AAAA,IACrC;AAAA,EACF;AAAA,EAEA,cAAc,cAAsB,SAAgC;AAClE,UAAM,SAAS,KAAK,kBAAkB,kBAAkB,YAAY;AAEpE,QAAI,QAAQ,SAAS,aAAa,SAAS;AACzC,WAAK,aAAa,OAAO,QAAQ,OAAO;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,aAAa,UAAkB,SAAgC;AAC7D,UAAM,SAAS,KAAK,kBAAkB,cAAc,QAAQ;AAE5D,QAAI,QAAQ,SAAS,aAAa,QAAQ;AACxC,WAAK,aAAa,OAAO,QAAQ,OAAO;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,oBAAoB,SAAgC;AAClD,eAAW,UAAU,KAAK,kBAAkB,UAAU,aAAa,OAAO,GAAG;AAC3E,WAAK,aAAa,OAAO,QAAQ,OAAO;AAAA,IAC1C;AAEA,WAAO,cAAc,UAAU;AAAA,EACjC;AAAA,EAEA,mBAAmB,SAAgC;AACjD,eAAW,UAAU,KAAK,kBAAkB,UAAU,aAAa,MAAM,GAAG;AAC1E,WAAK,aAAa,OAAO,QAAQ,OAAO;AAAA,IAC1C;AAEA,WAAO,cAAc,SAAS;AAAA,EAChC;AAAA,EAEA,eAAe,SAAgC;AAC7C,eAAW,UAAU,KAAK,kBAAkB,OAAO,GAAG;AACpD,WAAK,aAAa,OAAO,QAAQ,OAAO;AAAA,IAC1C;AAEA,WAAO,cAAc,KAAK;AAAA,EAC5B;AAAA,EAEA,UAAU,SAAkB,SAAyC,OAAa;AAChF,UAAM,mBAAmB,cAAgC;AAAA,MACvD,MAAM,YAAY;AAAA,MAClB,SAAS;AAAA,IACX,CAAC;AAED,QAAI,WAAW,YAAY;AACzB,WAAK,oBAAoB,gBAAgB;AACzC;AAAA,IACF;AAEA,QAAI,WAAW,WAAW;AACxB,WAAK,mBAAmB,gBAAgB;AACxC;AAAA,IACF;AAEA,SAAK,eAAe,gBAAgB;AAAA,EACtC;AAAA,EAEA,wBAA8B;AAC5B,UAAM,UAAU,cAAmC;AAAA,MACjD,MAAM,YAAY;AAAA,MAClB,SAAS,KAAK,eAAe,SAAS;AAAA,IACxC,CAAC;AAED,SAAK,eAAe,OAAO;AAAA,EAC7B;AACF;;;AClFO,IAAM,sBAAN,MAA0B;AAAA,EACd,kBAAkB,oBAAI,IAA4B;AAAA,EAEnE,OAAO,OAA6B;AAClC,SAAK,gBAAgB,IAAI,MAAM,UAAU,KAAK;AAAA,EAChD;AAAA,EAEA,IAAI,UAA8C;AAChD,WAAO,KAAK,gBAAgB,IAAI,QAAQ;AAAA,EAC1C;AAAA,EAEA,IAAI,UAA2B;AAC7B,WAAO,KAAK,gBAAgB,IAAI,QAAQ;AAAA,EAC1C;AAAA,EAEA,OAAO,UAAwB;AAC7B,SAAK,gBAAgB,OAAO,QAAQ;AAAA,EACtC;AAAA,EAEA,WAAW,MAAM,KAAK,IAAI,GAAqB;AAC7C,WAAO,CAAC,GAAG,KAAK,gBAAgB,OAAO,CAAC,EAAE;AAAA,MACxC,CAAC,YAAY,MAAM,QAAQ,aAAa;AAAA,IAC1C;AAAA,EACF;AACF;;;ACdO,IAAM,qBAAN,MAAyB;AAAA,EAC9B,YACmB,mBACA,QACA,SACA,WACA,eACjB;AALiB;AACA;AACA;AACA;AACA;AAAA,EAChB;AAAA,EALgB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAGnB,qBAAqB,eAA0B,SAAsC;AACnF,UAAM,UAAU,KAAK,kBAAkB,YAAY,aAAa;AAEhE,QAAI,CAAC,WAAW,QAAQ,SAAS,aAAa,SAAS;AACrD;AAAA,IACF;AAEA,QAAI,QAAQ,gBAAgB,YAAY;AACtC,WAAK,iBAAiB,QAAQ,cAAc;AAAA,QAC1C,UAAU,QAAQ;AAAA,QAClB,MAAM;AAAA,QACN,SAAS,6BAA6B,QAAQ,WAAW;AAAA,MAC3D,CAAC;AACD;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,kBAAkB,cAAc,QAAQ,QAAQ;AAEpE,QAAI,CAAC,QAAQ;AACX,WAAK,iBAAiB,QAAQ,cAAc;AAAA,QAC1C,UAAU,QAAQ;AAAA,QAClB,MAAM;AAAA,QACN,SAAS,UAAU,QAAQ,QAAQ;AAAA,MACrC,CAAC;AACD;AAAA,IACF;AAEA,QAAI,KAAK,QAAQ,IAAI,QAAQ,QAAQ,GAAG;AACtC,WAAK,iBAAiB,QAAQ,cAAc;AAAA,QAC1C,UAAU,QAAQ;AAAA,QAClB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,SAAK,QAAQ,OAAO;AAAA,MAClB,UAAU,QAAQ;AAAA,MAClB,WAAW;AAAA,MACX,qBAAqB,QAAQ;AAAA,MAC7B,aAAa,QAAQ;AAAA,MACrB,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC;AAED,WAAO,eAAe,QAAQ,QAAQ;AAEtC,SAAK,kBAAkB,QAAQ,cAAc,QAAQ,UAAU,WAAW;AAC1E,SAAK,kBAAkB,QAAQ,cAAc,QAAQ,UAAU,WAAW;AAE1E,SAAK,oBAAoB,QAAQ,UAAU,QAAQ,WAAW;AAAA,EAChE;AAAA,EAEA,0BAA0B,cAAyB,SAA6C;AAC9F,UAAM,SAAS,KAAK,kBAAkB,YAAY,YAAY;AAE9D,QAAI,CAAC,UAAU,OAAO,SAAS,aAAa,UAAU,CAAC,OAAO,UAAU;AACtE;AAAA,IACF;AAEA,QAAI,QAAQ,gBAAgB,YAAY;AACtC,WAAK,wBAAwB,cAAc;AAAA,QACzC,MAAM;AAAA,QACN,SAAS,6BAA6B,QAAQ,WAAW;AAAA,MAC3D,CAAC;AACD;AAAA,IACF;AAEA,QAAI,KAAK,QAAQ,IAAI,OAAO,QAAQ,GAAG;AACrC,WAAK,wBAAwB,cAAc;AAAA,QACzC,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,SAAK,QAAQ,OAAO;AAAA,MAClB,UAAU,OAAO;AAAA,MACjB,WAAW;AAAA,MACX,mBAAmB;AAAA,MACnB,aAAa,QAAQ;AAAA,MACrB,WAAW,KAAK,IAAI;AAAA,IACtB,CAAC;AAED,WAAO,eAAe,OAAO,QAAQ;AAErC,SAAK,oBAAoB,OAAO,UAAU,QAAQ,WAAW;AAAA,EAC/D;AAAA,EAEA,MAAM,qBACJ,UACA,MACA,UAC6F;AAC7F,UAAM,UAAU,KAAK,QAAQ,IAAI,QAAQ;AAEzC,QAAI,CAAC,SAAS;AACZ,aAAO,EAAE,IAAI,OAAO,MAAM,qBAAqB;AAAA,IACjD;AAEA,QAAI,QAAQ,qBAAqB;AAC/B,WAAK,kBAAkB,QAAQ,qBAAqB,UAAU,WAAW;AAAA,IAC3E;AAEA,UAAM,SAAS,KAAK,UAAU,IAAI,UAAU,MAAM;AAAA,MAChD,MAAM,UAAU,QAAQ;AAAA,MACxB,UAAU,UAAU,YAAY;AAAA,MAChC,cAAc,UAAU;AAAA,IAC1B,CAAC;AAED,UAAM,SAAS,KAAK,kBAAkB,cAAc,QAAQ;AAE5D,UAAM,KAAK,eAAe,sBAAsB;AAAA,MAC9C;AAAA,MACA,OAAO;AAAA,MACP,MAAM,OAAO;AAAA,MACb,UAAU,OAAO;AAAA,MACjB,cAAc,OAAO;AAAA,MACrB,UAAU,QAAQ,UAAU;AAAA,IAC9B,CAAC;AAED,WAAO,gBAAgB,UAAU,KAAK,UAAU;AAEhD,UAAM,eAAe,cAAoC;AAAA,MACvD,MAAM,YAAY;AAAA,MAClB;AAAA,MACA,MAAM,KAAK;AAAA,MACX,YAAY,OAAO;AAAA,MACnB,MAAM,OAAO;AAAA,MACb,UAAU,OAAO;AAAA,MACjB,GAAI,OAAO,eAAe,EAAE,cAAc,OAAO,aAAa,IAAI,CAAC;AAAA,IACrE,CAAC;AAED,QAAI,QAAQ,mBAAmB;AAC7B,WAAK,OAAO,oBAAoB,YAAY;AAAA,IAC9C,WAAW,QAAQ,qBAAqB;AACtC,WAAK,kBAAkB,QAAQ,qBAAqB,UAAU,OAAO;AACrE,WAAK,OAAO,cAAc,QAAQ,qBAAqB,YAAY;AAAA,IACrE;AAEA,SAAK,QAAQ,OAAO,QAAQ;AAE5B,WAAO,EAAE,IAAI,MAAM,QAAQ,aAAa;AAAA,EAC1C;AAAA,EAEA,YAAY,UAAsC;AAChD,WAAO,KAAK,UAAU,SAAS,QAAQ;AAAA,EACzC;AAAA,EAEA,MAAM,iBAAiB,UAA+C;AACpE,QAAI,KAAK,eAAe;AACtB,YAAM,WAAW,MAAM,KAAK,cAAc,mBAAmB,QAAQ;AAErE,UAAI,UAAU;AACZ,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO,KAAK,UAAU,SAAS,QAAQ;AAAA,EACzC;AAAA,EAEA,gBAAsB;AACpB,eAAW,WAAW,KAAK,QAAQ,WAAW,GAAG;AAC/C,UAAI,QAAQ,cAAc,UAAU;AAClC,aAAK;AAAA,UACH,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,QACF;AACA;AAAA,MACF;AAEA,UAAI,QAAQ,qBAAqB;AAC/B,aAAK;AAAA,UACH,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF,OAAO;AACL,aAAK,QAAQ,OAAO,QAAQ,QAAQ;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,oBAAoB,UAAkB,aAA+B;AAC3E,SAAK,OAAO;AAAA,MACV;AAAA,MACA,cAA8C;AAAA,QAC5C,MAAM,YAAY;AAAA,QAClB;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,YACN,UACA,qBACA,MACA,SACM;AACN,WAAO,cAAc,UAAU,MAAM,OAAO;AAE5C,SAAK,iBAAiB,qBAAqB;AAAA,MACzC;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,OAAO,QAAQ;AAAA,EAC9B;AAAA,EAEQ,iBACN,UACA,MACA,SACM;AACN,WAAO,cAAc,UAAU,MAAM,OAAO;AAE5C,UAAM,SAAS,KAAK,kBAAkB,cAAc,QAAQ;AAE5D,QAAI,QAAQ;AACV,WAAK,wBAAwB,OAAO,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAAA,IAC/D;AAEA,UAAM,eAAe,cAAmC;AAAA,MACtD,MAAM,YAAY;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,SAAK,OAAO,oBAAoB,YAAY;AAC5C,SAAK,QAAQ,OAAO,QAAQ;AAAA,EAC9B;AAAA,EAEQ,kBACN,qBACA,UACA,OACM;AACN,UAAM,gBAAgB,cAAoC;AAAA,MACxD,MAAM,YAAY;AAAA,MAClB;AAAA,MACA;AAAA,IACF,CAAC;AAED,SAAK,OAAO,cAAc,qBAAqB,aAAa;AAAA,EAC9D;AAAA,EAEQ,iBACN,qBACA,OAKM;AACN,UAAM,UAAU,cAAmC;AAAA,MACjD,MAAM,YAAY;AAAA,MAClB,UAAU,MAAM;AAAA,MAChB,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,IACjB,CAAC;AAED,SAAK,OAAO,cAAc,qBAAqB,OAAO;AACtD,WAAO,cAAc,MAAM,UAAU,MAAM,MAAM,MAAM,OAAO;AAAA,EAChE;AAAA,EAEQ,wBACN,cACA,OAIM;AACN,UAAM,UAAU,cAA0C;AAAA,MACxD,MAAM,YAAY;AAAA,MAClB,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,IACjB,CAAC;AAED,SAAK,OAAO,aAAa,cAAc,OAAO;AAAA,EAChD;AACF;;;AC3TA,IAAAC,mBAAqD;AACrD,IAAAC,oBAAiB;;;ACDjB,sBAA2C;AAC3C,IAAAC,oBAAiB;AAEV,IAAM,mBAAmB;AAGzB,IAAM,iCAAiC;AAgD9C,IAAM,iBAAwC;AAAA,EAC5C,YAAY;AAAA,IACV,uBAAuB;AAAA,EACzB;AACF;AAEO,SAAS,eAAe,aAA8B;AAC3D,QAAM,UAAU,QAAQ,IAAI,4BAA4B,KAAK;AAE7D,MAAI,aAAa,KAAK,GAAG;AACvB,WAAO,kBAAAC,QAAK,QAAQ,YAAY,KAAK,CAAC;AAAA,EACxC;AAEA,MAAI,SAAS;AACX,WAAO,kBAAAA,QAAK,QAAQ,OAAO;AAAA,EAC7B;AAEA,SAAO,kBAAAA,QAAK,QAAQ,QAAQ,IAAI,GAAG,gBAAgB;AACrD;AAEO,SAAS,uBAAgC;AAC9C,QAAM,OAAO,QAAQ,IAAI,oCAAoC,KAAK,EAAE,YAAY;AAEhF,MAAI,SAAS,OAAO,SAAS,WAAW,SAAS,OAAO;AACtD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAEO,SAAS,oBAAoB,OAAuB;AACzD,SAAO,MAAM,QAAQ,qBAAqB,GAAG;AAC/C;AAEO,SAAS,oBAAoB,SAAiB;AACnD,QAAM,eAAe,kBAAAA,QAAK,KAAK,SAAS,WAAW;AACnD,QAAM,aAAa,kBAAAA,QAAK,KAAK,cAAc,SAAS;AACpD,QAAM,aAAa,kBAAAA,QAAK,KAAK,SAAS,eAAe;AACrD,QAAM,eAAe,kBAAAA,QAAK,KAAK,SAAS,eAAe;AAEvD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,yBAAyB,SAAgC;AAC7E,QAAM,QAAQ,oBAAoB,OAAO;AAEzC,YAAM,uBAAM,MAAM,YAAY,EAAE,WAAW,KAAK,CAAC;AACnD;AAqBA,eAAsB,0BAA0B,SAAgC;AAC9E,QAAM,EAAE,WAAW,IAAI,oBAAoB,OAAO;AAElD,MAAI;AACF,cAAM,0BAAS,YAAY,MAAM;AAAA,EACnC,QAAQ;AACN,cAAM,uBAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AACxC,cAAM,2BAAU,YAAY,GAAG,KAAK,UAAU,gBAAgB,MAAM,CAAC,CAAC;AAAA,GAAM,MAAM;AAAA,EACpF;AACF;AAOO,SAAS,uBAAuB,UAA0B;AAC/D,SAAO,YAAY,oBAAoB,QAAQ,CAAC;AAClD;AAEO,IAAM,0BAA0B;AAEhC,SAAS,wBAAwB,OAAwD;AAC9F,QAAM,WAAW,MAAM,UAAU,KAAK;AAEtC,MAAI,UAAU;AACZ,WAAO,oBAAoB,QAAQ;AAAA,EACrC;AAEA,SAAO,oBAAoB,MAAM,QAAQ;AAC3C;AAEO,SAAS,wBAAwB,YAA4B;AAClE,SAAO,UAAU,UAAU;AAC7B;AAEO,SAAS,0BAA0B,YAA4B;AACpE,SAAO,kBAAAC,QACJ,KAAK,aAAa,WAAW,YAAY,uBAAuB,EAChE,QAAQ,OAAO,GAAG;AACvB;AAEO,SAAS,2BAA2B,UAA0B;AACnE,QAAM,UAAU,oBAAoB,QAAQ;AAC5C,SAAO,kBAAAA,QACJ,KAAK,aAAa,WAAW,SAAS,uBAAuB,QAAQ,CAAC,EACtE,QAAQ,OAAO,GAAG;AACvB;AAGO,SAAS,yBAAyB,UAA0B;AACjE,SAAO,kBAAAA,QAAK,KAAK,aAAa,WAAW,oBAAoB,QAAQ,GAAG,WAAW,EAAE,QAAQ,OAAO,GAAG;AACzG;AAEA,eAAsB,aAAa,SAA4C;AAC7E,QAAM,EAAE,aAAa,IAAI,oBAAoB,OAAO;AAEpD,MAAI;AACF,UAAM,MAAM,UAAM,0BAAS,cAAc,MAAM;AAC/C,UAAM,SAAS,KAAK,MAAM,GAAG;AAE7B,QAAI,OAAO,YAAY,KAAK,CAAC,MAAM,QAAQ,OAAO,OAAO,GAAG;AAC1D,aAAO,EAAE,SAAS,GAAG,SAAS,CAAC,EAAE;AAAA,IACnC;AAEA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,EAAE,SAAS,GAAG,SAAS,CAAC,EAAE;AAAA,EACnC;AACF;AAEA,eAAsB,cAAc,SAAiB,UAA2C;AAC9F,QAAM,EAAE,aAAa,IAAI,oBAAoB,OAAO;AAEpD,YAAM,uBAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AACxC,YAAM,2BAAU,cAAc,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,GAAM,MAAM;AAChF;AAEO,SAAS,oBACd,UACA,OACkB;AAClB,QAAM,UAAU,SAAS,QAAQ,OAAO,CAAC,SAAS,KAAK,OAAO,MAAM,EAAE;AACtE,UAAQ,KAAK,KAAK;AAElB,UAAQ,KAAK,CAAC,MAAM,UAAU,MAAM,YAAY,KAAK,SAAS;AAE9D,SAAO;AAAA,IACL,SAAS,SAAS;AAAA,IAClB;AAAA,EACF;AACF;;;AC/MO,SAAS,0BAA0B,OAAsC;AAC9E,MAAI,MAAM,YAAY;AACpB,WAAO,MAAM;AAAA,EACf;AAEA,MAAI,MAAM,UAAU;AAClB,WAAO,oBAAoB,MAAM,QAAQ;AAAA,EAC3C;AAEA,QAAM,QAAQ,MAAM,aAAa,MAAM,+BAA+B;AAEtE,MAAI,QAAQ,CAAC,GAAG;AACd,WAAO,MAAM,CAAC;AAAA,EAChB;AAEA,MAAI,MAAM,UAAU;AAClB,WAAO,oBAAoB,MAAM,QAAQ;AAAA,EAC3C;AAEA,SAAO,MAAM;AACf;AAEO,SAAS,4BACd,SACA,UACmC;AACnC,SAAO,QAAQ,KAAK,CAAC,UAAU,MAAM,WAAW,YAAY,MAAM,aAAa,QAAQ;AACzF;AASO,SAAS,iCACd,SACA,MACyB;AACzB,QAAM,iBAAiB,wBAAwB,KAAK,cAAc;AAElE,SAAO,QAAQ,OAAO,CAAC,UAAU;AAC/B,QAAI,MAAM,WAAW,UAAU;AAC7B,aAAO;AAAA,IACT;AAEA,QAAI,MAAM,OAAO,gBAAgB;AAC/B,aAAO;AAAA,IACT;AAEA,UAAM,kBAAkB,0BAA0B,KAAK;AAEvD,QAAI,oBAAoB,KAAK,gBAAgB;AAC3C,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,YAAY,MAAM,aAAa,KAAK,UAAU;AACrD,aAAO;AAAA,IACT;AAEA,QACE,KAAK,YACL,KAAK,gBACL,CAAC,MAAM,YACP,MAAM,iBAAiB,KAAK,cAC5B;AACA,aAAO;AAAA,IACT;AAEA,QACE,CAAC,KAAK,YACN,KAAK,gBACL,MAAM,iBAAiB,KAAK,gBAC5B,MAAM,aAAa,KAAK,cACxB;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT,CAAC;AACH;AAEO,SAAS,0BAA4D,SAAmB;AAC7F,QAAM,eAAe,oBAAI,IAAe;AAExC,aAAW,SAAS,SAAS;AAC3B,UAAM,aAAa,MAAM,aACrB,MAAM,aACN,MAAM,WACJ,oBAAoB,MAAM,QAAQ,IAClC,MAAM,WACJ,oBAAoB,MAAM,QAAQ,IAClC,MAAM;AAEd,UAAM,WAAW,aAAa,IAAI,UAAU;AAE5C,QAAI,CAAC,YAAY,MAAM,YAAY,SAAS,WAAW;AACrD,mBAAa,IAAI,YAAY,KAAK;AAAA,IACpC;AAAA,EACF;AAEA,SAAO,CAAC,GAAG,aAAa,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,UAAU,MAAM,YAAY,KAAK,SAAS;AAC1F;AAOO,SAAS,+BACd,OACyB;AACzB,QAAM,gBAAgB,MAAM,QAAQ,OAAO,CAAC,UAAU,MAAM,WAAW,QAAQ;AAC/E,QAAM,eAAe,MAAM,QAAQ,OAAO,CAAC,UAAU,MAAM,WAAW,QAAQ;AAC9E,QAAM,SAAS,oBAAI,IAAqC;AAExD,aAAW,SAAS,eAAe;AACjC,UAAM,WAAW,MAAM,WACnB,UAAU,MAAM,QAAQ,KACxB,MAAM,eACJ,MAAM,MAAM,YAAY,KACxB,UAAU,0BAA0B,KAAK,CAAC;AAEhD,UAAM,QAAQ,OAAO,IAAI,QAAQ,KAAK,CAAC;AACvC,UAAM,KAAK,KAAK;AAChB,WAAO,IAAI,UAAU,KAAK;AAAA,EAC5B;AAEA,QAAM,oBAA6C,CAAC;AAEpD,aAAW,SAAS,OAAO,OAAO,GAAG;AACnC,QAAI,MAAM,WAAW,GAAG;AACtB,wBAAkB,KAAK,MAAM,CAAC,CAAE;AAChC;AAAA,IACF;AAEA,UAAM,YAAY,MAAM,oBACpB,MAAM,KAAK,CAAC,UAAU,MAAM,aAAa,MAAM,iBAAiB,IAChE;AAEJ,UAAM,SAAS,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,MAAM,UAAU,MAAM,YAAY,KAAK,SAAS,EAAE,CAAC;AACnF,sBAAkB,KAAK,aAAa,MAAM;AAAA,EAC5C;AAEA,SAAO,CAAC,GAAG,cAAc,GAAG,iBAAiB,EAAE,KAAK,CAAC,MAAM,UAAU,MAAM,YAAY,KAAK,SAAS;AACvG;AAEO,SAAS,uBACd,QACA,OACyB;AACzB,QAAM,WAAW,IAAI,IAAI,MAAM,IAAI,CAAC,UAAU,MAAM,EAAE,CAAC;AACvD,SAAO,OAAO,OAAO,CAAC,UAAU,CAAC,SAAS,IAAI,MAAM,EAAE,CAAC;AACzD;;;ACtKA,IAAAC,mBAA8C;AAC9C,IAAAC,oBAAiB;AAUjB,IAAM,oBAA2C;AAAA,EAC/C,YAAY;AAAA,IACV,uBAAuB;AAAA,EACzB;AACF;AAEO,SAAS,0BAA0B,UAA8C;AACtF,QAAM,UAAU,SAAS,QAAQ;AAAA,IAC/B,CAAC,UACC,MAAM,WAAW,YACjB,MAAM,OAAO,YACb,CAAC,MAAM,GAAG,WAAW,SAAS;AAAA,EAClC;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,EACF;AACF;AAEO,SAAS,uBAAuB,QAAsD;AAC3F,SAAO;AAAA,IACL,GAAG;AAAA,IACH,YAAY;AAAA,MACV,GAAG,kBAAkB;AAAA,MACrB,uBAAuB;AAAA,IACzB;AAAA,EACF;AACF;AAEA,eAAsB,4BAA4B,SAAmC;AACnF,QAAM,EAAE,WAAW,IAAI,oBAAoB,OAAO;AAClD,QAAM,WAAW,MAAM,aAAa,OAAO;AAC3C,QAAM,WAAW,0BAA0B,QAAQ;AACnD,QAAM,eAAe,kBAAAC,QAAK,KAAK,SAAS,8BAA8B;AAEtE,MAAI,UACF,SAAS,QAAQ,WAAW,SAAS,QAAQ,UAAU,QAAQ,SAAS,cAAc;AAExF,MAAI,SAAS;AACX,UAAM,cAAc,SAAS,QAAQ;AAAA,EACvC;AAEA,MAAI;AACF,cAAM,uBAAK,YAAY;AACvB,UAAM,mBAAmB,SAAS,QAAQ,KAAK,CAAC,UAAU,MAAM,WAAW,QAAQ;AAEnF,QAAI,oBAAoB,SAAS,QAAQ,KAAK,CAAC,UAAU,MAAM,WAAW,QAAQ,GAAG;AACnF,gBAAM,qBAAG,cAAc,EAAE,OAAO,KAAK,CAAC;AACtC,gBAAU;AAAA,IACZ;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,MAAI;AACF,UAAM,MAAM,UAAM,2BAAS,YAAY,MAAM;AAC7C,UAAM,SAAS,KAAK,MAAM,GAAG;AAE7B,QAAI,OAAO,mBAAmB,OAAO,YAAY,uBAAuB;AACtE,gBAAM;AAAA,QACJ;AAAA,QACA,GAAG,KAAK,UAAU,uBAAuB,MAAM,GAAG,MAAM,CAAC,CAAC;AAAA;AAAA,QAC1D;AAAA,MACF;AACA,gBAAU;AAAA,IACZ;AAAA,EACF,QAAQ;AAAA,EAER;AAEA,QAAM,aAAa,kBAAAA,QAAK,KAAK,SAAS,aAAa,SAAS;AAE5D,MAAI;AACF,cAAM,uBAAK,UAAU;AACrB,cAAM,qBAAG,YAAY,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AACrD,cAAU;AAAA,EACZ,QAAQ;AAAA,EAER;AAEA,SAAO;AACT;;;AHpCO,IAAM,oBAAN,MAAwB;AAAA,EACZ;AAAA,EACA;AAAA,EAEjB,YAAY,SAAmD;AAC7D,SAAK,UAAU,eAAe,SAAS,OAAO;AAC9C,SAAK,UAAU,SAAS,WAAW,qBAAqB;AAAA,EAC1D;AAAA,EAEA,aAAqB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,YAAqB;AACnB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,sBACJ,OAC6C;AAC7C,QAAI,CAAC,KAAK,SAAS;AACjB,aAAO;AAAA,IACT;AAEA,UAAM,0BAA0B,KAAK,OAAO;AAC5C,UAAM,yBAAyB,KAAK,OAAO;AAE3C,UAAM,aAAa,wBAAwB;AAAA,MACzC,UAAU,MAAM;AAAA,MAChB,UAAU,MAAM;AAAA,IAClB,CAAC;AACD,UAAM,qBAAqB,0BAA0B,UAAU;AAC/D,UAAM,qBAAqB,kBAAAC,QAAK,KAAK,KAAK,SAAS,kBAAkB;AACrE,UAAM,aAAa,KAAK,IAAI;AAE5B,UAAM,KAAK,mBAAmB;AAAA,MAC5B,gBAAgB;AAAA,MAChB,cAAc,MAAM;AAAA,MACpB,UAAU,MAAM;AAAA,MAChB,cAAc,MAAM;AAAA,IACtB,CAAC;AAED,cAAM,wBAAM,kBAAAA,QAAK,QAAQ,kBAAkB,GAAG,EAAE,WAAW,KAAK,CAAC;AACjE,cAAM,4BAAU,oBAAoB,MAAM,KAAK;AAE/C,UAAM,WAAW,MAAM,aAAa,KAAK,OAAO;AAEhD,UAAM,cAAqC;AAAA,MACzC,IAAI,wBAAwB,UAAU;AAAA,MACtC,OAAO,MAAM,gBAAgB,UAAU,MAAM,QAAQ;AAAA,MACrD,cAAc,mBAAmB,QAAQ,OAAO,GAAG;AAAA,MACnD,QAAQ;AAAA,MACR,UAAU,MAAM;AAAA,MAChB,UAAU,MAAM;AAAA,MAChB;AAAA,MACA,MAAM,MAAM;AAAA,MACZ,UAAU,MAAM;AAAA,MAChB,cAAc,MAAM;AAAA,MACpB,MAAM,MAAM,MAAM;AAAA,MAClB,WAAW;AAAA,IACb;AAEA,UAAM,eAAe,oBAAoB,UAAU,WAAW;AAE9D,UAAM,cAAc,KAAK,SAAS,YAAY;AAE9C,WAAO;AAAA,MACL,oBAAoB,mBAAmB,QAAQ,OAAO,GAAG;AAAA,MACzD;AAAA,MACA,MAAM,MAAM,MAAM;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,MAAM,yBAAyB,OAGb;AAChB,QAAI,CAAC,KAAK,SAAS;AACjB;AAAA,IACF;AAEA,UAAM,KAAK,uBAAuB,MAAM,QAAQ;AAEhD,UAAM,aAAa,wBAAwB;AAAA,MACzC,UAAU,MAAM;AAAA,MAChB,UAAU,MAAM;AAAA,IAClB,CAAC;AACD,UAAM,WAAW,MAAM,aAAa,KAAK,OAAO;AAChD,UAAM,iBAAiB,SAAS,QAAQ;AAAA,MACtC,CAAC,UAAU,MAAM,WAAW,YAAY,MAAM,eAAe;AAAA,IAC/D;AAEA,QAAI,kBAAkB,eAAe,aAAa,MAAM,UAAU;AAChE,YAAM,UAAU,oBAAoB,UAAU;AAAA,QAC5C,GAAG;AAAA,QACH,UAAU,MAAM;AAAA,QAChB,UAAU,MAAM,YAAY,eAAe;AAAA,QAC3C,WAAW,KAAK,IAAI;AAAA,MACtB,CAAC;AAED,YAAM,cAAc,KAAK,SAAS,OAAO;AAAA,IAC3C;AAEA,UAAM,KAAK,mBAAmB;AAAA,MAC5B,gBAAgB;AAAA,MAChB,cAAc,MAAM;AAAA,MACpB,UAAU,MAAM;AAAA,MAChB,cAAc,gBAAgB;AAAA,IAChC,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,mBAAmB,UAA+C;AACtE,WAAO,KAAK,mBAAmB,QAAQ;AAAA,EACzC;AAAA,EAEA,MAAM,mBAAmB,UAA+C;AACtE,QAAI,CAAC,KAAK,SAAS;AACjB,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,MAAM,KAAK,0BAA0B,QAAQ;AAE9D,QAAI,CAAC,UAAU;AACb,aAAO;AAAA,IACT;AAEA,QAAI;AACF,aAAO,UAAM,2BAAS,SAAS,YAAY;AAAA,IAC7C,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,sBAAsB,UAAgD;AAC1E,QAAI,CAAC,KAAK,SAAS;AACjB,aAAO,EAAE,QAAQ,OAAO,SAAS;AAAA,IACnC;AAEA,UAAM,WAAW,MAAM,KAAK,0BAA0B,QAAQ;AAE9D,QAAI,CAAC,UAAU;AACb,aAAO,EAAE,QAAQ,OAAO,SAAS;AAAA,IACnC;AAEA,QAAI;AACF,YAAM,WAAW,UAAM,uBAAK,SAAS,YAAY;AACjD,YAAM,WAAW,MAAM,aAAa,KAAK,OAAO;AAChD,YAAM,QAAQ,SAAS,QAAQ;AAAA,QAC7B,CAAC,SAAS,KAAK,aAAa,YAAY,KAAK,WAAW;AAAA,MAC1D;AAEA,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,cAAc,SAAS;AAAA,QACvB,cAAc,SAAS;AAAA,QACvB,MAAM,OAAO,QAAQ;AAAA,QACrB,UAAU,OAAO,YAAY;AAAA,QAC7B,cAAc,OAAO,gBAAgB,kBAAAA,QAAK,SAAS,SAAS,YAAY;AAAA,QACxE,MAAM,SAAS;AAAA,QACf,WAAW,OAAO,aAAa,SAAS;AAAA,QACxC,QAAQ;AAAA,QACR;AAAA,MACF;AAAA,IACF,QAAQ;AACN,aAAO,EAAE,QAAQ,OAAO,UAAU,cAAc,SAAS,aAAa;AAAA,IACxE;AAAA,EACF;AAAA,EAEA,MAAM,oBAAsD;AAC1D,UAAM,KAAK,uBAAuB;AAClC,UAAM,YAAY,MAAM,KAAK,cAAc;AAC3C,UAAM,gBAAgB,UAAU,OAAO,CAAC,UAAU,MAAM,WAAW,YAAY,MAAM,QAAQ;AAC7F,WAAO,0BAA0B,aAAa;AAAA,EAChD;AAAA,EAEA,MAAc,uBAAuB,mBAA2C;AAC9E,QAAI,CAAC,KAAK,SAAS;AACjB;AAAA,IACF;AAEA,UAAM,4BAA4B,KAAK,OAAO;AAE9C,UAAM,WAAW,MAAM,aAAa,KAAK,OAAO;AAChD,UAAM,cAAc,+BAA+B;AAAA,MACjD,SAAS,SAAS;AAAA,MAClB;AAAA,IACF,CAAC;AAED,QAAI,YAAY,WAAW,SAAS,QAAQ,QAAQ;AAClD,YAAM,YAAY,YAAY,MAAM,CAAC,OAAO,UAAU,MAAM,OAAO,SAAS,QAAQ,KAAK,GAAG,EAAE;AAE9F,UAAI,WAAW;AACb;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAU,uBAAuB,SAAS,SAAS,WAAW;AAEpE,eAAW,SAAS,SAAS;AAC3B,YAAM,KAAK,iBAAiB,KAAK;AAAA,IACnC;AAEA,UAAM,cAAc,KAAK,SAAS;AAAA,MAChC,GAAG;AAAA,MACH,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,mBAAmB,OAKf;AAChB,UAAM,WAAW,MAAM,aAAa,KAAK,OAAO;AAChD,UAAM,UAAU,iCAAiC,SAAS,SAAS,KAAK;AAExE,QAAI,QAAQ,WAAW,GAAG;AACxB;AAAA,IACF;AAEA,eAAW,SAAS,SAAS;AAC3B,YAAM,KAAK,iBAAiB,KAAK;AAAA,IACnC;AAEA,UAAM,aAAa,IAAI,IAAI,QAAQ,IAAI,CAAC,UAAU,MAAM,EAAE,CAAC;AAE3D,UAAM,cAAc,KAAK,SAAS;AAAA,MAChC,GAAG;AAAA,MACH,SAAS,SAAS,QAAQ,OAAO,CAAC,UAAU,CAAC,WAAW,IAAI,MAAM,EAAE,CAAC;AAAA,IACvE,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,iBAAiB,OAA6C;AAC1E,UAAM,eAAe,kBAAAA,QAAK,KAAK,KAAK,SAAS,MAAM,YAAY;AAE/D,QAAI;AACF,gBAAM,qBAAG,cAAc,EAAE,OAAO,KAAK,CAAC;AAAA,IACxC,QAAQ;AAAA,IAER;AAEA,QAAI;AACF,gBAAM,qBAAG,kBAAAA,QAAK,QAAQ,YAAY,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,IACvE,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,sBAAsB,OAA8B,UAAmD;AAC7G,WAAO;AAAA,MACL,IAAI,MAAM;AAAA,MACV,OAAO,MAAM;AAAA,MACb,cAAc,MAAM;AAAA,MACpB,QAAQ,MAAM;AAAA,MACd,UAAU,MAAM;AAAA,MAChB,UAAU,MAAM;AAAA,MAChB,YAAY,MAAM;AAAA,MAClB,cAAc,MAAM;AAAA,MACpB,MAAM,SAAS;AAAA,MACf,WAAW,MAAM;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,MAAc,0BACZ,UACqE;AACrE,UAAM,WAAW,MAAM,aAAa,KAAK,OAAO;AAChD,UAAM,gBAAgB,4BAA4B,SAAS,SAAS,QAAQ;AAE5E,QAAI,eAAe;AACjB,YAAMC,gBAAe,kBAAAD,QAAK,KAAK,KAAK,SAAS,cAAc,YAAY;AAEvE,UAAI;AACF,kBAAM,uBAAKC,aAAY;AACvB,eAAO,EAAE,cAAc,cAAc,cAAc,cAAAA,cAAa;AAAA,MAClE,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,aAAa;AAAA,MACjB,2BAA2B,QAAQ;AAAA,MACnC,yBAAyB,QAAQ;AAAA,IACnC;AAEA,eAAW,gBAAgB,YAAY;AACrC,YAAMA,gBAAe,kBAAAD,QAAK,KAAK,KAAK,SAAS,YAAY;AAEzD,UAAI;AACF,kBAAM,uBAAKC,aAAY;AACvB,eAAO,EAAE,cAAc,cAAAA,cAAa;AAAA,MACtC,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,QAAI,CAAC,eAAe;AAClB,aAAO;AAAA,IACT;AAEA,UAAM,eAAe,kBAAAD,QAAK,KAAK,KAAK,SAAS,cAAc,YAAY;AAEvE,QAAI;AACF,gBAAM,uBAAK,YAAY;AACvB,aAAO,EAAE,cAAc,cAAc,cAAc,aAAa;AAAA,IAClE,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,qBAAkD;AACtD,QAAI,CAAC,KAAK,SAAS;AACjB,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,MAAM,KAAK,sBAAsB;AAE9C,QAAI,CAAC,KAAK,UAAU,CAAC,KAAK,UAAU;AAClC,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,mBAAmB,KAAK,QAAQ;AAAA,EAC9C;AAAA;AAAA,EAGA,MAAM,wBAAsD;AAC1D,QAAI,CAAC,KAAK,SAAS;AACjB,aAAO,EAAE,QAAQ,MAAM;AAAA,IACzB;AAEA,UAAM,4BAA4B,KAAK,OAAO;AAE9C,UAAME,WAAU,MAAM,KAAK,kBAAkB;AAC7C,UAAM,SAASA,SAAQ,CAAC;AAExB,QAAI,CAAC,QAAQ,UAAU;AACrB,aAAO,EAAE,QAAQ,MAAM;AAAA,IACzB;AAEA,WAAO,KAAK,sBAAsB,OAAO,QAAQ;AAAA,EACnD;AAAA,EAEA,MAAM,gBAAkD;AACtD,QAAI,CAAC,KAAK,SAAS;AACjB,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,yBAAyB,KAAK,OAAO;AAC3C,UAAM,KAAK,uBAAuB;AAElC,UAAM,WAAW,MAAM,aAAa,KAAK,OAAO;AAChD,UAAM,SAAS,oBAAI,IAAmC;AAEtD,eAAW,SAAS,SAAS,SAAS;AACpC,UAAI,MAAM,WAAW,YAAY,MAAM,GAAG,WAAW,SAAS,GAAG;AAC/D;AAAA,MACF;AAEA,YAAM,eAAe,kBAAAF,QAAK,KAAK,KAAK,SAAS,MAAM,YAAY;AAE/D,UAAI;AACF,cAAM,WAAW,UAAM,uBAAK,YAAY;AAExC,eAAO,IAAI,MAAM,IAAI,KAAK,sBAAsB,OAAO,QAAQ,CAAC;AAAA,MAClE,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,WAAO,CAAC,GAAG,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM,UAAU,MAAM,YAAY,KAAK,SAAS;AAAA,EACpF;AAAA,EAEA,MAAM,2BAA2B,cAAmD;AAClF,QAAI,CAAC,KAAK,SAAS;AACjB,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,aAAa,QAAQ,OAAO,GAAG;AAClD,UAAM,eAAe,kBAAAA,QAAK,QAAQ,KAAK,SAAS,UAAU;AAC1D,UAAM,kBAAkB,kBAAAA,QAAK,QAAQ,KAAK,OAAO;AAEjD,QAAI,CAAC,aAAa,WAAW,eAAe,GAAG;AAC7C,aAAO;AAAA,IACT;AAEA,QAAI,CAAC,WAAW,YAAY,EAAE,SAAS,KAAK,GAAG;AAC7C,aAAO;AAAA,IACT;AAEA,QAAI;AACF,aAAO,UAAM,2BAAS,YAAY;AAAA,IACpC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,uBAAuB,UAA0B;AAC/C,WAAO,oBAAoB,QAAQ;AAAA,EACrC;AACF;;;AIjcO,IAAM,gBAAN,MAAoB;AAAA,EACR,YAAY,oBAAI,IAA4B;AAAA,EAE7D,IACE,UACA,OACA,UACgB;AAChB,UAAM,SAAyB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA,MAAM,SAAS;AAAA,MACf,UAAU,SAAS;AAAA,MACnB,cAAc,SAAS;AAAA,MACvB,YAAY,KAAK,IAAI;AAAA,IACvB;AAEA,SAAK,UAAU,IAAI,UAAU,MAAM;AACnC,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,UAA8C;AAChD,WAAO,KAAK,UAAU,IAAI,QAAQ;AAAA,EACpC;AAAA,EAEA,SAAS,UAAsC;AAC7C,WAAO,KAAK,UAAU,IAAI,QAAQ,GAAG;AAAA,EACvC;AACF;;;ACZO,IAAM,mBAAN,MAAuB;AAAA,EAC5B,YACmB,mBACA,QACA,UACjB;AAHiB;AACA;AACA;AAAA,EAChB;AAAA,EAHgB;AAAA,EACA;AAAA,EACA;AAAA,EAGnB,8BACE,eACA,SACM;AACN,UAAM,UAAU,KAAK,kBAAkB,YAAY,aAAa;AAEhE,QAAI,CAAC,WAAW,QAAQ,SAAS,aAAa,SAAS;AACrD;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,kBAAkB,cAAc,QAAQ,QAAQ;AAEpE,QAAI,CAAC,QAAQ;AACX,WAAK,eAAe,QAAQ,cAAc;AAAA,QACxC,eAAe,QAAQ;AAAA,QACvB,MAAM;AAAA,QACN,SAAS,UAAU,QAAQ,QAAQ;AAAA,MACrC,CAAC;AACD;AAAA,IACF;AAEA,QAAI,KAAK,SAAS,mBAAmB,QAAQ,QAAQ,GAAG;AACtD,WAAK,eAAe,QAAQ,cAAc;AAAA,QACxC,eAAe,QAAQ;AAAA,QACvB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,SAAK,SAAS,OAAO;AAAA,MACnB,eAAe,QAAQ;AAAA,MACvB,UAAU,QAAQ;AAAA,MAClB,qBAAqB,QAAQ;AAAA,IAC/B,CAAC;AAED,WAAO,YAAY,QAAQ,eAAe,QAAQ,QAAQ;AAE1D,SAAK,OAAO;AAAA,MACV,QAAQ;AAAA,MACR,cAAuC;AAAA,QACrC,MAAM,YAAY;AAAA,QAClB,eAAe,QAAQ;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,+BACE,eACA,SACM;AACN,UAAM,UAAU,KAAK,kBAAkB,YAAY,aAAa;AAChE,UAAM,UAAU,KAAK,SAAS,IAAI,QAAQ,aAAa;AAEvD,QAAI,CAAC,WAAW,QAAQ,SAAS,aAAa,WAAW,CAAC,SAAS;AACjE;AAAA,IACF;AAEA,QAAI,QAAQ,wBAAwB,QAAQ,cAAc;AACxD;AAAA,IACF;AAEA,QAAI,QAAQ,UAAU,QAAQ;AAC5B,WAAK,eAAe,QAAQ,cAAc;AAAA,QACxC,eAAe,QAAQ;AAAA,QACvB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,SAAK,SAAS,SAAS,QAAQ,eAAe,YAAY;AAE1D,SAAK,OAAO;AAAA,MACV,QAAQ;AAAA,MACR,cAAwC;AAAA,QACtC,MAAM,YAAY;AAAA,QAClB,eAAe,QAAQ;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,iCACE,eACA,SACM;AACN,UAAM,UAAU,KAAK,kBAAkB,YAAY,aAAa;AAChE,UAAM,UAAU,KAAK,SAAS,IAAI,QAAQ,aAAa;AAEvD,QAAI,CAAC,WAAW,QAAQ,SAAS,aAAa,WAAW,CAAC,SAAS;AACjE;AAAA,IACF;AAEA,QAAI,QAAQ,wBAAwB,QAAQ,cAAc;AACxD;AAAA,IACF;AAEA,QAAI,QAAQ,UAAU,UAAU,QAAQ,UAAU,cAAc;AAC9D,WAAK,eAAe,QAAQ,cAAc;AAAA,QACxC,eAAe,QAAQ;AAAA,QACvB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,SAAK,SAAS,SAAS,QAAQ,eAAe,cAAc;AAE5D,SAAK,OAAO;AAAA,MACV,QAAQ;AAAA,MACR,cAA0C;AAAA,QACxC,MAAM,YAAY;AAAA,QAClB,eAAe,QAAQ;AAAA,MACzB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,mBAAmB,eAA0B,SAAoC;AAC/E,UAAM,UAAU,KAAK,kBAAkB,YAAY,aAAa;AAChE,UAAM,UAAU,KAAK,SAAS,IAAI,QAAQ,aAAa;AAEvD,QAAI,CAAC,WAAW,QAAQ,SAAS,aAAa,WAAW,CAAC,SAAS;AACjE;AAAA,IACF;AAEA,QAAI,QAAQ,wBAAwB,QAAQ,cAAc;AACxD;AAAA,IACF;AAEA,QAAI,QAAQ,UAAU,QAAQ;AAC5B,WAAK,eAAe,QAAQ,cAAc;AAAA,QACxC,eAAe,QAAQ;AAAA,QACvB,SAAS,QAAQ;AAAA,QACjB,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,kBAAkB,cAAc,QAAQ,QAAQ;AAEpE,QAAI,CAAC,QAAQ;AACX,WAAK,eAAe,QAAQ,cAAc;AAAA,QACxC,eAAe,QAAQ;AAAA,QACvB,SAAS,QAAQ;AAAA,QACjB,MAAM;AAAA,QACN,SAAS,UAAU,QAAQ,QAAQ;AAAA,MACrC,CAAC;AACD;AAAA,IACF;AAEA,SAAK,SAAS,uBAAuB,QAAQ,aAAa;AAE1D,SAAK,OAAO;AAAA,MACV,QAAQ;AAAA,MACR,cAAmC;AAAA,QACjC,MAAM,YAAY;AAAA,QAClB,SAAS,QAAQ;AAAA,QACjB,eAAe,QAAQ;AAAA,QACvB,WAAW,QAAQ;AAAA,MACrB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,qBAAqB,SAAsC;AACzD,UAAM,UAAU,KAAK,SAAS,IAAI,QAAQ,aAAa;AAEvD,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AAEA,QAAI,CAAC,QAAQ,IAAI;AACf,WAAK,SAAS,SAAS,QAAQ,eAAe,QAAQ;AACtD,WAAK,eAAe,QAAQ,qBAAqB;AAAA,QAC/C,eAAe,QAAQ;AAAA,QACvB,MAAM,QAAQ,WAAW,UAAU,kBAAkB;AAAA,QACrD,SAAS,QAAQ,WAAW,eAAe,QAAQ,MAAM;AAAA,MAC3D,CAAC;AACD,WAAK,SAAS,OAAO,QAAQ,aAAa;AAC1C;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,SAAS;AAC9B,WAAK,sBAAsB,QAAQ,qBAAqB;AAAA,QACtD,eAAe,QAAQ;AAAA,QACvB,UAAU,QAAQ;AAAA,QAClB,OAAO;AAAA,MACT,CAAC;AACD;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,UAAU;AAC/B,WAAK,sBAAsB,QAAQ,qBAAqB;AAAA,QACtD,eAAe,QAAQ;AAAA,QACvB,UAAU,QAAQ;AAAA,QAClB,OAAO;AAAA,MACT,CAAC;AACD,WAAK,SAAS,OAAO,QAAQ,aAAa;AAC1C;AAAA,IACF;AAEA,SAAK,sBAAsB,QAAQ,qBAAqB;AAAA,MACtD,eAAe,QAAQ;AAAA,MACvB,UAAU,QAAQ;AAAA,MAClB,OAAO;AAAA,MACP,SAAS,QAAQ;AAAA,IACnB,CAAC;AACD,SAAK,SAAS,OAAO,QAAQ,aAAa;AAAA,EAC5C;AAAA,EAEA,eAAe,SAAgC;AAC7C,UAAM,UAAU,KAAK,SAAS,IAAI,QAAQ,aAAa;AAEvD,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AAEA,SAAK,SAAS,uBAAuB,QAAQ,aAAa;AAE1D,QAAI,CAAC,QAAQ,IAAI;AACf,WAAK,eAAe,QAAQ,qBAAqB;AAAA,QAC/C,eAAe,QAAQ;AAAA,QACvB,SAAS,QAAQ;AAAA,QACjB,MAAM;AAAA,QACN,SAAS,QAAQ,WAAW;AAAA,MAC9B,CAAC;AACD;AAAA,IACF;AAEA,SAAK,OAAO;AAAA,MACV,QAAQ;AAAA,MACR,cAAkC;AAAA,QAChC,MAAM,YAAY;AAAA,QAClB,SAAS,QAAQ;AAAA,QACjB,eAAe,QAAQ;AAAA,QACvB,cAAc,QAAQ,gBAAgB;AAAA,MACxC,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,gBAAsB;AACpB,eAAW,WAAW,KAAK,SAAS,WAAW,GAAG;AAChD,WAAK,gBAAgB,SAAS,WAAW,6BAA6B;AAAA,IACxE;AAAA,EACF;AAAA,EAEA,oCAAoC,qBAAmC;AACrE,eAAW,WAAW,KAAK,SAAS,yBAAyB,mBAAmB,GAAG;AACjF,WAAK,gBAAgB,SAAS,kBAAkB,sBAAsB;AAAA,IACxE;AAAA,EACF;AAAA,EAEA,0BAA0B,UAAwB;AAChD,eAAW,WAAW,KAAK,SAAS,cAAc,QAAQ,GAAG;AAC3D,WAAK,gBAAgB,SAAS,kBAAkB,qBAAqB;AAAA,IACvE;AAAA,EACF;AAAA,EAEQ,gBACN,SACA,MACA,SACM;AACN,WAAO,WAAW,QAAQ,eAAe,MAAM,OAAO;AAEtD,SAAK,eAAe,QAAQ,qBAAqB;AAAA,MAC/C,eAAe,QAAQ;AAAA,MACvB;AAAA,MACA;AAAA,IACF,CAAC;AAED,SAAK,OAAO;AAAA,MACV,QAAQ;AAAA,MACR,cAA0C;AAAA,QACxC,MAAM,YAAY;AAAA,QAClB,eAAe,QAAQ;AAAA,MACzB,CAAC;AAAA,IACH;AAEA,SAAK,SAAS,OAAO,QAAQ,aAAa;AAAA,EAC5C;AAAA,EAEQ,sBACN,qBACA,SACM;AACN,SAAK,OAAO;AAAA,MACV;AAAA,MACA,cAAwC;AAAA,QACtC,MAAM,YAAY;AAAA,QAClB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,eACN,qBACA,SAMM;AACN,SAAK,OAAO;AAAA,MACV;AAAA,MACA,cAAiC;AAAA,QAC/B,MAAM,YAAY;AAAA,QAClB,GAAG;AAAA,MACL,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AC5UO,IAAM,sBAAN,MAA0B;AAAA,EACd,WAAW,oBAAI,IAA0B;AAAA,EACzC,iBAAiB,oBAAI,IAAoB;AAAA,EAE1D,OAAO,OAIU;AACf,UAAM,UAAwB;AAAA,MAC5B,eAAe,MAAM;AAAA,MACrB,UAAU,MAAM;AAAA,MAChB,qBAAqB,MAAM;AAAA,MAC3B,OAAO;AAAA,MACP,eAAe;AAAA,MACf,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,SAAK,SAAS,IAAI,MAAM,eAAe,OAAO;AAC9C,SAAK,eAAe,IAAI,MAAM,UAAU,MAAM,aAAa;AAC3D,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,eAAiD;AACnD,WAAO,KAAK,SAAS,IAAI,aAAa;AAAA,EACxC;AAAA,EAEA,mBAAmB,UAA4C;AAC7D,UAAM,gBAAgB,KAAK,eAAe,IAAI,QAAQ;AAEtD,QAAI,CAAC,eAAe;AAClB,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,SAAS,IAAI,aAAa;AAAA,EACxC;AAAA,EAEA,SAAS,eAAuB,OAAyD;AACvF,UAAM,UAAU,KAAK,SAAS,IAAI,aAAa;AAE/C,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AAEA,YAAQ,QAAQ;AAChB,WAAO;AAAA,EACT;AAAA,EAEA,uBAAuB,eAAiD;AACtE,UAAM,UAAU,KAAK,SAAS,IAAI,aAAa;AAE/C,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AAEA,YAAQ,iBAAiB;AACzB,WAAO;AAAA,EACT;AAAA,EAEA,uBAAuB,eAAiD;AACtE,UAAM,UAAU,KAAK,SAAS,IAAI,aAAa;AAE/C,QAAI,CAAC,SAAS;AACZ,aAAO;AAAA,IACT;AAEA,YAAQ,gBAAgB,KAAK,IAAI,GAAG,QAAQ,gBAAgB,CAAC;AAC7D,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,eAA6B;AAClC,UAAM,UAAU,KAAK,SAAS,IAAI,aAAa;AAE/C,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AAEA,QAAI,KAAK,eAAe,IAAI,QAAQ,QAAQ,MAAM,eAAe;AAC/D,WAAK,eAAe,OAAO,QAAQ,QAAQ;AAAA,IAC7C;AAEA,SAAK,SAAS,OAAO,aAAa;AAAA,EACpC;AAAA,EAEA,WAAW,MAAM,KAAK,IAAI,GAAmB;AAC3C,WAAO,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY;AACrD,UAAI,QAAQ,UAAU,UAAU,QAAQ,UAAU,UAAU;AAC1D,eAAO;AAAA,MACT;AAEA,aAAO,MAAM,QAAQ,aAAa;AAAA,IACpC,CAAC;AAAA,EACH;AAAA,EAEA,yBAAyB,qBAA6C;AACpE,WAAO,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC,EAAE;AAAA,MACjC,CAAC,YAAY,QAAQ,wBAAwB;AAAA,IAC/C;AAAA,EACF;AAAA,EAEA,cAAc,UAAkC;AAC9C,WAAO,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,QAAQ,aAAa,QAAQ;AAAA,EACtF;AACF;;;ApBtDA,eAAsB,qBACpB,UAAiC,CAAC,GACT;AACzB,QAAM,OAAO,QAAQ,QAAQ;AAC7B,QAAM,OAAO,QAAQ,QAAQ;AAE7B,QAAM,UAAM,gBAAAG,SAAQ;AACpB,QAAM,oBAAoB,IAAI,kBAAkB;AAChD,QAAM,iBAAiB,IAAI,eAAe,iBAAiB;AAC3D,QAAM,SAAS,IAAI,cAAc,mBAAmB,cAAc;AAClE,QAAM,YAAY,IAAI,UAAU,mBAAmB,MAAM;AACzD,QAAM,gBAAgB,IAAI,cAAc;AACxC,QAAM,oBAAoB,IAAI,kBAAkB;AAAA,IAC9C,SAAS,QAAQ;AAAA,IACjB,SAAS,QAAQ;AAAA,EACnB,CAAC;AACD,QAAM,sBAAsB,IAAI,oBAAoB;AACpD,QAAM,gBAAgB,IAAI,oBAAoB;AAE9C,QAAM,qBAAqB,IAAI;AAAA,IAC7B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,mBAAmB,IAAI,iBAAiB,mBAAmB,QAAQ,aAAa;AAEtF,MAAI,IAAI,qBAAqB,CAAC;AAE9B,MAAI,IAAI,WAAW,CAAC,UAAU,aAAa;AACzC,aAAS,KAAK,EAAE,IAAI,MAAM,GAAG,eAAe,SAAS,EAAE,CAAC;AAAA,EAC1D,CAAC;AAED,MAAI;AAAA,IACF,GAAG,wBAAwB;AAAA,IAC3B,gBAAAA,QAAQ,IAAI,EAAE,MAAM,4BAA4B,OAAO,mBAAmB,CAAC;AAAA,IAC3E,OAAO,SAAS,aAAa;AAC3B,YAAM,WAAW,mBAAmB,QAAQ,OAAO,QAAQ;AAC3D,YAAM,OAAO,QAAQ;AAErB,UAAI,CAAC,OAAO,SAAS,IAAI,KAAK,KAAK,WAAW,GAAG;AAC/C,iBAAS,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,OAAO,OAAO,sBAAsB,CAAC;AACrE;AAAA,MACF;AAEA,YAAM,aAAa,QAAQ,OAAO,oBAAoB;AACtD,YAAM,aAAa,QAAQ,OAAO,oBAAoB;AACtD,YAAM,aAAa,QAAQ,OAAO,oBAAoB;AAEtD,YAAM,SAAS,MAAM,mBAAmB,qBAAqB,UAAU,MAAM;AAAA,QAC3E,MAAM,OAAO,eAAe,WAAW,aAAa;AAAA,QACpD,UAAU,OAAO,eAAe,WAAW,aAAa;AAAA,QACxD,cAAc,OAAO,eAAe,WAAW,aAAa;AAAA,MAC9D,CAAC;AAED,UAAI,CAAC,OAAO,IAAI;AACd,iBAAS,OAAO,OAAO,SAAS,uBAAuB,MAAM,GAAG,EAAE,KAAK;AAAA,UACrE,IAAI;AAAA,UACJ,OAAO,OAAO;AAAA,QAChB,CAAC;AACD;AAAA,MACF;AAEA,eAAS,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,MAAM,UAAU,MAAM,KAAK,WAAW,CAAC;AAAA,IACzE;AAAA,EACF;AAEA,MAAI,IAAI,GAAG,wBAAwB,uBAAuB,OAAO,SAAS,aAAa;AACrF,UAAM,WAAW,mBAAmB,QAAQ,OAAO,QAAQ;AAC3D,UAAM,WAAW,MAAM,mBAAmB,iBAAiB,QAAQ;AAEnE,QAAI,CAAC,UAAU;AACb,eAAS,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,OAAO,OAAO,qBAAqB,CAAC;AACpE;AAAA,IACF;AAEA,aACG,OAAO,GAAG,EACV,IAAI,gBAAgB,0BAA0B,EAC9C,KAAK,QAAQ;AAAA,EAClB,CAAC;AAED,MAAI,IAAI,gCAAgC,OAAO,UAAU,aAAa;AACpE,UAAM,OAAO,MAAM,kBAAkB,sBAAsB;AAC3D,aAAS,KAAK,IAAI;AAAA,EACpB,CAAC;AAED,MAAI,IAAI,4BAA4B,OAAO,UAAU,aAAa;AAChE,UAAM,YAAY,MAAM,kBAAkB,cAAc;AACxD,aAAS,KAAK,EAAE,UAAU,CAAC;AAAA,EAC7B,CAAC;AAED,MAAI,IAAI,iCAAiC,OAAO,UAAU,aAAa;AACrE,UAAM,UAAU,MAAM,kBAAkB,kBAAkB;AAC1D,aAAS,KAAK,EAAE,QAAQ,CAAC;AAAA,EAC3B,CAAC;AAED,MAAI,IAAI,GAAG,+BAA+B,4BAA4B,OAAO,SAAS,aAAa;AACjG,UAAM,WAAW,mBAAmB,QAAQ,OAAO,QAAQ;AAC3D,UAAM,OAAO,MAAM,kBAAkB,sBAAsB,QAAQ;AACnE,aAAS,KAAK,IAAI;AAAA,EACpB,CAAC;AAED,MAAI,IAAI,GAAG,+BAA+B,uBAAuB,OAAO,SAAS,aAAa;AAC5F,UAAM,WAAW,mBAAmB,QAAQ,OAAO,QAAQ;AAC3D,UAAM,OAAO,MAAM,kBAAkB,sBAAsB,QAAQ;AAEnE,QAAI,CAAC,KAAK,QAAQ;AAChB,eAAS,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,OAAO,OAAO,6BAA6B,SAAS,CAAC;AACrF;AAAA,IACF;AAEA,UAAM,QAAQ,MAAM,kBAAkB,mBAAmB,QAAQ;AAEjE,QAAI,CAAC,OAAO;AACV,eAAS,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,OAAO,OAAO,6BAA6B,SAAS,CAAC;AACrF;AAAA,IACF;AAEA,aACG,OAAO,GAAG,EACV,IAAI,gBAAgB,KAAK,YAAY,yBAAyB,EAC9D,KAAK,KAAK;AAAA,EACf,CAAC;AAED,MAAI,IAAI,2BAA2B,OAAO,UAAU,aAAa;AAC/D,UAAM,OAAO,MAAM,kBAAkB,sBAAsB;AAE3D,QAAI,CAAC,KAAK,QAAQ;AAChB,eAAS,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,OAAO,OAAO,6BAA6B,CAAC;AAC5E;AAAA,IACF;AAEA,UAAM,QAAQ,MAAM,kBAAkB,mBAAmB;AAEzD,QAAI,CAAC,OAAO;AACV,eAAS,OAAO,GAAG,EAAE,KAAK,EAAE,IAAI,OAAO,OAAO,6BAA6B,CAAC;AAC5E;AAAA,IACF;AAEA,aACG,OAAO,GAAG,EACV,IAAI,gBAAgB,KAAK,YAAY,yBAAyB,EAC9D,KAAK,KAAK;AAAA,EACf,CAAC;AAED,MAAI,QAAQ,aAAa;AACvB,gBAAY,KAAK,QAAQ,WAAW;AAAA,EACtC;AAEA,QAAM,iBAAa,+BAAa,GAAG;AACnC;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,EAAE,kBAAkB;AAAA,EACtB;AAEA,QAAM,yBAAyB,YAAY,MAAM;AAC/C,uBAAmB,cAAc;AACjC,qBAAiB,cAAc;AAAA,EACjC,GAAG,GAAK;AAER,MAAI,kBAAkB,UAAU,GAAG;AACjC,UAAM,kBAAkB,kBAAkB;AAAA,EAC5C;AAEA,QAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,eAAW,KAAK,SAAS,MAAM;AAC/B,eAAW,OAAO,MAAM,MAAM,MAAM,QAAQ,CAAC;AAAA,EAC/C,CAAC;AAED,QAAM,cAAc,SAAS,YAAY,cAAc;AACvD,QAAM,UAAU,qBAAqB,aAAa,IAAI;AACtD,QAAM,QAAQ,mBAAmB,aAAa,IAAI;AAClD,QAAM,eAAe,QAAQ,QAAQ,WAAW;AAEhD,SAAO,cAAc,SAAS,OAAO,YAAY;AAEjD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,OAAO,MACL,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC/B,oBAAc,sBAAsB;AACpC,gBAAU,KAAK;AACf,iBAAW,MAAM,CAAC,UAAU;AAC1B,YAAI,OAAO;AACT,iBAAO,KAAK;AACZ;AAAA,QACF;AAEA,gBAAQ;AAAA,MACV,CAAC;AAAA,IACH,CAAC;AAAA,EACL;AACF;;;AqBpRA,IAAAC,kBAA2B;AAC3B,IAAAC,oBAAiB;AAEjB,SAAS,yBAAyB,UAA4B;AAC5D,QAAM,aAAuB,CAAC;AAC9B,QAAM,UAAU,QAAQ,IAAI,4BAA4B,KAAK;AAE7D,MAAI,SAAS;AACX,eAAW,KAAK,kBAAAC,QAAK,QAAQ,OAAO,CAAC;AAAA,EACvC;AAEA,MAAI,UAAU,kBAAAA,QAAK,QAAQ,QAAQ;AAEnC,WAAS,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG;AACzC,eAAW,KAAK,kBAAAA,QAAK,KAAK,SAAS,QAAQ,KAAK,CAAC;AACjD,eAAW,KAAK,kBAAAA,QAAK,KAAK,SAAS,KAAK,CAAC;AAEzC,UAAM,SAAS,kBAAAA,QAAK,QAAQ,OAAO;AAEnC,QAAI,WAAW,SAAS;AACtB;AAAA,IACF;AAEA,cAAU;AAAA,EACZ;AAEA,SAAO;AACT;AAEO,SAAS,mBAAmB,UAAsC;AACvE,QAAM,OAAO,oBAAI,IAAY;AAE7B,aAAW,aAAa,yBAAyB,QAAQ,GAAG;AAC1D,UAAM,aAAa,kBAAAA,QAAK,QAAQ,SAAS;AAEzC,QAAI,KAAK,IAAI,UAAU,GAAG;AACxB;AAAA,IACF;AAEA,SAAK,IAAI,UAAU;AAEnB,YAAI,4BAAW,kBAAAA,QAAK,KAAK,YAAY,YAAY,CAAC,GAAG;AACnD,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;;;AC/CA,gCAAqB;AAEd,SAAS,YAAY,KAAmB;AAC7C,MAAI,QAAQ,IAAI,8BAA8B,KAAK;AACjD;AAAA,EACF;AAEA,QAAM,WAAW,QAAQ;AACzB,QAAM,UACJ,aAAa,UACT,aAAa,GAAG,MAChB,aAAa,WACX,SAAS,GAAG,MACZ,aAAa,GAAG;AAExB,sCAAK,SAAS,CAAC,UAAU;AACvB,QAAI,OAAO;AACT,cAAQ,KAAK,6DAA6D,MAAM,OAAO,EAAE;AAAA,IAC3F;AAAA,EACF,CAAC;AACH;;;AvBfA,SAAS,qBAA6B;AACpC,QAAM,aAAa,QAAQ,KAAK,CAAC;AAEjC,MAAI,YAAY;AACd,WAAO,kBAAAC,QAAK,QAAQ,kBAAAA,QAAK,QAAQ,UAAU,CAAC;AAAA,EAC9C;AAEA,SAAO,QAAQ,IAAI;AACrB;AAEA,eAAe,OAAsB;AACnC,QAAM,OAAO,OAAO,QAAQ,IAAI,0BAA0B,QAAQ,IAAI,QAAQ,IAAI;AAClF,QAAM,OAAO,QAAQ,IAAI,0BAA0B;AACnD,QAAM,cAAc,mBAAmB,mBAAmB,CAAC;AAE3D,QAAM,SAAS,MAAM,qBAAqB;AAAA,IACxC;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,MAAI,OAAO,KAAK,cAAc;AAC5B,gBAAY,OAAO,KAAK,OAAO;AAAA,EACjC,OAAO;AACL,YAAQ;AAAA,MACN;AAAA,IACF;AAAA,EACF;AACF;AAEA,KAAK,EAAE,MAAM,CAAC,UAAmB;AAC/B,UAAQ,MAAM,+CAA+C,KAAK;AAClE,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["import_node_path","import_express","path","express","import_promises","import_node_path","import_node_path","path","path","import_promises","import_node_path","path","path","absolutePath","exports","express","import_node_fs","import_node_path","path","path"]}