{"version":3,"file":"index.mjs","names":["digest","parseIpv4","integer","parsePublicOrigin","performance","execFile","regularFile","createHttpsServer","createHttpServer","requestHttp","request","FRP_VERSION","MAX_ARCHIVE_ENTRIES","MAX_ARCHIVE_LIST_BYTES","releases","inside","regularFile","sha256","runCapture","validatedArchiveEntry","defaultExtractArtifact","defaultFetchArtifact","performance","releases","DOWNLOAD_PAGE","TERMS_URL","inside","sha256","regularFile","defaultFetchArtifact","defaultExtractArtifact","MAX_SETTINGS_BYTES","hostname","connectTls","execFile","START_TIMEOUT_MS","publicStatus","httpsRequest","RESERVED_LAN_GATEWAY_PORT","MAX_LOG_BUFFER_BYTES","START_TIMEOUT_MS","publicStatus","reserveLoopbackPort","withoutProxyEnvironment","MAX_CONFIG_BYTES","hostname","execFile","proxyRequest","tlsConnect","publicStatus","finished","execFile"],"sources":["../src/access.ts","../src/ip.ts","../src/network.ts","../src/websocket-paths.ts","../src/extension-worker-config.ts","../src/config.ts","../src/exec-file.ts","../src/private-file.ts","../src/client-module-preferences.ts","../src/control.ts","../src/client-module-recovery.ts","../src/local-admin-host.ts","../src/http-security.ts","../src/mobile-compat-bootstrap.ts","../src/http-cache.ts","../src/browser-auth-cookies.ts","../src/websocket-compression.ts","../src/version.ts","../src/computer-images.ts","../src/extension-worker-protocol.ts","../src/extension-worker.ts","../src/extensions.ts","../src/auth-pages.ts","../src/gateway.ts","../src/storage.ts","../src/managed-files.ts","../src/component-download.ts","../src/frp-component.ts","../src/windows-msi-extract.ts","../src/cpolar-component.ts","../src/frp-template.ts","../src/frp-config.ts","../src/frp-attach.ts","../src/frp-attach-plan.ts","../src/cert-renewal.ts","../src/managed-setup.ts","../src/frp-ingress.ts","../src/remote.ts","../src/frp.ts","../src/origin-proxy-config.ts","../src/origin-proxy.ts","../src/cloudflared-component.ts","../src/cloudflared.ts","../src/cloudflared-tunnel.ts","../src/task-events.ts","../src/diagnostics.ts","../src/mobile-guide.ts","../src/vps-deploy.ts","../src/funnel.ts","../src/cpolar.ts","../src/caddy-files.ts","../src/caddy-component.ts","../src/caddy-config.ts","../src/caddy.ts","../src/managed-origin.ts","../src/release-update.ts","../src/file-logger.ts","../src/installation-id.ts","../src/lan-setup.ts","../src/plugin.ts"],"sourcesContent":["import { createHash, randomBytes, timingSafeEqual } from 'node:crypto'\nimport type { DeviceSnapshot, DeviceStore, StoredDevice } from './storage.js'\n\n/** Stable error categories converted to deliberately terse HTTP responses. */\nexport class AccessError extends Error {\n  constructor(readonly status: number, readonly code: string) {\n    super(code)\n    this.name = 'AccessError'\n  }\n}\n\n/** Resource and lifetime controls for device authentication. */\nexport interface AccessControllerOptions {\n  readonly pairingTtlMs: number\n  readonly deviceTtlMs: number\n  readonly sessionTtlMs: number\n  readonly maxDevices: number\n  readonly maxSessions: number\n  readonly rateLimitWindowMs: number\n  readonly maxPairingAttempts: number\n  readonly maxRateLimitKeys: number\n  readonly now?: () => number\n}\n\n/** Values issued once after pairing; only digests survive the response. */\nexport interface PairingResult {\n  readonly deviceId: string\n  readonly deviceToken: string\n  readonly deviceExpiresAt: number\n  readonly sessionToken: string\n  readonly csrfToken: string\n  readonly sessionExpiresAt: number\n}\n\n/** Values issued after renewal with the persistent HttpOnly device Cookie. */\nexport interface RenewalResult {\n  readonly deviceId: string\n  readonly sessionToken: string\n  readonly csrfToken: string\n  readonly sessionExpiresAt: number\n}\n\n/** Authenticated Session identity retained only inside the gateway. */\nexport interface SessionAuthorization {\n  readonly sessionKey: string\n  readonly deviceId: string\n  readonly expiresAt: number\n}\n\n/** Result of a persistent-device reachability check without opening a Session. */\nexport interface DeviceProbeResult {\n  readonly deviceId: string\n  readonly deviceExpiresAt: number\n}\n\n/** Why a short-lived Session ended; only device revocation is sent to clients. */\nexport type SessionEndReason = 'logout' | 'expired' | 'evicted' | 'revoked'\n\n/** Safe device metadata returned by the loopback administration API. */\nexport interface DeviceSummary {\n  readonly id: string\n  readonly label: string\n  readonly createdAt: number\n  readonly expiresAt: number\n  readonly lastSeenAt: number\n  readonly revokedAt?: number\n}\n\ninterface PairingWindow {\n  readonly digest: Buffer\n  readonly expiresAt: number\n}\n\ninterface SessionRecord {\n  readonly key: string\n  readonly deviceId: string\n  readonly csrfDigest: Buffer\n  readonly createdAt: number\n  readonly expiresAt: number\n}\n\ninterface LimitBucket {\n  count: number\n  resetAt: number\n}\n\n/** Fixed-window limiter whose attacker-controlled key table is itself bounded. */\nexport class BoundedRateLimiter {\n  private readonly buckets = new Map<string, LimitBucket>()\n\n  constructor(\n    private readonly limit: number,\n    private readonly windowMs: number,\n    private readonly maximumKeys: number,\n  ) {}\n\n  /** Consume one attempt; unknown keys fail closed when the bounded table is full. */\n  take(key: string, now: number): boolean {\n    for (const [candidate, bucket] of this.buckets) {\n      if (bucket.resetAt <= now) this.buckets.delete(candidate)\n    }\n    const current = this.buckets.get(key)\n    if (current === undefined) {\n      if (this.buckets.size >= this.maximumKeys) return false\n      this.buckets.set(key, { count: 1, resetAt: now + this.windowMs })\n      return true\n    }\n    if (current.count >= this.limit) return false\n    current.count += 1\n    return true\n  }\n\n  /** Current table size, exposed for bounded-state assertions. */\n  get size(): number {\n    return this.buckets.size\n  }\n}\n\nfunction opaqueToken(): string {\n  return randomBytes(32).toString('base64url')\n}\n\nfunction digest(value: string): Buffer {\n  return createHash('sha256').update(value, 'utf8').digest()\n}\n\nfunction digestHex(value: string): string {\n  return digest(value).toString('hex')\n}\n\nfunction matchesDigest(value: string, expected: Buffer): boolean {\n  return timingSafeEqual(digest(value), expected)\n}\n\nfunction normalizeLabel(value: string | undefined): string {\n  const label = (value ?? 'Mobile device').normalize('NFC').trim()\n  if (label.length < 1 || label.length > 64 || /[\\u0000-\\u001f\\u007f]/u.test(label)) {\n    throw new AccessError(400, 'invalid_request')\n  }\n  return label\n}\n\nfunction publicDevice(device: StoredDevice): DeviceSummary {\n  return Object.freeze({\n    id: device.id,\n    label: device.label,\n    createdAt: device.createdAt,\n    expiresAt: device.expiresAt,\n    lastSeenAt: device.lastSeenAt,\n    ...(device.revokedAt === undefined ? {} : { revokedAt: device.revokedAt }),\n  })\n}\n\n/** Pairing, persistent-device, short-Session, revocation, and CSRF state machine. */\nexport class AccessController {\n  private readonly now: () => number\n  private readonly pairLimiter: BoundedRateLimiter\n  private devices: StoredDevice[] = []\n  private pairingWindow: PairingWindow | undefined\n  private readonly sessions = new Map<string, SessionRecord>()\n  private readonly sessionEndedListeners = new Set<(authorization: SessionAuthorization, reason: SessionEndReason) => void>()\n  private mutation: Promise<void> = Promise.resolve()\n  private initialized = false\n  private closing = false\n  private closeTask: Promise<void> | undefined\n\n  constructor(private readonly store: DeviceStore, private readonly options: AccessControllerOptions) {\n    this.now = options.now ?? Date.now\n    this.pairLimiter = new BoundedRateLimiter(\n      options.maxPairingAttempts,\n      options.rateLimitWindowMs,\n      options.maxRateLimitKeys,\n    )\n  }\n\n  /** Load and validate digest-only durable state before accepting traffic. */\n  async initialize(): Promise<void> {\n    if (this.initialized || this.closing) throw new Error('access controller cannot be initialized again')\n    const snapshot = await this.store.load()\n    // Older releases retained revoked identities. Remove those tombstones on upgrade.\n    const devices = snapshot.devices.filter(device => device.revokedAt === undefined)\n    if (devices.length > this.options.maxDevices) throw new Error('device state exceeds configured maxDevices')\n    if (devices.length !== snapshot.devices.length) await this.store.save(this.snapshot(devices))\n    this.devices = devices\n    this.initialized = true\n  }\n\n  private requireInitialized(): void {\n    if (!this.initialized || this.closing) throw new Error('access controller is not available')\n  }\n\n  private async exclusive<T>(operation: () => Promise<T>): Promise<T> {\n    const prior = this.mutation\n    let release!: () => void\n    this.mutation = new Promise<void>(resolve => { release = resolve })\n    await prior\n    try {\n      return await operation()\n    } finally {\n      release()\n    }\n  }\n\n  private snapshot(devices: readonly StoredDevice[]): DeviceSnapshot {\n    return Object.freeze({ version: 1, devices: Object.freeze([...devices]) })\n  }\n\n  private emitSessionEnded(session: SessionRecord, reason: SessionEndReason): void {\n    const authorization = Object.freeze({\n      sessionKey: session.key,\n      deviceId: session.deviceId,\n      expiresAt: session.expiresAt,\n    })\n    for (const listener of this.sessionEndedListeners) listener(authorization, reason)\n  }\n\n  private removeSession(key: string, reason: SessionEndReason): void {\n    const session = this.sessions.get(key)\n    if (session === undefined) return\n    this.sessions.delete(key)\n    this.emitSessionEnded(session, reason)\n  }\n\n  private pruneSessions(now: number): void {\n    for (const [key, session] of this.sessions) {\n      if (session.expiresAt <= now) this.removeSession(key, 'expired')\n    }\n  }\n\n  private createSession(deviceId: string, now: number, deviceExpiresAt: number): RenewalResult {\n    this.pruneSessions(now)\n    if (this.sessions.size >= this.options.maxSessions) {\n      const oldest = [...this.sessions.values()].sort((left, right) => left.createdAt - right.createdAt)[0]\n      if (oldest !== undefined) this.removeSession(oldest.key, 'evicted')\n    }\n    const sessionToken = opaqueToken()\n    const csrfToken = opaqueToken()\n    const key = digestHex(sessionToken)\n    const record: SessionRecord = Object.freeze({\n      key,\n      deviceId,\n      csrfDigest: digest(csrfToken),\n      createdAt: now,\n      expiresAt: Math.min(now + this.options.sessionTtlMs, deviceExpiresAt),\n    })\n    this.sessions.set(key, record)\n    return Object.freeze({ deviceId, sessionToken, csrfToken, sessionExpiresAt: record.expiresAt })\n  }\n\n  /** Open one short pairing window and return its one-time secret to a loopback caller only. */\n  async openPairing(requestedTtlMs?: number): Promise<{ token: string; expiresAt: number }> {\n    this.requireInitialized()\n    return this.exclusive(async () => {\n      const ttl = requestedTtlMs ?? this.options.pairingTtlMs\n      if (!Number.isSafeInteger(ttl) || ttl < 10_000 || ttl > this.options.pairingTtlMs) {\n        throw new AccessError(400, 'invalid_request')\n      }\n      const token = opaqueToken()\n      const expiresAt = this.now() + ttl\n      this.pairingWindow = Object.freeze({ digest: digest(token), expiresAt })\n      return Object.freeze({ token, expiresAt })\n    })\n  }\n\n  /** Consume the pairing window exactly once and persist only the device-token digest. */\n  async pair(sourceKey: string, token: string, label?: string): Promise<PairingResult> {\n    this.requireInitialized()\n    const now = this.now()\n    if (!this.pairLimiter.take(sourceKey, now)) throw new AccessError(429, 'rate_limited')\n    if (token.length > 512) throw new AccessError(401, 'authentication_failed')\n    return this.exclusive(async () => {\n      const window = this.pairingWindow\n      if (window === undefined || window.expiresAt <= now || !matchesDigest(token, window.digest)) {\n        if (window !== undefined && window.expiresAt <= now) this.pairingWindow = undefined\n        throw new AccessError(401, 'authentication_failed')\n      }\n      this.pairingWindow = undefined\n      const active = this.devices.filter(device => device.revokedAt === undefined && device.expiresAt > now)\n      if (active.length >= this.options.maxDevices) throw new AccessError(409, 'device_limit')\n\n      const deviceToken = opaqueToken()\n      const device: StoredDevice = Object.freeze({\n        id: randomBytes(16).toString('hex'),\n        label: normalizeLabel(label),\n        tokenDigest: digestHex(deviceToken),\n        createdAt: now,\n        expiresAt: now + this.options.deviceTtlMs,\n        lastSeenAt: now,\n      })\n      const retained = this.devices.filter(candidate => candidate.revokedAt === undefined && candidate.expiresAt > now)\n      const next = [...retained, device]\n      await this.store.save(this.snapshot(next))\n      this.devices = next\n      const session = this.createSession(device.id, now, device.expiresAt)\n      return Object.freeze({\n        ...session,\n        deviceToken,\n        deviceExpiresAt: device.expiresAt,\n      })\n    })\n  }\n\n  /** Exchange a valid persistent device credential for a new short Session. */\n  async renew(deviceToken: string): Promise<RenewalResult> {\n    this.requireInitialized()\n    return this.exclusive(async () => {\n      const now = this.now()\n      const device = this.requireDevice(deviceToken, now)\n      const index = this.devices.indexOf(device)\n      const updated: StoredDevice = Object.freeze({ ...device, lastSeenAt: now })\n      const next = [...this.devices]\n      next[index] = updated\n      await this.store.save(this.snapshot(next))\n      this.devices = next\n      return this.createSession(device.id, now, device.expiresAt)\n    })\n  }\n\n  /** Validate a persistent device credential without consuming a Session slot. */\n  async probe(deviceToken: string): Promise<DeviceProbeResult> {\n    this.requireInitialized()\n    return this.exclusive(async () => {\n      const now = this.now()\n      const device = this.requireDevice(deviceToken, now)\n      const index = this.devices.indexOf(device)\n      const updated: StoredDevice = Object.freeze({ ...device, lastSeenAt: now })\n      const next = [...this.devices]\n      next[index] = updated\n      await this.store.save(this.snapshot(next))\n      this.devices = next\n      return Object.freeze({ deviceId: device.id, deviceExpiresAt: device.expiresAt })\n    })\n  }\n\n  /** Validate a device credential without writing state or opening a Session. */\n  authorizeDevice(deviceToken: string): DeviceProbeResult {\n    this.requireInitialized()\n    const device = this.requireDevice(deviceToken, this.now())\n    return Object.freeze({ deviceId: device.id, deviceExpiresAt: device.expiresAt })\n  }\n\n  private requireDevice(deviceToken: string, now: number): StoredDevice {\n    if (deviceToken.length > 512) throw new AccessError(401, 'authentication_failed')\n    const tokenDigest = digest(deviceToken)\n    const device = this.devices.find(candidate => timingSafeEqual(Buffer.from(candidate.tokenDigest, 'hex'), tokenDigest))\n    if (device === undefined) throw new AccessError(401, 'authentication_failed')\n    if (device.revokedAt !== undefined) throw new AccessError(401, 'device_revoked')\n    if (device.expiresAt <= now) throw new AccessError(401, 'device_expired')\n    return device\n  }\n\n  /** Resolve a short Session Cookie without revealing whether device or Session failed. */\n  authorizeSession(sessionToken: string): SessionAuthorization {\n    this.requireInitialized()\n    if (sessionToken.length > 512) throw new AccessError(401, 'authentication_failed')\n    const now = this.now()\n    this.pruneSessions(now)\n    const key = digestHex(sessionToken)\n    const session = this.sessions.get(key)\n    const device = session === undefined ? undefined : this.devices.find(candidate => candidate.id === session.deviceId)\n    if (session === undefined || device === undefined || device.revokedAt !== undefined || device.expiresAt <= now) {\n      if (session !== undefined) this.removeSession(session.key, 'expired')\n      throw new AccessError(401, 'authentication_failed')\n    }\n    return Object.freeze({ sessionKey: key, deviceId: session.deviceId, expiresAt: session.expiresAt })\n  }\n\n  /** Require the Session-bound anti-CSRF value for an authenticated mutation. */\n  assertCsrf(authorization: SessionAuthorization, csrfToken: string | undefined): void {\n    const session = this.sessions.get(authorization.sessionKey)\n    if (session === undefined || csrfToken === undefined || csrfToken.length > 512\n      || !matchesDigest(csrfToken, session.csrfDigest)) {\n      throw new AccessError(403, 'forbidden')\n    }\n  }\n\n  /** End one short Session and notify the gateway to abort its attached work. */\n  logout(authorization: SessionAuthorization): void {\n    this.removeSession(authorization.sessionKey, 'logout')\n  }\n\n  /** Durably delete the device, then end every Session owned by that device. */\n  async revokeDevice(deviceId: string): Promise<boolean> {\n    this.requireInitialized()\n    return this.exclusive(async () => {\n      const next = this.devices.filter(device => device.id !== deviceId)\n      if (next.length === this.devices.length) return false\n      await this.store.save(this.snapshot(next))\n      this.devices = next\n      for (const [key, session] of this.sessions) {\n        if (session.deviceId === deviceId) this.removeSession(key, 'revoked')\n      }\n      return true\n    })\n  }\n\n  /** Remove every persistent credential and terminate every active Session. */\n  async resetDevices(): Promise<void> {\n    this.requireInitialized()\n    await this.exclusive(async () => {\n      await this.store.save(this.snapshot([]))\n      this.devices = []\n      for (const key of [...this.sessions.keys()]) this.removeSession(key, 'revoked')\n      this.pairingWindow = undefined\n    })\n  }\n\n  /** Safe metadata for the loopback administration surface. */\n  listDevices(): readonly DeviceSummary[] {\n    this.requireInitialized()\n    return Object.freeze(this.devices.map(publicDevice))\n  }\n\n  /** Pairing status without exposing the one-time secret. */\n  pairingStatus(): { open: boolean; expiresAt?: number } {\n    this.requireInitialized()\n    const window = this.pairingWindow\n    if (window === undefined || window.expiresAt <= this.now()) {\n      this.pairingWindow = undefined\n      return Object.freeze({ open: false })\n    }\n    return Object.freeze({ open: true, expiresAt: window.expiresAt })\n  }\n\n  /** Subscribe gateway resources to Session logout, expiry, eviction, and device revocation. */\n  onSessionEnded(listener: (authorization: SessionAuthorization, reason: SessionEndReason) => void): () => void {\n    this.sessionEndedListeners.add(listener)\n    return () => { this.sessionEndedListeners.delete(listener) }\n  }\n\n  /** Stop new operations, drain durable mutations, then clear volatile credentials. */\n  close(): Promise<void> {\n    if (this.closeTask !== undefined) return this.closeTask\n    this.closing = true\n    this.closeTask = this.finishClose()\n    return this.closeTask\n  }\n\n  private async finishClose(): Promise<void> {\n    await this.mutation\n    this.pairingWindow = undefined\n    for (const key of [...this.sessions.keys()]) this.removeSession(key, 'expired')\n    this.sessionEndedListeners.clear()\n    this.initialized = false\n  }\n\n  /** Bounded volatile-state metrics for tests and local status. */\n  metrics(): { sessions: number; rateLimitKeys: number } {\n    return Object.freeze({ sessions: this.sessions.size, rateLimitKeys: this.pairLimiter.size })\n  }\n}\n","/**\n * Browser-safe IP literal classification.\n *\n * `node:net` cannot be imported from the browser Client face, so the pure\n * predicate lives here instead. Semantics are deliberately identical to\n * `net.isIP`: strict dotted-quad IPv4 (no leading zeros, no signs, no\n * whitespace), IPv6 with at most one `::`, at most four hex digits per group,\n * an optional dotted-quad tail in the final position, and an optional\n * non-empty zone id after a single `%`.\n *\n * This module is dependency-free and side-effect-free on purpose: it is the\n * single classification source shared by every face of the plugin — the Node\n * side (`config.ts`, `cloudflared-tunnel.ts`, `origin-proxy-config.ts`,\n * `vps-deploy.ts`, `gateway.ts`, `network.ts`, `frp-config.ts`) and the browser\n * Client face that cannot reach `node:net` — so both classify a given literal\n * identically. Callers rely on the strict reading above and never post-process\n * the literal afterwards, so changing the accept/reject boundary here changes\n * it everywhere, which is the intended contract.\n */\n\n/** Strict dotted-quad IPv4: POSIX `inet_pton` rules, so `01.1.1.1` is rejected. */\nfunction isStrictIpv4(value: string): boolean {\n  const parts = value.split('.')\n  if (parts.length !== 4) return false\n  for (const part of parts) {\n    if (!/^(?:0|[1-9][0-9]{0,2})$/u.test(part)) return false\n    if (Number(part) > 255) return false\n  }\n  return true\n}\n\n/**\n * Count the 16-bit groups one side of an IPv6 address occupies.\n *\n * A dotted-quad tail counts as two groups and is accepted only where the caller\n * allows it — that is, only in the final label of the whole address.\n *\n * @returns the group count, or `-1` when any label is malformed.\n */\nfunction countIpv6Groups(labels: readonly string[], allowDottedQuad: boolean): number {\n  let groups = 0\n  for (let index = 0; index < labels.length; index += 1) {\n    const label = labels[index] as string\n    if (label.includes('.')) {\n      if (index !== labels.length - 1 || !allowDottedQuad || !isStrictIpv4(label)) return -1\n      groups += 2\n      continue\n    }\n    if (!/^[\\da-f]{1,4}$/iu.test(label)) return -1\n    groups += 1\n  }\n  return groups\n}\n\n/**\n * Classify an IP literal.\n *\n * @param value - candidate address; non-strings are never an IP.\n * @returns `4` for IPv4, `6` for IPv6, `0` when the value is neither.\n */\nexport function isIP(value: unknown): 0 | 4 | 6 {\n  if (typeof value !== 'string') return 0\n  if (isStrictIpv4(value)) return 4\n  let text = value\n  const zone = text.indexOf('%')\n  if (zone !== -1) {\n    const suffix = text.slice(zone + 1)\n    if (suffix.length === 0 || suffix.includes('%')) return 0\n    text = text.slice(0, zone)\n  }\n  if (text.length === 0) return 0\n  const halves = text.split('::')\n  if (halves.length > 2) return 0\n  if (halves.length === 1) {\n    return countIpv6Groups(text.split(':'), true) === 8 ? 6 : 0\n  }\n  const leftText = halves[0] as string\n  const rightText = halves[1] as string\n  const left = leftText === '' ? [] : leftText.split(':')\n  const right = rightText === '' ? [] : rightText.split(':')\n  // `::` must stand for at least one group, and a dotted-quad tail is valid only\n  // in the final label of the final non-empty side — so `1.2.3.4::` is rejected.\n  const leftGroups = countIpv6Groups(left, false)\n  const rightGroups = countIpv6Groups(right, right.length > 0)\n  if (leftGroups < 0 || rightGroups < 0) return 0\n  return leftGroups + rightGroups >= 8 ? 0 : 6\n}","import { connect } from 'node:net'\nimport { isIP } from './ip.js'\n\n/** A parsed IP network used to authorize directly connected clients. */\nexport interface ParsedCidr {\n  readonly bits: 32 | 128\n  readonly network: bigint\n  readonly prefix: number\n  readonly source: string\n}\n\n/** A normalized public authority. A missing port is filled from the bound listener. */\nexport interface AuthoritySpec {\n  readonly hostname: string\n  readonly port?: number\n}\n\nfunction parseIpv4(address: string): bigint {\n  const parts = address.split('.')\n  if (parts.length !== 4) throw new Error(`invalid IPv4 address ${JSON.stringify(address)}`)\n  let value = 0n\n  for (const part of parts) {\n    if (!/^\\d{1,3}$/u.test(part)) throw new Error(`invalid IPv4 address ${JSON.stringify(address)}`)\n    const octet = Number(part)\n    if (octet > 255) throw new Error(`invalid IPv4 address ${JSON.stringify(address)}`)\n    value = (value << 8n) | BigInt(octet)\n  }\n  return value\n}\n\nfunction parseIpv6Part(part: string, address: string): number[] {\n  if (part.includes('.')) {\n    const ipv4 = parseIpv4(part)\n    return [Number((ipv4 >> 16n) & 0xffffn), Number(ipv4 & 0xffffn)]\n  }\n  if (!/^[\\da-f]{1,4}$/iu.test(part)) throw new Error(`invalid IPv6 address ${JSON.stringify(address)}`)\n  return [Number.parseInt(part, 16)]\n}\n\nfunction parseIpv6(address: string): bigint {\n  const withoutZone = address.split('%', 1)[0] ?? address\n  if (withoutZone.split('::').length > 2) throw new Error(`invalid IPv6 address ${JSON.stringify(address)}`)\n  const [leftText, rightText] = withoutZone.split('::')\n  const left = leftText === '' ? [] : leftText!.split(':').flatMap(part => parseIpv6Part(part, address))\n  const right = rightText === undefined || rightText === ''\n    ? []\n    : rightText.split(':').flatMap(part => parseIpv6Part(part, address))\n  const omitted = 8 - left.length - right.length\n  if (rightText === undefined ? omitted !== 0 : omitted < 1) {\n    throw new Error(`invalid IPv6 address ${JSON.stringify(address)}`)\n  }\n  const groups = [...left, ...Array.from({ length: omitted }, () => 0), ...right]\n  if (groups.length !== 8) throw new Error(`invalid IPv6 address ${JSON.stringify(address)}`)\n  return groups.reduce((value, group) => (value << 16n) | BigInt(group), 0n)\n}\n\nfunction mappedIpv4(address: string): string | undefined {\n  const match = /^::ffff:(\\d{1,3}(?:\\.\\d{1,3}){3})$/iu.exec(address)\n  return match?.[1]\n}\n\nfunction parseIp(address: string): { bits: 32 | 128; value: bigint } {\n  const unwrapped = address.startsWith('[') && address.endsWith(']') ? address.slice(1, -1) : address\n  const mapped = mappedIpv4(unwrapped)\n  if (mapped !== undefined) return { bits: 32, value: parseIpv4(mapped) }\n  const version = isIP(unwrapped.split('%', 1)[0] ?? unwrapped)\n  if (version === 4) return { bits: 32, value: parseIpv4(unwrapped) }\n  if (version === 6) return { bits: 128, value: parseIpv6(unwrapped) }\n  throw new Error(`invalid IP address ${JSON.stringify(address)}`)\n}\n\n/** Parse and canonicalize one IPv4 or IPv6 CIDR. */\nexport function parseCidr(source: string): ParsedCidr {\n  const slash = source.lastIndexOf('/')\n  if (slash <= 0 || slash === source.length - 1) throw new Error(`invalid CIDR ${JSON.stringify(source)}`)\n  const address = source.slice(0, slash)\n  const parsed = parseIp(address)\n  const prefixText = source.slice(slash + 1)\n  if (!/^\\d{1,3}$/u.test(prefixText)) throw new Error(`invalid CIDR ${JSON.stringify(source)}`)\n  const prefix = Number(prefixText)\n  if (prefix > parsed.bits) throw new Error(`invalid CIDR ${JSON.stringify(source)}`)\n  const hostBits = BigInt(parsed.bits - prefix)\n  const mask = hostBits === BigInt(parsed.bits)\n    ? 0n\n    : ((1n << BigInt(parsed.bits)) - 1n) ^ ((1n << hostBits) - 1n)\n  const network = parsed.value & mask\n  if (network !== parsed.value) {\n    throw new Error(`CIDR ${JSON.stringify(source)} has host bits set`)\n  }\n  return Object.freeze({ bits: parsed.bits, network, prefix, source })\n}\n\n/** Whether a directly connected socket address belongs to at least one allowed CIDR. */\nexport function addressAllowed(address: string | undefined, cidrs: readonly ParsedCidr[]): boolean {\n  if (address === undefined) return false\n  let parsed: ReturnType<typeof parseIp>\n  try {\n    parsed = parseIp(address)\n  } catch {\n    return false\n  }\n  return cidrs.some((cidr) => {\n    if (cidr.bits !== parsed.bits) return false\n    const hostBits = BigInt(cidr.bits - cidr.prefix)\n    const mask = hostBits === BigInt(cidr.bits)\n      ? 0n\n      : ((1n << BigInt(cidr.bits)) - 1n) ^ ((1n << hostBits) - 1n)\n    return (parsed.value & mask) === cidr.network\n  })\n}\n\n/** Whether an IP literal is loopback and therefore eligible for HTTP-only development. */\nexport function isLoopbackAddress(address: string): boolean {\n  try {\n    const parsed = parseIp(address)\n    if (parsed.bits === 32) return (parsed.value >> 24n) === 127n\n    return parsed.value === 1n\n  } catch {\n    return false\n  }\n}\n\n/**\n * IPv4 ranges that are never a public VPS endpoint (IANA special-purpose,\n * private, shared, loopback, link-local, documentation, benchmark, multicast,\n * and reserved space). Kept in sync with Android `RemoteHostPolicy`.\n */\nconst NON_ROUTABLE_IPV4_RANGES: ReadonlyArray<readonly [network: bigint, prefix: number]> = Object.freeze([\n  [0x00000000n, 8], // \"This network\" / software scope\n  [0x0a000000n, 8], // Private-Use (RFC 1918)\n  [0x64400000n, 10], // Shared address space / CGNAT (RFC 6598)\n  [0x7f000000n, 8], // Loopback (RFC 1122)\n  [0xa9fe0000n, 16], // Link-local (RFC 3927)\n  [0xac100000n, 12], // Private-Use (RFC 1918)\n  [0xc0000000n, 24], // IETF protocol assignments (RFC 6890)\n  [0xc0000200n, 24], // Documentation TEST-NET-1 (RFC 5737)\n  [0xc01fc400n, 24], // AS112-v4 (RFC 7534)\n  [0xc034c100n, 24], // AMT relay (RFC 7450)\n  [0xc0586300n, 24], // 6to4 relay anycast, deprecated (RFC 7526)\n  [0xc0a80000n, 16], // Private-Use (RFC 1918)\n  [0xc0af3000n, 24], // Direct delegation AS112 (RFC 7535)\n  [0xc6120000n, 15], // Benchmarking (RFC 2544)\n  [0xc6336400n, 24], // Documentation TEST-NET-2 (RFC 5737)\n  [0xcb007100n, 24], // Documentation TEST-NET-3 (RFC 5737)\n  [0xe0000000n, 4], // Multicast (RFC 1112, incl. MCAST-TEST-NET)\n  [0xf0000000n, 4], // Reserved for future use + broadcast (RFC 1112)\n])\n\nfunction parseStrictIpv4Octets(address: string): readonly [number, number, number, number] | undefined {\n  const parts = address.split('.')\n  if (parts.length !== 4) return undefined\n  const octets: number[] = []\n  for (const part of parts) {\n    if (!/^(?:0|[1-9][0-9]{0,2})$/u.test(part)) return undefined\n    const octet = Number(part)\n    if (octet > 255) return undefined\n    octets.push(octet)\n  }\n  return octets as [number, number, number, number]\n}\n\n/**\n * Whether a dotted-quad IPv4 literal is globally routable and therefore usable\n * as a public VPS / remote HTTPS endpoint. Rejects documentation addresses such\n * as 203.0.113.10 alongside private, shared, and reserved space.\n */\nexport function isGloballyRoutableIpv4(address: string): boolean {\n  const octets = parseStrictIpv4Octets(address)\n  if (octets === undefined) return false\n  const value = (BigInt(octets[0]) << 24n) | (BigInt(octets[1]) << 16n) | (BigInt(octets[2]) << 8n) | BigInt(octets[3])\n  return !NON_ROUTABLE_IPV4_RANGES.some(([network, prefix]) => {\n    if (prefix === 0) return true\n    const hostBits = BigInt(32 - prefix)\n    const mask = ((1n << 32n) - 1n) ^ ((1n << hostBits) - 1n)\n    return (value & mask) === network\n  })\n}\n\n/** Parse a bare host or host:port authority without accepting URL components. */\nexport function parseAuthority(source: string): AuthoritySpec {\n  if (source.trim() !== source || source.length === 0 || /[/?#@\\\\]/u.test(source)) {\n    throw new Error(`invalid public authority ${JSON.stringify(source)}`)\n  }\n  let url: URL\n  try {\n    url = new URL(`https://${source}`)\n  } catch {\n    throw new Error(`invalid public authority ${JSON.stringify(source)}`)\n  }\n  if (url.username !== '' || url.password !== '' || url.pathname !== '/' || url.search !== '' || url.hash !== '') {\n    throw new Error(`invalid public authority ${JSON.stringify(source)}`)\n  }\n  const explicitPort = /\\]:\\d+$/u.test(source) || (!source.startsWith('[') && /:\\d+$/u.test(source))\n  const hostname = url.hostname.toLowerCase()\n  const port = explicitPort ? Number(url.port === '' ? 443 : url.port) : undefined\n  if (port !== undefined && (!Number.isInteger(port) || port < 1 || port > 65535)) {\n    throw new Error(`invalid public authority ${JSON.stringify(source)}`)\n  }\n  return port === undefined ? Object.freeze({ hostname }) : Object.freeze({ hostname, port })\n}\n\nfunction formatHostname(hostname: string): string {\n  return hostname.includes(':') && !hostname.startsWith('[') ? `[${hostname}]` : hostname\n}\n\n/** Resolve an authority against the actual listener port. */\nexport function resolveAuthority(spec: AuthoritySpec, listenerPort: number): string {\n  return `${formatHostname(spec.hostname)}:${String(spec.port ?? listenerPort)}`\n}\n\n/** Exact Host/Origin/CIDR policy for the directly exposed listener. */\nexport class RequestTrustPolicy {\n  readonly authorities: ReadonlySet<string>\n  readonly origins: ReadonlySet<string>\n  private readonly scheme: 'http' | 'https'\n\n  constructor(\n    specs: readonly AuthoritySpec[],\n    listenerPort: number,\n    readonly cidrs: readonly ParsedCidr[],\n    tls: boolean,\n  ) {\n    this.scheme = tls ? 'https' : 'http'\n    this.authorities = new Set(specs.map(spec => resolveAuthority(spec, listenerPort).toLowerCase()))\n    this.origins = new Set([...this.authorities].map(\n      authority => new URL(`${this.scheme}://${authority}`).origin.toLowerCase(),\n    ))\n  }\n\n  /** Validate the exact Host header after WHATWG authority normalization. */\n  acceptsHost(header: string | undefined): boolean {\n    return this.canonicalHost(header) !== undefined\n  }\n\n  /** Return the canonical accepted Host authority, otherwise undefined. */\n  canonicalHost(header: string | undefined): string | undefined {\n    if (header === undefined || /[/?#@\\\\]/u.test(header)) return undefined\n    let normalized: string\n    try {\n      const parsed = new URL(`${this.scheme}://${header}`)\n      if (parsed.pathname !== '/' || parsed.username !== '' || parsed.password !== '') return undefined\n      normalized = resolveAuthority({\n        hostname: parsed.hostname,\n        port: Number(parsed.port || (this.scheme === 'https' ? '443' : '80')),\n      }, 80).toLowerCase()\n    } catch {\n      return undefined\n    }\n    return this.authorities.has(normalized) ? normalized : undefined\n  }\n\n  /** Validate an exact same-scheme browser Origin. */\n  acceptsOrigin(header: string | undefined): boolean {\n    return this.canonicalOrigin(header) !== undefined\n  }\n\n  /** Return the canonical accepted Origin, otherwise undefined. */\n  canonicalOrigin(header: string | undefined): string | undefined {\n    if (header === undefined) return undefined\n    // 微信小程序 wx.connectSocket 会把允许的 Origin 与 undefined 用逗号合并。\n    let normalized: string | undefined\n    for (const part of header.split(',')) {\n      const trimmed = part.trim()\n      if (trimmed === 'undefined') continue\n      let candidate: string\n      try {\n        const parsed = new URL(trimmed)\n        if (parsed.pathname !== '/' || parsed.search !== '' || parsed.hash !== '' || parsed.username !== '' || parsed.password !== '') {\n          return undefined\n        }\n        candidate = parsed.origin.toLowerCase()\n      } catch {\n        return undefined\n      }\n      if (!this.origins.has(candidate) || normalized !== undefined) return undefined\n      normalized = candidate\n    }\n    return normalized\n  }\n}\n\n/**\n * Open a plain TCP connection only to learn whether something is listening.\n *\n * Used by the on-demand self-check so the panel can tell \"frps is up\" from\n * \"frps is not listening\". A transparent proxy can acknowledge any connect, so\n * this result is advisory and never authorises a security decision on its own.\n */\nexport async function probeTcpReachable(host: string, port: number, timeoutMs = 1_500): Promise<boolean> {\n  if (!Number.isSafeInteger(port) || port < 1 || port > 65_535) return false\n  return new Promise<boolean>((resolveProbe) => {\n    let finished = false\n    const socket = connect({ host, port })\n    const finish = (reachable: boolean): void => {\n      if (finished) return\n      finished = true\n      clearTimeout(timer)\n      socket.destroy()\n      resolveProbe(reachable)\n    }\n    const timer = setTimeout(() => { finish(false) }, timeoutMs)\n    timer.unref()\n    socket.once('connect', () => { finish(true) })\n    socket.once('error', () => { finish(false) })\n    socket.once('close', () => { finish(false) })\n  })\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\n\n/** Cap the admin-approved extra WebSocket upgrade paths (exact pathnames). */\nexport const MAX_EXTRA_WEBSOCKET_PATHS = 16\nexport const MAX_WEBSOCKET_PATH_LENGTH = 256\n\nfunction fail(code: string): never {\n  throw new Error(code)\n}\n\n/**\n * Validate one exact pathname for proxying. Query strings are matched at\n * upgrade time, so only the pathname is stored. Rejects anything the\n * gateway cannot match exactly.\n */\nexport function validateWebSocketPath(value: unknown): string {\n  if (typeof value !== 'string') fail('websocket_path_invalid')\n  const path = value as string\n  if (path.length === 0 || path.length > MAX_WEBSOCKET_PATH_LENGTH) fail('websocket_path_invalid')\n  if (!path.startsWith('/')) fail('websocket_path_invalid')\n  // eslint-disable-next-line no-control-regex\n  if (/[\\s\\u0000-\\u001f\\u007f#?]/u.test(path)) fail('websocket_path_invalid')\n  if (path.includes('..')) fail('websocket_path_invalid')\n  return path\n}\n\n/** Validate a whole replacement list all-or-nothing; duplicates collapse. */\nexport function normalizeWebSocketPaths(value: unknown): string[] {\n  if (!Array.isArray(value)) fail('websocket_paths_invalid')\n  if (value.length > MAX_EXTRA_WEBSOCKET_PATHS) fail('websocket_paths_invalid')\n  const seen = new Set<string>()\n  for (const entry of value) {\n    const path = validateWebSocketPath(entry)\n    seen.add(path)\n  }\n  return [...seen]\n}\n\n/** Cap remembered rejected upgrade paths offered for one-click approval. */\nexport const MAX_BLOCKED_UPGRADE_PATHS = 32\n\nexport interface BlockedUpgradePathEntry {\n  readonly path: string\n  readonly attempts: number\n  readonly firstSeen: number\n  readonly lastSeen: number\n}\n\n/**\n * In-memory log of rejected third-party upgrade paths, shared by every\n * gateway instance so the approval UI sees attempts on any listener.\n * Bounded and newest-first; a restart clears it (attempts reappear on\n * the next blocked handshake).\n */\nexport class BlockedUpgradePathLog {\n  private readonly entries = new Map<string, { attempts: number; firstSeen: number; lastSeen: number }>()\n\n  record(pathname: string): void {\n    const now = Date.now()\n    const stats = this.entries.get(pathname)\n    if (stats === undefined) {\n      if (this.entries.size >= MAX_BLOCKED_UPGRADE_PATHS) {\n        let oldest: string | undefined\n        for (const [path, entry] of this.entries) {\n          if (oldest === undefined || entry.lastSeen < (this.entries.get(oldest)?.lastSeen ?? 0)) oldest = path\n        }\n        if (oldest !== undefined) this.entries.delete(oldest)\n      }\n      this.entries.set(pathname, { attempts: 1, firstSeen: now, lastSeen: now })\n      return\n    }\n    stats.attempts += 1\n    stats.lastSeen = now\n  }\n\n  report(): BlockedUpgradePathEntry[] {\n    return [...this.entries]\n      .map(([path, stats]) => ({ path, ...stats }))\n      .sort((a, b) => b.lastSeen - a.lastSeen)\n  }\n}\n\n/** File-backed store shared by every gateway instance (LAN and remote). */\nexport class WebSocketPathStore {\n  private paths = new Set<string>()\n  private loaded = false\n\n  constructor(private readonly file: string) {}\n\n  /** Snapshot for the upgrade check. */\n  has(pathname: string): boolean {\n    return this.paths.has(pathname)\n  }\n\n  list(): string[] {\n    return [...this.paths]\n  }\n\n  async load(): Promise<string[]> {\n    if (!this.loaded) {\n      try {\n        const raw = JSON.parse(await readFile(this.file, 'utf8')) as { readonly paths?: unknown }\n        this.paths = new Set(normalizeWebSocketPaths(raw.paths ?? []))\n      } catch {\n        // Missing, corrupt, or unreadable: fall back to the empty (most\n        // restrictive) list. The panel always shows the active list, so an\n        // admin notices and re-adds entries instead of silently widening.\n        this.paths = new Set()\n      }\n      this.loaded = true\n    }\n    return this.list()\n  }\n\n  /** Replace the whole list after validating; persists atomically. */\n  async replace(paths: readonly string[]): Promise<string[]> {\n    const next = normalizeWebSocketPaths([...paths])\n    await mkdir(dirname(this.file), { recursive: true })\n    await writeFile(this.file, `${JSON.stringify({ paths: next })}\\n`, 'utf8')\n    this.paths = new Set(next)\n    this.loaded = true\n    return this.list()\n  }\n}\n","/** Operator-owned limits for opt-in local extension worker execution. */\nexport interface HostExecutionConfig {\n  readonly mode?: 'in-process' | 'worker'\n  /** Apply worker mode only to these exact local ids; omitted selects every local host. */\n  readonly extensions?: readonly string[] | undefined\n  readonly maxWorkers?: number\n  readonly maxRegistrations?: number\n  readonly maxOldGenerationSizeMb?: number\n  readonly maxYoungGenerationSizeMb?: number\n  readonly stackSizeMb?: number\n  readonly activationTimeoutMs?: number\n  readonly operationTimeoutMs?: number\n  readonly cancelGraceMs?: number\n  readonly streamCancelGraceMs?: number\n  readonly disposeGraceMs?: number\n  readonly resultMaxBytes?: number\n  readonly streamWindowBytes?: number\n  readonly streamChunkBytes?: number\n  readonly streamAggregateBytes?: number\n  readonly logWindowMs?: number\n  readonly logMessagesPerWindow?: number\n  readonly logMessageBytes?: number\n}\n\n/** Complete settings passed to each owned worker; Node limits do not isolate filesystem access. */\nexport interface ResolvedHostExecutionConfig extends Required<Omit<HostExecutionConfig, 'extensions'>> {\n  readonly extensions: readonly string[] | undefined\n}\n\nfunction integer(value: unknown, name: string, fallback: number, minimum: number, maximum: number): number {\n  const resolved = value ?? fallback\n  if (typeof resolved !== 'number' || !Number.isSafeInteger(resolved) || resolved < minimum || resolved > maximum) {\n    throw new Error(`hostExecution.${name} must be an integer from ${minimum} through ${maximum}`)\n  }\n  return resolved\n}\n\n/** Resolve configuration once; reject malformed modes, ids and incoherent stream windows. */\nexport function resolveHostExecution(raw: unknown): ResolvedHostExecutionConfig {\n  if (raw !== undefined && (raw === null || typeof raw !== 'object' || Array.isArray(raw))) throw new Error('hostExecution must be an object')\n  const value = (raw ?? {}) as HostExecutionConfig\n  const mode = value.mode ?? 'in-process'\n  if (mode !== 'worker' && mode !== 'in-process') throw new Error('hostExecution.mode is invalid')\n  if (value.extensions !== undefined && (!Array.isArray(value.extensions) || value.extensions.some(id => typeof id !== 'string' || !/^[a-z][a-z0-9-]{0,63}$/u.test(id)) || new Set(value.extensions).size !== value.extensions.length)) throw new Error('hostExecution.extensions must contain unique local extension ids')\n  const streamWindowBytes = integer(value.streamWindowBytes, 'streamWindowBytes', 256 * 1024, 1024, 4 * 1024 * 1024)\n  const streamChunkBytes = integer(value.streamChunkBytes, 'streamChunkBytes', 64 * 1024, 1024, streamWindowBytes)\n  const streamAggregateBytes = integer(value.streamAggregateBytes, 'streamAggregateBytes', 1024 * 1024, streamWindowBytes, 32 * 1024 * 1024)\n  return Object.freeze({\n    mode, extensions: value.extensions === undefined ? undefined : Object.freeze([...value.extensions]),\n    maxWorkers: integer(value.maxWorkers, 'maxWorkers', 8, 1, 128),\n    maxRegistrations: integer(value.maxRegistrations, 'maxRegistrations', 256, 1, 4096),\n    maxOldGenerationSizeMb: integer(value.maxOldGenerationSizeMb, 'maxOldGenerationSizeMb', 128, 16, 4096),\n    maxYoungGenerationSizeMb: integer(value.maxYoungGenerationSizeMb, 'maxYoungGenerationSizeMb', 16, 1, 512),\n    stackSizeMb: integer(value.stackSizeMb, 'stackSizeMb', 4, 1, 64),\n    activationTimeoutMs: integer(value.activationTimeoutMs, 'activationTimeoutMs', 5000, 1, 300_000),\n    operationTimeoutMs: integer(value.operationTimeoutMs, 'operationTimeoutMs', 30_000, 1, 300_000),\n    cancelGraceMs: integer(value.cancelGraceMs, 'cancelGraceMs', 250, 1, 30_000),\n    streamCancelGraceMs: integer(value.streamCancelGraceMs, 'streamCancelGraceMs', 1000, 1, 30_000),\n    disposeGraceMs: integer(value.disposeGraceMs, 'disposeGraceMs', 2000, 1, 30_000),\n    resultMaxBytes: integer(value.resultMaxBytes, 'resultMaxBytes', 4 * 1024 * 1024, 1024, 4 * 1024 * 1024),\n    streamWindowBytes, streamChunkBytes, streamAggregateBytes,\n    logWindowMs: integer(value.logWindowMs, 'logWindowMs', 1000, 1, 60_000),\n    logMessagesPerWindow: integer(value.logMessagesPerWindow, 'logMessagesPerWindow', 64, 1, 1024),\n    logMessageBytes: integer(value.logMessageBytes, 'logMessageBytes', 4096, 128, 64 * 1024),\n  })\n}\n","import { dirname, isAbsolute, join, resolve } from 'node:path'\nimport { createHash } from 'node:crypto'\nimport { fileURLToPath } from 'node:url'\nimport z from '@deepseek-ai/schemastery'\nimport { isIP } from './ip.js'\nimport { isLoopbackAddress, parseAuthority, parseCidr, type AuthoritySpec, type ParsedCidr } from './network.js'\nimport { normalizeWebSocketPaths } from './websocket-paths.js'\nimport { resolveHostExecution, type HostExecutionConfig, type ResolvedHostExecutionConfig } from './extension-worker-config.js'\n\n/** Optional compression for exact, already authorized WebSocket paths. */\nexport interface WebSocketCompressionConfig {\n  paths?: string[]\n  maxMessageBytes?: number\n  maxQueuedBytes?: number\n  thresholdBytes?: number\n  concurrencyLimit?: number\n  level?: number\n}\n\n/** Validated compression settings; an empty path list keeps the raw transport. */\nexport interface ResolvedWebSocketCompressionConfig {\n  readonly paths: readonly string[]\n  readonly maxMessageBytes: number\n  readonly maxQueuedBytes: number\n  readonly thresholdBytes: number\n  readonly concurrencyLimit: number\n  readonly level: number\n}\n\n/** TLS source accepted by the LAN listener. */\nexport interface ProvidedTlsConfig {\n  readonly mode: 'provided'\n  /** PEM server leaf followed by any intermediate certificate chain. */\n  readonly certFile: string\n  readonly keyFile: string\n  /** Optional PEM intermediates appended after the chain in `certFile`; roots are rejected. */\n  readonly caFile?: string\n}\n\n/** HTTP is available only for an explicitly loopback-bound listener. */\nexport interface DisabledTlsConfig {\n  readonly mode: 'disabled'\n}\n\nexport type TlsConfig = ProvidedTlsConfig | DisabledTlsConfig\n\n/** Operator-facing plugin configuration. */\nexport interface PluginConfig {\n  /** Local host execution mode and owned worker budgets; defaults to in-process. */\n  hostExecution?: HostExecutionConfig\n  /** Optional setup JSON written by the packaged CLI. */\n  setupFile?: string\n  /** Preferred HTTPS origin used to derive the public authority and listener port. */\n  publicOrigin?: string\n  listenHost?: string\n  listenPort?: number\n  upstreamOrigin?: string\n  publicAuthorities?: string[]\n  allowedCidrs?: string[]\n  stateFile: string\n  /** Internal persisted on/off preference managed by the DSH plugin card. */\n  controlFile: string\n  /** Optional user stylesheet served to the authenticated mobile UI. */\n  customCssFile?: string\n  /** Optional user script that mounts authenticated mobile-only Web features. */\n  customScriptFile?: string\n  /** Internal dedicated mobile layout browser bundle. */\n  mobileLayoutFile?: string\n  /** Standalone browser compatibility bundle used before DSH boot. */\n  mobileCompatibilityFile?: string\n  /** Optional application-phase client package ids omitted only from the mobile boot graph. */\n  excludedClientModules?: string[]\n  /** Compression is opt-in; it does not authorize additional WebSocket paths. */\n  websocketCompression?: WebSocketCompressionConfig\n  /** Stable public discovery identifier; it is not an authentication secret. */\n  instanceId?: string\n  /** Managed CA certificate offered to the Android installer after fingerprint binding. */\n  pairingCaFile?: string\n  /** First-run state used only while the control file does not exist. */\n  initiallyEnabled: boolean\n  tls?: {\n    mode?: 'provided' | 'disabled'\n    certFile?: string\n    keyFile?: string\n    caFile?: string\n  }\n  pairingTtlMs?: number\n  deviceTtlMs?: number\n  sessionTtlMs?: number\n  maxDevices?: number\n  maxSessions?: number\n  maxConnections?: number\n  maxActiveRequests?: number\n  maxWebSockets?: number\n  maxBodyBytes?: number\n  /** Transport, upload, static-response and WebSocket-handshake idle timeout. */\n  upstreamTimeoutMs?: number\n  /** Authenticated /api response idle timeout after upload; zero disables it. */\n  upstreamApiTimeoutMs?: number\n  rateLimitWindowMs?: number\n  maxPairingAttempts?: number\n  maxRateLimitKeys?: number\n}\n\n/** Resolved, validated security and resource limits. */\nexport interface ResolvedGatewayConfig {\n  readonly hostExecution: ResolvedHostExecutionConfig\n  readonly listenHost: string\n  readonly listenPort: number\n  readonly upstreamOrigin: URL\n  readonly authorities: readonly AuthoritySpec[]\n  readonly allowedCidrs: readonly ParsedCidr[]\n  readonly stateFile: string\n  /** Local extension root adjacent to the mobile-access state file. */\n  readonly extensionsDir: string\n  readonly customCssFile: string\n  readonly customScriptFile: string\n  readonly mobileLayoutFile: string\n  readonly mobileCompatibilityFile: string\n  readonly excludedClientModules: readonly string[]\n  readonly websocketCompression: ResolvedWebSocketCompressionConfig\n  readonly instanceId: string\n  readonly pairingCaFile?: string\n  readonly tls: TlsConfig\n  /** Whether the public hop is HTTPS, even when a trusted loopback proxy terminates TLS. */\n  readonly publicTls: boolean\n  /** LAN discovery is disabled for private proxy listeners such as Funnel ingress. */\n  readonly discovery: boolean\n  readonly pairingTtlMs: number\n  readonly deviceTtlMs: number\n  readonly sessionTtlMs: number\n  readonly maxDevices: number\n  readonly maxSessions: number\n  readonly maxConnections: number\n  readonly maxActiveRequests: number\n  readonly maxWebSockets: number\n  readonly maxBodyBytes: number\n  readonly upstreamTimeoutMs: number\n  readonly upstreamApiTimeoutMs: number\n  readonly rateLimitWindowMs: number\n  readonly maxPairingAttempts: number\n  readonly maxRateLimitKeys: number\n}\n\n/** Loader-facing defaults; {@link parseGatewayConfig} enforces cross-field security rules. */\nexport const Config: z<PluginConfig> = z.object({\n  hostExecution: z.object({\n    mode: z.union([z.const('in-process'), z.const('worker')]),\n    // Omission selects every local host; an explicit empty array selects none.\n    extensions: z.union([z.const(undefined), z.array(String)]),\n    maxWorkers: z.natural(), maxRegistrations: z.natural(), maxOldGenerationSizeMb: z.natural(), maxYoungGenerationSizeMb: z.natural(), stackSizeMb: z.natural(),\n    activationTimeoutMs: z.natural(), operationTimeoutMs: z.natural(), cancelGraceMs: z.natural(), streamCancelGraceMs: z.natural(), disposeGraceMs: z.natural(),\n    resultMaxBytes: z.natural(), streamWindowBytes: z.natural(), streamChunkBytes: z.natural(), streamAggregateBytes: z.natural(),\n    logWindowMs: z.natural(), logMessagesPerWindow: z.natural(), logMessageBytes: z.natural(),\n  }) as z<HostExecutionConfig>,\n  setupFile: z.string().hidden(),\n  publicOrigin: z.string(),\n  listenHost: z.string(),\n  listenPort: z.natural().max(65535),\n  upstreamOrigin: z.string(),\n  publicAuthorities: z.array(String).default(undefined as unknown as string[]),\n  allowedCidrs: z.array(String).default(undefined as unknown as string[]),\n  stateFile: String,\n  controlFile: z.string().hidden().required(),\n  customCssFile: z.string().hidden(),\n  customScriptFile: z.string().hidden(),\n  mobileLayoutFile: z.string().hidden(),\n  mobileCompatibilityFile: z.string().hidden(),\n  excludedClientModules: z.array(String).default([]),\n  websocketCompression: z.object({\n    paths: z.array(String).default([]),\n    maxMessageBytes: z.natural(),\n    maxQueuedBytes: z.natural(),\n    thresholdBytes: z.natural(),\n    concurrencyLimit: z.natural(),\n    level: z.natural().max(9),\n  }),\n  instanceId: z.string().hidden(),\n  pairingCaFile: z.string().hidden(),\n  initiallyEnabled: z.boolean().hidden().required(),\n  tls: z.object({\n    mode: z.union([z.const('provided'), z.const('disabled')]),\n    certFile: z.string(),\n    keyFile: z.string(),\n    caFile: z.string(),\n  }),\n  pairingTtlMs: z.natural(),\n  deviceTtlMs: z.natural(),\n  sessionTtlMs: z.natural(),\n  maxDevices: z.natural(),\n  maxSessions: z.natural(),\n  maxConnections: z.natural(),\n  maxActiveRequests: z.natural(),\n  maxWebSockets: z.natural(),\n  maxBodyBytes: z.natural(),\n  upstreamTimeoutMs: z.natural(),\n  upstreamApiTimeoutMs: z.natural(),\n  rateLimitWindowMs: z.natural(),\n  maxPairingAttempts: z.natural(),\n  maxRateLimitKeys: z.natural(),\n})\n\nfunction integer(value: unknown, name: string, fallback: number, minimum: number, maximum: number): number {\n  const resolved = value ?? fallback\n  if (typeof resolved !== 'number' || !Number.isSafeInteger(resolved) || resolved < minimum || resolved > maximum) {\n    throw new Error(`${name} must be an integer from ${String(minimum)} through ${String(maximum)}`)\n  }\n  return resolved\n}\n\nfunction parseWebSocketCompression(raw: unknown): ResolvedWebSocketCompressionConfig {\n  if (raw !== undefined && (typeof raw !== 'object' || raw === null || Array.isArray(raw))) {\n    throw new Error('websocketCompression must be an object')\n  }\n  const value = (raw ?? {}) as WebSocketCompressionConfig\n  const maxMessageBytes = integer(value.maxMessageBytes, 'websocketCompression.maxMessageBytes', 32 * 1024 * 1024, 1024, 256 * 1024 * 1024)\n  const maxQueuedBytes = integer(value.maxQueuedBytes, 'websocketCompression.maxQueuedBytes', 64 * 1024 * 1024, 1024, 256 * 1024 * 1024)\n  if (maxQueuedBytes < maxMessageBytes + 14) throw new Error('websocketCompression.maxQueuedBytes must cover maxMessageBytes and the frame header')\n  return Object.freeze({\n    paths: Object.freeze(normalizeWebSocketPaths(value.paths ?? [])),\n    maxMessageBytes,\n    maxQueuedBytes,\n    thresholdBytes: integer(value.thresholdBytes, 'websocketCompression.thresholdBytes', 1024, 0, maxMessageBytes),\n    concurrencyLimit: integer(value.concurrencyLimit, 'websocketCompression.concurrencyLimit', 4, 1, 32),\n    level: integer(value.level, 'websocketCompression.level', 3, 0, 9),\n  })\n}\n\nfunction stringArray(value: unknown, name: string): string[] {\n  if (!Array.isArray(value) || value.length === 0 || value.some(entry => typeof entry !== 'string')) {\n    throw new Error(`${name} must be a non-empty string array`)\n  }\n  return value as string[]\n}\n\nfunction absoluteFile(value: unknown, name: string): string {\n  if (typeof value !== 'string' || value.length === 0 || !isAbsolute(value)) {\n    throw new Error(`${name} must be an absolute file path`)\n  }\n  return resolve(value)\n}\n\nfunction excludedClientModules(value: unknown): readonly string[] {\n  if (value === undefined) return Object.freeze([])\n  if (!Array.isArray(value) || value.some(id => typeof id !== 'string' || id.length === 0 || id.trim() !== id)) {\n    throw new Error('excludedClientModules must be an array of exact, non-empty client module ids')\n  }\n  const ids = value as string[]\n  if (new Set(ids).size !== ids.length) throw new Error('excludedClientModules must not contain duplicate ids')\n  return Object.freeze([...ids])\n}\n\n/** Resolve the hidden runtime-control file independently from gateway configuration. */\nexport function parseControlFile(value: unknown): string {\n  return absoluteFile(value, 'controlFile')\n}\n\nfunction parseUpstream(value: unknown): URL {\n  const source = value ?? 'http://127.0.0.1:3080'\n  if (typeof source !== 'string') throw new Error('upstreamOrigin must be a string')\n  let url: URL\n  try {\n    url = new URL(source)\n  } catch {\n    throw new Error('upstreamOrigin must be an HTTP loopback origin')\n  }\n  if (url.protocol !== 'http:' || !isLoopbackAddress(url.hostname) || url.username !== '' || url.password !== ''\n    || url.pathname !== '/' || url.search !== '' || url.hash !== '' || url.port === '') {\n    throw new Error('upstreamOrigin must be an HTTP loopback origin with an explicit port and no path or credentials')\n  }\n  return url\n}\n\nfunction parsePublicOrigin(value: unknown): { readonly authority: AuthoritySpec; readonly port: number } | undefined {\n  if (value === undefined) return undefined\n  if (typeof value !== 'string' || value.length === 0 || value.trim() !== value) {\n    throw new Error('publicOrigin must be an HTTPS origin')\n  }\n  let url: URL\n  try {\n    url = new URL(value)\n  } catch {\n    throw new Error('publicOrigin must be an HTTPS origin')\n  }\n  if (url.protocol !== 'https:' || url.username !== '' || url.password !== ''\n    || url.pathname !== '/' || url.search !== '' || url.hash !== '') {\n    throw new Error('publicOrigin must be an HTTPS origin with no path or credentials')\n  }\n  if (url.hostname === '0.0.0.0' || url.hostname === '[::]') {\n    throw new Error('publicOrigin must name a reachable host')\n  }\n  return Object.freeze({\n    authority: parseAuthority(url.host),\n    port: Number(url.port || '443'),\n  })\n}\n\nfunction parseTls(value: PluginConfig['tls'], listenHost: string): TlsConfig {\n  if (value !== undefined && (value === null || typeof value !== 'object' || Array.isArray(value))) {\n    throw new Error('tls must be an object')\n  }\n  const mode = value?.mode ?? 'provided'\n  if (value?.mode === null || (mode !== 'provided' && mode !== 'disabled')) throw new Error('tls.mode must be provided or disabled')\n  if (mode === 'disabled') {\n    if (!isLoopbackAddress(listenHost)) throw new Error('TLS may be disabled only on an IP loopback listener')\n    return Object.freeze({ mode })\n  }\n  return Object.freeze({\n    mode,\n    certFile: absoluteFile(value?.certFile, 'tls.certFile'),\n    keyFile: absoluteFile(value?.keyFile, 'tls.keyFile'),\n    ...(value?.caFile === undefined ? {} : { caFile: absoluteFile(value.caFile, 'tls.caFile') }),\n  })\n}\n\n/** Parse configuration and reject unsafe topology, credential, and resource combinations. */\nexport function parseGatewayConfig(raw: unknown): ResolvedGatewayConfig {\n  if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) throw new Error('mobile-access config must be an object')\n  const value = raw as PluginConfig\n  const publicOrigin = parsePublicOrigin(value.publicOrigin)\n  if (publicOrigin !== undefined && value.listenPort !== undefined) {\n    throw new Error('publicOrigin cannot be combined with listenPort')\n  }\n  if (publicOrigin !== undefined && value.publicAuthorities !== undefined) {\n    throw new Error('publicOrigin cannot be combined with publicAuthorities')\n  }\n  const listenHost = value.listenHost ?? (publicOrigin === undefined ? '127.0.0.1' : '0.0.0.0')\n  if (isIP(listenHost) === 0) throw new Error('listenHost must be an IP literal')\n  const listenPort = publicOrigin?.port ?? integer(value.listenPort, 'listenPort', 3443, 0, 65535)\n  const upstreamOrigin = parseUpstream(value.upstreamOrigin)\n  const tls = parseTls(value.tls, listenHost)\n  if (publicOrigin !== undefined && tls.mode !== 'provided') {\n    throw new Error('publicOrigin requires TLS')\n  }\n\n  let authorities: AuthoritySpec[]\n  if (publicOrigin !== undefined) {\n    authorities = [publicOrigin.authority]\n  } else {\n    let authoritySources = value.publicAuthorities\n    if (authoritySources === undefined || authoritySources.length === 0) {\n      if (!isLoopbackAddress(listenHost)) throw new Error('publicAuthorities is required for a non-loopback listener')\n      authoritySources = [listenHost]\n    }\n    authorities = authoritySources.map(parseAuthority)\n  }\n  for (const authority of authorities) {\n    if (listenPort === 0 && authority.port !== undefined) {\n      throw new Error('explicit public authority ports require a non-zero listenPort')\n    }\n    if (authority.port !== undefined && listenPort !== 0 && authority.port !== listenPort) {\n      throw new Error('every explicit public authority port must equal listenPort')\n    }\n  }\n  if (new Set(authorities.map(entry => `${entry.hostname}:${String(entry.port ?? listenPort)}`)).size !== authorities.length) {\n    throw new Error('publicAuthorities must not contain duplicates')\n  }\n\n  const cidrSources = value.allowedCidrs\n    ?? (isLoopbackAddress(listenHost) ? ['127.0.0.0/8', '::1/128'] : undefined)\n  const allowedCidrs = stringArray(cidrSources, 'allowedCidrs').map(parseCidr)\n  if (new Set(allowedCidrs.map(entry => `${String(entry.bits)}:${entry.network.toString(16)}:${String(entry.prefix)}`)).size !== allowedCidrs.length) {\n    throw new Error('allowedCidrs must not contain duplicates')\n  }\n  const deviceTtlMs = integer(value.deviceTtlMs, 'deviceTtlMs', 90 * 24 * 60 * 60_000, 60_000, 366 * 24 * 60 * 60_000)\n  const sessionTtlMs = integer(value.sessionTtlMs, 'sessionTtlMs', 8 * 60 * 60_000, 30_000, 24 * 60 * 60_000)\n  if (sessionTtlMs > deviceTtlMs) throw new Error('sessionTtlMs must not exceed deviceTtlMs')\n\n  return Object.freeze({\n    listenHost,\n    hostExecution: resolveHostExecution(value.hostExecution),\n    listenPort,\n    upstreamOrigin,\n    authorities: Object.freeze(authorities),\n    allowedCidrs: Object.freeze(allowedCidrs),\n    stateFile: absoluteFile(value.stateFile, 'stateFile'),\n    extensionsDir: join(dirname(absoluteFile(value.stateFile, 'stateFile')), 'extensions'),\n    customCssFile: value.customCssFile === undefined\n      ? join(dirname(absoluteFile(value.stateFile, 'stateFile')), 'mobile.css')\n      : absoluteFile(value.customCssFile, 'customCssFile'),\n    customScriptFile: value.customScriptFile === undefined\n      ? join(dirname(absoluteFile(value.stateFile, 'stateFile')), 'mobile.js')\n      : absoluteFile(value.customScriptFile, 'customScriptFile'),\n    mobileLayoutFile: value.mobileLayoutFile === undefined\n      ? fileURLToPath(new URL('./mobile-layout.js', import.meta.url))\n      : absoluteFile(value.mobileLayoutFile, 'mobileLayoutFile'),\n    mobileCompatibilityFile: value.mobileCompatibilityFile === undefined\n      ? fileURLToPath(new URL('./mobile-compat.js', import.meta.url))\n      : absoluteFile(value.mobileCompatibilityFile, 'mobileCompatibilityFile'),\n    excludedClientModules: excludedClientModules(value.excludedClientModules),\n    websocketCompression: parseWebSocketCompression(value.websocketCompression),\n    instanceId: value.instanceId === undefined\n      ? createHash('sha256').update(absoluteFile(value.stateFile, 'stateFile')).digest('hex')\n      : /^[a-f\\d]{64}$/u.test(value.instanceId)\n        ? value.instanceId\n        : (() => { throw new Error('instanceId must be a lowercase SHA-256 value') })(),\n    ...(value.pairingCaFile === undefined ? {} : { pairingCaFile: absoluteFile(value.pairingCaFile, 'pairingCaFile') }),\n    tls,\n    publicTls: tls.mode === 'provided',\n    discovery: true,\n    pairingTtlMs: integer(value.pairingTtlMs, 'pairingTtlMs', 120_000, 10_000, 600_000),\n    deviceTtlMs,\n    sessionTtlMs,\n    maxDevices: integer(value.maxDevices, 'maxDevices', 32, 1, 256),\n    maxSessions: integer(value.maxSessions, 'maxSessions', 64, 1, 1024),\n    maxConnections: integer(value.maxConnections, 'maxConnections', 64, 1, 1024),\n    maxActiveRequests: integer(value.maxActiveRequests, 'maxActiveRequests', 32, 1, 1024),\n    maxWebSockets: integer(value.maxWebSockets, 'maxWebSockets', 16, 1, 256),\n    maxBodyBytes: integer(value.maxBodyBytes, 'maxBodyBytes', 160 * 1024 * 1024, 1024, 256 * 1024 * 1024),\n    upstreamTimeoutMs: integer(value.upstreamTimeoutMs, 'upstreamTimeoutMs', 30_000, 1_000, 300_000),\n    upstreamApiTimeoutMs: integer(value.upstreamApiTimeoutMs, 'upstreamApiTimeoutMs', 0, 0, 2_147_483_647),\n    rateLimitWindowMs: integer(value.rateLimitWindowMs, 'rateLimitWindowMs', 60_000, 1_000, 3_600_000),\n    maxPairingAttempts: integer(value.maxPairingAttempts, 'maxPairingAttempts', 8, 1, 100),\n    maxRateLimitKeys: integer(value.maxRateLimitKeys, 'maxRateLimitKeys', 256, 1, 4096),\n  })\n}\n","import { execFile, type ExecFileOptions } from 'node:child_process'\n\n/** Capture both output streams even when a desktop host wraps execFile without Node's promisify metadata. */\nexport function execFileText(\n  file: string,\n  args: readonly string[],\n  options: Omit<ExecFileOptions, 'encoding'> & { encoding?: 'utf8' } = {},\n): Promise<{ stdout: string; stderr: string }> {\n  return new Promise((resolve, reject) => {\n    execFile(file, [...args], { windowsHide: true, ...options, encoding: 'utf8' }, (error, stdout, stderr) => {\n      if (error !== null) { reject(error); return }\n      if (typeof stdout !== 'string' || typeof stderr !== 'string') {\n        reject(new Error('subprocess returned invalid text output'))\n        return\n      }\n      resolve({ stdout, stderr })\n    })\n  })\n}\n","import { chmod } from 'node:fs/promises'\nimport { win32 } from 'node:path'\nimport { performance } from 'node:perf_hooks'\nimport { execFileText as execFile } from './exec-file.js'\n\nlet userSidTask: Promise<string> | undefined\n\n/** Windows permission operation that failed before the private file became usable. */\nexport type PrivateFilePermissionStage = 'sid-query' | 'acl-apply'\n\ninterface CommandFailureDetails {\n  readonly code?: string | number | null\n  readonly signal?: string | null\n  readonly killed?: boolean\n}\n\nfunction commandFailureDetails(error: unknown): CommandFailureDetails {\n  if (error === null || typeof error !== 'object') return {}\n  let descriptors: PropertyDescriptorMap\n  try { descriptors = Object.getOwnPropertyDescriptors(error) } catch (_error) {\n    // A host wrapper can supply an error whose proxy refuses inspection.\n    return {}\n  }\n  const code: unknown = descriptors.code?.value\n  const signal: unknown = descriptors.signal?.value\n  const killed: unknown = descriptors.killed?.value\n  return {\n    ...(code === null || (typeof code === 'number' && Number.isSafeInteger(code))\n      || (typeof code === 'string' && /^[A-Z][A-Z0-9_]{0,63}$/u.test(code)) ? { code } : {}),\n    ...(signal === null || (typeof signal === 'string' && /^SIG[A-Z0-9]{1,16}$/u.test(signal)) ? { signal } : {}),\n    ...(typeof killed === 'boolean' ? { killed } : {}),\n  }\n}\n\n/** Phase and full await duration, including subprocess creation, without arguments, output or private paths. */\nexport class PrivateFilePermissionError extends Error {\n  readonly code: string | number | null | undefined\n  readonly signal: string | null | undefined\n  readonly killed: boolean | undefined\n\n  constructor(readonly stage: PrivateFilePermissionStage, readonly elapsedMs: number, error: unknown) {\n    const details = commandFailureDetails(error)\n    const fields = [\n      ...(details.code === undefined ? [] : [`code=${String(details.code)}`]),\n      ...(details.signal === undefined ? [] : [`signal=${String(details.signal)}`]),\n      ...(details.killed === undefined ? [] : [`killed=${String(details.killed)}`]),\n    ]\n    const summary = `Windows private-file ${stage} failed after ${String(elapsedMs)} ms${fields.length === 0 ? '' : ` (${fields.join(', ')})`}`\n    // Cordis logs causes recursively; raw execFile errors can contain SID arguments and private paths.\n    const cause = Object.assign(new Error('Windows permission operation failed'), details)\n    super(summary, { cause })\n    this.name = 'PrivateFilePermissionError'\n    this.code = details.code\n    this.signal = details.signal\n    this.killed = details.killed\n  }\n}\n\nasync function permissionOperation<T>(stage: PrivateFilePermissionStage, operation: () => Promise<T>): Promise<T> {\n  const started = performance.now()\n  try { return await operation() } catch (error) {\n    throw new PrivateFilePermissionError(stage, Math.max(0, Math.round(performance.now() - started)), error)\n  }\n}\n\nfunction windowsSystemTool(name: 'whoami.exe' | 'icacls.exe'): string {\n  const systemRoot = process.env.SystemRoot ?? process.env.WINDIR\n  if (systemRoot === undefined || !win32.isAbsolute(systemRoot)) {\n    throw Object.assign(new Error('Windows system root is unavailable'), { code: 'WINDOWS_SYSTEM_ROOT_UNAVAILABLE' })\n  }\n  return win32.join(systemRoot, 'System32', name)\n}\n\nasync function currentWindowsUserSid(): Promise<string> {\n  userSidTask ??= permissionOperation('sid-query', async () => {\n    const { stdout } = await execFile(windowsSystemTool('whoami.exe'), ['/user', '/fo', 'csv', '/nh'], {\n      encoding: 'utf8',\n      windowsHide: true,\n      timeout: 10_000,\n    })\n    const match = /,\"(S-\\d(?:-\\d+)+)\"\\s*$/u.exec(stdout.trim())\n    if (match?.[1] === undefined) throw Object.assign(new Error('unable to resolve the current Windows user SID'), { code: 'WINDOWS_USER_SID_INVALID' })\n    return match[1]\n  }).catch((error: unknown) => {\n    userSidTask = undefined\n    throw error\n  })\n  return userSidTask\n}\n\n/** Restrict a sensitive regular file to the current user and Windows administrators; reject Windows permission failures with redacted phase and duration. */\nexport async function restrictPrivateFile(file: string, mode = 0o600): Promise<void> {\n  await chmod(file, mode)\n  if (process.platform !== 'win32') return\n  const userSid = await currentWindowsUserSid()\n  await permissionOperation('acl-apply', () => execFile(windowsSystemTool('icacls.exe'), [\n    file,\n    '/inheritance:r',\n    '/grant:r',\n    `*${userSid}:(F)`,\n    '*S-1-5-18:(F)',\n    '*S-1-5-32-544:(F)',\n    '/remove:g',\n    '*S-1-1-0',\n    '*S-1-5-11',\n    '*S-1-5-32-545',\n  ], { encoding: 'utf8', windowsHide: true, timeout: 10_000 }))\n}\n","import { randomBytes } from 'node:crypto'\nimport { lstat, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { basename, dirname, isAbsolute, join } from 'node:path'\nimport { restrictPrivateFile } from './private-file.js'\n\n/** Installed client module metadata, without upstream URLs or host paths. */\nexport interface ClientModuleEntry {\n  readonly id: string\n  readonly required: boolean\n  readonly dependencies: readonly string[]\n}\n\n/** Selection returned to the computer administrator or the authenticated device. */\nexport interface ClientModulePreferenceView {\n  readonly entries: readonly ClientModuleEntry[]\n  readonly excludedClientModules: readonly string[]\n  readonly defaultExcludedClientModules: readonly string[]\n  readonly source: 'device' | 'computer' | 'plugin'\n  readonly reloadRequired: true\n}\n\n/** Effective exclusion selection and the current computer default. */\nexport interface ClientModulePreferenceSelection {\n  readonly excludedClientModules: readonly string[]\n  readonly defaultExcludedClientModules: readonly string[]\n  readonly source: ClientModulePreferenceView['source']\n}\n\ninterface PreferenceRecord {\n  readonly version: 1\n  readonly computer?: readonly string[]\n  readonly devices: Readonly<Record<string, readonly string[]>>\n}\n\nconst MAX_RECORD_BYTES = 1024 * 1024\n\n/** Validate untrusted JSON selections; graph membership is checked by the Gateway. */\nexport function parseExcludedClientModules(value: unknown): readonly string[] {\n  if (!Array.isArray(value)\n    || value.some(id => typeof id !== 'string' || id.length === 0\n      || id.trim() !== id || /[\\u0000-\\u001f\\u007f]/u.test(id))) {\n    throw new Error('excluded_client_modules_invalid')\n  }\n  const ids = value as string[]\n  if (new Set(ids).size !== ids.length) throw new Error('excluded_client_modules_invalid')\n  return Object.freeze([...ids])\n}\n\nfunction deviceKey(deviceId: string): void {\n  if (!/^[a-f\\d]{32}$/u.test(deviceId)) throw new Error('client_module_device_invalid')\n}\n\nfunction parseRecord(value: unknown): PreferenceRecord {\n  if (value === null || typeof value !== 'object' || Array.isArray(value)) throw new Error('client_module_preferences_invalid')\n  const record = value as Record<string, unknown>\n  if (record.version !== 1 || record.devices === null || typeof record.devices !== 'object' || Array.isArray(record.devices)\n    || Object.keys(record).some(key => !['version', 'computer', 'devices'].includes(key))) throw new Error('client_module_preferences_invalid')\n  const devices: Record<string, readonly string[]> = {}\n  for (const [id, excluded] of Object.entries(record.devices)) { deviceKey(id); devices[id] = parseExcludedClientModules(excluded) }\n  return Object.freeze({\n    version: 1, devices: Object.freeze(devices),\n    ...(record.computer === undefined ? {} : { computer: parseExcludedClientModules(record.computer) }),\n  })\n}\n\n/** Atomic, serialized preferences shared by the LAN and remote Gateway instances. */\nexport class ClientModulePreferenceStore {\n  private readonly defaults: readonly string[]\n  private value: PreferenceRecord = Object.freeze({ version: 1, devices: Object.freeze({}) })\n  private initialization: Promise<void> | undefined\n  private queue: Promise<void> = Promise.resolve()\n\n  constructor(readonly file: string, defaults: readonly string[]) {\n    if (!isAbsolute(file)) throw new Error('client module preference path must be absolute')\n    this.defaults = parseExcludedClientModules(defaults)\n  }\n\n  /** Read existing state once. Missing state is not written during initialization. */\n  initialize(): Promise<void> {\n    this.initialization ??= this.load()\n    return this.initialization\n  }\n\n  private async load(): Promise<void> {\n    let information\n    try { information = await lstat(this.file) } catch (error) {\n      if ((error as NodeJS.ErrnoException).code === 'ENOENT') return\n      throw error\n    }\n    if (!information.isFile() || information.isSymbolicLink() || information.size > MAX_RECORD_BYTES) {\n      throw new Error('client module preferences must be a regular file no larger than 1 MiB')\n    }\n    this.value = parseRecord(JSON.parse(await readFile(this.file, 'utf8')))\n  }\n\n  private selection(deviceId?: string): ClientModulePreferenceSelection {\n    if (deviceId !== undefined) deviceKey(deviceId)\n    const computer = this.value.computer ?? this.defaults\n    const device = deviceId === undefined ? undefined : this.value.devices[deviceId]\n    return Object.freeze({\n      excludedClientModules: device ?? computer,\n      defaultExcludedClientModules: computer,\n      source: device !== undefined ? 'device' : this.value.computer !== undefined ? 'computer' : 'plugin',\n    })\n  }\n\n  private exclusive<T>(action: () => Promise<T>): Promise<T> {\n    const operation = this.queue.then(action)\n    this.queue = operation.then(() => undefined, () => undefined)\n    return operation\n  }\n\n  /** Resolve one device override, otherwise the computer or plugin default. */\n  async read(deviceId?: string): Promise<ClientModulePreferenceSelection> {\n    await this.initialize()\n    return this.exclusive(async () => this.selection(deviceId))\n  }\n\n  /** Revalidate against the current boot manifest inside the serialized mutation. */\n  async configure(\n    excluded: unknown,\n    deviceId: string | undefined,\n    validate: (selection: readonly string[]) => Promise<void>,\n  ): Promise<ClientModulePreferenceSelection> {\n    const ids = parseExcludedClientModules(excluded)\n    if (deviceId !== undefined) deviceKey(deviceId)\n    await this.initialize()\n    return this.exclusive(async () => {\n      await validate(ids)\n      const next: PreferenceRecord = deviceId === undefined\n        ? { ...this.value, computer: ids }\n        : { ...this.value, devices: { ...this.value.devices, [deviceId]: ids } }\n      await this.save(next)\n      return this.selection(deviceId)\n    })\n  }\n\n  /** Remove only the selected override; retain all other device selections. */\n  async reset(deviceId: string | undefined, validate: (selection: readonly string[]) => Promise<void>): Promise<ClientModulePreferenceSelection> {\n    if (deviceId !== undefined) deviceKey(deviceId)\n    await this.initialize()\n    return this.exclusive(async () => {\n      const devices = { ...this.value.devices }\n      if (deviceId !== undefined) delete devices[deviceId]\n      const next: PreferenceRecord = {\n        version: 1, devices,\n        ...(deviceId === undefined || this.value.computer === undefined ? {} : { computer: this.value.computer }),\n      }\n      const effective = deviceId === undefined ? this.defaults : this.value.computer ?? this.defaults\n      await validate(effective)\n      await this.save(next)\n      return this.selection(deviceId)\n    })\n  }\n\n  /** Remove exactly the revoked device's record without evaluating its obsolete graph. */\n  removeDevice(deviceId: string): Promise<void> {\n    return this.removeDevices([deviceId])\n  }\n\n  /** Remove an explicit set of revoked identities, not every record in the shared store. */\n  async removeDevices(deviceIds: readonly string[]): Promise<void> {\n    for (const deviceId of deviceIds) deviceKey(deviceId)\n    await this.initialize()\n    await this.exclusive(async () => {\n      if (!deviceIds.some(id => this.value.devices[id] !== undefined)) return\n      const devices = { ...this.value.devices }\n      for (const deviceId of deviceIds) delete devices[deviceId]\n      await this.save({ ...this.value, devices })\n    })\n  }\n\n  private async save(record: PreferenceRecord): Promise<void> {\n    const valid = parseRecord(record)\n    const body = `${JSON.stringify(valid)}\\n`\n    if (Buffer.byteLength(body) > MAX_RECORD_BYTES) throw new Error('client_module_preferences_limit')\n    const directory = dirname(this.file)\n    const created = await mkdir(directory, { recursive: true, mode: 0o700 })\n    if (created !== undefined) await restrictPrivateFile(directory, 0o700)\n    try {\n      const existing = await lstat(this.file)\n      if (!existing.isFile() || existing.isSymbolicLink()) throw new Error('client module preference target must be a regular file')\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n    }\n    const temporary = join(directory, `.${basename(this.file)}.${randomBytes(12).toString('hex')}.tmp`)\n    try {\n      await writeFile(temporary, body, { encoding: 'utf8', flag: 'wx', mode: 0o600 })\n      await restrictPrivateFile(temporary)\n      await rename(temporary, this.file)\n      this.value = valid\n    } catch (error) {\n      try { await rm(temporary, { force: true }) } catch (cleanupError) {\n        throw new AggregateError([error, cleanupError], 'client module preference write and temporary cleanup failed')\n      }\n      throw error\n    }\n  }\n}\n","import { randomBytes } from 'node:crypto'\nimport { lstat, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { basename, dirname, join } from 'node:path'\nimport { restrictPrivateFile } from './private-file.js'\n\n/** Versioned durable preference for the resident mobile-access runtime. */\nexport interface MobileAccessControlState {\n  readonly version: 1\n  readonly enabled: boolean\n}\n\n/** Persistence seam for the runtime preference. */\nexport interface MobileAccessControlStore {\n  load(): Promise<MobileAccessControlState>\n  save(state: MobileAccessControlState): Promise<void>\n}\n\n/** One started gateway runtime owned by the controller. */\nexport interface MobileAccessRuntime {\n  close(): Promise<void>\n}\n\n/** One address-specific runtime selected from the current LAN state. */\nexport interface MobileAccessRuntimeSelection {\n  readonly key: string\n  start(): Promise<MobileAccessRuntime>\n}\n\n/** Keeps one runtime aligned with a changing network selection. */\nexport class FollowingMobileAccessRuntime implements MobileAccessRuntime {\n  private runtime: MobileAccessRuntime | undefined\n  private key: string | undefined\n  private queue: Promise<void> = Promise.resolve()\n  private closed = false\n  private timer: ReturnType<typeof setInterval> | undefined\n\n  constructor(\n    private readonly select: () => Promise<MobileAccessRuntimeSelection>,\n    private readonly onRefreshError: (error: unknown) => void,\n  ) {}\n\n  /** Start the current selection and optionally poll for later changes. */\n  async initialize(refreshIntervalMs?: number): Promise<void> {\n    await this.refresh()\n    if (refreshIntervalMs === undefined) return\n    this.beginPolling(refreshIntervalMs)\n  }\n\n  /**\n   * Arm the refresh poller without requiring an initial selection.\n   * Boot-degraded path: the first selection already failed (e.g. the saved\n   * LAN is down), but later refreshes must still get their chance so a\n   * returning network recovers without a restart. Failures keep flowing to\n   * onRefreshError; close() stays the single teardown.\n   */\n  beginPolling(refreshIntervalMs: number): void {\n    if (this.timer !== undefined) return\n    this.timer = setInterval(() => {\n      void this.refresh().catch(this.onRefreshError)\n    }, refreshIntervalMs)\n    this.timer.unref()\n  }\n\n  /** Reconcile the active runtime with the latest selection. */\n  refresh(): Promise<void> {\n    return this.enqueue(async () => {\n      if (this.closed) return\n      const selection = await this.select()\n      if (this.closed || (this.runtime !== undefined && this.key === selection.key)) return\n      const previous = this.runtime\n      this.runtime = undefined\n      this.key = undefined\n      if (previous !== undefined) await previous.close()\n      this.runtime = await selection.start()\n      this.key = selection.key\n    })\n  }\n\n  /** Stop polling and close the most recently selected runtime. */\n  close(): Promise<void> {\n    if (this.closed) return this.queue\n    this.closed = true\n    if (this.timer !== undefined) clearInterval(this.timer)\n    return this.enqueue(async () => {\n      const runtime = this.runtime\n      this.runtime = undefined\n      this.key = undefined\n      if (runtime !== undefined) await runtime.close()\n    })\n  }\n\n  private enqueue(operation: () => Promise<void>): Promise<void> {\n    const run = this.queue.then(operation, operation)\n    this.queue = run.then(() => {}, () => {})\n    return run\n  }\n}\n\n/** Validate control state loaded across the filesystem boundary. */\nexport function parseMobileAccessControlState(value: unknown): MobileAccessControlState {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n    throw new Error('mobile-access control state must be an object')\n  }\n  const record = value as Record<string, unknown>\n  if (record.version !== 1 || typeof record.enabled !== 'boolean'\n    || Reflect.ownKeys(record).some(key => key !== 'version' && key !== 'enabled')) {\n    throw new Error('mobile-access control state has an unsupported format')\n  }\n  return Object.freeze({ version: 1, enabled: record.enabled })\n}\n\n/** Atomic JSON store whose absent-file state comes from the installation-time default. */\nexport class JsonMobileAccessControlStore implements MobileAccessControlStore {\n  constructor(private readonly file: string, private readonly initiallyEnabled: boolean) {}\n\n  /** Disable an existing preference, returning the state only after private-file preparation completes. */\n  async disableIfPresent(): Promise<MobileAccessControlState> {\n    const disabled: MobileAccessControlState = Object.freeze({ version: 1, enabled: false })\n    try {\n      await lstat(this.file)\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n        if (this.initiallyEnabled) await this.save(disabled)\n        return disabled\n      }\n      throw error\n    }\n    await this.save(disabled)\n    return disabled\n  }\n\n  async load(): Promise<MobileAccessControlState> {\n    let stat\n    try {\n      stat = await lstat(this.file)\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n        return Object.freeze({ version: 1, enabled: this.initiallyEnabled })\n      }\n      throw error\n    }\n    if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 4096) {\n      throw new Error('mobile-access control state must be a regular file no larger than 4 KiB')\n    }\n    await restrictPrivateFile(this.file)\n    let parsed: unknown\n    try {\n      parsed = JSON.parse(await readFile(this.file, 'utf8')) as unknown\n    } catch (error) {\n      throw new Error('mobile-access control state is not valid JSON', { cause: error })\n    }\n    return parseMobileAccessControlState(parsed)\n  }\n\n  async save(state: MobileAccessControlState): Promise<void> {\n    const validated = parseMobileAccessControlState(state)\n    const directory = dirname(this.file)\n    await mkdir(directory, { recursive: true, mode: 0o700 })\n    try {\n      const current = await lstat(this.file)\n      if (!current.isFile() || current.isSymbolicLink()) {\n        throw new Error('mobile-access control state target must remain a regular file')\n      }\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n    }\n    const temporary = join(directory, `.${basename(this.file)}.${randomBytes(12).toString('hex')}.tmp`)\n    try {\n      await writeFile(temporary, `${JSON.stringify(validated)}\\n`, {\n        encoding: 'utf8',\n        flag: 'wx',\n        mode: 0o600,\n      })\n      await restrictPrivateFile(temporary)\n      await rename(temporary, this.file)\n    } catch (error) {\n      try {\n        await rm(temporary, { force: true })\n      } catch (cleanupError) {\n        throw new AggregateError([error, cleanupError], 'control state write and temporary cleanup both failed')\n      }\n      throw error\n    }\n  }\n}\n\n/** Serialized persistent lifecycle for the gateway behind the always-loaded Cordis entry. */\nexport class MobileAccessGatewayController {\n  private runtime: MobileAccessRuntime | undefined\n  private initialized = false\n  private closing = false\n  private queue: Promise<void> = Promise.resolve()\n  private closeTask: Promise<void> | undefined\n\n  constructor(\n    private readonly store: MobileAccessControlStore,\n    private readonly startRuntime: () => Promise<MobileAccessRuntime>,\n  ) {}\n\n  /** Load the durable preference and start the first runtime when enabled. */\n  initialize(): Promise<void> {\n    return this.enqueue(async () => {\n      if (this.initialized) throw new Error('mobile-access control is already initialized')\n      if (this.closing) throw new Error('mobile-access control is closing')\n      const state = await this.store.load()\n      if (state.enabled) this.runtime = await this.startRuntime()\n      this.initialized = true\n    })\n  }\n\n  /** Return the committed in-process runtime state. */\n  isRunning(): boolean {\n    return this.runtime !== undefined\n  }\n\n  /** Start or stop the runtime and persist only a successfully committed transition. */\n  setRunning(running: boolean): Promise<void> {\n    if (this.closing) return Promise.reject(new Error('mobile-access control is closing'))\n    return this.enqueue(async () => {\n      if (!this.initialized) throw new Error('mobile-access control is not initialized')\n      if (this.isRunning() === running) return\n      if (running) {\n        await this.enable()\n      } else {\n        await this.disable()\n      }\n    })\n  }\n\n  /** Stop the runtime after earlier transitions without changing the restart preference. */\n  close(): Promise<void> {\n    if (this.closeTask !== undefined) return this.closeTask\n    this.closing = true\n    this.closeTask = this.enqueue(async () => {\n      const runtime = this.runtime\n      if (runtime === undefined) return\n      await runtime.close()\n      this.runtime = undefined\n    })\n    return this.closeTask\n  }\n\n  private async enable(): Promise<void> {\n    const candidate = await this.startRuntime()\n    try {\n      await this.store.save({ version: 1, enabled: true })\n    } catch (error) {\n      try {\n        await candidate.close()\n      } catch (rollbackError) {\n        throw new AggregateError([error, rollbackError], 'enabling mobile access failed and runtime rollback also failed')\n      }\n      throw error\n    }\n    this.runtime = candidate\n  }\n\n  private async disable(): Promise<void> {\n    const previous = this.runtime\n    if (previous === undefined) return\n    await previous.close()\n    try {\n      await this.store.save({ version: 1, enabled: false })\n    } catch (error) {\n      try {\n        this.runtime = await this.startRuntime()\n      } catch (rollbackError) {\n        this.runtime = undefined\n        throw new AggregateError([error, rollbackError], 'disabling mobile access failed and runtime rollback also failed')\n      }\n      throw error\n    }\n    this.runtime = undefined\n  }\n\n  private enqueue(operation: () => Promise<void>): Promise<void> {\n    const run = this.queue.then(operation, operation)\n    this.queue = run.then(() => {}, () => {})\n    return run\n  }\n}\n","/** Authenticated recovery document for a saved module selection that cannot boot the current DSH graph. */\nimport type { AuthPageLocale } from './auth-pages.js'\n\nexport const CLIENT_MODULE_RECOVERY_COPY = {\n  zh: {\n    title: '移动页面模块需要调整',\n    explanation: '电脑上的插件或依赖关系已变化，之前保存的模块选择无法加载当前页面。',\n    scope: '可为本设备加载全部模块并重新打开 DSH。不会修改电脑默认设置、其他设备或已安装的插件。',\n    action: '为本设备加载全部模块并重试',\n    working: '正在更新本设备的模块选择…',\n    failed: '未能恢复。请确认电脑和远程通道仍在线，然后重试。',\n  },\n  en: {\n    title: 'Mobile page modules need attention',\n    explanation: 'The computer’s plugins or dependencies have changed. The saved module selection can no longer load this page.',\n    scope: 'Load all modules for this device and reopen DSH. Computer defaults, other devices, and installed plugins are unchanged.',\n    action: 'Load all modules for this device and retry',\n    working: 'Updating this device’s module selection…',\n    failed: 'Could not restore the page. Check that the computer and remote connection are online, then retry.',\n  },\n  it: {\n    title: 'I moduli della pagina mobile richiedono attenzione',\n    explanation: 'I plugin o le dipendenze del computer sono cambiati. La selezione salvata non può più caricare questa pagina.',\n    scope: 'Carica tutti i moduli per questo dispositivo e riapri DSH. I predefiniti del computer, gli altri dispositivi e i plugin installati non cambiano.',\n    action: 'Carica tutti i moduli per questo dispositivo e riprova',\n    working: 'Aggiornamento dei moduli per questo dispositivo…',\n    failed: 'Ripristino non riuscito. Verifica che il computer e la connessione remota siano online, poi riprova.',\n  },\n} as const\n\n/** Render an explicit device-only recovery action without interpolating graph diagnostics or credentials.\n * @param locale - Negotiated browser display language.\n * @returns An owned HTML page which changes no selection until the user activates its button.\n */\nexport function renderClientModuleRecoveryPage(locale: AuthPageLocale): string {\n  const copy = CLIENT_MODULE_RECOVERY_COPY[locale]\n  return `<!doctype html>\n<html lang=\"${locale === 'zh' ? 'zh-CN' : locale}\">\n<head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1,viewport-fit=cover\">\n<meta name=\"color-scheme\" content=\"light dark\"><title>${copy.title}</title>\n<style>\nbody{margin:0;background:Canvas;color:CanvasText;font:16px/1.5 system-ui,sans-serif}\nmain{box-sizing:border-box;max-width:640px;margin:32px auto;padding:24px max(24px,env(safe-area-inset-left)) 24px max(24px,env(safe-area-inset-right));overflow-wrap:anywhere}\nh1{font-size:24px;line-height:1.3}button{min-height:48px;max-width:100%;padding:12px 20px;border:1px solid ButtonText;border-radius:12px;background:ButtonFace;color:ButtonText;font:inherit;cursor:pointer}\nbutton:focus-visible{outline:2px solid Highlight;outline-offset:3px}button:disabled{opacity:.6;cursor:wait}#recovery-status{min-height:1.5em}\n</style></head>\n<body><main><h1>${copy.title}</h1><p>${copy.explanation}</p><p>${copy.scope}</p>\n<button id=\"load-all-modules\" type=\"button\">${copy.action}</button><p id=\"recovery-status\" role=\"status\" aria-live=\"polite\"></p>\n</main><script>${renderClientModuleRecoveryScript(locale)}</script></body></html>\n`\n}\n\n/** Render the fixed same-origin action; CSRF values are read from the active browser cookie only at user activation.\n * @param locale - Negotiated browser display language.\n * @returns JavaScript that preserves selections on failure and reloads only after an authorized save succeeds.\n */\nexport function renderClientModuleRecoveryScript(locale: AuthPageLocale): string {\n  const copy = CLIENT_MODULE_RECOVERY_COPY[locale]\n  return `(() => {\n  const button = document.getElementById('load-all-modules')\n  const status = document.getElementById('recovery-status')\n  button.addEventListener('click', async () => {\n    if (button.disabled) return\n    button.disabled = true\n    status.textContent = ${JSON.stringify(copy.working)}\n    try {\n      const values = document.cookie.split(';').map(value => value.trim())\n      const host = values.filter(value => value.startsWith('__Host-dsh_ma_csrf='))\n      const candidates = host.length === 0 ? values.filter(value => value.startsWith('dsh_ma_csrf=')) : host\n      if (candidates.length !== 1) throw new Error('csrf_unavailable')\n      const csrf = candidates[0].slice(candidates[0].indexOf('=') + 1)\n      const response = await fetch('/mobile-access/client-modules', {\n        method: 'POST', credentials: 'same-origin', redirect: 'error', cache: 'no-store',\n        headers: { 'content-type': 'application/json', 'x-dsh-mobile-csrf': csrf },\n        body: JSON.stringify({ excludedClientModules: [] }),\n      })\n      if (!response.ok) throw new Error('recovery_failed')\n      location.reload()\n    } catch {\n      status.textContent = ${JSON.stringify(copy.failed)}\n      button.disabled = false\n    }\n  })\n})()`\n}\n","/** Browser-safe desktop-admin Host checks. Do not import Node APIs here. */\n\nexport const DESKTOP_ADMIN_HEADER = 'x-dsh-mobile-desktop-admin'\nexport const DESKTOP_ADMIN_MARKER = 'dsh-app://app'\n\n/** Add the forwarded Desktop marker only to this plugin's mutating admin requests. */\nexport function localAdminRequestHeaders(\n  init: RequestInit | undefined,\n  location: Pick<Location, 'hostname' | 'protocol'>,\n): Headers {\n  const headers = new Headers(init?.headers)\n  if (!headers.has('content-type')) headers.set('content-type', 'application/json')\n  headers.delete(DESKTOP_ADMIN_HEADER)\n  if (init?.method?.toUpperCase() === 'POST' && location.protocol === 'dsh-app:' && location.hostname === 'app') {\n    headers.set(DESKTOP_ADMIN_HEADER, DESKTOP_ADMIN_MARKER)\n  }\n  return headers\n}\n\nfunction unwrapBrackets(hostname: string): string {\n  return hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname\n}\n\nfunction parseIpv4(hostname: string): readonly [number, number, number, number] | undefined {\n  const parts = hostname.split('.')\n  if (parts.length !== 4) return undefined\n  const octets: number[] = []\n  for (const part of parts) {\n    if (!/^(?:0|[1-9]\\d{0,2})$/u.test(part)) return undefined\n    const value = Number(part)\n    if (value > 255) return undefined\n    octets.push(value)\n  }\n  return octets as [number, number, number, number]\n}\n\nfunction isLoopbackIpv4(octets: readonly [number, number, number, number]): boolean {\n  return octets[0] === 127\n}\n\nfunction isPrivateIpv4(octets: readonly [number, number, number, number]): boolean {\n  return octets[0] === 10\n    || (octets[0] === 172 && octets[1] >= 16 && octets[1] <= 31)\n    || (octets[0] === 192 && octets[1] === 168)\n}\n\nfunction isLinkLocalIpv4(octets: readonly [number, number, number, number]): boolean {\n  return octets[0] === 169 && octets[1] === 254\n}\n\n/**\n * Hostnames that may appear on the DSH desktop admin surface.\n * Loopback, RFC1918, and IPv4 link-local are accepted. Public IPs,\n * CGNAT, and arbitrary DNS names stay rejected so DNS rebinding\n * cannot reach `/api/mobile-access`.\n */\nexport function isLocalAdminHostname(hostname: string): boolean {\n  const host = unwrapBrackets(hostname).trim().toLowerCase()\n  if (host === 'localhost' || host === '::1') return true\n  const octets = parseIpv4(host)\n  if (octets === undefined) return false\n  return isLoopbackIpv4(octets) || isPrivateIpv4(octets) || isLinkLocalIpv4(octets)\n}\n\n/**\n * Whether the current browser document should mount the desktop Mobile access\n * control. Dedicated Mobile HTTPS (the phone surface) stays native even when\n * the Host is a private LAN address. DSH Desktop (dsh-app://app) has neither,\n * so its protocol gated on the fixed hostname \"app\" counts too.\n */\nexport function isDesktopAdminSurface(\n  hostname: string,\n  search = '',\n  frontend?: string,\n  protocol = '',\n): boolean {\n  const query = search.startsWith('?') ? search.slice(1) : search\n  return (protocol === 'dsh-app:' ? hostname === 'app' : (protocol === '' || protocol === 'http:' || protocol === 'https:') && isLocalAdminHostname(hostname))\n    && frontend !== 'dedicated'\n    && !new URLSearchParams(query).has('dsh-mobile-preview')\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http'\nimport { addressAllowed, isLoopbackAddress, RequestTrustPolicy } from './network.js'\nimport { DESKTOP_ADMIN_HEADER, DESKTOP_ADMIN_MARKER, isLocalAdminHostname } from './local-admin-host.js'\n\nexport const DEVICE_COOKIE = 'dsh_ma_device'\nexport const SESSION_COOKIE = 'dsh_ma_session'\nexport const CSRF_COOKIE = 'dsh_ma_csrf'\nexport const CSRF_HEADER = 'x-dsh-mobile-csrf'\nexport const LOCAL_ADMIN_PREFIX = '/api/mobile-access'\nexport const AUTH_PREFIX = '/mobile-access'\nexport const WS_PATHS = new Set([\n  '/api/events.mux',\n  '/api/events.host',\n  '/api/remote.mux',\n  // DSH desktop UI's sidebar terminal (renderer-v2) upgrades through this\n  // exact path with a session query string; it is a first-party DSH surface.\n  '/sidebar/ws/terminal',\n])\n\n/** Terse request failure safe to expose without internal diagnostics. */\nexport class HttpError extends Error {\n  constructor(readonly status: number, readonly code: string) {\n    super(code)\n    this.name = 'HttpError'\n  }\n}\n\n/** Parsed origin-form request target with a decoded path for protected-prefix checks. */\nexport interface RequestTarget {\n  readonly raw: string\n  readonly pathname: string\n  readonly decodedPathname: string\n  readonly search: string\n}\n\n/** Parse only origin-form request targets and reject ambiguous slash encodings. */\nexport function parseRequestTarget(raw: string | undefined): RequestTarget {\n  if (raw === undefined || !raw.startsWith('/') || raw.startsWith('//') || raw.includes('\\\\') || /[\\u0000-\\u001f\\u007f]/u.test(raw)) {\n    throw new HttpError(400, 'bad_request')\n  }\n  let parsed: URL\n  let decodedPathname: string\n  try {\n    parsed = new URL(raw, 'http://gateway.invalid')\n    decodedPathname = decodeURIComponent(parsed.pathname)\n  } catch {\n    throw new HttpError(400, 'bad_request')\n  }\n  if (decodedPathname.includes('\\\\') || decodedPathname.startsWith('//') || /[\\u0000-\\u001f\\u007f]/u.test(decodedPathname)) {\n    throw new HttpError(400, 'bad_request')\n  }\n  return Object.freeze({ raw, pathname: parsed.pathname, decodedPathname, search: parsed.search })\n}\n\n/**\n * Which framing policy a response carries.\n *\n * - `gateway`: the gateway's OWN documents (login, pairing, the CA helper) and\n *   its JSON/SSE responses. Nothing may frame them at all.\n * - `proxied`: the upstream DSH GUI and its routes, forwarded through the\n *   gateway. The GUI must be able to frame its OWN same-origin surfaces (the\n *   sidebar's HTML/diff preview routes, the browser tab pointed at the GUI\n *   itself) and the sidebar browser tab must be able to frame external http(s)\n *   sites plus `blob:` PDF previews — a plain `default-src 'self'` with no\n *   `frame-src` refuses all of them, which is what broke the sidebar browser\n *   over remote access.\n */\nexport type FramingPolicy = 'gateway' | 'proxied'\n\n/**\n * The frame sources a proxied GUI document may embed: its own routes, blob:\n * (the PDF viewer's object URL) and external http(s) pages (the sidebar\n * browser tab). The framed document runs in the tab's existing sandbox\n * (opaque origin, no same-origin privileges), so this does not hand the\n * embedded page anything it did not already have.\n */\nconst PROXIED_FRAME_SRC = \"frame-src 'self' blob: https: http:\"\n\n/**\n * Set the gateway browser protections and non-cacheability.\n * @param response - the response to decorate.\n * @param tls - whether the connection is TLS (adds HSTS).\n * @param framing - the framing policy; defaults to the strict gateway one, so\n *   every existing call site keeps refusing to be framed. Only the two PROXIED\n *   forwarders pass `'proxied'`.\n */\nexport function setSecurityHeaders(response: ServerResponse, tls: boolean, framing: FramingPolicy = 'gateway'): void {\n  const proxied = framing === 'proxied'\n  response.setHeader('Cache-Control', 'no-store')\n  // DSH emits inline boot code, revives Schemastery callbacks, and applies dynamic styles.\n  // These allowances provide compatibility, not XSS isolation.\n  response.setHeader('Content-Security-Policy', [\n    \"default-src 'self'\",\n    \"base-uri 'none'\",\n    \"object-src 'none'\",\n    // A proxied GUI is frameable by ITS OWN origin only (its preview routes and\n    // the sidebar's page routes); every third-party origin stays refused, so\n    // clickjacking protection is unchanged for the gateway's own documents.\n    proxied ? \"frame-ancestors 'self'\" : \"frame-ancestors 'none'\",\n    \"form-action 'self'\",\n    \"script-src 'self' 'unsafe-inline' 'unsafe-eval'\",\n    \"style-src 'self' 'unsafe-inline'\",\n    \"img-src 'self' data: blob:\",\n    \"font-src 'self' data:\",\n    \"connect-src 'self'\",\n    \"worker-src 'self' blob:\",\n    // `frame-src` has no allow-by-default: the sidebar browser tab embeds\n    // cross-origin pages, which only an explicit frame-src admits.\n    ...(proxied ? [PROXIED_FRAME_SRC] : []),\n  ].join('; '))\n  // The proxied GUI document owns local voice input: DSH's voice-input plugin\n  // records through `getUserMedia`, which a bare `microphone=()` refuses before\n  // any prompt. Only that document widens the microphone to itself; the\n  // gateway's own pages and every other feature stay refused.\n  const microphone = proxied ? 'microphone=(self)' : 'microphone=()'\n  response.setHeader('Permissions-Policy', `camera=(), ${microphone}, geolocation=(), payment=(), usb=()`)\n  response.setHeader('Referrer-Policy', 'no-referrer')\n  response.setHeader('X-Content-Type-Options', 'nosniff')\n  // The legacy twin of frame-ancestors: SAMEORIGIN keeps older engines aligned\n  // with the proxied policy instead of refusing the GUI's own frames.\n  response.setHeader('X-Frame-Options', proxied ? 'SAMEORIGIN' : 'DENY')\n  response.setHeader('Cross-Origin-Resource-Policy', 'same-origin')\n  if (tls) response.setHeader('Strict-Transport-Security', 'max-age=31536000')\n}\n\n/** Send a bounded JSON response without reflecting request or upstream data. */\nexport function sendJson(response: ServerResponse, status: number, value: unknown, tls: boolean): void {\n  if (response.headersSent || response.destroyed) return\n  setSecurityHeaders(response, tls)\n  const body = `${JSON.stringify(value)}\\n`\n  response.writeHead(status, {\n    'Content-Type': 'application/json; charset=utf-8',\n    'Content-Length': Buffer.byteLength(body),\n  })\n  response.end(body)\n}\n\n/** Send a generic failure containing only a stable category. */\nexport function sendFailure(response: ServerResponse, status: number, code: string, tls: boolean): void {\n  sendJson(response, status, { error: code }, tls)\n}\n\n/** Read and parse one bounded JSON object. */\nexport async function readJsonObject(request: IncomingMessage, maximumBytes: number): Promise<Record<string, unknown>> {\n  const contentType = request.headers['content-type']?.split(';', 1)[0]?.trim().toLowerCase()\n  if (contentType !== 'application/json') throw new HttpError(415, 'unsupported_media_type')\n  const declared = request.headers['content-length']\n  if (declared !== undefined) {\n    if (!/^\\d+$/u.test(declared) || Number(declared) > maximumBytes) throw new HttpError(413, 'payload_too_large')\n  }\n  const chunks: Buffer[] = []\n  let total = 0\n  for await (const chunk of request) {\n    const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n    total += buffer.length\n    if (total > maximumBytes) throw new HttpError(413, 'payload_too_large')\n    chunks.push(buffer)\n  }\n  let parsed: unknown\n  try {\n    parsed = JSON.parse(Buffer.concat(chunks).toString('utf8')) as unknown\n  } catch {\n    throw new HttpError(400, 'bad_request')\n  }\n  if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) throw new HttpError(400, 'bad_request')\n  return parsed as Record<string, unknown>\n}\n\n/** Strict cookie parser: malformed or duplicate names invalidate the whole header. */\nexport function parseCookies(header: string | undefined): ReadonlyMap<string, string> | undefined {\n  if (header === undefined) return new Map()\n  if (header.length > 8192) return undefined\n  const cookies = new Map<string, string>()\n  for (const part of header.split(';')) {\n    const equals = part.indexOf('=')\n    if (equals <= 0) return undefined\n    const name = part.slice(0, equals).trim()\n    const value = part.slice(equals + 1).trim()\n    if (!/^[!#$%&'*+\\-.^_`|~\\dA-Za-z]+$/u.test(name) || !/^[\\w\\-.~+/=]*$/u.test(value) || cookies.has(name)) {\n      return undefined\n    }\n    cookies.set(name, value)\n  }\n  return cookies\n}\n\n/** Serialize a host-only Cookie with no Domain attribute. */\nexport function cookie(\n  name: string,\n  value: string,\n  options: { tls: boolean; httpOnly: boolean; path: string; maxAgeSeconds: number },\n): string {\n  const parts = [\n    `${name}=${value}`,\n    `Path=${options.path}`,\n    `Max-Age=${String(Math.max(0, Math.floor(options.maxAgeSeconds)))}`,\n    'SameSite=Strict',\n    'Priority=High',\n  ]\n  if (options.tls) parts.push('Secure')\n  if (options.httpOnly) parts.push('HttpOnly')\n  return parts.join('; ')\n}\n\n/** Enforce direct CIDR, exact Host, and browser same-origin facts. */\nexport function assertExternalTrust(request: IncomingMessage, policy: RequestTrustPolicy, requireOrigin: boolean): void {\n  if (!addressAllowed(request.socket.remoteAddress, policy.cidrs) || !policy.acceptsHost(request.headers.host)) {\n    throw new HttpError(403, 'forbidden')\n  }\n  const origin = request.headers.origin\n  if (origin !== undefined && !policy.acceptsOrigin(origin)) throw new HttpError(403, 'forbidden')\n  const site = request.headers['sec-fetch-site']\n  // 微信小程序（wx.request / wx.connectSocket）的 Sec-Fetch-Site 由微信自动附加\n  // （same-origin / same-site / cross-site），客户端无法控制，也不代表真实跨站攻击；\n  // CSRF 防护的核心是下方对 Origin 的强制校验，因此这里接受全部合法取值。\n  if (site !== undefined && site !== 'same-origin' && site !== 'same-site' && site !== 'cross-site' && site !== 'none') throw new HttpError(403, 'forbidden')\n  // POST 只强制 Origin 正确。\n  if (requireOrigin && !policy.acceptsOrigin(origin)) throw new HttpError(403, 'forbidden')\n}\n\nfunction localAuthority(header: string | undefined): { hostname: string; authority: string } | undefined {\n  if (header === undefined || /[/?#@\\\\]/u.test(header)) return undefined\n  try {\n    const url = new URL(`http://${header}`)\n    if (url.pathname !== '/' || url.username !== '' || url.password !== '') return undefined\n    return { hostname: url.hostname, authority: url.host.toLowerCase() }\n  } catch {\n    return undefined\n  }\n}\n\n/** Protect the inner management route from non-loopback and DNS-rebinding callers. */\nexport function assertLocalAdminTrust(\n  request: IncomingMessage,\n  requireBrowserOrigin: boolean,\n  authenticateDesktop: () => boolean = () => false,\n): void {\n  if (request.socket.remoteAddress === undefined || !isLoopbackAddress(request.socket.remoteAddress)) {\n    throw new HttpError(403, 'forbidden')\n  }\n  const host = localAuthority(request.headers.host)\n  if (host === undefined || !isLocalAdminHostname(host.hostname)) {\n    throw new HttpError(403, 'forbidden')\n  }\n  const site = request.headers['sec-fetch-site']\n  if (site !== undefined && site !== 'same-origin' && site !== 'none') throw new HttpError(403, 'forbidden')\n  const origin = request.headers.origin\n  if (origin !== undefined) {\n    try {\n      const parsed = new URL(origin)\n      if (parsed.host.toLowerCase() !== host.authority || (parsed.protocol !== 'http:' && parsed.protocol !== 'https:')) {\n        throw new HttpError(403, 'forbidden')\n      }\n    } catch (error) {\n      if (error instanceof HttpError) throw error\n      throw new HttpError(403, 'forbidden')\n    }\n  }\n  // Desktop strips Origin and Sec-Fetch-Site before forwarding, but preserves\n  // this plugin's non-simple request header. An unrelated browser origin cannot\n  // send that header through CORS; a local process could already forge Origin.\n  const desktopForward = site === undefined && request.headers[DESKTOP_ADMIN_HEADER] === DESKTOP_ADMIN_MARKER\n  if (requireBrowserOrigin && origin === undefined && !(desktopForward && authenticateDesktop())) {\n    throw new HttpError(403, 'forbidden')\n  }\n  if (requireBrowserOrigin && site !== undefined && site !== 'same-origin') {\n    throw new HttpError(403, 'forbidden')\n  }\n}\n","import { AUTH_PREFIX } from './http-security.js'\n\nexport const MOBILE_COMPAT_PATH = `${AUTH_PREFIX}/compat.js`\n\n/**\n * Read one attribute out of a tag body.\n *\n * A plain `/\\snonce\\s*=/` search can be fooled by a value that merely contains the\n * text, and cannot tell a double-quoted attribute from a single-quoted one. Walking\n * `name=value` pairs consumes each quoted value whole, so the attribute that is\n * actually present is the one returned.\n */\nfunction attributeValue(tag: string, name: string): string | undefined {\n  const pattern = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)\\s*=\\s*(\"[^\"]*\"|'[^']*')/gu\n  for (const match of tag.matchAll(pattern)) {\n    const attribute = match[1]\n    const raw = match[2]\n    if (attribute === undefined || raw === undefined) continue\n    if (attribute.toLowerCase() === name) return raw.slice(1, -1)\n  }\n  return undefined\n}\n\n/** Character ranges covered by an HTML comment, where markup is inert text. */\nfunction commentRanges(html: string): readonly (readonly [number, number])[] {\n  return [...html.matchAll(/<!--[\\s\\S]*?-->/gu)].map(match => [match.index, match.index + match[0].length] as const)\n}\n\n/**\n * Load the compatibility bundle synchronously, before the first DSH script.\n *\n * Returns the HTML unchanged when there is no executable script to anchor to.\n * The bundle supplies missing browser APIs before the page's scripts execute.\n */\nexport function ensureMobileCompatibility(html: string): string {\n  const comments = commentRanges(html)\n  const isInert = (at: number): boolean => comments.some(([start, end]) => at >= start && at < end)\n  // Markup inside a comment never executes, so anchoring to it would inject the\n  // bundle into inert text and silently skip the fix.\n  const scripts = [...html.matchAll(/<script\\b[^>]*>/giu)].filter(match => !isInert(match.index))\n  if (scripts.length === 0) return html\n  if (scripts.some(match => attributeValue(match[0], 'src') === MOBILE_COMPAT_PATH)) return html\n  const first = scripts[0]\n  if (first === undefined) return html\n  // Keep any upstream CSP nonce; do not move execution ahead of preceding CSP meta tags.\n  const nonce = attributeValue(first[0], 'nonce')?.replace(/[\"'<>\\s]/gu, '') ?? ''\n  const attribute = nonce === '' ? '' : ` nonce=\"${nonce}\"`\n  const script = `<script src=\"${MOBILE_COMPAT_PATH}\"${attribute}></script>`\n  return `${html.slice(0, first.index)}${script}${html.slice(first.index)}`\n}\n","/** Entity-tag handling for authenticated GET and HEAD cache validation. */\n\nconst ENTITY_TAG = /^[\\t ]*(?:W\\/)?(\"[\\x21\\x23-\\x7e\\x80-\\xff]*\")[\\t ]*$/u\nconst ENTITY_TAG_LIST_ITEM = /(?:W\\/)?\"[\\x21\\x23-\\x7e\\x80-\\xff]*\"/gu\n\n/**\n * Compare a GET or HEAD If-None-Match field with an existing representation.\n * Invalid fields do not match; empty list elements are ignored per HTTP list syntax.\n * @param field - The received conditional request field.\n * @param etag - The selected representation's valid entity tag.\n * @returns Whether the representation is unchanged under weak comparison.\n */\nexport function matchesIfNoneMatch(field: string | undefined, etag: string): boolean {\n  if (field === undefined) return false\n  const current = ENTITY_TAG.exec(etag)?.[1]\n  if (current === undefined) return false\n  if (/^[\\t ]*\\*[\\t ]*$/u.test(field)) return true\n  let cursor = 0\n  let count = 0\n  let matches = false\n  for (const item of field.matchAll(ENTITY_TAG_LIST_ITEM)) {\n    const gap = field.slice(cursor, item.index)\n    if (!(count === 0 ? /^[\\t ,]*$/u : /^[\\t ]*,[\\t ,]*$/u).test(gap)) return false\n    const opaque = item[0].startsWith('W/') ? item[0].slice(2) : item[0]\n    if (opaque === current) matches = true\n    cursor = item.index + item[0].length\n    count++\n  }\n  return count > 0 && /^[\\t ,]*$/u.test(field.slice(cursor)) && matches\n}\n\n/**\n * Keep an upstream validator usable after lossless content encoding changes.\n * @param etag - An upstream entity tag, if supplied.\n * @returns A weak quoted entity tag, or undefined for an absent or invalid tag.\n */\nexport function weakenEntityTag(etag: string | undefined): string | undefined {\n  const opaque = etag === undefined ? undefined : ENTITY_TAG.exec(etag)?.[1]\n  return opaque === undefined ? undefined : `W/${opaque}`\n}\n","import { AccessError } from './access.js'\nimport { CSRF_COOKIE, DEVICE_COOKIE, HttpError, SESSION_COOKIE } from './http-security.js'\n\nexport const HOST_SESSION_COOKIE = '__Host-dsh_ma_session'\nexport const HOST_CSRF_COOKIE = '__Host-dsh_ma_csrf'\n/** Non-secret browser identity; the persistent device credential keeps its narrow renewal path. */\nexport const HOST_DEVICE_COOKIE = '__Host-dsh_ma_device_id'\n\nconst AUTH_COOKIE_NAMES = new Set([\n  SESSION_COOKIE, DEVICE_COOKIE, CSRF_COOKIE,\n  HOST_SESSION_COOKIE, HOST_CSRF_COOKIE, HOST_DEVICE_COOKIE,\n])\n\n/** Read only gateway authentication cookies, retaining distinct values from different scopes. */\nexport function browserAuthCookies(header: string | undefined): ReadonlyMap<string, readonly string[]> {\n  if (header === undefined) return new Map()\n  if (header.length > 8192) throw new HttpError(401, 'authentication_failed')\n  const cookies = new Map<string, string[]>()\n  for (const part of header.split(';')) {\n    const equals = part.indexOf('=')\n    if (equals <= 0) continue\n    const name = part.slice(0, equals).trim()\n    if (!AUTH_COOKIE_NAMES.has(name)) continue\n    const values = cookies.get(name) ?? []\n    cookies.set(name, values)\n    const value = part.slice(equals + 1).trim()\n    if (!/^[\\w\\-.~+/=]{1,512}$/u.test(value) || values.includes(value)) continue\n    values.push(value)\n  }\n  return cookies\n}\n\n/** Select exactly one authenticated value; never let cookie order choose between valid identities. */\nexport function authenticatedCookie<T>(\n  values: readonly string[],\n  authenticate: (value: string) => T,\n  accepts: (result: T) => boolean = () => true,\n): { readonly value: string; readonly result: T } {\n  let selected: { readonly value: string; readonly result: T } | undefined\n  for (const value of values) {\n    let result: T\n    try {\n      result = authenticate(value)\n    } catch (error) {\n      if (error instanceof AccessError && error.status === 401) continue\n      throw error\n    }\n    if (!accepts(result)) continue\n    if (selected !== undefined) throw new HttpError(401, 'authentication_failed')\n    selected = { value, result }\n  }\n  if (selected === undefined) throw new HttpError(401, 'authentication_failed')\n  return selected\n}\n","/** Terminate optional browser WebSocket compression at the authenticated Mobile gateway. */\nimport type { IncomingMessage } from 'node:http'\nimport type { Socket } from 'node:net'\nimport WebSocket, { WebSocketServer, type RawData } from 'ws'\n\n/** Resolved limits for one gateway's optional WebSocket compression bridge. */\nexport interface WebSocketCompressionOptions {\n  /** Maximum decoded message size in either direction. */\n  readonly maxMessageBytes: number\n  /** Maximum queued payload and frame-header bytes in either direction. */\n  readonly maxQueuedBytes: number\n  /** Minimum message bytes considered for browser-facing compression. */\n  readonly thresholdBytes: number\n  /** ws process-wide zlib concurrency setting, established by its first compressed connection. */\n  readonly concurrencyLimit: number\n  /** zlib compression level for browser-facing messages. */\n  readonly level: number\n}\n\nfunction payloadBytes(data: RawData): number {\n  if (Array.isArray(data)) return data.reduce((bytes, part) => bytes + part.byteLength, 0)\n  return data.byteLength\n}\n\nfunction forwardableClose(code: number): boolean {\n  return (code >= 1000 && code <= 1014 && code !== 1004 && code !== 1005 && code !== 1006)\n    || (code >= 3000 && code <= 4999)\n}\n\n/**\n * Bridge an authorized HTTP upgrade, negotiating compression only with the client.\n * Errors after acceptance close both legs. Socket destruction by the gateway also\n * releases the ws wrappers, pending compression, and handshake/close timers.\n * @param request - validated browser upgrade request.\n * @param client - gateway-owned client socket, paused during authorization.\n * @param upstream - gateway-owned loopback socket, connecting or connected.\n * @param head - bytes the HTTP parser read after the client's upgrade headers.\n * @param target - validated upstream URL, including the original query.\n * @param upstreamCookie - gateway's signed upstream cookie; browser cookies are discarded.\n * @param options - resolved message, queue, and compression limits.\n * @param handshakeTimeoutMs - maximum handshake and close-handshake duration.\n * @returns fulfillment after both HTTP upgrades are accepted, or rejection before acceptance.\n */\nexport function bridgeCompressedWebSocket(\n  request: IncomingMessage,\n  client: Socket,\n  upstream: Socket,\n  head: Buffer,\n  target: URL,\n  upstreamCookie: string | undefined,\n  options: Readonly<WebSocketCompressionOptions>,\n  handshakeTimeoutMs: number,\n): Promise<void> {\n  return new Promise((resolve, reject) => {\n    let incoming: WebSocket | undefined\n    let outgoing: WebSocket | undefined\n    let server: WebSocketServer | undefined\n    let accepted = false\n    let stopped = false\n    let closing = false\n    let closeTimer: NodeJS.Timeout | undefined\n    const handshakeTimer = setTimeout(() => { stop(new Error('WebSocket bridge handshake timed out')) }, handshakeTimeoutMs)\n    handshakeTimer.unref()\n\n    const stop = (error: Error): void => {\n      if (stopped) return\n      stopped = true\n      clearTimeout(handshakeTimer)\n      clearTimeout(closeTimer)\n      if (!accepted) reject(error)\n      incoming?.terminate()\n      outgoing?.terminate()\n      client.destroy()\n      upstream.destroy()\n      server?.close()\n    }\n    const finish = (): void => {\n      if (incoming?.readyState === WebSocket.CLOSED && outgoing?.readyState === WebSocket.CLOSED) {\n        stop(new Error('WebSocket bridge closed'))\n      }\n    }\n    const beginClose = (code: number, reason: string): void => {\n      if (!accepted) { stop(new Error(reason)); return }\n      if (stopped || closing) return\n      closing = true\n      incoming?.resume()\n      outgoing?.resume()\n      for (const socket of [incoming, outgoing]) {\n        if (socket?.readyState === WebSocket.OPEN) socket.close(code, reason)\n      }\n      closeTimer = setTimeout(() => { stop(new Error('WebSocket bridge close timed out')) }, handshakeTimeoutMs)\n      closeTimer.unref()\n    }\n    const socketError = (error: Error): void => { stop(error) }\n    const socketClosed = (): void => {\n      if (!accepted) stop(new Error('WebSocket socket closed before acceptance'))\n    }\n    client.on('error', socketError)\n    upstream.on('error', socketError)\n    client.once('close', socketClosed)\n    upstream.once('close', socketClosed)\n\n    const wsError = (error: Error & { code?: string }): void => {\n      if (!accepted) { stop(error); return }\n      beginClose(error.code === 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH' ? 1009 : 1011,\n        error.code === 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH' ? 'Message too large' : 'WebSocket bridge failed')\n    }\n    const attachRelay = (source: WebSocket, destination: WebSocket): void => {\n      let queuedBytes = 0\n      const send = (bytes: number, operation: (callback: (error?: Error | null) => void) => void): void => {\n        if (stopped || closing) return\n        if (destination.readyState !== WebSocket.OPEN) { beginClose(1011, 'WebSocket peer unavailable'); return }\n        // Count the RFC 6455 maximum frame header too: empty frames still occupy a queue entry.\n        const queued = bytes + 14\n        if (queued > options.maxQueuedBytes - queuedBytes) { beginClose(1009, 'WebSocket queue limit'); return }\n        queuedBytes += queued\n        source.pause()\n        const complete = (error?: Error | null): void => {\n          queuedBytes -= queued\n          if (error != null) { wsError(error); return }\n          if (!stopped && !closing && queuedBytes === 0 && source.readyState === WebSocket.OPEN) source.resume()\n        }\n        try { operation(complete) } catch (error) {\n          complete(error instanceof Error ? error : new Error('WebSocket forwarding failed'))\n        }\n      }\n      source.on('message', (data: RawData, binary: boolean) => {\n        const bytes = payloadBytes(data)\n        if (bytes > options.maxMessageBytes) { beginClose(1009, 'Message too large'); return }\n        send(bytes, callback => { destination.send(data, { binary, compress: destination === incoming }, callback) })\n      })\n      source.on('ping', data => { send(data.byteLength, callback => { destination.ping(data, undefined, callback) }) })\n      source.on('pong', data => { send(data.byteLength, callback => { destination.pong(data, undefined, callback) }) })\n      source.on('close', (code: number, reason: Buffer) => {\n        if (stopped) return\n        if (code === 1006 || !forwardableClose(code) && code !== 1005) {\n          stop(new Error('WebSocket peer closed without a valid close frame'))\n          return\n        }\n        closing = true\n        destination.resume()\n        if (destination.readyState === WebSocket.OPEN) {\n          if (code === 1005) destination.close()\n          else destination.close(code, reason)\n        }\n        closeTimer ??= setTimeout(() => { stop(new Error('WebSocket bridge close timed out')) }, handshakeTimeoutMs)\n        closeTimer.unref()\n        finish()\n      })\n    }\n\n    try {\n      if (client.destroyed || upstream.destroyed) throw new Error('WebSocket socket is already closed')\n      const protocolHeader = request.headers['sec-websocket-protocol']\n      const protocols = typeof protocolHeader === 'string' ? protocolHeader.split(',').map(protocol => protocol.trim()) : []\n      const url = new URL(target)\n      url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:'\n      outgoing = new WebSocket(url, protocols, {\n        createConnection: () => upstream,\n        handshakeTimeout: handshakeTimeoutMs,\n        perMessageDeflate: false,\n        autoPong: false,\n        followRedirects: false,\n        maxPayload: options.maxMessageBytes,\n        headers: {\n          host: target.host,\n          origin: target.origin,\n          'sec-fetch-site': 'same-origin',\n          ...(upstreamCookie === undefined ? {} : { cookie: upstreamCookie }),\n        },\n      })\n      outgoing.on('error', wsError)\n      outgoing.once('close', () => {\n        if (!accepted) stop(new Error('Upstream WebSocket closed before acceptance'))\n        else finish()\n      })\n      outgoing.once('open', () => {\n        if (stopped || client.destroyed) { stop(new Error('Client closed before WebSocket acceptance')); return }\n        upstream.setTimeout(0)\n        server = new WebSocketServer({\n          noServer: true,\n          clientTracking: false,\n          autoPong: false,\n          maxPayload: options.maxMessageBytes,\n          handleProtocols: () => outgoing?.protocol || false,\n          perMessageDeflate: {\n            clientNoContextTakeover: true,\n            serverNoContextTakeover: true,\n            threshold: options.thresholdBytes,\n            concurrencyLimit: options.concurrencyLimit,\n            zlibDeflateOptions: { level: options.level },\n          },\n        })\n        server.on('error', wsError)\n        try {\n          server.handleUpgrade(request, client, head, socket => {\n            incoming = socket\n            incoming.on('error', wsError)\n            incoming.once('close', finish)\n            attachRelay(incoming, outgoing!)\n            attachRelay(outgoing!, incoming)\n            accepted = true\n            clearTimeout(handshakeTimer)\n            incoming.resume()\n            resolve()\n          })\n        } catch (error) {\n          stop(error instanceof Error ? error : new Error('Client WebSocket upgrade failed'))\n        }\n      })\n    } catch (error) { stop(error instanceof Error ? error : new Error('WebSocket bridge setup failed')) }\n  })\n}\n","import { createRequire } from 'node:module'\n\ninterface PackageManifest {\n  readonly version?: unknown\n}\n\nconst manifest = createRequire(import.meta.url)('../package.json') as PackageManifest\n\n/** Version of the installed DSH Mobile plugin package. */\nexport const DSH_MOBILE_VERSION = typeof manifest.version === 'string' ? manifest.version : 'unknown'\n\n/** Oldest Android App release supported by this plugin generation. */\nexport const MINIMUM_ANDROID_APP_VERSION = '0.2.2'\n\n/** Public gateway metadata format understood by the Android App. */\nexport const MOBILE_METADATA_VERSION = 1\n","import { lstat, opendir, readFile } from 'node:fs/promises'\nimport { homedir } from 'node:os'\nimport { basename, dirname, extname, isAbsolute, resolve } from 'node:path'\nimport { HttpError } from './http-security.js'\n\nconst MAX_ENTRIES = 500\nconst MAX_IMAGE_BYTES = 20 * 1024 * 1024\nconst IMAGE_TYPES: Readonly<Record<string, string>> = Object.freeze({\n  '.gif': 'image/gif',\n  '.jpeg': 'image/jpeg',\n  '.jpg': 'image/jpeg',\n  '.png': 'image/png',\n  '.webp': 'image/webp',\n})\n\n/** One computer-side row rendered by the authenticated mobile file sheet. */\nexport interface ComputerImageEntry {\n  readonly kind: 'directory' | 'image'\n  readonly name: string\n  readonly path: string\n}\n\n/** A bounded computer-side directory listing containing folders and supported images. */\nexport interface ComputerImageListing {\n  readonly path: string\n  readonly parent?: string\n  readonly entries: readonly ComputerImageEntry[]\n  readonly truncated: boolean\n}\n\n/** Normalize an optional mobile-browser path without rebasing relative input. */\nexport function resolveComputerImagePath(path: string | null): string {\n  if (path === null || path === '') return homedir()\n  if (!isAbsolute(path) || path.includes('\\0')) throw new HttpError(400, 'bad_path')\n  return resolve(path)\n}\n\n/** List folders and supported image files without following symbolic links. */\nexport async function listComputerImages(path: string | null, signal?: AbortSignal): Promise<ComputerImageListing> {\n  signal?.throwIfAborted()\n  const target = resolveComputerImagePath(path)\n  const rows: ComputerImageEntry[] = []\n  let truncated = false\n  let directory\n  try {\n    directory = await opendir(target)\n    for await (const entry of directory) {\n      signal?.throwIfAborted()\n      if (entry.isSymbolicLink()) continue\n      const kind = entry.isDirectory() ? 'directory' : IMAGE_TYPES[extname(entry.name).toLowerCase()] === undefined ? undefined : 'image'\n      if (kind === undefined) continue\n      if (rows.length === MAX_ENTRIES) {\n        truncated = true\n        break\n      }\n      rows.push({ kind, name: entry.name, path: resolve(target, entry.name) })\n    }\n  } catch (error) {\n    if (signal?.aborted) throw signal.reason\n    throw new HttpError(404, 'directory_unavailable')\n  } finally {\n    await directory?.close().catch(() => undefined)\n  }\n  rows.sort((left, right) => left.kind === right.kind\n    ? left.name.localeCompare(right.name)\n    : left.kind === 'directory' ? -1 : 1)\n  const parent = dirname(target)\n  return Object.freeze({\n    path: target,\n    ...(parent === target ? {} : { parent }),\n    entries: Object.freeze(rows),\n    truncated,\n  })\n}\n\n/** Read one bounded regular image file selected by an authenticated device. */\nexport async function readComputerImage(path: string | null, signal?: AbortSignal): Promise<{ body: Buffer; contentType: string; name: string }> {\n  signal?.throwIfAborted()\n  const target = resolveComputerImagePath(path)\n  const contentType = IMAGE_TYPES[extname(target).toLowerCase()]\n  if (contentType === undefined) throw new HttpError(415, 'unsupported_file_type')\n  let info\n  try {\n    info = await lstat(target)\n  } catch {\n    throw new HttpError(404, 'file_unavailable')\n  }\n  if (!info.isFile() || info.isSymbolicLink()) throw new HttpError(404, 'file_unavailable')\n  if (info.size > MAX_IMAGE_BYTES) throw new HttpError(413, 'file_too_large')\n  try {\n    return { body: await readFile(target, { signal }), contentType, name: basename(target) }\n  } catch (error) {\n    if (signal?.aborted) throw signal.reason\n    throw new HttpError(404, 'file_unavailable')\n  }\n}\n","/**\n * Message protocol for opt-in extension worker\n * execution mode. This module is imported by BOTH the parent supervisor and\n * the worker runtime, so it must stay pure: types and dependency-free helpers\n * only — no Cordis, no node:worker_threads.\n */\n\n/** Upper bound for a per-operation `timeoutMs` override (mirrors extensions.ts). */\nexport const WORKER_OPERATION_TIMEOUT_MAX_MS = 300_000\n\n/** Ceiling for one serialized action result, enforced worker-side. */\nexport const WORKER_RESULT_MAX_BYTES = 4 * 1024 * 1024\n/** HTTP response metadata crossing threads stays within the ordinary HTTP header budget. */\nexport const WORKER_RESPONSE_METADATA_MAX_BYTES = 16 * 1024\n\n/** Per-stream credit window: the worker may send at most this many unacknowledged bytes. */\nexport const WORKER_STREAM_CREDIT_BYTES = 256 * 1024\n\n/** The worker splits source chunks larger than this before credit control. */\nexport const WORKER_STREAM_MAX_CHUNK_BYTES = 64 * 1024\n\n/** Per-worker aggregate bound: total unacknowledged bytes across ALL streams. */\nexport const WORKER_STREAM_AGGREGATE_BYTES = 1024 * 1024\n\n/** Logger-adapter budget per time window: bursts are allowed, silence is not permanent. */\nexport const WORKER_LOG_WINDOW_MS = 1_000\n\n/** If a cancelled stream is not ended by the worker within this grace, the supervisor terminates it. */\nexport const WORKER_STREAM_CANCEL_GRACE_MS = 1_000\n\n/** Default budget for one worker action when the action sets no override. */\nexport const WORKER_OPERATION_TIMEOUT_MS = 30_000\n\n/** After a deadline-detached action fails to settle within this grace, the worker is terminated. */\nexport const WORKER_DEADLINE_GRACE_MS = 250\n\n/** Parent → worker: activate one extension generation inside this runtime. */\nexport interface WorkerActivateMessage {\n  readonly kind: 'activate'\n  readonly id: string\n  readonly hostFile: string\n  readonly generation: string\n  /** Full manifest so `api.manifest` matches the in-process contract. */\n  readonly manifest: WorkerActivationManifest\n}\n\n/** Manifest shape crossing the boundary (structural, Cordis-free). */\nexport interface WorkerActivationManifest {\n  readonly schemaVersion: 1\n  readonly id: string\n  readonly name: string\n  readonly version: string\n  readonly description?: string\n}\n\n/** Parent → worker: run one action; reply with worker-serialized bytes. */\nexport interface WorkerInvokeMessage {\n  readonly kind: 'invoke'\n  readonly id: string\n  readonly action: string\n  readonly deviceId: string\n  readonly input: unknown\n}\n\n/** Parent → worker: the caller detached; stop the identified operation. */\nexport interface WorkerCancelMessage {\n  readonly kind: 'cancel'\n  readonly id: string\n}\n\n/** Parent → worker: run generation teardown inside the runtime. */\nexport interface WorkerDisposeMessage {\n  readonly kind: 'dispose'\n  readonly id: string\n}\n\n/** Parent → worker: run one route handler; the body crosses as bytes. */\nexport interface WorkerRouteMessage {\n  readonly kind: 'route'\n  readonly id: string\n  readonly routeIndex: number\n  readonly method: string\n  readonly path: string\n  readonly query: readonly (readonly [string, string])[]\n  readonly headers: Readonly<Record<string, string>>\n  readonly body: Uint8Array\n  readonly deviceId: string\n}\n\n/** Parent → worker: the consumer took this many streamed bytes; grant credit. */\nexport interface WorkerStreamAckMessage {\n  readonly kind: 'stream-ack'\n  readonly id: string\n  readonly bytes: number\n}\n\n/** Parent → worker: the consumer is gone; stop this stream. */\nexport interface WorkerStreamCancelMessage {\n  readonly kind: 'stream-cancel'\n  readonly id: string\n}\n\nexport type ParentMessage = WorkerActivateMessage | WorkerInvokeMessage | WorkerCancelMessage | WorkerDisposeMessage | WorkerRouteMessage | WorkerStreamAckMessage | WorkerStreamCancelMessage\n\n/** Metadata for one action, crossing the boundary without its functions. */\nexport interface WorkerActionMetadata {\n  readonly name: string\n  readonly timeoutMs?: number\n}\n\n/** Metadata for one route, crossing the boundary without its functions. */\nexport interface WorkerRouteMetadata {\n  readonly method: string\n  readonly path: string\n  readonly kind?: 'exact' | 'prefix'\n  readonly timeoutMs?: number\n}\n\n/** Worker → parent: activation finished; registration crossed as metadata only. */\nexport interface WorkerActivatedMessage {\n  readonly kind: 'activated'\n  readonly runtimeId: string\n  readonly actions: readonly WorkerActionMetadata[]\n  readonly routes: readonly WorkerRouteMetadata[]\n}\n\n/** Worker → parent: an action produced size-checked JSON bytes. */\nexport interface WorkerResultMessage {\n  readonly kind: 'result'\n  readonly runtimeId: string\n  readonly id: string\n  readonly bytes: Uint8Array\n}\n\n/** Worker → parent: an operation failed with a controlled business error. */\nexport interface WorkerErrorMessage {\n  readonly kind: 'error'\n  readonly runtimeId: string\n  readonly id: string\n  readonly code: string\n  readonly message: string\n  readonly status: number\n}\n\n/** Worker → parent: bounded logger-adapter traffic. */\nexport interface WorkerLogMessage {\n  readonly kind: 'log'\n  readonly level: 'debug' | 'info' | 'warn' | 'error'\n  readonly args: readonly unknown[]\n}\n\n/** Worker → parent: a route produced a complete buffered response as bytes. */\nexport interface WorkerRouteResponseMessage {\n  readonly kind: 'route-response'\n  readonly runtimeId: string\n  readonly id: string\n  readonly status?: number\n  readonly contentType?: string\n  readonly headers?: Readonly<Record<string, string>>\n  readonly bytes?: Uint8Array\n}\n\n/** Worker → parent: a route produced a stream; chunks follow under credit control. */\nexport interface WorkerStreamStartMessage {\n  readonly kind: 'stream-start'\n  readonly runtimeId: string\n  readonly id: string\n  readonly status?: number\n  readonly contentType?: string\n  readonly headers?: Readonly<Record<string, string>>\n}\n\n/** Worker → parent: one stream chunk, sent only while credit remains. */\nexport interface WorkerStreamChunkMessage {\n  readonly kind: 'stream-chunk'\n  readonly runtimeId: string\n  readonly id: string\n  readonly bytes: Uint8Array\n}\n\n/** Worker → parent: the stream finished normally. */\nexport interface WorkerStreamEndMessage {\n  readonly kind: 'stream-end'\n  readonly runtimeId: string\n  readonly id: string\n}\n\n/** Worker → parent: the stream failed. */\nexport interface WorkerStreamErrorMessage {\n  readonly kind: 'stream-error'\n  readonly runtimeId: string\n  readonly id: string\n  readonly message: string\n}\n\nexport type WorkerMessage = WorkerActivatedMessage | WorkerResultMessage | WorkerErrorMessage | WorkerLogMessage | WorkerRouteResponseMessage | WorkerStreamStartMessage | WorkerStreamChunkMessage | WorkerStreamEndMessage | WorkerStreamErrorMessage\n\n/** Validate an optional per-operation timeout override against the same bounds as in-process. */\nexport function validOperationTimeout(value: unknown): number | undefined {\n  if (value === undefined) return undefined\n  if (typeof value !== 'number' || !Number.isInteger(value) || value < 1 || value > WORKER_OPERATION_TIMEOUT_MAX_MS) return undefined\n  return value\n}\n\n/** Normalize an extension route path exactly like the in-process registry. */\nexport function normalizeWorkerRoutePath(value: string): string {\n  if (typeof value !== 'string' || value.length === 0 || value.length > 256 || value.includes('?') || value.includes('#') || value.includes('\\\\') || /[\\u0000-\\u001f\\u007f]/u.test(value)) throw new Error('invalid route path')\n  const normalizedInput = value.startsWith('/') ? value : `/${value}`\n  const parts = normalizedInput.split('/')\n  if (parts.some(part => part === '..' || part === '.')) throw new Error('invalid route path')\n  return normalizedInput === '/' ? '/' : normalizedInput.replace(/\\/+$/u, '')\n}\n\n/**\n * Recognize a controlled business error (MobileExtensionError shape) thrown by\n * host code so its code/status survive the boundary instead of collapsing to\n * a generic 500. Pure duck-typing keeps the runtime Cordis-free.\n */\nexport function businessErrorShape(error: unknown): { readonly code: string; readonly message: string; readonly status: number } | undefined {\n  if (error === null || typeof error !== 'object') return undefined\n  const candidate = error as { readonly code?: unknown; readonly message?: unknown; readonly status?: unknown }\n  if (typeof candidate.code !== 'string' || candidate.code.length === 0 || candidate.code.length > 64) return undefined\n  if (typeof candidate.message !== 'string' || candidate.message.length > 500) return undefined\n  if (typeof candidate.status !== 'number' || !Number.isInteger(candidate.status) || candidate.status < 400 || candidate.status > 599) return undefined\n  return { code: candidate.code, message: candidate.message, status: candidate.status }\n}\n\n/**\n * Serialize an action result to JSON bytes worker-side.\n *\n * Plain JSON.stringify, matching the in-process gateway contract exactly:\n * non-JSON-serializable values (e.g. BigInt) throw and surface as\n * `extension_failed`, same as in-process mode today.\n */\nexport function serializeWorkerResult(value: unknown): Uint8Array {\n  const serialized = JSON.stringify(value)\n  if (serialized === undefined) throw new Error('extension result is not JSON serializable')\n  return new TextEncoder().encode(serialized)\n}\n","/** Supervise opt-in local hosts without executing extension code on the DSH thread. */\nimport { randomUUID } from 'node:crypto'\nimport { Worker } from 'node:worker_threads'\nimport { Readable } from 'node:stream'\nimport { MobileExtensionError, type LocalExtensionManifest, type MobileRouteRequest, type MobileRouteResponse } from './extensions.js'\nimport { resolveHostExecution, type HostExecutionConfig, type ResolvedHostExecutionConfig } from './extension-worker-config.js'\nimport { WORKER_RESPONSE_METADATA_MAX_BYTES, type ParentMessage, type WorkerActionMetadata, type WorkerRouteMetadata } from './extension-worker-protocol.js'\n\n/** JSON bytes serialized and size-checked inside the worker. */\nexport class PreparedJsonResult { constructor(readonly bytes: Buffer) {} }\n/** Identify worker results without invoking an extension serializer in the gateway. */\nexport function isPreparedJson(value: unknown): value is PreparedJsonResult { return value instanceof PreparedJsonResult }\n/** Resolve the installed standalone entry adjacent to the plugin bundle. */\nexport function defaultExtensionWorkerModule(): URL { return new URL('./extension-worker-runtime.mjs', import.meta.url) }\n/** Worker context is logger-only, never a Cordis Context or service proxy. */\nexport type WorkerParentLogger = Record<'debug' | 'info' | 'warn' | 'error', (...args: unknown[]) => void>\n\n/** Every thread counts until actual exit, including activation, retirement and termination. */\nexport class ExtensionWorkerBudget {\n  private count = 0\n  constructor(readonly maximum: number) {}\n  get current(): number { return this.count }\n  reserve(): () => void {\n    if (this.count >= this.maximum) throw new MobileExtensionError('extension_worker_limit', 'local extension worker limit reached', 503)\n    this.count += 1\n    let released = false\n    return () => { if (!released) { released = true; this.count -= 1 } }\n  }\n}\nexport interface ExtensionWorkerHostOptions {\n  readonly workerModule: string | URL\n  readonly hostFile: string\n  readonly manifest: LocalExtensionManifest\n  readonly generation: string\n  readonly logger: WorkerParentLogger\n  readonly activationTimeoutMs?: number\n  readonly limits?: HostExecutionConfig\n  readonly budget?: ExtensionWorkerBudget\n  readonly onUnavailable?: (error: MobileExtensionError) => void\n}\nexport interface ExtensionWorkerActivation {\n  readonly runtimeId: string\n  readonly actions: readonly WorkerActionMetadata[]\n  readonly routes: readonly WorkerRouteMetadata[]\n}\ninterface PendingRpc<T> { readonly resolve: (value: T) => void; readonly reject: (error: Error) => void; readonly cleanup: () => void }\ninterface LiveStream { readonly bridge: WorkerStreamBridge; unacked: number; ended: boolean; cancelTimer?: NodeJS.Timeout }\n/** Diagnostic count; production admission uses an instance-owned budget. */\nexport const activeWorkerCount = { current: 0 }\nconst LIFECYCLE_ID = 'lifecycle'\n\n/** Node accepts quoted NODE_OPTIONS words; inspect option names without exposing their values. */\nfunction nodeOptionWords(value: string): string[] {\n  const words:string[]=[]\n  let word='';let quoted=false;let escaped=false\n  for(const character of value){\n    if(escaped){word+=character;escaped=false;continue}\n    if(character==='\\\\'){escaped=true;continue}\n    if(character==='\"'){quoted=!quoted;continue}\n    if(/\\s/u.test(character)&&!quoted){if(word!==''){words.push(word);word=''};continue}\n    word+=character\n  }\n  if(word!=='')words.push(word)\n  return words\n}\n\n/** Known parent V8 heap flags take precedence over Worker resourceLimits. */\nexport function parentWorkerHeapOverrides(argv:readonly string[],nodeOptions:string|undefined):readonly string[]{\n  const heapFlags=new Set(['--max-old-space-size','--max-semi-space-size','--max-heap-size','--max-old-space-size-percentage'])\n  const found=new Set<string>()\n  for(const argument of [...argv,...nodeOptionWords(nodeOptions??'')]){\n    const name=argument.split('=',1)[0]!.replaceAll('_','-')\n    if(heapFlags.has(name))found.add(name)\n  }\n  return Object.freeze([...found])\n}\nconst initialNodeOptions=process.env.NODE_OPTIONS\n\nexport class ExtensionWorkerHost {\n  private readonly limits: ResolvedHostExecutionConfig\n  private readonly worker: Worker\n  private readonly pending = new Map<string, PendingRpc<PreparedJsonResult>>()\n  private readonly routePending = new Map<string, PendingRpc<MobileRouteResponse>>()\n  private readonly streams = new Map<string, LiveStream>()\n  private readonly detachedRoutes = new Set<string>()\n  private readonly executionGrace = new Map<string, NodeJS.Timeout>()\n  private readonly exited: Promise<void>\n  private readonly unavailableController = new AbortController()\n  private termination: Promise<void> | undefined\n  private activation: ExtensionWorkerActivation | undefined\n  private dead = false\n  private disposed = false\n  private maxBufferedBytes = 0\n  private cancelledStreams = 0\n  private logWindowStart = Date.now()\n  private logCount = 0\n  private stdioBytes = 0\n  private stdioResume: NodeJS.Timeout | undefined\n\n  constructor(private readonly options: ExtensionWorkerHostOptions) {\n    this.limits = resolveHostExecution(options.limits)\n    const overrides=new Set(parentWorkerHeapOverrides(process.execArgv,initialNodeOptions))\n    for(const flag of parentWorkerHeapOverrides([],process.env.NODE_OPTIONS))overrides.add(flag)\n    if(overrides.size>0)throw new MobileExtensionError('extension_worker_heap_override',`worker heap limits require launching DSH without ${[...overrides].join(', ')}`,503)\n    const release = options.budget?.reserve() ?? (() => undefined)\n    try {\n      this.worker = new Worker(options.workerModule, {\n        workerData: { limits: this.limits }, stdout: true, stderr: true,\n        resourceLimits: { maxOldGenerationSizeMb: this.limits.maxOldGenerationSizeMb, maxYoungGenerationSizeMb: this.limits.maxYoungGenerationSizeMb, stackSizeMb: this.limits.stackSizeMb },\n      })\n    } catch (error) { release(); throw error }\n    // Extension console output has no ambient parent stdout; only the bounded logger adapter is forwarded.\n    const drainConsole = (chunk: Buffer): void => {\n      this.stdioBytes += chunk.byteLength\n      if (this.stdioBytes < this.limits.logMessageBytes * this.limits.logMessagesPerWindow || this.stdioResume !== undefined) return\n      this.worker.stdout?.pause(); this.worker.stderr?.pause()\n      this.stdioResume = setTimeout(() => {\n        this.stdioResume = undefined; this.stdioBytes = 0\n        if (!this.dead) { this.worker.stdout?.resume(); this.worker.stderr?.resume() }\n      }, this.limits.logWindowMs)\n      this.stdioResume.unref()\n    }\n    this.worker.stdout?.on('data', drainConsole); this.worker.stderr?.on('data', drainConsole)\n    this.worker.unref()\n    activeWorkerCount.current += 1\n    this.exited = new Promise<void>(resolve => {\n      this.worker.once('exit', () => {\n        this.dead = true\n        if (this.stdioResume !== undefined) clearTimeout(this.stdioResume)\n        this.markUnavailable()\n        release(); activeWorkerCount.current -= 1\n        for (const timer of this.executionGrace.values()) clearTimeout(timer)\n        this.executionGrace.clear()\n        const error = this.unavailable()\n        for (const entry of this.pending.values()) { entry.cleanup(); entry.reject(error) }\n        for (const entry of this.routePending.values()) { entry.cleanup(); entry.reject(error) }\n        this.pending.clear(); this.routePending.clear(); this.detachedRoutes.clear()\n        for (const live of this.streams.values()) {\n          if (live.cancelTimer !== undefined) clearTimeout(live.cancelTimer)\n          live.bridge.destroy(error)\n        }\n        this.streams.clear()\n        resolve()\n      })\n    })\n    this.worker.on('message', (raw: unknown) => {\n      try { this.handleMessage(raw) } catch (error) { void error; void this.terminate('invalid-worker-message') }\n    })\n    this.worker.on('error', () => { void this.terminate('worker-error') })\n  }\n  /** A stopped generation never silently respawns. */\n  available(): boolean { return !this.dead && this.termination === undefined && !this.disposed && !this.unavailableController.signal.aborted }\n  /** Activate once and receive executable-free registration metadata. */\n  async activate(): Promise<ExtensionWorkerActivation> {\n    let timer: NodeJS.Timeout | undefined\n    try {\n      const reply = new Promise<PreparedJsonResult>((resolve, reject) => {\n        this.pending.set(LIFECYCLE_ID, { resolve, reject, cleanup: () => undefined })\n        this.post({ kind: 'activate', id: LIFECYCLE_ID, hostFile: this.options.hostFile, generation: this.options.generation, manifest: this.options.manifest })\n      })\n      await Promise.race([reply, new Promise<never>((_, reject) => {\n        timer = setTimeout(() => reject(new MobileExtensionError('host_load_timeout', 'extension worker activation timed out', 500)), this.options.activationTimeoutMs ?? this.limits.activationTimeoutMs)\n      })])\n      if (this.activation === undefined) throw new MobileExtensionError('host_activation_failed', 'extension worker activation failed', 500)\n      return this.activation\n    } catch (error) { await this.terminate('activation-failed'); throw error }\n    finally { if (timer !== undefined) clearTimeout(timer) }\n  }\n  actionMetadata(): readonly WorkerActionMetadata[] { return this.activation?.actions ?? [] }\n  routeMetadata(): readonly WorkerRouteMetadata[] { return this.activation?.routes ?? [] }\n\n  /** Underlying action: settles only when execution completes or the thread exits. */\n  invokeExecution(action: string, input: unknown, caller: { readonly signal: AbortSignal; readonly deviceId: string }): Promise<PreparedJsonResult> {\n    if (!this.available()) return Promise.reject(this.unavailable())\n    if (caller.signal.aborted) return Promise.reject(caller.signal.reason)\n    const id = randomUUID()\n    return new Promise<PreparedJsonResult>((resolve, reject) => {\n      const onAbort = (): void => { this.post({ kind: 'cancel', id }); this.armExecutionGrace(id) }\n      caller.signal.addEventListener('abort', onAbort, { once: true })\n      this.pending.set(id, { resolve, reject, cleanup: () => { caller.signal.removeEventListener('abort', onAbort); this.settleExecutionGrace(id) } })\n      try { this.post({ kind: 'invoke', id, action, deviceId: caller.deviceId, input }) }\n      catch (error) { this.pending.get(id)?.cleanup(); this.pending.delete(id); reject(error instanceof Error ? error : new Error(String(error))) }\n    })\n  }\n  /** Direct caller budget; service dispatch observes invokeExecution separately. */\n  invoke(action: string, input: unknown, caller: { readonly signal: AbortSignal; readonly deviceId: string }): Promise<PreparedJsonResult> {\n    return this.callerBudget(signal => this.invokeExecution(action, input, { ...caller, signal }), caller.signal,\n      this.actionMetadata().find(entry => entry.name === action)?.timeoutMs ?? this.limits.operationTimeoutMs, 'extension_action_timeout')\n  }\n  /** Underlying route: late streams are cancelled and observed to confirmed end. */\n  handleRouteExecution(routeIndex: number, request: MobileRouteRequest): Promise<MobileRouteResponse> {\n    if (!this.available()) return Promise.reject(this.unavailable())\n    if (request.signal.aborted) return Promise.reject(request.signal.reason)\n    const id = randomUUID()\n    return new Promise<MobileRouteResponse>((resolve, reject) => {\n      const onAbort = (): void => {\n        this.post({ kind: 'cancel', id })\n        if (this.routePending.has(id)) { this.detachedRoutes.add(id); this.armExecutionGrace(id) }\n        this.cancelStream(id)\n      }\n      request.signal.addEventListener('abort', onAbort, { once: true })\n      this.routePending.set(id, { resolve, reject, cleanup: () => { request.signal.removeEventListener('abort', onAbort); this.settleExecutionGrace(id) } })\n      try { this.post({ kind: 'route', id, routeIndex, method: request.method, path: request.pathname, query: [...request.query.entries()], headers: request.headers, body: new Uint8Array(request.body), deviceId: request.deviceId }) }\n      catch (error) { this.routePending.get(id)?.cleanup(); this.routePending.delete(id); reject(error instanceof Error ? error : new Error(String(error))) }\n    })\n  }\n  /** Handler budget ends at stream-start; stream lifetime remains cancellation-bound. */\n  handleRoute(routeIndex: number, request: MobileRouteRequest): Promise<MobileRouteResponse> {\n    return this.callerBudget(signal => this.handleRouteExecution(routeIndex, { ...request, signal }), request.signal,\n      this.routeMetadata()[routeIndex]?.timeoutMs ?? this.limits.operationTimeoutMs, 'extension_route_timeout', true)\n  }\n  private async callerBudget<T>(start: (signal: AbortSignal) => Promise<T>, external: AbortSignal, timeoutMs: number, code: string, holdForStream = false): Promise<T> {\n    const controller = new AbortController()\n    let timer: NodeJS.Timeout | undefined\n    let detach: ((error: unknown) => void) | undefined\n    const onAbort = (): void => { controller.abort(external.reason); detach?.(external.reason ?? new MobileExtensionError('extension_cancelled', 'caller cancelled', 409)) }\n    const onUnavailable = (): void => { detach?.(this.unavailableController.signal.reason) }\n    if (external.aborted) throw external.reason\n    if (!this.available()) throw this.unavailable()\n    external.addEventListener('abort', onAbort, { once: true }); this.unavailableController.signal.addEventListener('abort', onUnavailable, { once: true })\n    const release = (): void => { external.removeEventListener('abort', onAbort); this.unavailableController.signal.removeEventListener('abort', onUnavailable); if (timer !== undefined) clearTimeout(timer) }\n    let retained = false\n    try {\n      const result = await Promise.race([start(controller.signal), new Promise<never>((_, reject) => {\n        detach = reject\n        timer = setTimeout(() => { const error = new MobileExtensionError(code, 'extension operation timed out', 500); controller.abort(error); reject(error) }, timeoutMs)\n      })])\n      if (holdForStream && result !== null && typeof result === 'object' && 'body' in result && result.body instanceof Readable) {\n        retained = true\n        result.body.once('close', release); result.body.once('end', release)\n      }\n      return result\n    } finally { if (timer !== undefined) clearTimeout(timer); if (!retained) release() }\n  }\n  streamStats(): { readonly activeStreams: number; readonly maxBufferedBytes: number; readonly cancelledStreams: number; readonly bufferedBytes: number } {\n    return { activeStreams: [...this.streams.values()].filter(live => !live.ended).length, maxBufferedBytes: this.maxBufferedBytes, cancelledStreams: this.cancelledStreams, bufferedBytes: this.totalUnacked() }\n  }\n  /** Graceful effects cleanup followed by termination; completion requires actual exit. */\n  async dispose(): Promise<void> {\n    if (!this.available()) { await this.terminate('dispose-unavailable'); return }\n    this.disposed = true\n    let timer: NodeJS.Timeout | undefined\n    try {\n      const reply = new Promise<PreparedJsonResult>((resolve, reject) => { this.pending.set(LIFECYCLE_ID, { resolve, reject, cleanup: () => undefined }); this.post({ kind: 'dispose', id: LIFECYCLE_ID }) })\n      await Promise.race([reply, new Promise<void>(resolve => { timer = setTimeout(resolve, this.limits.disposeGraceMs) })])\n    } finally { if (timer !== undefined) clearTimeout(timer); await this.terminate('disposed') }\n  }\n  whenExited(): Promise<void> { return this.exited }\n  /** Stop admission now, retain execution/budget ownership until confirmed thread exit. */\n  terminate(reason: string): Promise<void> {\n    this.markUnavailable()\n    this.termination ??= (async () => { if (!this.dead) await this.worker.terminate(); await this.exited })()\n    // Callers may initiate termination from a listener; the lifecycle owner still awaits and reports failures.\n    void this.termination.catch(() => undefined)\n    void reason\n    return this.termination\n  }\n  private unavailable(): MobileExtensionError { return new MobileExtensionError('extension_host_unavailable', `extension ${this.options.manifest.id} worker is unavailable; explicit recovery is required`, 503) }\n  private markUnavailable(): void {\n    if (this.unavailableController.signal.aborted) return\n    const error = this.unavailable(); this.unavailableController.abort(error)\n    try { this.options.onUnavailable?.(error) } catch (cause) { void cause /* Observer failures cannot prevent thread termination. */ }\n  }\n  private armExecutionGrace(id: string): void {\n    if (this.executionGrace.has(id) || !this.available()) return\n    const timer = setTimeout(() => { this.executionGrace.delete(id); if (this.pending.has(id) || this.routePending.has(id)) void this.terminate('cancel-unresponsive') }, this.limits.cancelGraceMs)\n    timer.unref(); this.executionGrace.set(id, timer)\n  }\n  private settleExecutionGrace(id: string): void { const timer = this.executionGrace.get(id); if (timer !== undefined) clearTimeout(timer); this.executionGrace.delete(id) }\n  private post(message: ParentMessage): void { if (!this.dead && this.termination === undefined) this.worker.postMessage(message) }\n  private handleMessage(raw: unknown): void {\n    if (this.dead || raw === null || typeof raw !== 'object') return\n    const message = raw as Record<string, unknown>\n    if (message.kind === 'log') {\n      if (message.level !== 'debug' && message.level !== 'info' && message.level !== 'warn' && message.level !== 'error') return\n      if (!Array.isArray(message.args) || message.args.some(arg => typeof arg !== 'string')) return\n      if (Date.now() - this.logWindowStart >= this.limits.logWindowMs) { this.logWindowStart = Date.now(); this.logCount = 0 }\n      if (++this.logCount > this.limits.logMessagesPerWindow || Buffer.byteLength(message.args.join('')) > this.limits.logMessageBytes) return\n      try { this.options.logger[message.level](...message.args) } catch (error) { void error /* Logger failures do not change an extension outcome. */ }\n      return\n    }\n    if (typeof message.runtimeId !== 'string') return\n    if (this.activation !== undefined && message.runtimeId !== this.activation.runtimeId) return\n    if (message.kind === 'activated') {\n      if (this.activation !== undefined || !Array.isArray(message.actions) || !Array.isArray(message.routes)) throw new Error('invalid activation metadata')\n      const actions = message.actions as WorkerActionMetadata[]\n      const routes = message.routes as WorkerRouteMetadata[]\n      if (actions.length + routes.length > this.limits.maxRegistrations) throw new Error('worker registration limit exceeded')\n      for (const action of actions) if (typeof action?.name !== 'string' || !/^[a-z][a-z0-9-]{0,63}$/u.test(action.name)) throw new Error('invalid action metadata')\n      for (const route of routes) if (typeof route?.method !== 'string' || typeof route.path !== 'string') throw new Error('invalid route metadata')\n      this.activation = Object.freeze({ runtimeId: message.runtimeId, actions: Object.freeze(actions), routes: Object.freeze(routes) })\n      const pending = this.pending.get(LIFECYCLE_ID); this.pending.delete(LIFECYCLE_ID); pending?.cleanup(); pending?.resolve(new PreparedJsonResult(Buffer.alloc(0)))\n      return\n    }\n    if (typeof message.id !== 'string') return\n    const id = message.id\n    if (message.kind === 'result' || message.kind === 'error') {\n      const pending = this.pending.get(id); this.pending.delete(id); pending?.cleanup()\n      if (message.kind === 'result') {\n        if (!(message.bytes instanceof Uint8Array) || message.bytes.byteLength > this.limits.resultMaxBytes) { pending?.reject(new MobileExtensionError('extension_failed', 'invalid worker result', 500)); return }\n        pending?.resolve(new PreparedJsonResult(Buffer.from(message.bytes)))\n      } else {\n        const error = new MobileExtensionError(typeof message.code === 'string' ? message.code.slice(0, 64) : 'extension_failed', typeof message.message === 'string' ? message.message.slice(0, 500) : 'extension failed', typeof message.status === 'number' && Number.isInteger(message.status) && message.status >= 400 && message.status <= 599 ? message.status : 500)\n        pending?.reject(error)\n        const route = this.routePending.get(id); this.routePending.delete(id); this.detachedRoutes.delete(id); route?.cleanup(); route?.reject(error)\n      }\n      return\n    }\n    if (message.kind === 'route-response' || message.kind === 'stream-start') {\n      const route = this.routePending.get(id)\n      if (route === undefined) { if (message.kind === 'stream-start') this.post({ kind: 'stream-cancel', id }); return }\n      if (message.kind === 'stream-start' && this.detachedRoutes.has(id)) { this.cancelledStreams += 1; this.post({ kind: 'stream-cancel', id }); return }\n      const response = responseMetadata(message)\n      this.routePending.delete(id); this.detachedRoutes.delete(id)\n      if (message.kind === 'route-response') {\n        route.cleanup()\n        if (!(message.bytes instanceof Uint8Array) || message.bytes.byteLength > this.limits.resultMaxBytes) { route.reject(new MobileExtensionError('invalid_route_response', 'invalid worker route response', 500)); return }\n        route.resolve({ ...response, body: Buffer.from(message.bytes) })\n      } else {\n        this.settleExecutionGrace(id)\n        const live = this.openStream(id, route.cleanup)\n        route.resolve({ ...response, body: live.bridge })\n      }\n      return\n    }\n    if (message.kind === 'stream-chunk') {\n      const live = this.streams.get(id)\n      if (live === undefined || live.ended || live.bridge.destroyed) return\n      if (!(message.bytes instanceof Uint8Array) || message.bytes.byteLength > this.limits.streamChunkBytes || live.unacked + message.bytes.byteLength > this.limits.streamWindowBytes || this.totalUnacked() + message.bytes.byteLength > this.limits.streamAggregateBytes) throw new Error('worker exceeded stream credit')\n      live.unacked += message.bytes.byteLength\n      this.maxBufferedBytes = Math.max(this.maxBufferedBytes, this.totalUnacked())\n      live.bridge.push(Buffer.from(message.bytes))\n      return\n    }\n    if (message.kind === 'stream-end' || message.kind === 'stream-error') {\n      this.settleExecutionGrace(id)\n      const detached = this.routePending.get(id)\n      if (this.detachedRoutes.delete(id)) { this.routePending.delete(id); detached?.cleanup(); detached?.reject(new MobileExtensionError('extension_cancelled', 'caller detached', 409)) }\n      const live = this.streams.get(id)\n      if (live === undefined) return\n      live.ended = true\n      if (live.cancelTimer !== undefined) clearTimeout(live.cancelTimer)\n      if (message.kind === 'stream-error') live.bridge.destroy(new Error(typeof message.message === 'string' ? message.message.slice(0, 500) : 'worker stream failed'))\n      else if (live.bridge.destroyed) this.streams.delete(id)\n      else live.bridge.push(null)\n    }\n  }\n  private totalUnacked(): number { let total = 0; for (const live of this.streams.values()) total += live.unacked; return total }\n  private openStream(id: string, cleanup: () => void): LiveStream {\n    const live: LiveStream = { bridge: new WorkerStreamBridge(bytes => { live.unacked -= bytes; this.post({ kind: 'stream-ack', id, bytes }) }), unacked: 0, ended: false }\n    live.bridge.on('error', () => undefined)\n    const settle = (): void => {\n      cleanup()\n      if (live.ended) { if (live.unacked > 0) this.post({ kind: 'stream-cancel', id }); this.streams.delete(id) }\n      else this.cancelStream(id)\n    }\n    live.bridge.once('end', settle); live.bridge.once('close', settle)\n    this.streams.set(id, live)\n    return live\n  }\n  private cancelStream(id: string): void {\n    const live = this.streams.get(id)\n    if (live === undefined || live.ended || live.cancelTimer !== undefined) return\n    this.cancelledStreams += 1; this.post({ kind: 'stream-cancel', id })\n    // Mark the timer before destroying: close listeners may run synchronously in custom consumers.\n    live.cancelTimer = setTimeout(() => { if (!live.ended) void this.terminate('stream-cancel-unresponsive') }, this.limits.streamCancelGraceMs)\n    live.cancelTimer.unref(); live.bridge.destroy()\n  }\n}\n\nfunction responseMetadata(message: Record<string, unknown>): Omit<MobileRouteResponse, 'body'> {\n  const headers: Record<string, string> = {}\n  let bytes = typeof message.contentType === 'string' ? Buffer.byteLength(message.contentType) : 0\n  if (message.headers !== undefined) {\n    if (message.headers === null || typeof message.headers !== 'object' || Array.isArray(message.headers)) throw new Error('invalid response headers')\n    const entries = Object.entries(message.headers)\n    if (entries.length > 3) throw new Error('invalid response header count')\n    for (const [key, value] of entries) {\n      if (typeof value !== 'string' || !/^(?:content-disposition|cache-control|etag)$/iu.test(key)) throw new Error('invalid response header')\n      bytes += Buffer.byteLength(key) + Buffer.byteLength(value)\n      if (bytes > WORKER_RESPONSE_METADATA_MAX_BYTES) throw new Error('invalid response header bytes')\n      headers[key] = value\n    }\n  }\n  return { ...(typeof message.status === 'number' ? { status: message.status } : {}), ...(typeof message.contentType === 'string' ? { contentType: message.contentType } : {}), ...(message.headers === undefined ? {} : { headers }) }\n}\n/** Credit belongs to bytes actually removed by the consumer, including reads after source EOF. */\nclass WorkerStreamBridge extends Readable {\n  constructor(private readonly consume: (bytes: number) => void) { super({ highWaterMark: 16 * 1024 }) }\n  override _read(): void { /* The worker's credit window bounds incoming bytes. */ }\n  override emit(event: string | symbol, ...args: unknown[]): boolean {\n    // Node emits data both for explicit read() and for a push() into a flowing pipeline.\n    // Observing read() alone misses the latter and can permanently exhaust stream credit.\n    if (event === 'data' && Buffer.isBuffer(args[0])) this.consume(args[0].byteLength)\n    return super.emit(event, ...args)\n  }\n}\n","import { createHash } from 'node:crypto'\nimport type { Dirent } from 'node:fs'\nimport { lstat, mkdir, opendir, readFile, realpath } from 'node:fs/promises'\nimport { basename, isAbsolute, join, relative, resolve } from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport { Service, type Context } from '@deepseek-ai/cordis'\nimport z from '@deepseek-ai/schemastery'\nimport { finished, type Readable } from 'node:stream'\nimport { defaultExtensionWorkerModule, ExtensionWorkerBudget, ExtensionWorkerHost, type WorkerParentLogger } from './extension-worker.js'\nimport { resolveHostExecution, type HostExecutionConfig, type ResolvedHostExecutionConfig } from './extension-worker-config.js'\n\n/** Maximum sizes enforced at the local-extension filesystem boundary. */\nexport const EXTENSION_LIMITS = Object.freeze({\n  manifest: 64 * 1024,\n  script: 1024 * 1024,\n  css: 512 * 1024,\n  asset: 8 * 1024 * 1024,\n  assetFiles: 256,\n  assetBytes: 32 * 1024 * 1024,\n  assetDepth: 8,\n})\n\n/** A misbehaving host activation must not wedge the local watcher forever. */\nconst HOST_ACTIVATION_TIMEOUT_MS = 5_000\n\n/** The previous Host outlives the hidden-page refresh interval and one timed refresh. */\nconst RETIRED_GENERATION_TTL_MS = 10 * 60_000\n\n/** Extension teardown is advisory and must never stop watcher progress. */\nconst HOST_TEARDOWN_TIMEOUT_MS = 2_000\n\n/** Default budget for one extension action or route-handler execution. */\nexport const HOST_OPERATION_TIMEOUT_MS = 30_000\n\n/** Upper bound for a per-operation `timeoutMs` override. */\nexport const HOST_OPERATION_TIMEOUT_MAX_MS = 300_000\n\nasync function withActivationTimeout<T>(promise: Promise<T>, id: string, signal: AbortSignal, timeoutMs: number | undefined): Promise<T> {\n  let timer: NodeJS.Timeout | undefined\n  let onAbort: (() => void) | undefined\n  try {\n    return await Promise.race([\n      promise,\n      ...(timeoutMs === undefined ? [] : [new Promise<never>((_, reject) => {\n        timer = setTimeout(() => reject(new MobileExtensionError('host_load_timeout', `extension ${id} activation timed out`, 500)), timeoutMs)\n      })]),\n      new Promise<never>((_, reject) => {\n        const abort = (): void => { reject(new MobileExtensionError('host_activation_closed', `extension ${id} activation is closed`, 409)) }\n        if (signal.aborted) abort()\n        else { onAbort = abort; signal.addEventListener('abort', abort, { once: true }) }\n      }),\n    ])\n  } finally {\n    if (timer !== undefined) clearTimeout(timer)\n    if (onAbort !== undefined) signal.removeEventListener('abort', onAbort)\n  }\n}\n\n/** A controlled business failure returned by an extension action or route. */\nexport class MobileExtensionError extends Error {\n  constructor(readonly code: string, message: string, readonly status = 400) {\n    super(message)\n    this.name = 'MobileExtensionError'\n  }\n}\n\n/** One host-side action exposed by an extension. */\ntype CallableActionInput = (value?: never, options?: never) => unknown\n\nexport interface MobileHostAction {\n  /** A callable Schemastery schema or an adapter exposing parse(). */\n  readonly input?: CallableActionInput | { parse(value: unknown): unknown }\n  /** Optional per-action budget override; validated and snapshotted at registration. */\n  readonly timeoutMs?: number\n  readonly run: (context: MobileActionContext, input: unknown) => unknown | Promise<unknown>\n}\n\n/** Context supplied to a host action. */\nexport interface MobileActionContext {\n  readonly signal: AbortSignal\n  readonly deviceId: string\n}\n\n/** Safe request values supplied to a host route. */\nexport interface MobileRouteRequest {\n  readonly method: string\n  readonly pathname: string\n  readonly query: Readonly<URLSearchParams>\n  readonly headers: Readonly<Record<string, string>>\n  readonly body: Uint8Array\n  readonly signal: AbortSignal\n  readonly deviceId: string\n}\n\n/** Values an extension route may return; status is a final HTTP code from 200 through 599. */\nexport interface MobileRouteResponse {\n  readonly status?: number\n  readonly contentType?: string\n  readonly headers?: Readonly<Record<string, string>>\n  readonly body: string | Uint8Array | Readable\n}\n\n/** One host-side route exposed by an extension. */\nexport interface MobileHostRoute {\n  readonly method: string\n  readonly path: string\n  readonly kind?: 'exact' | 'prefix'\n  /** Optional per-route handler budget override; validated and snapshotted at registration. */\n  readonly timeoutMs?: number\n  readonly handle: (request: MobileRouteRequest) => MobileRouteResponse | Promise<MobileRouteResponse>\n}\n\n/** Metadata shared by local and npm-provided extensions. */\nexport interface MobileExtensionManifest {\n  readonly schemaVersion: 1\n  readonly id: string\n  readonly name: string\n  readonly version: string\n  readonly description?: string\n}\n\n/** Definition registered by a normal Cordis plugin. */\nexport interface MobileExtensionDefinition extends MobileExtensionManifest {\n  readonly actions?: Readonly<Record<string, MobileHostAction>>\n  readonly routes?: readonly MobileHostRoute[]\n}\n\ndeclare module '@deepseek-ai/cordis' {\n  interface Context {\n    mobileAccess: MobileAccessService\n  }\n}\n\n/** A local extension manifest read from extension.json. */\nexport interface LocalExtensionManifest extends MobileExtensionManifest {}\n\n/** Public snapshot sent to the mobile browser. */\nexport interface MobileExtensionClientEntry extends MobileExtensionManifest {\n  readonly generation?: string\n  readonly scriptUrl?: string\n  readonly styleUrl?: string\n  readonly assetsUrl?: string\n}\n\ninterface LocalAssetSnapshot {\n  readonly body: Buffer\n  readonly digest: string\n  readonly name: string\n}\n\n/** Small status summary used by the desktop mobile-access card. */\nexport interface MobileExtensionStatus {\n  readonly loaded: number\n  readonly failed: number\n}\n\ninterface ActiveLocalExtension {\n  readonly manifest: LocalExtensionManifest\n  readonly directory: string\n  readonly scriptBody?: Buffer\n  readonly styleBody?: Buffer\n  readonly assets: ReadonlyMap<string, LocalAssetSnapshot>\n  readonly host: MobileExtensionDefinition\n  readonly controller: AbortController\n  readonly cleanups: readonly (() => void | Promise<void>)[]\n  readonly digest: string\n  readonly worker?: ExtensionWorkerHost\n}\n\ninterface RegisteredExtension {\n  readonly definition: MobileExtensionDefinition\n  readonly dispose: () => void\n}\n\ninterface RetiredLocalExtension {\n  readonly active: ActiveLocalExtension\n  readonly timer: NodeJS.Timeout\n}\n\n/** Local execution options; the packaged worker entry is used unless a test supplies an override. */\nexport interface LocalExecutionOptions {\n  readonly hostExecution?: HostExecutionConfig & { readonly workerModule?: string }\n  readonly workerBudget?: ExtensionWorkerBudget\n}\n\ntype HostApi = {\n  readonly manifest: LocalExtensionManifest\n  readonly context: Context\n  readonly schema: typeof z\n  readonly signal: AbortSignal\n  action(name: string, spec: MobileHostAction): void\n  route(spec: MobileHostRoute): void\n  effect(setup: () => void | (() => void | Promise<void>) | Promise<void | (() => void | Promise<void>)>): void\n}\n\n/** Worker-host API: logger-only context, with no Cordis services or registrations crossing threads. */\nexport interface MobileWorkerHostApi {\n  readonly manifest: LocalExtensionManifest\n  readonly context: { readonly logger: WorkerParentLogger }\n  readonly schema: typeof z\n  readonly signal: AbortSignal\n  action(name: string, spec: MobileHostAction): void\n  route(spec: MobileHostRoute): void\n  effect(setup: () => void | (() => void | Promise<void>) | Promise<void | (() => void | Promise<void>)>): void\n}\n\ntype LocalHostModule = { readonly default?: (api: HostApi) => void | Promise<void> }\n\n/** Validate user-facing extension text without allowing control characters. */\nfunction text(value: unknown, field: string, maximum: number, required: boolean): string | undefined {\n  if (value === undefined && !required) return undefined\n  if (typeof value !== 'string' || (required && value.length === 0) || value.length > maximum\n    || /[\\u0000-\\u001f\\u007f]/u.test(value)) throw new MobileExtensionError('invalid_manifest', `${field} is invalid`)\n  return value\n}\n\n/** Validate a stable extension id. */\nexport function assertExtensionId(value: unknown): string {\n  if (typeof value !== 'string' || !/^[a-z][a-z0-9-]{0,63}$/u.test(value)) {\n    throw new MobileExtensionError('invalid_manifest', 'extension id is invalid')\n  }\n  return value\n}\n\n/** Validate a manifest from JSON or a plugin definition. */\nexport function parseExtensionManifest(value: unknown): LocalExtensionManifest {\n  if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n    throw new MobileExtensionError('invalid_manifest', 'extension.json must be an object')\n  }\n  const record = value as Record<string, unknown>\n  if (record.schemaVersion !== 1) throw new MobileExtensionError('invalid_manifest', 'unsupported extension schema')\n  const id = assertExtensionId(record.id)\n  const name = text(record.name, 'name', 120, true) as string\n  const version = text(record.version, 'version', 64, true) as string\n  const description = text(record.description, 'description', 500, false)\n  for (const key of Reflect.ownKeys(record)) {\n    if (!['schemaVersion', 'id', 'name', 'version', 'description'].includes(String(key))) {\n      throw new MobileExtensionError('invalid_manifest', 'extension.json has unknown fields')\n    }\n  }\n  return Object.freeze({ schemaVersion: 1, id, name, version, ...(description === undefined ? {} : { description }) })\n}\n\nfunction normalizeRelativePath(value: string, field: string): string {\n  if (value.length === 0 || value.includes('\\0') || isAbsolute(value)) throw new MobileExtensionError('invalid_extension_path', `${field} is invalid`)\n  const normalized = value.replaceAll('\\\\', '/')\n  if (normalized.split('/').some(part => part === '' || part === '.' || part === '..')) {\n    throw new MobileExtensionError('invalid_extension_path', `${field} escapes extension directory`)\n  }\n  return normalized\n}\n\nasync function regularFile(path: string, maximum: number, field: string): Promise<{ readonly path: string; readonly size: number }> {\n  let info\n  try { info = await lstat(path) } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') throw new MobileExtensionError('invalid_extension', `${field} is missing`)\n    throw error\n  }\n  if (!info.isFile() || info.isSymbolicLink() || info.size > maximum) {\n    throw new MobileExtensionError('invalid_extension', `${field} must be a regular file within its size limit`)\n  }\n  return { path, size: info.size }\n}\n\nasync function containedPath(root: string, relativePath: string, maximum: number, field: string): Promise<{ readonly path: string; readonly size: number }> {\n  const normalized = normalizeRelativePath(relativePath, field)\n  const target = resolve(root, normalized)\n  const rootReal = await realpath(root)\n  const targetReal = await realpath(target)\n  const relation = relative(rootReal, targetReal)\n  if (relation === '' || relation.startsWith('..') || isAbsolute(relation)) throw new MobileExtensionError('invalid_extension_path', `${field} escapes extension directory`)\n  return regularFile(targetReal, maximum, field)\n}\n\nasync function optionalFile(root: string, name: string, maximum: number, field: string): Promise<string | undefined> {\n  try {\n    return (await containedPath(root, name, maximum, field)).path\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n    if (error instanceof MobileExtensionError && error.message.includes('is missing')) return undefined\n    throw error\n  }\n}\n\nasync function optionalBytes(root: string, name: string, maximum: number, field: string): Promise<Buffer | undefined> {\n  const path = await optionalFile(root, name, maximum, field)\n  return path === undefined ? undefined : readFile(path)\n}\n\nfunction assertRealPathWithin(rootReal: string, targetReal: string, field: string): void {\n  const relation = relative(rootReal, targetReal)\n  if (relation === '' || relation.startsWith('..') || isAbsolute(relation)) {\n    throw new MobileExtensionError('invalid_extension_path', `${field} escapes extension directory`)\n  }\n}\n\nasync function realExtensionRoot(directory: string): Promise<string> {\n  const root = resolve(directory)\n  const info = await lstat(root)\n  if (!info.isDirectory() || info.isSymbolicLink()) throw new MobileExtensionError('invalid_extension', 'extension directory must be real')\n  return realpath(root)\n}\n\nasync function assetSnapshot(extensionRootReal: string): Promise<ReadonlyMap<string, LocalAssetSnapshot>> {\n  const assetsPath = join(extensionRootReal, 'assets')\n  let assetsInfo\n  try { assetsInfo = await lstat(assetsPath) } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return new Map()\n    throw error\n  }\n  if (!assetsInfo.isDirectory() || assetsInfo.isSymbolicLink()) {\n    throw new MobileExtensionError('invalid_extension', 'assets must be a real directory')\n  }\n  const assetsReal = await realpath(assetsPath)\n  assertRealPathWithin(extensionRootReal, assetsReal, 'assets')\n  const snapshots = new Map<string, LocalAssetSnapshot>()\n  let totalBytes = 0\n  const visit = async (directoryReal: string, prefix: string, depth: number): Promise<void> => {\n    if (depth > EXTENSION_LIMITS.assetDepth) {\n      throw new MobileExtensionError('invalid_extension', 'asset tree exceeds its depth limit')\n    }\n    assertRealPathWithin(extensionRootReal, directoryReal, 'asset directory')\n    const handle = await opendir(directoryReal)\n    const entries: Dirent[] = []\n    try { for await (const entry of handle) entries.push(entry) }\n    finally { await handle.close().catch(() => undefined) }\n    entries.sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0)\n    for (const entry of entries) {\n      const path = join(directoryReal, entry.name)\n      const info = await lstat(path)\n      if (info.isSymbolicLink()) throw new MobileExtensionError('invalid_extension_path', 'asset escapes extension directory')\n      const targetReal = await realpath(path)\n      assertRealPathWithin(extensionRootReal, targetReal, 'asset')\n      const key = prefix === '' ? entry.name : `${prefix}/${entry.name}`\n      if (info.isDirectory()) {\n        await visit(targetReal, key, depth + 1)\n        continue\n      }\n      if (!info.isFile() || info.size > EXTENSION_LIMITS.asset) {\n        throw new MobileExtensionError('invalid_extension', 'asset must be a regular file within its size limit')\n      }\n      const body = await readFile(targetReal)\n      totalBytes += body.byteLength\n      if (snapshots.size >= EXTENSION_LIMITS.assetFiles || totalBytes > EXTENSION_LIMITS.assetBytes) {\n        throw new MobileExtensionError('invalid_extension', 'asset tree exceeds its aggregate limit')\n      }\n      snapshots.set(key, Object.freeze({ body, digest: createHash('sha256').update(body).digest('hex'), name: entry.name }))\n    }\n  }\n  await visit(assetsReal, '', 0)\n  return snapshots\n}\n\ninterface LocalExtensionFingerprint {\n  readonly manifest: LocalExtensionManifest\n  readonly digest: string\n  readonly scriptBody?: Buffer\n  readonly styleBody?: Buffer\n  readonly assets: ReadonlyMap<string, LocalAssetSnapshot>\n}\n\nasync function extensionFingerprint(directory: string): Promise<LocalExtensionFingerprint> {\n  const root = await realExtensionRoot(directory)\n  const manifestFile = await regularFile(join(root, 'extension.json'), EXTENSION_LIMITS.manifest, 'extension.json')\n  const manifestBody = await readFile(manifestFile.path)\n  const manifest = parseExtensionManifest(JSON.parse(manifestBody.toString('utf8')) as unknown)\n  if (manifest.id !== basename(root)) throw new MobileExtensionError('invalid_manifest', 'extension id must match its directory name')\n  const [host, script, style, assets] = await Promise.all([\n    optionalBytes(root, 'host.mjs', EXTENSION_LIMITS.script, 'host.mjs'),\n    optionalBytes(root, 'mobile.js', EXTENSION_LIMITS.script, 'mobile.js'),\n    optionalBytes(root, 'mobile.css', EXTENSION_LIMITS.css, 'mobile.css'),\n    assetSnapshot(root),\n  ])\n  const digest = createHash('sha256').update(`manifest:${manifestBody.byteLength}:`).update(createHash('sha256').update(manifestBody).digest())\n  for (const [name, body] of [['host', host], ['script', script], ['style', style]] as const) {\n    digest.update(`\\0${name}:${body?.byteLength ?? -1}:`)\n    if (body !== undefined) digest.update(createHash('sha256').update(body).digest())\n  }\n  for (const [name, asset] of assets) {\n    digest.update(`\\0asset:${Buffer.byteLength(name)}:${name}:${asset.body.byteLength}:${asset.digest}`)\n  }\n  return {\n    manifest,\n    digest: digest.digest('hex'),\n    assets,\n    ...(script === undefined ? {} : { scriptBody: script }),\n    ...(style === undefined ? {} : { styleBody: style }),\n  }\n}\n\nfunction routeKey(route: MobileHostRoute): string {\n  const method = route.method.toUpperCase()\n  const path = normalizeRoutePath(route.path)\n  return `${method} ${route.kind ?? 'exact'} ${path}`\n}\n\nfunction normalizeRoutePath(value: string): string {\n  if (typeof value !== 'string' || value.length === 0 || value.length > 256\n    || value.includes('?') || value.includes('#') || value.includes('\\\\') || value.includes('\\0')\n    || /[\\u0000-\\u001f\\u007f]/u.test(value)) throw new MobileExtensionError('invalid_route', 'extension route path is invalid')\n  const normalizedInput = value.startsWith('/') ? value : `/${value}`\n  const parts = normalizedInput.split('/')\n  if (parts.some(part => part === '..' || part === '.')) throw new MobileExtensionError('invalid_route', 'extension route path is invalid')\n  return normalizedInput === '/' ? '/' : normalizedInput.replace(/\\/+$/u, '')\n}\n\n/** Validate and snapshot an optional per-operation timeout override. */\nfunction operationTimeout(value: unknown, code: 'invalid_action' | 'invalid_route'): number | undefined {\n  if (value === undefined) return undefined\n  if (typeof value !== 'number' || !Number.isInteger(value) || value < 1 || value > HOST_OPERATION_TIMEOUT_MAX_MS) {\n    throw new MobileExtensionError(code, 'operation timeoutMs is invalid')\n  }\n  return value\n}\n\nfunction validateDefinition(definition: MobileExtensionDefinition): MobileExtensionDefinition {\n  const manifest = parseExtensionManifest({\n    schemaVersion: definition.schemaVersion,\n    id: definition.id,\n    name: definition.name,\n    version: definition.version,\n    ...(definition.description === undefined ? {} : { description: definition.description }),\n  })\n  const actionNames = new Set<string>()\n  const actions: Record<string, MobileHostAction> = {}\n  for (const [name, action] of Object.entries(definition.actions ?? {})) {\n    if (!/^[a-z][a-z0-9-]{0,63}$/u.test(name) || action === null || typeof action !== 'object' || typeof action.run !== 'function' || actionNames.has(name)) {\n      throw new MobileExtensionError('invalid_action', `invalid action ${name}`)\n    }\n    actionNames.add(name)\n    const actionTimeout = operationTimeout(action.timeoutMs, 'invalid_action')\n    const actionInput = action.input\n    actions[name] = Object.freeze({\n      ...(actionInput === undefined ? {} : { input: actionInput }),\n      run: action.run.bind(action),\n      ...(actionTimeout === undefined ? {} : { timeoutMs: actionTimeout }),\n    })\n  }\n  const routeNames = new Set<string>()\n  const routes = (definition.routes ?? []).map(route => {\n    if (route === null || typeof route !== 'object' || typeof route.handle !== 'function') throw new MobileExtensionError('invalid_route', 'invalid extension route')\n    const method = route.method.toUpperCase()\n    if (!['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) throw new MobileExtensionError('invalid_route', 'unsupported extension route method')\n    const routeTimeout = operationTimeout(route.timeoutMs, 'invalid_route')\n    const normalized: MobileHostRoute = Object.freeze({\n      method, path: normalizeRoutePath(route.path), ...(route.kind === undefined ? {} : { kind: route.kind }),\n      handle: route.handle.bind(route),\n      ...(routeTimeout === undefined ? {} : { timeoutMs: routeTimeout }),\n    })\n    const key = routeKey(normalized)\n    if (routeNames.has(key)) throw new MobileExtensionError('duplicate_route', `duplicate route ${key}`)\n    routeNames.add(key)\n    return normalized\n  })\n  return Object.freeze({ ...manifest, ...(definition.actions === undefined ? {} : { actions: Object.freeze(actions) }), ...(routes.length === 0 ? {} : { routes: Object.freeze(routes) }) })\n}\n\ninterface CombinedSignalLifetime {\n  readonly signal: AbortSignal\n  readonly cleanup: () => void\n}\n\nfunction combineSignalLifetime(first: AbortSignal, second: AbortSignal): CombinedSignalLifetime {\n  if (first.aborted || second.aborted) {\n    const aborted = new AbortController()\n    aborted.abort(first.aborted ? first.reason : second.reason)\n    return { signal: aborted.signal, cleanup: () => undefined }\n  }\n  const controller = new AbortController()\n  const cleanup = (): void => {\n    first.removeEventListener('abort', abortFirst)\n    second.removeEventListener('abort', abortSecond)\n  }\n  const abortFirst = (): void => { cleanup(); controller.abort(first.reason) }\n  const abortSecond = (): void => { cleanup(); controller.abort(second.reason) }\n  first.addEventListener('abort', abortFirst, { once: true })\n  second.addEventListener('abort', abortSecond, { once: true })\n  return { signal: controller.signal, cleanup }\n}\n\n/** Validate and normalize an action input through either supported schema form. */\nfunction parseActionInput(schema: MobileHostAction['input'], input: unknown): unknown {\n  if (schema === undefined) return input\n  if (typeof schema === 'function') return (schema as (value: unknown) => unknown)(input)\n  return schema.parse(input) ?? input\n}\n\n/** Combine two abort lifetimes without relying on AbortSignal.any in older WebViews. */\nexport function combineSignals(first: AbortSignal, second: AbortSignal): AbortSignal {\n  return combineSignalLifetime(first, second).signal\n}\n\n/** Host registry and service consumed by both npm plugins and local extensions. */\nexport class MobileAccessService extends Service {\n  private readonly registered = new Map<string, RegisteredExtension>()\n  private readonly local = new Map<string, ActiveLocalExtension>()\n  private readonly retired = new Map<string, RetiredLocalExtension>()\n  private readonly failures = new Map<string, string>()\n  /** Extensions with caller-detached, still-unresolved operations. */\n  private readonly abandoned = new Map<string, number>()\n  private readonly contentListeners = new Set<() => void>()\n  private contentHash = createHash('sha256').update('').digest('hex')\n  private localRoot: string | undefined\n  private localContext: Context | undefined\n  private localTimer: NodeJS.Timeout | undefined\n  private localRefreshing: Promise<void> | undefined\n  private localRefreshAbort: AbortController | undefined\n  private localLifecycle = 0\n  private localClosed = true\n  private localExecution: LocalExecutionOptions | undefined\n  private localExecutionKey: string | undefined\n  private workerBudget: ExtensionWorkerBudget | undefined\n  private readonly disposal = new Set<Promise<void>>()\n  private readonly recoveries = new Map<string, Promise<void>>()\n\n  constructor(ctx: Context) { super(ctx, 'mobileAccess') }\n\n  /** Register a normal Cordis extension and return an idempotent disposer. */\n  registerExtension(definition: MobileExtensionDefinition): () => void {\n    const validated = validateDefinition(definition)\n    if (this.registered.has(validated.id) || this.local.has(validated.id)) throw new Error(`mobile extension id already registered: ${validated.id}`)\n    const dispose = (): void => {\n      const current = this.registered.get(validated.id)\n      if (current?.dispose === dispose) {\n        this.registered.delete(validated.id)\n        this.updateContentHash()\n      }\n    }\n    this.registered.set(validated.id, { definition: validated, dispose })\n    this.updateContentHash()\n    return dispose\n  }\n\n  /** Aggregate digest covering every registered and active local extension. */\n  contentDigest(): string {\n    return this.contentHash\n  }\n\n  /** Subscribe to committed extension generation changes. */\n  onContentChanged(listener: () => void): () => void {\n    this.contentListeners.add(listener)\n    return () => { this.contentListeners.delete(listener) }\n  }\n\n  private updateContentHash(): void {\n    const parts = [\n      ...[...this.registered.values()].map(entry => entry.definition.id),\n      ...[...this.local.values()].map(active => `${active.manifest.id}:${active.digest}`),\n    ]\n    const next = createHash('sha256').update(parts.sort().join('|')).digest('hex')\n    if (next === this.contentHash) return\n    this.contentHash = next\n    for (const listener of this.contentListeners) {\n      try { listener() } catch { /* One observer cannot block a committed generation. */ }\n    }\n  }\n\n  /** Return the current client-facing manifest, deterministically sorted by id. */\n  manifest(): readonly MobileExtensionClientEntry[] {\n    const entries = new Map<string, MobileExtensionClientEntry>()\n    for (const { definition } of this.registered.values()) entries.set(definition.id, {\n      schemaVersion: 1, id: definition.id, name: definition.name, version: definition.version,\n      ...(definition.description === undefined ? {} : { description: definition.description }),\n    })\n    for (const active of this.local.values()) entries.set(active.manifest.id, {\n      ...active.manifest,\n      generation: active.digest,\n      ...(active.scriptBody === undefined ? {} : { scriptUrl: `/mobile-access/extensions/${active.manifest.id}/mobile.js?generation=${active.digest}` }),\n      ...(active.styleBody === undefined ? {} : { styleUrl: `/mobile-access/extensions/${active.manifest.id}/mobile.css?generation=${active.digest}` }),\n      assetsUrl: `/mobile-access/extensions/${active.manifest.id}/assets/`,\n    })\n    return [...entries.values()].sort((left, right) => left.id.localeCompare(right.id))\n  }\n\n  /** Return loaded and failed local extension counts without exposing host errors. */\n  status(): MobileExtensionStatus {\n    const unavailable = [...this.local.values()].filter(entry => entry.worker !== undefined && !entry.worker.available()).length\n    return Object.freeze({ loaded: this.registered.size + this.local.size - unavailable, failed: this.failures.size + unavailable })\n  }\n\n  /** Local Host status does not reveal filesystem paths, credentials or extension errors. */\n  hostStatus(): { readonly hosts: readonly { readonly id: string; readonly name: string; readonly mode: 'worker' | 'in-process'; readonly state: 'ready' | 'unavailable'; readonly generation: string }[]; readonly limits: { readonly maxWorkers: number; readonly workers: number } } {\n    const limits = resolveHostExecution(this.localExecution?.hostExecution)\n    return {\n      hosts: [...this.local.values()].map(entry => ({ id: entry.manifest.id, name: entry.manifest.name, mode: entry.worker === undefined ? 'in-process' : 'worker', state: entry.worker === undefined || entry.worker.available() ? 'ready' : 'unavailable', generation: entry.digest })),\n      limits: { maxWorkers: limits.maxWorkers, workers: this.workerBudget?.current ?? 0 },\n    }\n  }\n\n  /** Explicitly replace one unavailable worker without replaying requests or changing its files. */\n  recoverExtension(id: string): Promise<void> {\n    assertExtensionId(id)\n    const existing = this.recoveries.get(id)\n    if (existing !== undefined) return existing\n    const recovering = (async (): Promise<void> => {\n      if (this.localRefreshing !== undefined) await this.localRefreshing\n      const previous = this.local.get(id)\n      if (this.localClosed || previous?.worker === undefined || this.localContext === undefined) throw new MobileExtensionError('extension_recovery_unavailable', 'local worker recovery is unavailable', 409)\n      if (previous.worker.available()) throw new MobileExtensionError('extension_host_running', 'extension worker is already running', 409)\n      await previous.worker.terminate('explicit-recovery')\n      const lifecycle = this.localLifecycle\n      const fingerprint = await extensionFingerprint(previous.directory)\n      const fresh = await loadLocalExtension(previous.directory, this.localContext, fingerprint, undefined, this.localExecution)\n      try {\n        const confirmed = await extensionFingerprint(previous.directory)\n        if (this.localClosed || this.localLifecycle !== lifecycle || this.local.get(id) !== previous || confirmed.digest !== fingerprint.digest) throw new MobileExtensionError('extension_changed_during_activation', 'extension changed during recovery', 409)\n      } catch (error) { await abortAndDisposeLocal([fresh]); throw error }\n      this.local.set(id, fresh)\n      this.failures.delete(id)\n      this.queueDisposal([previous])\n      this.updateContentHash()\n    })().finally(() => { if (this.recoveries.get(id) === recovering) this.recoveries.delete(id) })\n    this.recoveries.set(id, recovering)\n    return recovering\n  }\n\n  private queueDisposal(entries: readonly ActiveLocalExtension[]): void {\n    const pending = abortAndDisposeLocal(entries).finally(() => { this.disposal.delete(pending) })\n    this.disposal.add(pending)\n  }\n\n  /** Locate one active extension. */\n  extension(id: string, generation?: string): MobileExtensionDefinition | ActiveLocalExtension | undefined {\n    if (generation !== undefined) {\n      const current = this.local.get(id)\n      if (current?.digest === generation) return current\n      const previous = this.retired.get(id)?.active\n      return previous?.digest === generation ? previous : undefined\n    }\n    return this.local.get(id) ?? this.registered.get(id)?.definition\n  }\n\n  /** Return the active local generation signal for gateway cancellation wiring. */\n  signal(id: string, generation?: string): AbortSignal | undefined {\n    const extension = this.extension(id, generation)\n    return extension !== undefined && 'host' in extension ? extension.controller.signal : undefined\n  }\n\n  /** Read a local client entry after validating that it remains inside its directory. */\n  async readClientFile(id: string, kind: 'script' | 'style', signal?: AbortSignal, generation?: string): Promise<{ readonly body: Buffer; readonly digest: string }> {\n    signal?.throwIfAborted()\n    const selected = this.extension(id, generation)\n    const active = selected !== undefined && 'host' in selected ? selected : undefined\n    if (active === undefined) throw new MobileExtensionError('extension_generation_not_found', 'extension generation not found', 404)\n    const snapshot = kind === 'script' ? active.scriptBody : active.styleBody\n    if (snapshot === undefined) throw new MobileExtensionError('extension_asset_not_found', 'extension asset not found', 404)\n    const body = Buffer.from(snapshot)\n    return { body, digest: createHash('sha256').update(body).digest('hex') }\n  }\n\n  /** Read a generation-pinned static asset from its validated snapshot. */\n  async readAsset(id: string, assetPath: string, signal?: AbortSignal, generation?: string): Promise<{ readonly body: Buffer; readonly digest: string; readonly name: string }> {\n    signal?.throwIfAborted()\n    const selected = this.extension(id, generation)\n    const active = selected !== undefined && 'host' in selected ? selected : undefined\n    if (active === undefined) throw new MobileExtensionError('extension_generation_not_found', 'extension generation not found', 404)\n    const normalized = normalizeRelativePath(assetPath, 'asset')\n    const asset = active.assets.get(normalized)\n    if (asset === undefined) throw new MobileExtensionError('extension_asset_not_found', 'extension asset not found', 404)\n    return { body: Buffer.from(asset.body), digest: asset.digest, name: asset.name }\n  }\n\n  /** Reject new dispatches to an extension whose abandoned work is unresolved. */\n  private requireAdmission(id: string): void {\n    if ((this.abandoned.get(id) ?? 0) > 0) {\n      throw new MobileExtensionError('extension_busy', `extension ${id} has unresolved abandoned work`, 503)\n    }\n  }\n\n  /** Account for one operation until its underlying work actually settles. */\n  private trackOperation<T>(id: string, operation: BoundedOperation<T>): void {\n    operation.settled.then(() => {\n      if (operation.detached()) {\n        const remaining = (this.abandoned.get(id) ?? 1) - 1\n        if (remaining <= 0) this.abandoned.delete(id)\n        else this.abandoned.set(id, remaining)\n      }\n    }).catch(() => undefined)\n  }\n\n  /** Invoke one action after parsing its input and binding the request lifetime. */\n  async invoke(id: string, actionName: string, input: unknown, context: MobileActionContext, generation?: string): Promise<unknown> {\n    const extension = this.extension(id, generation)\n    if (extension === undefined) throw new MobileExtensionError('extension_not_found', 'extension not found', 404)\n    const definition = 'host' in extension ? extension.host : extension\n    const action = definition.actions?.[actionName]\n    if (action === undefined) throw new MobileExtensionError('action_not_found', 'action not found', 404)\n    // A cancelled invocation must not execute host code or occupy admission accounting.\n    if ('host' in extension) extension.controller.signal.throwIfAborted()\n    context.signal.throwIfAborted()\n    this.requireAdmission(id)\n    const external = 'host' in extension ? combineSignalLifetime(extension.controller.signal, context.signal) : undefined\n    let operation: BoundedOperation<unknown> | undefined\n    try {\n      operation = startBoundedOperation(\n        signal => {\n          let parsed: unknown\n          try { parsed = parseActionInput(action.input, input) } catch { throw new MobileExtensionError('invalid_action_input', 'action input is invalid', 400) }\n          // Schema callables and parse adapters may validate asynchronously; both stay inside the budget,\n          // and a caller that detached mid-parse must not start a further execution stage.\n          return Promise.resolve(parsed).then(\n            value => {\n              signal.throwIfAborted()\n              return action.run({ ...context, signal }, value)\n            },\n            () => { throw new MobileExtensionError('invalid_action_input', 'action input is invalid', 400) },\n          )\n        },\n        {\n          external: external?.signal ?? context.signal,\n          timeoutMs: action.timeoutMs ?? ('host' in extension && extension.worker !== undefined ? resolveHostExecution(this.localExecution?.hostExecution).operationTimeoutMs : HOST_OPERATION_TIMEOUT_MS),\n          timeoutError: () => new MobileExtensionError('extension_action_timeout', `extension ${id} action ${actionName} timed out`, 500),\n          onDetach: () => { this.abandoned.set(id, (this.abandoned.get(id) ?? 0) + 1) },\n        },\n      )\n      this.trackOperation(id, operation)\n      // Action values are JSON-serialized downstream; late values are simply discarded.\n      return await operation.caller\n    } catch (error) {\n      if (error instanceof OperationCancelled) throw error.reason\n      if (error instanceof MobileExtensionError) throw error\n      throw new MobileExtensionError('extension_failed', 'extension action failed', 500)\n    } finally {\n      operation?.release()\n      external?.cleanup()\n    }\n  }\n\n  /** Match one route and invoke it with a generation-bound abort signal. */\n  async route(id: string, method: string, pathname: string, request: MobileRouteRequest, generation?: string): Promise<MobileRouteResponse> {\n    const extension = this.extension(id, generation)\n    if (extension === undefined) throw new MobileExtensionError('extension_not_found', 'extension not found', 404)\n    const definition = 'host' in extension ? extension.host : extension\n    const route = definition.routes?.find((candidate: MobileHostRoute) => {\n      if (candidate.method !== method) return false\n      return (candidate.kind ?? 'exact') === 'exact'\n        ? candidate.path === pathname\n        : candidate.path === '/' || pathname === candidate.path || pathname.startsWith(`${candidate.path}/`)\n    })\n    if (route === undefined) throw new MobileExtensionError('route_not_found', 'route not found', 404)\n    // A cancelled request must not execute host code or occupy admission accounting.\n    if ('host' in extension) extension.controller.signal.throwIfAborted()\n    request.signal.throwIfAborted()\n    this.requireAdmission(id)\n    const external = 'host' in extension ? combineSignalLifetime(extension.controller.signal, request.signal) : undefined\n    let operation: BoundedOperation<MobileRouteResponse> | undefined\n    let holdForStream = false\n    try {\n      operation = startBoundedOperation(\n        signal => route.handle({ ...request, signal }),\n        {\n          external: external?.signal ?? request.signal,\n          timeoutMs: route.timeoutMs ?? ('host' in extension && extension.worker !== undefined ? resolveHostExecution(this.localExecution?.hostExecution).operationTimeoutMs : HOST_OPERATION_TIMEOUT_MS),\n          timeoutError: () => new MobileExtensionError('extension_route_timeout', `extension ${id} route ${method} ${pathname} timed out`, 500),\n          onDetach: () => { this.abandoned.set(id, (this.abandoned.get(id) ?? 0) + 1) },\n        },\n      )\n      this.trackOperation(id, operation)\n      // A handler that resolves after its deadline may still open a stream nobody owns.\n      operation.settled.then(() => {\n        disposeLateExtensionResponse(operation?.lateValue())\n      }).catch(() => undefined)\n      const result = await operation.caller\n      if (result === null || typeof result !== 'object' || typeof result.body !== 'string' && !(result.body instanceof Uint8Array) && !isReadable(result.body)) {\n        throw new MobileExtensionError('invalid_route_response', 'extension returned an invalid response', 500)\n      }\n      if (isReadable(result.body)) {\n        // The deadline ended at resolution; request and generation cancellation\n        // keep flowing until the returned stream itself settles.\n        holdForStream = true\n        releaseSignalLifetimeWhenStreamSettles(result.body, () => { operation?.release(); external?.cleanup() })\n      }\n      return result\n    } catch (error) {\n      if (error instanceof OperationCancelled) throw error.reason\n      if (error instanceof MobileExtensionError) throw error\n      throw new MobileExtensionError('extension_failed', 'extension route failed', 500)\n    } finally {\n      if (!holdForStream) {\n        operation?.release()\n        external?.cleanup()\n      }\n    }\n  }\n\n  /** Start the local directory watcher; an absent directory is intentionally inert. */\n  async startLocal(root: string, context: Context, options?: LocalExecutionOptions): Promise<void> {\n    const targetRoot = resolve(root)\n    const limits = resolveHostExecution(options?.hostExecution)\n    const executionKey = JSON.stringify({ limits, module: options?.hostExecution?.workerModule })\n    if (this.localRoot !== undefined && (resolve(this.localRoot) !== targetRoot || this.localExecutionKey !== executionKey)) await this.stopLocal()\n    if (this.localTimer !== undefined) clearInterval(this.localTimer)\n    const lifecycle = ++this.localLifecycle\n    this.workerBudget ??= new ExtensionWorkerBudget(limits.maxWorkers)\n    this.localRoot = targetRoot; this.localContext = context; this.localExecution = { ...options, workerBudget: this.workerBudget }; this.localExecutionKey = executionKey; this.localClosed = false\n    await mkdir(this.localRoot, { recursive: true })\n    if (this.localClosed || this.localLifecycle !== lifecycle || this.localRoot !== targetRoot || this.localContext !== context) return\n    await this.refreshLocal()\n    if (this.localClosed || this.localLifecycle !== lifecycle || this.localRoot !== targetRoot || this.localContext !== context) return\n    this.localTimer = setInterval(() => { void this.refreshLocal() }, 2_000)\n    this.localTimer.unref()\n  }\n\n  /** Stop the watcher and abort every local host generation. */\n  async stopLocal(): Promise<void> {\n    this.localClosed = true\n    const lifecycle = ++this.localLifecycle\n    if (this.localTimer !== undefined) clearInterval(this.localTimer)\n    this.localTimer = undefined\n    const refreshing = this.localRefreshing\n    this.localRefreshAbort?.abort()\n    const previous = [...this.local.values(), ...[...this.retired.values()].map(entry => entry.active)]\n    this.local.clear()\n    for (const entry of this.retired.values()) clearTimeout(entry.timer)\n    this.retired.clear()\n    this.failures.clear()\n    this.updateContentHash()\n    await Promise.allSettled([\n      abortAndDisposeLocal(previous),\n      ...(refreshing === undefined ? [] : [refreshing]),\n    ])\n    if (this.localLifecycle !== lifecycle) return\n    const late = [...this.local.values(), ...[...this.retired.values()].map(entry => entry.active)]\n    this.local.clear()\n    for (const entry of this.retired.values()) clearTimeout(entry.timer)\n    this.retired.clear()\n    this.failures.clear()\n    this.updateContentHash()\n    await abortAndDisposeLocal(late)\n    await Promise.allSettled([...this.disposal, ...this.recoveries.values()])\n    this.workerBudget = undefined\n    if (this.localTimer !== undefined) clearInterval(this.localTimer)\n    this.localTimer = undefined\n  }\n\n  /** Refresh all local extensions atomically; failures keep the previous snapshot. */\n  refreshLocal(): Promise<void> {\n    if (this.localRefreshing !== undefined) return this.localRefreshing\n    const controller = new AbortController()\n    this.localRefreshAbort = controller\n    const refreshing = this.stageAndCommit(controller.signal).finally(() => {\n      if (this.localRefreshing === refreshing) this.localRefreshing = undefined\n      if (this.localRefreshAbort === controller) this.localRefreshAbort = undefined\n    })\n    this.localRefreshing = refreshing\n    return refreshing\n  }\n\n  private async stageAndCommit(signal: AbortSignal): Promise<void> {\n    if (this.localClosed || signal.aborted || this.localRoot === undefined || this.localContext === undefined) return\n    let names: string[] = []\n    try {\n      const directory = await opendir(this.localRoot)\n      try { for await (const entry of directory) if (entry.isDirectory() && !entry.isSymbolicLink()) names.push(entry.name) }\n      finally { await directory.close().catch(() => undefined) }\n    } catch { return }\n    names.sort()\n    const staged: ActiveLocalExtension[] = []\n    const stagedFresh: ActiveLocalExtension[] = []\n    let failingName = 'local'\n    try {\n      for (const name of names) {\n        signal.throwIfAborted()\n        failingName = name\n        const directory = join(this.localRoot, name)\n        const fingerprint = await extensionFingerprint(directory)\n        const current = this.local.get(fingerprint.manifest.id)\n        const retired = this.retired.get(fingerprint.manifest.id)?.active\n        const previous = current?.digest === fingerprint.digest ? current : retired?.digest === fingerprint.digest ? retired : undefined\n        if (previous?.digest === fingerprint.digest) staged.push(previous)\n        else {\n          const fresh = await loadLocalExtension(directory, this.localContext, fingerprint, signal, this.localExecution)\n          try {\n            signal.throwIfAborted()\n            const confirmed = await extensionFingerprint(directory)\n            if (confirmed.digest !== fingerprint.digest) {\n              throw new MobileExtensionError('extension_changed_during_activation', `extension ${fingerprint.manifest.id} changed during activation`, 409)\n            }\n          } catch (error) {\n            await abortAndDisposeLocal([fresh])\n            throw error\n          }\n          staged.push(fresh); stagedFresh.push(fresh)\n        }\n      }\n      if (this.localClosed || signal.aborted || this.localRoot === undefined || this.localContext === undefined) {\n        await abortAndDisposeLocal(stagedFresh)\n        return\n      }\n      const duplicate = new Set<string>()\n      for (const entry of staged) {\n        if (duplicate.has(entry.manifest.id) || this.registered.has(entry.manifest.id)) throw new MobileExtensionError('duplicate_extension', `duplicate extension id ${entry.manifest.id}`)\n        duplicate.add(entry.manifest.id)\n      }\n      const previous = [...this.local.values()]\n      for (const entry of staged) {\n        const retired = this.retired.get(entry.manifest.id)\n        if (retired?.active === entry) {\n          clearTimeout(retired.timer)\n          this.retired.delete(entry.manifest.id)\n        }\n      }\n      const stagedIds = new Set(staged.map(entry => entry.manifest.id))\n      const removed: ActiveLocalExtension[] = []\n      for (const entry of previous) {\n        if (staged.includes(entry)) continue\n        if (stagedIds.has(entry.manifest.id)) {\n          this.retire(entry)\n          continue\n        }\n        removed.push(entry)\n        const retired = this.retired.get(entry.manifest.id)\n        if (retired !== undefined) {\n          clearTimeout(retired.timer)\n          this.retired.delete(entry.manifest.id)\n          removed.push(retired.active)\n        }\n      }\n      this.local.clear()\n      for (const entry of staged) this.local.set(entry.manifest.id, entry)\n      for (const entry of staged) this.failures.delete(entry.manifest.id)\n      for (const name of names) this.failures.delete(name)\n      for (const failure of this.failures.keys()) {\n        if (failure !== 'local' && !names.includes(failure)) this.failures.delete(failure)\n      }\n      this.failures.delete('local')\n      if (removed.length > 0) this.queueDisposal(removed)\n      this.updateContentHash()\n    } catch (error) {\n      await abortAndDisposeLocal(stagedFresh)\n      if (this.localClosed || signal.aborted) return\n      const message = error instanceof Error ? error.message : String(error)\n      const changedFailure=this.failures.get(failingName)!==message\n      this.failures.set(failingName, message)\n      if(changedFailure&&error instanceof MobileExtensionError&&error.code==='extension_worker_heap_override')this.ctx.logger.warn('local extension worker refused: %s',error.message)\n      if (!(error instanceof MobileExtensionError)) this.ctx.logger.warn(error instanceof Error ? error : new Error(String(error)))\n    }\n  }\n\n  private retire(active: ActiveLocalExtension): void {\n    const previous = this.retired.get(active.manifest.id)\n    if (previous?.active === active) return\n    if (previous !== undefined) {\n      clearTimeout(previous.timer)\n      this.retired.delete(active.manifest.id)\n      this.queueDisposal([previous.active])\n    }\n    const timer = setTimeout(() => {\n      const current = this.retired.get(active.manifest.id)\n      if (current?.active !== active) return\n      this.retired.delete(active.manifest.id)\n      this.queueDisposal([active])\n    }, RETIRED_GENERATION_TTL_MS)\n    timer.unref()\n    this.retired.set(active.manifest.id, { active, timer })\n  }\n}\n\nfunction isReadable(value: unknown): value is Readable {\n  return value !== null && typeof value === 'object' && typeof (value as { pipe?: unknown }).pipe === 'function'\n}\n\n/** Destroy a route response that arrived after its caller detached; must never throw or emit unhandled stream errors. */\nexport function disposeLateExtensionResponse(value: unknown): void {\n  try {\n    if (value === null || typeof value !== 'object') return\n    const body = (value as { readonly body?: unknown }).body\n    if (!isReadable(body) || typeof body.once !== 'function' || typeof body.destroy !== 'function') return\n    body.once('error', () => undefined)\n    body.destroy()\n  } catch { /* Invalid late results and disposal failures must not escape. */ }\n}\n\nfunction releaseSignalLifetimeWhenStreamSettles(stream: Readable, cleanup: () => void): void {\n  let stopObserving: (() => void) | undefined\n  stopObserving = finished(stream, () => {\n    stopObserving?.()\n    cleanup()\n  })\n}\n\nfunction invokeCleanups(cleanups: readonly (() => void | Promise<void>)[]): Promise<unknown>[] {\n  const pending: Promise<unknown>[] = []\n  for (const cleanup of [...cleanups].reverse()) {\n    try { pending.push(Promise.resolve(cleanup())) } catch { /* extension teardown cannot block the owner */ }\n  }\n  return pending\n}\n\nasync function settleBounded(pending: readonly Promise<unknown>[], timeoutMs: number): Promise<void> {\n  if (pending.length === 0) return\n  let timer: NodeJS.Timeout | undefined\n  await Promise.race([\n    Promise.allSettled(pending),\n    new Promise<void>(resolveTimeout => { timer = setTimeout(resolveTimeout, timeoutMs) }),\n  ])\n  if (timer !== undefined) clearTimeout(timer)\n}\n\n/** Sentinel distinguishing caller detachment (deadline or external cancel) from a host error. */\nclass OperationCancelled {\n  constructor(readonly reason: unknown) {}\n}\n\n/**\n * Run one extension operation under a per-invocation deadline.\n *\n * Releasing the caller, stopping the wait, and stopping the work are separate\n * concerns: the caller settles at the deadline (or on external cancellation)\n * even when the host ignores its signal, while the underlying work is observed\n * to settlement so late results can be disposed and accounted for.\n */\ninterface BoundedOperation<T> {\n  /** Settles exactly once with the caller-visible outcome. */\n  readonly caller: Promise<T>\n  /** Settles when the underlying work settles; never rejects. */\n  readonly settled: Promise<void>\n  /** Whether the caller detached before the work settled. */\n  detached(): boolean\n  /** The value when the work fulfilled after the caller detached. */\n  lateValue(): T | undefined\n  /** End the per-invocation cancellation lifetime exactly once. */\n  release(): void\n}\n\nfunction startBoundedOperation<T>(\n  start: (signal: AbortSignal) => T | Promise<T>,\n  options: {\n    readonly external: AbortSignal | undefined\n    readonly timeoutMs: number\n    readonly timeoutError: () => MobileExtensionError\n    /** Invoked at most once when the caller detaches with work unresolved. */\n    readonly onDetach?: () => void\n  },\n): BoundedOperation<T> {\n  const deadline = new AbortController()\n  const combined = options.external === undefined\n    ? { signal: deadline.signal, cleanup: (): void => undefined }\n    : combineSignalLifetime(options.external, deadline.signal)\n  let detached = false\n  let workState: 'fulfilled' | 'rejected' | undefined\n  let lateFulfilled: T | undefined\n  let notifySettled: (() => void) | undefined\n  let callerTimer: NodeJS.Timeout | undefined\n  let onExternal: (() => void) | undefined\n  const settled = new Promise<void>(resolve => { notifySettled = resolve })\n  const detach = (reject: (reason?: unknown) => void, reason: unknown): void => {\n    // A queued timer must not detach work that already settled.\n    if (detached || workState !== undefined) return\n    detached = true\n    // The caller is gone: stop its timer and observer, and record abandonment\n    // before firing cancellation listeners so re-entrant dispatch is gated.\n    if (callerTimer !== undefined) clearTimeout(callerTimer)\n    if (onExternal !== undefined) options.external?.removeEventListener('abort', onExternal)\n    options.onDetach?.()\n    deadline.abort(reason)\n    reject(new OperationCancelled(reason))\n  }\n  const caller = new Promise<T>((resolve, reject) => {\n    callerTimer = setTimeout(() => detach(reject, options.timeoutError()), options.timeoutMs)\n    onExternal = (): void => { detach(reject, combined.signal.reason) }\n    options.external?.addEventListener('abort', onExternal, { once: true })\n    void (async (): Promise<void> => {\n      try {\n        const value = await start(combined.signal)\n        workState = 'fulfilled'\n        if (callerTimer !== undefined) clearTimeout(callerTimer)\n        if (onExternal !== undefined) options.external?.removeEventListener('abort', onExternal)\n        // A detached caller owns nothing anymore; a live caller decides via release().\n        if (detached) combined.cleanup()\n        if (detached) lateFulfilled = value\n        else resolve(value)\n        notifySettled?.()\n      } catch (error) {\n        workState = 'rejected'\n        if (callerTimer !== undefined) clearTimeout(callerTimer)\n        if (onExternal !== undefined) options.external?.removeEventListener('abort', onExternal)\n        if (detached) combined.cleanup()\n        if (!detached) reject(error)\n        notifySettled?.()\n      }\n    })()\n  })\n  let released = false\n  return {\n    caller,\n    settled,\n    detached: () => detached,\n    lateValue: () => (detached && workState === 'fulfilled' ? lateFulfilled : undefined),\n    release: () => { if (!released) { released = true; combined.cleanup() } },\n  }\n}\n\nasync function abortAndDisposeLocal(entries: readonly ActiveLocalExtension[]): Promise<void> {\n  const pending: Promise<unknown>[] = []\n  for (const entry of entries) {\n    entry.controller.abort()\n    pending.push(...invokeCleanups(entry.cleanups))\n  }\n  await settleBounded(pending, HOST_TEARDOWN_TIMEOUT_MS)\n  // Worker disposal requires confirmed exit even when its effect cleanup exceeded the advisory budget.\n  await Promise.all(entries.flatMap(entry => entry.worker === undefined ? [] : [entry.worker.dispose()]))\n}\n\nasync function loadLocalExtension(directory: string, context: Context, known?: LocalExtensionFingerprint, parentSignal?: AbortSignal, execution?: LocalExecutionOptions): Promise<ActiveLocalExtension> {\n  const root = await realExtensionRoot(directory)\n  const manifestFile = await regularFile(join(root, 'extension.json'), EXTENSION_LIMITS.manifest, 'extension.json')\n  const manifest = known?.manifest ?? parseExtensionManifest(JSON.parse(await readFile(manifestFile.path, 'utf8')) as unknown)\n  if (manifest.id !== basename(root)) throw new MobileExtensionError('invalid_manifest', 'extension id must match its directory name')\n  const scriptBody = known === undefined\n    ? await optionalFile(root, 'mobile.js', EXTENSION_LIMITS.script, 'mobile.js').then(path => path === undefined ? undefined : readFile(path))\n    : known.scriptBody\n  const styleBody = known === undefined\n    ? await optionalFile(root, 'mobile.css', EXTENSION_LIMITS.css, 'mobile.css').then(path => path === undefined ? undefined : readFile(path))\n    : known.styleBody\n  const assets = known?.assets ?? await assetSnapshot(root)\n  const hostFile = await optionalFile(root, 'host.mjs', EXTENSION_LIMITS.script, 'host.mjs')\n  const controller = new AbortController()\n  const actions: Record<string, MobileHostAction> = {}\n  const routes: MobileHostRoute[] = []\n  const cleanups: (() => void | Promise<void>)[] = []\n  const pendingEffects: Promise<void>[] = []\n  let activationOpen = true\n  const onParentAbort = (): void => { controller.abort(parentSignal?.reason) }\n  if (parentSignal?.aborted === true) onParentAbort()\n  else parentSignal?.addEventListener('abort', onParentAbort, { once: true })\n  const ensureActivationOpen = (): void => {\n    if (!activationOpen || controller.signal.aborted) throw new MobileExtensionError('host_activation_closed', `extension ${manifest.id} activation is closed`, 409)\n  }\n  const api: HostApi = {\n    manifest,\n    context,\n    schema: z,\n    signal: controller.signal,\n    action(name, spec) { ensureActivationOpen(); if (actions[name] !== undefined) throw new MobileExtensionError('duplicate_action', `duplicate action ${name}`); actions[name] = spec },\n    route(spec) { ensureActivationOpen(); routes.push(spec) },\n    effect(setup) {\n      ensureActivationOpen()\n      const result = setup()\n      if (result instanceof Promise) {\n        pendingEffects.push(result.then(async cleanup => {\n          if (typeof cleanup !== 'function') return\n          if (activationOpen) cleanups.push(cleanup)\n          else await cleanup()\n        }))\n      } else if (typeof result === 'function') {\n        if (activationOpen) cleanups.push(result)\n        else void Promise.resolve(result()).catch(() => undefined)\n      }\n    },\n  }\n  try {\n    // Worker mode: all executable host behavior runs inside one worker\n    // per generation; registration crosses as metadata only and action results\n    // cross as worker-serialized bytes.\n    const limits = resolveHostExecution(execution?.hostExecution)\n    const selected = limits.mode === 'worker' && (limits.extensions === undefined || limits.extensions.includes(manifest.id))\n    const worker = selected && hostFile !== undefined\n      ? new ExtensionWorkerHost({\n        workerModule: execution?.hostExecution?.workerModule ?? defaultExtensionWorkerModule(),\n        hostFile,\n        manifest,\n        generation: known?.digest ?? createHash('sha256').update(manifest.id).digest('hex'),\n        logger: workerLoggerAdapter(context),\n        limits,\n        ...(execution?.workerBudget === undefined ? {} : { budget: execution.workerBudget }),\n        onUnavailable: error => { controller.abort(error) },\n      })\n      : undefined\n    let host: MobileExtensionDefinition\n    if (worker !== undefined) {\n      try {\n        // Worker activation owns its configured deadline; this wait only observes cancellation.\n        await withActivationTimeout(worker.activate(), manifest.id, controller.signal, undefined)\n      } catch (error) {\n        // A failed activation must not leak a live worker thread (the watcher\n        // retries every interval).\n        await worker.terminate('activation-failed')\n        throw error\n      }\n      const proxyActions: Record<string, MobileHostAction> = {}\n      for (const metadata of worker.actionMetadata()) {\n        proxyActions[metadata.name] = {\n          ...(metadata.timeoutMs === undefined ? {} : { timeoutMs: metadata.timeoutMs }),\n          run: (actionContext, input) => worker.invokeExecution(metadata.name, input, actionContext),\n        }\n      }\n      const proxyRoutes: MobileHostRoute[] = worker.routeMetadata().map((metadata, index) => ({\n        method: metadata.method,\n        path: metadata.path,\n        ...(metadata.kind === undefined ? {} : { kind: metadata.kind }),\n        ...(metadata.timeoutMs === undefined ? {} : { timeoutMs: metadata.timeoutMs }),\n        handle: request => worker.handleRouteExecution(index, request),\n      }))\n      try {\n        host = validateDefinition({ ...manifest, ...(Object.keys(proxyActions).length === 0 ? {} : { actions: proxyActions }), ...(proxyRoutes.length === 0 ? {} : { routes: proxyRoutes }) })\n      } catch (error) {\n        await worker.terminate('definition-invalid')\n        throw error\n      }\n      // Worker lifecycle cleanup is owned separately from advisory in-process effect cleanup.\n    } else {\n      const activate = async (): Promise<void> => {\n        controller.signal.throwIfAborted()\n        if (hostFile !== undefined) {\n          const digest = createHash('sha256').update(await readFile(hostFile)).digest('hex')\n          controller.signal.throwIfAborted()\n          let imported: LocalHostModule\n          try { imported = await import(`${pathToFileURL(hostFile).href}?dsh_generation=${digest}`) as LocalHostModule }\n          catch { throw new MobileExtensionError('host_load_failed', `could not load ${manifest.id}/host.mjs`, 500) }\n          controller.signal.throwIfAborted()\n          if (imported.default !== undefined) await imported.default(api)\n        }\n        await Promise.all(pendingEffects)\n      }\n      await withActivationTimeout(activate(), manifest.id, controller.signal, HOST_ACTIVATION_TIMEOUT_MS)\n      host = validateDefinition({ ...manifest, actions, routes })\n    }\n    activationOpen = false\n    const digest = known?.digest ?? createHash('sha256').update(manifest.id).digest('hex')\n    return Object.freeze({ manifest, directory: root, ...(scriptBody === undefined ? {} : { scriptBody }), ...(styleBody === undefined ? {} : { styleBody }), assets, host, controller, cleanups: Object.freeze(cleanups), digest, ...(worker === undefined ? {} : { worker }) })\n  } catch (error) {\n    activationOpen = false\n    controller.abort()\n    const cleanupPromises = invokeCleanups(cleanups.splice(0))\n    await settleBounded([...pendingEffects, ...cleanupPromises], HOST_TEARDOWN_TIMEOUT_MS)\n    throw error\n  } finally {\n    parentSignal?.removeEventListener('abort', onParentAbort)\n  }\n}\n\n/** Forward the worker's logger-only context adapter into the plugin logger. */\nfunction workerLoggerAdapter(context: Context): WorkerParentLogger {\n  return {\n    debug: (...args: unknown[]) => { context.logger.debug(...args as Parameters<typeof context.logger.debug>) },\n    info: (...args: unknown[]) => { context.logger.info(...args as Parameters<typeof context.logger.info>) },\n    warn: (...args: unknown[]) => { context.logger.warn(...args as Parameters<typeof context.logger.warn>) },\n    error: (...args: unknown[]) => { context.logger.error(...args as Parameters<typeof context.logger.error>) },\n  }\n}\n\n/** Construct the service in a Cordis plugin without importing DSH internals. */\nexport function createMobileAccessService(ctx: Context): MobileAccessService {\n  return new MobileAccessService(ctx)\n}\n","/** Browser-facing pairing and reauthentication pages with language negotiation. */\nexport type AuthPageLocale = 'zh' | 'en' | 'it'\n\ninterface AuthPageCopy {\n  readonly lang: string\n  readonly pairTitle: string\n  readonly pairHeading: string\n  readonly pairingCode: string\n  readonly pairingCodeHint: string\n  readonly invalidPairingCode: string\n  readonly appKeyNotCode: string\n  readonly deviceName: string\n  readonly pair: string\n  readonly pairing: string\n  readonly pairFailed: string\n  readonly pairingExpired: string\n  readonly pairingLimited: string\n  readonly deviceLimit: string\n  readonly unavailable: string\n  readonly reconnectTitle: string\n  readonly reconnectHeading: string\n  readonly restoring: string\n  readonly noLongerPaired: string\n  readonly openPairing: string\n}\n\nconst COPY: Record<AuthPageLocale, AuthPageCopy> = {\n  en: {\n    lang: 'en', pairTitle: 'Pair DSH mobile access', pairHeading: 'Pair this device',\n    pairingCode: 'Pairing code', deviceName: 'Device name', pair: 'Pair', pairing: 'Pairing…',\n    pairingCodeHint: 'Use the 43-character pairing code shown on the computer. Keys starting with dsh1. or dsh2. are for the Android app.',\n    invalidPairingCode: 'Enter the 43-character pairing code from the current pairing window on the computer.',\n    appKeyNotCode: 'This is an Android app key. Use it in the app, or copy the browser pairing code from the computer.',\n    pairFailed: 'Pairing failed. Check the code or generate a new one on the computer.',\n    pairingExpired: 'The pairing code is invalid or has expired. Generate a new code on the computer and try again.',\n    pairingLimited: 'Too many pairing attempts. Wait a moment and try again.',\n    deviceLimit: 'The paired-device limit has been reached. Remove an unused device and generate a new pairing code on the computer.',\n    unavailable: 'The computer is unavailable. Check the connection and try again.',\n    reconnectTitle: 'Reconnect DSH mobile access', reconnectHeading: 'Reconnect this device',\n    restoring: 'Restoring the secure Session…', noLongerPaired: 'This device is no longer paired. Open pairing on the computer, then pair it again.',\n    openPairing: 'Open pairing',\n  },\n  zh: {\n    lang: 'zh-CN', pairTitle: '配对 DSH 移动访问', pairHeading: '配对此设备',\n    pairingCode: '配对码', deviceName: '设备名称', pair: '配对', pairing: '正在配对…',\n    pairingCodeHint: '请输入电脑端显示的 43 位配对码。以 dsh1. 或 dsh2. 开头的密钥用于 Android App。',\n    invalidPairingCode: '请输入电脑端当前配对窗口中的 43 位配对码。',\n    appKeyNotCode: '这是 Android App 密钥。请在 App 中使用，或回到电脑端复制浏览器配对码。',\n    pairFailed: '配对失败，请检查输入或在电脑端重新生成配对码。',\n    pairingExpired: '配对码无效或已过期，请在电脑端重新生成后重试。',\n    pairingLimited: '配对尝试过于频繁，请稍后再试。',\n    deviceLimit: '已达到配对设备上限，请在电脑端移除不需要的设备后重新生成配对码。',\n    unavailable: '电脑当前不可用，请检查连接后重试。',\n    reconnectTitle: '重新连接 DSH 移动访问', reconnectHeading: '重新连接此设备',\n    restoring: '正在恢复安全会话…', noLongerPaired: '此设备已不在配对列表中。请在电脑端打开配对，然后重新配对。',\n    openPairing: '打开配对页面',\n  },\n  it: {\n    lang: 'it-IT', pairTitle: 'Abbina accesso mobile DSH', pairHeading: 'Abbina questo dispositivo',\n    pairingCode: 'Codice di abbinamento', deviceName: 'Nome dispositivo', pair: 'Abbina', pairing: 'Abbinamento…',\n    pairingCodeHint: 'Usa il codice di abbinamento di 43 caratteri mostrato sul computer. Le chiavi che iniziano con dsh1. o dsh2. sono per l’app Android.',\n    invalidPairingCode: 'Inserisci il codice di 43 caratteri dalla finestra di abbinamento attuale sul computer.',\n    appKeyNotCode: 'Questa è una chiave per l’app Android. Usala nell’app oppure copia il codice di abbinamento per il browser dal computer.',\n    pairFailed: 'Abbinamento non riuscito. Controlla il codice o generane uno nuovo sul computer.',\n    pairingExpired: 'Il codice non è valido o è scaduto. Genera un nuovo codice sul computer e riprova.',\n    pairingLimited: 'Troppi tentativi di abbinamento. Attendi un momento e riprova.',\n    deviceLimit: 'È stato raggiunto il limite di dispositivi abbinati. Rimuovi un dispositivo inutilizzato e genera un nuovo codice sul computer.',\n    unavailable: 'Il computer non è disponibile. Controlla la connessione e riprova.',\n    reconnectTitle: 'Riconnetti accesso mobile DSH', reconnectHeading: 'Riconnetti questo dispositivo',\n    restoring: 'Ripristino della sessione sicura…', noLongerPaired: 'Questo dispositivo non è più abbinato. Apri l’abbinamento sul computer e ripeti la procedura.',\n    openPairing: 'Apri abbinamento',\n  },\n}\n\n/** Choose Chinese, Italian, or English from an HTTP Accept-Language header. */\nexport function resolveAuthPageLocale(header: string | undefined): AuthPageLocale {\n  const values = header?.split(',').map((value, index) => {\n    const [language, ...parameters] = value.split(';')\n    const quality = parameters.find(parameter => parameter.trim().toLowerCase().startsWith('q='))\n    const parsedQuality = quality === undefined ? 1 : Number(quality.trim().slice(2))\n    return {\n      language: language?.trim().toLowerCase() ?? '',\n      quality: Number.isFinite(parsedQuality) ? Math.max(0, Math.min(1, parsedQuality)) : 0,\n      index,\n    }\n  }).filter(value => value.quality > 0).sort((left, right) => right.quality - left.quality || left.index - right.index).map(value => value.language) ?? []\n  for (const value of values) {\n    if (value.startsWith('zh')) return 'zh'\n    if (value.startsWith('it')) return 'it'\n    if (value.startsWith('en')) return 'en'\n  }\n  return 'en'\n}\n\n/** Render the browser pairing form without reflecting request data into HTML. */\nexport function renderPairPage(locale: AuthPageLocale): string {\n  const copy = COPY[locale]\n  return `<!doctype html>\n<html lang=\"${copy.lang}\">\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,viewport-fit=cover\">\n<style>input,textarea{font-size:16px}</style>\n<title>${copy.pairTitle}</title>\n<main>\n  <h1>${copy.pairHeading}</h1>\n  <form id=\"pair-form\">\n    <label>${copy.pairingCode} <input id=\"pair-token\" autocomplete=\"one-time-code\" autocapitalize=\"off\" spellcheck=\"false\" aria-describedby=\"pair-token-hint pair-status\" required></label>\n    <p id=\"pair-token-hint\">${copy.pairingCodeHint}</p>\n    <label>${copy.deviceName} <input id=\"device-label\" maxlength=\"64\" autocomplete=\"off\"></label>\n    <button type=\"submit\">${copy.pair}</button>\n    <output id=\"pair-status\" aria-live=\"polite\"></output>\n  </form>\n</main>\n<script src=\"/mobile-access/pair.js\" defer></script>\n</html>\n`\n}\n\n/** Render the pairing form script with locale-owned status messages. */\nexport function renderPairScript(locale: AuthPageLocale): string {\n  const copy = COPY[locale]\n  return `(() => {\n  const form = document.getElementById('pair-form')\n  const token = document.getElementById('pair-token')\n  const label = document.getElementById('device-label')\n  const status = document.getElementById('pair-status')\n  const submit = form.querySelector('button[type=\"submit\"]')\n  let submitting = false\n  const fragment = new URLSearchParams(location.hash.slice(1))\n  const supplied = fragment.get('token')\n  history.replaceState(null, '', location.pathname)\n  if (supplied) token.value = supplied\n  token.addEventListener('input', () => {\n    token.removeAttribute('aria-invalid')\n    if (!submitting) status.value = ''\n  })\n  form.addEventListener('submit', async (event) => {\n    event.preventDefault()\n    if (submitting) return\n    const code = token.value.trim()\n    token.removeAttribute('aria-invalid')\n    if (/^dsh[12]\\\\./u.test(code) || !/^[A-Za-z0-9_-]{43}$/u.test(code)) {\n      status.value = /^dsh[12]\\\\./u.test(code)\n        ? ${JSON.stringify(copy.appKeyNotCode)} : ${JSON.stringify(copy.invalidPairingCode)}\n      token.setAttribute('aria-invalid', 'true')\n      token.focus()\n      return\n    }\n    submitting = true\n    submit.disabled = true\n    status.value = ${JSON.stringify(copy.pairing)}\n    try {\n      const response = await fetch('/mobile-access/auth/pair', {\n        method: 'POST',\n        credentials: 'same-origin',\n        headers: { 'content-type': 'application/json' },\n        body: JSON.stringify({ token: code, label: label.value || undefined }),\n      })\n      if (!response.ok) {\n        if (token.value.trim() !== code) { status.value = ''; return }\n        status.value = response.status === 401 ? ${JSON.stringify(copy.pairingExpired)}\n          : response.status === 429 ? ${JSON.stringify(copy.pairingLimited)}\n          : response.status === 409 ? ${JSON.stringify(copy.deviceLimit)}\n          : response.status >= 500 ? ${JSON.stringify(copy.unavailable)}\n          : ${JSON.stringify(copy.pairFailed)}\n        if (response.status === 401) token.setAttribute('aria-invalid', 'true')\n        return\n      }\n      location.replace('/')\n    } catch {\n      status.value = token.value.trim() === code ? ${JSON.stringify(copy.unavailable)} : ''\n    } finally {\n      submitting = false\n      submit.disabled = false\n    }\n  })\n})()\n`\n}\n\n/** Render the browser reauthentication page. */\nexport function renderLoginPage(locale: AuthPageLocale): string {\n  const copy = COPY[locale]\n  return `<!doctype html>\n<html lang=\"${copy.lang}\">\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,viewport-fit=cover\">\n<title>${copy.reconnectTitle}</title>\n<main>\n  <h1>${copy.reconnectHeading}</h1>\n  <p id=\"login-progress\" aria-live=\"polite\">${copy.restoring}</p>\n  <section id=\"login-failed\" hidden>\n    <p>${copy.noLongerPaired}</p>\n    <a href=\"/mobile-access/pair\">${copy.openPairing}</a>\n  </section>\n</main>\n<script src=\"/mobile-access/login.js\" defer></script>\n</html>\n`\n}\n\n/** Render the reauthentication script with locale-owned failure text. */\nexport function renderLoginScript(locale: AuthPageLocale): string {\n  const copy = COPY[locale]\n  return `(() => {\n  const candidate = new URL(location.href).searchParams.get('return')\n  let returnPath = '/'\n  if (candidate && candidate.startsWith('/')) {\n    try {\n      const resolved = new URL(candidate, location.origin)\n      const pathname = decodeURIComponent(resolved.pathname)\n      if (resolved.origin === location.origin && pathname !== '/mobile-access'\n        && !pathname.startsWith('/mobile-access/') && !pathname.includes('\\\\\\\\')) {\n        returnPath = resolved.pathname + resolved.search + resolved.hash\n      }\n    } catch {\n      // Malformed untrusted return targets keep the safe root default.\n    }\n  }\n  fetch('/mobile-access/auth/renew', {\n    method: 'POST',\n    credentials: 'same-origin',\n    headers: { 'content-type': 'application/json' },\n    body: '{}',\n  }).then((response) => {\n    if (response.ok) {\n      location.replace(returnPath)\n      return\n    }\n    document.getElementById('login-progress').hidden = true\n    document.getElementById('login-failed').hidden = false\n  }).catch(() => {\n    document.getElementById('login-progress').textContent = ${JSON.stringify(copy.unavailable)}\n  })\n})()\n`\n}\n","import { createHash, X509Certificate } from 'node:crypto'\nimport { createSocket, type Socket as DatagramSocket } from 'node:dgram'\nimport { lstat, readFile, stat } from 'node:fs/promises'\nimport { hostname } from 'node:os'\nimport { basename, dirname, extname, join } from 'node:path'\nimport {\n  createServer as createHttpServer,\n  request as requestHttp,\n  type ClientRequest,\n  type IncomingHttpHeaders,\n  type IncomingMessage,\n  type OutgoingHttpHeaders,\n  type Server as HttpServer,\n  type ServerResponse,\n} from 'node:http'\nimport { createServer as createHttpsServer, type Server as HttpsServer, type ServerOptions } from 'node:https'\nimport { connect, type AddressInfo, type Socket } from 'node:net'\nimport { isIP } from './ip.js'\nimport { Transform, type TransformCallback } from 'node:stream'\nimport { pipeline } from 'node:stream/promises'\nimport { promisify } from 'node:util'\nimport { createGzip, gzip } from 'node:zlib'\nimport type { WebRoute } from '@deepseek-ai/dsh-host-webserver'\nimport Bonjour from 'bonjour-service'\nimport * as QRCode from 'qrcode'\nimport {\n  AccessController,\n  AccessError,\n  BoundedRateLimiter,\n  type DeviceSummary,\n  type SessionAuthorization,\n} from './access.js'\nimport type { ResolvedGatewayConfig } from './config.js'\nimport { ClientModulePreferenceStore, parseExcludedClientModules, type ClientModuleEntry, type ClientModulePreferenceView } from './client-module-preferences.js'\nimport { renderClientModuleRecoveryPage } from './client-module-recovery.js'\nimport { ensureMobileCompatibility, MOBILE_COMPAT_PATH } from './mobile-compat-bootstrap.js'\nimport { matchesIfNoneMatch, weakenEntityTag } from './http-cache.js'\nimport {\n  AUTH_PREFIX,\n  assertExternalTrust,\n  assertLocalAdminTrust,\n  cookie,\n  CSRF_COOKIE,\n  CSRF_HEADER,\n  DEVICE_COOKIE,\n  HttpError,\n  LOCAL_ADMIN_PREFIX,\n  parseRequestTarget,\n  readJsonObject,\n  sendFailure,\n  sendJson,\n  SESSION_COOKIE,\n  setSecurityHeaders,\n  WS_PATHS,\n} from './http-security.js'\nimport {\n  authenticatedCookie,\n  browserAuthCookies,\n  HOST_CSRF_COOKIE,\n  HOST_DEVICE_COOKIE,\n  HOST_SESSION_COOKIE,\n} from './browser-auth-cookies.js'\nimport type { BlockedUpgradePathEntry, BlockedUpgradePathLog } from './websocket-paths.js'\nimport { bridgeCompressedWebSocket } from './websocket-compression.js'\nimport {\n  DSH_MOBILE_VERSION,\n  MINIMUM_ANDROID_APP_VERSION,\n  MOBILE_METADATA_VERSION,\n} from './version.js'\nimport { addressAllowed, isLoopbackAddress, type ParsedCidr, RequestTrustPolicy } from './network.js'\nimport type { DeviceStore } from './storage.js'\nimport { listComputerImages, readComputerImage } from './computer-images.js'\nimport {\n  disposeLateExtensionResponse,\n  EXTENSION_LIMITS,\n  MobileExtensionError,\n  type MobileAccessService,\n  type MobileRouteRequest,\n  type MobileRouteResponse,\n} from './extensions.js'\nimport { isPreparedJson } from './extension-worker.js'\nimport {\n  renderLoginPage,\n  renderLoginScript,\n  renderPairPage,\n  renderPairScript,\n  resolveAuthPageLocale,\n} from './auth-pages.js'\n\ntype GatewayServer = HttpServer | HttpsServer\n\ninterface ActiveRequest {\n  readonly sessionKey: string\n  readonly deviceId: string\n  readonly expiresAt: number\n  readonly abort: () => void\n  readonly timer: NodeJS.Timeout\n}\n\ninterface ActiveWebSocket {\n  readonly sessionKey: string\n  readonly deviceId: string\n  readonly client: Socket\n  readonly upstream: Socket\n  readonly timer: NodeJS.Timeout\n}\n\nconst MAX_CONTROL_BODY_BYTES = 16 * 1024\nconst MAX_HEADER_BYTES = 16 * 1024\nconst DISCOVERY_QUERY = Buffer.from('DSH_MOBILE_DISCOVER_V1', 'ascii')\nconst DISCOVERY_PROTOCOL = 1\nconst DISCOVERY_INTERVAL_MS = 3_000\nconst MDNS_SERVICE_TYPE = 'dsh-mobile'\nconst MOBILE_LAYOUT_MODULE = '@deepseek-ai/dsh-client-ui-layout'\nconst MOBILE_LAYOUT_PATH = `${AUTH_PREFIX}/mobile-layout.js`\nconst MOBILE_BOOT_BATCH_PREFIX = `${AUTH_PREFIX}/mobile-boot/`\nconst MAX_MOBILE_BOOT_BATCH_BYTES = 32 * 1024 * 1024\nconst MAX_MOBILE_BOOT_ENTRY_BYTES = 8 * 1024 * 1024\n/**\n * Per-merged-batch byte budget. One upstream application batch can carry dozens\n * of client bundles whose combined size exceeds the hard batch cap; the layout\n * batch is therefore chunked into multiple merged batches, each kept safely\n * below {@link MAX_MOBILE_BOOT_BATCH_BYTES} so assembly can never reject it.\n */\nconst MOBILE_BOOT_CHUNK_BYTES = 16 * 1024 * 1024\n/** Bytes the assembly emits after each entry (`body` plus `\\n;\\n`). */\nconst MOBILE_BOOT_SEPARATOR_BYTES = 3\n/** Freshness window for cached upstream bundle byte sizes. */\nconst MOBILE_BOOT_SIZE_CACHE_TTL_MS = 30_000\n/** Marker header distinguishing size probes from ordinary proxied bundle fetches. */\nconst MOBILE_BOOT_SIZE_PROBE_HEADER = 'x-dsh-mobile-size-probe'\nconst MAX_MOBILE_BOOT_BATCHES = 8\nconst MOBILE_BOOT_UPSTREAM_ATTEMPTS = 4\nconst MOBILE_BOOT_RETRY_DELAY_MS = 150\n\nfunction upstreamPluginBundleUrl(source: string, upstreamOrigin: URL): URL | undefined {\n  if ((!source.startsWith('/plugins/') && !source.startsWith('plugins/')) || source.includes('#')) return undefined\n  try {\n    const target = new URL(source, new URL('/', upstreamOrigin))\n    if (target.origin !== upstreamOrigin.origin || !target.pathname.startsWith('/plugins/')) return undefined\n    return target\n  } catch {\n    return undefined\n  }\n}\n\nconst TRANSIENT_UPSTREAM_ERROR_CODES = new Set([\n  'EAI_AGAIN',\n  'ECONNABORTED',\n  'ECONNREFUSED',\n  'ECONNRESET',\n  'EPIPE',\n  'EHOSTUNREACH',\n  'ENETDOWN',\n  'ENETRESET',\n  'ENETUNREACH',\n  'ETIMEDOUT',\n  'ERR_STREAM_PREMATURE_CLOSE',\n])\nconst UPSTREAM_AUTH_REFRESH_MARGIN_MS = 60_000\nconst UPSTREAM_COOKIE_PAIR = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+=[\\x21-\\x3A\\x3C-\\x7E]*$/u\nconst CUSTOM_STYLE_FALLBACK = '/* Add mobile overrides in the DSH home mobile-access/mobile.css file. */\\n'\nconst CUSTOM_SCRIPT_FALLBACK = 'window.dshMobile?.register(() => undefined)\\n'\nconst EXTENSION_CHANGE_POLL_MS = 2_000\nconst EXTENSION_EVENT_HEARTBEAT_MS = 15_000\nconst MOBILE_CLIENT_MODULE = 'dsh-mobile'\nconst CONNECTION_MODULE = '@deepseek-ai/dsh-client-connection'\nconst RUNTIME_MODULE = '@deepseek-ai/dsh-client-runtime'\nconst RENDERER_MODULE = '@deepseek-ai/dsh-client-ui-renderer'\nconst SIDEBAR_MODULE = '@deepseek-ai/dsh-client-ui-sidebar'\nconst SETTINGS_MODULE = '@deepseek-ai/dsh-client-ui-settings'\nconst API_GATEWAY_MODULE = '@deepseek-ai/dsh-api-gateway'\nconst API_REMOTES_MODULE = '@deepseek-ai/dsh-api-remotes'\nconst MOBILE_BOOT_CORE_MODULES = new Set([\n  MOBILE_CLIENT_MODULE, MOBILE_LAYOUT_MODULE, CONNECTION_MODULE, RUNTIME_MODULE,\n  RENDERER_MODULE, SIDEBAR_MODULE, SETTINGS_MODULE, API_GATEWAY_MODULE, API_REMOTES_MODULE,\n])\nconst MOBILE_LAYOUT_DEPENDENCY_PROFILES = Object.freeze([\n  Object.freeze({\n    slots: RUNTIME_MODULE,\n    dependencies: Object.freeze([RUNTIME_MODULE, '@deepseek-ai/dsh-client-ui-theme']),\n  }),\n  Object.freeze({\n    slots: RENDERER_MODULE,\n    dependencies: Object.freeze([\n      '@deepseek-ai/dsh-client-locale',\n      RENDERER_MODULE,\n      '@deepseek-ai/dsh-client-ui-session',\n      '@deepseek-ai/dsh-client-ui-theme',\n    ]),\n  }),\n])\nfunction mobileCsrfFetchBootstrap(cookieName: string): string {\n  return `(()=>{const nativeFetch=window.fetch.bind(window);window.fetch=(input,init)=>{const source=input instanceof Request?input:undefined;const method=String(init?.method??source?.method??'GET').toUpperCase();if(method==='GET'||method==='HEAD')return nativeFetch(input,init);const raw=typeof input==='string'?input:input instanceof URL?input.href:source?.url;if(raw===undefined||new URL(raw,location.href).origin!==location.origin)return nativeFetch(input,init);const headers=new Headers(init?.headers??source?.headers);if(!headers.has(${JSON.stringify(CSRF_HEADER)})){const prefix=${JSON.stringify(`${cookieName}=`)};const values=[...new Set(document.cookie.split(';').map(value=>value.trim()).filter(value=>value.startsWith(prefix)).map(value=>value.slice(prefix.length)))];if(values.length===1)headers.set(${JSON.stringify(CSRF_HEADER)},values[0])}return nativeFetch(input,{...init,headers})};})();`\n}\n// Paired pages use the gateway's authenticated HTTP carrier; streams retain DSH's WebSocket transport.\n// DSH's default file-upload Worker bypasses this gateway's CSRF fetch wrapper. Resolve\n// window.fetch when called because the wrapper is installed after the transport hook.\nconst MOBILE_AUTHENTICATED_TRANSPORT_BOOTSTRAP = `(()=>{if(window.__DSH_TRANSPORT__!==undefined)throw new Error('DSH Mobile cannot replace an existing transport override');window.__DSH_TRANSPORT__={fetch:(input,init)=>window.fetch(input,init),ownsHost:true},window.__DSH_FILE_UPLOAD__={fetch:(input,init)=>window.fetch(input,init)}})();`\n/** Use this page's gateway health, rather than OS internet validation, for DSH reconnects. */\nconst MOBILE_GATEWAY_REACHABILITY_BOOTSTRAP = `(()=>{\n  const view=globalThis;\n  const port=view.navigator;\n  const nativeFetch=typeof view.fetch==='function'?view.fetch.bind(view):undefined;\n  let reachable=true;\n  let checking=false;\n  let replaying=false;\n  let disposed=false;\n  let epoch=0;\n  let retryTimer;\n  let activeController;\n  const clearRetry=()=>{if(retryTimer!==undefined){view.clearTimeout(retryTimer);retryTimer=undefined}};\n  const scheduleRetry=()=>{if(!disposed&&!reachable&&retryTimer===undefined){retryTimer=view.setTimeout(()=>{retryTimer=undefined;check()},5000)}};\n  const check=()=>{\n    if(checking||disposed||nativeFetch===undefined)return;\n    checking=true;\n    const current=++epoch;\n    const controller=new AbortController();\n    activeController=controller;\n    const timer=view.setTimeout(()=>controller.abort(),2000);\n    void nativeFetch('/mobile-access/health',{cache:'no-store',credentials:'same-origin',signal:controller.signal})\n      .then(response=>response.ok,()=>false)\n      .then(ok=>{\n        if(disposed||current!==epoch)return;\n        if(ok){\n          const wasOffline=!reachable;\n          reachable=true;\n          clearRetry();\n          if(wasOffline)view.dispatchEvent(new Event('online'));\n          return;\n        }\n        const wasOnline=reachable;\n        reachable=false;\n        if(wasOnline){\n          replaying=true;\n          try{view.dispatchEvent(new Event('offline'))}finally{replaying=false}\n        }\n        scheduleRetry();\n      })\n      .finally(()=>{view.clearTimeout(timer);activeController=undefined;checking=false});\n  };\n  if(port!==undefined&&typeof Object.defineProperty==='function'){\n    try{Object.defineProperty(port,'onLine',{configurable:true,get:()=>reachable})}catch{/* A frozen navigator retains its native value. */}\n  }\n  if(typeof view.addEventListener==='function'){\n    view.addEventListener('offline',event=>{if(replaying||nativeFetch===undefined)return;event.stopImmediatePropagation();check()},true);\n    view.addEventListener('online',()=>{++epoch;reachable=true;clearRetry()},true);\n    view.addEventListener('pagehide',()=>{disposed=true;++epoch;clearRetry();activeController?.abort()},true);\n  }\n})();`\nconst PAIR_PAGE = `<!doctype html>\n<html lang=\"en\">\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,viewport-fit=cover\">\n<title>Pair DSH mobile access</title>\n<main>\n  <h1>Pair this device</h1>\n  <form id=\"pair-form\">\n    <label>Pairing code <input id=\"pair-token\" autocomplete=\"one-time-code\" required></label>\n    <label>Device name <input id=\"device-label\" maxlength=\"64\" autocomplete=\"off\"></label>\n    <button type=\"submit\">Pair</button>\n    <output id=\"pair-status\"></output>\n  </form>\n</main>\n<script src=\"/mobile-access/pair.js\" defer></script>\n</html>\n`\n\ninterface BootGraphEntry {\n  id: string\n  url: string\n  rev: string\n  inject?: string[]\n  external?: string[]\n  immediately?: boolean\n}\n\ninterface BootGraphBatch {\n  phase: 'bootstrap' | 'application'\n  url: string\n  rev: string\n  entries: string[]\n}\n\ninterface MobileBootBatchEntry {\n  readonly id: string\n  readonly url: string\n  readonly rev: string\n}\n\ninterface MobileBootBatchPlan {\n  readonly key: string\n  readonly path: string\n  readonly entries: readonly MobileBootBatchEntry[]\n}\n\ninterface RewrittenMobileIndex {\n  readonly html: string\n  /** Merged batches the gateway assembles and serves; pass-through rows are not plans. */\n  readonly batches: readonly MobileBootBatchPlan[]\n}\n\n/** Parsed boot manifest with the layout entry rewired to the gateway-owned layout module. */\ninterface MobileBootPlanRef {\n  readonly parsed: { rev: string; entries: BootGraphEntry[]; batches?: BootGraphBatch[] }\n  readonly entries: BootGraphEntry[]\n  readonly batches?: BootGraphBatch[]\n  readonly slotProvider: string\n  readonly assignment: string\n  readonly replaceStart: number\n  readonly replaceEnd: number\n  readonly layoutBatch?: BootGraphBatch\n  readonly planEntries?: readonly MobileBootBatchEntry[]\n  readonly originalApplicationBatches?: readonly BootGraphBatch[]\n  readonly rewrittenBatchEntries?: readonly { readonly batch: BootGraphBatch; readonly entries: readonly MobileBootBatchEntry[] }[]\n}\n\ninterface SplitMobileBootBatch {\n  readonly plans: readonly MobileBootBatchPlan[]\n  readonly rows: readonly BootGraphBatch[]\n}\n\ninterface StoredMobileBootBatch {\n  readonly plan: MobileBootBatchPlan\n  body?: Buffer\n  gzipBody?: Buffer\n  etag?: string\n  layoutMtimeMs?: number\n  /** In-flight assembly shared by every concurrent requester of this batch. */\n  assembly?: MobileBootBatchAssembly\n}\n\ninterface MobileBootBatchAssembly {\n  readonly controller: AbortController\n  readonly task: Promise<Buffer>\n}\n\nconst gzipBuffer = promisify(gzip)\n\nfunction ensureMobileViewport(html: string): string {\n  const viewport = /<meta\\b(?=[^>]*\\bname\\s*=\\s*[\"']viewport[\"'])[^>]*>/iu\n  const match = viewport.exec(html)\n  if (match === null) {\n    const head = /<head\\b[^>]*>/iu.exec(html)\n    if (head?.index === undefined) return html\n    const position = head.index + head[0].length\n    return `${html.slice(0, position)}<meta name=\"viewport\" content=\"width=device-width,initial-scale=1,viewport-fit=cover\">${html.slice(position)}`\n  }\n  if (/\\bviewport-fit\\s*=\\s*cover\\b/iu.test(match[0])) return html\n  const content = /\\bcontent\\s*=\\s*([\"'])(.*?)\\1/iu\n  const next = content.test(match[0])\n    ? match[0].replace(content, (_whole, quote: string, value: string) => `content=${quote}${value},viewport-fit=cover${quote}`)\n    : match[0].replace(/\\s*\\/?>$/u, ' content=\"width=device-width,initial-scale=1,viewport-fit=cover\">')\n  return `${html.slice(0, match.index)}${next}${html.slice(match.index + match[0].length)}`\n}\n\nfunction orderAuthenticatedSettings(entries: BootGraphEntry[], slotsProvider: string): boolean {\n  const mobile = entries.filter(entry => entry !== null && typeof entry === 'object' && entry.id === MOBILE_CLIENT_MODULE)\n  const settings = entries.filter(entry => entry !== null && typeof entry === 'object' && entry.id === SETTINGS_MODULE)\n  if (mobile.length === 0 || settings.length === 0) return false\n  if (mobile.length !== 1 || settings.length !== 1) throw new Error('upstream DSH mobile settings graph is ambiguous')\n  if (!Array.isArray(mobile[0]?.inject)\n    || !mobile[0].inject.includes(CONNECTION_MODULE)\n    || !mobile[0].inject.includes(SIDEBAR_MODULE)) {\n    throw new Error('dsh-mobile client has unsupported dependencies')\n  }\n  if (!Array.isArray(settings[0]?.inject)) {\n    throw new Error('upstream DSH settings module has unsupported dependencies')\n  }\n  const remoteSettings = !settings[0].inject.includes(CONNECTION_MODULE)\n  if (remoteSettings) {\n    if (!settings[0].inject.includes(API_REMOTES_MODULE) || slotsProvider !== RENDERER_MODULE) {\n      throw new Error('upstream DSH settings module has unsupported dependencies')\n    }\n    const remotes = entries.filter(entry => entry !== null && typeof entry === 'object' && entry.id === API_REMOTES_MODULE)\n    const gateway = entries.filter(entry => entry !== null && typeof entry === 'object' && entry.id === API_GATEWAY_MODULE)\n    if (remotes.length !== 1 || !Array.isArray(remotes[0]?.inject) || !remotes[0].inject.includes(API_GATEWAY_MODULE)\n      || gateway.length !== 1 || !Array.isArray(gateway[0]?.inject) || !gateway[0].inject.includes(CONNECTION_MODULE)) {\n      throw new Error('upstream DSH settings Remote graph has unsupported dependencies')\n    }\n    // These package edges order factory arrival; authenticated transport trust is installed before boot.\n    if (!gateway[0].inject.includes(MOBILE_CLIENT_MODULE)) gateway[0].inject = [...gateway[0].inject, MOBILE_CLIENT_MODULE]\n  }\n  mobile[0].inject = [CONNECTION_MODULE, slotsProvider]\n  if (!settings[0].inject.includes(MOBILE_CLIENT_MODULE)) settings[0].inject = [...settings[0].inject, MOBILE_CLIENT_MODULE]\n  return remoteSettings\n}\n\nfunction revisionedMobileBatchPath(entries: readonly MobileBootBatchEntry[]): { readonly key: string; readonly path: string } {\n  const key = createHash('sha256')\n    .update(DSH_MOBILE_VERSION)\n    .update(JSON.stringify(entries))\n    .digest('hex')\n  return { key, path: `${MOBILE_BOOT_BATCH_PREFIX}${key}.js` }\n}\n\nclass ExcludedClientModulesError extends Error {\n  constructor(message: string) { super(`excludedClientModules: ${message}`) }\n}\n\n/** A graph-selection conflict with a bounded diagnostic safe for authenticated callers. */\nexport class ClientModuleConflictError extends HttpError {\n  readonly detail: string\n\n  constructor(detail: string) {\n    super(409, 'excluded_client_modules_invalid')\n    this.detail = detail.replace(/[\\u0000-\\u001f\\u007f]/gu, ' ')\n      .replace(/(?:https?:\\/\\/|[a-z]:[\\\\/])\\S+/giu, '[redacted]')\n      .slice(0, 512)\n  }\n}\n\nfunction requiredClientModule(entry: BootGraphEntry, phase: BootGraphBatch['phase'] | undefined): boolean {\n  return MOBILE_BOOT_CORE_MODULES.has(entry.id) || entry.immediately === true || phase !== 'application'\n}\n\nfunction clientModuleDependencies(entry: BootGraphEntry): readonly string[] {\n  const dependencies = new Set<string>()\n  for (const [field, edges] of [['inject', entry.inject], ['external', entry.external]] as const) {\n    if (edges !== undefined && (!Array.isArray(edges) || edges.some(id => typeof id !== 'string'))) {\n      throw new ExcludedClientModulesError(`upstream module ${entry.id} has malformed ${field} dependencies`)\n    }\n    for (const dependency of edges ?? []) dependencies.add(dependency.endsWith('/client') ? dependency.slice(0, -'/client'.length) : dependency)\n  }\n  return Object.freeze([...dependencies])\n}\n\nfunction clientModulePhases(entries: readonly BootGraphEntry[], batches: readonly BootGraphBatch[]): ReadonlyMap<string, BootGraphBatch['phase']> {\n  const phases = new Map<string, BootGraphBatch['phase']>()\n  for (const batch of batches) {\n    for (const id of batch.entries) {\n      if (phases.has(id)) throw new ExcludedClientModulesError(`upstream module ${id} belongs to multiple batches`)\n      phases.set(id, batch.phase)\n    }\n  }\n  for (const entry of entries) {\n    if (!phases.has(entry.id)) throw new ExcludedClientModulesError(`upstream module ${entry.id} belongs to no batch`)\n  }\n  return phases\n}\n\n/** Read only installed module ids and declared edges from the same boot parser used for serving. */\nexport function describeMobileClientModules(html: string): readonly ClientModuleEntry[] {\n  const plan = parseMobileBootPlan(html)\n  const ids = new Set(plan.entries.map(entry => entry.id))\n  const phases = plan.batches === undefined ? new Map<string, BootGraphBatch['phase']>() : clientModulePhases(plan.entries, plan.batches)\n  return Object.freeze(plan.entries.map(entry => Object.freeze({\n    id: entry.id,\n    required: requiredClientModule(entry, phases.get(entry.id)),\n    dependencies: Object.freeze(clientModuleDependencies(entry).filter(id => ids.has(id))),\n  })))\n}\n\n/** Validate graph edges before removing application rows from both manifest views. */\nfunction excludeMobileBootEntries(\n  entries: BootGraphEntry[],\n  batches: BootGraphBatch[],\n  excludedIds: readonly string[],\n): void {\n  if (excludedIds.length === 0) return\n  const excluded = new Set(excludedIds)\n  if (excluded.size !== excludedIds.length) throw new ExcludedClientModulesError('duplicate module ids')\n  const byId = new Map(entries.map(entry => [entry.id, entry]))\n  const phases = clientModulePhases(entries, batches)\n  for (const id of excluded) {\n    const entry = byId.get(id)\n    if (entry === undefined) throw new ExcludedClientModulesError(`module ${id} is not installed in this DSH client graph`)\n    if (requiredClientModule(entry, phases.get(id))) {\n      throw new ExcludedClientModulesError(`module ${id} is required for mobile boot or belongs to a bootstrap batch`)\n    }\n  }\n  for (const entry of entries) {\n    if (excluded.has(entry.id)) continue\n    for (const packageId of clientModuleDependencies(entry)) {\n      if (excluded.has(packageId)) {\n        throw new ExcludedClientModulesError(`module ${entry.id} still depends on excluded module ${packageId}; exclude the dependent too or keep ${packageId}`)\n      }\n    }\n  }\n  entries.splice(0, entries.length, ...entries.filter(entry => !excluded.has(entry.id)))\n  for (const batch of batches) batch.entries = batch.entries.filter(id => !excluded.has(id))\n  batches.splice(0, batches.length, ...batches.filter(batch => batch.entries.length > 0))\n}\n\n/**\n * Parse one upstream boot manifest and rewire the layout entry onto the\n * gateway-owned layout module. Optional exclusions remove application entries\n * and identify every affected batch for reassembly. The dedicated frontend is\n * authenticated in the gateway, so the layout needs no upstream address.\n */\nexport function parseMobileBootPlan(html: string, excludedClientModules: readonly string[] = []): MobileBootPlanRef {\n  const assignment = /(?:window\\.__DSH_BOOT__|globalThis\\[\"__DSH_BOOT__\"\\])\\s*=\\s*/u.exec(html)\n  if (assignment?.index === undefined) throw new Error('upstream DSH index has no boot manifest')\n  const replaceStart = assignment.index\n  const valueStart = replaceStart + assignment[0].length\n  const scriptEnd = html.indexOf('</script>', valueStart)\n  if (scriptEnd < 0) throw new Error('upstream DSH boot manifest script is incomplete')\n  const source = html.slice(valueStart, scriptEnd).trim().replace(/;$/u, '')\n  const parsed = JSON.parse(source) as { rev?: unknown; entries?: unknown; batches?: unknown }\n  if (typeof parsed.rev !== 'string' || !Array.isArray(parsed.entries)) {\n    throw new Error('upstream DSH boot manifest is malformed')\n  }\n  const entries = parsed.entries as BootGraphEntry[]\n  const layout = entries.filter(entry => entry !== null && typeof entry === 'object' && entry.id === MOBILE_LAYOUT_MODULE)\n  if (layout.length !== 1 || typeof layout[0]?.url !== 'string' || typeof layout[0].rev !== 'string') {\n    throw new Error('upstream DSH boot manifest has no unique layout module')\n  }\n  if (!Array.isArray(layout[0].inject)) {\n    throw new Error('upstream DSH layout module has unsupported dependencies')\n  }\n  const dependencyProfile = MOBILE_LAYOUT_DEPENDENCY_PROFILES.find(profile => (\n    profile.dependencies.every(dependency => layout[0]?.inject?.includes(dependency))\n  ))\n  if (dependencyProfile === undefined) throw new Error('upstream DSH layout module has unsupported dependencies')\n  layout[0].url = MOBILE_LAYOUT_PATH\n  layout[0].rev = `dsh-mobile-layout-${DSH_MOBILE_VERSION}`\n  const parsedBatches = parsed.batches\n  if (parsedBatches === undefined) {\n    if (excludedClientModules.length > 0) {\n      throw new ExcludedClientModulesError('this DSH version has no batched boot manifest; disable exclusions or update DSH')\n    }\n    return Object.freeze({\n      parsed: parsed as { rev: string; entries: BootGraphEntry[] },\n      entries,\n      slotProvider: dependencyProfile.slots,\n      assignment: assignment[0],\n      replaceStart,\n      replaceEnd: scriptEnd,\n    })\n  }\n  if (!Array.isArray(parsedBatches)) throw new Error('upstream DSH boot manifest batches are malformed')\n  const batches = parsedBatches as BootGraphBatch[]\n  const entryById = new Map(entries.map(entry => [entry.id, entry]))\n  if (entryById.size !== entries.length) throw new Error('upstream DSH boot manifest has duplicate entries')\n  const layoutBatches: BootGraphBatch[] = []\n  for (const batch of batches) {\n    if (batch === null || typeof batch !== 'object'\n      || (batch.phase !== 'bootstrap' && batch.phase !== 'application')\n      || typeof batch.url !== 'string' || typeof batch.rev !== 'string'\n      || !Array.isArray(batch.entries) || batch.entries.length === 0\n      || batch.entries.some(id => typeof id !== 'string' || !entryById.has(id))) {\n      throw new Error('upstream DSH boot manifest batches are malformed')\n    }\n    if (batch.entries.includes(MOBILE_LAYOUT_MODULE)) layoutBatches.push(batch)\n  }\n  if (layoutBatches.length !== 1 || layoutBatches[0]?.phase !== 'application') {\n    throw new Error('upstream DSH boot manifest has no unique application layout batch')\n  }\n  const layoutBatch = layoutBatches[0]\n  const originalApplicationBatches = batches\n    .filter(batch => batch.phase === 'application')\n    .map(batch => ({ ...batch, entries: [...batch.entries] }))\n  excludeMobileBootEntries(entries, batches, excludedClientModules)\n  // Canonical entry order. Upstream lists application batch entries in\n  // module-registration order, which is not stable across restarts of an\n  // unchanged configuration. `splitMobileBootBatch` derives the batch key, the\n  // merged chunk boundaries, and the concatenation order of the assembled body\n  // from this sequence, so an unstable order re-hashes every batch after each\n  // restart — and, because the body hash is the `ETag`, it also changes the\n  // validator. Every paired device then re-downloads the whole boot payload\n  // even though no module changed. Entry ids are unique (the map above rejects\n  // duplicates), so sorting them is a total order.\n  const affectedBatchUrls = new Set(originalApplicationBatches\n    .filter(batch => batch.entries.some(id => excludedClientModules.includes(id)))\n    .map(batch => batch.url))\n  const rewrittenBatchEntries = batches\n    .filter(batch => batch === layoutBatch || (batch.phase === 'application' && affectedBatchUrls.has(batch.url)))\n    .map(batch => ({\n      batch,\n      entries: [...batch.entries].sort((left, right) => (left < right ? -1 : left > right ? 1 : 0))\n        .map((id): MobileBootBatchEntry => {\n          const entry = entryById.get(id)\n          if (entry === undefined || typeof entry.url !== 'string' || typeof entry.rev !== 'string') {\n            throw new Error('upstream DSH boot manifest batches are malformed')\n          }\n          return Object.freeze({ id, url: entry.url, rev: entry.rev })\n        }),\n    }))\n  const planEntries = rewrittenBatchEntries.find(candidate => candidate.batch === layoutBatch)?.entries\n  if (planEntries === undefined) throw new Error('upstream DSH boot manifest lost the application layout batch')\n  return Object.freeze({\n    parsed: parsed as { rev: string; entries: BootGraphEntry[]; batches: BootGraphBatch[] },\n    entries,\n    batches,\n    slotProvider: dependencyProfile.slots,\n    assignment: assignment[0],\n    replaceStart,\n    replaceEnd: scriptEnd,\n    layoutBatch,\n    planEntries,\n    originalApplicationBatches,\n    rewrittenBatchEntries,\n  })\n}\n\n/**\n * Partition one upstream application batch into merged batches plus pass-through\n * rows. Every entry whose bundle is at or above the per-entry cap keeps its own\n * upstream `/plugins` row (the gateway proxies it verbatim), because a merged\n * batch cannot carry it. The remaining entries are greedily packed into merged\n * batches under {@link MOBILE_BOOT_CHUNK_BYTES}; the layout module always merges,\n * since its body is the gateway-owned layout file, never an upstream fetch.\n */\nexport function splitMobileBootBatch(\n  entries: readonly MobileBootBatchEntry[],\n  sizes: ReadonlyMap<string, number>,\n  passThrough: ReadonlySet<string>,\n): SplitMobileBootBatch {\n  const rows: BootGraphBatch[] = []\n  const plans: MobileBootBatchPlan[] = []\n  let chunk: { ids: string[]; entries: MobileBootBatchEntry[]; bytes: number } | undefined\n  const flush = (): void => {\n    if (chunk === undefined || chunk.entries.length === 0) return\n    const revision = revisionedMobileBatchPath(chunk.entries)\n    rows.push({ phase: 'application', url: revision.path, rev: revision.key, entries: chunk.ids })\n    plans.push(Object.freeze({ key: revision.key, path: revision.path, entries: Object.freeze(chunk.entries) }))\n    chunk = undefined\n  }\n  for (const entry of entries) {\n    const size = sizes.get(entry.url)\n    const oversized = passThrough.has(entry.url)\n      || (size !== undefined && size >= MAX_MOBILE_BOOT_ENTRY_BYTES)\n    if (oversized && entry.id !== MOBILE_LAYOUT_MODULE) {\n      // A pass-through row never joins a merged batch; it also must not split\n      // the open chunk, because chunk contents are independent of row order.\n      rows.push({ phase: 'application', url: entry.url, rev: entry.rev, entries: [entry.id] })\n      continue\n    }\n    const bytes = (size ?? 0) + MOBILE_BOOT_SEPARATOR_BYTES\n    if (chunk !== undefined && chunk.entries.length > 0 && chunk.bytes + bytes > MOBILE_BOOT_CHUNK_BYTES) flush()\n    chunk ??= { ids: [], entries: [], bytes: 0 }\n    chunk.ids.push(entry.id)\n    chunk.entries.push(entry)\n    chunk.bytes += bytes\n  }\n  flush()\n  return { plans, rows }\n}\n\nfunction escapeMobilePreloadAttribute(value: string): string {\n  return value.replaceAll('&', '&amp;').replaceAll('\"', '&quot;').replaceAll('<', '&lt;').replaceAll('>', '&gt;')\n}\n\nfunction mobileApplicationPreload(url: string): string {\n  return `<link rel=\"preload\" as=\"script\" href=\"${escapeMobilePreloadAttribute(url)}\">`\n}\n\nfunction preloadAttribute(tag: string, name: string): string | undefined {\n  const match = new RegExp(`(?:^|\\\\s)${name}\\\\s*=\\\\s*(?:\"([^\"]*)\"|'([^']*)')`, 'iu').exec(tag)\n  return match?.[1] ?? match?.[2]\n}\n\n/** Replace only DSH's application-script preloads; bootstrap and unrelated links are untouched. */\nfunction rewriteMobileApplicationPreloads(html: string, replacements: ReadonlyMap<string, string>): string {\n  if (replacements.size === 0) return html\n  const escaped = new Map([...replacements].map(([url, markup]) => [escapeMobilePreloadAttribute(url), markup]))\n  return html.replace(/<link\\b[^>]*>/giu, (tag) => {\n    const rel = preloadAttribute(tag, 'rel')\n    if (!rel?.split(/\\s+/u).includes('preload') || preloadAttribute(tag, 'as') !== 'script') return tag\n    return escaped.get(preloadAttribute(tag, 'href') ?? '') ?? tag\n  })\n}\n\nfunction rewriteMobileIndexWithBatch(\n  html: string,\n  options: { readonly sizes?: ReadonlyMap<string, number>; readonly passThrough?: ReadonlySet<string>; readonly excludedClientModules?: readonly string[]; readonly csrfCookie?: string } = {},\n): RewrittenMobileIndex {\n  const plan = parseMobileBootPlan(html, options.excludedClientModules)\n  const remoteSettings = orderAuthenticatedSettings(plan.entries, plan.slotProvider)\n  let batches: readonly MobileBootBatchPlan[] = []\n  let preloadReplacements = new Map<string, string>()\n  if (plan.batches !== undefined && plan.rewrittenBatchEntries !== undefined) {\n    const rewrites = plan.rewrittenBatchEntries.map(({ batch, entries }) => ({\n      batch,\n      split: splitMobileBootBatch(entries, options.sizes ?? new Map(), options.passThrough ?? new Set()),\n    }))\n    if (rewrites.reduce((count, item) => count + item.split.plans.length, 0) > MAX_MOBILE_BOOT_BATCHES) {\n      throw new Error(`upstream DSH mobile boot requires more than ${String(MAX_MOBILE_BOOT_BATCHES)} merged batches`)\n    }\n    for (const { batch, split } of rewrites) {\n      const at = plan.batches.indexOf(batch)\n      if (at < 0) throw new Error('upstream DSH boot manifest lost an application batch')\n      plan.batches.splice(at, 1, ...split.rows)\n      batches = [...batches, ...split.plans]\n    }\n    for (const original of plan.originalApplicationBatches ?? []) {\n      const replacement = rewrites.find(item => item.batch.url === original.url)\n      preloadReplacements.set(\n        original.url,\n        replacement === undefined\n          ? plan.batches.some(batch => batch.url === original.url) ? mobileApplicationPreload(original.url) : ''\n          : replacement.split.rows.map(row => mobileApplicationPreload(row.url)).join(''),\n      )\n    }\n    batches = Object.freeze(batches)\n    plan.parsed.rev = createHash('sha256').update(JSON.stringify({ entries: plan.entries, batches: plan.batches })).digest('hex').slice(0, 16)\n  }\n  const transportBootstrap = remoteSettings ? MOBILE_AUTHENTICATED_TRANSPORT_BOOTSTRAP : ''\n  const replacement = `${MOBILE_GATEWAY_REACHABILITY_BOOTSTRAP}${transportBootstrap}${mobileCsrfFetchBootstrap(options.csrfCookie ?? CSRF_COOKIE)}window.__DSH_MOBILE_FRONTEND__=\"dedicated\";${plan.assignment}${JSON.stringify(plan.parsed)};`\n  const rewritten = `${html.slice(0, plan.replaceStart)}${replacement}${html.slice(plan.replaceEnd)}`\n  return Object.freeze({\n    html: ensureMobileViewport(ensureMobileCompatibility(rewriteMobileApplicationPreloads(rewritten, preloadReplacements))),\n    batches,\n  })\n}\n\n/** Rewrite the dedicated mobile graph; exclusions are opt-in and leave stock DSH unchanged. */\nexport function rewriteMobileIndex(html: string, excludedClientModules: readonly string[] = []): string {\n  return rewriteMobileIndexWithBatch(html, { excludedClientModules }).html\n}\n\nclass ByteLimitTransform extends Transform {\n  private total = 0\n\n  constructor(private readonly maximum: number) {\n    super()\n  }\n\n  override _transform(chunk: Buffer, encoding: BufferEncoding, callback: TransformCallback): void {\n    const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding)\n    this.total += buffer.length\n    if (this.total > this.maximum) {\n      callback(new HttpError(413, 'payload_too_large'))\n      return\n    }\n    callback(null, buffer)\n  }\n}\n\nfunction stripIpv6Brackets(hostname: string): string {\n  return hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname\n}\n\ninterface PemCertificate {\n  readonly pem: string\n  readonly certificate: X509Certificate\n}\n\nfunction parsePemCertificates(contents: Buffer, source: string): PemCertificate[] {\n  const text = contents.toString('utf8')\n  const pattern = /-----BEGIN CERTIFICATE-----[\\s\\S]*?-----END CERTIFICATE-----/gu\n  const blocks = text.match(pattern) ?? []\n  if (blocks.length === 0 || text.replace(pattern, '').trim() !== '') {\n    throw new Error(`${source} must contain only PEM certificates`)\n  }\n  return blocks.map((pem) => {\n    let certificate: X509Certificate\n    try {\n      certificate = new X509Certificate(pem)\n    } catch (error) {\n      throw new Error(`${source} contains an invalid certificate`, { cause: error })\n    }\n    return Object.freeze({ pem: `${pem}\\n`, certificate })\n  })\n}\n\nfunction validateServerChain(chain: readonly PemCertificate[]): void {\n  const now = Date.now()\n  for (const [index, entry] of chain.entries()) {\n    if (Date.parse(entry.certificate.validFrom) > now || Date.parse(entry.certificate.validTo) <= now) {\n      throw new Error('TLS certificate chain contains a certificate that is not currently valid')\n    }\n    if (index === 0) continue\n    if (entry.certificate.subject === entry.certificate.issuer\n      && entry.certificate.verify(entry.certificate.publicKey)) {\n      throw new Error('TLS server certificate chain must not include a self-signed root')\n    }\n    const child = chain[index - 1]!.certificate\n    if (!entry.certificate.ca || !child.checkIssued(entry.certificate)\n      || !child.verify(entry.certificate.publicKey)) {\n      throw new Error('TLS server certificate chain is not an ordered leaf-to-intermediate chain')\n    }\n  }\n}\n\nasync function tlsOptions(config: ResolvedGatewayConfig): Promise<ServerOptions> {\n  if (config.tls.mode === 'disabled') throw new Error('TLS options requested for a disabled listener')\n  const [certFile, key, additionalChainFile] = await Promise.all([\n    readFile(config.tls.certFile),\n    readFile(config.tls.keyFile),\n    config.tls.caFile === undefined ? Promise.resolve(undefined) : readFile(config.tls.caFile),\n  ])\n  const chain = [\n    ...parsePemCertificates(certFile, 'tls.certFile'),\n    ...(additionalChainFile === undefined ? [] : parsePemCertificates(additionalChainFile, 'tls.caFile')),\n  ]\n  validateServerChain(chain)\n  const leaf = chain[0]!.certificate\n  for (const authority of config.authorities) {\n    const hostname = stripIpv6Brackets(authority.hostname)\n    const match = isIP(hostname) === 0 ? leaf.checkHost(hostname) : leaf.checkIP(hostname)\n    if (match === undefined) throw new Error(`TLS certificate does not cover configured authority ${hostname}`)\n  }\n  return {\n    cert: chain.map(entry => entry.pem).join(''),\n    key,\n    requestCert: false,\n    minVersion: 'TLSv1.2',\n    maxHeaderSize: MAX_HEADER_BYTES,\n  }\n}\n\nfunction websocketAccept(key: string): string {\n  return createHash('sha1').update(`${key}258EAFA5-E914-47DA-95CA-C5AB0DC85B11`, 'ascii').digest('base64')\n}\n\nfunction headerValue(headers: IncomingHttpHeaders, name: string): string | undefined {\n  const value = headers[name]\n  return Array.isArray(value) ? undefined : value\n}\n\nfunction hasToken(header: string | undefined, token: string): boolean {\n  return header?.split(',').some(value => value.trim().toLowerCase() === token) ?? false\n}\n\nfunction rejectUpgrade(socket: Socket, status: number, code: string): void {\n  if (socket.destroyed) return\n  const body = `${JSON.stringify({ error: code })}\\n`\n  socket.end([\n    `HTTP/1.1 ${String(status)} ${status === 401 ? 'Unauthorized' : status === 403 ? 'Forbidden' : 'Bad Request'}`,\n    'Connection: close',\n    'Cache-Control: no-store',\n    'Content-Type: application/json; charset=utf-8',\n    'Referrer-Policy: no-referrer',\n    'X-Content-Type-Options: nosniff',\n    `Content-Length: ${String(Buffer.byteLength(body))}`,\n    '',\n    body,\n  ].join('\\r\\n'))\n}\n\nfunction sanitizeRequestHeaders(\n  request: IncomingMessage,\n  upstream: URL,\n): OutgoingHttpHeaders {\n  const headers: OutgoingHttpHeaders = {\n    host: upstream.host,\n  }\n  if (request.headers.origin !== undefined) headers.origin = upstream.origin\n  if (request.headers['sec-fetch-site'] !== undefined) headers['sec-fetch-site'] = 'same-origin'\n  const allowed: readonly string[] = [\n    'accept', 'accept-encoding', 'accept-language', 'content-encoding', 'content-length', 'content-type',\n    'if-match', 'if-modified-since', 'if-none-match', 'if-range', 'if-unmodified-since', 'range', 'user-agent',\n  ]\n  for (const name of allowed) {\n    const value = request.headers[name]\n    if (value !== undefined) headers[name] = value\n  }\n  return headers\n}\n\nconst BLOCKED_RESPONSE_HEADERS = new Set([\n  'alt-svc', 'cache-control', 'connection', 'content-security-policy', 'content-security-policy-report-only',\n  'cross-origin-embedder-policy', 'cross-origin-opener-policy', 'cross-origin-resource-policy', 'expires',\n  'keep-alive', 'nel', 'permissions-policy', 'pragma', 'proxy-authenticate', 'referrer-policy',\n  'report-to', 'reporting-endpoints', 'server', 'set-cookie', 'strict-transport-security', 'trailer',\n  'transfer-encoding', 'upgrade', 'via', 'x-content-type-options', 'x-frame-options', 'x-powered-by',\n])\n\nfunction sanitizeResponseHeaders(headers: IncomingHttpHeaders, upstream: URL): OutgoingHttpHeaders {\n  const clean: OutgoingHttpHeaders = {}\n  for (const [name, value] of Object.entries(headers)) {\n    const lower = name.toLowerCase()\n    if (value === undefined || BLOCKED_RESPONSE_HEADERS.has(lower) || lower.startsWith('access-control-')) continue\n    if (lower === 'location' && typeof value === 'string') {\n      try {\n        const location = new URL(value, upstream)\n        clean.location = location.origin === upstream.origin\n          ? `${location.pathname}${location.search}${location.hash}`\n          : value\n      } catch {\n        continue\n      }\n      continue\n    }\n    clean[lower] = value\n  }\n  return clean\n}\n\nfunction acceptsGzip(header: string | undefined): boolean {\n  if (header === undefined) return false\n  let wildcard: boolean | undefined\n  for (const entry of header.split(',')) {\n    const [rawName, ...parameters] = entry.split(';')\n    const name = rawName?.trim().toLowerCase()\n    if (name === undefined || name === '') continue\n    let quality = 1\n    for (const parameter of parameters) {\n      const match = /^\\s*q\\s*=\\s*(0(?:\\.\\d+)?|1(?:\\.0+)?)\\s*$/iu.exec(parameter)\n      if (match !== null) quality = Number(match[1])\n    }\n    if (name === 'gzip') return quality > 0\n    if (name === '*') wildcard = quality > 0\n  }\n  return wildcard ?? false\n}\n\nfunction isCompressibleContentType(value: string | string[] | undefined): boolean {\n  const contentType = Array.isArray(value) ? value[0] : value\n  if (contentType === undefined) return false\n  const mediaType = contentType.split(';', 1)[0]?.trim().toLowerCase() ?? ''\n  return mediaType.startsWith('text/')\n    || /^(?:application\\/(?:javascript|json|xml|x-javascript)|image\\/svg\\+xml)$/u.test(mediaType)\n}\n\nfunction canCompressResponse(request: IncomingMessage, response: IncomingMessage): boolean {\n  const pathname = request.url?.split('?', 1)[0] ?? ''\n  const compressibleRequest = (request.method === 'GET' || request.method === 'HEAD')\n    && (pathname.startsWith('/plugins/') || pathname.startsWith('/assets/'))\n  return compressibleRequest\n    && response.statusCode === 200\n    && request.headers.range === undefined\n    && response.headers['content-range'] === undefined\n    && response.headers['content-encoding'] === undefined\n    && isCompressibleContentType(response.headers['content-type'])\n}\n\nfunction revisionedStaticCacheControl(\n  request: IncomingMessage,\n  statusCode: number | undefined,\n): string | undefined {\n  if (request.method !== 'GET' && request.method !== 'HEAD') return undefined\n  // Delivered or successfully revalidated artifacts are immutable. Upstream DSH\n  // revisions identify successful bundles; a failed fetch is not that artifact.\n  // Stamping `max-age=31536000, immutable` onto a failure lets the WebView\n  // cache the rejection for a year and keep failing until its cache is cleared.\n  // Upstream DSH only marks successful responses immutable. Failures carry no\n  // cache-control, so the gateway keeps `no-store` from setSecurityHeaders.\n  if (statusCode !== 200 && statusCode !== 304) return undefined\n  let target: URL\n  try { target = new URL(request.url ?? '/', 'https://dsh-mobile.invalid') } catch { return undefined }\n  const revision = target.searchParams.get('rev')\n  const hasRevision = revision !== null && /^[a-z0-9_-]{4,128}$/iu.test(revision)\n  const hashedAsset = /^\\/assets\\/.*-[a-z0-9_-]{8,}\\.[a-z0-9]+$/iu.test(target.pathname)\n  if (!(target.pathname.startsWith('/plugins/') && hasRevision)\n    && !(target.pathname.startsWith('/assets/') && (hasRevision || hashedAsset))) return undefined\n  return 'private, max-age=31536000, immutable'\n}\n\nfunction addVaryAcceptEncoding(headers: OutgoingHttpHeaders): void {\n  const existing = headers.vary\n  const rawValues: string[] = Array.isArray(existing)\n    ? existing.map(value => String(value))\n    : existing === undefined ? [] : [String(existing)]\n  const values = rawValues.flatMap(value => value.split(',').map(part => part.trim()).filter(Boolean))\n  if (!values.some(value => value.toLowerCase() === 'accept-encoding')) values.push('Accept-Encoding')\n  headers.vary = values.join(', ')\n}\n\nfunction mapError(error: unknown): HttpError {\n  if (error instanceof HttpError) return error\n  if (error instanceof AccessError) return new HttpError(error.status, error.code)\n  if (error instanceof MobileExtensionError) return new HttpError(error.status, error.code)\n  return new HttpError(500, 'internal_error')\n}\n\nfunction requestAbortedError(): Error {\n  const error = new Error('request aborted')\n  error.name = 'AbortError'\n  return error\n}\n\nfunction isTransientUpstreamError(error: unknown): boolean {\n  if (!(error instanceof Error)) return false\n  const code = (error as NodeJS.ErrnoException).code\n  return typeof code === 'string' && TRANSIENT_UPSTREAM_ERROR_CODES.has(code)\n}\n\nfunction upstreamTimeoutError(): NodeJS.ErrnoException {\n  const error = new Error('upstream timeout') as NodeJS.ErrnoException\n  error.code = 'ETIMEDOUT'\n  return error\n}\n\nfunction waitForAbortableDelay(delayMs: number, signal: AbortSignal): Promise<void> {\n  if (signal.aborted) return Promise.reject(requestAbortedError())\n  return new Promise((resolve, reject) => {\n    const aborted = (): void => {\n      clearTimeout(timer)\n      reject(requestAbortedError())\n    }\n    const timer = setTimeout(() => {\n      signal.removeEventListener('abort', aborted)\n      resolve()\n    }, delayMs)\n    signal.addEventListener('abort', aborted, { once: true })\n  })\n}\n\nfunction waitForRequestTask<T>(task: Promise<T>, signal: AbortSignal): Promise<T> {\n  if (signal.aborted) return Promise.reject(requestAbortedError())\n  return new Promise((resolve, reject) => {\n    const aborted = (): void => {\n      reject(requestAbortedError())\n    }\n    signal.addEventListener('abort', aborted, { once: true })\n    void task.then(\n      value => {\n        signal.removeEventListener('abort', aborted)\n        resolve(value)\n      },\n      error => {\n        signal.removeEventListener('abort', aborted)\n        reject(error)\n      },\n    )\n  })\n}\n\nfunction discoveryDeviceName(): string {\n  const value = hostname().trim().replaceAll(/[\\u0000-\\u001f\\u007f]/gu, '')\n  return (value === '' ? 'DeepSeek Harness' : value).slice(0, 63)\n}\n\nfunction discoveryMdnsHost(instanceId: string): string {\n  const label = hostname().toLowerCase().replaceAll(/[^a-z0-9-]/gu, '-').replaceAll(/^-+|-+$/gu, '').slice(0, 40)\n  return `${label === '' ? 'dsh' : label}-${instanceId.slice(0, 8)}.local`\n}\n\nfunction discoveryBroadcastTargets(cidrs: readonly ParsedCidr[]): readonly string[] {\n  const targets = new Set<string>(['255.255.255.255'])\n  for (const cidr of cidrs) {\n    if (cidr.bits !== 32 || cidr.prefix >= 32) continue\n    const hostBits = BigInt(32 - cidr.prefix)\n    const broadcast = cidr.network | ((1n << hostBits) - 1n)\n    targets.add([24n, 16n, 8n, 0n].map(shift => Number((broadcast >> shift) & 0xffn)).join('.'))\n  }\n  return [...targets]\n}\n\n/** Keep Node's upgrade-owned socket safe after the HTTP parser removes its listener. */\nfunction guardUpgradeSocket(socket: Socket): void {\n  socket.on('error', () => {\n    if (!socket.destroyed) socket.destroy()\n  })\n}\n\nfunction discoveryFailure(error: unknown): { readonly code: string; readonly message: string } {\n  const code = error instanceof Error && typeof (error as NodeJS.ErrnoException).code === 'string'\n    ? (error as NodeJS.ErrnoException).code!\n    : 'unknown'\n  return Object.freeze({ code, message: error instanceof Error ? error.message : String(error) })\n}\n\nfunction extensionTarget(pathname: string):\n  | { readonly kind: 'manifest' }\n  | { readonly kind: 'events' }\n  | { readonly kind: 'script' | 'style' | 'asset'; readonly id: string; readonly path?: string }\n  | { readonly kind: 'action'; readonly id: string; readonly action: string }\n  | { readonly kind: 'route'; readonly id: string; readonly path: string }\n  | undefined {\n  const prefix = `${AUTH_PREFIX}/extensions`\n  if (pathname === prefix || pathname === `${prefix}/` || pathname === `${prefix}/manifest`) return { kind: 'manifest' }\n  if (pathname === `${prefix}/events`) return { kind: 'events' }\n  if (!pathname.startsWith(`${prefix}/`)) return undefined\n  const parts = pathname.slice(prefix.length + 1).split('/')\n  const id = parts.shift()\n  if (id === undefined || !/^[a-z][a-z0-9-]{0,63}$/u.test(id)) return undefined\n  const leaf = parts.shift()\n  if (leaf === 'mobile.js' && parts.length === 0) return { kind: 'script', id }\n  if (leaf === 'mobile.css' && parts.length === 0) return { kind: 'style', id }\n  if (leaf === 'assets' && parts.length > 0) return { kind: 'asset', id, path: parts.join('/') }\n  if (leaf === 'actions' && parts.length === 1 && /^[a-z][a-z0-9-]{0,63}$/u.test(parts[0]!)) return { kind: 'action', id, action: parts[0]! }\n  if (leaf === 'routes') return { kind: 'route', id, path: `/${parts.join('/')}`.replace(/\\/{2,}/gu, '/') }\n  return undefined\n}\n\nconst EXTENSION_GENERATION_HEADER = 'x-dsh-mobile-extension-generation'\n\nfunction extensionGeneration(value: string | undefined): string | undefined {\n  if (value === undefined) return undefined\n  if (!/^[a-f\\d]{64}$/u.test(value)) throw new HttpError(400, 'invalid_extension_generation')\n  return value\n}\n\nfunction mobileBootBatchKey(pathname: string): string | undefined {\n  const match = new RegExp(`^${MOBILE_BOOT_BATCH_PREFIX.replaceAll('/', '\\\\/')}([a-f\\\\d]{64})\\\\.js$`, 'u').exec(pathname)\n  return match?.[1]\n}\n\nfunction assertBoundedContentLength(request: IncomingMessage, maximum: number): void {\n  const declared = request.headers['content-length']\n  if (declared !== undefined && (!/^\\d+$/u.test(declared) || Number(declared) > maximum)) {\n    throw new HttpError(413, 'payload_too_large')\n  }\n}\n\nasync function readBoundedBody(request: IncomingMessage, maximum: number): Promise<Buffer> {\n  assertBoundedContentLength(request, maximum)\n  const chunks: Buffer[] = []\n  let total = 0\n  for await (const chunk of request) {\n    const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n    total += buffer.length\n    if (total > maximum) throw new HttpError(413, 'payload_too_large')\n    chunks.push(buffer)\n  }\n  return Buffer.concat(chunks)\n}\n\nfunction extensionRequestHeaders(headers: IncomingHttpHeaders): Readonly<Record<string, string>> {\n  const allowed = new Set(['accept', 'content-type', 'content-length', 'content-range', 'range', 'if-none-match', 'if-modified-since'])\n  const output: Record<string, string> = {}\n  for (const [name, value] of Object.entries(headers)) {\n    if (!allowed.has(name) || typeof value !== 'string') continue\n    output[name] = value\n  }\n  return Object.freeze(output)\n}\n\nfunction extensionContentType(path: string): string {\n  const type = {\n    '.css': 'text/css; charset=utf-8',\n    '.csv': 'text/csv; charset=utf-8',\n    '.gif': 'image/gif',\n    '.html': 'text/html; charset=utf-8',\n    '.jpeg': 'image/jpeg',\n    '.jpg': 'image/jpeg',\n    '.js': 'text/javascript; charset=utf-8',\n    '.json': 'application/json; charset=utf-8',\n    '.png': 'image/png',\n    '.svg': 'image/svg+xml',\n    '.webp': 'image/webp',\n  }[extname(path).toLowerCase()]\n  return type ?? 'application/octet-stream'\n}\n\n/** Authenticated TLS edge in front of the ordinary loopback-only DSH Web server. */\nexport class MobileAccessGateway {\n  readonly access: AccessController\n  private readonly listenerTlsEnabled: boolean\n  private readonly tlsEnabled: boolean\n  private policy: RequestTrustPolicy | undefined\n  private server: GatewayServer | undefined\n  private discoverySocket: DatagramSocket | undefined\n  private discoveryTimer: NodeJS.Timeout | undefined\n  /**\n   * Why broadcast discovery is unavailable, if it is. Windows keeps separate TCP and\n   * UDP port-exclusion tables, so the port the OS handed the TCP listener can be\n   * refused for UDP. That degradation is survivable but must stay observable: without\n   * it, \"the phone cannot find this computer\" has no diagnosable cause on the host.\n   */\n  private discoveryError: { readonly code: string; readonly message: string } | undefined\n  private mdnsError: { readonly code: string; readonly message: string } | undefined\n  /** Names of the bundled mobile assets that could not be read, if any. */\n  private mobileAssetError: string | undefined\n  private lastModuleExclusionError: string | undefined\n  private bonjour: Bonjour | undefined\n  private pairingCaCertificate: string | undefined\n  private listenerPort: number | undefined\n  private readonly connectedSockets = new Set<Socket>()\n  private readonly activeRequests = new Map<number, ActiveRequest>()\n  private readonly activeWebSockets = new Map<number, ActiveWebSocket>()\n  private readonly mobileBootBatches = new Map<string, StoredMobileBootBatch>()\n  /** Cached upstream bundle byte sizes (HEAD probes), keyed by resource URL. */\n  private readonly bootEntrySizeCache = new Map<string, { size: number; at: number }>()\n  private readonly extensionEventListeners = new Set<(revision: number) => void>()\n  private extensionEventRevision = 0\n  private readonly taskEventListeners = new Set<(payload: string) => void>()\n  private readonly deviceEventListeners = new Map<string, Set<(payload: string) => void>>()\n  private readonly pendingDeviceRevocations = new Set<string>()\n  private extensionChangeTimer: NodeJS.Timeout | undefined\n  private extensionChangeTask: Promise<void> | undefined\n  private legacyCustomDigest = ''\n  private upstreamCookie: string | undefined\n  private upstreamCookieExpiresAt = 0\n  private upstreamCookieTask: Promise<string> | undefined\n  private upstreamAuthRequest: ClientRequest | undefined\n  private nextOperationId = 1\n  private closing = false\n  private started = false\n  private closeTask: Promise<void> | undefined\n  private readonly removeSessionListener: () => void\n  private readonly removeExtensionContentListener: () => void\n  private readonly renewLimiter: BoundedRateLimiter\n  private readonly probeLimiter: BoundedRateLimiter\n  private readonly clientModulePreferences: ClientModulePreferenceStore\n  private readonly clientModuleOperations = new Set<AbortController>()\n  private readonly clientModuleTasks = new Set<Promise<ClientModulePreferenceView>>()\n  private readonly clientModuleRevocations = new Set<Promise<void>>()\n\n  constructor(\n    readonly config: ResolvedGatewayConfig,\n    store: DeviceStore,\n    private readonly extensions?: MobileAccessService,\n    private readonly upstreamAuthenticatedUrl?: string,\n    private readonly extraWebSocketPaths?: { has(pathname: string): boolean },\n    private readonly blockedUpgradeLog?: BlockedUpgradePathLog,\n    private readonly onDiscoveryDegraded?: (source: 'broadcast' | 'mdns', code: string) => void,\n    clientModulePreferences?: ClientModulePreferenceStore,\n  ) {\n    this.clientModulePreferences = clientModulePreferences ?? new ClientModulePreferenceStore(\n      join(dirname(config.stateFile), `${basename(config.stateFile)}.client-modules.json`), config.excludedClientModules,\n    )\n    this.listenerTlsEnabled = config.tls.mode === 'provided'\n    this.tlsEnabled = config.publicTls\n    this.access = new AccessController(store, {\n      pairingTtlMs: config.pairingTtlMs,\n      deviceTtlMs: config.deviceTtlMs,\n      sessionTtlMs: config.sessionTtlMs,\n      maxDevices: config.maxDevices,\n      maxSessions: config.maxSessions,\n      rateLimitWindowMs: config.rateLimitWindowMs,\n      maxPairingAttempts: config.maxPairingAttempts,\n      maxRateLimitKeys: config.maxRateLimitKeys,\n    })\n    this.renewLimiter = new BoundedRateLimiter(\n      Math.min(100, config.maxPairingAttempts * 4),\n      config.rateLimitWindowMs,\n      config.maxRateLimitKeys,\n    )\n    // Reachability checks do not create Sessions; allow one short poll for\n    // each configured device without weakening the Session-creating limit.\n    this.probeLimiter = new BoundedRateLimiter(\n      Math.min(1_000, config.maxDevices * 4),\n      config.rateLimitWindowMs,\n      config.maxRateLimitKeys,\n    )\n    this.removeSessionListener = this.access.onSessionEnded((authorization, reason) => {\n      if (reason === 'revoked') {\n        const cleanup = this.clientModulePreferences.removeDevice(authorization.deviceId)\n          .catch(() => { process.emitWarning('Unable to remove revoked device client preferences', { code: 'DSH_MOBILE_PREFERENCE_CLEANUP_FAILED' }) })\n        this.clientModuleRevocations.add(cleanup)\n        void cleanup.finally(() => this.clientModuleRevocations.delete(cleanup))\n        if (!this.pendingDeviceRevocations.has(authorization.deviceId)) {\n          this.pendingDeviceRevocations.add(authorization.deviceId)\n          this.broadcastDeviceRevoked(authorization.deviceId)\n        }\n        // Let the final SSE frame enter the socket before revocation closes\n        // the session-owned stream and WebSockets.\n        setImmediate(() => {\n          this.abortSessionResources(authorization.sessionKey)\n          this.pendingDeviceRevocations.delete(authorization.deviceId)\n        })\n      } else {\n        this.abortSessionResources(authorization.sessionKey)\n      }\n    })\n    this.removeExtensionContentListener = this.extensions?.onContentChanged(() => {\n      this.broadcastExtensionChange()\n    }) ?? (() => undefined)\n  }\n\n  /** Initialize durable state, validate TLS, and bind the externally reachable listener. */\n  async start(): Promise<void> {\n    if (this.started || this.server !== undefined) throw new Error('mobile-access gateway cannot be started twice')\n    this.started = true\n    await this.access.initialize()\n    try {\n      await this.clientModulePreferences.initialize()\n      if (this.config.pairingCaFile !== undefined) {\n        const certificate = new X509Certificate(await readFile(this.config.pairingCaFile))\n        const fingerprint = certificate.fingerprint256.replaceAll(':', '').toLowerCase()\n        if (!certificate.ca || certificate.subject !== certificate.issuer\n          || !certificate.verify(certificate.publicKey) || fingerprint !== this.config.instanceId) {\n          throw new Error('pairingCaFile must be the self-signed CA identified by instanceId')\n        }\n        this.pairingCaCertificate = certificate.raw.toString('base64')\n      }\n      // Both mobile assets are injected into the served index, so a missing one would\n      // otherwise surface only as a 503 subresource: the page still renders and the\n      // compatibility bundle silently never applies. Record it instead of failing, so an\n      // enhancement cannot take the whole listener down, and expose it for diagnosis.\n      const missingAssets: string[] = []\n      for (const [label, file] of [\n        ['compatibility', this.config.mobileCompatibilityFile],\n        ['layout', this.config.mobileLayoutFile],\n      ] as const) {\n        if (!(await lstat(file).catch(() => undefined))?.isFile()) missingAssets.push(label)\n      }\n      this.mobileAssetError = missingAssets.length === 0 ? undefined : `mobile_assets_missing_${missingAssets.join('_')}`\n      const handler = (request: IncomingMessage, response: ServerResponse): void => {\n        void this.handleExternalRequest(request, response).catch((error: unknown) => {\n          const mapped = mapError(error)\n          if (response.headersSent) response.destroy()\n          else sendFailure(response, mapped.status, mapped.code, this.tlsEnabled)\n        })\n      }\n      const server = this.listenerTlsEnabled\n        ? createHttpsServer(await tlsOptions(this.config), handler)\n        : createHttpServer({ maxHeaderSize: MAX_HEADER_BYTES }, handler)\n      this.server = server\n      server.maxHeadersCount = 64\n      server.maxConnections = this.config.maxConnections\n      server.headersTimeout = 10_000\n      server.requestTimeout = this.config.upstreamTimeoutMs\n      server.keepAliveTimeout = 5_000\n      server.on('connection', (socket: Socket) => {\n        if (this.connectedSockets.size >= this.config.maxConnections) {\n          socket.destroy()\n          return\n        }\n        this.connectedSockets.add(socket)\n        socket.on('error', () => { socket.destroy() })\n        socket.once('close', () => { this.connectedSockets.delete(socket) })\n      })\n      server.on('connect', (_request, socket) => { socket.destroy() })\n      server.on('upgrade', (request, socket, head) => {\n        const client = socket as Socket\n        // Node removes its normal connection error listener when it hands this\n        // socket to the upgrade event. Install ours before any sync validation\n        // or await so a stale TLS/WebSocket connection cannot terminate DSH.\n        guardUpgradeSocket(client)\n        void this.handleUpgrade(request, client, head).catch((error: unknown) => {\n          const mapped = mapError(error)\n          rejectUpgrade(client, mapped.status, mapped.code)\n        })\n      })\n      server.on('clientError', (_error, socket) => { rejectUpgrade(socket as Socket, 400, 'bad_request') })\n      await new Promise<void>((resolve, reject) => {\n        const failed = (error: Error): void => { reject(error) }\n        server.once('error', failed)\n        server.listen(this.config.listenPort, this.config.listenHost, () => {\n          server.off('error', failed)\n          resolve()\n        })\n      })\n      const address = server.address()\n      if (address === null || typeof address === 'string') throw new Error('gateway listener has no TCP address')\n      this.listenerPort = address.port\n      this.policy = new RequestTrustPolicy(\n        this.config.authorities,\n        address.port,\n        this.config.allowedCidrs,\n        this.tlsEnabled,\n      )\n      if (this.config.discovery) await this.startDiscovery(address.port)\n      await this.pollLegacyCustomChanges()\n      this.extensionChangeTimer = setInterval(() => { void this.pollLegacyCustomChanges() }, EXTENSION_CHANGE_POLL_MS)\n      this.extensionChangeTimer.unref()\n    } catch (error) {\n      await this.closeFailedStart()\n      throw error\n    }\n  }\n\n  /** Install a newly signed provided leaf for future TLS handshakes without dropping sessions. */\n  async refreshProvidedTls(): Promise<void> {\n    if (!this.listenerTlsEnabled || this.config.tls.mode !== 'provided') {\n      throw new Error('gateway does not terminate provided TLS')\n    }\n    const server = this.server\n    if (server === undefined || !this.started || this.closing) throw new Error('gateway is not running')\n    const options = await tlsOptions(this.config)\n    if (this.server !== server || this.closing) throw new Error('gateway is not running');\n    (server as HttpsServer).setSecureContext(options)\n  }\n\n  private async startDiscovery(port: number): Promise<void> {\n    const socket = createSocket('udp4')\n    this.discoverySocket = socket\n    const announcement = this.discoveryAnnouncement(port)\n    let binding = true\n    socket.on('error', error => {\n      if (!binding) this.recordBroadcastFailure(error, true)\n    })\n    const sendAnnouncement = (targetPort: number, address: string): void => {\n      if (this.closing || this.discoveryError !== undefined) return\n      try {\n        socket.send(announcement, targetPort, address, error => {\n          if (error !== null) this.recordBroadcastFailure(error, true)\n        })\n      } catch (error) {\n        this.recordBroadcastFailure(error, true)\n      }\n    }\n    socket.on('message', (message, remote) => {\n      if (this.closing || this.discoveryError !== undefined || !message.equals(DISCOVERY_QUERY)\n        || !addressAllowed(remote.address, this.config.allowedCidrs)) return\n      sendAnnouncement(remote.port, remote.address)\n    })\n    // The UDP socket is IPv4-only; only a literal IPv4 loopback address is bindable, never ::1.\n    const bindHost = isIP(this.config.listenHost) === 4 && isLoopbackAddress(this.config.listenHost) ? this.config.listenHost : '0.0.0.0'\n    // Windows keeps separate TCP and UDP port-exclusion tables, so the port the OS handed\n    // the TCP listener can be unavailable for UDP; another process may also already hold\n    // it. Broadcast discovery is a convenience, so a failed bind must not take the whole\n    // gateway down — the mDNS publication below still advertises this origin.\n    const bound = await new Promise<boolean>(resolve => {\n      const onBindError = (error: NodeJS.ErrnoException): void => {\n        socket.off('error', onBindError)\n        this.recordBroadcastFailure(error, false)\n        resolve(false)\n      }\n      socket.once('error', onBindError)\n      try {\n        socket.bind(port, bindHost, () => {\n          socket.off('error', onBindError)\n          binding = false\n          try {\n            socket.setBroadcast(true)\n            resolve(true)\n          } catch (error) {\n            this.recordBroadcastFailure(error, true)\n            resolve(false)\n          }\n        })\n      } catch (error) {\n        onBindError(error as NodeJS.ErrnoException)\n      }\n    })\n    if (bound && this.discoveryError === undefined) {\n      const announce = (): void => {\n        for (const target of discoveryBroadcastTargets(this.config.allowedCidrs)) {\n          sendAnnouncement(port, target)\n        }\n      }\n      announce()\n      if (this.discoveryError === undefined) {\n        this.discoveryTimer = setInterval(announce, DISCOVERY_INTERVAL_MS)\n        this.discoveryTimer.unref()\n      }\n    } else {\n      this.discoverySocket = undefined\n      // A socket whose bind failed was never running, so close() throws synchronously.\n      try { socket.close() } catch { /* the socket never started */ }\n    }\n\n    const deviceName = discoveryDeviceName()\n    const onMdnsError = (error: unknown): void => { this.recordMdnsFailure(error) }\n    const bonjour = new Bonjour({ disableIPv6: true }, onMdnsError)\n    this.bonjour = bonjour\n    // bonjour-service 1.4.4 does not forward multicast-dns EventEmitter errors\n    // through errorCallback. Keep a listener on its underlying emitter for its lifetime.\n    const mdns = (bonjour as unknown as { server: { mdns: { on(event: 'error', listener: (error: Error) => void): void } } }).server.mdns\n    mdns.on('error', onMdnsError)\n    bonjour.publish({\n      name: `${deviceName} (${this.config.instanceId.slice(0, 8)})`,\n      type: MDNS_SERVICE_TYPE,\n      protocol: 'tcp',\n      port,\n      host: discoveryMdnsHost(this.config.instanceId),\n      disableIPv6: true,\n      txt: {\n        deviceName,\n        origin: this.address().origin,\n        instanceId: this.config.instanceId,\n        protocol: String(DISCOVERY_PROTOCOL),\n      },\n    })\n  }\n\n  private reportDiscoveryDegraded(source: 'broadcast' | 'mdns', code: string): void {\n    try {\n      this.onDiscoveryDegraded?.(source, code)\n    } catch (error) {\n      process.emitWarning(`DSH Mobile could not log ${source} discovery error: ${String(error)}`, {\n        code: 'DSH_MOBILE_DISCOVERY_LOG_FAILED',\n      })\n    }\n  }\n\n  private recordBroadcastFailure(error: unknown, notify: boolean): void {\n    if (this.closing || this.discoveryError !== undefined) return\n    this.discoveryError = discoveryFailure(error)\n    if (this.discoveryTimer !== undefined) clearInterval(this.discoveryTimer)\n    this.discoveryTimer = undefined\n    if (notify) this.reportDiscoveryDegraded('broadcast', this.discoveryError.code)\n  }\n\n  private recordMdnsFailure(error: unknown): void {\n    if (this.closing || this.mdnsError !== undefined) return\n    this.mdnsError = discoveryFailure(error)\n    this.reportDiscoveryDegraded('mdns', this.mdnsError.code)\n  }\n\n  private discoveryAnnouncement(port: number): Buffer {\n    return Buffer.from(JSON.stringify({\n      deviceName: discoveryDeviceName(),\n      origin: this.address().origin,\n      port,\n      protocol: DISCOVERY_PROTOCOL,\n      instanceId: this.config.instanceId,\n    }), 'utf8')\n  }\n\n  private async closeFailedStart(): Promise<void> {\n    if (this.extensionChangeTimer !== undefined) clearInterval(this.extensionChangeTimer)\n    this.extensionChangeTimer = undefined\n    this.removeExtensionContentListener()\n    if (this.discoveryTimer !== undefined) clearInterval(this.discoveryTimer)\n    this.discoveryTimer = undefined\n    await this.closeBonjour()\n    this.discoverySocket?.close()\n    this.discoverySocket = undefined\n    for (const socket of this.connectedSockets) socket.destroy()\n    const server = this.server\n    this.server = undefined\n    if (server?.listening === true) {\n      await new Promise<void>(resolve => { server.close(() => resolve()) })\n    }\n    await this.access.close()\n  }\n\n  private async closeBonjour(): Promise<void> {\n    const bonjour = this.bonjour\n    this.bonjour = undefined\n    if (bonjour === undefined) return\n    await new Promise<void>(resolve => {\n      bonjour.unpublishAll(() => { bonjour.destroy(() => resolve()) })\n    })\n  }\n\n  /** Actual bound address, available after start and safe for loopback status output. */\n  address(): { host: string; port: number; origin: string } {\n    if (this.listenerPort === undefined || this.policy === undefined) throw new Error('gateway is not listening')\n    const origin = this.policy.origins.values().next().value as string | undefined\n    if (origin === undefined) throw new Error('gateway has no public authority')\n    return Object.freeze({ host: this.config.listenHost, port: this.listenerPort, origin })\n  }\n\n  /**\n   * Report which discovery channels this gateway actually owns.\n   *\n   * Broadcast discovery degrades on its own when its UDP port cannot be bound, so\n   * callers need to tell \"discovery is off\" from \"discovery was never attempted\".\n   * mDNS is published independently and is unaffected by that failure.\n   */\n  discoveryStatus(): {\n    readonly broadcast: boolean\n    readonly mdns: boolean\n    readonly errorCode?: string\n    readonly mdnsErrorCode?: string\n    readonly mobileAssetsErrorCode?: string\n  } {\n    return Object.freeze({\n      broadcast: this.discoverySocket !== undefined && this.discoveryTimer !== undefined,\n      mdns: this.bonjour !== undefined && this.mdnsError === undefined,\n      ...(this.discoveryError === undefined ? {} : { errorCode: `discovery_broadcast_${this.discoveryError.code}` }),\n      ...(this.mdnsError === undefined ? {} : { mdnsErrorCode: `discovery_mdns_${this.mdnsError.code}` }),\n      // A bundled asset that is missing would otherwise only show up as a 503 on a\n      // subresource the served page still references.\n      ...(this.mobileAssetError === undefined ? {} : { mobileAssetsErrorCode: this.mobileAssetError }),\n    })\n  }\n\n  private requirePolicy(): RequestTrustPolicy {\n    if (this.policy === undefined || this.closing) throw new HttpError(503, 'unavailable')\n    return this.policy\n  }\n\n  private authorize(request: IncomingMessage): SessionAuthorization {\n    const cookies = browserAuthCookies(request.headers.cookie)\n    const name = this.tlsEnabled && cookies.has(HOST_SESSION_COOKIE) ? HOST_SESSION_COOKIE : SESSION_COOKIE\n    return authenticatedCookie(cookies.get(name) ?? [], token => this.access.authorizeSession(token)).result\n  }\n\n  private requireCsrf(request: IncomingMessage, authorization: SessionAuthorization): void {\n    const value = headerValue(request.headers, CSRF_HEADER)\n    this.access.assertCsrf(authorization, value)\n  }\n\n  private setSessionCookies(response: ServerResponse, result: {\n    sessionToken: string\n    csrfToken: string\n    sessionExpiresAt: number\n  }, now: number): void {\n    const maxAge = (result.sessionExpiresAt - now) / 1000\n    response.setHeader('Set-Cookie', [\n      cookie(SESSION_COOKIE, result.sessionToken, { tls: this.tlsEnabled, httpOnly: true, path: '/', maxAgeSeconds: maxAge }),\n      cookie(CSRF_COOKIE, result.csrfToken, { tls: this.tlsEnabled, httpOnly: false, path: '/', maxAgeSeconds: maxAge }),\n      ...(this.tlsEnabled ? [\n        cookie(HOST_SESSION_COOKIE, result.sessionToken, { tls: true, httpOnly: true, path: '/', maxAgeSeconds: maxAge }),\n        cookie(HOST_CSRF_COOKIE, result.csrfToken, { tls: true, httpOnly: false, path: '/', maxAgeSeconds: maxAge }),\n      ] : []),\n    ])\n  }\n\n  private setBrowserDeviceBinding(response: ServerResponse, deviceId: string, deviceExpiresAt: number): void {\n    if (!this.tlsEnabled) return\n    const existing = response.getHeader('Set-Cookie') as string[]\n    response.setHeader('Set-Cookie', [...existing, cookie(HOST_DEVICE_COOKIE, deviceId, {\n      tls: true, httpOnly: true, path: '/', maxAgeSeconds: (deviceExpiresAt - Date.now()) / 1000,\n    })])\n  }\n\n  private async handlePair(request: IncomingMessage, response: ServerResponse): Promise<void> {\n    const body = await readJsonObject(request, MAX_CONTROL_BODY_BYTES)\n    if (typeof body.token !== 'string' || (body.label !== undefined && typeof body.label !== 'string')) {\n      throw new HttpError(400, 'bad_request')\n    }\n    const result = await this.access.pair(request.socket.remoteAddress ?? 'unknown', body.token, body.label as string | undefined)\n    const now = Date.now()\n    this.setSessionCookies(response, result, now)\n    const sessionCookies = response.getHeader('Set-Cookie') as string[]\n    response.setHeader('Set-Cookie', [\n      ...sessionCookies,\n      cookie(DEVICE_COOKIE, result.deviceToken, {\n        tls: this.tlsEnabled,\n        httpOnly: true,\n        path: '/mobile-access/auth/renew',\n        maxAgeSeconds: (result.deviceExpiresAt - now) / 1000,\n      }),\n    ])\n    this.setBrowserDeviceBinding(response, result.deviceId, result.deviceExpiresAt)\n    sendJson(response, 201, {\n      paired: true,\n      deviceId: result.deviceId,\n      csrfToken: result.csrfToken,\n      sessionExpiresAt: result.sessionExpiresAt,\n    }, this.tlsEnabled)\n  }\n\n  private async handleRenew(request: IncomingMessage, response: ServerResponse): Promise<void> {\n    if (!this.renewLimiter.take(request.socket.remoteAddress ?? 'unknown', Date.now())) {\n      throw new HttpError(429, 'rate_limited')\n    }\n    await readJsonObject(request, MAX_CONTROL_BODY_BYTES)\n    const cookies = browserAuthCookies(request.headers.cookie)\n    const bindings = this.tlsEnabled ? cookies.get(HOST_DEVICE_COOKIE) : undefined\n    if (bindings !== undefined && bindings.length !== 1) throw new HttpError(401, 'authentication_failed')\n    const device = authenticatedCookie(\n      cookies.get(DEVICE_COOKIE) ?? [],\n      token => this.access.authorizeDevice(token),\n      candidate => bindings === undefined || candidate.deviceId === bindings[0],\n    )\n    const result = await this.access.renew(device.value)\n    this.setSessionCookies(response, result, Date.now())\n    this.setBrowserDeviceBinding(response, result.deviceId, device.result.deviceExpiresAt)\n    sendJson(response, 200, {\n      renewed: true,\n      deviceId: result.deviceId,\n      csrfToken: result.csrfToken,\n      sessionExpiresAt: result.sessionExpiresAt,\n    }, this.tlsEnabled)\n  }\n\n  private async handleNativePair(request: IncomingMessage, response: ServerResponse): Promise<void> {\n    const body = await readJsonObject(request, MAX_CONTROL_BODY_BYTES)\n    if (typeof body.token !== 'string' || (body.label !== undefined && typeof body.label !== 'string')) {\n      throw new HttpError(400, 'bad_request')\n    }\n    const result = await this.access.pair(\n      request.socket.remoteAddress ?? 'unknown',\n      body.token,\n      body.label as string | undefined,\n    )\n    sendJson(response, 201, {\n      instanceId: this.config.instanceId,\n      deviceId: result.deviceId,\n      deviceToken: result.deviceToken,\n      deviceExpiresAt: result.deviceExpiresAt,\n      sessionToken: result.sessionToken,\n      csrfToken: result.csrfToken,\n      sessionExpiresAt: result.sessionExpiresAt,\n    }, this.tlsEnabled)\n  }\n\n  private async handleNativeRenew(request: IncomingMessage, response: ServerResponse): Promise<void> {\n    if (!this.renewLimiter.take(request.socket.remoteAddress ?? 'unknown', Date.now())) {\n      throw new HttpError(429, 'rate_limited')\n    }\n    const body = await readJsonObject(request, MAX_CONTROL_BODY_BYTES)\n    if (typeof body.deviceToken !== 'string') throw new HttpError(400, 'bad_request')\n    const result = await this.access.renew(body.deviceToken)\n    sendJson(response, 200, {\n      instanceId: this.config.instanceId,\n      deviceId: result.deviceId,\n      sessionToken: result.sessionToken,\n      csrfToken: result.csrfToken,\n      sessionExpiresAt: result.sessionExpiresAt,\n    }, this.tlsEnabled)\n  }\n\n  private async handleNativeProbe(request: IncomingMessage, response: ServerResponse): Promise<void> {\n    if (!this.probeLimiter.take(request.socket.remoteAddress ?? 'unknown', Date.now())) {\n      throw new HttpError(429, 'rate_limited')\n    }\n    const body = await readJsonObject(request, MAX_CONTROL_BODY_BYTES)\n    if (typeof body.deviceToken !== 'string') throw new HttpError(400, 'bad_request')\n    const result = await this.access.probe(body.deviceToken)\n    sendJson(response, 200, {\n      instanceId: this.config.instanceId,\n      deviceId: result.deviceId,\n      deviceExpiresAt: result.deviceExpiresAt,\n    }, this.tlsEnabled)\n  }\n\n  private async handleLogout(request: IncomingMessage, response: ServerResponse): Promise<void> {\n    await readJsonObject(request, MAX_CONTROL_BODY_BYTES)\n    const authorization = this.authorize(request)\n    this.requireCsrf(request, authorization)\n    this.access.logout(authorization)\n    response.setHeader('Set-Cookie', [\n      cookie(SESSION_COOKIE, '', { tls: this.tlsEnabled, httpOnly: true, path: '/', maxAgeSeconds: 0 }),\n      cookie(CSRF_COOKIE, '', { tls: this.tlsEnabled, httpOnly: false, path: '/', maxAgeSeconds: 0 }),\n      ...(this.tlsEnabled ? [\n        cookie(HOST_SESSION_COOKIE, '', { tls: true, httpOnly: true, path: '/', maxAgeSeconds: 0 }),\n        cookie(HOST_CSRF_COOKIE, '', { tls: true, httpOnly: false, path: '/', maxAgeSeconds: 0 }),\n      ] : []),\n    ])\n    sendJson(response, 200, { loggedOut: true }, this.tlsEnabled)\n  }\n\n  private async handleExternalRequest(request: IncomingMessage, response: ServerResponse): Promise<void> {\n    const target = parseRequestTarget(request.url)\n    const policy = this.requirePolicy()\n    const isMutation = request.method !== 'GET' && request.method !== 'HEAD'\n    assertExternalTrust(request, policy, isMutation)\n    if (target.decodedPathname === LOCAL_ADMIN_PREFIX || target.decodedPathname.startsWith(`${LOCAL_ADMIN_PREFIX}/`)) {\n      throw new HttpError(404, 'not_found')\n    }\n    if (request.method === 'TRACE' || request.method === 'CONNECT') throw new HttpError(405, 'method_not_allowed')\n\n    if (target.search === '' && request.method === 'GET' && target.decodedPathname === `${AUTH_PREFIX}/health`) {\n      sendJson(response, 200, { ok: true }, this.tlsEnabled)\n      return\n    }\n    if (target.search === '' && request.method === 'GET' && target.decodedPathname === `${AUTH_PREFIX}/metadata`) {\n      sendJson(response, 200, {\n        version: MOBILE_METADATA_VERSION,\n        pluginVersion: DSH_MOBILE_VERSION,\n        minimumAndroidAppVersion: MINIMUM_ANDROID_APP_VERSION,\n        discoveryProtocol: DISCOVERY_PROTOCOL,\n      }, this.tlsEnabled)\n      return\n    }\n    if (target.search === '' && request.method === 'GET' && target.decodedPathname === `${AUTH_PREFIX}/discovery`) {\n      sendJson(response, 200, {\n        deviceName: discoveryDeviceName(),\n        origin: this.address().origin,\n        port: this.address().port,\n        protocol: DISCOVERY_PROTOCOL,\n        instanceId: this.config.instanceId,\n      }, this.tlsEnabled)\n      return\n    }\n    if (target.search === '' && request.method === 'GET' && target.decodedPathname === `${AUTH_PREFIX}/ca.cer`) {\n      if (this.pairingCaCertificate === undefined) throw new HttpError(404, 'not_found')\n      const body = Buffer.from(this.pairingCaCertificate, 'base64')\n      setSecurityHeaders(response, this.tlsEnabled)\n      response.writeHead(200, {\n        'Content-Type': 'application/pkix-cert',\n        'Content-Length': body.length,\n        'Cache-Control': 'no-store',\n      })\n      response.end(body)\n      return\n    }\n    if (target.search === '' && request.method === 'GET'\n      && (target.decodedPathname === `${AUTH_PREFIX}/pair` || target.decodedPathname === `${AUTH_PREFIX}/pair.js`)) {\n      if (!this.access.pairingStatus().open) throw new HttpError(404, 'not_found')\n      const languageHeader = request.headers['accept-language']\n      const locale = resolveAuthPageLocale(typeof languageHeader === 'string' ? languageHeader : undefined)\n      setSecurityHeaders(response, this.tlsEnabled)\n      response.setHeader('Vary', 'Accept-Language')\n      const body = target.decodedPathname.endsWith('.js') ? renderPairScript(locale) : renderPairPage(locale)\n      response.writeHead(200, {\n        'Content-Type': target.decodedPathname.endsWith('.js') ? 'text/javascript; charset=utf-8' : 'text/html; charset=utf-8',\n        'Content-Length': Buffer.byteLength(body),\n      })\n      response.end(body)\n      return\n    }\n    if (request.method === 'GET'\n      && (target.decodedPathname === `${AUTH_PREFIX}/login` || target.decodedPathname === `${AUTH_PREFIX}/login.js`)) {\n      if (target.decodedPathname.endsWith('.js') && target.search !== '') throw new HttpError(400, 'bad_request')\n      const languageHeader = request.headers['accept-language']\n      const locale = resolveAuthPageLocale(typeof languageHeader === 'string' ? languageHeader : undefined)\n      setSecurityHeaders(response, this.tlsEnabled)\n      response.setHeader('Vary', 'Accept-Language')\n      const body = target.decodedPathname.endsWith('.js') ? renderLoginScript(locale) : renderLoginPage(locale)\n      response.writeHead(200, {\n        'Content-Type': target.decodedPathname.endsWith('.js') ? 'text/javascript; charset=utf-8' : 'text/html; charset=utf-8',\n        'Content-Length': Buffer.byteLength(body),\n      })\n      response.end(body)\n      return\n    }\n    if (target.search === '' && request.method === 'POST' && target.decodedPathname === `${AUTH_PREFIX}/auth/pair`) {\n      await this.handlePair(request, response)\n      return\n    }\n    if (target.search === '' && request.method === 'POST' && target.decodedPathname === `${AUTH_PREFIX}/auth/renew`) {\n      await this.handleRenew(request, response)\n      return\n    }\n    if (target.search === '' && request.method === 'POST' && target.decodedPathname === `${AUTH_PREFIX}/auth/native-pair`) {\n      await this.handleNativePair(request, response)\n      return\n    }\n    if (target.search === '' && request.method === 'POST' && target.decodedPathname === `${AUTH_PREFIX}/auth/native-renew`) {\n      await this.handleNativeRenew(request, response)\n      return\n    }\n    if (target.search === '' && request.method === 'POST' && target.decodedPathname === `${AUTH_PREFIX}/auth/native-probe`) {\n      await this.handleNativeProbe(request, response)\n      return\n    }\n    if (target.search === '' && request.method === 'POST' && target.decodedPathname === `${AUTH_PREFIX}/auth/logout`) {\n      await this.handleLogout(request, response)\n      return\n    }\n    const computerImages = request.method === 'GET' && target.decodedPathname === `${AUTH_PREFIX}/computer-images`\n    const computerImage = request.method === 'GET' && target.decodedPathname === `${AUTH_PREFIX}/computer-image`\n    const clientModules = target.decodedPathname === `${AUTH_PREFIX}/client-modules`\n    const requestedExtension = extensionTarget(target.decodedPathname)\n    const requestedMobileBootBatch = mobileBootBatchKey(target.decodedPathname)\n    const customAsset = (request.method === 'GET' || request.method === 'HEAD')\n      ? target.decodedPathname === `${AUTH_PREFIX}/custom.css`\n        ? {\n            file: this.config.customCssFile,\n            contentType: 'text/css; charset=utf-8',\n            fallback: CUSTOM_STYLE_FALLBACK,\n          }\n        : target.decodedPathname === `${AUTH_PREFIX}/custom.js`\n          ? {\n              file: this.config.customScriptFile,\n              contentType: 'text/javascript; charset=utf-8',\n              fallback: CUSTOM_SCRIPT_FALLBACK,\n            }\n          : target.decodedPathname === MOBILE_LAYOUT_PATH\n            ? {\n                file: this.config.mobileLayoutFile,\n                contentType: 'text/javascript; charset=utf-8',\n                fallback: undefined,\n              }\n            : target.decodedPathname === MOBILE_COMPAT_PATH\n              ? {\n                  file: this.config.mobileCompatibilityFile,\n                  contentType: 'text/javascript; charset=utf-8',\n                  fallback: undefined,\n                }\n              : undefined\n      : undefined\n    if (customAsset === undefined && requestedMobileBootBatch === undefined && !computerImages && !computerImage && !clientModules\n      && extensionTarget(target.decodedPathname) === undefined\n      && (target.decodedPathname === AUTH_PREFIX || target.decodedPathname.startsWith(`${AUTH_PREFIX}/`))) {\n      throw new HttpError(404, 'not_found')\n    }\n\n    if (!['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(request.method ?? '')\n      && requestedExtension?.kind !== 'route') {\n      throw new HttpError(405, 'method_not_allowed')\n    }\n    let authorization: SessionAuthorization\n    try {\n      authorization = this.authorize(request)\n    } catch (error) {\n      const mapped = mapError(error)\n      const acceptsHtml = request.headers.accept?.split(',').some(value => value.trim().split(';', 1)[0] === 'text/html') ?? false\n      const topLevel = request.method === 'GET'\n        && acceptsHtml\n        && (request.headers['sec-fetch-dest'] === undefined || request.headers['sec-fetch-dest'] === 'document')\n        && target.decodedPathname !== '/api'\n        && !target.decodedPathname.startsWith('/api/')\n      if (mapped.status === 401 && topLevel) {\n        const returnPath = target.raw.length <= 2048 ? target.raw : '/'\n        setSecurityHeaders(response, this.tlsEnabled)\n        response.writeHead(302, {\n          Location: `${AUTH_PREFIX}/login?return=${encodeURIComponent(returnPath)}`,\n          'Content-Length': 0,\n        })\n        response.end()\n        return\n      }\n      throw error\n    }\n    if (isMutation) this.requireCsrf(request, authorization)\n    if (clientModules) {\n      if (target.search !== '') throw new HttpError(400, 'bad_request')\n      if (request.method !== 'GET' && request.method !== 'POST') throw new HttpError(405, 'method_not_allowed')\n      const operation = this.allocateRequest(authorization, response, {})\n      const onClose = (): void => { operation.abort(); operation.release() }\n      response.once('close', onClose)\n      try {\n        let kind: 'describe' | 'configure' | 'reset' = 'describe'\n        let excluded: unknown\n        if (request.method === 'POST') {\n          const body = await readJsonObject(request, this.config.maxBodyBytes)\n          const keys = Object.keys(body)\n          if (keys.length !== 1) throw new HttpError(400, 'bad_request')\n          if (keys[0] === 'reset' && body.reset === true) kind = 'reset'\n          else if (keys[0] === 'excludedClientModules') { kind = 'configure'; excluded = body.excludedClientModules }\n          else throw new HttpError(400, 'bad_request')\n        }\n        const view = await this.clientModulePreferenceOperation(kind, excluded, authorization.deviceId, operation.signal)\n        operation.signal.throwIfAborted()\n        sendJson(response, 200, view, this.tlsEnabled)\n      } catch (error) {\n        if (operation.signal.aborted) return\n        if (error instanceof ClientModuleConflictError) sendJson(response, 409, { error: error.code, detail: error.detail }, this.tlsEnabled)\n        else throw error\n      } finally {\n        response.removeListener('close', onClose)\n        operation.release()\n      }\n      return\n    }\n    const extension = requestedExtension\n    if (extension !== undefined) {\n      await this.handleExtensionRequest(extension, target, request, response, authorization)\n      return\n    }\n    if (requestedMobileBootBatch !== undefined) {\n      await this.serveMobileBootBatch(requestedMobileBootBatch, request, response, authorization)\n      return\n    }\n    if (customAsset !== undefined) {\n      const operation = this.allocateRequest(authorization, response, {})\n      try {\n        let body: Buffer\n        let mtime: Date | undefined\n        try {\n          body = await readFile(customAsset.file, { signal: operation.signal })\n          try {\n            const fileStat = await stat(customAsset.file)\n            mtime = fileStat.mtime\n          } catch { /* keep undefined */ }\n        } catch (error) {\n          if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n          if (customAsset.fallback === undefined) throw new HttpError(503, 'mobile_frontend_unavailable')\n          body = Buffer.from(customAsset.fallback)\n        }\n        if (body.byteLength > 256 * 1024) throw new HttpError(413, 'payload_too_large')\n        const etag = `\"${createHash('sha256').update(body).digest('hex')}\"`\n        const responseHeaders: Record<string, string | number> = { ETag: etag }\n        if (mtime !== undefined) responseHeaders['Last-Modified'] = mtime.toUTCString()\n        if (matchesIfNoneMatch(headerValue(request.headers, 'if-none-match'), etag)) {\n          setSecurityHeaders(response, this.tlsEnabled)\n          response.writeHead(304, responseHeaders)\n          response.end()\n          return\n        }\n        setSecurityHeaders(response, this.tlsEnabled)\n        response.writeHead(200, {\n          ...responseHeaders,\n          'Content-Type': customAsset.contentType,\n          'Content-Length': body.byteLength,\n        })\n        if (request.method === 'HEAD') response.end(); else response.end(body)\n        return\n      } finally {\n        operation.release()\n      }\n    }\n    if (computerImages) {\n      const operation = this.allocateRequest(authorization, response, {})\n      try {\n        const query = new URL(target.raw, this.address().origin).searchParams\n        sendJson(response, 200, await listComputerImages(query.get('path'), operation.signal), this.tlsEnabled)\n        return\n      } finally {\n        operation.release()\n      }\n    }\n    if (computerImage) {\n      const operation = this.allocateRequest(authorization, response, {})\n      try {\n        const query = new URL(target.raw, this.address().origin).searchParams\n        const image = await readComputerImage(query.get('path'), operation.signal)\n        setSecurityHeaders(response, this.tlsEnabled)\n        response.writeHead(200, {\n          'Content-Type': image.contentType,\n          'Content-Length': image.body.byteLength,\n          'Content-Disposition': `inline; filename*=UTF-8''${encodeURIComponent(image.name)}`,\n        })\n        response.end(image.body)\n        return\n      } finally {\n        operation.release()\n      }\n    }\n    const stockFrontend = new URL(target.raw, this.address().origin).searchParams.get('frontend') === 'stock'\n    const acceptsHtml = request.headers.accept?.split(',').some(value => value.trim().split(';', 1)[0] === 'text/html') ?? false\n    // DSH's frontend-static owner renders its boot document only at these\n    // entry points. An HTML Accept header also belongs to plugin previews,\n    // iframe documents and downloads; those must retain their own route.\n    const frontendDocument = target.decodedPathname === '/' || target.decodedPathname === '/index.html'\n    if (request.method === 'GET' && frontendDocument && acceptsHtml && !stockFrontend) {\n      await this.proxyMobileIndex(request, response, authorization)\n      return\n    }\n    if (stockFrontend && target.decodedPathname === '/') request.url = '/'\n    await this.proxyHttp(request, response, authorization)\n  }\n\n  private async handleExtensionRequest(\n    targetInfo: NonNullable<ReturnType<typeof extensionTarget>>,\n    target: ReturnType<typeof parseRequestTarget>,\n    request: IncomingMessage,\n    response: ServerResponse,\n    authorization: SessionAuthorization,\n  ): Promise<void> {\n    const extensions = this.extensions\n    if (extensions === undefined) throw new HttpError(404, 'not_found')\n    if (targetInfo.kind === 'events') {\n      if (request.method !== 'GET' || target.search !== '') throw new HttpError(request.method === 'GET' ? 400 : 405, request.method === 'GET' ? 'bad_request' : 'method_not_allowed')\n      this.openExtensionEventStream(request, response, authorization)\n      return\n    }\n    if (targetInfo.kind === 'manifest') {\n      if (request.method !== 'GET' && request.method !== 'HEAD') throw new HttpError(405, 'method_not_allowed')\n      const operation = this.allocateRequest(authorization, response, {})\n      try {\n        operation.signal.throwIfAborted()\n        const customRevision = async (file: string, fallback: string): Promise<string> => {\n          let source: Buffer\n          try {\n            source = await readFile(file, { signal: operation.signal })\n          } catch (error) {\n            if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n            source = Buffer.from(fallback)\n          }\n          if (source.byteLength > 256 * 1024) throw new HttpError(413, 'payload_too_large')\n          return createHash('sha256').update(source).digest('hex')\n        }\n        const [scriptRevision, styleRevision] = await Promise.all([\n          customRevision(this.config.customScriptFile, CUSTOM_SCRIPT_FALLBACK),\n          customRevision(this.config.customCssFile, CUSTOM_STYLE_FALLBACK),\n        ])\n        const body = Buffer.from(JSON.stringify({\n          protocol: 1,\n          extensions: extensions.manifest(),\n          legacy: { scriptRevision, styleRevision },\n        }))\n        // The ETag must cover extension content, not just the manifest body, so\n        // editing mobile.js/css alone invalidates the client's cached manifest.\n        const etag = `\"${createHash('sha256').update(body).update(extensions.contentDigest()).digest('hex')}\"`\n        if (matchesIfNoneMatch(headerValue(request.headers, 'if-none-match'), etag)) {\n          setSecurityHeaders(response, this.tlsEnabled); response.writeHead(304, { ETag: etag }); response.end(); return\n        }\n        setSecurityHeaders(response, this.tlsEnabled)\n        response.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': body.byteLength, ETag: etag })\n        if (request.method === 'HEAD') response.end(); else response.end(body)\n        return\n      } finally {\n        operation.release()\n      }\n    }\n    if (targetInfo.kind === 'script' || targetInfo.kind === 'style' || targetInfo.kind === 'asset') {\n      if (request.method !== 'GET' && request.method !== 'HEAD') throw new HttpError(405, 'method_not_allowed')\n      const generation = extensionGeneration(new URLSearchParams(target.search).get('generation') ?? undefined)\n      const operation = this.allocateRequest(authorization, response, {})\n      try {\n        const file = targetInfo.kind === 'script'\n          ? await extensions.readClientFile(targetInfo.id, 'script', operation.signal, generation)\n          : targetInfo.kind === 'style'\n            ? await extensions.readClientFile(targetInfo.id, 'style', operation.signal, generation)\n            : await extensions.readAsset(targetInfo.id, targetInfo.path ?? '', operation.signal, generation)\n        const etag = `\"${file.digest}\"`\n        if (matchesIfNoneMatch(headerValue(request.headers, 'if-none-match'), etag)) {\n          setSecurityHeaders(response, this.tlsEnabled); response.writeHead(304, { ETag: etag }); response.end(); return\n        }\n        const contentType = targetInfo.kind === 'script'\n          ? 'text/javascript; charset=utf-8'\n          : targetInfo.kind === 'style' ? 'text/css; charset=utf-8' : extensionContentType(targetInfo.path ?? '')\n        setSecurityHeaders(response, this.tlsEnabled)\n        response.writeHead(200, { 'Content-Type': contentType, 'Content-Length': file.body.byteLength, ETag: etag })\n        if (request.method === 'HEAD') response.end(); else response.end(file.body)\n        return\n      } finally {\n        operation.release()\n      }\n    }\n    if (targetInfo.kind === 'action') {\n      if (request.method !== 'POST') throw new HttpError(405, 'method_not_allowed')\n      const maximum = 1024 * 1024\n      assertBoundedContentLength(request, maximum)\n      const generation = extensionGeneration(headerValue(request.headers, EXTENSION_GENERATION_HEADER))\n      const operation = this.allocateRequest(authorization, response, {})\n      const abort = new AbortController()\n      // Release bookkeeping before signalling, so a closed response can never pin a slot.\n      response.once('close', () => { operation.release(); abort.abort() })\n      const generationSignal = extensions.signal(targetInfo.id, generation)\n      const onGenerationAbort = (): void => { abort.abort(); if (!response.destroyed) response.destroy() }\n      generationSignal?.addEventListener('abort', onGenerationAbort, { once: true })\n      try {\n        const body = await readJsonObject(request, maximum)\n        const result = await extensions.invoke(targetInfo.id, targetInfo.action, body, { signal: abort.signal, deviceId: authorization.deviceId }, generation)\n        if (isPreparedJson(result)) {\n          // Worker mode: the extension result already crossed as worker-generated,\n          // size-checked JSON bytes. The gateway never serializes extension data;\n          // framing (guards, trailing newline) mirrors sendJson exactly.\n          if (result.bytes.byteLength > 4 * 1024 * 1024) throw new MobileExtensionError('extension_result_too_large', 'extension result is too large', 500)\n          if (!response.headersSent && !response.destroyed) {\n            const body = Buffer.concat([result.bytes, Buffer.from('\\n')])\n            setSecurityHeaders(response, this.tlsEnabled)\n            response.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': body.byteLength })\n            response.end(body)\n          }\n        } else {\n          let serialized: Buffer\n          try { serialized = Buffer.from(JSON.stringify(result)) } catch { throw new MobileExtensionError('extension_failed', 'extension action failed', 500) }\n          if (serialized.byteLength > 4 * 1024 * 1024) throw new MobileExtensionError('extension_result_too_large', 'extension result is too large', 500)\n          sendJson(response, 200, result, this.tlsEnabled)\n        }\n      } finally {\n        generationSignal?.removeEventListener('abort', onGenerationAbort)\n        abort.abort(); operation.release()\n      }\n      return\n    }\n    if (targetInfo.kind === 'route') {\n      const method = request.method ?? 'GET'\n      if (!['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(method)) throw new HttpError(405, 'method_not_allowed')\n      const hasBody = method !== 'GET' && method !== 'HEAD'\n      if (hasBody) assertBoundedContentLength(request, this.config.maxBodyBytes)\n      const generation = extensionGeneration(headerValue(request.headers, EXTENSION_GENERATION_HEADER))\n      const operation = this.allocateRequest(authorization, response, {})\n      const abort = new AbortController()\n      // Release bookkeeping before signalling, so a closed response can never pin a slot.\n      response.once('close', () => { operation.release(); abort.abort() })\n      const generationSignal = extensions.signal(targetInfo.id, generation)\n      const onGenerationAbort = (): void => { abort.abort(); if (!response.destroyed) response.destroy() }\n      generationSignal?.addEventListener('abort', onGenerationAbort, { once: true })\n      try {\n        const body = hasBody ? await readBoundedBody(request, this.config.maxBodyBytes) : Buffer.alloc(0)\n        const parsed = new URL(target.raw, this.address().origin)\n        const routeRequest: MobileRouteRequest = {\n          method, pathname: targetInfo.path, query: parsed.searchParams,\n          headers: extensionRequestHeaders(request.headers), body, signal: abort.signal, deviceId: authorization.deviceId,\n        }\n        const result = await extensions.route(targetInfo.id, method, targetInfo.path, routeRequest, generation)\n        await this.sendExtensionResponse(response, result, request.method === 'HEAD')\n      } finally {\n        generationSignal?.removeEventListener('abort', onGenerationAbort)\n        abort.abort(); operation.release()\n      }\n    }\n  }\n\n  private async sendExtensionResponse(response: ServerResponse, result: MobileRouteResponse, head: boolean): Promise<void> {\n    try {\n      const status = result.status ?? 200\n      if (!Number.isSafeInteger(status) || status < 200 || status > 599) {\n        throw new MobileExtensionError('invalid_route_response', 'extension returned an invalid HTTP status', 500)\n      }\n      const contentType = result.contentType ?? 'application/octet-stream'\n      if (contentType.length > 1024\n        || !/^[\\x20-\\x7e]+$/u.test(contentType)\n        || !/^[\\w!#$&+.^-]+\\/[\\w!#$&+.^-]+(?:;[\\x20-\\x7e]*)?$/u.test(contentType)) {\n        throw new MobileExtensionError('invalid_route_response', 'extension returned an invalid content type', 500)\n      }\n      const safeHeaders: Record<string, string> = {}\n      for (const [name, value] of Object.entries(result.headers ?? {})) {\n        if (!/^(?:content-disposition|cache-control|etag)$/iu.test(name) || /[\\r\\n]/u.test(value)) continue\n        safeHeaders[name] = value\n      }\n      setSecurityHeaders(response, this.tlsEnabled)\n      if (typeof result.body === 'string' || result.body instanceof Uint8Array) {\n        const body = typeof result.body === 'string' ? Buffer.from(result.body) : Buffer.from(result.body)\n        if (body.byteLength > 4 * 1024 * 1024) throw new MobileExtensionError('extension_result_too_large', 'extension response is too large', 500)\n        response.writeHead(status, { ...safeHeaders, 'Content-Type': contentType, 'Content-Length': body.byteLength })\n        if (head) response.end(); else response.end(body)\n        return\n      }\n      response.writeHead(status, { ...safeHeaders, 'Content-Type': contentType })\n      if (head) { result.body.destroy(); response.end(); return }\n    } catch (error) {\n      disposeLateExtensionResponse(result)\n      throw error\n    }\n    await pipeline(result.body, new ByteLimitTransform(4 * 1024 * 1024), response)\n  }\n\n  /** Exchange DSH's process-local launch token for an authority-bound cookie kept inside this gateway. */\n  private async upstreamCookieHeader(): Promise<string | undefined> {\n    if (this.upstreamAuthenticatedUrl === undefined) return undefined\n    if (this.upstreamCookie !== undefined\n      && this.upstreamCookieExpiresAt > Date.now() + UPSTREAM_AUTH_REFRESH_MARGIN_MS) {\n      return this.upstreamCookie\n    }\n    if (this.upstreamCookieTask !== undefined) return this.upstreamCookieTask\n    const task = this.exchangeUpstreamCookie()\n    this.upstreamCookieTask = task\n    try {\n      return await task\n    } finally {\n      if (this.upstreamCookieTask === task) this.upstreamCookieTask = undefined\n    }\n  }\n\n  private async exchangeUpstreamCookie(): Promise<string> {\n    const authenticatedUrl = this.upstreamAuthenticatedUrl\n    if (authenticatedUrl === undefined) throw new HttpError(502, 'upstream_unavailable')\n    let target: URL\n    try {\n      target = new URL(authenticatedUrl)\n    } catch {\n      throw new HttpError(502, 'upstream_unavailable')\n    }\n    if (target.origin !== this.config.upstreamOrigin.origin || target.pathname !== '/'\n      || target.hash !== '' || target.search === '') {\n      throw new HttpError(502, 'upstream_unavailable')\n    }\n    try {\n      const proxied = await new Promise<IncomingMessage>((resolve, reject) => {\n        const upstreamRequest = requestHttp({\n          protocol: 'http:',\n          hostname: stripIpv6Brackets(this.config.upstreamOrigin.hostname),\n          port: Number(this.config.upstreamOrigin.port),\n          method: 'GET',\n          path: `${target.pathname}${target.search}`,\n          headers: {\n            host: this.config.upstreamOrigin.host,\n            accept: 'text/html',\n            'accept-encoding': 'identity',\n          },\n          agent: false,\n        })\n        this.upstreamAuthRequest = upstreamRequest\n        upstreamRequest.setTimeout(this.config.upstreamTimeoutMs, () => {\n          upstreamRequest.destroy(new HttpError(504, 'upstream_timeout'))\n        })\n        upstreamRequest.once('response', resolve)\n        upstreamRequest.once('error', reject)\n        upstreamRequest.end()\n      })\n      await new Promise<void>((resolve, reject) => {\n        proxied.once('end', resolve)\n        proxied.once('error', reject)\n        proxied.resume()\n      })\n      const setCookie = proxied.headers['set-cookie']?.[0]\n      const pair = setCookie?.split(';', 1)[0]\n      const maxAgeText = setCookie === undefined\n        ? undefined\n        : /(?:^|;\\s*)Max-Age=(\\d+)(?:;|$)/iu.exec(setCookie)?.[1]\n      const maxAgeSeconds = maxAgeText === undefined ? Number.NaN : Number(maxAgeText)\n      const expiresAt = Date.now() + maxAgeSeconds * 1000\n      if (proxied.statusCode !== 303 || pair === undefined || pair.length > 4096\n        || !UPSTREAM_COOKIE_PAIR.test(pair) || !Number.isSafeInteger(expiresAt)\n        || maxAgeSeconds <= 0) {\n        throw new HttpError(502, 'upstream_unavailable')\n      }\n      this.upstreamCookie = pair\n      this.upstreamCookieExpiresAt = expiresAt\n      return pair\n    } catch (error) {\n      if (error instanceof HttpError) throw error\n      throw new HttpError(502, 'upstream_unavailable')\n    } finally {\n      this.upstreamAuthRequest?.destroy()\n      this.upstreamAuthRequest = undefined\n    }\n  }\n\n  /** List installed modules and resolve the next-open selection.\n   * @param deviceId - Authenticated device identity; omitted for computer defaults.\n   * @param callerSignal - Cancels catalog fetching when the admin request closes.\n   * @returns The installed catalog and effective module selection.\n   */\n  describeClientModules(deviceId?: string, callerSignal?: AbortSignal): Promise<ClientModulePreferenceView> {\n    return this.clientModulePreferenceOperation('describe', undefined, deviceId, callerSignal)\n  }\n\n  /** Persist a validated device override or computer default.\n   * @param excluded - Untrusted module IDs to validate against the current boot graph.\n   * @param deviceId - Authenticated device identity; omitted for computer defaults.\n   * @param callerSignal - Cancels fetching and validation, not an atomic write already started.\n   * @returns The catalog and saved selection without reloading clients.\n   */\n  configureClientModules(excluded: unknown, deviceId?: string, callerSignal?: AbortSignal): Promise<ClientModulePreferenceView> {\n    return this.clientModulePreferenceOperation('configure', excluded, deviceId, callerSignal)\n  }\n\n  /** Reset one override without reloading connected clients.\n   * @param deviceId - Authenticated device identity; omitted to reset computer defaults.\n   * @param callerSignal - Cancels fetching and validation, not an atomic write already started.\n   * @returns The catalog and inherited selection.\n   */\n  resetClientModules(deviceId?: string, callerSignal?: AbortSignal): Promise<ClientModulePreferenceView> {\n    return this.clientModulePreferenceOperation('reset', undefined, deviceId, callerSignal)\n  }\n\n  private async clientModulePreferenceOperation(\n    kind: 'describe' | 'configure' | 'reset', excluded: unknown, deviceId?: string, callerSignal?: AbortSignal,\n  ): Promise<ClientModulePreferenceView> {\n    if (this.closing || !this.started) throw new HttpError(503, 'unavailable')\n    const controller = new AbortController()\n    const abort = (): void => controller.abort()\n    if (callerSignal?.aborted === true) controller.abort()\n    callerSignal?.addEventListener('abort', abort, { once: true })\n    this.clientModuleOperations.add(controller)\n    const task = (async (): Promise<ClientModulePreferenceView> => {\n      let html = ''\n      const validate = async (selection: readonly string[]): Promise<void> => {\n        html = (await this.fetchAuthenticatedUpstreamIndex(controller.signal)).html\n        try { parseMobileBootPlan(html, selection) } catch (error) {\n          if (error instanceof ExcludedClientModulesError) throw new ClientModuleConflictError(error.message)\n          throw new HttpError(502, 'upstream_unavailable')\n        }\n        controller.signal.throwIfAborted()\n      }\n      let selection\n      if (kind === 'configure') {\n        let ids: readonly string[]\n        try { ids = parseExcludedClientModules(excluded) } catch { throw new HttpError(400, 'excluded_client_modules_invalid') }\n        selection = await this.clientModulePreferences.configure(ids, deviceId, validate)\n      } else if (kind === 'reset') selection = await this.clientModulePreferences.reset(deviceId, validate)\n      else {\n        html = (await this.fetchAuthenticatedUpstreamIndex(controller.signal)).html\n        selection = await this.clientModulePreferences.read(deviceId)\n      }\n      controller.signal.throwIfAborted()\n      try {\n        const plan = parseMobileBootPlan(html)\n        return Object.freeze({\n          entries: describeMobileClientModules(html),\n          ...selection,\n          ...(plan.batches === undefined ? { excludedClientModules: Object.freeze([]), defaultExcludedClientModules: Object.freeze([]) } : {}),\n          reloadRequired: true,\n        })\n      } catch (error) {\n        if (error instanceof HttpError) throw error\n        throw new HttpError(502, 'upstream_unavailable')\n      }\n    })()\n    this.clientModuleTasks.add(task)\n    try { return await task } finally {\n      callerSignal?.removeEventListener('abort', abort)\n      this.clientModuleOperations.delete(controller)\n      this.clientModuleTasks.delete(task)\n    }\n  }\n\n  private async fetchAuthenticatedUpstreamIndex(\n    signal: AbortSignal, incoming?: IncomingMessage,\n  ): Promise<{ readonly html: string; readonly headers: IncomingHttpHeaders }> {\n    signal.throwIfAborted()\n    let upstreamRequest: ClientRequest | undefined\n    const abort = (): void => { upstreamRequest?.destroy(requestAbortedError()) }\n    signal.addEventListener('abort', abort, { once: true })\n    try {\n      const headers = incoming === undefined\n        ? { host: this.config.upstreamOrigin.host, accept: 'text/html', 'accept-encoding': 'identity' }\n        : sanitizeRequestHeaders(incoming, this.config.upstreamOrigin)\n      const upstreamCookie = await waitForRequestTask(this.upstreamCookieHeader(), signal)\n      signal.throwIfAborted()\n      if (upstreamCookie !== undefined) headers.cookie = upstreamCookie\n      headers['accept-encoding'] = 'identity'\n      const proxied = await new Promise<IncomingMessage>((resolve, reject) => {\n        upstreamRequest = requestHttp({\n          protocol: 'http:', hostname: stripIpv6Brackets(this.config.upstreamOrigin.hostname),\n          port: Number(this.config.upstreamOrigin.port), method: 'GET', path: incoming?.url ?? '/', headers, agent: false,\n        })\n        upstreamRequest.setTimeout(this.config.upstreamTimeoutMs, () => { upstreamRequest?.destroy(new HttpError(504, 'upstream_timeout')) })\n        upstreamRequest.once('response', resolve)\n        upstreamRequest.once('error', reject)\n        upstreamRequest.end()\n      })\n      if (proxied.statusCode !== 200) throw new HttpError(502, 'upstream_unavailable')\n      const chunks: Buffer[] = []\n      let bytes = 0\n      for await (const chunk of proxied) {\n        const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n        bytes += buffer.byteLength\n        if (bytes > 4 * 1024 * 1024) throw new HttpError(502, 'upstream_unavailable')\n        chunks.push(buffer)\n      }\n      signal.throwIfAborted()\n      return { html: Buffer.concat(chunks).toString('utf8'), headers: proxied.headers }\n    } catch (error) {\n      if (signal.aborted || error instanceof HttpError) throw error\n      throw new HttpError(502, 'upstream_unavailable')\n    } finally {\n      signal.removeEventListener('abort', abort)\n      upstreamRequest?.destroy()\n    }\n  }\n\n  private async proxyMobileIndex(\n    request: IncomingMessage,\n    response: ServerResponse,\n    authorization: SessionAuthorization,\n  ): Promise<void> {\n    const holder: { request?: ClientRequest } = {}\n    const operation = this.allocateRequest(authorization, response, holder)\n    const onClose = (): void => { operation.abort(); operation.release() }\n    response.once('close', onClose)\n    try {\n      const index = await this.fetchAuthenticatedUpstreamIndex(operation.signal, request)\n      const preference = await this.clientModulePreferences.read(authorization.deviceId)\n      const excludedClientModules = preference.excludedClientModules\n      let body: Buffer\n      try {\n        const html = index.html\n        const plan = parseMobileBootPlan(html, excludedClientModules)\n        const options = plan.rewrittenBatchEntries === undefined\n          ? { excludedClientModules }\n          : { ...await this.resolveMobileBootSizes(plan.rewrittenBatchEntries.flatMap(batch => batch.entries), operation.signal), excludedClientModules }\n        const cookies = browserAuthCookies(request.headers.cookie)\n        const csrfCookie = this.tlsEnabled && cookies.has(HOST_SESSION_COOKIE) ? HOST_CSRF_COOKIE : CSRF_COOKIE\n        const rewritten = rewriteMobileIndexWithBatch(html, { ...options, csrfCookie })\n        for (const batch of rewritten.batches) this.rememberMobileBootBatch(batch)\n        body = Buffer.from(rewritten.html)\n      } catch (error) {\n        if (error instanceof ExcludedClientModulesError) {\n          const detail = error.message.replace(/[\\r\\n]/gu, ' ').slice(0, 512)\n          if (detail !== this.lastModuleExclusionError) {\n            this.lastModuleExclusionError = detail\n            process.emitWarning(detail, { code: 'DSH_MOBILE_MODULE_EXCLUSION_INVALID' })\n          }\n          if (preference.source === 'device' || preference.source === 'computer') {\n            operation.signal.throwIfAborted()\n            const locale = resolveAuthPageLocale(headerValue(request.headers, 'accept-language'))\n            const recovery = Buffer.from(renderClientModuleRecoveryPage(locale))\n            // A valid owned document uses 200 so Android does not replace its recovery action with a generic HTTP-error dialog.\n            setSecurityHeaders(response, this.tlsEnabled)\n            response.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Content-Length': recovery.byteLength })\n            response.end(recovery)\n            return\n          }\n          sendJson(response, 409, { error: 'excluded_client_modules_invalid', detail }, this.tlsEnabled)\n          return\n        }\n        throw new HttpError(502, 'upstream_unavailable')\n      }\n      operation.signal.throwIfAborted()\n      const headers = sanitizeResponseHeaders(index.headers, this.config.upstreamOrigin)\n      delete headers['content-length']\n      delete headers['content-encoding']\n      delete headers.etag\n      // The proxied GUI document: it must be able to frame its own surfaces.\n      setSecurityHeaders(response, this.tlsEnabled, 'proxied')\n      response.writeHead(200, {\n        ...headers,\n        'Content-Type': 'text/html; charset=utf-8',\n        'Content-Length': body.byteLength,\n      })\n      response.end(body)\n    } catch (error) {\n      holder.request?.destroy()\n      if (error instanceof HttpError) throw error\n      if (response.headersSent) response.destroy()\n      else throw new HttpError(502, 'upstream_unavailable')\n    } finally {\n      response.removeListener('close', onClose)\n      operation.release()\n    }\n  }\n\n  private rememberMobileBootBatch(plan: MobileBootBatchPlan): void {\n    const existing = this.mobileBootBatches.get(plan.key)\n    this.mobileBootBatches.delete(plan.key)\n    this.mobileBootBatches.set(plan.key, existing ?? { plan })\n    while (this.mobileBootBatches.size > MAX_MOBILE_BOOT_BATCHES) {\n      const oldest = this.mobileBootBatches.keys().next().value as string | undefined\n      if (oldest === undefined) break\n      this.mobileBootBatches.get(oldest)?.assembly?.controller.abort()\n      this.mobileBootBatches.delete(oldest)\n    }\n  }\n\n  /**\n   * Determine which layout-batch entries can share a merged boot batch and which\n   * must pass through. An entry at or above the per-entry cap, or one whose size\n   * could not be probed, keeps its own upstream `/plugins` row: a merged batch\n   * cannot carry it, and an unknown bundle must not risk the whole batch.\n   */\n  private async resolveMobileBootSizes(\n    planEntries: readonly MobileBootBatchEntry[],\n    signal?: AbortSignal,\n  ): Promise<{ sizes: Map<string, number>; passThrough: Set<string> }> {\n    const sizes = new Map<string, number>()\n    const passThrough = new Set<string>()\n    const candidates = planEntries.filter(entry => entry.id !== MOBILE_LAYOUT_MODULE\n      && upstreamPluginBundleUrl(entry.url, this.config.upstreamOrigin) !== undefined)\n    let cursor = 0\n    const worker = async (): Promise<void> => {\n      while (cursor < candidates.length) {\n        signal?.throwIfAborted()\n        const index = cursor++\n        const source = candidates[index]!.url\n        const size = await this.upstreamBundleSize(source, signal)\n        if (size === undefined || size >= MAX_MOBILE_BOOT_ENTRY_BYTES) passThrough.add(source)\n        else sizes.set(source, size)\n      }\n    }\n    await Promise.all(Array.from({ length: Math.min(8, candidates.length) }, worker))\n    return { sizes, passThrough }\n  }\n\n  /**\n   * Measure one upstream bundle by reading its body. The upstream serves\n   * `/plugins` bundles as chunked streams without a Content-Length, so a probe\n   * counts bytes; it aborts instantly past the per-entry cap. Measurements are\n   * cached for a short window.\n   */\n  private async upstreamBundleSize(source: string, signal?: AbortSignal): Promise<number | undefined> {\n    signal?.throwIfAborted()\n    const target = upstreamPluginBundleUrl(source, this.config.upstreamOrigin)\n    if (target === undefined) return undefined\n    const cached = this.bootEntrySizeCache.get(source)\n    if (cached !== undefined && Date.now() - cached.at < MOBILE_BOOT_SIZE_CACHE_TTL_MS) return cached.size\n    let upstreamRequest: ClientRequest | undefined\n    const abort = (): void => { upstreamRequest?.destroy(requestAbortedError()) }\n    signal?.addEventListener('abort', abort, { once: true })\n    try {\n      const upstreamCookie = signal === undefined\n        ? await this.upstreamCookieHeader()\n        : await waitForRequestTask(this.upstreamCookieHeader(), signal)\n      signal?.throwIfAborted()\n      const proxied = await new Promise<IncomingMessage>((resolve, reject) => {\n        upstreamRequest = requestHttp({\n          protocol: 'http:',\n          hostname: stripIpv6Brackets(this.config.upstreamOrigin.hostname),\n          port: Number(this.config.upstreamOrigin.port),\n          method: 'GET',\n          path: `${target.pathname}${target.search}`,\n          headers: {\n            host: this.config.upstreamOrigin.host,\n            accept: 'text/javascript',\n            'accept-encoding': 'identity',\n            [MOBILE_BOOT_SIZE_PROBE_HEADER]: '1',\n            ...(upstreamCookie === undefined ? {} : { cookie: upstreamCookie }),\n          },\n          agent: false,\n        })\n        upstreamRequest.setTimeout(this.config.upstreamTimeoutMs, () => {\n          upstreamRequest?.destroy(upstreamTimeoutError())\n        })\n        upstreamRequest.once('response', resolve)\n        upstreamRequest.once('error', reject)\n        upstreamRequest.end()\n      })\n      if (proxied.statusCode !== 200) {\n        proxied.resume()\n        return undefined\n      }\n      const size = await new Promise<number | undefined>((resolve, reject) => {\n        let bytes = 0\n        proxied.on('data', (chunk: Buffer) => {\n          bytes += chunk.length\n          if (bytes > MAX_MOBILE_BOOT_ENTRY_BYTES) {\n            proxied.destroy()\n            resolve(undefined)\n          }\n        })\n        proxied.once('end', () => resolve(bytes))\n        proxied.once('error', reject)\n      })\n      if (size === undefined) return undefined\n      this.bootEntrySizeCache.set(source, { size, at: Date.now() })\n      return size\n    } catch (error) {\n      if (signal?.aborted === true) throw error\n      return undefined\n    } finally {\n      signal?.removeEventListener('abort', abort)\n      upstreamRequest?.destroy()\n    }\n  }\n\n  private async serveMobileBootBatch(\n    key: string,\n    request: IncomingMessage,\n    response: ServerResponse,\n    authorization: SessionAuthorization,\n  ): Promise<void> {\n    if (request.method !== 'GET' && request.method !== 'HEAD') throw new HttpError(405, 'method_not_allowed')\n    const stored = this.mobileBootBatches.get(key)\n    if (stored === undefined) throw new HttpError(404, 'not_found')\n    const operation = this.allocateRequest(authorization, response, {})\n    response.once('close', operation.abort)\n    try {\n      const layoutStat = await stat(this.config.mobileLayoutFile)\n      if (stored.body === undefined || stored.etag === undefined || stored.layoutMtimeMs !== layoutStat.mtimeMs) {\n        operation.signal.throwIfAborted()\n        const assembly = stored.assembly ?? this.startMobileBootBatchAssembly(stored, layoutStat.mtimeMs)\n        await waitForRequestTask(assembly.task, operation.signal)\n      }\n      const compressed = acceptsGzip(request.headers['accept-encoding'])\n      // The assembly above assigns stored.body; TypeScript cannot narrow a\n      // property written inside an awaited closure, so read it once here.\n      const assembled = stored.body\n      if (assembled === undefined) throw new HttpError(502, 'upstream_unavailable')\n      const body = compressed\n        ? stored.gzipBody ??= await gzipBuffer(assembled)\n        : assembled\n      const etag = `\"${compressed ? `${stored.etag}-gzip` : stored.etag}\"`\n      const headers: OutgoingHttpHeaders = {\n        'Content-Type': 'text/javascript; charset=utf-8',\n        'Content-Length': body.byteLength,\n        'Cache-Control': 'private, no-cache',\n        ETag: etag,\n      }\n      if (compressed) headers['Content-Encoding'] = 'gzip'\n      addVaryAcceptEncoding(headers)\n      if (matchesIfNoneMatch(headerValue(request.headers, 'if-none-match'), etag)) {\n        setSecurityHeaders(response, this.tlsEnabled)\n        response.writeHead(304, { ETag: etag, 'Cache-Control': 'private, no-cache', Vary: String(headers.vary) })\n        response.end()\n        return\n      }\n      setSecurityHeaders(response, this.tlsEnabled)\n      response.writeHead(200, headers)\n      if (request.method === 'HEAD') response.end()\n      else response.end(body)\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code === 'ENOENT') throw new HttpError(503, 'mobile_frontend_unavailable')\n      throw error\n    } finally {\n      response.removeListener('close', operation.abort)\n      operation.release()\n    }\n  }\n\n  private startMobileBootBatchAssembly(stored: StoredMobileBootBatch, layoutMtimeMs: number): MobileBootBatchAssembly {\n    const controller = new AbortController()\n    const task = (async (): Promise<Buffer> => {\n      const body = await this.assembleMobileBootBatch(stored.plan, controller.signal)\n      stored.body = body\n      delete stored.gzipBody\n      stored.etag = createHash('sha256').update(body).digest('hex')\n      stored.layoutMtimeMs = layoutMtimeMs\n      return body\n    })()\n    const assembly = Object.freeze({ controller, task })\n    stored.assembly = assembly\n    void task.then(\n      () => { if (stored.assembly === assembly) delete stored.assembly },\n      () => { if (stored.assembly === assembly) delete stored.assembly },\n    )\n    return assembly\n  }\n\n  private async assembleMobileBootBatch(plan: MobileBootBatchPlan, signal: AbortSignal): Promise<Buffer> {\n    const bodies = new Array<Buffer>(plan.entries.length)\n    let cursor = 0\n    const worker = async (): Promise<void> => {\n      while (cursor < plan.entries.length) {\n        const index = cursor++\n        const entry = plan.entries[index]!\n        bodies[index] = entry.id === MOBILE_LAYOUT_MODULE\n          ? await readFile(this.config.mobileLayoutFile, { signal })\n          : await this.readUpstreamClientBundleWithRetry(entry.url, signal)\n        if (bodies[index]!.byteLength > MAX_MOBILE_BOOT_ENTRY_BYTES) throw new HttpError(502, 'upstream_unavailable')\n      }\n    }\n    // Three workers keep the fan-out gentle: the upstream resets a fraction of\n    // connections when this many entries are pulled at once, and every reset\n    // used to fail the whole batch.\n    await Promise.all(Array.from({ length: Math.min(3, plan.entries.length) }, worker))\n    const total = bodies.reduce((bytes, body) => bytes + body.byteLength + MOBILE_BOOT_SEPARATOR_BYTES, 0)\n    if (total > MAX_MOBILE_BOOT_BATCH_BYTES) throw new HttpError(502, 'upstream_unavailable')\n    return Buffer.concat(bodies.flatMap(body => [body, Buffer.from('\\n;\\n')]))\n  }\n\n  /**\n   * Read one upstream bundle, retrying transient connection failures.\n   *\n   * Assembling a batch fans out over every client entry, and the upstream\n   * resets a fraction of those connections before sending a byte\n   * (`read ECONNRESET`, recv=0) — randomly, on any entry, at any concurrency.\n   * A single such reset used to fail the whole batch with 502\n   * `upstream_unavailable`, surfacing in the browser as \"bundle script\n   * /mobile-access/mobile-boot/<hash>.js failed to load\". Retrying recovers\n   * every observed reset; a genuine upstream error still fails.\n   */\n  private async readUpstreamClientBundleWithRetry(source: string, signal: AbortSignal): Promise<Buffer> {\n    for (let attempt = 1; attempt <= MOBILE_BOOT_UPSTREAM_ATTEMPTS; attempt++) {\n      signal.throwIfAborted()\n      try {\n        return await this.readUpstreamClientBundle(source, signal)\n      } catch (error) {\n        if (signal.aborted) throw error\n        if (!isTransientUpstreamError(error)) throw error\n        if (attempt === MOBILE_BOOT_UPSTREAM_ATTEMPTS) throw new HttpError(502, 'upstream_unavailable')\n        await waitForAbortableDelay(MOBILE_BOOT_RETRY_DELAY_MS * attempt, signal)\n      }\n    }\n    throw new HttpError(502, 'upstream_unavailable')\n  }\n\n  private async readUpstreamClientBundle(source: string, signal: AbortSignal): Promise<Buffer> {\n    signal.throwIfAborted()\n    const target = upstreamPluginBundleUrl(source, this.config.upstreamOrigin)\n    if (target === undefined) throw new HttpError(502, 'upstream_unavailable')\n    let upstreamRequest: ClientRequest | undefined\n    const aborted = (): void => { upstreamRequest?.destroy(new Error('request aborted')) }\n    signal.addEventListener('abort', aborted, { once: true })\n    try {\n      const upstreamCookie = await this.upstreamCookieHeader()\n      signal.throwIfAborted()\n      const proxied = await new Promise<IncomingMessage>((resolve, reject) => {\n        upstreamRequest = requestHttp({\n          protocol: 'http:',\n          hostname: stripIpv6Brackets(this.config.upstreamOrigin.hostname),\n          port: Number(this.config.upstreamOrigin.port),\n          method: 'GET',\n          path: `${target.pathname}${target.search}`,\n          headers: {\n            host: this.config.upstreamOrigin.host,\n            accept: 'text/javascript',\n            'accept-encoding': 'identity',\n            ...(upstreamCookie === undefined ? {} : { cookie: upstreamCookie }),\n          },\n          agent: false,\n        })\n        upstreamRequest.setTimeout(this.config.upstreamTimeoutMs, () => {\n          upstreamRequest?.destroy(upstreamTimeoutError())\n        })\n        upstreamRequest.once('response', resolve)\n        upstreamRequest.once('error', reject)\n        upstreamRequest.end()\n      })\n      if ((proxied.statusCode ?? 502) !== 200) throw new HttpError(502, 'upstream_unavailable')\n      const chunks: Buffer[] = []\n      let bytes = 0\n      for await (const chunk of proxied) {\n        const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)\n        bytes += buffer.byteLength\n        if (bytes > MAX_MOBILE_BOOT_ENTRY_BYTES) throw new HttpError(502, 'upstream_unavailable')\n        chunks.push(buffer)\n      }\n      return Buffer.concat(chunks)\n    } catch (error) {\n      if (error instanceof HttpError) throw error\n      if (signal.aborted || isTransientUpstreamError(error)) throw error\n      throw new HttpError(502, 'upstream_unavailable')\n    } finally {\n      signal.removeEventListener('abort', aborted)\n      upstreamRequest?.destroy()\n    }\n  }\n\n  private allocateRequest(\n    authorization: SessionAuthorization,\n    response: ServerResponse,\n    upstream: { request?: ClientRequest },\n  ): { id: number; signal: AbortSignal; abort: () => void; release: () => void } {\n    if (this.closing || response.destroyed || response.writableEnded) throw requestAbortedError()\n    if (this.activeRequests.size >= this.config.maxActiveRequests) throw new HttpError(429, 'busy')\n    const id = this.nextOperationId++\n    const controller = new AbortController()\n    const abort = (): void => {\n      controller.abort()\n      upstream.request?.destroy()\n      if (!response.destroyed) response.destroy()\n    }\n    const timer = setTimeout(abort, Math.max(1, authorization.expiresAt - Date.now()))\n    timer.unref()\n    this.activeRequests.set(id, Object.freeze({ ...authorization, abort, timer }))\n    return {\n      id,\n      signal: controller.signal,\n      abort,\n      release: () => {\n        const entry = this.activeRequests.get(id)\n        if (entry !== undefined) clearTimeout(entry.timer)\n        this.activeRequests.delete(id)\n      },\n    }\n  }\n\n  /**\n   * Proxy one request, retrying transient failures for plugin and asset GETs.\n   * Only bodyless GETs can be replayed, before response headers reach the client.\n   * One request slot and cancellation signal cover attempts and backoff together.\n   * API requests and requests with bodies are forwarded once.\n   */\n  private async proxyHttp(\n    request: IncomingMessage,\n    response: ServerResponse,\n    authorization: SessionAuthorization,\n  ): Promise<void> {\n    const declared = request.headers['content-length']\n    if (declared !== undefined && (!/^\\d+$/u.test(declared) || Number(declared) > this.config.maxBodyBytes)) {\n      throw new HttpError(413, 'payload_too_large')\n    }\n    const replayable = request.method === 'GET'\n      && request.headers['transfer-encoding'] === undefined\n      && (declared === undefined || Number(declared) === 0)\n      && (request.url?.split('?', 1)[0]?.startsWith('/plugins/') === true\n        || request.url?.split('?', 1)[0]?.startsWith('/assets/') === true)\n    const holder: { request?: ClientRequest } = {}\n    const operation = this.allocateRequest(authorization, response, holder)\n    const onClose = (): void => { operation.release(); operation.abort() }\n    response.once('close', onClose)\n    // The HTTP parser accepts no payload without Content-Length or Transfer-Encoding.\n    // Draining a bodyless GET once keeps its IncomingMessage out of retry pipelines.\n    if (replayable) request.resume()\n    try {\n      const attempts = replayable ? MOBILE_BOOT_UPSTREAM_ATTEMPTS : 1\n      for (let attempt = 1; attempt <= attempts; attempt++) {\n        operation.signal.throwIfAborted()\n        try {\n          await this.proxyHttpOnce(request, response, holder, operation.signal, replayable)\n          return\n        } catch (error) {\n          if (operation.signal.aborted || response.destroyed) return\n          if (response.headersSent) {\n            response.destroy()\n            return\n          }\n          if (error instanceof HttpError || !isTransientUpstreamError(error)) {\n            throw error instanceof HttpError ? error : new HttpError(502, 'upstream_unavailable')\n          }\n          if (attempt === attempts) throw new HttpError(502, 'upstream_unavailable')\n          await waitForAbortableDelay(MOBILE_BOOT_RETRY_DELAY_MS * attempt, operation.signal)\n        }\n      }\n    } catch (error) {\n      if (!operation.signal.aborted) throw error\n    } finally {\n      response.removeListener('close', onClose)\n      operation.release()\n    }\n  }\n\n  private async proxyHttpOnce(\n    request: IncomingMessage,\n    response: ServerResponse,\n    holder: { request?: ClientRequest },\n    signal: AbortSignal,\n    replayable: boolean,\n  ): Promise<void> {\n    let bodyDone: Promise<void> | undefined\n    try {\n      const upstreamHeaders = sanitizeRequestHeaders(request, this.config.upstreamOrigin)\n      // IncomingMessage removes chunk framing; GET does not opt into Node's\n      // default outgoing chunk framing, so rebuild it when forwarding its body.\n      if (request.headers['transfer-encoding'] !== undefined) {\n        upstreamHeaders['transfer-encoding'] = request.headers['transfer-encoding']\n      }\n      const upstreamCookie = await this.upstreamCookieHeader()\n      signal.throwIfAborted()\n      if (upstreamCookie !== undefined) upstreamHeaders.cookie = upstreamCookie\n      const upstreamResponse = new Promise<IncomingMessage>((resolve, reject) => {\n        const upstreamRequest = requestHttp({\n          protocol: 'http:',\n          hostname: stripIpv6Brackets(this.config.upstreamOrigin.hostname),\n          port: Number(this.config.upstreamOrigin.port),\n          method: request.method,\n          path: request.url,\n          headers: upstreamHeaders,\n          agent: false,\n        })\n        holder.request = upstreamRequest\n        upstreamRequest.setTimeout(this.config.upstreamTimeoutMs, () => {\n          upstreamRequest.destroy(new HttpError(504, 'upstream_timeout'))\n        })\n        const pathname = parseRequestTarget(request.url).decodedPathname\n        if (pathname === '/api' || pathname.startsWith('/api/')) {\n          // Uploads keep the transport budget; authenticated API response waits\n          // use their separate idle budget only once the body has been sent.\n          upstreamRequest.once('finish', () => { upstreamRequest.setTimeout(this.config.upstreamApiTimeoutMs) })\n        }\n        upstreamRequest.once('response', resolve)\n        upstreamRequest.once('error', reject)\n        if (replayable) upstreamRequest.end()\n        else {\n          bodyDone = pipeline(request, new ByteLimitTransform(this.config.maxBodyBytes), upstreamRequest)\n          void bodyDone.catch(reject)\n        }\n      })\n      const proxied = await upstreamResponse\n      // Proxied upstream routes (static assets, the GUI's own /sidebar routes,\n      // the API): the GUI frames some of its own routes (HTML/diff previews),\n      // so they follow the proxied framing policy.\n      setSecurityHeaders(response, this.tlsEnabled, 'proxied')\n      const headers = sanitizeResponseHeaders(proxied.headers, this.config.upstreamOrigin)\n      const statusCode = proxied.statusCode ?? 502\n      const cacheControl = revisionedStaticCacheControl(request, statusCode)\n      if (cacheControl !== undefined) headers['cache-control'] = cacheControl\n      const compressible = canCompressResponse(request, proxied)\n      const compressed = compressible && acceptsGzip(request.headers['accept-encoding'])\n      if (compressible) addVaryAcceptEncoding(headers)\n      if (compressed) {\n        delete headers['accept-ranges']\n        delete headers['content-length']\n        const etag = weakenEntityTag(proxied.headers.etag)\n        if (etag === undefined) delete headers.etag\n        else headers.etag = etag\n        headers['content-encoding'] = 'gzip'\n      } else if (statusCode === 304 && (request.method === 'GET' || request.method === 'HEAD')\n        && request.headers.range === undefined\n        && (request.url?.split('?', 1)[0]?.startsWith('/plugins/') === true\n          || request.url?.split('?', 1)[0]?.startsWith('/assets/') === true)) {\n        // A 304 has no body or media type to identify gateway gzip eligibility.\n        // Weakening remains valid for unchanged or already encoded upstream bytes.\n        if (proxied.headers['content-encoding'] === undefined && acceptsGzip(request.headers['accept-encoding'])) {\n          delete headers['content-length']\n          delete headers['accept-ranges']\n          const etag = weakenEntityTag(proxied.headers.etag)\n          if (etag === undefined) delete headers.etag\n          else headers.etag = etag\n        }\n        addVaryAcceptEncoding(headers)\n      }\n      response.writeHead(statusCode, headers)\n      await Promise.all([\n        bodyDone,\n        compressed && request.method !== 'HEAD' ? pipeline(proxied, createGzip(), response) : pipeline(proxied, response),\n      ])\n    } catch (error) {\n      holder.request?.destroy()\n      await bodyDone?.catch(() => undefined)\n      if (error instanceof HttpError) throw error\n      if (response.headersSent) response.destroy()\n      // Raw transient errors reach the proxyHttp retry window; anything else\n      // becomes the standard upstream-unavailable answer.\n      throw error\n    } finally {\n      delete holder.request\n    }\n  }\n\n  private abortSessionResources(sessionKey: string): void {\n    for (const request of this.activeRequests.values()) {\n      if (request.sessionKey === sessionKey) request.abort()\n    }\n    for (const socket of this.activeWebSockets.values()) {\n      if (socket.sessionKey === sessionKey) {\n        socket.client.destroy()\n        socket.upstream.destroy()\n      }\n    }\n  }\n\n  private broadcastExtensionChange(): void {\n    if (this.closing) return\n    this.extensionEventRevision += 1\n    for (const listener of this.extensionEventListeners) listener(this.extensionEventRevision)\n  }\n\n  /** Fan a completed task to every phone holding this gateway's event stream. */\n  broadcastTaskEvent(event: { readonly sessionId: string; readonly turn: number }): void {\n    if (this.closing) return\n    const payload = JSON.stringify({ sessionId: String(event.sessionId), turn: Number(event.turn) || 0 })\n    for (const listener of this.taskEventListeners) listener(payload)\n  }\n\n  /** Notify only the device whose persistent credential was revoked by the Host. */\n  private broadcastDeviceRevoked(deviceId: string): void {\n    const listeners = this.deviceEventListeners.get(deviceId)\n    if (listeners === undefined) return\n    const payload = JSON.stringify({ reason: 'device_revoked' })\n    for (const listener of [...listeners]) listener(payload)\n  }\n\n  private pollLegacyCustomChanges(): Promise<void> {\n    if (this.extensionChangeTask !== undefined) return this.extensionChangeTask\n    const digestFile = async (path: string, fallback: string): Promise<string> => {\n      try {\n        const info = await stat(path)\n        if (!info.isFile() || info.size > 256 * 1024) return `invalid:${String(info.size)}:${String(info.mtimeMs)}`\n        return createHash('sha256').update(await readFile(path)).digest('hex')\n      } catch (error) {\n        if ((error as NodeJS.ErrnoException).code === 'ENOENT') return createHash('sha256').update(fallback).digest('hex')\n        return `error:${String((error as NodeJS.ErrnoException).code ?? 'unknown')}`\n      }\n    }\n    const task = Promise.all([\n      digestFile(this.config.customScriptFile, CUSTOM_SCRIPT_FALLBACK),\n      digestFile(this.config.customCssFile, CUSTOM_STYLE_FALLBACK),\n    ]).then(parts => {\n      const next = createHash('sha256').update(parts.join('|')).digest('hex')\n      if (this.legacyCustomDigest !== '' && next !== this.legacyCustomDigest) this.broadcastExtensionChange()\n      this.legacyCustomDigest = next\n    }).finally(() => {\n      if (this.extensionChangeTask === task) this.extensionChangeTask = undefined\n    })\n    this.extensionChangeTask = task\n    return task\n  }\n\n  private openExtensionEventStream(\n    request: IncomingMessage,\n    response: ServerResponse,\n    authorization: SessionAuthorization,\n  ): void {\n    const operation = this.allocateRequest(authorization, response, {})\n    let closed = false\n    let heartbeat: NodeJS.Timeout | undefined\n    const close = (): void => {\n      if (closed) return\n      closed = true\n      if (heartbeat !== undefined) clearInterval(heartbeat)\n      this.extensionEventListeners.delete(send)\n      this.taskEventListeners.delete(sendTask)\n      const deviceListeners = this.deviceEventListeners.get(authorization.deviceId)\n      deviceListeners?.delete(sendDevice)\n      if (deviceListeners?.size === 0) this.deviceEventListeners.delete(authorization.deviceId)\n      request.removeListener('aborted', close)\n      response.removeListener('close', close)\n      operation.release()\n    }\n    const send = (revision: number): void => {\n      if (closed || response.destroyed || response.writableEnded) return\n      response.write(`id: ${String(revision)}\\nevent: extensions-changed\\ndata: {\\\"revision\\\":${String(revision)}}\\n\\n`)\n    }\n    const sendTask = (payload: string): void => {\n      if (closed || response.destroyed || response.writableEnded) return\n      response.write(`event: task-notify\\ndata: ${payload}\\n\\n`)\n    }\n    const sendDevice = (payload: string): void => {\n      if (closed || response.destroyed || response.writableEnded) return\n      response.write(`event: device-revoked\\ndata: ${payload}\\n\\n`)\n    }\n    setSecurityHeaders(response, this.tlsEnabled)\n    response.writeHead(200, {\n      'Content-Type': 'text/event-stream; charset=utf-8',\n      'Cache-Control': 'no-store',\n      Connection: 'keep-alive',\n      'X-Accel-Buffering': 'no',\n    })\n    response.write('retry: 2000\\n: ready\\n\\n')\n    this.extensionEventListeners.add(send)\n    this.taskEventListeners.add(sendTask)\n    const deviceListeners = this.deviceEventListeners.get(authorization.deviceId) ?? new Set<(payload: string) => void>()\n    deviceListeners.add(sendDevice)\n    this.deviceEventListeners.set(authorization.deviceId, deviceListeners)\n    heartbeat = setInterval(() => {\n      if (!closed && !response.destroyed && !response.writableEnded) response.write(': heartbeat\\n\\n')\n    }, EXTENSION_EVENT_HEARTBEAT_MS)\n    heartbeat.unref()\n    request.once('aborted', close)\n    response.once('close', close)\n  }\n\n  private async readUpgradeResponse(upstream: Socket, expectedAccept: string): Promise<{ header: string; remainder: Buffer }> {\n    return new Promise((resolve, reject) => {\n      let buffer = Buffer.alloc(0)\n      const failed = (error: Error): void => { cleanup(); reject(error) }\n      const closed = (): void => { cleanup(); reject(new Error('upstream closed during WebSocket handshake')) }\n      const data = (chunk: Buffer): void => {\n        buffer = Buffer.concat([buffer, chunk])\n        const end = buffer.indexOf('\\r\\n\\r\\n')\n        if (end < 0) {\n          if (buffer.length >= MAX_HEADER_BYTES) failed(new Error('upstream WebSocket headers are too large'))\n          return\n        }\n        if (end + 4 > MAX_HEADER_BYTES) {\n          failed(new Error('upstream WebSocket headers are too large'))\n          return\n        }\n        cleanup()\n        const lines = buffer.subarray(0, end).toString('latin1').split('\\r\\n')\n        if (lines.shift() !== 'HTTP/1.1 101 Switching Protocols') {\n          reject(new Error('upstream refused WebSocket upgrade'))\n          return\n        }\n        const selected = new Map<string, string>()\n        for (const line of lines) {\n          const colon = line.indexOf(':')\n          if (colon <= 0) {\n            reject(new Error('upstream returned malformed WebSocket headers'))\n            return\n          }\n          const name = line.slice(0, colon).trim().toLowerCase()\n          const value = line.slice(colon + 1).trim()\n          if (selected.has(name)) {\n            reject(new Error('upstream returned duplicate WebSocket headers'))\n            return\n          }\n          selected.set(name, value)\n        }\n        if (selected.get('upgrade')?.toLowerCase() !== 'websocket'\n          || !hasToken(selected.get('connection'), 'upgrade')\n          || selected.get('sec-websocket-accept') !== expectedAccept) {\n          reject(new Error('upstream returned an invalid WebSocket handshake'))\n          return\n        }\n        const output = [\n          'HTTP/1.1 101 Switching Protocols',\n          'Upgrade: websocket',\n          'Connection: Upgrade',\n          `Sec-WebSocket-Accept: ${expectedAccept}`,\n        ]\n        const protocol = selected.get('sec-websocket-protocol')\n        const extensions = selected.get('sec-websocket-extensions')\n        if (protocol !== undefined) output.push(`Sec-WebSocket-Protocol: ${protocol}`)\n        if (extensions !== undefined) output.push(`Sec-WebSocket-Extensions: ${extensions}`)\n        output.push('Referrer-Policy: no-referrer', 'X-Content-Type-Options: nosniff', '', '')\n        resolve({ header: output.join('\\r\\n'), remainder: buffer.subarray(end + 4) })\n      }\n      const cleanup = (): void => {\n        upstream.off('data', data)\n        upstream.off('error', failed)\n        upstream.off('close', closed)\n      }\n      upstream.on('data', data)\n      upstream.once('error', failed)\n      upstream.once('close', closed)\n    })\n  }\n\n  /** Snapshot of rejected upgrade paths for the approval UI (newest first). */\n  blockedUpgradePathReport(): BlockedUpgradePathEntry[] {\n    return this.blockedUpgradeLog?.report() ?? []\n  }\n\n  private async handleUpgrade(request: IncomingMessage, client: Socket, head: Buffer): Promise<void> {\n    const target = parseRequestTarget(request.url)\n    const policy = this.requirePolicy()\n    // Android WebView WebSockets do not consistently carry Fetch Metadata.\n    // Exact Origin, direct CIDR, exact Host, and the short Session Cookie\n    // remain mandatory; when Sec-Fetch-Site is present, assertExternalTrust\n    // still requires it to be same-origin.\n    assertExternalTrust(request, policy, false)\n    if (!policy.acceptsOrigin(request.headers.origin)) throw new HttpError(403, 'forbidden')\n    // Core DSH paths plus admin-approved third-party plugin paths (exact\n    // pathname match; the query string rides along to the upstream plugin,\n    // which owns its parsing). Everything else stays 404: paired-device\n    // auth, Origin, and handshake checks below still apply to allowed paths.\n    const upgradeAllowed = WS_PATHS.has(target.decodedPathname)\n      || (this.extraWebSocketPaths?.has(target.decodedPathname) ?? false)\n    if (!upgradeAllowed) {\n      this.blockedUpgradeLog?.record(target.decodedPathname)\n      throw new HttpError(404, 'not_found')\n    }\n    if (request.method !== 'GET' || headerValue(request.headers, 'upgrade')?.toLowerCase() !== 'websocket'\n      || !hasToken(headerValue(request.headers, 'connection'), 'upgrade')) {\n      throw new HttpError(400, 'bad_request')\n    }\n    const key = headerValue(request.headers, 'sec-websocket-key')\n    if (key === undefined || headerValue(request.headers, 'sec-websocket-version') !== '13') {\n      throw new HttpError(400, 'bad_request')\n    }\n    let decodedKey: Buffer\n    try {\n      decodedKey = Buffer.from(key, 'base64')\n    } catch {\n      throw new HttpError(400, 'bad_request')\n    }\n    if (decodedKey.length !== 16 || decodedKey.toString('base64') !== key) throw new HttpError(400, 'bad_request')\n    let authorization = this.authorize(request)\n    if (this.activeWebSockets.size >= this.config.maxWebSockets) throw new HttpError(429, 'busy')\n    const upstreamCookie = await this.upstreamCookieHeader()\n    if (client.destroyed) return\n    authorization = this.authorize(request)\n    if (this.activeWebSockets.size >= this.config.maxWebSockets) throw new HttpError(429, 'busy')\n    const compressed = this.config.websocketCompression.paths.includes(target.decodedPathname)\n\n    const upstream = connect({\n      host: stripIpv6Brackets(this.config.upstreamOrigin.hostname),\n      port: Number(this.config.upstreamOrigin.port),\n    })\n    client.pause()\n    const id = this.nextOperationId++\n    const closeBoth = (): void => {\n      client.destroy()\n      upstream.destroy()\n    }\n    client.on('error', closeBoth)\n    upstream.on('error', closeBoth)\n    const timer = setTimeout(closeBoth, Math.max(1, authorization.expiresAt - Date.now()))\n    timer.unref()\n    const record: ActiveWebSocket = Object.freeze({ ...authorization, client, upstream, timer })\n    this.activeWebSockets.set(id, record)\n    const cleanup = (): void => {\n      if (compressed && (!client.destroyed || !upstream.destroyed)) return\n      const active = this.activeWebSockets.get(id)\n      if (active !== undefined) clearTimeout(active.timer)\n      this.activeWebSockets.delete(id)\n    }\n    client.once('close', () => { if (!compressed) upstream.destroy(); cleanup() })\n    upstream.once('close', () => { if (!compressed) client.destroy(); cleanup() })\n    upstream.setTimeout(this.config.upstreamTimeoutMs, closeBoth)\n    try {\n      if (compressed) {\n        const upstreamTarget = new URL(this.config.upstreamOrigin.href)\n        const compressionTarget = upstreamTarget\n        compressionTarget.pathname = target.pathname\n        compressionTarget.search = target.search\n        await bridgeCompressedWebSocket(\n          request, client, upstream, head, compressionTarget, upstreamCookie,\n          this.config.websocketCompression, this.config.upstreamTimeoutMs,\n        )\n        return\n      }\n      await new Promise<void>((resolve, reject) => {\n        const connected = (): void => {\n          upstream.off('error', failed)\n          resolve()\n        }\n        const failed = (error: Error): void => {\n          upstream.off('connect', connected)\n          reject(error)\n        }\n        upstream.once('connect', connected)\n        upstream.once('error', failed)\n      })\n      const requestLines = [\n        `GET ${target.raw} HTTP/1.1`,\n        `Host: ${this.config.upstreamOrigin.host}`,\n        'Upgrade: websocket',\n        'Connection: Upgrade',\n        `Origin: ${this.config.upstreamOrigin.origin}`,\n        'Sec-Fetch-Site: same-origin',\n        `Sec-WebSocket-Key: ${key}`,\n        'Sec-WebSocket-Version: 13',\n      ]\n      if (upstreamCookie !== undefined) requestLines.push(`Cookie: ${upstreamCookie}`)\n      const protocol = headerValue(request.headers, 'sec-websocket-protocol')\n      const extensions = headerValue(request.headers, 'sec-websocket-extensions')\n      if (protocol !== undefined) requestLines.push(`Sec-WebSocket-Protocol: ${protocol}`)\n      if (extensions !== undefined) requestLines.push(`Sec-WebSocket-Extensions: ${extensions}`)\n      requestLines.push('', '')\n      upstream.write(requestLines.join('\\r\\n'))\n      if (head.length > 0) upstream.write(head)\n      const handshake = await this.readUpgradeResponse(upstream, websocketAccept(key))\n      upstream.setTimeout(0)\n      client.write(handshake.header)\n      if (handshake.remainder.length > 0) client.write(handshake.remainder)\n      upstream.pipe(client)\n      client.pipe(upstream)\n      client.resume()\n    } catch (error) {\n      closeBoth()\n      if (error instanceof HttpError) throw error\n      throw new HttpError(502, 'upstream_unavailable')\n    }\n  }\n\n  /** Loopback-only DSH WebServer route for opening pairing and managing devices. */\n  localAdminRoute(\n    prefix: string = LOCAL_ADMIN_PREFIX,\n    authenticateDesktop?: (request: IncomingMessage) => boolean,\n  ): WebRoute {\n    return {\n      kind: 'prefix',\n      path: prefix,\n      handler: async (request, response) => {\n        try {\n          const target = parseRequestTarget(request.url)\n          const mutation = request.method === 'POST'\n          assertLocalAdminTrust(request, mutation, () => authenticateDesktop?.(request) === true)\n          if (target.search !== '') throw new HttpError(400, 'bad_request')\n          if (request.method === 'GET' && target.decodedPathname === `${prefix}/status`) {\n            sendJson(response, 200, {\n              gateway: this.address(),\n              pairing: this.access.pairingStatus(),\n              deviceCount: this.access.listDevices().length,\n              resources: {\n                connections: this.connectedSockets.size,\n                activeRequests: this.activeRequests.size,\n                webSockets: this.activeWebSockets.size,\n              },\n              discovery: this.discoveryStatus(),\n            }, false)\n            return\n          }\n          if (request.method === 'GET' && target.decodedPathname === `${prefix}/devices`) {\n            sendJson(response, 200, { devices: this.access.listDevices() }, false)\n            return\n          }\n          if (request.method === 'POST' && target.decodedPathname === `${prefix}/pairing/open`) {\n            const body = await readJsonObject(request, MAX_CONTROL_BODY_BYTES)\n            if (body.ttlMs !== undefined && typeof body.ttlMs !== 'number') throw new HttpError(400, 'bad_request')\n            const opened = await this.access.openPairing(body.ttlMs as number | undefined)\n            // A self-signed remote entry must never fall back to public-CA trust.\n            // dsh2 is not understood by old Android apps, so they fail closed.\n            const requiresRemoteCa = this.config.pairingCaFile !== undefined && !this.config.discovery\n            const appKey = `dsh${requiresRemoteCa ? '2' : '1'}.${this.config.instanceId}.${opened.token}`\n            const fragment = requiresRemoteCa\n              ? `key=${appKey}`\n              : `instance=${this.config.instanceId}&token=${opened.token}`\n            const pairUrl = `${this.address().origin}/mobile-access/pair#${fragment}`\n            const appPairUrl = pairUrl\n            // The QR code is an enhancement; a failed render must not waste an opened window.\n            let qrSvg = ''\n            try {\n              qrSvg = await QRCode.toString(appPairUrl, { type: 'svg', margin: 1 })\n            } catch {\n              // keep qrSvg empty\n            }\n            sendJson(response, 201, {\n              ...opened,\n              appKey,\n              pairUrl,\n              appPairUrl,\n              qrSvg,\n            }, false)\n            return\n          }\n          if (request.method === 'POST' && target.decodedPathname === `${prefix}/devices/revoke`) {\n            const body = await readJsonObject(request, MAX_CONTROL_BODY_BYTES)\n            if (typeof body.deviceId !== 'string' || !/^[a-f\\d]{32}$/u.test(body.deviceId)) {\n              throw new HttpError(400, 'bad_request')\n            }\n            const revoked = await this.access.revokeDevice(body.deviceId)\n            if (!revoked) throw new HttpError(404, 'not_found')\n            await this.clientModulePreferences.removeDevice(body.deviceId).catch(() => {\n              process.emitWarning('Unable to remove revoked device client preferences', { code: 'DSH_MOBILE_PREFERENCE_CLEANUP_FAILED' })\n            })\n            sendJson(response, 200, { revoked: true }, false)\n            return\n          }\n          if (request.method === 'POST' && target.decodedPathname === `${prefix}/devices/reset`) {\n            const body = await readJsonObject(request, MAX_CONTROL_BODY_BYTES)\n            if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n            const removed = this.access.listDevices().map(device => device.id)\n            await this.access.resetDevices()\n            await this.clientModulePreferences.removeDevices(removed).catch(() => {\n              process.emitWarning('Unable to remove revoked device client preferences', { code: 'DSH_MOBILE_PREFERENCE_CLEANUP_FAILED' })\n            })\n            sendJson(response, 200, { reset: true }, false)\n            return\n          }\n          throw new HttpError(404, 'not_found')\n        } catch (error) {\n          const mapped = mapError(error)\n          if (response.headersSent) response.destroy()\n          else sendFailure(response, mapped.status, mapped.code, false)\n        }\n      },\n    }\n  }\n\n  /** Close listeners and abort all accepted work before resolving teardown. */\n  async close(): Promise<void> {\n    if (this.closeTask !== undefined) return this.closeTask\n    this.closeTask = this.performClose()\n    return this.closeTask\n  }\n\n  private async performClose(): Promise<void> {\n    this.closing = true\n    for (const controller of this.clientModuleOperations) controller.abort()\n    if (this.extensionChangeTimer !== undefined) clearInterval(this.extensionChangeTimer)\n    this.extensionChangeTimer = undefined\n    this.removeExtensionContentListener()\n    this.upstreamAuthRequest?.destroy()\n    this.upstreamAuthRequest = undefined\n    this.removeSessionListener()\n    this.pendingDeviceRevocations.clear()\n    const accessClose = this.access.close()\n    for (const stored of this.mobileBootBatches.values()) stored.assembly?.controller.abort()\n    for (const request of this.activeRequests.values()) request.abort()\n    for (const websocket of this.activeWebSockets.values()) {\n      websocket.client.destroy()\n      websocket.upstream.destroy()\n    }\n    for (const socket of this.connectedSockets) socket.destroy()\n    if (this.discoveryTimer !== undefined) clearInterval(this.discoveryTimer)\n    this.discoveryTimer = undefined\n    await this.closeBonjour()\n    const discoverySocket = this.discoverySocket\n    this.discoverySocket = undefined\n    if (discoverySocket !== undefined) {\n      await new Promise<void>(resolve => { discoverySocket.close(() => resolve()) })\n    }\n    const server = this.server\n    this.server = undefined\n    if (server !== undefined && server.listening) {\n      server.closeAllConnections()\n      await new Promise<void>(resolve => { server.close(() => resolve()) })\n    }\n    await accessClose\n    await Promise.allSettled(this.clientModuleTasks)\n    await Promise.allSettled(this.clientModuleRevocations)\n    this.activeRequests.clear()\n    this.activeWebSockets.clear()\n    this.connectedSockets.clear()\n    this.policy = undefined\n    this.listenerPort = undefined\n  }\n\n  /** Safe metadata helper for direct loopback integrations. */\n  devices(): readonly DeviceSummary[] {\n    return this.access.listDevices()\n  }\n\n  /** Status shown by the loopback mobile-access control card. */\n  extensionStatus(): { readonly loaded: number; readonly failed: number } {\n    return this.extensions?.status() ?? { loaded: 0, failed: 0 }\n  }\n}\n","import { lstat, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { basename, dirname, join } from 'node:path'\nimport { randomBytes } from 'node:crypto'\nimport { restrictPrivateFile } from './private-file.js'\n\n/** Persistent record containing only a digest of the long-lived device credential. */\nexport interface StoredDevice {\n  readonly id: string\n  readonly label: string\n  readonly tokenDigest: string\n  readonly createdAt: number\n  readonly expiresAt: number\n  readonly lastSeenAt: number\n  /** Legacy tombstone accepted on load; AccessController removes it during initialization. */\n  readonly revokedAt?: number\n}\n\n/** Versioned device state. Raw device and Session credentials are never members. */\nexport interface DeviceSnapshot {\n  readonly version: 1\n  readonly devices: readonly StoredDevice[]\n}\n\n/** Persistence seam for device-token digests and revocation metadata. */\nexport interface DeviceStore {\n  load(): Promise<DeviceSnapshot>\n  save(snapshot: DeviceSnapshot): Promise<void>\n}\n\nfunction assertInteger(value: unknown, name: string): asserts value is number {\n  if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {\n    throw new Error(`device state ${name} must be a non-negative integer`)\n  }\n}\n\nfunction parseDevice(value: unknown): StoredDevice {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('device state contains an invalid device')\n  const record = value as Record<string, unknown>\n  if (typeof record.id !== 'string' || !/^[a-f\\d]{32}$/u.test(record.id)) throw new Error('device state contains an invalid id')\n  if (typeof record.label !== 'string' || record.label.length < 1 || record.label.length > 64 || /[\\u0000-\\u001f\\u007f]/u.test(record.label)) {\n    throw new Error('device state contains an invalid label')\n  }\n  if (typeof record.tokenDigest !== 'string' || !/^[a-f\\d]{64}$/u.test(record.tokenDigest)) {\n    throw new Error('device state contains an invalid credential digest')\n  }\n  assertInteger(record.createdAt, 'createdAt')\n  assertInteger(record.expiresAt, 'expiresAt')\n  assertInteger(record.lastSeenAt, 'lastSeenAt')\n  if (record.revokedAt !== undefined) assertInteger(record.revokedAt, 'revokedAt')\n  if (record.expiresAt <= record.createdAt || record.lastSeenAt < record.createdAt) {\n    throw new Error('device state contains inconsistent timestamps')\n  }\n  return Object.freeze({\n    id: record.id,\n    label: record.label,\n    tokenDigest: record.tokenDigest,\n    createdAt: record.createdAt,\n    expiresAt: record.expiresAt,\n    lastSeenAt: record.lastSeenAt,\n    ...(record.revokedAt === undefined ? {} : { revokedAt: record.revokedAt }),\n  })\n}\n\n/** Validate durable data before it can authorize a device. */\nexport function parseDeviceSnapshot(value: unknown, maximumDevices = 256): DeviceSnapshot {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('device state must be an object')\n  const snapshot = value as Record<string, unknown>\n  if (snapshot.version !== 1 || !Array.isArray(snapshot.devices) || snapshot.devices.length > maximumDevices) {\n    throw new Error('device state has an unsupported version or device count')\n  }\n  const devices = snapshot.devices.map(parseDevice)\n  if (new Set(devices.map(device => device.id)).size !== devices.length\n    || new Set(devices.map(device => device.tokenDigest)).size !== devices.length) {\n    throw new Error('device state contains duplicate device identities')\n  }\n  return Object.freeze({ version: 1, devices: Object.freeze(devices) })\n}\n\n/** Atomic JSON implementation with symlink refusal and owner-only file creation. */\nexport class JsonDeviceStore implements DeviceStore {\n  constructor(private readonly file: string, private readonly maximumDevices = 256) {}\n\n  async load(): Promise<DeviceSnapshot> {\n    let stat\n    try {\n      stat = await lstat(this.file)\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code === 'ENOENT') return Object.freeze({ version: 1, devices: Object.freeze([]) })\n      throw error\n    }\n    if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024) {\n      throw new Error('device state must be a regular file no larger than 1 MiB')\n    }\n    await restrictPrivateFile(this.file)\n    let parsed: unknown\n    try {\n      parsed = JSON.parse(await readFile(this.file, 'utf8')) as unknown\n    } catch (error) {\n      throw new Error('device state is not valid JSON', { cause: error })\n    }\n    return parseDeviceSnapshot(parsed, this.maximumDevices)\n  }\n\n  async save(snapshot: DeviceSnapshot): Promise<void> {\n    const validated = parseDeviceSnapshot(snapshot, this.maximumDevices)\n    const directory = dirname(this.file)\n    await mkdir(directory, { recursive: true, mode: 0o700 })\n    try {\n      const current = await lstat(this.file)\n      if (!current.isFile() || current.isSymbolicLink()) throw new Error('device state target must remain a regular file')\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n    }\n    const temporary = join(directory, `.${basename(this.file)}.${randomBytes(12).toString('hex')}.tmp`)\n    try {\n      await writeFile(temporary, `${JSON.stringify(validated)}\\n`, { encoding: 'utf8', flag: 'wx', mode: 0o600 })\n      await rename(temporary, this.file)\n      await restrictPrivateFile(this.file)\n    } catch (error) {\n      try {\n        await rm(temporary, { force: true })\n      } catch (cleanupError) {\n        throw new AggregateError([error, cleanupError], 'device state write and temporary cleanup both failed')\n      }\n      throw error\n    }\n  }\n}\n\n/** In-memory store useful for embedding and deterministic tests. */\nexport class MemoryDeviceStore implements DeviceStore {\n  private snapshot: DeviceSnapshot\n\n  constructor(initial: DeviceSnapshot = { version: 1, devices: [] }) {\n    this.snapshot = parseDeviceSnapshot(initial)\n  }\n\n  async load(): Promise<DeviceSnapshot> {\n    return structuredClone(this.snapshot)\n  }\n\n  async save(snapshot: DeviceSnapshot): Promise<void> {\n    this.snapshot = structuredClone(parseDeviceSnapshot(snapshot))\n  }\n\n  /** Return a defensive copy for assertions or administrative export. */\n  inspect(): DeviceSnapshot {\n    return structuredClone(this.snapshot)\n  }\n}\n","import { randomBytes } from 'node:crypto'\nimport { lstat, mkdir, readdir, rename, rmdir, unlink, writeFile } from 'node:fs/promises'\nimport { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path'\nimport { restrictPrivateFile } from './private-file.js'\n\n/** Refuse link-shaped ancestors inside an owned state root before accessing a child. */\nexport async function assertManagedParents(root: string, target: string, prefix: string): Promise<void> {\n  const parent = resolve(root)\n  const candidate = resolve(target)\n  const offset = relative(parent, candidate)\n  if (!isAbsolute(root) || (offset !== '' && (offset.startsWith('..') || isAbsolute(offset)))) throw new Error(`${prefix}_path_invalid`)\n  const paths = [parent]\n  let cursor = parent\n  if (offset !== '') {\n    for (const segment of relative(parent, dirname(candidate)).split(/[\\\\/]/u).filter(Boolean)) {\n      cursor = join(cursor, segment); paths.push(cursor)\n    }\n  }\n  for (const path of paths) {\n    let entry\n    try { entry = await lstat(path) } catch (error) {\n      if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue\n      throw error\n    }\n    if (!entry.isDirectory() || entry.isSymbolicLink()) throw new Error(`${prefix}_path_invalid`)\n  }\n}\n\n/** Retry Windows handle contention while checking ownership before every mutation. */\nasync function mutateManagedPath(validate: () => Promise<void>, mutate: () => Promise<void>): Promise<void> {\n  let original: unknown\n  for (let attempt = 0; ; attempt++) {\n    await validate()\n    try { await mutate(); return } catch (error) {\n      const code = (error as NodeJS.ErrnoException).code\n      if (process.platform !== 'win32' || (code !== 'EPERM' && code !== 'EBUSY')) throw error\n      if (attempt === 0) original = error\n      if (attempt === 7) throw original\n      await new Promise<void>(resolve => setTimeout(resolve, Math.min(50 * 2 ** attempt, 400)))\n    }\n  }\n}\n\n/** Move only owned paths, retaining parent checks on every Windows retry. */\nexport async function renameManagedPath(root: string, source: string, destination: string, prefix: string): Promise<void> {\n  if (resolve(source) === resolve(root) || resolve(destination) === resolve(root)) throw new Error(`${prefix}_path_invalid`)\n  await mutateManagedPath(async () => {\n    await assertManagedParents(root, source, prefix)\n    await assertManagedParents(root, destination, prefix)\n  }, () => rename(source, destination))\n}\n\n/** Create a real owned directory; secure new directories without changing existing child ACLs. */\nexport async function ensureManagedDirectory(root: string, directory: string, prefix: string): Promise<void> {\n  await assertManagedParents(root, directory, prefix)\n  const created = await mkdir(directory, { recursive: true, mode: 0o700 })\n  const entry = await lstat(directory)\n  if (!entry.isDirectory() || entry.isSymbolicLink()) throw new Error(`${prefix}_path_invalid`)\n  // Existing directories may contain user-owned children with inherited ACLs.\n  // Sensitive new files receive their own ACL before promotion.\n  if (created !== undefined) await restrictPrivateFile(directory, 0o700)\n}\n\n/** Delete an owned child tree; remove links themselves and never delete the root. */\nexport async function removeManagedTree(root: string, target: string, prefix: string): Promise<void> {\n  if (resolve(target) === resolve(root)) throw new Error(`${prefix}_path_invalid`)\n  await assertManagedParents(root, target, prefix)\n  let entry\n  try { entry = await lstat(target) } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return\n    throw error\n  }\n  if (entry.isSymbolicLink() || !entry.isDirectory()) {\n    await mutateManagedPath(() => assertManagedParents(root, target, prefix), () => unlink(target))\n    return\n  }\n  for (const name of await readdir(target)) await removeManagedTree(root, join(target, name), prefix)\n  await mutateManagedPath(() => assertManagedParents(root, target, prefix), () => rmdir(target))\n}\n\n/** Validate every selected child, then await all deletion work even when one fails. */\nexport async function removeManagedPaths(root: string, paths: readonly string[], prefix: string): Promise<void> {\n  for (const path of paths) {\n    if (resolve(path) === resolve(root)) throw new Error(`${prefix}_path_invalid`)\n    await assertManagedParents(root, path, prefix)\n  }\n  const results = await Promise.allSettled(paths.map(path => removeManagedTree(root, path, prefix)))\n  const errors = results.filter(result => result.status === 'rejected').map(result => result.reason as unknown)\n  if (errors.length === 1) throw errors[0]\n  if (errors.length > 1) throw new AggregateError(errors, `${prefix}_cleanup_failed`)\n}\n\n/** Atomically replace one sensitive file beneath real owned directories. */\nexport async function writeManagedPrivateFile(root: string, file: string, body: string, prefix: string): Promise<void> {\n  await ensureManagedDirectory(root, dirname(file), prefix)\n  try {\n    const entry = await lstat(file)\n    if (!entry.isFile() || entry.isSymbolicLink()) throw new Error(`${prefix}_config_target_invalid`)\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n  }\n  const temporary = join(dirname(file), '.' + basename(file) + '.' + randomBytes(12).toString('hex') + '.tmp')\n  let failed = false\n  try {\n    await writeFile(temporary, body, { encoding: 'utf8', flag: 'wx', mode: 0o600 })\n    await restrictPrivateFile(temporary)\n    await renameManagedPath(root, temporary, file, prefix)\n  } catch (error) { failed = true; throw error } finally {\n    try { await removeManagedTree(root, temporary, prefix) } catch (error) { if (!failed) throw error }\n  }\n}\n\n/** Filesystem operations used to exercise publication failures without downloading artifacts. */\nexport interface ManagedPublicationOperations {\n  readonly move?: (source: string, destination: string) => Promise<void>\n  readonly remove?: (target: string) => Promise<void>\n}\n\n/** Promote a verified directory, restoring the previous version if promotion fails. */\nexport async function replaceManagedDirectory(\n  root: string, target: string, candidate: string, prefix: string,\n  operations: ManagedPublicationOperations = {},\n): Promise<void> {\n  if (resolve(target) === resolve(root) || resolve(candidate) === resolve(root)) throw new Error(`${prefix}_path_invalid`)\n  const move = async (source: string, destination: string): Promise<void> => {\n    await assertManagedParents(root, source, prefix)\n    await assertManagedParents(root, destination, prefix)\n    if (operations.move === undefined) await renameManagedPath(root, source, destination, prefix)\n    else await operations.move(source, destination)\n  }\n  const remove = operations.remove ?? (path => removeManagedTree(root, path, prefix))\n  const backup = join(dirname(target), `.${basename(target)}.previous-${randomBytes(12).toString('hex')}`)\n  let previous = false\n  let promoted = false\n  try {\n    await assertManagedParents(root, join(candidate, 'publication-check'), prefix)\n    await assertManagedParents(root, target, prefix)\n    try {\n      const entry = await lstat(target)\n      if (!entry.isDirectory() || entry.isSymbolicLink()) throw new Error(`${prefix}_path_invalid`)\n      await move(target, backup)\n      previous = true\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n    }\n    try {\n      await move(candidate, target)\n      promoted = true\n    } catch (error) {\n      if (previous) {\n        try { await move(backup, target); previous = false } catch (restoreError) {\n          throw new AggregateError([error, restoreError], `${prefix}_component_replace_failed`)\n        }\n      }\n      throw error\n    }\n  } finally {\n    try { await remove(candidate) } catch (_error) {\n      process.emitWarning(`${prefix} candidate cleanup failed`, { code: 'DSH_MOBILE_COMPONENT_CLEANUP_FAILED' })\n    }\n    if (promoted && previous) {\n      try { await remove(backup) } catch (_error) {\n        process.emitWarning(`${prefix} previous component cleanup failed`, { code: 'DSH_MOBILE_COMPONENT_CLEANUP_FAILED' })\n      }\n    }\n  }\n}\n","/**\n * Hosts a pinned GitHub release download may redirect to.\n *\n * `github.com/<owner>/<repo>/releases/download/<tag>/<asset>` does not serve the bytes itself: it\n * answers 302 with a signed URL on a release-asset host. A fetch configured with\n * `redirect: 'error'` fails that hop as `TypeError: fetch failed` (cause: `unexpected redirect`)\n * before a single byte is transferred, which is exactly how the cloudflared component could never\n * install. Following one validated hop keeps the origin restriction while allowing the shape\n * every GitHub release download uses.\n */\nconst RELEASE_ASSET_HOSTS: readonly string[] = Object.freeze([\n  'release-assets.githubusercontent.com',\n  'objects.githubusercontent.com',\n])\n\n/** Input for {@link downloadPinnedArtifact}. */\nexport interface PinnedDownloadRequest {\n  /** Absolute URL of the pinned artifact. */\n  readonly url: string\n  /** Exact byte length the artifact must have. */\n  readonly expectedBytes: number\n  /** Stable error-code prefix owned by the calling component, such as `cloudflared`. */\n  readonly errorPrefix: string\n  readonly signal: AbortSignal\n  /** Hosts a single redirect hop may target; defaults to the GitHub release asset hosts. */\n  readonly redirectHosts?: readonly string[]\n}\n\n/** Release an unused body without replacing a download or validation failure. */\nasync function discardBody(body: { cancel(): Promise<void> } | null): Promise<void> {\n  if (body === null) return\n  try { await body.cancel() } catch (_error) {\n    // Cancellation can reject after a transport failure; the download verdict remains authoritative.\n  }\n}\n\n/** Follow one redirect hop after checking its scheme and host. A second hop is refused. */\nasync function followValidatedRedirect(response: Response, request: PinnedDownloadRequest): Promise<Response> {\n  let target: URL\n  try {\n    const location = response.headers.get('location')\n    if (location === null) throw new Error(`${request.errorPrefix}_download_redirect_missing`)\n    try {\n      target = new URL(location, request.url)\n    } catch {\n      throw new Error(`${request.errorPrefix}_download_redirect_invalid`)\n    }\n    const hosts = request.redirectHosts ?? RELEASE_ASSET_HOSTS\n    if (target.protocol !== 'https:' || !hosts.includes(target.hostname)) {\n      throw new Error(`${request.errorPrefix}_download_redirect_rejected`)\n    }\n  } finally { await discardBody(response.body) }\n  return fetch(target, { redirect: 'error', signal: request.signal })\n}\n\n/** Attempts per install. A 55 MB transfer through a TUN proxy can reset mid-stream: the first\n * real run in the development environment failed after 1.5 MB and succeeded on the next attempt,\n * which is exactly the confusing \"nothing happened\" the user saw. */\nconst DOWNLOAD_ATTEMPTS = 2\nconst RETRY_DELAY_MS = 750\n\n/** Whether a failure is a transport problem worth a second attempt rather than a verdict. */\nfunction isRetryable(error: unknown): boolean {\n  // undici reports network faults as TypeError('fetch failed'), and a 5xx is worth one more try.\n  if (error instanceof TypeError) return true\n  if (error instanceof Error && /_download_http_5\\d\\d$/u.test(error.message)) return true\n  return false\n}\n\nfunction delay(ms: number): Promise<void> {\n  return new Promise(resolve => { setTimeout(resolve, ms) })\n}\n\nasync function attemptDownload(request: PinnedDownloadRequest): Promise<Uint8Array> {\n  const first = await fetch(request.url, { redirect: 'manual', signal: request.signal })\n  const redirected = first.status >= 300 && first.status < 400\n  const response = redirected ? await followValidatedRedirect(first, request) : first\n  let reader: ReadableStreamDefaultReader<Uint8Array> | undefined\n  let ended = false\n  try {\n    if (!response.ok) throw new Error(`${request.errorPrefix}_download_http_${String(response.status)}`)\n    const contentLength = response.headers.get('content-length')\n    if (contentLength !== null && (!/^\\d+$/u.test(contentLength) || Number(contentLength) !== request.expectedBytes)) {\n      throw new Error(`${request.errorPrefix}_download_size_mismatch`)\n    }\n    if (response.body === null) throw new Error(`${request.errorPrefix}_download_size_mismatch`)\n    const bytes = new Uint8Array(request.expectedBytes)\n    reader = response.body.getReader()\n    let received = 0\n    while (true) {\n      const chunk = await reader.read()\n      if (chunk.done) { ended = true; break }\n      if (chunk.value.byteLength > bytes.byteLength - received) {\n        throw new Error(`${request.errorPrefix}_download_size_mismatch`)\n      }\n      bytes.set(chunk.value, received)\n      received += chunk.value.byteLength\n    }\n    if (received !== request.expectedBytes) throw new Error(`${request.errorPrefix}_download_size_mismatch`)\n    return bytes\n  } finally {\n    if (reader === undefined) await discardBody(response.body)\n    else {\n      try { if (!ended) await discardBody(reader) } finally { reader.releaseLock() }\n    }\n  }\n}\n\n/**\n * Download a pinned artifact, following at most one validated redirect, and check its exact length.\n * A transport failure is retried once; a length or redirect verdict is not. The caller still\n * verifies the SHA-256 before publishing anything.\n * @param request - the pinned URL, its exact byte length and the caller's error prefix.\n * @returns the artifact bytes.\n */\nexport async function downloadPinnedArtifact(request: PinnedDownloadRequest): Promise<Uint8Array> {\n  let lastError: unknown\n  for (let attempt = 1; attempt <= DOWNLOAD_ATTEMPTS; attempt += 1) {\n    try {\n      return await attemptDownload(request)\n    } catch (error) {\n      lastError = error\n      if (attempt === DOWNLOAD_ATTEMPTS || !isRetryable(error)) throw error\n      await delay(RETRY_DELAY_MS)\n    }\n  }\n  throw lastError\n}\n","import { createHash, randomBytes } from 'node:crypto'\nimport { execFile } from 'node:child_process'\nimport {\n  chmod,\n  copyFile,\n  lstat,\n  mkdir,\n  mkdtemp,\n  readFile,\n  stat,\n  writeFile,\n} from 'node:fs/promises'\nimport { isAbsolute, join, relative, resolve } from 'node:path'\nimport { assertManagedParents, ensureManagedDirectory, removeManagedPaths, removeManagedTree, replaceManagedDirectory } from './managed-files.js'\nimport { downloadPinnedArtifact } from './component-download.js'\n\nconst FRP_VERSION = '0.70.1'\nconst MAX_ARCHIVE_ENTRIES = 128\nconst MAX_ARCHIVE_LIST_BYTES = 256 * 1024\n\ninterface FrpArtifact {\n  readonly platform: NodeJS.Platform\n  readonly arch: string\n  readonly downloadUrl: string\n  readonly downloadBytes: number\n  readonly downloadSha256: string\n  readonly archiveName: string\n  readonly executableName: string\n}\n\nconst releases = [\n  {\n    platform: 'win32', arch: 'x64', archiveName: 'frp.zip', executableName: 'frpc.exe',\n    downloadBytes: 13_924_309,\n    downloadSha256: '531f3cd3cc41c0b4f077b54fe6b7dd83c0ff727e7f0bf412a4c78fa279165de5',\n    downloadUrl: `https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_windows_amd64.zip`,\n  },\n  {\n    platform: 'win32', arch: 'arm64', archiveName: 'frp.zip', executableName: 'frpc.exe',\n    downloadBytes: 12_204_751,\n    downloadSha256: '74d3acaf0f03ee190dd0462f9b49861dca50b0559c5488af4b36572fc951fcca',\n    downloadUrl: `https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_windows_arm64.zip`,\n  },\n  {\n    platform: 'linux', arch: 'x64', archiveName: 'frp.tar.gz', executableName: 'frpc',\n    downloadBytes: 13_924_042,\n    downloadSha256: '333da23d1b9009d7c01638e9ba38cf4600f7d37d393f854e96ee1396adefa9a6',\n    downloadUrl: `https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_amd64.tar.gz`,\n  },\n  {\n    platform: 'linux', arch: 'arm64', archiveName: 'frp.tar.gz', executableName: 'frpc',\n    downloadBytes: 12_371_290,\n    downloadSha256: '3990f396a9a490ee7f0e5f355287750ed41520064ed999eab443b5e9a78d773d',\n    downloadUrl: `https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_arm64.tar.gz`,\n  },\n  {\n    platform: 'darwin', arch: 'x64', archiveName: 'frp.tar.gz', executableName: 'frpc',\n    downloadBytes: 13_951_979,\n    downloadSha256: 'cbf69cf26e5553e914e97d37f5d4367fa30f5f531d073a889465af4719281e25',\n    downloadUrl: `https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_darwin_amd64.tar.gz`,\n  },\n  {\n    platform: 'darwin', arch: 'arm64', archiveName: 'frp.tar.gz', executableName: 'frpc',\n    downloadBytes: 12_670_664,\n    downloadSha256: 'cfa733b5a261c1647edee3c1fc4133d2542989b28f5602e81d47fc821d25c55f',\n    downloadUrl: `https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_darwin_arm64.tar.gz`,\n  },\n] as const satisfies readonly FrpArtifact[]\n\n/** Pinned official FRP release metadata for supported desktop targets. */\nexport const FRP_COMPONENT_RELEASES: Readonly<Record<string, FrpArtifact>> = Object.freeze(Object.fromEntries(\n  releases.map(release => [`${release.platform}-${release.arch}`, Object.freeze(release)]),\n))\n\n/** Public, credential-free description of the managed FRP client. */\nexport interface FrpComponentStatus {\n  readonly supported: boolean\n  readonly installed: boolean\n  readonly version: string\n  readonly downloadBytes: number\n  readonly installedBytes: number\n  readonly sourceUrl: string\n  readonly releasePage: string\n  readonly storagePath: string\n  readonly errorCode?: string\n}\n\ninterface FrpComponentManagerOptions {\n  readonly stateDirectory: string\n  readonly platform?: NodeJS.Platform\n  readonly arch?: string\n  readonly fetchArtifact?: (artifact: FrpArtifact, signal: AbortSignal) => Promise<Uint8Array>\n  readonly extractArtifact?: (archive: string, destination: string, executableName: string) => Promise<void>\n  readonly inspectExecutable?: (executable: string) => Promise<string>\n}\n\nfunction inside(parent: string, child: string): boolean {\n  const candidate = relative(parent, child)\n  return candidate !== '' && !candidate.startsWith('..') && !isAbsolute(candidate)\n}\n\nasync function regularFile(file: string): Promise<boolean> {\n  try {\n    const entry = await lstat(file)\n    return entry.isFile() && !entry.isSymbolicLink()\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false\n    throw error\n  }\n}\n\nfunction sha256(bytes: Uint8Array): string {\n  return createHash('sha256').update(bytes).digest('hex')\n}\n\nasync function runCapture(file: string, args: readonly string[]): Promise<string> {\n  return new Promise<string>((resolveRun, reject) => {\n    execFile(file, [...args], {\n      windowsHide: true,\n      timeout: 120_000,\n      maxBuffer: MAX_ARCHIVE_LIST_BYTES,\n      encoding: 'utf8',\n    }, (error, stdout) => {\n      if (error === null) resolveRun(stdout)\n      else reject(error)\n    })\n  })\n}\n\nfunction validatedArchiveEntry(rawEntry: string): readonly string[] {\n  if (rawEntry.length === 0 || rawEntry.includes('\\\\') || rawEntry.includes('\\u0000')\n    || rawEntry.startsWith('/') || /^[a-zA-Z]:/u.test(rawEntry)) {\n    throw new Error('frp_archive_path_invalid')\n  }\n  const segments = rawEntry.replace(/\\/$/u, '').split('/')\n  if (segments.some(segment => segment === '' || segment === '.' || segment === '..')) {\n    throw new Error('frp_archive_path_invalid')\n  }\n  return segments\n}\n\n/** Select exactly one nested frpc executable from a safe archive listing. */\nexport function selectFrpExecutableEntry(entries: readonly string[], executableName: string): string {\n  if (entries.length === 0 || entries.length > MAX_ARCHIVE_ENTRIES) throw new Error('frp_archive_entries_invalid')\n  let executableEntry: string | undefined\n  for (const entry of entries) {\n    const segments = validatedArchiveEntry(entry)\n    if (segments.length >= 2 && segments.at(-1) === executableName) {\n      if (executableEntry !== undefined) throw new Error('frp_archive_executable_ambiguous')\n      executableEntry = entry.replace(/\\/$/u, '')\n    }\n  }\n  if (executableEntry === undefined) throw new Error('frp_archive_executable_missing')\n  return executableEntry\n}\n\nasync function defaultExtractArtifact(archive: string, destination: string, executableName: string): Promise<void> {\n  const tar = process.platform === 'win32' ? 'tar.exe' : 'tar'\n  const listing = await runCapture(tar, ['-tf', archive])\n  const entries = listing.split(/\\r?\\n/u).filter(entry => entry.length > 0)\n  const executableEntry = selectFrpExecutableEntry(entries, executableName)\n  const unpacked = join(destination, 'archive')\n  await mkdir(unpacked, { recursive: true, mode: 0o700 })\n  await runCapture(tar, ['-xf', archive, '-C', unpacked, executableEntry])\n  const extracted = join(unpacked, ...validatedArchiveEntry(executableEntry))\n  if (!await regularFile(extracted)) throw new Error('frp_archive_executable_invalid')\n  await copyFile(extracted, join(destination, executableName))\n}\n\nasync function defaultFetchArtifact(artifact: FrpArtifact, signal: AbortSignal): Promise<Uint8Array> {\n  return downloadPinnedArtifact({\n    url: artifact.downloadUrl,\n    expectedBytes: artifact.downloadBytes,\n    errorPrefix: 'frp',\n    signal,\n  })\n}\n\nasync function defaultInspectExecutable(executable: string): Promise<string> {\n  return (await runCapture(executable, ['--version'])).trim()\n}\n\n/** Owns the optional official frpc binary inside the DSH Mobile state directory. */\nexport class FrpComponentManager {\n  readonly executable: string\n  readonly componentRoot: string\n  readonly componentStorage: string\n  readonly logRoot: string\n  private readonly stagingRoot: string\n  private readonly stateDirectory: string\n  private readonly artifact: FrpArtifact | undefined\n  private readonly fetchArtifact: (artifact: FrpArtifact, signal: AbortSignal) => Promise<Uint8Array>\n  private readonly extractArtifact: (archive: string, destination: string, executableName: string) => Promise<void>\n  private readonly inspectExecutable: (executable: string) => Promise<string>\n  private installed = false\n  private installedBytes = 0\n  private errorCode: string | undefined\n  private queue: Promise<void> = Promise.resolve()\n\n  constructor(options: FrpComponentManagerOptions) {\n    if (!isAbsolute(options.stateDirectory)) throw new Error('frp state directory must be absolute')\n    const stateDirectory = resolve(options.stateDirectory)\n    this.stateDirectory = stateDirectory\n    const platform = options.platform ?? process.platform\n    const arch = options.arch ?? process.arch\n    this.artifact = FRP_COMPONENT_RELEASES[`${platform}-${arch}`]\n    this.componentRoot = join(stateDirectory, 'components', 'frp')\n    this.componentStorage = join(this.componentRoot, FRP_VERSION)\n    this.executable = join(this.componentStorage, platform === 'win32' ? 'frpc.exe' : 'frpc')\n    this.logRoot = join(stateDirectory, 'logs', 'frp')\n    this.stagingRoot = join(stateDirectory, 'staging', 'frp')\n    for (const child of [this.componentRoot, this.componentStorage, this.logRoot, this.stagingRoot]) {\n      if (!inside(stateDirectory, child)) throw new Error('frp component path escaped its state directory')\n    }\n    this.fetchArtifact = options.fetchArtifact ?? defaultFetchArtifact\n    this.extractArtifact = options.extractArtifact ?? defaultExtractArtifact\n    this.inspectExecutable = options.inspectExecutable ?? defaultInspectExecutable\n  }\n\n  /** Inspect the managed executable without relying on global FRP installations. */\n  async initialize(): Promise<void> {\n    this.installed = false\n    this.installedBytes = 0\n    this.errorCode = undefined\n    try {\n      await assertManagedParents(this.stateDirectory, this.executable, 'frp')\n      this.installed = await regularFile(this.executable)\n      this.installedBytes = this.installed ? (await stat(this.executable)).size : 0\n      if (this.installed) {\n        const version = await this.inspectExecutable(this.executable)\n        if (version !== FRP_VERSION) throw new Error('frp_component_version_mismatch')\n      }\n    } catch (_error) {\n      this.installed = false\n      this.installedBytes = 0\n      this.errorCode = 'frp_component_invalid'\n    }\n  }\n\n  /** Return component metadata without exposing configuration or credentials. */\n  status(): FrpComponentStatus {\n    return Object.freeze({\n      supported: this.artifact !== undefined,\n      installed: this.installed,\n      version: FRP_VERSION,\n      downloadBytes: this.artifact?.downloadBytes ?? 0,\n      installedBytes: this.installedBytes,\n      sourceUrl: this.artifact?.downloadUrl ?? 'https://github.com/fatedier/frp/releases',\n      releasePage: `https://github.com/fatedier/frp/releases/tag/v${FRP_VERSION}`,\n      storagePath: this.componentRoot,\n      ...(this.errorCode === undefined ? {} : { errorCode: this.errorCode }),\n    })\n  }\n\n  /** Download, verify, and extract only frpc after explicit confirmation. */\n  install(): Promise<FrpComponentStatus> {\n    return this.enqueue(async () => {\n      const artifact = this.artifact\n      if (artifact === undefined) throw new Error('frp_component_unsupported')\n      await assertManagedParents(this.stateDirectory, this.executable, 'frp')\n      await ensureManagedDirectory(this.stateDirectory, this.stagingRoot, 'frp')\n      const staging = await mkdtemp(join(this.stagingRoot, 'install-'))\n      try {\n        const controller = new AbortController()\n        const timeout = setTimeout(() => { controller.abort() }, 120_000)\n        timeout.unref()\n        let bytes: Uint8Array\n        try { bytes = await this.fetchArtifact(artifact, controller.signal) } finally { clearTimeout(timeout) }\n        if (bytes.byteLength !== artifact.downloadBytes) throw new Error('frp_download_size_mismatch')\n        if (sha256(bytes) !== artifact.downloadSha256) throw new Error('frp_download_hash_mismatch')\n        const archive = join(staging, artifact.archiveName)\n        await writeFile(archive, bytes, { flag: 'wx', mode: 0o600 })\n        await this.extractArtifact(archive, staging, artifact.executableName)\n        const extracted = join(staging, artifact.executableName)\n        if (!await regularFile(extracted)) throw new Error('frp_executable_missing')\n        await chmod(extracted, 0o700)\n        const version = await this.inspectExecutable(extracted)\n        if (version !== FRP_VERSION) throw new Error('frp_component_version_mismatch')\n        const candidate = join(this.componentRoot, `.install-${randomBytes(12).toString('hex')}`)\n        await ensureManagedDirectory(this.stateDirectory, candidate, 'frp')\n        try {\n          const candidateExecutable = join(candidate, artifact.executableName)\n          await copyFile(extracted, candidateExecutable)\n          await chmod(candidateExecutable, 0o700)\n          await replaceManagedDirectory(this.stateDirectory, this.componentStorage, candidate, 'frp')\n        } catch (error) {\n          try { await removeManagedTree(this.stateDirectory, candidate, 'frp') } catch (_cleanupError) {\n            process.emitWarning('FRP candidate cleanup failed', { code: 'DSH_MOBILE_COMPONENT_CLEANUP_FAILED' })\n          }\n          throw error\n        }\n        this.installed = true\n        this.installedBytes = (await stat(this.executable)).size\n        this.errorCode = undefined\n      } finally {\n        await removeManagedTree(this.stateDirectory, staging, 'frp')\n      }\n    })\n  }\n\n  /** Remove all FRP executable, staging, and log files owned by DSH Mobile. */\n  purge(): Promise<FrpComponentStatus> {\n    return this.enqueue(async () => {\n      await removeManagedPaths(this.stateDirectory, [this.componentRoot, this.logRoot, this.stagingRoot], 'frp')\n      this.installed = false\n      this.installedBytes = 0\n      this.errorCode = undefined\n    })\n  }\n\n  private enqueue(operation: () => Promise<void>): Promise<FrpComponentStatus> {\n    const task = this.queue.then(operation, operation)\n    this.queue = task.then(() => undefined, () => undefined)\n    return task.then(() => this.status())\n  }\n}\n","import { copyFile, lstat, mkdir, readdir } from 'node:fs/promises'\nimport { isAbsolute, join, win32 } from 'node:path'\nimport { performance } from 'node:perf_hooks'\nimport { execFileText } from './exec-file.js'\n\n/** Windows extraction stage reported without subprocess output or private paths. */\nexport type WindowsMsiExtractionStage = 'tools' | 'archive' | 'database' | 'cabinet' | 'file'\n\ninterface SafeCommandDetails {\n  readonly code?: number | string | null\n  readonly signal?: string | null\n  readonly killed?: boolean\n  readonly deadlineMs?: number\n}\n\n/** A failed read-only MSI extraction; causes deliberately exclude raw command arguments. */\nexport class WindowsMsiExtractionError extends Error {\n  readonly signal: string | null | undefined\n  readonly killed: boolean | undefined\n  readonly deadlineMs: number | undefined\n\n  constructor(readonly stage: WindowsMsiExtractionStage, readonly elapsedMs: number, readonly nativeCode?: number | string | null,\n    details: SafeCommandDetails = {}) {\n    const fields = Object.entries({ ...details, ...(nativeCode === undefined ? {} : { code: nativeCode }) })\n      .map(([key, value]) => `${key}=${String(value)}`).join(', ')\n    super(`cpolar_extract_${stage}_failed`, { cause: Object.assign(new Error(\n      `Windows cpolar ${stage} extraction failed after ${String(elapsedMs)} ms${fields === '' ? '' : ` (${fields})`}`,\n    ), details) })\n    this.name = 'WindowsMsiExtractionError'\n    this.signal = details.signal\n    this.killed = details.killed\n    this.deadlineMs = details.deadlineMs\n  }\n}\n\n// MsiOpenDatabase READONLY accesses tables, never an installation/action sequence.\n// All handles are closed on this synchronous reader's thread. Media maps File.Sequence\n// to an embedded _Streams CAB; the cabinet reader extracts only the selected File key.\nconst READ_MSI_CABINET = String.raw`\n$ErrorActionPreference = 'Stop'\n$ProgressPreference = 'SilentlyContinue'\n[Console]::OutputEncoding = New-Object System.Text.UTF8Encoding($false)\ntry {\n  Add-Type -TypeDefinition @'\nusing System;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Text.RegularExpressions;\n[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32)]\n\npublic sealed class DshMsiEntry {\n  public string Member;\n  public int Bytes;\n  public long CabinetBytes;\n}\npublic static class DshReadOnlyMsi {\n  [DllImport(\"msi.dll\", CharSet = CharSet.Unicode, ExactSpelling = true)]\n  private static extern uint MsiOpenDatabaseW(string path, IntPtr mode, out uint database);\n  [DllImport(\"msi.dll\", CharSet = CharSet.Unicode, ExactSpelling = true)]\n  private static extern uint MsiDatabaseOpenViewW(uint database, string query, out uint view);\n  [DllImport(\"msi.dll\", ExactSpelling = true)]\n  private static extern uint MsiViewExecute(uint view, uint parameters);\n  [DllImport(\"msi.dll\", ExactSpelling = true)]\n  private static extern uint MsiViewFetch(uint view, out uint record);\n  [DllImport(\"msi.dll\", CharSet = CharSet.Unicode, ExactSpelling = true)]\n  private static extern uint MsiRecordGetStringW(uint record, uint field, StringBuilder value, ref uint size);\n  [DllImport(\"msi.dll\", ExactSpelling = true)]\n  private static extern int MsiRecordGetInteger(uint record, uint field);\n  [DllImport(\"msi.dll\", ExactSpelling = true)]\n  private static extern uint MsiRecordReadStream(uint record, uint field, byte[] buffer, ref uint size);\n  [DllImport(\"msi.dll\", ExactSpelling = true)]\n  private static extern uint MsiRecordDataSize(uint record, uint field);\n  [DllImport(\"msi.dll\", ExactSpelling = true)]\n  private static extern uint MsiCreateRecord(uint fields);\n  [DllImport(\"msi.dll\", CharSet = CharSet.Unicode, ExactSpelling = true)]\n  private static extern uint MsiRecordSetStringW(uint record, uint field, string value);\n  [DllImport(\"msi.dll\", ExactSpelling = true)]\n  private static extern uint MsiCloseHandle(uint handle);\n\n  private static void Check(uint result) {\n    if (result != 0) throw new InvalidOperationException(\"MSI_\" + result);\n  }\n  private static string Text(uint record, uint field) {\n    uint count = 512;\n    var buffer = new StringBuilder((int)count + 1);\n    Check(MsiRecordGetStringW(record, field, buffer, ref count));\n    return buffer.ToString();\n  }\n  private static uint Query(uint database, string sql, uint parameters) {\n    uint view = 0;\n    Check(MsiDatabaseOpenViewW(database, sql, out view));\n    try { Check(MsiViewExecute(view, parameters)); return view; }\n    catch { MsiCloseHandle(view); throw; }\n  }\n  private static bool Next(uint view, out uint record) {\n    uint result = MsiViewFetch(view, out record);\n    if (result == 259) return false;\n    Check(result);\n    return record != 0;\n  }\n  public static DshMsiEntry Read(string msi, string output, string wanted, int expectedBytes) {\n    uint database = 0;\n    Check(MsiOpenDatabaseW(msi, IntPtr.Zero, out database));\n    try {\n      string member = null;\n      int sequence = 0;\n      uint view = Query(database, \"SELECT File, FileName, FileSize, Sequence FROM File\", 0);\n      try {\n        int rows = 0;\n        uint record;\n        while (Next(view, out record)) {\n          try {\n            if (++rows > 4096) throw new InvalidDataException(\"FILE_ROWS_LIMIT\");\n            string filename = Text(record, 2);\n            string[] names = filename.Split('|');\n            if (!String.Equals(names[names.Length - 1], wanted, StringComparison.OrdinalIgnoreCase)) continue;\n            if (member != null) throw new InvalidDataException(\"FILE_AMBIGUOUS\");\n            member = Text(record, 1);\n            sequence = MsiRecordGetInteger(record, 4);\n            if (!Regex.IsMatch(member, @\"\\A[A-Za-z_][A-Za-z0-9_.]{0,71}\\z\") || member.Contains(\"..\")\n              || sequence < 1 || MsiRecordGetInteger(record, 3) != expectedBytes) {\n              throw new InvalidDataException(\"FILE_METADATA_INVALID\");\n            }\n          } finally { MsiCloseHandle(record); }\n        }\n      } finally { MsiCloseHandle(view); }\n      if (member == null) throw new InvalidDataException(\"FILE_MISSING\");\n      string cabinet = null;\n      int lowerSequence = 0;\n      view = Query(database, \"SELECT LastSequence, Cabinet FROM Media ORDER BY DiskId\", 0);\n      try {\n        int rows = 0;\n        uint record;\n        while (Next(view, out record)) {\n          try {\n            if (++rows > 128) throw new InvalidDataException(\"MEDIA_ROWS_LIMIT\");\n            int upperSequence = MsiRecordGetInteger(record, 1);\n            if (upperSequence < lowerSequence) throw new InvalidDataException(\"MEDIA_SEQUENCE_INVALID\");\n            if (sequence > lowerSequence && sequence <= upperSequence) cabinet = Text(record, 2);\n            lowerSequence = upperSequence;\n          } finally { MsiCloseHandle(record); }\n        }\n      } finally { MsiCloseHandle(view); }\n      if (cabinet == null || !Regex.IsMatch(cabinet, @\"\\A#[A-Za-z_][A-Za-z0-9_.-]{0,61}\\z\")) {\n        throw new InvalidDataException(\"EMBEDDED_CABINET_MISSING\");\n      }\n      uint parameter = MsiCreateRecord(1);\n      if (parameter == 0) throw new InvalidOperationException(\"RECORD_CREATE_FAILED\");\n      try {\n        Check(MsiRecordSetStringW(parameter, 1, cabinet.Substring(1)));\n        view = Query(database, \"SELECT Data FROM _Streams WHERE Name = ?\", parameter);\n        try {\n          uint record;\n          if (!Next(view, out record)) throw new InvalidDataException(\"CABINET_STREAM_MISSING\");\n          try {\n            uint bytes = MsiRecordDataSize(record, 1);\n            if (bytes < 36 || bytes > new FileInfo(msi).Length || bytes > 33554432) {\n              throw new InvalidDataException(\"CABINET_SIZE_INVALID\");\n            }\n            using (var stream = new FileStream(output, FileMode.CreateNew, FileAccess.Write, FileShare.None)) {\n              byte[] buffer = new byte[65536];\n              long total = 0;\n              while (true) {\n                uint count = (uint)buffer.Length;\n                Check(MsiRecordReadStream(record, 1, buffer, ref count));\n                if (count == 0) break;\n                total += count;\n                if (count > buffer.Length || total > bytes) throw new InvalidDataException(\"CABINET_STREAM_OVERFLOW\");\n                stream.Write(buffer, 0, (int)count);\n              }\n              if (total != bytes) throw new InvalidDataException(\"CABINET_STREAM_TRUNCATED\");\n            }\n            return new DshMsiEntry { Member = member, Bytes = expectedBytes, CabinetBytes = bytes };\n          } finally { MsiCloseHandle(record); }\n        } finally { MsiCloseHandle(view); }\n      } finally { MsiCloseHandle(parameter); }\n    } finally { MsiCloseHandle(database); }\n  }\n}\n'@\n  $result = [DshReadOnlyMsi]::Read($env:DSH_MSI_SOURCE, $env:DSH_MSI_CABINET, $env:DSH_MSI_BINARY, [int]$env:DSH_MSI_BYTES)\n  $result | ConvertTo-Json -Compress\n} catch {\n  [Console]::Error.WriteLine('DSH_MSI_READ_FAILED')\n  exit 1\n}\n`\n\nconst READ_MSI_ZIP = String.raw`\n$ErrorActionPreference = 'Stop'\n$ProgressPreference = 'SilentlyContinue'\ntry {\n  Add-Type -AssemblyName System.IO.Compression.FileSystem\n  $zip = [System.IO.Compression.ZipFile]::OpenRead($env:DSH_MSI_ZIP)\n  try {\n    if ($zip.Entries.Count -lt 1 -or $zip.Entries.Count -gt 128) { throw 'ZIP_ENTRIES_LIMIT' }\n    $selected = $null\n    [long]$total = 0\n    foreach ($entry in $zip.Entries) {\n      $name = $entry.FullName.Replace('\\', '/')\n      $segments = $name.TrimEnd('/').Split('/')\n      if ($name.StartsWith('/') -or $name.Contains(':') -or $segments -contains '..' -or $segments -contains '.' -or $segments -contains '') { throw 'ZIP_PATH_INVALID' }\n      if (($entry.ExternalAttributes -band 0x400) -ne 0 -or (($entry.ExternalAttributes -shr 16) -band 0xF000) -eq 0xA000) { throw 'ZIP_LINK_INVALID' }\n      if ($entry.Length -lt 0 -or $entry.Length -gt (33554432 - $total)) { throw 'ZIP_SIZE_LIMIT' }\n      $total += $entry.Length\n      if (-not $name.EndsWith('/') -and $name.EndsWith('.msi', [System.StringComparison]::OrdinalIgnoreCase)) {\n        if ($null -ne $selected -or $entry.Length -lt 1) { throw 'ZIP_MSI_INVALID' }\n        $selected = $entry\n      }\n    }\n    if ($null -eq $selected) { throw 'ZIP_MSI_MISSING' }\n    if (([System.IO.File]::GetAttributes([System.IO.Path]::GetDirectoryName($env:DSH_MSI_OUTPUT)) -band [System.IO.FileAttributes]::ReparsePoint) -ne 0) { throw 'ZIP_PARENT_INVALID' }\n    $zipEntryStream = $selected.Open()\n    try {\n      $zipMsiOutput = [System.IO.File]::Open($env:DSH_MSI_OUTPUT, [System.IO.FileMode]::CreateNew, [System.IO.FileAccess]::Write, [System.IO.FileShare]::None)\n      try {\n        $buffer = New-Object byte[] 65536\n        [long]$written = 0\n        while (($count = $zipEntryStream.Read($buffer, 0, $buffer.Length)) -gt 0) {\n          $written += $count\n          if ($written -gt $selected.Length -or $written -gt 33554432) { throw 'ZIP_STREAM_OVERFLOW' }\n          $zipMsiOutput.Write($buffer, 0, $count)\n        }\n        if ($written -ne $selected.Length) { throw 'ZIP_STREAM_TRUNCATED' }\n      } finally { $zipMsiOutput.Dispose() }\n    } finally { $zipEntryStream.Dispose() }\n  } finally { $zip.Dispose() }\n  [Console]::WriteLine('DSH_MSI_ZIP_READY')\n} catch {\n  [Console]::Error.WriteLine('DSH_MSI_ZIP_FAILED')\n  exit 1\n}\n`\n\n// SetupIterateCabinetW notifications and FILE_IN_CABINET_INFO_W follow the Windows SDK:\n// https://learn.microsoft.com/windows/win32/api/setupapi/nf-setupapi-setupiteratecabinetw\n// https://learn.microsoft.com/windows/win32/api/setupapi/ns-setupapi-file_in_cabinet_info_w\n// The callback writes only FullTargetName's inline UTF-16 buffer, never the native name pointer.\nconst READ_MSI_CABINET_FILE = String.raw`\n$ErrorActionPreference = 'Stop'\n$ProgressPreference = 'SilentlyContinue'\ntry {\n  Add-Type -TypeDefinition @'\nusing System;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Text.RegularExpressions;\n[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.System32)]\n\npublic static class DshReadOnlyCabinet {\n  private const uint CabinetInfo = 0x10;\n  private const uint FileInCabinet = 0x11;\n  private const uint NeedNewCabinet = 0x12;\n  private const uint FileExtracted = 0x13;\n  private const uint FileopAbort = 0;\n  private const uint FileopDoit = 1;\n  private const uint FileopSkip = 2;\n  private const uint InvalidData = 13;\n  private const int MaxPath = 260;\n\n  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]\n  private struct FileInCabinetInfo {\n    public IntPtr NameInCabinet;\n    public uint FileSize;\n    public uint Win32Error;\n    public ushort DosDate;\n    public ushort DosTime;\n    public ushort DosAttribs;\n    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MaxPath)]\n    public string FullTargetName;\n  }\n  [StructLayout(LayoutKind.Sequential)]\n  private struct FilePaths {\n    public IntPtr Target;\n    public IntPtr Source;\n    public uint Win32Error;\n    public uint Flags;\n  }\n  [UnmanagedFunctionPointer(CallingConvention.Winapi)]\n  private delegate uint CabinetCallback(IntPtr context, uint notification, IntPtr param1, IntPtr param2);\n  [DllImport(\"setupapi.dll\", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)]\n  [return: MarshalAs(UnmanagedType.Bool)]\n  private static extern bool SetupIterateCabinetW(string cabinet, uint reserved, CabinetCallback callback, IntPtr context);\n\n  public static void Extract(string cabinet, string directory, string wanted, int expectedBytes) {\n    if (!Regex.IsMatch(wanted, @\"\\A[A-Za-z_][A-Za-z0-9_.]{0,71}\\z\") || wanted.Contains(\"..\")\n      || expectedBytes < 1 || !Path.IsPathRooted(cabinet) || !Path.IsPathRooted(directory)) {\n      throw new InvalidDataException(\"CABINET_INPUT_INVALID\");\n    }\n    if (!Directory.Exists(directory) || (File.GetAttributes(directory) & FileAttributes.ReparsePoint) != 0\n      || Directory.GetFileSystemEntries(directory).Length != 0) {\n      throw new InvalidDataException(\"CABINET_DESTINATION_INVALID\");\n    }\n    string target = Path.GetFullPath(Path.Combine(directory, wanted));\n    string source = Path.GetFullPath(cabinet);\n    if (target.Length >= MaxPath || (File.GetAttributes(source) & (FileAttributes.ReparsePoint | FileAttributes.Directory)) != 0) {\n      throw new InvalidDataException(\"CABINET_PATH_INVALID\");\n    }\n    int targetOffset = Marshal.OffsetOf(typeof(FileInCabinetInfo), \"FullTargetName\").ToInt32();\n    if (targetOffset != IntPtr.Size + 14) throw new InvalidDataException(\"CABINET_ABI_INVALID\");\n    int matched = 0;\n    int entries = 0;\n    int cabinets = 0;\n    bool completed = false;\n    bool callbackFailed = false;\n    CabinetCallback callback = delegate(IntPtr context, uint notification, IntPtr param1, IntPtr param2) {\n      try {\n        if (notification == CabinetInfo) {\n          if (++cabinets > 1) throw new InvalidDataException(\"CABINET_CONTINUATION_INVALID\");\n          return 0;\n        }\n        if (notification == NeedNewCabinet) throw new InvalidDataException(\"CABINET_CONTINUATION_INVALID\");\n        if (notification == FileInCabinet) {\n          if (++entries > 4096 || param1 == IntPtr.Zero) throw new InvalidDataException(\"CABINET_ENTRIES_INVALID\");\n          var entry = (FileInCabinetInfo)Marshal.PtrToStructure(param1, typeof(FileInCabinetInfo));\n          string name = Marshal.PtrToStringUni(entry.NameInCabinet);\n          if (!String.Equals(name, wanted, StringComparison.Ordinal)) return FileopSkip;\n          if (++matched != 1 || entry.FileSize != (uint)expectedBytes || entry.Win32Error != 0\n            || (entry.DosAttribs & 0x410) != 0 || File.Exists(target) || Directory.Exists(target)\n            || (File.GetAttributes(directory) & FileAttributes.ReparsePoint) != 0) {\n            throw new InvalidDataException(\"CABINET_MEMBER_INVALID\");\n          }\n          char[] path = new char[MaxPath];\n          target.CopyTo(0, path, 0, target.Length);\n          Marshal.Copy(path, 0, IntPtr.Add(param1, targetOffset), MaxPath);\n          return FileopDoit;\n        }\n        if (notification == FileExtracted) {\n          if (param1 == IntPtr.Zero) throw new InvalidDataException(\"CABINET_RESULT_INVALID\");\n          var result = (FilePaths)Marshal.PtrToStructure(param1, typeof(FilePaths));\n          if (completed || matched != 1 || result.Win32Error != 0\n            || !String.Equals(Marshal.PtrToStringUni(result.Target), target, StringComparison.OrdinalIgnoreCase)\n            || !String.Equals(Marshal.PtrToStringUni(result.Source), source, StringComparison.OrdinalIgnoreCase)) {\n            throw new InvalidDataException(\"CABINET_RESULT_INVALID\");\n          }\n          completed = true;\n          return 0;\n        }\n        throw new InvalidDataException(\"CABINET_NOTIFICATION_INVALID\");\n      } catch (Exception) {\n        callbackFailed = true;\n        return notification == FileInCabinet ? FileopAbort : InvalidData;\n      }\n    };\n    bool success = SetupIterateCabinetW(source, 0, callback, IntPtr.Zero);\n    int error = success ? 0 : Marshal.GetLastWin32Error();\n    GC.KeepAlive(callback);\n    if (callbackFailed || !success || matched != 1 || !completed) {\n      throw new InvalidDataException(\"CABINET_EXTRACTION_FAILED_\" + error);\n    }\n    if (!File.Exists(target) || (File.GetAttributes(target) & (FileAttributes.ReparsePoint | FileAttributes.Directory)) != 0\n      || new FileInfo(target).Length != expectedBytes || Directory.GetFileSystemEntries(directory).Length != 1) {\n      throw new InvalidDataException(\"CABINET_OUTPUT_INVALID\");\n    }\n  }\n}\n'@\n  [DshReadOnlyCabinet]::Extract($env:DSH_CAB_SOURCE, $env:DSH_CAB_DESTINATION, $env:DSH_CAB_MEMBER, [int]$env:DSH_CAB_BYTES)\n  [Console]::WriteLine('DSH_MSI_CABINET_READY')\n} catch {\n  [Console]::Error.WriteLine('DSH_MSI_CABINET_FAILED')\n  exit 1\n}\n`\n\n/** Resolve Windows built-in tools without inheriting a PATH-selected replacement. */\nexport function cpolarWindowsSystemTool(name: 'powershell.exe' | 'tar.exe'): string {\n  const root = process.env.SystemRoot ?? process.env.WINDIR\n  if (root === undefined || !win32.isAbsolute(root) || root.startsWith('\\\\\\\\')) {\n    throw new WindowsMsiExtractionError('tools', 0, 'SYSTEM_ROOT_UNAVAILABLE')\n  }\n  return name === 'powershell.exe'\n    ? win32.join(root, 'System32', 'WindowsPowerShell', 'v1.0', name)\n    : win32.join(root, 'System32', name)\n}\n\nfunction safeCommandDetails(error: unknown): SafeCommandDetails {\n  if (error === null || typeof error !== 'object') return {}\n  let descriptors: PropertyDescriptorMap\n  try { descriptors = Object.getOwnPropertyDescriptors(error) } catch (_error) { return {} }\n  const code: unknown = descriptors.code?.value\n  const signal: unknown = descriptors.signal?.value\n  const killed: unknown = descriptors.killed?.value\n  const deadlineMs: unknown = descriptors.deadlineMs?.value\n  return {\n    ...(code === null || (typeof code === 'number' && Number.isSafeInteger(code))\n      || (typeof code === 'string' && /^[A-Z][A-Z0-9_]{0,63}$/u.test(code)) ? { code } : {}),\n    ...(signal === null || (typeof signal === 'string' && /^SIG[A-Z0-9]{1,16}$/u.test(signal)) ? { signal } : {}),\n    ...(typeof killed === 'boolean' ? { killed } : {}),\n    ...(typeof deadlineMs === 'number' && Number.isSafeInteger(deadlineMs) && deadlineMs >= 0 ? { deadlineMs } : {}),\n  }\n}\n\n/** Execute one system extraction tool with a fixed deadline; distinguish an unavailable executable from a rejected artifact. */\nexport async function runCpolarWindowsTool(name: 'powershell.exe' | 'tar.exe', args: readonly string[],\n  env?: NodeJS.ProcessEnv): Promise<{ stdout: string; stderr: string }> {\n  const started = performance.now()\n  try {\n    return await execFileText(cpolarWindowsSystemTool(name), args, {\n      windowsHide: true, timeout: 120_000, maxBuffer: 16_384, ...(env === undefined ? {} : { env }),\n    })\n  } catch (error) {\n    if (error instanceof WindowsMsiExtractionError) throw error\n    const details = { ...safeCommandDetails(error), deadlineMs: 120_000 }\n    if (details.code === 'ENOENT') throw new WindowsMsiExtractionError('tools', Math.max(0, Math.round(performance.now() - started)), details.code, details)\n    throw Object.assign(new Error('Windows cpolar extraction command failed'), details)\n  }\n}\n\n/** Classify extraction failures without retaining raw command output, arguments or paths. */\nexport async function cpolarWindowsExtractionStep<T>(name: WindowsMsiExtractionStage, operation: () => Promise<T>): Promise<T> {\n  const started = performance.now()\n  try { return await operation() } catch (error) {\n    if (error instanceof WindowsMsiExtractionError) throw error\n    const details = safeCommandDetails(error)\n    throw new WindowsMsiExtractionError(name, Math.max(0, Math.round(performance.now() - started)), details.code, details)\n  }\n}\n\n/**\n * Read the verified Windows ZIP into a fixed MSI file using Unicode-aware .NET paths, without installer actions.\n * @param archive - Absolute path to the pinned, size/hash-verified ZIP.\n * @param destination - Owned, non-linked staging directory for a new installer.msi.\n * @returns Absolute path to the extracted ordinary MSI file.\n */\nexport async function extractWindowsMsiArchive(archive: string, destination: string): Promise<string> {\n  return cpolarWindowsExtractionStep('archive', async () => {\n    if (process.platform !== 'win32' || !isAbsolute(archive) || !isAbsolute(destination)) throw new Error('invalid ZIP input')\n    const parent = await lstat(destination)\n    if (!parent.isDirectory() || parent.isSymbolicLink()) throw new Error('invalid ZIP destination')\n    const msi = join(destination, 'installer.msi')\n    const { stdout } = await runCpolarWindowsTool('powershell.exe', [\n      '-NoLogo', '-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(READ_MSI_ZIP, 'utf16le').toString('base64'),\n    ], { ...process.env, DSH_MSI_ZIP: archive, DSH_MSI_OUTPUT: msi })\n    if (stdout.trim() !== 'DSH_MSI_ZIP_READY') throw new Error('invalid ZIP reader output')\n    const info = await lstat(msi)\n    if (!info.isFile() || info.isSymbolicLink() || info.size < 1 || info.size > 33_554_432) throw new Error('invalid extracted MSI')\n    return msi\n  })\n}\n\n/** Read one executable from an embedded MSI cabinet; never execute installer actions or alter system installation state. */\nexport async function extractWindowsMsiBinary(msi: string, destination: string, executableName: string, expectedBytes: number): Promise<void> {\n  if (process.platform !== 'win32' || !isAbsolute(msi) || !isAbsolute(destination)\n    || !/^[A-Za-z0-9_-]+\\.exe$/u.test(executableName) || !Number.isSafeInteger(expectedBytes) || expectedBytes < 1) {\n    throw new WindowsMsiExtractionError('file', 0, 'INPUT_INVALID')\n  }\n  const cabinet = join(destination, 'component.cab')\n  const extracted = join(destination, 'cabinet')\n  const metadata = await cpolarWindowsExtractionStep('database', async () => {\n    const { stdout } = await runCpolarWindowsTool('powershell.exe', [\n      '-NoLogo', '-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(READ_MSI_CABINET, 'utf16le').toString('base64'),\n    ], { ...process.env, DSH_MSI_SOURCE: msi, DSH_MSI_CABINET: cabinet, DSH_MSI_BINARY: executableName, DSH_MSI_BYTES: String(expectedBytes) })\n    const value: unknown = JSON.parse(stdout.trim())\n    if (value === null || typeof value !== 'object' || !('Member' in value) || typeof value.Member !== 'string'\n      || !/^[A-Za-z_][A-Za-z0-9_.]{0,71}$/u.test(value.Member) || value.Member.includes('..')\n      || !('Bytes' in value) || value.Bytes !== expectedBytes || !('CabinetBytes' in value)\n      || typeof value.CabinetBytes !== 'number' || !Number.isSafeInteger(value.CabinetBytes)\n      || value.CabinetBytes < 36 || value.CabinetBytes > 33_554_432) throw new Error('invalid cabinet metadata')\n    const info = await lstat(cabinet)\n    if (!info.isFile() || info.isSymbolicLink() || info.size !== value.CabinetBytes) throw new Error('invalid cabinet file')\n    return { member: value.Member, cabinetBytes: value.CabinetBytes }\n  })\n  await cpolarWindowsExtractionStep('cabinet', async () => {\n    await mkdir(extracted, { mode: 0o700 })\n    const { stdout } = await runCpolarWindowsTool('powershell.exe', [\n      '-NoLogo', '-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(READ_MSI_CABINET_FILE, 'utf16le').toString('base64'),\n    ], { ...process.env, DSH_CAB_SOURCE: cabinet, DSH_CAB_DESTINATION: extracted,\n      DSH_CAB_MEMBER: metadata.member, DSH_CAB_BYTES: String(expectedBytes) })\n    if (stdout.trim() !== 'DSH_MSI_CABINET_READY') throw new Error('invalid cabinet reader output')\n  })\n  await cpolarWindowsExtractionStep('file', async () => {\n    const entries = await readdir(extracted)\n    if (entries.length !== 1 || entries[0] !== metadata.member) throw new Error('unexpected cabinet members')\n    const binary = join(extracted, metadata.member)\n    const info = await lstat(binary)\n    if (!info.isFile() || info.isSymbolicLink() || info.size !== expectedBytes) throw new Error('invalid extracted binary')\n    await copyFile(binary, join(destination, executableName))\n  })\n}\n","import { createHash, randomBytes } from 'node:crypto'\nimport { execFile } from 'node:child_process'\nimport {\n  chmod,\n  copyFile,\n  lstat,\n  mkdir,\n  mkdtemp,\n  readFile,\n  readdir,\n  writeFile,\n} from 'node:fs/promises'\nimport { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path'\nimport { downloadPinnedArtifact } from './component-download.js'\nimport { restrictPrivateFile } from './private-file.js'\nimport { cpolarWindowsExtractionStep, cpolarWindowsSystemTool, extractWindowsMsiArchive, extractWindowsMsiBinary } from './windows-msi-extract.js'\nimport { assertManagedParents, ensureManagedDirectory, removeManagedPaths, removeManagedTree, renameManagedPath, writeManagedPrivateFile } from './managed-files.js'\n\n/** Pinned cpolar components fetched only after an explicit user action. */\ninterface CpolarArtifact {\n  readonly version: string\n  readonly platform: NodeJS.Platform\n  readonly arch: string\n  readonly downloadUrl: string\n  readonly downloadBytes: number\n  readonly downloadSha256: string\n  readonly executableName: string\n  readonly executableBytes: number\n  readonly executableSha256: string\n  /** Windows ships an MSI inside a zip; Linux ships the binary in a tarball. */\n  readonly archiveKind: 'msi-zip' | 'tar.gz'\n}\n\nconst CPOLAR_VERSION = '3.3.18'\n\nconst releases = [\n  {\n    version: CPOLAR_VERSION,\n    platform: 'win32',\n    arch: 'x64',\n    downloadUrl: `https://www.cpolar.com/static/downloads/releases/${CPOLAR_VERSION}/cpolar-stable-windows-amd64-setup.zip`,\n    downloadBytes: 7_603_505,\n    downloadSha256: 'fb8cf60289058ee26079f995d2eeea0b21768a742d90c93015afe96e83428830',\n    executableName: 'cpolar.exe',\n    executableBytes: 19_637_680,\n    executableSha256: 'b2d865ee505e842d22ceca5493a872efa893a79b079a7a8ee2bd3aa5343a5c41',\n    archiveKind: 'msi-zip',\n  },\n  {\n    version: CPOLAR_VERSION,\n    platform: 'linux',\n    arch: 'x64',\n    downloadUrl: `https://www.cpolar.com/static/downloads/releases/${CPOLAR_VERSION}/cpolar-stable-linux-amd64.tar.gz`,\n    downloadBytes: 7_404_781,\n    downloadSha256: '5cd3320c4369928ccb509c4f5fa2ec3b86151ead77e1b77c1694aa64c43e32e7',\n    executableName: 'cpolar',\n    executableBytes: 19_328_632,\n    executableSha256: 'c076e1109372a3f88031841c5989030e49b6871b54aee3260c796da9122dec05',\n    archiveKind: 'tar.gz',\n  },\n  {\n    version: CPOLAR_VERSION,\n    platform: 'linux',\n    arch: 'arm64',\n    downloadUrl: `https://www.cpolar.com/static/downloads/releases/${CPOLAR_VERSION}/cpolar-stable-linux-arm64.tar.gz`,\n    downloadBytes: 6_855_666,\n    downloadSha256: '8a61a97983f18ae5ffb4b8bac4c9b3d8e2399a6ee101844e7b0b30d7f326157c',\n    executableName: 'cpolar',\n    executableBytes: 19_017_169,\n    executableSha256: '8d76a1b7e518df45f387f107c7a428079c67ecd9b971a2915c53b947ea9b443a',\n    archiveKind: 'tar.gz',\n  },\n] as const satisfies readonly CpolarArtifact[]\n\n/** Pinned official cpolar release metadata for supported desktop targets. */\nexport const CPOLAR_COMPONENT_RELEASES: Readonly<Record<string, CpolarArtifact>> = Object.freeze(Object.fromEntries(\n  releases.map(release => [`${release.platform}-${release.arch}`, Object.freeze(release)]),\n))\n\n/**\n * Canonical release metadata. New code should select from\n * {@link CPOLAR_COMPONENT_RELEASES} by platform and architecture; this alias\n * preserves the original Windows x64 entry for existing callers.\n */\nexport const CPOLAR_COMPONENT_RELEASE = CPOLAR_COMPONENT_RELEASES['win32-x64'] as CpolarArtifact\n\nconst DOWNLOAD_PAGE = 'https://www.cpolar.com/download'\nconst SIGNUP_URL = 'https://dashboard.cpolar.com/signup'\nconst DASHBOARD_URL = 'https://dashboard.cpolar.com/auth'\nconst TERMS_URL = 'https://www.cpolar.com/tos'\n\n/** Public, credential-free description of the managed cpolar component. */\nexport interface CpolarComponentStatus {\n  readonly supported: boolean\n  readonly installed: boolean\n  readonly configured: boolean\n  readonly version: string\n  readonly downloadBytes: number\n  readonly installedBytes: number\n  readonly sourceUrl: string\n  readonly downloadPage: string\n  readonly signupUrl: string\n  readonly dashboardUrl: string\n  readonly termsUrl: string\n  readonly storagePath: string\n  readonly errorCode?: string\n}\n\ninterface CpolarComponentManagerOptions {\n  readonly stateDirectory: string\n  readonly platform?: NodeJS.Platform\n  readonly arch?: string\n  readonly fetchArtifact?: (url: string, signal: AbortSignal) => Promise<Uint8Array>\n  readonly extractArtifact?: (archive: string, destination: string) => Promise<void>\n}\n\nfunction inside(parent: string, child: string): boolean {\n  const candidate = relative(parent, child)\n  return candidate !== '' && !candidate.startsWith('..') && !isAbsolute(candidate)\n}\n\nasync function sha256(file: string): Promise<string> {\n  return createHash('sha256').update(await readFile(file)).digest('hex')\n}\n\nasync function regularFile(file: string, expectedBytes?: number): Promise<boolean> {\n  try {\n    const stat = await lstat(file)\n    return stat.isFile() && !stat.isSymbolicLink() && (expectedBytes === undefined || stat.size === expectedBytes)\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false\n    throw error\n  }\n}\n\ntype InstallFailureCode = 'cpolar_download_failed' | 'cpolar_extract_failed' | 'cpolar_storage_failed'\n\nasync function installStep<T>(code: InstallFailureCode, operation: () => Promise<T>): Promise<T> {\n  try {\n    return await operation()\n  } catch (error) {\n    if (error instanceof Error && error.message.startsWith('cpolar_')) throw error\n    throw new Error(code, { cause: error })\n  }\n}\n\nasync function pathExists(path: string): Promise<boolean> {\n  try {\n    await lstat(path)\n    return true\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false\n    throw error\n  }\n}\n\ninterface CpolarPublishOperations {\n  readonly move?: (from: string, to: string) => Promise<void>\n  readonly remove?: (path: string) => Promise<void>\n}\n\n/** Replace only this version's verified binary, retaining the previous directory until promotion succeeds. */\nexport async function publishVerifiedCpolarExecutable(\n  extracted: string,\n  componentRoot: string,\n  componentStorage: string,\n  executableName: string,\n  operations: CpolarPublishOperations = {},\n): Promise<void> {\n  if (dirname(componentStorage) !== componentRoot || !inside(componentRoot, componentStorage)\n    || basename(executableName) !== executableName || executableName === '.' || executableName === '..') {\n    throw new Error('cpolar component storage escaped its private root')\n  }\n  const move = async (from: string, to: string): Promise<void> => {\n    await assertManagedParents(componentRoot, from, 'cpolar')\n    await assertManagedParents(componentRoot, to, 'cpolar')\n    if (operations.move === undefined) await renameManagedPath(componentRoot, from, to, 'cpolar')\n    else await operations.move(from, to)\n  }\n  const remove = operations.remove ?? (path => removeManagedTree(componentRoot, path, 'cpolar'))\n  const candidate = join(componentRoot, `.install-${randomBytes(12).toString('hex')}`)\n  const backup = join(componentRoot, `.previous-${randomBytes(12).toString('hex')}`)\n  let backupContainsPrevious = false\n  let replacementInstalled = false\n  try {\n    await ensureManagedDirectory(componentRoot, candidate, 'cpolar')\n    await copyFile(extracted, join(candidate, executableName))\n    await chmod(join(candidate, executableName), 0o700)\n    if (await pathExists(componentStorage)) {\n      await move(componentStorage, backup)\n      backupContainsPrevious = true\n    }\n    try {\n      await move(candidate, componentStorage)\n      replacementInstalled = true\n    } catch (error) {\n      if (backupContainsPrevious) {\n        try {\n          await move(backup, componentStorage)\n          backupContainsPrevious = false\n        } catch (rollbackError) {\n          process.emitWarning(`cpolar previous component remains at ${backup}; automatic rollback failed`, {\n            code: 'DSH_MOBILE_CPOLAR_ROLLBACK_FAILED',\n          })\n          throw new Error('cpolar_storage_failed', { cause: new AggregateError([error, rollbackError]) })\n        }\n      }\n      throw error\n    }\n  } finally {\n    try {\n      await remove(candidate)\n    } catch {\n      process.emitWarning(`cpolar temporary component remains at ${candidate}; cleanup failed`, {\n        code: 'DSH_MOBILE_CPOLAR_CLEANUP_FAILED',\n      })\n    }\n    if (replacementInstalled && backupContainsPrevious) {\n      try {\n        await remove(backup)\n      } catch {\n        process.emitWarning(`cpolar previous component remains at ${backup}; cleanup failed`, {\n          code: 'DSH_MOBILE_CPOLAR_CLEANUP_FAILED',\n        })\n      }\n    }\n  }\n}\n\n/** Remove only this install's staging directory without replacing a preceding failure. */\nexport async function cleanupCpolarInstallStaging(\n  staging: string,\n  installFailed: boolean,\n  remove: (path: string) => Promise<void> = path => removeManagedTree(dirname(path), path, 'cpolar'),\n): Promise<void> {\n  try {\n    await remove(staging)\n  } catch (error) {\n    if (installFailed) {\n      process.emitWarning(`cpolar staging directory remains at ${staging}; cleanup failed`, {\n        code: 'DSH_MOBILE_CPOLAR_CLEANUP_FAILED',\n      })\n      return\n    }\n    throw new Error('cpolar_storage_failed', { cause: error })\n  }\n}\n\nasync function run(file: string, args: readonly string[]): Promise<void> {\n  await new Promise<void>((resolveRun, reject) => {\n    execFile(file, [...args], { windowsHide: true, timeout: 120_000 }, (error) => {\n      if (error === null) resolveRun()\n      else reject(error)\n    })\n  })\n}\n\nasync function defaultFetchArtifact(\n  url: string,\n  signal: AbortSignal,\n  expectedBytes: number,\n): Promise<Uint8Array> {\n  return downloadPinnedArtifact({\n    url,\n    expectedBytes,\n    errorPrefix: 'cpolar',\n    signal,\n  })\n}\n\nasync function extractWindowsMsi(archive: string, destination: string, executableName: string, expectedBytes: number): Promise<void> {\n  if (process.platform !== 'win32') throw new Error('cpolar_component_unsupported')\n  const unpacked = join(destination, 'archive')\n  await cpolarWindowsExtractionStep('archive', () => mkdir(unpacked, { mode: 0o700 }))\n  const msi = await extractWindowsMsiArchive(archive, unpacked)\n  await extractWindowsMsiBinary(msi, destination, executableName, expectedBytes)\n}\n\nasync function extractLinuxTarball(archive: string, destination: string, executableName: string): Promise<void> {\n  const unpacked = join(destination, 'archive')\n  await mkdir(unpacked, { recursive: true, mode: 0o700 })\n  // The Linux tarball carries the binary at its root; no installer involved.\n  await run(process.platform === 'win32' ? cpolarWindowsSystemTool('tar.exe') : 'tar', ['-xzf', archive, '-C', unpacked])\n  const archiveEntries = await readdir(unpacked, { recursive: true })\n  const executableRelative = archiveEntries.find(entry => basename(entry).toLowerCase() === executableName.toLowerCase())\n  if (executableRelative === undefined) throw new Error('cpolar_executable_missing')\n  await copyFile(join(unpacked, executableRelative), join(destination, executableName))\n}\n\nasync function defaultExtractArtifact(archive: string, destination: string, release: CpolarArtifact): Promise<void> {\n  if (release.archiveKind === 'tar.gz') return extractLinuxTarball(archive, destination, release.executableName)\n  return extractWindowsMsi(archive, destination, release.executableName, release.executableBytes)\n}\n\n/** Validate a cpolar Authtoken before it crosses the durable-file boundary. */\nexport function validateCpolarAuthtoken(value: unknown): string {\n  if (typeof value !== 'string' || value.length < 20 || value.length > 512\n    || /[\\s\\u0000-\\u001f\\u007f]/u.test(value)) {\n    throw new Error('cpolar_authtoken_invalid')\n  }\n  return value\n}\n\n/** Owns the optional cpolar binary and account configuration inside DSH Mobile state. */\nexport class CpolarComponentManager {\n  readonly executable: string\n  readonly configFile: string\n  readonly componentRoot: string\n  readonly componentStorage: string\n  readonly stateRoot: string\n  readonly logRoot: string\n  private readonly stagingRoot: string\n  private readonly stateDirectory: string\n  private readonly platform: NodeJS.Platform\n  private readonly arch: string\n  private readonly release: CpolarArtifact | undefined\n  private readonly fetchArtifact: (url: string, signal: AbortSignal) => Promise<Uint8Array>\n  private readonly extractArtifact: (archive: string, destination: string) => Promise<void>\n  private installed = false\n  private configured = false\n  private errorCode: string | undefined\n  private queue: Promise<void> = Promise.resolve()\n\n  constructor(options: CpolarComponentManagerOptions) {\n    if (!isAbsolute(options.stateDirectory)) throw new Error('cpolar state directory must be absolute')\n    const stateDirectory = resolve(options.stateDirectory)\n    this.stateDirectory = stateDirectory\n    this.platform = options.platform ?? process.platform\n    this.arch = options.arch ?? process.arch\n    this.release = CPOLAR_COMPONENT_RELEASES[`${this.platform}-${this.arch}`]\n    this.componentRoot = join(stateDirectory, 'components', 'cpolar')\n    this.componentStorage = join(this.componentRoot, this.release?.version ?? CPOLAR_VERSION)\n    this.executable = join(this.componentStorage, this.release?.executableName ?? 'cpolar')\n    this.stateRoot = join(stateDirectory, 'state', 'cpolar')\n    this.configFile = join(this.stateRoot, 'cpolar.yml')\n    this.logRoot = join(stateDirectory, 'logs', 'cpolar')\n    this.stagingRoot = join(stateDirectory, 'staging', 'cpolar')\n    for (const child of [this.componentRoot, this.componentStorage, this.stateRoot, this.logRoot, this.stagingRoot]) {\n      if (!inside(stateDirectory, child)) throw new Error('cpolar component path escaped its state directory')\n    }\n    const release = this.release\n    this.fetchArtifact = options.fetchArtifact\n      ?? ((url, signal) => defaultFetchArtifact(url, signal, release?.downloadBytes ?? 0))\n    this.extractArtifact = options.extractArtifact\n      ?? ((archive, destination) => {\n        if (release === undefined) throw new Error('cpolar_component_unsupported')\n        return defaultExtractArtifact(archive, destination, release)\n      })\n  }\n\n  /** Inspect the managed binary and configuration without using global cpolar state. */\n  async initialize(): Promise<void> {\n    const release = this.release\n    this.installed = false\n    this.configured = false\n    this.errorCode = undefined\n    try {\n      await assertManagedParents(this.stateDirectory, this.executable, 'cpolar')\n      await assertManagedParents(this.stateDirectory, this.configFile, 'cpolar')\n      this.installed = release !== undefined && await regularFile(this.executable, release.executableBytes)\n      if (this.installed && release !== undefined && await sha256(this.executable) !== release.executableSha256) {\n        this.installed = false\n        this.errorCode = 'cpolar_component_invalid'\n      }\n      this.configured = await regularFile(this.configFile)\n      if (this.configured) await restrictPrivateFile(this.configFile)\n    } catch (_error) {\n      this.installed = false\n      this.configured = false\n      this.errorCode = 'cpolar_component_invalid'\n    }\n  }\n\n  /** Return a safe status that never includes the account token. */\n  status(): CpolarComponentStatus {\n    // Unsupported hosts still report the canonical entry so the panel can show\n    // what would be installed elsewhere; `supported` carries the actual gate.\n    const release = this.release ?? CPOLAR_COMPONENT_RELEASE\n    return Object.freeze({\n      supported: this.release !== undefined,\n      installed: this.installed,\n      configured: this.configured,\n      version: release.version,\n      downloadBytes: release.downloadBytes,\n      installedBytes: release.executableBytes,\n      sourceUrl: release.downloadUrl,\n      downloadPage: DOWNLOAD_PAGE,\n      signupUrl: SIGNUP_URL,\n      dashboardUrl: DASHBOARD_URL,\n      termsUrl: TERMS_URL,\n      storagePath: this.componentRoot,\n      ...(this.errorCode === undefined ? {} : { errorCode: this.errorCode }),\n    })\n  }\n\n  /** Download and verify cpolar, reading archive data without running installer actions. */\n  install(): Promise<CpolarComponentStatus> {\n    return this.enqueue(async () => {\n      const release = this.release\n      if (release === undefined) throw new Error('cpolar_component_unsupported')\n      await assertManagedParents(this.stateDirectory, this.executable, 'cpolar')\n      const staging = await installStep('cpolar_storage_failed', async () => {\n        await ensureManagedDirectory(this.stateDirectory, this.stagingRoot, 'cpolar')\n        return mkdtemp(join(this.stagingRoot, 'install-'))\n      })\n      let installFailed = false\n      try {\n        const controller = new AbortController()\n        const timeout = setTimeout(() => { controller.abort() }, 120_000)\n        timeout.unref()\n        let bytes: Uint8Array\n        try {\n          bytes = await installStep('cpolar_download_failed', () => this.fetchArtifact(release.downloadUrl, controller.signal))\n        } catch (error) {\n          if (controller.signal.aborted) throw new Error('cpolar_download_timeout', { cause: error })\n          throw error\n        } finally { clearTimeout(timeout) }\n        const digest = createHash('sha256').update(bytes).digest('hex')\n        if (digest !== release.downloadSha256) throw new Error('cpolar_download_hash_mismatch')\n        const archive = join(staging, release.archiveKind === 'tar.gz' ? 'cpolar.tar.gz' : 'cpolar.zip')\n        await installStep('cpolar_storage_failed', () => writeFile(archive, bytes, { flag: 'wx', mode: 0o600 }))\n        await installStep('cpolar_extract_failed', () => this.extractArtifact(archive, staging))\n        const extracted = join(staging, release.executableName)\n        const valid = await installStep('cpolar_extract_failed', async () => (\n          await regularFile(extracted, release.executableBytes)\n          && await sha256(extracted) === release.executableSha256\n        ))\n        if (!valid) {\n          throw new Error('cpolar_executable_hash_mismatch')\n        }\n        await installStep('cpolar_storage_failed', async () => {\n          await ensureManagedDirectory(this.stateDirectory, this.componentRoot, 'cpolar')\n          await assertManagedParents(this.stateDirectory, this.executable, 'cpolar')\n          await publishVerifiedCpolarExecutable(extracted, this.componentRoot, this.componentStorage, release.executableName)\n        })\n        this.installed = true\n        this.errorCode = undefined\n      } catch (error) {\n        installFailed = true\n        try {\n          await assertManagedParents(this.stateDirectory, this.executable, 'cpolar')\n          this.installed = await regularFile(this.executable, release.executableBytes)\n            && await sha256(this.executable) === release.executableSha256\n        } catch (_inspectionError) {\n          this.installed = false\n        }\n        throw error\n      } finally {\n        await cleanupCpolarInstallStaging(staging, installFailed, path => removeManagedTree(this.stateDirectory, path, 'cpolar'))\n      }\n    })\n  }\n\n  /** Store only the cpolar token in a private, self-update-disabled configuration. */\n  configure(authtoken: unknown): Promise<CpolarComponentStatus> {\n    return this.enqueue(async () => {\n      const token = validateCpolarAuthtoken(authtoken)\n      const body = `authtoken: ${JSON.stringify(token)}\\nconsole_ui: false\\nupdate: false\\ninspect_db_size: -1\\n`\n      await writeManagedPrivateFile(this.stateDirectory, this.configFile, body, 'cpolar')\n      this.configured = true\n      this.errorCode = undefined\n    })\n  }\n\n  /** Remove every cpolar file owned by DSH Mobile without touching global state. */\n  purge(): Promise<CpolarComponentStatus> {\n    return this.enqueue(async () => {\n      await removeManagedPaths(this.stateDirectory, [this.componentRoot, this.stateRoot, this.logRoot, this.stagingRoot], 'cpolar')\n      this.installed = false\n      this.configured = false\n      this.errorCode = undefined\n    })\n  }\n\n  private enqueue(operation: () => Promise<void>): Promise<CpolarComponentStatus> {\n    const task = this.queue.then(operation, operation)\n    this.queue = task.then(() => undefined, () => undefined)\n    return task.then(() => this.status())\n  }\n}\n","/** Loopback-only HTTP vhost port used between Caddy and frps. */\nexport const FRP_VHOST_HTTP_PORT = 7080\n\n/** Caddy snippet owned entirely by DSH Mobile; the main Caddyfile only imports it. */\nexport const FRP_CADDY_SNIPPET_PATH = '/etc/caddy/dsh-mobile-dsh.caddy'\n\n/** First line of the owned snippet; also the legacy whole-file marker. */\nexport const FRP_CADDY_SNIPPET_MARKER = '# Managed by DSH Mobile - snippet, safe to delete'\n\n/** Exact line the main Caddyfile must contain (uncommented) for the site to load. */\nexport const FRP_CADDY_IMPORT_LINE = `import ${FRP_CADDY_SNIPPET_PATH}`\n\n/** Directory holding the public-IPv4 certificates installed by certbot. */\nexport const FRP_CADDY_IP_CERT_DIR = '/var/lib/caddy/dsh-mobile-certs'\n\n/**\n * Entry TLS mode for the FRP channel.\n *\n * - `public-ip-cert` (default): the VPS Caddy terminates TLS with a public-CA\n *   certificate and reverse-proxies the plaintext vhost to frps.\n * - `self-signed`: no Caddy and no public certificate at all. frps publishes a\n *   raw TCP proxy and the DSH gateway terminates TLS itself with a leaf signed\n *   by its own pairing CA, which the Android app pins through `ca.cer`.\n */\nexport type FrpEntryTls = 'public-ip-cert' | 'self-signed'\n\n/** Optional overrides for the generated Caddy site; every field defaults to the upstream value. */\nexport interface CaddySiteOptions {\n  readonly certDir?: string\n  /**\n   * The user's real `vhostHTTPPort`. `attach` mode must never assume the\n   * upstream 7080: a wrong port silently disables the plaintext-exposure gate.\n   */\n  readonly vhostHttpPort?: number\n  /** `self-signed` is a TCP passthrough and never produces a Caddy site. */\n  readonly entryTls?: FrpEntryTls\n}\n\nfunction publicIpv4Address(value: string): boolean {\n  const parts = value.split('.')\n  return parts.length === 4 && parts.every(part => /^(?:0|[1-9][0-9]{0,2})$/u.test(part)\n    && Number(part) <= 255)\n}\n\nfunction publicDnsHostname(value: string): boolean {\n  return value.length <= 253 && value.includes('.') && !/^[0-9.]+$/u.test(value)\n    && !value.includes(':') && value.split('.').every(label => label.length >= 1 && label.length <= 63\n      && /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u.test(label))\n}\n\nfunction parsePublicOrigin(publicOrigin: string): string {\n  let url: URL\n  try { url = new URL(publicOrigin) } catch { throw new Error('frp_template_input_invalid') }\n  if (url.protocol !== 'https:' || url.port !== '' || url.pathname !== '/' || url.search !== '' || url.hash !== ''\n    || url.username !== '' || url.password !== '' || (!publicIpv4Address(url.hostname) && !publicDnsHostname(url.hostname))) {\n    throw new Error('frp_template_input_invalid')\n  }\n  return url.hostname\n}\n\nfunction resolveVhostHttpPort(options: CaddySiteOptions): number {\n  const port = options.vhostHttpPort ?? FRP_VHOST_HTTP_PORT\n  if (!Number.isSafeInteger(port) || port < 1 || port > 65_535) throw new Error('frp_template_input_invalid')\n  return port\n}\n\n/**\n * A self-signed entry deliberately never reaches Caddy: the tunnel is a raw TCP\n * passthrough and the DSH gateway is the TLS endpoint. Refuse loudly instead of\n * emitting a Caddy site that would need the gateway's private CA on the VPS.\n */\nfunction rejectSelfSignedCaddySite(options: CaddySiteOptions): void {\n  if (options.entryTls === 'self-signed') throw new Error('frp_entry_tls_invalid')\n}\n\n/**\n * Build the Caddy site for one public host (without markers or import wiring).\n *\n * The second parameter accepts either a bare certificate directory (the legacy\n * signature) or a full {@link CaddySiteOptions} object, so existing callers keep\n * working unchanged.\n */\nexport function createCaddySite(publicHost: string, options: CaddySiteOptions | string = {}): string {\n  const resolved: CaddySiteOptions = typeof options === 'string' ? { certDir: options } : options\n  rejectSelfSignedCaddySite(resolved)\n  const certDir = resolved.certDir ?? FRP_CADDY_IP_CERT_DIR\n  const vhostHttpPort = resolveVhostHttpPort(resolved)\n  if (publicIpv4Address(publicHost)) {\n    return [\n      '{',\n      `  default_sni ${publicHost}`,\n      '}',\n      '',\n      `http://${publicHost} {`,\n      `  redir https://${publicHost}{uri} permanent`,\n      '}',\n      '',\n      `https://${publicHost} {`,\n      `  tls ${certDir}/fullchain.pem ${certDir}/privkey.pem`,\n      `  reverse_proxy 127.0.0.1:${String(vhostHttpPort)}`,\n      '}',\n      '',\n    ].join('\\n')\n  }\n  if (!publicDnsHostname(publicHost)) throw new Error('frp_template_input_invalid')\n  return [\n    `${publicHost} {`,\n    `  reverse_proxy 127.0.0.1:${String(vhostHttpPort)}`,\n    '}',\n    '',\n  ].join('\\n')\n}\n\n/** Manual certbot steps for a public-IPv4 origin (Caddy cannot issue IP certificates itself). */\nexport function manualIpCertificateGuide(publicHost: string): string {\n  return [\n    '# Public-IPv4 manual HTTPS: Caddy cannot issue IP certificates by itself.',\n    '# On the VPS (Ubuntu/Debian, port 80 reachable from the internet), run once as root:',\n    '#   apt-get install -y python3-venv',\n    '#   python3 -m venv /opt/dsh-mobile/certbot-venv',\n    \"#   /opt/dsh-mobile/certbot-venv/bin/pip install 'certbot==5.8.0'\",\n    '#   systemctl stop caddy || true',\n    `#   /opt/dsh-mobile/certbot-venv/bin/certbot certonly --standalone --preferred-profile shortlived --ip-address ${publicHost} --agree-tos --register-unsafely-without-email --non-interactive --keep-until-expiring`,\n    '#   install -d -m 0750 -o caddy -g caddy /var/lib/caddy/dsh-mobile-certs',\n    `#   install -m 0640 -o caddy -g caddy /etc/letsencrypt/live/${publicHost}/fullchain.pem /var/lib/caddy/dsh-mobile-certs/fullchain.pem`,\n    `#   install -m 0640 -o caddy -g caddy /etc/letsencrypt/live/${publicHost}/privkey.pem /var/lib/caddy/dsh-mobile-certs/privkey.pem`,\n    '#   systemctl start caddy',\n    '# The site below already references those paths. Certificates last about 6 days: re-run certonly before expiry.',\n    '#',\n  ].join('\\n')\n}\n\n/**\n * Build the only supported frps config and Caddy snippet from validated user inputs.\n *\n * Default `options` reproduce the upstream artefact byte for byte; `attach` mode\n * passes the user's real vhost port, and `self-signed` is rejected because that\n * mode publishes a raw TCP proxy instead of an HTTP vhost.\n */\nexport function createRestrictedFrpServerTemplate(\n  serverPort: number,\n  token: string,\n  publicOrigin: string,\n  options: CaddySiteOptions = {},\n): string {\n  if (!Number.isSafeInteger(serverPort) || serverPort < 1 || serverPort > 65_535\n    || token.length < 16 || token.length > 512 || /[\\s\\u0000-\\u001f\\u007f]/u.test(token)) {\n    throw new Error('frp_template_input_invalid')\n  }\n  rejectSelfSignedCaddySite(options)\n  const vhostHttpPort = resolveVhostHttpPort(options)\n  const certDir = options.certDir ?? FRP_CADDY_IP_CERT_DIR\n  const publicHost = parsePublicOrigin(publicOrigin)\n  const lines = [\n    '# frps.toml — save as /etc/dsh-mobile/frps.toml, then start the frps service.',\n    `bindPort = ${String(serverPort)}`,\n    'proxyBindAddr = \"127.0.0.1\"',\n    `vhostHTTPPort = ${String(vhostHttpPort)}`,\n    'auth.method = \"token\"',\n    `auth.token = ${JSON.stringify(token)}`,\n    '',\n    `# Caddy — save the site below as ${FRP_CADDY_SNIPPET_PATH},`,\n    '# then make sure your Caddyfile contains exactly this line at the TOP of the file',\n    '# (create the file with just this line if needed; globals must precede sites):',\n    `#   ${FRP_CADDY_IMPORT_LINE}`,\n    '# finally run: caddy validate --config /etc/caddy/Caddyfile && systemctl reload caddy',\n    '# Uninstall later removes only this snippet file and the import line; your own Caddy content is kept.',\n    `${FRP_CADDY_SNIPPET_MARKER}`,\n    createCaddySite(publicHost, { certDir, vhostHttpPort }).trimEnd(),\n    '',\n  ]\n  if (publicIpv4Address(publicHost)) lines.push(manualIpCertificateGuide(publicHost), '')\n  return lines.join('\\n')\n}","import { isIP } from './ip.js'\nimport { lstat, readFile } from 'node:fs/promises'\nimport { isAbsolute, join, resolve } from 'node:path'\nimport { isGloballyRoutableIpv4 } from './network.js'\nimport { restrictPrivateFile } from './private-file.js'\nimport { assertManagedParents, removeManagedPaths, removeManagedTree, writeManagedPrivateFile } from './managed-files.js'\nimport { createRestrictedFrpServerTemplate, FRP_VHOST_HTTP_PORT, type FrpEntryTls } from './frp-template.js'\n\nconst MAX_SETTINGS_BYTES = 8 * 1024\n\n/** How the restricted FRP channel is provisioned on the VPS. */\nexport type FrpMode = 'deploy' | 'attach'\n\n/** Public entry port used by the self-signed TCP passthrough (never 443 by requirement). */\nexport const FRP_DEFAULT_PUBLIC_PORT = 33_080\n\n/** Ports owned by other DSH Mobile listeners; the public entry may never reuse them. */\nexport const FRP_RESERVED_PORTS: readonly number[] = Object.freeze([3080, 3443, 3444])\n\n/** Every key `settings.json` may contain. Unknown keys stay rejected. */\nconst FRP_SETTINGS_KEYS: ReadonlySet<string> = new Set([\n  'version', 'serverAddress', 'serverPort', 'token', 'publicOrigin',\n  'mode', 'entryTls', 'vhostHttpPort', 'publicPort',\n])\n\n/** Credentials and endpoints required by the restricted FRP provider. */\nexport interface FrpSettings {\n  readonly version: 1\n  readonly serverAddress: string\n  readonly serverPort: number\n  readonly token: string\n  readonly publicOrigin: string\n  /**\n   * `deploy` (default) installs the plugin's own frps on the VPS.\n   * `attach` reuses an frps that already runs there and never touches it.\n   */\n  readonly mode?: FrpMode\n  /** `public-ip-cert` (default) or the gateway-terminated `self-signed` passthrough. */\n  readonly entryTls?: FrpEntryTls\n  /** The real `vhostHTTPPort` of the user's frps; defaults to the upstream 7080. */\n  readonly vhostHttpPort?: number\n  /** Public entry port of the self-signed TCP proxy; defaults to 33080. */\n  readonly publicPort?: number\n}\n\n/** Safe FRP configuration fields returned to the desktop UI. */\nexport interface FrpConfigurationStatus {\n  readonly configured: boolean\n  readonly serverAddress?: string\n  readonly serverPort?: number\n  readonly publicOrigin?: string\n  readonly vhostHttpPort: number\n  readonly storagePath: string\n  /** Proxy name frpc registers on the shared frps; unique per DSH installation. */\n  readonly proxyName: string\n  readonly errorCode?: string\n  /** Present only when the saved configuration leaves the upstream `deploy` default. */\n  readonly mode?: FrpMode\n  /** Present only when the saved configuration uses the self-signed entry. */\n  readonly entryTls?: FrpEntryTls\n  /** Present only when a non-default public entry port is saved. */\n  readonly publicPort?: number\n}\n\nfunction hostname(value: string): boolean {\n  if (value.length > 253 || !value.includes('.')) return false\n  return value.split('.').every(label => label.length >= 1 && label.length <= 63\n    && /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u.test(label))\n}\n\n/** Validate the FRP server hostname or IP address. */\nexport function validateFrpServerAddress(value: unknown): string {\n  if (typeof value !== 'string' || value !== value.trim() || value.length === 0 || value.length > 253\n    || /[\\s\\u0000-\\u001f\\u007f/\\\\@?#]/u.test(value)) throw new Error('frp_server_address_invalid')\n  const normalized = value.toLowerCase().replace(/\\.$/u, '')\n  if (isIP(normalized) === 0 && !hostname(normalized)) throw new Error('frp_server_address_invalid')\n  return normalized\n}\n\n/** Validate the FRP control port. */\nexport function validateFrpServerPort(value: unknown): number {\n  if (!Number.isSafeInteger(value) || Number(value) < 1 || Number(value) > 65_535) {\n    throw new Error('frp_server_port_invalid')\n  }\n  return Number(value)\n}\n\n/** Validate a high-entropy FRP token before durable storage. */\nexport function validateFrpToken(value: unknown): string {\n  if (typeof value !== 'string' || value.length < 16 || value.length > 512\n    || /[\\s\\u0000-\\u001f\\u007f]/u.test(value)) throw new Error('frp_token_invalid')\n  return value\n}\n\n/** Validate the public HTTPS origin used by Caddy and Android pairing. */\nexport function validateFrpPublicOrigin(value: unknown): string {\n  if (typeof value !== 'string' || value.length > 512) throw new Error('frp_public_origin_invalid')\n  let url: URL\n  try { url = new URL(value) } catch { throw new Error('frp_public_origin_invalid') }\n  const publicHost = url.hostname\n  if (url.protocol !== 'https:' || url.port !== '' || url.pathname !== '/' || url.search !== '' || url.hash !== ''\n    || url.username !== '' || url.password !== '' || (isIP(publicHost) !== 4 && !hostname(publicHost))) {\n    throw new Error('frp_public_origin_invalid')\n  }\n  // Documentation and other non-routable IPv4 literals (e.g. 203.0.113.10)\n  // can never be a real VPS endpoint; reject them instead of deploying certs.\n  if (isIP(publicHost) === 4 && !isGloballyRoutableIpv4(publicHost)) throw new Error('frp_public_origin_invalid')\n  return url.origin\n}\n\n/** Validate the provisioning mode. */\nexport function validateFrpMode(value: unknown): FrpMode {\n  if (value !== 'deploy' && value !== 'attach') throw new Error('frp_settings_invalid')\n  return value\n}\n\n/** Validate the entry TLS mode. */\nexport function validateFrpEntryTls(value: unknown): FrpEntryTls {\n  if (value !== 'public-ip-cert' && value !== 'self-signed') throw new Error('frp_entry_tls_invalid')\n  return value\n}\n\nfunction validatePort(value: unknown, rejectReserved: boolean): number {\n  if (!Number.isSafeInteger(value) || Number(value) < 1 || Number(value) > 65_535) {\n    throw new Error('frp_settings_invalid')\n  }\n  const port = Number(value)\n  if (rejectReserved && FRP_RESERVED_PORTS.includes(port)) throw new Error('frp_settings_invalid')\n  return port\n}\n\n/** Validate the loopback vhost port of the target frps. */\nexport function validateFrpVhostHttpPort(value: unknown): number {\n  return validatePort(value, false)\n}\n\n/** Validate the public entry port of the self-signed TCP proxy. */\nexport function validateFrpPublicPort(value: unknown): number {\n  return validatePort(value, true)\n}\n\n/** Effective provisioning mode; an absent field keeps the upstream behaviour. */\nexport function resolveFrpMode(settings: FrpSettings): FrpMode {\n  return settings.mode ?? 'deploy'\n}\n\n/** Effective entry TLS mode; an absent field keeps the upstream behaviour. */\nexport function resolveFrpEntryTls(settings: FrpSettings): FrpEntryTls {\n  return settings.entryTls ?? 'public-ip-cert'\n}\n\n/** Effective loopback vhost port; an absent field keeps the upstream behaviour. */\nexport function resolveFrpVhostHttpPort(settings: FrpSettings): number {\n  return settings.vhostHttpPort ?? FRP_VHOST_HTTP_PORT\n}\n\n/** Effective public entry port of the self-signed passthrough. */\nexport function resolveFrpPublicPort(settings: FrpSettings): number {\n  return settings.publicPort ?? FRP_DEFAULT_PUBLIC_PORT\n}\n\n/** Public HTTPS endpoint the user opens, independent of the frps control address. */\nexport function resolveFrpEntryProbe(settings: FrpSettings): { host: string; port: number } {\n  const origin = new URL(frpEntryOrigin(settings))\n  return { host: origin.hostname, port: origin.port === '' ? 443 : Number(origin.port) }\n}\n\n/** HTTPS origin users actually open; the self-signed TCP entry is not on 443. */\nexport function frpEntryOrigin(settings: FrpSettings): string {\n  if (!isFrpSelfSignedIngress(settings)) return settings.publicOrigin\n  return `https://${new URL(settings.publicOrigin).hostname}:${String(resolveFrpPublicPort(settings))}`\n}\n\n/** True when the gateway terminates TLS itself behind a raw frps TCP proxy. */\nexport function isFrpSelfSignedIngress(settings: FrpSettings): boolean {\n  return resolveFrpEntryTls(settings) === 'self-signed'\n}\n\n/**\n * Parse FRP settings at the loopback request and filesystem boundaries.\n *\n * Optional keys are kept only when supplied, so a legacy `settings.json` still\n * round-trips byte for byte and every default stays the upstream behaviour.\n * Two cross-field rules are enforced here because neither can be recovered later:\n * the self-signed entry is a TCP passthrough and therefore attach-only, and\n * attach mode with a public-CA entry must state the user's real vhost port —\n * silently assuming 7080 would disable the plaintext-exposure gate.\n */\nexport function parseFrpSettings(value: unknown): FrpSettings {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('frp_settings_invalid')\n  const record = value as Record<string, unknown>\n  if (Reflect.ownKeys(record).some(key => !FRP_SETTINGS_KEYS.has(String(key)))) {\n    throw new Error('frp_settings_invalid')\n  }\n  if (record.version !== undefined && record.version !== 1) throw new Error('frp_settings_invalid')\n  const mode = record.mode === undefined ? undefined : validateFrpMode(record.mode)\n  const entryTls = record.entryTls === undefined ? undefined : validateFrpEntryTls(record.entryTls)\n  const vhostHttpPort = record.vhostHttpPort === undefined ? undefined : validateFrpVhostHttpPort(record.vhostHttpPort)\n  const publicPort = record.publicPort === undefined ? undefined : validateFrpPublicPort(record.publicPort)\n  const resolvedMode = mode ?? 'deploy'\n  const resolvedEntryTls: FrpEntryTls = entryTls ?? 'public-ip-cert'\n  if (resolvedEntryTls === 'self-signed' && resolvedMode !== 'attach') throw new Error('frp_entry_tls_invalid')\n  if (resolvedMode === 'attach' && resolvedEntryTls === 'public-ip-cert' && vhostHttpPort === undefined) {\n    throw new Error('frp_attach_mode_requires_vhost_port')\n  }\n  const publicOrigin = validateFrpPublicOrigin(record.publicOrigin)\n  if (resolvedEntryTls === 'self-signed' && isIP(new URL(publicOrigin).hostname) !== 4) {\n    throw new Error('frp_self_signed_requires_public_ipv4')\n  }\n  return Object.freeze({\n    version: 1,\n    serverAddress: validateFrpServerAddress(record.serverAddress),\n    serverPort: validateFrpServerPort(record.serverPort),\n    token: validateFrpToken(record.token),\n    publicOrigin,\n    ...(mode === undefined ? {} : { mode }),\n    ...(entryTls === undefined ? {} : { entryTls }),\n    ...(vhostHttpPort === undefined ? {} : { vhostHttpPort }),\n    ...(publicPort === undefined ? {} : { publicPort }),\n  })\n}\n\n/**\n * Merge a partial VPS request body with the saved configuration so a blank\n * field keeps its saved value (\"已保存时可留空\"). Every merged field is still\n * validated; with nothing saved and nothing supplied the result reports a\n * missing configuration instead of silently deploying blanks.\n */\nexport function mergeSavedFrpSettings(\n  partial: Readonly<Record<string, unknown>>,\n  saved: FrpSettings | undefined,\n): FrpSettings {\n  const pick = <K extends 'mode' | 'entryTls' | 'vhostHttpPort' | 'publicPort'>(key: K): unknown => {\n    const supplied = partial[key]\n    if (supplied === '' || supplied === undefined) return saved?.[key]\n    return supplied\n  }\n  const mode = pick('mode')\n  const entryTls = pick('entryTls')\n  const vhostHttpPort = pick('vhostHttpPort')\n  const publicPort = pick('publicPort')\n  const merged = {\n    serverAddress: partial.serverAddress === '' || partial.serverAddress === undefined\n      ? saved?.serverAddress : partial.serverAddress,\n    serverPort: typeof partial.serverPort === 'number' && Number.isSafeInteger(partial.serverPort) && partial.serverPort >= 1\n      ? partial.serverPort : saved?.serverPort,\n    token: partial.token === '' || partial.token === undefined ? saved?.token : partial.token,\n    publicOrigin: partial.publicOrigin === '' || partial.publicOrigin === undefined\n      ? saved?.publicOrigin : partial.publicOrigin,\n    ...(mode === '' || mode === undefined ? {} : { mode }),\n    ...(entryTls === '' || entryTls === undefined ? {} : { entryTls }),\n    ...(vhostHttpPort === '' || vhostHttpPort === undefined ? {} : { vhostHttpPort }),\n    ...(publicPort === '' || publicPort === undefined ? {} : { publicPort }),\n  }\n  if (merged.serverAddress === undefined && merged.serverPort === undefined\n    && merged.token === undefined && merged.publicOrigin === undefined) {\n    throw new Error('frp_config_missing')\n  }\n  return parseFrpSettings(merged)\n}\n\n/** Merge a VPS target (address and control port) with the saved configuration. */\nexport function mergeSavedFrpTarget(\n  partial: Readonly<Record<string, unknown>>,\n  saved: FrpSettings | undefined,\n): { readonly serverAddress: string; readonly serverPort: number } {\n  const serverAddress = partial.serverAddress === '' || partial.serverAddress === undefined\n    ? saved?.serverAddress : partial.serverAddress\n  const serverPort = typeof partial.serverPort === 'number' && Number.isSafeInteger(partial.serverPort) && partial.serverPort >= 1\n    ? partial.serverPort : saved?.serverPort\n  if (serverAddress === undefined || serverPort === undefined) throw new Error('frp_config_missing')\n  return Object.freeze({\n    serverAddress: validateFrpServerAddress(serverAddress),\n    serverPort: validateFrpServerPort(serverPort),\n  })\n}\n\nfunction tomlString(value: string): string {\n  return JSON.stringify(value)\n}\n\n/**\n * Legacy proxy name, kept only as the default of {@link createFrpcToml}.\n *\n * A shared frps accepts one proxy per name across *all* its clients, so a fixed\n * name let any other DSH installation — or a not yet reaped session of this one —\n * own `dsh-mobile` first. frpc then logged `start error: proxy name [dsh-mobile]\n * is already in use`, kept running without publishing the entry port, and the\n * start-up self-check ended in `frp_start_timeout` (\"the public endpoint did not\n * become ready\"). Product callers therefore pass an installation-derived name\n * from {@link frpProxyName}; this constant only keeps the exported API and the\n * byte-for-byte compatibility test working for legacy callers.\n */\nexport const FRP_DEFAULT_PROXY_NAME = 'dsh-mobile'\n\n/**\n * Validate a proxy name for the generated frpc configuration.\n *\n * frps accepts one proxy per name on the whole server, so the name must be a\n * single safe token: no whitespace, no quotes, no path or bracket characters.\n */\nexport function validateFrpProxyName(value: unknown): string {\n  if (typeof value !== 'string' || value.length < 1 || value.length > 128\n    || !/^[A-Za-z0-9._-]+$/u.test(value)) throw new Error('frp_proxy_name_invalid')\n  return value\n}\n\n/**\n * Proxy name for one DSH installation.\n *\n * Derived from the stable installation identity so two computers sharing one\n * frps never register the same proxy, while a single installation keeps the\n * same name across restarts (so its own stale registration is the only possible\n * conflict, and that one expires with the frps heartbeat).\n */\nexport function frpProxyName(instanceId: string): string {\n  if (typeof instanceId !== 'string' || !/^[a-f0-9]{64}$/u.test(instanceId)) throw new Error('frp_instance_id_invalid')\n  return `${FRP_DEFAULT_PROXY_NAME}-${instanceId.slice(0, 12)}`\n}\n\n/**\n * Build the single-purpose frpc configuration for the current loopback gateway.\n *\n * The default (public-CA) entry is an HTTP vhost behind Caddy and is emitted byte\n * for byte as before. The self-signed entry cannot use a vhost at all: frps only\n * forwards raw TCP, and the gateway terminates TLS on that connection.\n *\n * `proxyName` defaults to the legacy fixed name only for legacy callers; the\n * provider and the attach preview always pass {@link frpProxyName}.\n */\nexport function createFrpcToml(\n  settings: FrpSettings,\n  localPort: number,\n  proxyName: string = FRP_DEFAULT_PROXY_NAME,\n): string {\n  if (!Number.isSafeInteger(localPort) || localPort < 1 || localPort > 65_535) throw new Error('frp_local_port_invalid')\n  const header = [\n    `serverAddr = ${tomlString(settings.serverAddress)}`,\n    `serverPort = ${String(settings.serverPort)}`,\n    'auth.method = \"token\"',\n    `auth.token = ${tomlString(settings.token)}`,\n    'transport.tls.enable = true',\n    '',\n    '[[proxies]]',\n    `name = ${tomlString(validateFrpProxyName(proxyName))}`,\n  ]\n  if (isFrpSelfSignedIngress(settings)) {\n    return [\n      ...header,\n      // Raw TCP passthrough: frps never terminates or inspects TLS. The DSH\n      // gateway terminates it and the app pins the gateway CA instead of any\n      // public certificate authority.\n      'type = \"tcp\"',\n      'localIP = \"127.0.0.1\"',\n      `localPort = ${String(localPort)}`,\n      `remotePort = ${String(resolveFrpPublicPort(settings))}`,\n      'transport.useEncryption = true',\n      'transport.useCompression = true',\n      '',\n    ].join('\\n')\n  }\n  const hostnameValue = new URL(settings.publicOrigin).hostname\n  return [\n    ...header,\n    'type = \"http\"',\n    'localIP = \"127.0.0.1\"',\n    `localPort = ${String(localPort)}`,\n    `customDomains = [${tomlString(hostnameValue)}]`,\n    'transport.useEncryption = true',\n    'transport.useCompression = true',\n    '',\n  ].join('\\n')\n}\n\n/** Build the matching restricted frps and Caddy templates for one VPS. */\nexport function createFrpServerTemplate(settings: FrpSettings): string {\n  return createRestrictedFrpServerTemplate(settings.serverPort, settings.token, settings.publicOrigin, {\n    vhostHttpPort: resolveFrpVhostHttpPort(settings),\n    entryTls: resolveFrpEntryTls(settings),\n  })\n}\n\n/** Owns private FRP settings and generation-specific frpc configuration. */\nexport class FrpConfigStore {\n  readonly stateRoot: string\n  readonly settingsFile: string\n  readonly runtimeConfigFile: string\n  /**\n   * Proxy name every generated frpc.toml registers.\n   *\n   * Injected by the composing plugin ({@link frpProxyName}) so one frps can\n   * serve several DSH installations; the legacy fixed name stays the default\n   * for direct constructions in tests and for the exported API.\n   */\n  readonly proxyName: string\n  private settingsValue: FrpSettings | undefined\n  private errorCode: string | undefined\n\n  constructor(stateDirectory: string, proxyName: string = FRP_DEFAULT_PROXY_NAME, private readonly ownedRoot = stateDirectory) {\n    if (!isAbsolute(stateDirectory)) throw new Error('frp config state directory must be absolute')\n    this.stateRoot = resolve(stateDirectory)\n    this.settingsFile = join(this.stateRoot, 'settings.json')\n    this.runtimeConfigFile = join(this.stateRoot, 'frpc.toml')\n    this.proxyName = validateFrpProxyName(proxyName)\n  }\n\n  /** Load private settings while rejecting links, oversized files, and unknown fields. */\n  async initialize(): Promise<void> {\n    this.settingsValue = undefined\n    this.errorCode = undefined\n    try { await assertManagedParents(this.ownedRoot, this.settingsFile, 'frp') } catch (_error) {\n      this.errorCode = 'frp_config_invalid'\n      return\n    }\n    let entry\n    try { entry = await lstat(this.settingsFile) } catch (error) {\n      if ((error as NodeJS.ErrnoException).code === 'ENOENT') return\n      throw error\n    }\n    if (!entry.isFile() || entry.isSymbolicLink() || entry.size > MAX_SETTINGS_BYTES) {\n      this.errorCode = 'frp_config_invalid'\n      return\n    }\n    await restrictPrivateFile(this.settingsFile)\n    try {\n      this.settingsValue = parseFrpSettings(JSON.parse(await readFile(this.settingsFile, 'utf8')) as unknown)\n      this.errorCode = undefined\n    } catch {\n      this.settingsValue = undefined\n      this.errorCode = 'frp_config_invalid'\n    }\n  }\n\n  /**\n   * Return configuration metadata without exposing the FRP token.\n   *\n   * The optional keys appear only when the saved configuration departs from the\n   * upstream defaults, so the pre-existing field set is unchanged for every\n   * legacy configuration.\n   */\n  status(): FrpConfigurationStatus {\n    const settings = this.settingsValue\n    const mode = settings === undefined ? undefined : resolveFrpMode(settings)\n    const entryTls = settings === undefined ? undefined : resolveFrpEntryTls(settings)\n    return Object.freeze({\n      configured: settings !== undefined,\n      ...(settings === undefined ? {} : {\n        serverAddress: settings.serverAddress,\n        serverPort: settings.serverPort,\n        publicOrigin: settings.publicOrigin,\n      }),\n      vhostHttpPort: settings === undefined ? FRP_VHOST_HTTP_PORT : resolveFrpVhostHttpPort(settings),\n      storagePath: this.stateRoot,\n      proxyName: this.proxyName,\n      ...(this.errorCode === undefined ? {} : { errorCode: this.errorCode }),\n      ...(mode === undefined || mode === 'deploy' ? {} : { mode }),\n      ...(entryTls === undefined || entryTls === 'public-ip-cert' ? {} : { entryTls }),\n      ...(settings?.publicPort === undefined ? {} : { publicPort: settings.publicPort }),\n    })\n  }\n\n  /** Return private settings only to the provider lifecycle. */\n  settings(): FrpSettings | undefined {\n    return this.settingsValue\n  }\n\n  /** Atomically replace private FRP settings. */\n  async configure(value: unknown): Promise<FrpConfigurationStatus> {\n    const settings = parseFrpSettings(value)\n    await writeManagedPrivateFile(this.ownedRoot, this.settingsFile, `${JSON.stringify(settings)}\\n`, 'frp')\n    await removeManagedTree(this.ownedRoot, this.runtimeConfigFile, 'frp')\n    this.settingsValue = settings\n    this.errorCode = undefined\n    return this.status()\n  }\n\n  /** Materialize the private generation-specific frpc configuration. */\n  async writeRuntimeConfig(localPort: number): Promise<string> {\n    const settings = this.settingsValue\n    if (settings === undefined) throw new Error('frp_config_missing')\n    await writeManagedPrivateFile(this.ownedRoot, this.runtimeConfigFile, createFrpcToml(settings, localPort, this.proxyName), 'frp')\n    return this.runtimeConfigFile\n  }\n\n  /** Remove only configuration files owned by the FRP provider. */\n  async purge(): Promise<FrpConfigurationStatus> {\n    await removeManagedPaths(this.ownedRoot, [this.settingsFile, this.runtimeConfigFile], 'frp')\n    this.settingsValue = undefined\n    this.errorCode = undefined\n    return this.status()\n  }\n}\n\nexport { FRP_VHOST_HTTP_PORT as DEFAULT_VHOST_HTTP_PORT }\nexport type { FrpEntryTls } from './frp-template.js'\n","import { isIP } from './ip.js'\nimport {\n  createFrpcToml,\n  FRP_DEFAULT_PROXY_NAME,\n  isFrpSelfSignedIngress,\n  resolveFrpMode,\n  resolveFrpPublicPort,\n  resolveFrpVhostHttpPort,\n  type FrpSettings,\n} from './frp-config.js'\nimport {\n  createCaddySite,\n  FRP_CADDY_IMPORT_LINE,\n  FRP_CADDY_SNIPPET_MARKER,\n  FRP_CADDY_SNIPPET_PATH,\n  manualIpCertificateGuide,\n} from './frp-template.js'\n\n/** Default proof path used to confirm the public entry answered from this computer. */\nexport const FRP_ATTACH_DISCOVERY_PATH = '/mobile-access/discovery'\n\n/** Declaration printed above the VPS half of an attach template. */\nexport const FRP_ATTACH_VPS_DECLARATION = '# 本模板不安装、不改动、不重启你的 frps；只新增 Caddy 片段与证书。'\n  + 'frps 侧需你自行确认 vhostHTTPPort=<N> 与 proxyBindAddr=\"127.0.0.1\"。'\n\n/** Declaration printed above the local half of an attach template. */\nexport const FRP_ATTACH_LOCAL_DECLARATION = '# 本机只写入 frpc.toml 并启动 frpc：不安装、不改动本机 frps，也不改动 DSH 自身配置。'\n\n/** Declaration for the self-signed passthrough, which keeps its CA on this computer. */\nexport const FRP_ATTACH_SELF_SIGNED_DECLARATION = '# 自签穿透档不使用 Caddy 或公开证书：'\n  + 'frps 只做 TCP 透传，由本机 DSH 网关终止 TLS；服务端证书会在运行时续签，CA 到期需重新配对。'\n\n/** Optional inputs for attach artefacts; every field falls back to the validated settings. */\nexport interface FrpAttachOptions {\n  readonly vhostHttpPort?: number\n  readonly publicPort?: number\n  readonly certDir?: string\n  /** Absolute path of the plugin-written frpc.toml, used for the `frpc verify` self-check. */\n  readonly configFile?: string\n  /**\n   * Proxy name the previewed frpc.toml registers.\n   *\n   * Defaults to the legacy fixed name; the panel and the provider pass the\n   * installation-derived {@link frpProxyName} so a preview never describes a\n   * registration that would collide on a shared frps.\n   */\n  readonly proxyName?: string\n  /** Loopback port the gateway will listen on; only a placeholder inside the copied runbook. */\n  readonly localPort?: number\n  /**\n   * Explicit reveal of the shared token inside previews and clipboard copies.\n   *\n   * Defaults to `false`: every artefact the panel produces on its own stays\n   * masked, because the copied text lands in the system clipboard. Only the\n   * panel's dedicated \"copy the frpc.toml with its token\" action sets this, and\n   * the result never reaches a stored state, a log, or localStorage.\n   */\n  readonly revealToken?: boolean\n}\n\n/** Fixed placeholder that replaces the shared token in every preview or copied artefact. */\nexport const FRP_ATTACH_TOKEN_PLACEHOLDER = '***'\n\n/**\n * One-line notice printed above the masked frpc.toml preview.\n *\n * It states both facts a reader cannot verify from the text itself: the real\n * file is written with 0600 permissions, and an unmasked copy would survive in\n * the system clipboard.\n */\nexport function frpAttachTokenMaskNotice(configFile: string): string {\n  return `# 预览已打码：真正的 frpc.toml 已由插件以 0600 权限写入 ${configFile}；`\n    + '明文 token 不打码会随复制进入系统剪贴板，故此处只显示占位符。'\n}\n\n/** One-line notice printed above an explicitly revealed frpc.toml preview. */\nexport const FRP_ATTACH_TOKEN_REVEAL_NOTICE = '# 明文 token 已按你的显式操作显示：'\n  + '复制后即进入系统剪贴板并长期留存，请勿粘贴到公开位置。'\n\n/** Matches the single `auth.token` assignment of a generated frpc.toml. */\nconst FRPC_TOKEN_ASSIGNMENT = /^auth\\.token\\s*=\\s*\"(?:[^\"\\\\]|\\\\.)*\"/mu\n\n/**\n * Replace the `auth.token` value of a rendered frpc.toml with a fixed placeholder.\n *\n * Only the preview and clipboard paths call this: the file written to disk keeps\n * the real token, because frpc has to read it. The mapping never fails open — a\n * token line that cannot be masked raises instead of leaking the secret.\n */\nexport function redactFrpcTomlToken(frpcToml: string): string {\n  if (!/(^|\\n)auth\\.token/u.test(frpcToml)) return frpcToml\n  const masked = frpcToml.replace(FRPC_TOKEN_ASSIGNMENT, `auth.token = \"${FRP_ATTACH_TOKEN_PLACEHOLDER}\"`)\n  if (!masked.includes(`auth.token = \"${FRP_ATTACH_TOKEN_PLACEHOLDER}\"`)) throw new Error('frp_token_mask_failed')\n  return masked\n}\n\n/**\n * The frpc.toml exactly as the panel displays or copies it.\n *\n * `options.revealToken` is the only way to obtain the plaintext variant; the\n * default is the masked text. `createFrpcToml` itself is untouched, so the file\n * the provider writes stays byte-for-byte identical to the upstream output.\n */\nexport function createFrpAttachFrpcToml(settings: FrpSettings, options: FrpAttachOptions = {}): string {\n  const frpcToml = createFrpcToml(\n    settings,\n    attachLocalPort(options),\n    options.proxyName ?? FRP_DEFAULT_PROXY_NAME,\n  )\n  return options.revealToken === true ? frpcToml : redactFrpcTomlToken(frpcToml)\n}\n\n/** The two separated halves of the attach artefact, plus their combined text. */\nexport interface FrpAttachTemplate {\n  readonly mode: 'attach'\n  readonly vps: string\n  readonly local: string\n  readonly text: string\n}\n\nconst DEFAULT_ATTACH_CONFIG_FILE = '<DSH Mobile 私有目录>/remote/frp/config/frpc.toml'\n\nfunction attachConfigFile(options: FrpAttachOptions): string {\n  const file = options.configFile\n  if (file === undefined || file === '') return DEFAULT_ATTACH_CONFIG_FILE\n  return file\n}\n\nfunction attachLocalPort(options: FrpAttachOptions): number {\n  const port = options.localPort ?? 3443\n  if (!Number.isSafeInteger(port) || port < 1 || port > 65_535) throw new Error('frp_local_port_invalid')\n  return port\n}\n\n/**\n * Reject every attach request that could not be carried out safely before any\n * artefact is produced. Attach never installs frps, so it must know the user's\n * real vhost port (unless the self-signed passthrough removes the vhost entirely).\n */\nexport function validateAttachSettings(settings: FrpSettings, options: FrpAttachOptions = {}): void {\n  if (resolveFrpMode(settings) !== 'attach') throw new Error('frp_settings_invalid')\n  if (isFrpSelfSignedIngress(settings)) {\n    if (settings.mode !== 'attach') throw new Error('frp_entry_tls_invalid')\n    resolveFrpPublicPort(settings)\n    return\n  }\n  const vhostHttpPort = options.vhostHttpPort ?? settings.vhostHttpPort\n  if (vhostHttpPort === undefined) throw new Error('frp_attach_mode_requires_vhost_port')\n  if (!Number.isSafeInteger(vhostHttpPort) || vhostHttpPort < 1 || vhostHttpPort > 65_535) {\n    throw new Error('frp_settings_invalid')\n  }\n}\n\n/** Strip the leading `# ` of a guide block so it can be pasted as runnable shell. */\nfunction guideCommands(guide: string): string[] {\n  return guide\n    .split('\\n')\n    .map(line => line.replace(/^#\\s?/u, '').trimEnd())\n    .filter(line => line !== '')\n}\n\n/** Shared VPS-side inputs of both the copied runbook and the panel plan. */\nexport interface FrpAttachVpsParts {\n  readonly publicHost: string\n  readonly selfSigned: boolean\n  readonly vhostHttpPort?: number\n  readonly publicPort?: number\n  readonly snippet: string\n  readonly certGuide: readonly string[]\n}\n\n/**\n * Derive every VPS-side value once so the copied runbook and the panel plan can\n * never drift apart.\n */\nexport function frpAttachVpsParts(settings: FrpSettings, options: FrpAttachOptions = {}): FrpAttachVpsParts {\n  validateAttachSettings(settings, options)\n  const publicHost = new URL(settings.publicOrigin).hostname\n  if (isFrpSelfSignedIngress(settings)) {\n    return Object.freeze({\n      publicHost,\n      selfSigned: true,\n      publicPort: resolveFrpPublicPort(settings),\n      snippet: '',\n      certGuide: Object.freeze([] as string[]),\n    })\n  }\n  const vhostHttpPort = options.vhostHttpPort ?? resolveFrpVhostHttpPort(settings)\n  const certDir = options.certDir\n  const site = createCaddySite(publicHost, {\n    vhostHttpPort,\n    ...(certDir === undefined ? {} : { certDir }),\n  })\n  return Object.freeze({\n    publicHost,\n    selfSigned: false,\n    vhostHttpPort,\n    snippet: `${FRP_CADDY_SNIPPET_MARKER}\\n${site.trimEnd()}\\n`,\n    certGuide: Object.freeze(isIP(publicHost) === 4 ? guideCommands(manualIpCertificateGuide(publicHost)) : []),\n  })\n}\n\n/**\n * Build the attach artefact for an existing frps.\n *\n * The result is deliberately split in two: the VPS half contains only what the\n * user's own server needs (Caddy snippet + import + certificate guidance, or a\n * single firewall rule for the self-signed passthrough), and the local half\n * contains the generated frpc.toml plus its `frpc verify` self-check. Neither\n * half installs, rewrites, or restarts the user's frps.\n */\nexport function createFrpAttachTemplateParts(\n  settings: FrpSettings,\n  options: FrpAttachOptions = {},\n): FrpAttachTemplate {\n  const parts = frpAttachVpsParts(settings, options)\n  const configFile = attachConfigFile(options)\n  const revealed = options.revealToken === true\n  const frpcToml = createFrpAttachFrpcToml(settings, options)\n  const local = [\n    '# ---- (b) 本机侧（在这台电脑上执行）----',\n    FRP_ATTACH_LOCAL_DECLARATION,\n    revealed ? FRP_ATTACH_TOKEN_REVEAL_NOTICE : frpAttachTokenMaskNotice(configFile),\n    `# frpc.toml 全文（插件同样会以 0600 权限写入 ${configFile}）`,\n    frpcToml.trimEnd(),\n    '',\n    '# 启动前自检：',\n    `frpc verify -c \"${configFile}\"`,\n    '',\n  ].join('\\n')\n\n  if (parts.selfSigned) {\n    const publicPort = parts.publicPort ?? resolveFrpPublicPort(settings)\n    const vps = [\n      '# ---- (a) VPS 侧（在你的服务器上执行，共 3 项）----',\n      FRP_ATTACH_SELF_SIGNED_DECLARATION,\n      '#',\n      '# 1) 放行公网入口端口（就是这台电脑网关的 HTTPS 入口，TCP 透传不解密）：',\n      `ufw allow ${String(publicPort)}/tcp`,\n      `ufw status | grep ${String(publicPort)}`,\n      '# 若使用 firewalld / 云厂商安全组，请放行同样的 TCP 端口。',\n      '# 前提：现有 frps 的 TCP 代理已监听公网地址；若 proxyBindAddr=127.0.0.1，放行防火墙仍无法从公网访问。',\n      '# 插件不会修改你现有的 frps；不满足此前提时请改选受信任证书入口。',\n      '#',\n      '# 2) 确认你既有的 frps 已就绪（无需修改它的配置）：',\n      'systemctl is-active frps || true',\n      `ss -lnt | grep -E ':(${String(settings.serverPort)}|${String(publicPort)})\\\\b' || true`,\n      '#',\n      '# 3) frpc 启动后，用 -k 检查连通性；此命令不验证身份，App 配对后会固定网关 CA：',\n      `curl -k -sS -o /dev/null -w '%{http_code}\\\\n' https://${parts.publicHost}:${String(publicPort)}${FRP_ATTACH_DISCOVERY_PATH}`,\n      '# 期望输出 200。',\n      '',\n    ].join('\\n')\n    return Object.freeze({\n      mode: 'attach' as const,\n      vps,\n      local,\n      text: `${vps}${local}`,\n    })\n  }\n\n  const vps = [\n    '# ---- (a) VPS 侧（在你的服务器上执行）----',\n    FRP_ATTACH_VPS_DECLARATION,\n    '#',\n    `# 1) 保存 Caddy 片段到 ${FRP_CADDY_SNIPPET_PATH}（只新增这一个文件）：`,\n    `cat > ${FRP_CADDY_SNIPPET_PATH} <<'DSH_MOBILE_CADDY_SNIPPET'`,\n    parts.snippet.trimEnd(),\n    'DSH_MOBILE_CADDY_SNIPPET',\n    '#',\n    '# 2) 确认 Caddyfile 顶部含下面这一行（全局块必须在前；没有则加到文件最上方）：',\n    `#   ${FRP_CADDY_IMPORT_LINE}`,\n    'caddy validate --config /etc/caddy/Caddyfile && systemctl reload caddy',\n    '#',\n    ...(parts.certGuide.length === 0\n      ? ['# 3) 域名 HTTPS：确认 DNS 指向 VPS，开放 80/443；Caddy 会自动申请和续期证书。']\n      : [\n          '# 3) 公网 IP 的 HTTPS 证书（Caddy 不能为 IP 自动签发，故用 certbot 签发）：',\n          ...parts.certGuide.map(line => `#   ${line}`),\n          '#',\n          '# 4) 确认证书续期任务，并在续期后将新证书安装到 Caddy：',\n          'systemctl list-timers certbot.timer --all || true',\n        ]),\n    '#',\n    '# 端到端验证（公网入口为 443，与 frps 的 vhost 端口无关）：',\n    `curl -sS -o /dev/null -w '%{http_code}\\\\n' https://${parts.publicHost}${FRP_ATTACH_DISCOVERY_PATH}`,\n    '# 期望输出 200。',\n    '',\n  ].join('\\n')\n  return Object.freeze({\n    mode: 'attach' as const,\n    vps,\n    local,\n    text: `${vps}${local}`,\n  })\n}\n\n/** Combined attach artefact, ready for the clipboard. */\nexport function createFrpAttachTemplate(settings: FrpSettings, options: FrpAttachOptions = {}): string {\n  return createFrpAttachTemplateParts(settings, options).text\n}\n","import {\n  resolveFrpEntryTls,\n  isFrpSelfSignedIngress,\n  type FrpEntryTls,\n  type FrpSettings,\n} from './frp-config.js'\nimport {\n  FRP_ATTACH_DISCOVERY_PATH,\n  FRP_ATTACH_LOCAL_DECLARATION,\n  FRP_ATTACH_SELF_SIGNED_DECLARATION,\n  FRP_ATTACH_VPS_DECLARATION,\n  createFrpAttachFrpcToml,\n  frpAttachVpsParts,\n  type FrpAttachOptions,\n} from './frp-attach.js'\nimport { FRP_CADDY_IMPORT_LINE, FRP_CADDY_SNIPPET_PATH } from './frp-template.js'\n\n/** Stable step identifiers; the panel maps each one to a translated title. */\nexport type FrpAttachStepId =\n  | 'write-snippet'\n  | 'add-import'\n  | 'issue-ip-cert'\n  | 'enable-cert-timer'\n  | 'verify-https'\n  | 'open-public-port'\n  | 'verify-frps'\n  | 'verify-entry'\n\n/** One actionable VPS-side step; `title` is a message key, `label` the copied text. */\nexport interface FrpAttachPlanStep {\n  readonly id: FrpAttachStepId\n  readonly title: string\n  readonly label: string\n  readonly commands: readonly string[]\n  readonly optional: boolean\n  readonly verifyHint: string\n}\n\n/** The local half of the plan: the exact frpc.toml plus its self-check command. */\nexport interface FrpAttachPlanLocal {\n  /** The frpc.toml as previewed: masked unless the caller explicitly revealed the token. */\n  readonly frpcToml: string\n  /** True when `frpcToml` carries the fixed placeholder instead of the shared token. */\n  readonly tokenMasked: boolean\n  readonly verifyCommand: string\n  readonly configFile: string\n  readonly declaration: string\n}\n\n/** Zero-SSH plan for attaching to an frps the user already runs. */\nexport interface FrpAttachPlan {\n  readonly mode: 'attach'\n  readonly entryTls: FrpEntryTls\n  readonly vhostHttpPort?: number\n  readonly publicPort?: number\n  readonly local: FrpAttachPlanLocal\n  readonly vps: readonly FrpAttachPlanStep[]\n  readonly warnings: readonly string[]\n}\n\nconst DEFAULT_PLAN_CONFIG_FILE = '<DSH Mobile 私有目录>/remote/frp/config/frpc.toml'\n\nfunction planConfigFile(options: FrpAttachOptions): string {\n  const file = options.configFile\n  return file === undefined || file === '' ? DEFAULT_PLAN_CONFIG_FILE : file\n}\n\n/**\n * Build the copy-only attach plan. It performs no network access, no SSH, and no\n * filesystem write: the caller renders or copies the steps and the local frpc\n * configuration is written by the ordinary provider lifecycle.\n */\nexport function createFrpAttachPlan(settings: FrpSettings, options: FrpAttachOptions = {}): FrpAttachPlan {\n  const parts = frpAttachVpsParts(settings, options)\n  const configFile = planConfigFile(options)\n  const localPort = options.localPort ?? 3443\n  // The plan is a preview structure: it stays masked unless the panel's explicit\n  // reveal action asked for the plaintext variant.\n  const frpcToml = createFrpAttachFrpcToml(settings, { ...options, localPort })\n  const tokenMasked = options.revealToken !== true\n  const verifyCommand = `frpc verify -c \"${configFile}\"`\n  const commonWarnings: string[] = [\n    '本机探测 ≠ 公网验证：请在外部（手机流量或另一台机器）再执行一次 VPS 侧清单里的 curl 验证。',\n    '插件不会安装、不会改动、不会重启你既有的 frps，也不会改动 Caddyfile 里的其他内容。',\n  ]\n\n  if (isFrpSelfSignedIngress(settings)) {\n    const publicPort = parts.publicPort ?? 0\n    const publicHost = parts.publicHost\n    return Object.freeze({\n      mode: 'attach' as const,\n      entryTls: resolveFrpEntryTls(settings),\n      publicPort,\n      local: Object.freeze({\n        frpcToml,\n        tokenMasked,\n        verifyCommand,\n        configFile,\n        declaration: FRP_ATTACH_LOCAL_DECLARATION,\n      }),\n      vps: Object.freeze([\n        Object.freeze({\n          id: 'open-public-port' as const,\n          title: 'frpAttachStepOpenPort',\n          label: `放行公网入口端口 ${String(publicPort)}/tcp`,\n          commands: Object.freeze([`ufw allow ${String(publicPort)}/tcp`, `ufw status | grep ${String(publicPort)}`]),\n          optional: false,\n          verifyHint: `ufw status 中应出现 ${String(publicPort)}/tcp ALLOW；云厂商安全组也需放行同一 TCP 端口。`,\n        }),\n        Object.freeze({\n          id: 'verify-frps' as const,\n          title: 'frpAttachStepVerifyFrps',\n          label: '确认既有 frps 已就绪（不改动它的配置）',\n          commands: Object.freeze([\n            'systemctl is-active frps || true',\n            `ss -lnt | grep -E ':(${String(settings.serverPort)}|${String(publicPort)})\\\\b' || true`,\n          ]),\n          optional: false,\n          verifyHint: `frps 控制端口 ${String(settings.serverPort)} 应监听；入口 ${String(publicPort)} 的 Local Address 不应是 127.0.0.1。若仅回环监听，防火墙放行也无法公网访问。`,\n        }),\n        Object.freeze({\n          id: 'verify-entry' as const,\n          title: 'frpAttachStepVerifyEntry',\n          label: 'frpc 启动后端到端验证（自签证书需 -k）',\n          commands: Object.freeze([\n            `curl -k -sS -o /dev/null -w '%{http_code}\\\\n' https://${publicHost}:${String(publicPort)}${FRP_ATTACH_DISCOVERY_PATH}`,\n          ]),\n          optional: false,\n          verifyHint: '期望输出 200；curl -k 仅验证连通性，不验证服务器身份；App 配对后会固定网关 CA。返回 000 时检查端口与转发。',\n        }),\n      ]),\n      warnings: Object.freeze([\n        ...commonWarnings,\n        FRP_ATTACH_SELF_SIGNED_DECLARATION,\n        '现有 frps 的 TCP 代理必须已监听公网地址；若 proxyBindAddr=127.0.0.1，单靠开放防火墙端口无法连通，请改选公网证书 + Caddy 模式。插件不会修改你的 frps。',\n        '手机浏览器访问自签入口会提示证书不受信任 —— 请用 App 扫码配对；App 已固定网关 CA，不需要公开证书。',\n        '切勿把网关 listenHost 改成 0.0.0.0：公网入口由 frps 的 TCP 代理提供，网关只监听 127.0.0.1。',\n      ]),\n    })\n  }\n\n  const vhostHttpPort = parts.vhostHttpPort ?? 0\n  const publicHost = parts.publicHost\n  const certGuide = parts.certGuide\n  const certificateSteps: FrpAttachPlanStep[] = certGuide.length === 0 ? [] : [\n    Object.freeze({\n      id: 'issue-ip-cert' as const,\n      title: 'frpAttachStepIssueCert',\n      label: '为公网 IP 签发受信任证书（certbot）',\n      commands: Object.freeze([...certGuide]),\n      optional: false,\n      verifyHint: `证书应落到 /etc/letsencrypt/live/${publicHost}/ 并安装到 Caddy 证书目录。`,\n    }),\n    Object.freeze({\n      id: 'enable-cert-timer' as const,\n      title: 'frpAttachStepCertTimer',\n      label: '确认 certbot 续期定时器并更新 Caddy 证书文件',\n      commands: Object.freeze(['systemctl list-timers certbot.timer --all || true']),\n      optional: false,\n      verifyHint: '公网 IP 证书有效期较短；续期后还须将新证书安装到 Caddy 并重载。',\n    }),\n  ]\n  return Object.freeze({\n    mode: 'attach' as const,\n    entryTls: resolveFrpEntryTls(settings),\n    vhostHttpPort,\n    local: Object.freeze({\n      frpcToml,\n      tokenMasked,\n      verifyCommand,\n      configFile,\n      declaration: FRP_ATTACH_LOCAL_DECLARATION,\n    }),\n    vps: Object.freeze([\n      Object.freeze({\n        id: 'write-snippet' as const,\n        title: 'frpAttachStepWriteSnippet',\n        label: `新增 Caddy 片段 ${FRP_CADDY_SNIPPET_PATH}`,\n        commands: Object.freeze([\n          `cat > ${FRP_CADDY_SNIPPET_PATH} <<'DSH_MOBILE_CADDY_SNIPPET'`,\n          parts.snippet.trimEnd(),\n          'DSH_MOBILE_CADDY_SNIPPET',\n        ]),\n        optional: false,\n        verifyHint: `片段内容里的反代目标是 127.0.0.1:${String(vhostHttpPort)}，即你 frps 的 vhostHTTPPort。`,\n      }),\n      Object.freeze({\n        id: 'add-import' as const,\n        title: 'frpAttachStepAddImport',\n        label: '在 Caddyfile 顶部加入 import 行并重载',\n        commands: Object.freeze([\n          `# 确认 /etc/caddy/Caddyfile 顶部包含：${FRP_CADDY_IMPORT_LINE}`,\n          'caddy validate --config /etc/caddy/Caddyfile && systemctl reload caddy',\n        ]),\n        optional: false,\n        verifyHint: 'caddy validate 通过且 reload 无报错；Caddyfile 中你自己原有的站点内容保持不变。',\n      }),\n      ...certificateSteps,\n      Object.freeze({\n        id: 'verify-https' as const,\n        title: 'frpAttachStepVerifyHttps',\n        label: '端到端验证公网 HTTPS 入口',\n        commands: Object.freeze([\n          `curl -sS -o /dev/null -w '%{http_code}\\\\n' https://${publicHost}${FRP_ATTACH_DISCOVERY_PATH}`,\n        ]),\n        optional: true,\n        verifyHint: certGuide.length === 0\n          ? '期望输出 200；证书错误时检查 DNS、80/443 端口和 Caddy 日志。'\n          : '期望输出 200；证书错误时检查 certbot 证书是否安装并重载 Caddy。',\n      }),\n    ]),\n    warnings: Object.freeze([\n      ...commonWarnings,\n      FRP_ATTACH_VPS_DECLARATION,\n      `你 frps 的明文 vhost 必须只监听 127.0.0.1（proxyBindAddr）且 vhostHTTPPort=${String(vhostHttpPort)}；`\n        + '插件启动前会探测该端口，若公网可达将直接拒绝启动。',\n    ]),\n  })\n}\n","import { X509Certificate } from 'node:crypto'\nimport { readFile } from 'node:fs/promises'\nimport { connect as connectTls } from 'node:tls'\n\n/** Days left below which the entry certificate is reported as expiring. */\nexport const CERT_EXPIRING_DAYS = 2\n\nconst DAY_MS = 24 * 60 * 60_000\n\n/** Read-only lifetime verdict for one certificate; never mutates or renews anything. */\nexport interface CertRenewalStatus {\n  readonly state: 'ok' | 'expiring' | 'expired' | 'unknown'\n  /** Unix milliseconds of `notAfter`. */\n  readonly notAfter?: number\n  readonly daysRemaining?: number\n  readonly subject?: string\n  readonly issuer?: string\n  readonly errorCode?: string\n}\n\n/** Evaluate one `notAfter` timestamp against the current clock. */\nexport function evaluateCertificateLifetime(notAfter: number, now: number = Date.now()): CertRenewalStatus {\n  if (!Number.isFinite(notAfter) || !Number.isFinite(now)) {\n    return Object.freeze({ state: 'unknown' as const, errorCode: 'frp_attach_cert_unknown' })\n  }\n  const daysRemaining = Math.floor((notAfter - now) / DAY_MS)\n  if (notAfter <= now) return Object.freeze({ state: 'expired' as const, notAfter, daysRemaining })\n  if (daysRemaining <= CERT_EXPIRING_DAYS) return Object.freeze({ state: 'expiring' as const, notAfter, daysRemaining })\n  return Object.freeze({ state: 'ok' as const, notAfter, daysRemaining })\n}\n\nfunction statusFromCertificate(certificate: X509Certificate, now: number): CertRenewalStatus {\n  const notAfter = Date.parse(certificate.validTo)\n  const lifetime = evaluateCertificateLifetime(notAfter, now)\n  return Object.freeze({\n    ...lifetime,\n    subject: certificate.subject,\n    issuer: certificate.issuer,\n  })\n}\n\n/**\n * Read one PEM certificate from disk and report only its lifetime.\n *\n * A missing or unreadable file yields `unknown` with the stable\n * `frp_attach_cert_unknown` code so the panel can explain how to re-issue it.\n */\nexport async function readCertificateRenewal(file: string, now: number = Date.now()): Promise<CertRenewalStatus> {\n  try {\n    return statusFromCertificate(new X509Certificate(await readFile(file)), now)\n  } catch {\n    return Object.freeze({ state: 'unknown' as const, errorCode: 'frp_attach_cert_unknown' })\n  }\n}\n\n/**\n * Ask a live TLS endpoint for its leaf certificate and report its lifetime.\n *\n * Verification is intentionally skipped: this is a read-only lifetime probe for\n * an endpoint whose trust anchor is already pinned elsewhere, and a self-signed\n * leaf is the expected answer for the passthrough entry.\n */\nexport async function probeOriginCertificate(\n  host: string,\n  port: number,\n  timeoutMs = 5_000,\n): Promise<CertRenewalStatus> {\n  if (!Number.isSafeInteger(port) || port < 1 || port > 65_535) {\n    return Object.freeze({ state: 'unknown' as const, errorCode: 'frp_attach_cert_unknown' })\n  }\n  return new Promise<CertRenewalStatus>((resolveProbe) => {\n    let finished = false\n    const socket = connectTls({ host, port, rejectUnauthorized: false, servername: undefined })\n    const finish = (status: CertRenewalStatus): void => {\n      if (finished) return\n      finished = true\n      clearTimeout(timer)\n      socket.destroy()\n      resolveProbe(status)\n    }\n    const timer = setTimeout(() => { finish(Object.freeze({ state: 'unknown' as const, errorCode: 'frp_attach_cert_unknown' })) }, timeoutMs)\n    timer.unref()\n    socket.once('secureConnect', () => {\n      const certificate = socket.getPeerX509Certificate()\n      finish(certificate === undefined\n        ? Object.freeze({ state: 'unknown' as const, errorCode: 'frp_attach_cert_unknown' })\n        : statusFromCertificate(certificate, Date.now()))\n    })\n    socket.once('error', () => { finish(Object.freeze({ state: 'unknown' as const, errorCode: 'frp_attach_cert_unknown' })) })\n    socket.once('close', () => { finish(Object.freeze({ state: 'unknown' as const, errorCode: 'frp_attach_cert_unknown' })) })\n  })\n}","import {\n  X509Certificate,\n  createPrivateKey,\n  createPublicKey,\n  randomBytes,\n} from 'node:crypto'\nimport { execFileText as execFile } from './exec-file.js'\nimport { lstat, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { networkInterfaces, type NetworkInterfaceInfo } from 'node:os'\nimport { basename, dirname, join } from 'node:path'\nimport { generate } from 'selfsigned'\nimport { restrictPrivateFile } from './private-file.js'\nimport { parseCidr } from './network.js'\n\n/** One active private IPv4 address tied to a stable operating-system interface name. */\nexport interface LanNetwork {\n  readonly name: string\n  readonly address: string\n  readonly cidr: string\n}\n\n/** Versioned setup that survives DHCP address changes on the selected interface. */\nexport interface ManagedSetup {\n  readonly version: 2\n  readonly networkInterface: string\n  readonly listenPort: number\n  /** Legacy setup snapshot retained for file compatibility; the active WebServer port wins at runtime. */\n  readonly upstreamOrigin: string\n  /** Additional admin-selected source networks; the active LAN subnet remains trusted. */\n  readonly extraAllowedCidrs?: readonly string[]\n  readonly tls: {\n    readonly mode: 'managed'\n    readonly caCertFile: string\n    readonly caKeyFile: string\n    readonly certFile: string\n    readonly keyFile: string\n  }\n}\n\ntype InterfaceTable = NodeJS.Dict<NetworkInterfaceInfo[]>\ntype RouteCommand = (file: string, args: readonly string[]) => Promise<string>\n\nconst VIRTUAL_INTERFACE_MARKERS = [\n  'bridge', 'docker', 'hyper-v', 'mihomo', 'radmin', 'tailscale', 'tap', 'tun',\n  'utun', 'vbox', 'veth', 'virtual', 'vmware', 'vpn', 'vethernet', 'wsl', 'zerotier',\n]\n\n/** Route inspection is advisory; never let a system command hold setup open indefinitely. */\nconst ROUTE_COMMAND_TIMEOUT_MS = 5_000\n\nfunction requiredString(value: unknown, name: string): string {\n  if (typeof value !== 'string' || value.length === 0) throw new Error(`${name} must be a non-empty string`)\n  return value\n}\n\n/** Validate the durable managed setup before it controls network and filesystem operations. */\nexport function parseManagedSetup(value: unknown): ManagedSetup {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n    throw new Error('mobile setup file must be an object')\n  }\n  const record = value as Record<string, unknown>\n  if (record.version !== 2 || Reflect.ownKeys(record)\n    .some(key => typeof key !== 'string' || !['version', 'networkInterface', 'listenPort', 'upstreamOrigin', 'tls', 'extraAllowedCidrs'].includes(key))) {\n    throw new Error('mobile setup file has an unsupported format')\n  }\n  if (!Number.isSafeInteger(record.listenPort) || (record.listenPort as number) < 1024\n    || (record.listenPort as number) > 65535) {\n    throw new Error('mobile setup listenPort must be from 1024 through 65535')\n  }\n  if (typeof record.tls !== 'object' || record.tls === null || Array.isArray(record.tls)) {\n    throw new Error('mobile setup tls must be an object')\n  }\n  const tls = record.tls as Record<string, unknown>\n  if (tls.mode !== 'managed' || Reflect.ownKeys(tls)\n    .some(key => typeof key !== 'string' || !['mode', 'caCertFile', 'caKeyFile', 'certFile', 'keyFile'].includes(key))) {\n    throw new Error('mobile setup tls has an unsupported format')\n  }\n  return Object.freeze({\n    version: 2,\n    networkInterface: requiredString(record.networkInterface, 'mobile setup networkInterface'),\n    listenPort: record.listenPort as number,\n    upstreamOrigin: requiredString(record.upstreamOrigin, 'mobile setup upstreamOrigin'),\n    ...(record.extraAllowedCidrs === undefined ? {} : { extraAllowedCidrs: parseAdditionalTrustedNetworks(record.extraAllowedCidrs) }),\n    tls: Object.freeze({\n      mode: 'managed',\n      caCertFile: requiredString(tls.caCertFile, 'mobile setup tls.caCertFile'),\n      caKeyFile: requiredString(tls.caKeyFile, 'mobile setup tls.caKeyFile'),\n      certFile: requiredString(tls.certFile, 'mobile setup tls.certFile'),\n      keyFile: requiredString(tls.keyFile, 'mobile setup tls.keyFile'),\n    }),\n  })\n}\n\n/** Validate explicitly trusted networks without adding implicit VPN or private ranges.\n * @param value - CIDR strings submitted by the computer administrator.\n * @returns Deduplicated validated CIDRs in input order.\n */\nexport function parseAdditionalTrustedNetworks(value: unknown): readonly string[] {\n  if (!Array.isArray(value)) {\n    throw new Error('extraAllowedCidrs must be an array of CIDR strings')\n  }\n  const sources = value.map((entry: unknown): string => {\n    if (typeof entry !== 'string' || entry.trim() === '') throw new Error('extraAllowedCidrs must be an array of CIDR strings')\n    return entry.trim()\n  })\n  const entries: string[] = []\n  const seen = new Set<string>()\n  for (const cidr of sources) {\n    const parsed = parseCidr(cidr)\n    const key = `${parsed.bits}:${parsed.network}:${parsed.prefix}`\n    if (seen.has(key)) continue\n    seen.add(key)\n    entries.push(cidr)\n  }\n  return Object.freeze(entries)\n}\n\n/** Save extra trusted networks without replacing the interface or pairing identity.\n * @param setupFile - Existing managed setup file.\n * @param values - Explicitly selected additional networks.\n * @returns The saved managed setup.\n */\nexport async function saveManagedTrustedNetworks(setupFile: string, values: unknown): Promise<ManagedSetup> {\n  const extraAllowedCidrs = parseAdditionalTrustedNetworks(values)\n  const setup = parseManagedSetup(JSON.parse(await readFile(setupFile, 'utf8')))\n  const next = Object.freeze({ ...setup, extraAllowedCidrs })\n  await atomicWrite(setupFile, `${JSON.stringify(next, null, 2)}\\n`)\n  await restrictPrivateFile(setupFile)\n  return next\n}\n\nfunction privateIpv4(value: string): boolean {\n  const parts = value.split('.').map(Number)\n  return parts.length === 4 && parts.every(part => Number.isInteger(part) && part >= 0 && part <= 255)\n    && (parts[0] === 10\n      || (parts[0] === 172 && parts[1]! >= 16 && parts[1]! <= 31)\n      || (parts[0] === 192 && parts[1] === 168))\n}\n\nfunction networkCidr(address: string, cidr: string): string {\n  const prefix = Number(cidr.slice(cidr.lastIndexOf('/') + 1))\n  const value = address.split('.').reduce((total, part) => ((total << 8) | Number(part)) >>> 0, 0)\n  const mask = prefix === 0 ? 0 : (0xffffffff << (32 - prefix)) >>> 0\n  const network = (value & mask) >>> 0\n  return `${[24, 16, 8, 0].map(shift => (network >>> shift) & 255).join('.')}/${String(prefix)}`\n}\n\n/** List current private IPv4 candidates with their interface identity. */\nexport function availableLanNetworks(table: InterfaceTable = networkInterfaces()): LanNetwork[] {\n  const candidates = Object.entries(table).flatMap(([name, entries]) => (entries ?? [])\n    .filter(entry => entry.family === 'IPv4' && !entry.internal && privateIpv4(entry.address) && entry.cidr !== null)\n    .map(entry => ({ name, address: entry.address, cidr: networkCidr(entry.address, entry.cidr!) })))\n  return [...new Map(candidates.map(entry => [`${entry.name}\\0${entry.address}`, entry])).values()]\n}\n\nfunction likelyVirtualInterface(name: string): boolean {\n  const normalized = name.toLowerCase().replaceAll(/[^a-z0-9]+/gu, ' ')\n  return VIRTUAL_INTERFACE_MARKERS.some(marker => normalized.includes(marker.replaceAll('-', ' ')))\n    || /^(?:br|wg)\\d*\\b/u.test(normalized)\n}\n\nasync function runRouteCommand(file: string, args: readonly string[]): Promise<string> {\n  const result = await execFile(file, [...args], { encoding: 'utf8', timeout: ROUTE_COMMAND_TIMEOUT_MS })\n  return result.stdout\n}\n\nfunction uniqueLines(output: string): string[] {\n  return [...new Set(output.split(/\\r?\\n/gu).map(line => line.trim()).filter(Boolean))]\n}\n\n/** Return operating-system default-route interfaces in routing preference order. */\nexport async function preferredLanInterfaceNames(\n  platform: NodeJS.Platform = process.platform,\n  run: RouteCommand = runRouteCommand,\n): Promise<string[]> {\n  try {\n    if (platform === 'win32') {\n      const script = [\n        \"$routes = Get-NetRoute -AddressFamily IPv4 -DestinationPrefix '0.0.0.0/0' -ErrorAction Stop\",\n        \"$ranked = $routes | Where-Object { $_.State -eq 'Alive' -and $_.NextHop -ne '0.0.0.0' } | ForEach-Object {\",\n        '  $route = $_',\n        '  $adapter = Get-NetAdapter -InterfaceIndex $route.InterfaceIndex -ErrorAction SilentlyContinue',\n        '  $ip = Get-NetIPInterface -AddressFamily IPv4 -InterfaceIndex $route.InterfaceIndex -ErrorAction SilentlyContinue',\n        \"  if ($adapter -and $ip -and $adapter.Status -eq 'Up' -and $adapter.HardwareInterface -eq $true -and $adapter.Virtual -ne $true) {\",\n        '    [pscustomobject]@{ Name = $route.InterfaceAlias; Metric = [int]$route.RouteMetric + [int]$ip.InterfaceMetric }',\n        '  }',\n        '}',\n        '$ranked | Sort-Object Metric | Select-Object -ExpandProperty Name -Unique',\n      ].join('; ')\n      return uniqueLines(await run('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', script]))\n    }\n    if (platform === 'linux') {\n      const routes = uniqueLines(await run('ip', ['-o', '-4', 'route', 'show', 'default']))\n        .map(line => ({\n          name: /(?:^|\\s)dev\\s+(\\S+)/u.exec(line)?.[1],\n          metric: Number(/(?:^|\\s)metric\\s+(\\d+)/u.exec(line)?.[1] ?? 0),\n        }))\n        .filter((route): route is { name: string; metric: number } => route.name !== undefined\n          && !likelyVirtualInterface(route.name))\n        .sort((left, right) => left.metric - right.metric)\n      return [...new Set(routes.map(route => route.name))]\n    }\n    if (platform === 'darwin') {\n      const name = /^\\s*interface:\\s*(\\S+)\\s*$/mu.exec(await run('route', ['-n', 'get', 'default']))?.[1]\n      return name === undefined || likelyVirtualInterface(name) ? [] : [name]\n    }\n  } catch {\n    // Route discovery is advisory; deterministic candidate checks below remain the fallback.\n  }\n  return []\n}\n\n/** Select an active LAN, optionally by address or by a previously saved interface name. */\nexport function selectLanNetwork(\n  requestedAddress?: string,\n  requestedInterface?: string,\n  table?: InterfaceTable,\n  preferredInterfaces: readonly string[] = [],\n): LanNetwork {\n  const candidates = availableLanNetworks(table)\n  if (requestedAddress !== undefined) {\n    const match = candidates.find(candidate => candidate.address === requestedAddress)\n    if (match === undefined) throw new Error(`--address ${requestedAddress} is not an active private LAN address`)\n    return match\n  }\n  if (requestedInterface !== undefined) {\n    const matches = candidates.filter(candidate => candidate.name === requestedInterface)\n    if (matches.length === 1) return matches[0]!\n    if (matches.length === 0) {\n      throw new Error(`saved LAN interface ${JSON.stringify(requestedInterface)} is not connected`)\n    }\n    throw new Error(`saved LAN interface ${JSON.stringify(requestedInterface)} has more than one private IPv4 address`)\n  }\n  if (candidates.length === 1) return candidates[0]!\n  if (candidates.length === 0) throw new Error('no active private LAN address was found; connect to Wi-Fi or Ethernet')\n  for (const name of preferredInterfaces) {\n    const matches = candidates.filter(candidate => candidate.name === name)\n    if (matches.length === 1) return matches[0]!\n  }\n  const physicalCandidates = candidates.filter(candidate => !likelyVirtualInterface(candidate.name))\n  if (physicalCandidates.length === 1) return physicalCandidates[0]!\n  throw new Error(`more than one LAN address is active; rerun with --address and one of: ${candidates.map(entry => `${entry.name}=${entry.address}`).join(', ')}`)\n}\n\n/**\n * True when the failure came from LAN selection (the configured network is\n * gone, nothing is up, or several are) rather than from config/TLS code.\n * Callers use it to degrade (warn + stay down) instead of failing boot.\n * Pinned to the selectLanNetwork message contract — keep in sync.\n */\nexport function isNetworkSelectionError(error: unknown): boolean {\n  const message = error instanceof Error ? error.message : String(error ?? '')\n  return message.includes('is not connected')\n    || message.includes('no active private LAN address was found')\n    || message.includes('more than one LAN address is active')\n    || message.includes('has more than one private IPv4 address')\n    || message.includes('is not an active private LAN address')\n}\n\nfunction assertMatchingCa(certPem: string, keyPem: string): X509Certificate {\n  const certificate = new X509Certificate(certPem)\n  if (!certificate.ca || certificate.subject !== certificate.issuer\n    || !certificate.verify(certificate.publicKey)) {\n    throw new Error('managed TLS CA must be a self-signed CA certificate')\n  }\n  const privatePublic = createPublicKey(createPrivateKey(keyPem)).export({ format: 'der', type: 'spki' })\n  const certificatePublic = certificate.publicKey.export({ format: 'der', type: 'spki' })\n  if (!privatePublic.equals(certificatePublic)) throw new Error('managed TLS CA certificate and key do not match')\n  if (Date.parse(certificate.validFrom) > Date.now() || Date.parse(certificate.validTo) <= Date.now()) {\n    throw new Error('managed TLS CA certificate is not currently valid')\n  }\n  return certificate\n}\n\n/** Read an existing managed CA without ever generating a replacement identity. */\nexport async function readManagedCa(setup: ManagedSetup['tls']): Promise<X509Certificate> {\n  const [certPem, keyPem] = await Promise.all([\n    readFile(setup.caCertFile, 'utf8'),\n    readFile(setup.caKeyFile, 'utf8'),\n  ])\n  return assertMatchingCa(certPem, keyPem)\n}\n\nasync function stagePrivateFile(file: string, contents: string | Uint8Array): Promise<string> {\n  const directory = dirname(file)\n  await mkdir(directory, { recursive: true, mode: 0o700 })\n  const temporary = join(directory, `.${basename(file)}.${randomBytes(12).toString('hex')}.tmp`)\n  try {\n    await writeFile(temporary, '', { mode: 0o600, flag: 'wx' })\n    await restrictPrivateFile(temporary)\n    await writeFile(temporary, contents)\n    return temporary\n  } catch (error) {\n    await rm(temporary, { force: true })\n    throw error\n  }\n}\n\nasync function atomicWrite(file: string, contents: string | Uint8Array): Promise<void> {\n  const temporary = await stagePrivateFile(file, contents)\n  try {\n    await rename(temporary, file)\n    await restrictPrivateFile(file)\n  } finally { await rm(temporary, { force: true }) }\n}\n\nconst certificatePublications = new Map<string, Promise<void>>()\n\n/** Stage both files before promotion and retain a private rollback copy until the pair is installed. */\nasync function installServerCertificatePair(output: ServerCertificateFiles, cert: string, key: string): Promise<void> {\n  const identity = `${output.certFile}\\0${output.keyFile}`\n  const previous = certificatePublications.get(identity) ?? Promise.resolve()\n  const publication = previous.catch(() => undefined).then(async () => {\n    const files = [output.certFile, output.keyFile]\n    const contents = [cert, key]\n    const staged: string[] = []\n    const backups: Array<string | undefined> = []\n    let promoted = 0\n    let restored = true\n    const failures: unknown[] = []\n    try {\n      for (let index = 0; index < files.length; index += 1) {\n        const file = files[index]!\n        staged.push(await stagePrivateFile(file, contents[index]!))\n        let old: Buffer | undefined\n        try {\n          const metadata = await lstat(file)\n          if (!metadata.isFile() || metadata.isSymbolicLink()) throw new Error('managed TLS output is not a regular file')\n          old = await readFile(file)\n        } catch (error) {\n          if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n        }\n        backups.push(old === undefined ? undefined : await stagePrivateFile(file, old))\n      }\n      for (let index = 0; index < files.length; index += 1) {\n        await rename(staged[index]!, files[index]!)\n        promoted += 1\n      }\n    } catch (error) {\n      failures.push(error)\n      for (let index = promoted - 1; index >= 0; index -= 1) {\n        try {\n          const backup = backups[index]\n          if (backup === undefined) await rm(files[index]!, { force: true })\n          else await rename(backup, files[index]!)\n        } catch (restoreError) { restored = false; failures.push(restoreError) }\n      }\n    } finally {\n      const cleanup = await Promise.allSettled(staged.map(file => rm(file, { force: true })))\n      for (const result of cleanup) if (result.status === 'rejected') failures.push(result.reason)\n      // Failed rollback copies stay private on disk for manual recovery.\n      if (restored) {\n        const backupCleanup = await Promise.allSettled(backups.filter((file): file is string => file !== undefined).map(file => rm(file, { force: true })))\n        for (const result of backupCleanup) if (result.status === 'rejected') failures.push(result.reason)\n      }\n    }\n    if (failures.length > 1) throw new AggregateError(failures, 'managed TLS certificate replacement, rollback or cleanup failed')\n    if (failures.length === 1) throw failures[0]\n  })\n  certificatePublications.set(identity, publication)\n  try { await publication } finally { if (certificatePublications.get(identity) === publication) certificatePublications.delete(identity) }\n}\n\n/** Create a long-lived CA or migrate the legacy self-signed server certificate as that CA. */\nexport async function ensureManagedCa(\n  setup: ManagedSetup['tls'],\n  legacy?: { readonly certFile: string; readonly keyFile: string },\n): Promise<X509Certificate> {\n  let certPem: string | undefined\n  let keyPem: string | undefined\n  try {\n    [certPem, keyPem] = await Promise.all([readFile(setup.caCertFile, 'utf8'), readFile(setup.caKeyFile, 'utf8')])\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n    let migrated = false\n    if (legacy !== undefined) {\n      try {\n        [certPem, keyPem] = await Promise.all([readFile(legacy.certFile, 'utf8'), readFile(legacy.keyFile, 'utf8')])\n        assertMatchingCa(certPem, keyPem)\n        migrated = true\n      } catch (legacyError) {\n        if ((legacyError as NodeJS.ErrnoException).code !== 'ENOENT') throw legacyError\n      }\n    }\n    if (!migrated) {\n      const now = new Date()\n      const notAfter = new Date(now)\n      notAfter.setFullYear(notAfter.getFullYear() + 5)\n      const generated = await generate([{ name: 'commonName', value: 'DeepSeek Harness Mobile CA' }], {\n        keyType: 'ec',\n        curve: 'P-256',\n        algorithm: 'sha256',\n        notBeforeDate: new Date(now.getTime() - 5 * 60_000),\n        notAfterDate: notAfter,\n        extensions: [\n          { name: 'basicConstraints', cA: true, critical: true },\n          { name: 'keyUsage', digitalSignature: true, keyCertSign: true, cRLSign: true, critical: true },\n        ],\n      })\n      certPem = generated.cert\n      keyPem = generated.private\n    }\n    if (certPem === undefined || keyPem === undefined) throw new Error('managed TLS CA creation did not produce key material')\n    await Promise.all([atomicWrite(setup.caCertFile, certPem), atomicWrite(setup.caKeyFile, keyPem)])\n  }\n  if (certPem === undefined || keyPem === undefined) throw new Error('managed TLS CA creation did not produce key material')\n  await Promise.all([restrictPrivateFile(setup.caCertFile), restrictPrivateFile(setup.caKeyFile)])\n  return assertMatchingCa(certPem, keyPem)\n}\n\n/** One host a server leaf must be valid for: an IP literal, a DNS name, or both. */\nexport interface ServerCertificateTarget {\n  readonly commonName: string\n  readonly ipAddresses?: readonly string[]\n  readonly dnsNames?: readonly string[]\n}\n\n/** Where a freshly signed server leaf is installed. */\nexport interface ServerCertificateFiles {\n  readonly certFile: string\n  readonly keyFile: string\n}\n\n/** CA material a leaf is signed with. */\nexport interface ServerCertificateAuthority {\n  readonly caCertFile: string\n  readonly caKeyFile: string\n}\n\nfunction subjectAltNames(target: ServerCertificateTarget): { type: 2 | 7; value?: string; ip?: string }[] {\n  const names: { type: 2 | 7; value?: string; ip?: string }[] = []\n  for (const ip of target.ipAddresses ?? []) names.push({ type: 7, ip })\n  for (const dns of target.dnsNames ?? []) names.push({ type: 2, value: dns })\n  if (names.length === 0) throw new Error('managed TLS leaf needs at least one server name')\n  return names\n}\n\n/**\n * Sign one server leaf with an existing self-signed CA and install it privately.\n *\n * Both the LAN listener and the self-signed FRP ingress use this one path, so a\n * certificate can never be produced by two divergent code paths. IP entries are\n * required for console addresses (`type: 7`), DNS entries (`type: 2`) cover named\n * hosts; the Android client accepts either through its pinned CA.\n */\nexport async function issueServerCertificate(\n  authority: ServerCertificateAuthority,\n  target: ServerCertificateTarget,\n  output: ServerCertificateFiles,\n  lifetimeDays = 397,\n): Promise<void> {\n  const altNames = subjectAltNames(target)\n  await Promise.all([restrictPrivateFile(authority.caCertFile), restrictPrivateFile(authority.caKeyFile)])\n  const [caCert, caKey] = await Promise.all([\n    readFile(authority.caCertFile, 'utf8'),\n    readFile(authority.caKeyFile, 'utf8'),\n  ])\n  assertMatchingCa(caCert, caKey)\n  const now = new Date()\n  const notAfter = new Date(now)\n  notAfter.setDate(notAfter.getDate() + lifetimeDays)\n  const server = await generate([{ name: 'commonName', value: target.commonName }], {\n    keyType: 'ec',\n    curve: 'P-256',\n    algorithm: 'sha256',\n    notBeforeDate: new Date(now.getTime() - 5 * 60_000),\n    notAfterDate: notAfter,\n    ca: { cert: caCert, key: caKey },\n    extensions: [\n      { name: 'basicConstraints', cA: false, critical: true },\n      { name: 'keyUsage', digitalSignature: true, critical: true },\n      { name: 'extKeyUsage', serverAuth: true },\n      { name: 'subjectAltName', altNames },\n    ],\n  })\n  await installServerCertificatePair(output, server.cert, server.private)\n}\n\n/** Sign and atomically install a server leaf for the interface's current address. */\nexport async function refreshManagedServerCertificate(setup: ManagedSetup, address: string): Promise<void> {\n  await issueServerCertificate(\n    { caCertFile: setup.tls.caCertFile, caKeyFile: setup.tls.caKeyFile },\n    { commonName: 'DeepSeek Harness Mobile', ipAddresses: [address] },\n    { certFile: setup.tls.certFile, keyFile: setup.tls.keyFile },\n  )\n}\n\n/** Resolve the saved interface to the ordinary gateway config consumed by the Host plugin. */\nexport async function materializeManagedSetup(\n  setup: ManagedSetup,\n  table?: InterfaceTable,\n): Promise<Record<string, unknown>> {\n  const network = selectLanNetwork(undefined, setup.networkInterface, table)\n  await refreshManagedServerCertificate(setup, network.address)\n  const ca = new X509Certificate(await readFile(setup.tls.caCertFile, 'utf8'))\n  return {\n    publicOrigin: `https://${network.address}:${String(setup.listenPort)}`,\n    listenHost: network.address,\n    allowedCidrs: parseAdditionalTrustedNetworks([network.cidr, ...(setup.extraAllowedCidrs ?? [])]),\n    instanceId: ca.fingerprint256.replaceAll(':', '').toLowerCase(),\n    pairingCaFile: setup.tls.caCertFile,\n    tls: {\n      mode: 'provided',\n      certFile: setup.tls.certFile,\n      keyFile: setup.tls.keyFile,\n    },\n  }\n}\n","import { X509Certificate, createPrivateKey } from 'node:crypto'\nimport { lstat, readFile, rmdir, unlink, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport { readCertificateRenewal, type CertRenewalStatus } from './cert-renewal.js'\nimport {\n  frpEntryOrigin,\n  isFrpSelfSignedIngress,\n  resolveFrpEntryTls,\n  resolveFrpMode,\n  resolveFrpPublicPort,\n  resolveFrpVhostHttpPort,\n  type FrpSettings,\n} from './frp-config.js'\nimport { ensureManagedCa, issueServerCertificate, readManagedCa } from './managed-setup.js'\nimport { restrictPrivateFile } from './private-file.js'\nimport { assertManagedParents, ensureManagedDirectory, writeManagedPrivateFile } from './managed-files.js'\n\n/** Private files owned by the self-signed FRP ingress. */\nexport interface FrpIngressPaths {\n  readonly directory: string\n  readonly caCertFile: string\n  readonly caKeyFile: string\n  readonly certFile: string\n  readonly keyFile: string\n  readonly statusFile: string\n}\n\n/** Signed ingress material plus the fingerprint the app must pin. */\nexport interface FrpIngressCertificate {\n  readonly paths: FrpIngressPaths\n  readonly ca: X509Certificate\n  readonly leaf: X509Certificate\n  readonly caFingerprint: string\n  readonly status: CertRenewalStatus\n}\n\n/** Everything the panel needs for the on-demand self-check. */\nexport interface FrpIngressSelfCheck {\n  readonly mode: 'deploy' | 'attach'\n  readonly entryTls: 'public-ip-cert' | 'self-signed'\n  readonly vhostHttpPort: number\n  readonly publicPort: number\n  readonly publicOrigin: string\n  /** Reachable HTTPS entry; includes the TCP proxy port in self-signed mode. */\n  readonly entryOrigin: string\n  readonly serverAddress: string\n  readonly serverPort: number\n  readonly caFingerprint?: string\n  readonly certificate?: CertRenewalStatus\n  readonly caCertificate?: CertRenewalStatus\n  readonly inbound: { readonly listenHost: '127.0.0.1'; readonly allowedCidrs: readonly string[] }\n}\n\n/** Private ingress directory, always a sibling of the remote device file. */\nexport function frpIngressPaths(stateFile: string): FrpIngressPaths {\n  const directory = join(dirname(stateFile), 'ingress')\n  return Object.freeze({\n    directory,\n    caCertFile: join(directory, 'ca.pem'),\n    caKeyFile: join(directory, 'ca-key.pem'),\n    certFile: join(directory, 'server.pem'),\n    keyFile: join(directory, 'server-key.pem'),\n    // Keep the identity marker outside the certificate directory so deleting\n    // that directory cannot silently create a replacement CA on next start.\n    statusFile: join(dirname(stateFile), 'ingress-identity.json'),\n  })\n}\n\nasync function regularFileExists(file: string): Promise<boolean> {\n  try {\n    const entry = await lstat(file)\n    if (!entry.isFile() || entry.isSymbolicLink()) throw new Error('frp_ingress_file_invalid')\n    return true\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false\n    throw error\n  }\n}\n\nasync function readIngressIdentity(file: string): Promise<string | undefined> {\n  if (!(await regularFileExists(file))) return undefined\n  try {\n    const parsed: unknown = JSON.parse(await readFile(file, 'utf8'))\n    if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) throw new Error('invalid identity')\n    const record = parsed as Record<string, unknown>\n    if (record.version !== 1 || typeof record.caFingerprint !== 'string'\n      || !/^[a-f0-9]{64}$/u.test(record.caFingerprint)) throw new Error('invalid identity')\n    return record.caFingerprint\n  } catch (error) {\n    throw new Error('frp_ingress_ca_invalid', { cause: error })\n  }\n}\n\nasync function writeIngressIdentity(file: string, fingerprint: string, ownedRoot: string): Promise<void> {\n  await writeManagedPrivateFile(ownedRoot, file, `${JSON.stringify({ version: 1, caFingerprint: fingerprint })}\\n`, 'frp_ingress')\n}\n\nfunction coversPublicIp(certificate: X509Certificate, address: string): boolean {\n  const alternatives = certificate.subjectAltName ?? ''\n  return alternatives.split(',').some(entry => entry.trim() === `IP Address:${address}`)\n}\n\n/**\n * Materialize the CA and leaf the gateway terminates TLS with.\n *\n * The CA remains stable for paired phones; an expired CA must be re-paired, not\n * replaced silently. The leaf is re-signed when expiring or no longer valid for\n * the public IPv4, and the running gateway reloads it after a renewal check.\n */\nexport async function ensureFrpIngressCertificate(\n  settings: FrpSettings,\n  stateFile: string,\n  now: number = Date.now(),\n  expectedCaFingerprint?: string,\n  ownedRoot: string = dirname(stateFile),\n): Promise<FrpIngressCertificate> {\n  if (resolveFrpMode(settings) !== 'attach' || !isFrpSelfSignedIngress(settings)) {\n    throw new Error('frp_entry_tls_invalid')\n  }\n  const paths = frpIngressPaths(stateFile)\n  await assertManagedParents(ownedRoot, paths.statusFile, 'frp_ingress')\n  await assertManagedParents(ownedRoot, paths.caCertFile, 'frp_ingress')\n  try {\n    const directory = await lstat(paths.directory)\n    if (!directory.isDirectory() || directory.isSymbolicLink()) throw new Error('frp_ingress_directory_invalid')\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n  }\n  const previousFingerprint = await readIngressIdentity(paths.statusFile)\n  const [caCertExists, caKeyExists, leafCertExists, leafKeyExists] = await Promise.all([\n    regularFileExists(paths.caCertFile), regularFileExists(paths.caKeyFile),\n    regularFileExists(paths.certFile), regularFileExists(paths.keyFile),\n  ])\n  if (caCertExists !== caKeyExists || (!caCertExists && (previousFingerprint !== undefined || leafCertExists || leafKeyExists))) {\n    throw new Error('frp_ingress_ca_invalid')\n  }\n  if (caCertExists && (await readCertificateRenewal(paths.caCertFile, now)).state === 'expired') {\n    throw new Error('frp_ingress_ca_expired')\n  }\n  if (previousFingerprint === undefined) {\n    await ensureManagedDirectory(ownedRoot, dirname(paths.statusFile), 'frp_ingress')\n    try {\n      await writeFile(paths.statusFile, '{\"version\":1,\"pending\":true}\\n', { flag: 'wx', mode: 0o600 })\n      await restrictPrivateFile(paths.statusFile)\n    } catch (error) {\n      throw new Error('frp_ingress_ca_invalid', { cause: error })\n    }\n  }\n  const caFiles = {\n    mode: 'managed',\n    caCertFile: paths.caCertFile,\n    caKeyFile: paths.caKeyFile,\n    certFile: paths.certFile,\n    keyFile: paths.keyFile,\n  } as const\n  let ca: X509Certificate\n  try {\n    await assertManagedParents(ownedRoot, paths.caCertFile, 'frp_ingress')\n    ca = expectedCaFingerprint === undefined ? await ensureManagedCa(caFiles) : await readManagedCa(caFiles)\n  } catch (error) {\n    throw new Error('frp_ingress_ca_invalid', { cause: error })\n  }\n  const caFingerprint = ca.fingerprint256.replaceAll(':', '').toLowerCase()\n  if (previousFingerprint !== undefined && caFingerprint !== previousFingerprint) {\n    throw new Error('frp_ingress_ca_changed')\n  }\n  if (expectedCaFingerprint !== undefined && caFingerprint !== expectedCaFingerprint) {\n    throw new Error('frp_ingress_ca_changed')\n  }\n  if (previousFingerprint === undefined) await writeIngressIdentity(paths.statusFile, caFingerprint, ownedRoot)\n  const publicHost = new URL(settings.publicOrigin).hostname\n  let leaf: X509Certificate | undefined\n  let matchingKey = false\n  try {\n    leaf = new X509Certificate(await readFile(paths.certFile))\n    if (leafKeyExists) matchingKey = leaf.checkPrivateKey(createPrivateKey(await readFile(paths.keyFile)))\n  } catch (_error) {\n    // Missing or damaged leaf material is repaired under the unchanged pairing CA.\n  }\n  const reusable = leaf !== undefined\n    && matchingKey\n    && Date.parse(leaf.validFrom) <= now\n    && Date.parse(leaf.validTo) > now + 24 * 60 * 60_000\n    && coversPublicIp(leaf, publicHost)\n    && leaf.verify(ca.publicKey)\n  if (!reusable) {\n    await assertManagedParents(ownedRoot, paths.certFile, 'frp_ingress')\n    await issueServerCertificate(\n      { caCertFile: paths.caCertFile, caKeyFile: paths.caKeyFile },\n      { commonName: 'DSH Mobile FRP ingress', ipAddresses: [publicHost] },\n      { certFile: paths.certFile, keyFile: paths.keyFile },\n    )\n    leaf = new X509Certificate(await readFile(paths.certFile))\n  }\n  const signed = leaf ?? (() => { throw new Error('frp_attach_cert_unknown') })()\n  return Object.freeze({\n    paths,\n    ca,\n    leaf: signed,\n    caFingerprint,\n    status: await readCertificateRenewal(paths.certFile, now),\n  })\n}\n\n/**\n * Build the read-only self-check payload shown in the desktop panel.\n *\n * No secret ever leaves this function: the CA is reported by fingerprint only,\n * and the token is never read.\n */\nexport async function frpIngressSelfCheck(settings: FrpSettings, stateFile: string, ownedRoot: string = dirname(stateFile)): Promise<FrpIngressSelfCheck> {\n  const paths = frpIngressPaths(stateFile)\n  const base = {\n    mode: resolveFrpMode(settings),\n    entryTls: resolveFrpEntryTls(settings),\n    vhostHttpPort: resolveFrpVhostHttpPort(settings),\n    publicPort: resolveFrpPublicPort(settings),\n    publicOrigin: settings.publicOrigin,\n    entryOrigin: frpEntryOrigin(settings),\n    serverAddress: settings.serverAddress,\n    serverPort: settings.serverPort,\n    inbound: { listenHost: '127.0.0.1' as const, allowedCidrs: Object.freeze(['127.0.0.0/8']) },\n  }\n  if (!isFrpSelfSignedIngress(settings)) {\n    // The public-CA entry keeps its certificate on the VPS; nothing local to read.\n    return Object.freeze(base)\n  }\n  await assertManagedParents(ownedRoot, paths.caCertFile, 'frp_ingress')\n  await assertManagedParents(ownedRoot, paths.certFile, 'frp_ingress')\n  let caFingerprint: string | undefined\n  try {\n    caFingerprint = new X509Certificate(await readFile(paths.caCertFile)).fingerprint256.replaceAll(':', '').toLowerCase()\n  } catch {\n    caFingerprint = undefined\n  }\n  return Object.freeze({\n    ...base,\n    ...(caFingerprint === undefined ? {} : { caFingerprint }),\n    certificate: await readCertificateRenewal(paths.certFile),\n    caCertificate: await readCertificateRenewal(paths.caCertFile),\n  })\n}\n\n/** Remove only the five files owned by the local self-signed FRP entry. */\nexport async function purgeFrpIngressCertificates(stateFile: string, ownedRoot: string = dirname(stateFile)): Promise<void> {\n  const paths = frpIngressPaths(stateFile)\n  await assertManagedParents(ownedRoot, paths.statusFile, 'frp_ingress')\n  await assertManagedParents(ownedRoot, paths.directory, 'frp_ingress')\n  try {\n    const marker = await lstat(paths.statusFile)\n    if (!marker.isFile() && !marker.isSymbolicLink()) throw new Error('frp_ingress_file_invalid')\n    await unlink(paths.statusFile)\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n  }\n  let directory\n  try { directory = await lstat(paths.directory) } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return\n    throw error\n  }\n  if (directory.isSymbolicLink()) {\n    await unlink(paths.directory)\n    return\n  }\n  if (!directory.isDirectory()) throw new Error('frp_ingress_directory_invalid')\n  for (const file of [paths.caCertFile, paths.caKeyFile, paths.certFile, paths.keyFile]) {\n    await assertManagedParents(ownedRoot, file, 'frp_ingress')\n    let entry\n    try { entry = await lstat(file) } catch (error) {\n      if ((error as NodeJS.ErrnoException).code === 'ENOENT') continue\n      throw error\n    }\n    if (!entry.isFile() && !entry.isSymbolicLink()) throw new Error('frp_ingress_file_invalid')\n    await unlink(file)\n  }\n  try {\n    await assertManagedParents(ownedRoot, paths.directory, 'frp_ingress')\n    await rmdir(paths.directory)\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return\n    throw error\n  }\n}\n","import { randomBytes } from 'node:crypto'\nimport type { ChildProcess } from 'node:child_process'\nimport { lstat, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { basename, dirname, join } from 'node:path'\nimport type { MobileAccessGateway } from './gateway.js'\nimport type { MobileAccessControlState } from './control.js'\nimport { restrictPrivateFile } from './private-file.js'\n\n/** Remote transports supported by the desktop plugin and Android client. */\nexport type RemoteProvider = 'tailscale' | 'cpolar' | 'cloudflared' | 'frp' | 'origin'\n\n/** Common safe status returned by every remote provider controller. */\nexport interface RemoteProviderStatus {\n  readonly enabled: boolean\n  readonly state: string\n  readonly origin?: string\n  readonly backendOrigin?: string\n  readonly loginUrl?: string\n  readonly setupUrl?: string\n  readonly errorCode?: string\n}\n\n/** Lifecycle shared by selectable remote providers. */\nexport interface RemoteProviderController {\n  /**\n   * Initialize from the current startup preparation, without retaining a permission-success cache.\n   * @param initialState - Fresh state prepared by this controller's own store; omission reads that store.\n   * @returns Completion of the normal provider initialization and optional startup.\n   */\n  initialize(initialState?: MobileAccessControlState): Promise<void>\n  gateway(): MobileAccessGateway | undefined\n  status(): RemoteProviderStatus\n  setEnabled(enabled: boolean): Promise<RemoteProviderStatus>\n  reconnect(): Promise<RemoteProviderStatus>\n  reset(): Promise<RemoteProviderStatus>\n  close(): Promise<void>\n}\n\n/** Durable selection for the single active remote transport. */\nexport interface RemoteProviderState {\n  readonly version: 1\n  readonly provider: RemoteProvider\n}\n\nexport const REMOTE_PROVIDERS: readonly RemoteProvider[] = Object.freeze(['tailscale', 'cpolar', 'cloudflared', 'frp', 'origin'])\n\n/** Persist only the selected remote provider. */\nexport interface RemoteProviderStore {\n  save(state: RemoteProviderState): Promise<void>\n}\n\nfunction aggregateErrors(errors: readonly unknown[], message: string): Error | undefined {\n  if (errors.length === 0) return undefined\n  if (errors.length === 1 && errors[0] instanceof Error) return errors[0]\n  return new AggregateError(errors, message)\n}\n\n/**\n * Prepare each inactive provider's disabled state and settle every write before reporting a failure.\n * @param selected - Provider whose startup must still read its durable preference.\n * @param stores - The same stores supplied to the corresponding provider controllers.\n * @returns Fresh disabled states for this initialization only; no permission-success cache is retained.\n */\nexport async function prepareDisabledRemoteProviders(\n  selected: RemoteProvider,\n  stores: Readonly<Record<RemoteProvider, { disableIfPresent(): Promise<MobileAccessControlState> }>>,\n): Promise<ReadonlyMap<RemoteProvider, MobileAccessControlState>> {\n  const results = await Promise.allSettled(REMOTE_PROVIDERS\n    .filter(provider => provider !== selected)\n    .map(async provider => [provider, await stores[provider].disableIfPresent()] as const))\n  const errors: unknown[] = results.filter(result => result.status === 'rejected').map(result => result.reason)\n  const failure = aggregateErrors(errors, 'remote provider control preparation failed')\n  if (failure !== undefined) throw failure\n  return new Map(results.flatMap(result => result.status === 'fulfilled' ? [result.value] : []))\n}\n\n/** Settle independent remote cleanup work before reporting any collected failure. */\nexport async function settleRemoteResources(\n  steps: readonly (() => void | Promise<void>)[],\n  message = 'remote resource cleanup failed',\n): Promise<void> {\n  const results = await Promise.allSettled(steps.map(async step => step()))\n  const errors = results\n    .filter(result => result.status === 'rejected')\n    .map(result => result.reason as unknown)\n  const failure = aggregateErrors(errors, message)\n  if (failure !== undefined) throw failure\n}\n\n/**\n * Serialize all provider mutations and preserve the single-provider invariant.\n * Operations read the selected controller only after reaching the front of the queue.\n */\nexport class RemoteProviderCoordinator {\n  private selectedValue: RemoteProvider\n  private queue: Promise<void> = Promise.resolve()\n\n  constructor(\n    selected: RemoteProvider,\n    private readonly controllers: Readonly<Record<RemoteProvider, RemoteProviderController>>,\n    private readonly store: RemoteProviderStore,\n  ) {\n    this.selectedValue = selected\n  }\n\n  /** Return the durable provider currently selected by the desktop UI. */\n  get selected(): RemoteProvider {\n    return this.selectedValue\n  }\n\n  /** Return the controller selected when this method is called. */\n  controller(): RemoteProviderController {\n    return this.controllers[this.selectedValue]\n  }\n\n  /** Run a provider-owned mutation after all earlier provider work settles. */\n  mutate<T>(operation: (controller: RemoteProviderController) => Promise<T>): Promise<T> {\n    return this.enqueue(() => operation(this.controller()))\n  }\n\n  /** Apply one operation only while its intended provider remains selected.\n   * @param provider - Provider the caller explicitly chose.\n   * @param operation - Configuration and activation performed in the same queue item.\n   * @returns The operation result, or a rejection when another selection won the queue.\n   */\n  mutateSelected<T>(provider: RemoteProvider, operation: (controller: RemoteProviderController) => Promise<T>): Promise<T> {\n    return this.enqueue(async () => {\n      if (provider !== this.selectedValue) throw new Error('remote_provider_changed')\n      return operation(this.controller())\n    })\n  }\n\n  /** Disable the previous provider, persist the new selection, and retain rollback on write failure. */\n  select(provider: RemoteProvider): Promise<void> {\n    return this.enqueue(async () => {\n      if (provider === this.selectedValue) return\n      const previous = this.controllers[this.selectedValue]\n      const restore = previous.status().enabled\n      if (restore) await previous.setEnabled(false)\n      try {\n        await this.store.save({ version: 1, provider })\n        this.selectedValue = provider\n      } catch (error) {\n        if (restore) {\n          try { await previous.setEnabled(true) }\n          catch (restoreError) { throw new AggregateError([error, restoreError], 'remote provider selection rollback failed') }\n        }\n        throw error\n      }\n    })\n  }\n\n  private enqueue<T>(operation: () => Promise<T>): Promise<T> {\n    const task = this.queue.then(\n      () => this.runAndEnforce(operation),\n      () => this.runAndEnforce(operation),\n    )\n    this.queue = task.then(() => undefined, () => undefined)\n    return task\n  }\n\n  private async runAndEnforce<T>(operation: () => Promise<T>): Promise<T> {\n    let value: T | undefined\n    let operationError: unknown\n    try { value = await operation() } catch (error) { operationError = error }\n    const results = await Promise.allSettled(\n      REMOTE_PROVIDERS\n        .filter(provider => provider !== this.selectedValue)\n        .map(provider => this.controllers[provider].setEnabled(false)),\n    )\n    const errors = [\n      ...(operationError === undefined ? [] : [operationError]),\n      ...results.filter(result => result.status === 'rejected').map(result => result.reason as unknown),\n    ]\n    const failure = aggregateErrors(errors, 'remote provider operation failed')\n    if (failure !== undefined) throw failure\n    return value as T\n  }\n}\n\n/** Stop an owned provider process and do not report completion before its close event. */\nexport async function terminateRemoteProcess(\n  child: ChildProcess,\n  gracefulTimeoutMs = 1_500,\n  forcedTimeoutMs = 1_500,\n): Promise<void> {\n  if (child.exitCode !== null || child.signalCode !== null) return\n  await new Promise<void>((resolveClose, rejectClose) => {\n    let gracefulTimer: NodeJS.Timeout | undefined\n    let forcedTimer: NodeJS.Timeout | undefined\n    let settled = false\n    const finish = (error?: Error): void => {\n      if (settled) return\n      settled = true\n      if (gracefulTimer !== undefined) clearTimeout(gracefulTimer)\n      if (forcedTimer !== undefined) clearTimeout(forcedTimer)\n      child.off('close', onClose)\n      if (error === undefined) resolveClose()\n      else rejectClose(error)\n    }\n    const onClose = (): void => { finish() }\n    child.once('close', onClose)\n    try { child.kill('SIGTERM') } catch (error) {\n      finish(error instanceof Error ? error : new Error(String(error)))\n      return\n    }\n    if (settled) return\n    gracefulTimer = setTimeout(() => {\n      try {\n        if (child.exitCode === null && child.signalCode === null) child.kill('SIGKILL')\n      } catch (error) {\n        finish(error instanceof Error ? error : new Error(String(error)))\n        return\n      }\n      if (settled) return\n      forcedTimer = setTimeout(() => {\n        finish(new Error('remote_process_stop_timeout'))\n      }, forcedTimeoutMs)\n      forcedTimer.unref()\n    }, gracefulTimeoutMs)\n    gracefulTimer.unref()\n  })\n}\n\n/** Validate the provider selection loaded across the filesystem boundary. */\nexport function parseRemoteProviderState(value: unknown): RemoteProviderState {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n    throw new Error('remote provider state must be an object')\n  }\n  const record = value as Record<string, unknown>\n  if (record.version !== 1\n    || (record.provider !== 'tailscale' && record.provider !== 'cpolar' && record.provider !== 'cloudflared'\n      && record.provider !== 'frp' && record.provider !== 'origin')\n    || Reflect.ownKeys(record).some(key => key !== 'version' && key !== 'provider')) {\n    throw new Error('remote provider state has an unsupported format')\n  }\n  return Object.freeze({ version: 1, provider: record.provider })\n}\n\n/** Atomic selection store whose absent-file state uses the configured default. */\nexport class JsonRemoteProviderStore {\n  constructor(private readonly file: string, private readonly defaultProvider: RemoteProvider) {}\n\n  async load(): Promise<RemoteProviderState> {\n    let stat\n    try {\n      stat = await lstat(this.file)\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n        return Object.freeze({ version: 1, provider: this.defaultProvider })\n      }\n      throw error\n    }\n    if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 4096) {\n      throw new Error('remote provider state must be a regular file no larger than 4 KiB')\n    }\n    await restrictPrivateFile(this.file)\n    let parsed: unknown\n    try { parsed = JSON.parse(await readFile(this.file, 'utf8')) as unknown } catch (error) {\n      throw new Error('remote provider state is not valid JSON', { cause: error })\n    }\n    return parseRemoteProviderState(parsed)\n  }\n\n  async save(state: RemoteProviderState): Promise<void> {\n    const validated = parseRemoteProviderState(state)\n    const directory = dirname(this.file)\n    await mkdir(directory, { recursive: true, mode: 0o700 })\n    try {\n      const current = await lstat(this.file)\n      if (!current.isFile() || current.isSymbolicLink()) {\n        throw new Error('remote provider state target must remain a regular file')\n      }\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n    }\n    const temporary = join(directory, `.${basename(this.file)}.${randomBytes(12).toString('hex')}.tmp`)\n    try {\n      await writeFile(temporary, `${JSON.stringify(validated)}\\n`, { encoding: 'utf8', flag: 'wx', mode: 0o600 })\n      await rename(temporary, this.file)\n      await restrictPrivateFile(this.file)\n    } catch (error) {\n      await rm(temporary, { force: true })\n      throw error\n    }\n  }\n}\n\n/** Resolve the first-run provider without letting environment values bypass validation. */\nexport function configuredRemoteProvider(environment: NodeJS.ProcessEnv): RemoteProvider {\n  const value = environment.DSH_MOBILE_REMOTE_PROVIDER ?? 'tailscale'\n  if (value !== 'tailscale' && value !== 'cpolar' && value !== 'cloudflared' && value !== 'frp' && value !== 'origin') {\n    throw new Error('DSH_MOBILE_REMOTE_PROVIDER must be tailscale, cpolar, cloudflared, frp, or origin')\n  }\n  return value\n}\n","import { spawn, execFile, type ChildProcessWithoutNullStreams } from 'node:child_process'\nimport { lstat, rm } from 'node:fs/promises'\nimport { request as httpsRequest } from 'node:https'\nimport type { ClientRequest, IncomingMessage } from 'node:http'\nimport { connect } from 'node:net'\nimport { isAbsolute } from 'node:path'\nimport { Readable } from 'node:stream'\nimport type { MobileAccessControlState, MobileAccessControlStore } from './control.js'\nimport type { FrpConfigStore, FrpSettings } from './frp-config.js'\nimport { frpEntryOrigin, isFrpSelfSignedIngress, resolveFrpVhostHttpPort } from './frp-config.js'\nimport type { MobileAccessGateway } from './gateway.js'\nimport { settleRemoteResources, terminateRemoteProcess, type RemoteProviderController } from './remote.js'\n\nconst START_TIMEOUT_MS = 45_000\nconst DISCOVERY_REQUEST_TIMEOUT_MS = 5_000\nconst DISCOVERY_RETRY_MS = 1_000\nconst MAX_DISCOVERY_BYTES = 16 * 1024\nconst VHOST_PROBE_TIMEOUT_MS = 1_500\nconst INGRESS_CERT_CHECK_MS = 12 * 60 * 60_000\n/** Cap on the frpc output retained for start-failure diagnosis. */\nconst MAX_CLIENT_DIAGNOSIS_CHARS = 8 * 1024\n\n/**\n * frpc start-failure signatures, most specific first.\n *\n * frpc reports a refused proxy registration as a warning and keeps running, so\n * without this mapping the controller only ever saw a healthy child process and\n * an entry port nobody published: the start-up self-check burned its full 45s\n * deadline and reported `frp_start_timeout` (\"the public endpoint did not become\n * ready\"), which sent users looking at DNS, Caddy, and firewalls.\n *\n * The two real conflicts are a proxy name another client of the same frps holds\n * and an entry port another proxy already owns. Both are reported directly.\n */\nconst CLIENT_FAILURE_CODES: readonly (readonly [RegExp, string])[] = Object.freeze([\n  [/proxy name \\[[^\\]]*\\] is already in use/iu, 'frp_proxy_name_in_use'],\n  [/(?:remote )?port (?:\\[?[0-9]+\\]? )?already (?:used|in use)/iu, 'frp_remote_port_in_use'],\n  [/start error:/iu, 'frp_proxy_start_failed'],\n])\n\n/**\n * Stable error code for a chunk of frpc output, or undefined when it reports no\n * start failure. Exported for the conflict tests.\n */\nexport function frpcDiagnosisCode(output: string): string | undefined {\n  return CLIENT_FAILURE_CODES.find(([pattern]) => pattern.test(output))?.[1]\n}\n\n/** Product-facing states for the restricted self-hosted FRP transport. */\nexport type FrpState = 'off' | 'unavailable' | 'starting' | 'connecting' | 'ready' | 'error'\n\n/** Safe FRP state returned only through the loopback DSH control route. */\nexport interface FrpStatus {\n  readonly enabled: boolean\n  readonly state: FrpState\n  readonly origin?: string\n  readonly errorCode?: string\n}\n\n/**\n * Explicit target of the start-up discovery self-check.\n *\n * The target is derived from the effective entry, never assumed: the public-CA\n * entry answers on the saved origin (443 behind Caddy, publicly trusted chain),\n * while the self-signed entry is a raw TCP passthrough on `publicPort` whose\n * leaf chains to the plugin's own ingress CA.\n */\nexport interface FrpDiscoveryProbeTarget {\n  /** Absolute HTTPS origin to dial, including the public entry port. */\n  readonly origin: string\n  /**\n   * PEM bundle that anchors the entry leaf in place of the system trust store.\n   * Absent keeps the default chain, which is correct for a publicly trusted\n   * certificate; it is never a way to skip verification.\n   */\n  readonly trustAnchorPem?: string\n}\n\n/** Derived self-check target plus the origin the panel is told about. */\ninterface FrpDiscoveryCheck {\n  /** Origin reported once the channel is ready; the actual HTTPS entry. */\n  readonly publicOrigin: string\n  /** Absolute origin the probe dials, including the effective entry port. */\n  readonly targetOrigin: string\n  /** Present only for the self-signed entry, where it must be pinned. */\n  readonly trustAnchorPem?: string\n}\n\n/** Inputs for one FRP client process and authenticated DSH gateway. */\nexport interface FrpControllerOptions {\n  readonly store: MobileAccessControlStore\n  readonly executable: string\n  readonly config: FrpConfigStore\n  /**\n   * Plugin-wide installation identity (the LAN pairing CA fingerprint).\n   *\n   * Retained for backward compatibility and constructor validation only. It no\n   * longer takes part in the start-up self-check: that check compares against the\n   * identity of the gateway this controller created and advertises, because the\n   * self-signed FRP ingress gateway is pinned to the ingress CA fingerprint by\n   * design, and that value deliberately differs from this one.\n   */\n  readonly instanceId: string\n  readonly createGateway: (origin: string, settings: FrpSettings) => Promise<MobileAccessGateway>\n  readonly onStatus?: (status: FrpStatus) => void\n  readonly verifyConfig?: (executable: string, configFile: string) => Promise<void>\n  readonly launchClient?: (executable: string, configFile: string) => ChildProcessWithoutNullStreams\n  readonly probeVhostExposure?: (serverAddress: string, port: number) => Promise<boolean>\n  readonly probeDiscovery?: (target: FrpDiscoveryProbeTarget, expectedInstanceId: string, signal: AbortSignal) => Promise<boolean>\n  /**\n   * Resolve the CA the self-check must pin for the self-signed entry.\n   *\n   * Only the composing plugin knows where the ingress material lives, so the\n   * trust anchor is injected instead of guessed here. Consulted solely for the\n   * self-signed passthrough; the public-CA entry always keeps the system trust\n   * store. A configured resolver that cannot provide the CA fails startup with\n   * `frp_ingress_ca_invalid`; the system trust store must not mask that failure.\n   */\n  readonly resolveDiscoveryTrustAnchor?: (settings: FrpSettings) => Promise<string | undefined>\n  /** Re-issue an expiring leaf and reload the live TLS listener without changing its CA. */\n  readonly maintainIngressCertificate?: (settings: FrpSettings, gateway: MobileAccessGateway) => Promise<void>\n  /** Test seam for the maintenance timer; the product uses a twelve-hour interval. */\n  readonly ingressCertificateCheckMs?: number\n  readonly startTimeoutMs?: number\n  readonly retryIntervalMs?: number\n}\n\nfunction publicStatus(status: FrpStatus): FrpStatus {\n  return Object.freeze({\n    enabled: status.enabled,\n    state: status.state,\n    ...(status.origin === undefined ? {} : { origin: status.origin }),\n    ...(status.errorCode === undefined ? {} : { errorCode: status.errorCode }),\n  })\n}\n\nasync function defaultVerifyConfig(executable: string, configFile: string): Promise<void> {\n  await new Promise<void>((resolveRun, reject) => {\n    execFile(executable, ['verify', '-c', configFile], {\n      windowsHide: true,\n      timeout: 30_000,\n      maxBuffer: 64 * 1024,\n    }, error => {\n      if (error === null) resolveRun()\n      else reject(error)\n    })\n  })\n}\n\nfunction defaultLaunchClient(executable: string, configFile: string): ChildProcessWithoutNullStreams {\n  return spawn(executable, ['-c', configFile], {\n    shell: false,\n    stdio: ['pipe', 'pipe', 'pipe'],\n    windowsHide: true,\n  })\n}\n\nasync function defaultProbeVhostExposure(serverAddress: string, port: number): Promise<boolean> {\n  return new Promise<boolean>(resolveProbe => {\n    const socket = connect({ host: serverAddress, port })\n    let finished = false\n    let received = ''\n    const finish = (exposed: boolean): void => {\n      if (finished) return\n      finished = true\n      clearTimeout(timer)\n      socket.destroy()\n      resolveProbe(exposed)\n    }\n    const timer = setTimeout(() => { finish(false) }, VHOST_PROBE_TIMEOUT_MS)\n    timer.unref()\n    socket.once('connect', () => {\n      // A transparent proxy/TUN can acknowledge every TCP connect even when\n      // the remote port is closed. Require an actual HTTP response from the\n      // FRP vhost listener before treating the plaintext port as exposed.\n      socket.write('GET /dsh-mobile-exposure-probe HTTP/1.1\\r\\nHost: invalid.example\\r\\nConnection: close\\r\\n\\r\\n')\n    })\n    socket.on('data', chunk => {\n      received = `${received}${chunk.toString('latin1')}`.slice(0, 32)\n      if (/^HTTP\\/1\\.[01] [1-5][0-9]{2}/u.test(received)) finish(true)\n    })\n    socket.once('close', () => { finish(false) })\n    socket.once('error', () => { finish(false) })\n  })\n}\n\nasync function boundedResponseBytes(response: Response): Promise<Uint8Array> {\n  if (response.body === null) throw new Error('frp_discovery_invalid')\n  const declaredLength = Number(response.headers.get('content-length'))\n  if (Number.isFinite(declaredLength) && declaredLength > MAX_DISCOVERY_BYTES) throw new Error('frp_discovery_invalid')\n  const reader = response.body.getReader()\n  const chunks: Uint8Array[] = []\n  let received = 0\n  while (true) {\n    const result = await reader.read()\n    if (result.done) break\n    received += result.value.byteLength\n    if (received > MAX_DISCOVERY_BYTES) {\n      await reader.cancel()\n      throw new Error('frp_discovery_invalid')\n    }\n    chunks.push(result.value)\n  }\n  const bytes = new Uint8Array(received)\n  let offset = 0\n  for (const chunk of chunks) {\n    bytes.set(chunk, offset)\n    offset += chunk.byteLength\n  }\n  return bytes\n}\n\n/** Web view over an HTTPS response so the byte cap applies to both paths alike. */\nfunction discoveryResponse(message: IncomingMessage): Response {\n  const headers = new Headers()\n  const declaredLength = message.headers['content-length']\n  if (declaredLength !== undefined) headers.set('content-length', declaredLength)\n  return new Response(Readable.toWeb(message) as ReadableStream<Uint8Array>, {\n    status: message.statusCode ?? 200,\n    headers,\n  })\n}\n\n/**\n * Perform one discovery request against the public entry.\n *\n * `node:https` carries this request instead of the global `fetch` for a single\n * reason: only here can the trust anchor be stated. The self-signed entry\n * presents a leaf the plugin's own ingress CA signed, so the default chain\n * always fails there (`UNABLE_TO_VERIFY_LEAF_SIGNATURE`) even though the\n * transport itself is healthy. The anchor is *added* to the trust store — never\n * `rejectUnauthorized: false` — so the peer must still prove its identity, and\n * the verified name stays the host of the origin, which is the name the app\n * dials as well (Node matches IP literals against `IP Address:` SANs).\n *\n * A non-200 answer resolves `undefined` for retry; discovery requires a body.\n * transport, TLS, and timeout failures reject so the caller keeps retrying.\n * The request stays cancellable until the bounded response body has completed.\n */\nfunction requestDiscovery(\n  target: FrpDiscoveryProbeTarget,\n  signal: AbortSignal,\n): Promise<Uint8Array | undefined> {\n  if (signal.aborted) return Promise.reject(new Error('frp_discovery_aborted'))\n  const url = new URL(`${target.origin}/mobile-access/discovery`)\n  if (url.protocol !== 'https:' || url.hostname === '') return Promise.reject(new Error('frp_discovery_invalid'))\n  return new Promise<Uint8Array | undefined>((resolveRequest, rejectRequest) => {\n    let settled = false\n    let request: ClientRequest | undefined\n    const release = (): void => {\n      clearTimeout(timeout)\n      signal.removeEventListener('abort', onAbort)\n    }\n    const fail = (error: Error): void => {\n      if (settled) return\n      settled = true\n      release()\n      request?.destroy()\n      rejectRequest(error)\n    }\n    const succeed = (value: Uint8Array | undefined): void => {\n      if (settled) return\n      settled = true\n      release()\n      resolveRequest(value)\n    }\n    const onAbort = (): void => { fail(new Error('frp_discovery_aborted')) }\n    // The request timeout spans the whole exchange, body included: it is released\n    // only once the response socket is done, which is exactly what the aborted\n    // fetch used to do. A timeout after the headers still tears the body read\n    // down, so a stalled body keeps retrying instead of hanging forever.\n    const timeout = setTimeout(() => { fail(new Error('frp_discovery_timeout')) }, DISCOVERY_REQUEST_TIMEOUT_MS)\n    timeout.unref()\n    signal.addEventListener('abort', onAbort, { once: true })\n    request = httpsRequest({\n      host: url.hostname,\n      port: url.port === '' ? 443 : Number(url.port),\n      path: url.pathname,\n      method: 'GET',\n      headers: { accept: 'application/json' },\n      // Adding the anchor keeps certificate verification and the hostname check\n      // switched on; it only widens what counts as a trusted issuer.\n      ...(target.trustAnchorPem === undefined ? {} : { ca: target.trustAnchorPem }),\n      // One fresh connection per attempt: a pooled socket must never let a stale\n      // handshake decide the state of a new generation.\n      agent: false,\n    }, message => {\n      const status = message.statusCode ?? 0\n      if (status !== 200) {\n        succeed(undefined)\n        message.destroy()\n        return\n      }\n      void boundedResponseBytes(discoveryResponse(message)).then(succeed, fail)\n    })\n    request.once('error', error => {\n      fail(error instanceof Error ? error : new Error('frp_discovery_request_failed'))\n    })\n    request.end()\n  })\n}\n\n/**\n * Read the public discovery advertisement and compare it with the expected\n * identity.\n *\n * `frp_discovery_invalid` (malformed body) and `frp_discovery_mismatch` (the\n * entry advertises another identity) stay immediate failures; transport, TLS,\n * and timeout problems reject so the caller retries until its deadline.\n */\nexport async function defaultProbeDiscovery(\n  target: FrpDiscoveryProbeTarget,\n  expectedInstanceId: string,\n  signal: AbortSignal,\n): Promise<boolean> {\n  // The byte cap, transport faults, and timeout all cover the complete body;\n  // a peer that sends only headers cannot leave the controller connecting forever.\n  const bytes = await requestDiscovery(target, signal)\n  if (bytes === undefined) return false\n  let value: unknown\n  try { value = JSON.parse(new TextDecoder().decode(bytes)) as unknown } catch {\n    throw new Error('frp_discovery_invalid')\n  }\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('frp_discovery_invalid')\n  const actual = (value as Record<string, unknown>).instanceId\n  if (typeof actual !== 'string') throw new Error('frp_discovery_invalid')\n  if (actual !== expectedInstanceId) throw new Error('frp_discovery_mismatch')\n  return true\n}\n\n/** Owns frpc, its generation-specific configuration, and the remote gateway. */\nexport class FrpController implements RemoteProviderController {\n  private enabled = false\n  private initialized = false\n  private disposed = false\n  private child: ChildProcessWithoutNullStreams | undefined\n  private gatewayValue: MobileAccessGateway | undefined\n  private generation = 0\n  private latest: FrpStatus = publicStatus({ enabled: false, state: 'off' })\n  private queue: Promise<void> = Promise.resolve()\n  private startupAbort: AbortController | undefined\n  private ingressCertificateTimer: NodeJS.Timeout | undefined\n\n  constructor(private readonly options: FrpControllerOptions) {\n    if (!isAbsolute(options.executable)) throw new Error('frpc executable path must be absolute')\n    if (!/^[a-f0-9]{64}$/u.test(options.instanceId)) throw new Error('FRP instance ID is invalid')\n    if (options.ingressCertificateCheckMs !== undefined\n      && (!Number.isSafeInteger(options.ingressCertificateCheckMs)\n        || options.ingressCertificateCheckMs < 1 || options.ingressCertificateCheckMs > 2_147_483_647)) {\n      throw new Error('frp_ingress_check_interval_invalid')\n    }\n  }\n\n  /** Restore the remembered FRP switch without changing LAN or other providers. */\n  async initialize(initialState?: MobileAccessControlState): Promise<void> {\n    const state = initialState ?? await this.options.store.load()\n    this.enabled = state.enabled\n    this.initialized = true\n    if (this.enabled) await this.start()\n    else this.publish({ enabled: false, state: 'off' })\n  }\n\n  /** Return the active FRP-backed DSH gateway. */\n  gateway(): MobileAccessGateway | undefined {\n    return this.gatewayValue\n  }\n\n  /** Return state safe for the desktop control UI. */\n  status(): FrpStatus {\n    return publicStatus(this.latest)\n  }\n\n  /** Enable or disable FRP without changing LAN or another provider. */\n  async setEnabled(enabled: boolean): Promise<FrpStatus> {\n    if (!this.initialized || this.disposed) throw new Error('FRP controller is unavailable')\n    await this.enqueue(async () => {\n      if (this.enabled === enabled && (enabled === false || this.child !== undefined)) return\n      await this.options.store.save({ version: 1, enabled })\n      this.enabled = enabled\n      if (!enabled) await this.stop()\n      if (enabled) await this.start()\n      else this.publish({ enabled: false, state: 'off' })\n    })\n    return this.status()\n  }\n\n  /** Restart FRP while retaining its private server settings and devices. */\n  async reconnect(): Promise<FrpStatus> {\n    if (!this.initialized || this.disposed) throw new Error('FRP controller is unavailable')\n    await this.enqueue(async () => {\n      if (!this.enabled) {\n        await this.options.store.save({ version: 1, enabled: true })\n        this.enabled = true\n      }\n      await this.stop()\n      await this.start()\n    })\n    return this.status()\n  }\n\n  /** Disable FRP without deleting its explicitly managed component or settings. */\n  async reset(): Promise<FrpStatus> {\n    if (!this.initialized || this.disposed) throw new Error('FRP controller is unavailable')\n    await this.enqueue(async () => {\n      await this.options.store.save({ version: 1, enabled: false })\n      this.enabled = false\n      await this.stop()\n      this.publish({ enabled: false, state: 'off' })\n    })\n    return this.status()\n  }\n\n  /** Stop all FRP resources without changing the remembered switch. */\n  async close(): Promise<void> {\n    if (this.disposed) return\n    this.disposed = true\n    await this.enqueue(() => this.stop())\n  }\n\n  private enqueue(operation: () => Promise<void>): Promise<void> {\n    const task = this.queue.then(operation, operation)\n    this.queue = task.then(() => undefined, () => undefined)\n    return task\n  }\n\n  private publish(status: FrpStatus): void {\n    this.latest = publicStatus(status)\n    try { this.options.onStatus?.(this.status()) } catch { /* UI observation cannot own runtime state. */ }\n  }\n\n  private async start(): Promise<void> {\n    const generation = ++this.generation\n    let executableEntry\n    try { executableEntry = await lstat(this.options.executable) } catch {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'frp_component_missing' })\n      return\n    }\n    if (!executableEntry.isFile() || executableEntry.isSymbolicLink()) {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'frp_component_invalid' })\n      return\n    }\n    const settings = this.options.config.settings()\n    if (settings === undefined) {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'frp_config_missing' })\n      return\n    }\n    const entryOrigin = frpEntryOrigin(settings)\n    this.publish({ enabled: true, state: 'starting', origin: entryOrigin })\n    // The plaintext-vhost gate must probe the port the user's frps actually\n    // listens on. Probing the hard-coded upstream 7080 would report \"not\n    // exposed\" for a reachable vhost on any other port and let a cleartext\n    // session-cookie path through.\n    //\n    // The self-signed entry is a raw TCP passthrough with no vhost at all, so\n    // the probe does not apply: there the equivalent exposure — the public entry\n    // port being reachable — is the design itself, and protection comes from the\n    // gateway's own device pairing and authentication.\n    if (!isFrpSelfSignedIngress(settings)) {\n      let exposed: boolean\n      try {\n        exposed = await (this.options.probeVhostExposure ?? defaultProbeVhostExposure)(\n          settings.serverAddress,\n          resolveFrpVhostHttpPort(settings),\n        )\n      } catch {\n        this.publish({ enabled: true, state: 'error', origin: entryOrigin, errorCode: 'frp_vhost_probe_failed' })\n        return\n      }\n      if (exposed) {\n        this.publish({ enabled: true, state: 'error', origin: entryOrigin, errorCode: 'frp_vhost_publicly_reachable' })\n        return\n      }\n    }\n    let gateway: MobileAccessGateway\n    try { gateway = await this.options.createGateway(settings.publicOrigin, settings) } catch (error) {\n      // Ingress certificate problems carry their own stable code so the panel can\n      // explain how to re-issue it instead of showing a generic start failure.\n      const code = error instanceof Error && error.message.startsWith('frp_') ? error.message : 'gateway_start_failed'\n      this.publish({ enabled: true, state: 'error', origin: entryOrigin, errorCode: code })\n      return\n    }\n    if (generation !== this.generation || !this.enabled) {\n      await gateway.close()\n      return\n    }\n    this.gatewayValue = gateway\n    let configFile: string\n    try {\n      configFile = await this.options.config.writeRuntimeConfig(gateway.address().port)\n      await (this.options.verifyConfig ?? defaultVerifyConfig)(this.options.executable, configFile)\n    } catch {\n      await this.failGeneration(generation, 'frp_config_verify_failed')\n      return\n    }\n    if (generation !== this.generation || !this.enabled) return\n    let child: ChildProcessWithoutNullStreams\n    try { child = (this.options.launchClient ?? defaultLaunchClient)(this.options.executable, configFile) } catch {\n      await this.failGeneration(generation, 'frp_launch_failed')\n      return\n    }\n    this.child = child\n    // frpc can keep running after a refused proxy registration. Buffer each\n    // stream separately so a partial `start error:` chunk cannot hide the more\n    // specific name or port conflict later on the same line.\n    const pending = { stdout: '', stderr: '' }\n    let diagnosed = false\n    const inspectLine = (line: string): void => {\n      if (diagnosed) return\n      const code = frpcDiagnosisCode(line)\n      if (code === undefined) return\n      diagnosed = true\n      void this.enqueue(() => this.failGeneration(generation, code))\n    }\n    const inspect = (stream: 'stdout' | 'stderr', chunk: Buffer | string): void => {\n      if (diagnosed) return\n      const lines = (pending[stream] + String(chunk)).split(/\\r\\n|\\r|\\n/u)\n      pending[stream] = (lines.pop() ?? '').slice(-MAX_CLIENT_DIAGNOSIS_CHARS)\n      for (const line of lines) inspectLine(line.slice(-MAX_CLIENT_DIAGNOSIS_CHARS))\n    }\n    child.stdout.on('data', chunk => inspect('stdout', chunk))\n    child.stderr.on('data', chunk => inspect('stderr', chunk))\n    child.stdout.resume()\n    child.stderr.resume()\n    child.once('error', () => { void this.enqueue(() => this.failGeneration(generation, 'frp_launch_failed')) })\n    child.once('close', code => {\n      inspectLine(pending.stdout)\n      inspectLine(pending.stderr)\n      if (generation !== this.generation || this.child !== child) return\n      this.child = undefined\n      if (this.enabled && !diagnosed) void this.enqueue(() => this.failGeneration(generation, code === 0 ? 'frp_stopped' : 'frp_exited'))\n    })\n    this.publish({ enabled: true, state: 'connecting', origin: entryOrigin })\n    // The probe target is derived from the effective entry *before* the abort\n    // controller exists, so reading the ingress anchor can never resurrect it\n    // after a concurrent stop.\n    let check: FrpDiscoveryCheck\n    try { check = await this.discoveryCheck(settings) } catch (error) {\n      const code = error instanceof Error && error.message.startsWith('frp_')\n        ? error.message : 'frp_ingress_ca_invalid'\n      await this.failGeneration(generation, code)\n      return\n    }\n    if (generation !== this.generation || !this.enabled) return\n    // A conflict reported while the ingress material was being resolved already\n    // failed this generation; continuing would overwrite that diagnosis with the\n    // generic deadline code.\n    if (diagnosed) return\n    const controller = new AbortController()\n    this.startupAbort = controller\n    // The self-check must compare the public advertisement against the identity\n    // *this* gateway advertises, never the plugin-wide installation identity.\n    // The self-signed ingress gateway is pinned to the ingress CA fingerprint\n    // (`frpIngressGatewayConfig`), which is exactly what the app pins from\n    // `pairingCaFile`, so the plugin identity can never match there and the\n    // channel would only ever end in `frp_start_timeout`. For the public-CA entry\n    // both values are equal, so that path is unchanged. `discoveryCheck` supplies\n    // the other half of the contract: the port that is actually dialled and, for\n    // the self-signed entry, the CA that must anchor the handshake.\n    void this.waitForDiscovery(generation, check, gateway.config.instanceId, settings, gateway, controller.signal)\n  }\n\n  /**\n   * Derive the self-check target and trust anchor for the effective entry.\n   *\n   * The public-CA entry is reached on the saved origin itself: Caddy terminates\n   * TLS on 443 with a publicly trusted certificate, so the probe must keep the\n   * system trust store and the origin URL untouched. The self-signed entry is a\n   * raw TCP passthrough on `publicPort` whose leaf chains to the ingress CA the\n   * app pins from `pairingCaFile`; probing `publicOrigin` there would knock on\n   * 443 — where nothing listens — with a chain the system cannot verify. Both\n   * facts used to be implicit, and together they kept the channel out of `ready`\n   * until `frp_start_timeout`.\n   */\n  private async discoveryCheck(settings: FrpSettings): Promise<FrpDiscoveryCheck> {\n    if (!isFrpSelfSignedIngress(settings)) {\n      return { publicOrigin: settings.publicOrigin, targetOrigin: settings.publicOrigin }\n    }\n    const targetOrigin = frpEntryOrigin(settings)\n    const trustAnchorPem = await this.options.resolveDiscoveryTrustAnchor?.(settings)\n    if (this.options.resolveDiscoveryTrustAnchor !== undefined && trustAnchorPem === undefined) {\n      throw new Error('frp_ingress_ca_invalid')\n    }\n    return Object.freeze({\n      publicOrigin: targetOrigin,\n      targetOrigin,\n      ...(trustAnchorPem === undefined ? {} : { trustAnchorPem }),\n    })\n  }\n\n  private async waitForDiscovery(\n    generation: number,\n    check: FrpDiscoveryCheck,\n    advertisedInstanceId: string,\n    settings: FrpSettings,\n    gateway: MobileAccessGateway,\n    signal: AbortSignal,\n  ): Promise<void> {\n    const deadline = Date.now() + (this.options.startTimeoutMs ?? START_TIMEOUT_MS)\n    const probe = this.options.probeDiscovery ?? defaultProbeDiscovery\n    const target: FrpDiscoveryProbeTarget = Object.freeze({\n      origin: check.targetOrigin,\n      ...(check.trustAnchorPem === undefined ? {} : { trustAnchorPem: check.trustAnchorPem }),\n    })\n    while (!signal.aborted && Date.now() < deadline) {\n      try {\n        if (await probe(target, advertisedInstanceId, signal)) {\n          await this.enqueue(async () => {\n            if (generation !== this.generation || signal.aborted || !this.enabled) return\n            this.startupAbort = undefined\n            this.publish({ enabled: true, state: 'ready', origin: check.publicOrigin })\n            this.scheduleIngressCertificateCheck(generation, settings, gateway)\n          })\n          return\n        }\n      } catch (error) {\n        if (signal.aborted) return\n        if (error instanceof Error && (error.message === 'frp_discovery_mismatch' || error.message === 'frp_discovery_invalid')) {\n          await this.enqueue(() => this.failGeneration(generation, error.message))\n          return\n        }\n      }\n      await new Promise<void>(resolveWait => {\n        let finished = false\n        const finish = (): void => {\n          if (finished) return\n          finished = true\n          clearTimeout(timer)\n          signal.removeEventListener('abort', finish)\n          resolveWait()\n        }\n        const timer = setTimeout(finish, this.options.retryIntervalMs ?? DISCOVERY_RETRY_MS)\n        timer.unref()\n        signal.addEventListener('abort', finish, { once: true })\n      })\n    }\n    if (!signal.aborted) await this.enqueue(() => this.failGeneration(generation, 'frp_start_timeout'))\n  }\n\n  private scheduleIngressCertificateCheck(generation: number, settings: FrpSettings, gateway: MobileAccessGateway): void {\n    const maintain = this.options.maintainIngressCertificate\n    if (!isFrpSelfSignedIngress(settings) || maintain === undefined) return\n    const timer = setTimeout(() => {\n      if (this.ingressCertificateTimer !== timer) return\n      this.ingressCertificateTimer = undefined\n      void this.enqueue(async () => {\n        if (generation !== this.generation || !this.enabled || this.disposed || this.gatewayValue !== gateway) return\n        try {\n          await maintain(settings, gateway)\n        } catch (error) {\n          const code = error instanceof Error && error.message.startsWith('frp_')\n            ? error.message : 'frp_ingress_renewal_failed'\n          await this.failGeneration(generation, code)\n          return\n        }\n        if (generation === this.generation && this.enabled && !this.disposed && this.gatewayValue === gateway) {\n          this.scheduleIngressCertificateCheck(generation, settings, gateway)\n        }\n      }).catch(() => {\n        if (generation === this.generation && this.enabled && !this.disposed) {\n          this.publish({ enabled: true, state: 'error', errorCode: 'frp_ingress_renewal_failed' })\n        }\n      })\n    }, this.options.ingressCertificateCheckMs ?? INGRESS_CERT_CHECK_MS)\n    timer.unref()\n    this.ingressCertificateTimer = timer\n  }\n\n  private async failGeneration(generation: number, code: string): Promise<void> {\n    if (generation !== this.generation) return\n    await this.stopProcessAndGateway()\n    if (this.enabled) this.publish({ enabled: true, state: 'error', errorCode: code })\n  }\n\n  private async stop(): Promise<void> {\n    ++this.generation\n    await this.stopProcessAndGateway()\n  }\n\n  private async stopProcessAndGateway(): Promise<void> {\n    clearTimeout(this.ingressCertificateTimer)\n    this.ingressCertificateTimer = undefined\n    this.startupAbort?.abort()\n    this.startupAbort = undefined\n    const child = this.child\n    this.child = undefined\n    const gateway = this.gatewayValue\n    this.gatewayValue = undefined\n    await settleRemoteResources([\n      () => child !== undefined && child.exitCode === null ? terminateRemoteProcess(child) : undefined,\n      () => gateway?.close(),\n      () => rm(this.options.config.runtimeConfigFile, { force: true }),\n    ], 'FRP resource cleanup failed')\n  }\n}\n","import { lstat, readFile } from 'node:fs/promises'\nimport { isIP } from './ip.js'\nimport { isAbsolute, join, resolve } from 'node:path'\nimport { addressAllowed, isGloballyRoutableIpv4, isLoopbackAddress, parseCidr } from './network.js'\nimport { restrictPrivateFile } from './private-file.js'\nimport { assertManagedParents, removeManagedTree, writeManagedPrivateFile } from './managed-files.js'\n\nexport const DEFAULT_ORIGIN_LISTEN_PORT = 3444\nconst MAX_SETTINGS_BYTES = 8 * 1024\n/**\n * Ports a user-space listener can actually hold on every supported platform. Below\n * this the bind needs privileges on Linux and macOS and fails with EACCES, which\n * surfaces as a generic start failure rather than a rejected choice.\n */\nconst MIN_ORIGIN_LISTEN_PORT = 1024\n/** The LAN gateway's HTTPS port, held for as long as DSH runs. */\nconst RESERVED_LAN_GATEWAY_PORT = 3443\n/** DSH's own WebServer port; the plugin cannot function while it is taken. */\nconst RESERVED_DSH_WEB_PORT = 3080\nconst PRIVATE_NETWORKS = ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'].map(parseCidr)\nconst TRUSTED_NETWORKS = [...PRIVATE_NETWORKS, parseCidr('127.0.0.0/8')]\n\n/** A private HTTP listener behind a user-managed HTTPS reverse proxy. */\nexport interface OriginSettings {\n  readonly version: 1\n  readonly publicOrigin: string\n  readonly listenHost: string\n  readonly listenPort: number\n  readonly allowedCidrs: readonly string[]\n}\n\n/** Configuration metadata returned only to the local desktop control UI. */\nexport interface OriginConfigurationStatus {\n  readonly configured: boolean\n  readonly publicOrigin?: string\n  readonly listenHost?: string\n  readonly listenPort?: number\n  readonly allowedCidrs?: readonly string[]\n  readonly backendOrigin?: string\n  readonly storagePath: string\n  readonly errorCode?: string\n}\n\n/** Require a public HTTPS origin; custom external ports are supported. */\nexport function validateOriginPublicOrigin(value: unknown): string {\n  if (typeof value !== 'string' || value.length > 512 || /[\\s\\u0000-\\u001f\\u007f\\\\@?#]/u.test(value)) {\n    throw new Error('origin_public_origin_invalid')\n  }\n  let url: URL\n  try { url = new URL(value) } catch { throw new Error('origin_public_origin_invalid') }\n  const host = url.hostname\n  const validHostname = host.length <= 253 && host.includes('.')\n    && host.split('.').every(label => label.length >= 1 && label.length <= 63\n      && /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u.test(label))\n    && !['localhost', 'local', 'lan', 'home', 'internal', 'home.arpa']\n      .some(suffix => host === suffix || host.endsWith('.' + suffix))\n  if (url.protocol !== 'https:' || url.pathname !== '/' || url.username !== '' || url.password !== ''\n    || url.search !== '' || url.hash !== '' || (url.port !== '' && Number(url.port) < 1)\n    || (isIP(host) === 4 ? !isGloballyRoutableIpv4(host) : isIP(host) !== 0 || !validHostname)) {\n    throw new Error('origin_public_origin_invalid')\n  }\n  return url.origin\n}\n\n/** Bind only one explicit loopback or RFC1918 IPv4 interface, never all interfaces. */\nexport function validateOriginListenHost(value: unknown): string {\n  if (typeof value !== 'string' || isIP(value) !== 4\n    || (!isLoopbackAddress(value) && !addressAllowed(value, PRIVATE_NETWORKS))) {\n    throw new Error('origin_listen_host_invalid')\n  }\n  return value\n}\n\nexport function validateOriginListenPort(value: unknown): number {\n  if (!Number.isSafeInteger(value) || Number(value) < MIN_ORIGIN_LISTEN_PORT || Number(value) > 65_535) {\n    throw new Error('origin_listen_port_invalid')\n  }\n  // 3443 is the LAN gateway and 3080 is DSH's own WebServer. Neither is a transient\n  // conflict, so both are refused as choices rather than left to fail on bind.\n  if (value === RESERVED_LAN_GATEWAY_PORT || value === RESERVED_DSH_WEB_PORT) {\n    throw new Error('origin_listen_port_reserved')\n  }\n  return Number(value)\n}\n\n/** Authorize direct proxy socket peers, not untrusted forwarded client headers. */\nexport function validateOriginAllowedCidrs(value: unknown, listenHost: string): readonly string[] {\n  const input = value === undefined && isLoopbackAddress(listenHost) ? ['127.0.0.0/8'] : value\n  if (!Array.isArray(input) || input.length === 0 || input.length > 16) {\n    throw new Error('origin_allowed_cidrs_invalid')\n  }\n  const cidrs: string[] = []\n  for (const entry of input) {\n    if (typeof entry !== 'string' || entry.length > 64 || isIP(entry.split('/')[0] ?? '') !== 4) {\n      throw new Error('origin_allowed_cidrs_invalid')\n    }\n    try {\n      const cidr = parseCidr(entry)\n      if (cidr.bits !== 32 || !TRUSTED_NETWORKS.some(range => cidr.prefix >= range.prefix\n        && addressAllowed(entry.split('/')[0], [range]))) throw new Error('untrusted CIDR')\n      cidrs.push(cidr.source)\n    } catch { throw new Error('origin_allowed_cidrs_invalid') }\n  }\n  if (!isLoopbackAddress(listenHost) && !cidrs.some(cidr => !isLoopbackAddress(cidr.split('/')[0]!))) {\n    throw new Error('origin_allowed_cidrs_invalid')\n  }\n  return Object.freeze([...new Set(cidrs)])\n}\n\n/** Validate both saved settings and local administrative requests. */\nexport function parseOriginSettings(value: unknown): OriginSettings {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('origin_settings_invalid')\n  const record = value as Record<string, unknown>\n  if (Reflect.ownKeys(record).some(key => !['version', 'publicOrigin', 'listenHost', 'listenPort', 'allowedCidrs'].includes(String(key)))\n    || (record.version !== undefined && record.version !== 1)) throw new Error('origin_settings_invalid')\n  const listenHost = validateOriginListenHost(record.listenHost === undefined ? '127.0.0.1' : record.listenHost)\n  return Object.freeze({\n    version: 1,\n    publicOrigin: validateOriginPublicOrigin(record.publicOrigin),\n    listenHost,\n    listenPort: validateOriginListenPort(record.listenPort === undefined ? DEFAULT_ORIGIN_LISTEN_PORT : record.listenPort),\n    allowedCidrs: validateOriginAllowedCidrs(record.allowedCidrs, listenHost),\n  })\n}\n\n/** Owns only origin settings; shared paired-device storage is never removed. */\nexport class OriginConfigStore {\n  readonly stateRoot: string\n  readonly settingsFile: string\n  private settingsValue: OriginSettings | undefined\n  private errorCode: string | undefined\n\n  constructor(stateDirectory: string, private readonly ownedRoot = stateDirectory) {\n    if (!isAbsolute(stateDirectory)) throw new Error('origin config state directory must be absolute')\n    this.stateRoot = resolve(stateDirectory)\n    this.settingsFile = join(this.stateRoot, 'settings.json')\n  }\n\n  async initialize(): Promise<void> {\n    this.settingsValue = undefined\n    this.errorCode = undefined\n    try { await assertManagedParents(this.ownedRoot, this.settingsFile, 'origin') } catch (_error) {\n      this.errorCode = 'origin_config_invalid'\n      return\n    }\n    let entry\n    try { entry = await lstat(this.settingsFile) } catch (error) {\n      if ((error as NodeJS.ErrnoException).code === 'ENOENT') return\n      throw error\n    }\n    if (!entry.isFile() || entry.isSymbolicLink() || entry.size > MAX_SETTINGS_BYTES) {\n      this.errorCode = 'origin_config_invalid'\n      return\n    }\n    await restrictPrivateFile(this.settingsFile)\n    try {\n      this.settingsValue = parseOriginSettings(JSON.parse(await readFile(this.settingsFile, 'utf8')) as unknown)\n    } catch { this.errorCode = 'origin_config_invalid' }\n  }\n\n  status(): OriginConfigurationStatus {\n    const settings = this.settingsValue\n    return Object.freeze({\n      configured: settings !== undefined,\n      ...(settings === undefined ? {} : {\n        publicOrigin: settings.publicOrigin,\n        listenHost: settings.listenHost,\n        listenPort: settings.listenPort,\n        allowedCidrs: settings.allowedCidrs,\n        backendOrigin: 'http://' + settings.listenHost + ':' + String(settings.listenPort),\n      }),\n      storagePath: this.stateRoot,\n      ...(this.errorCode === undefined ? {} : { errorCode: this.errorCode }),\n    })\n  }\n\n  settings(): OriginSettings | undefined { return this.settingsValue }\n\n  async configure(value: unknown): Promise<OriginConfigurationStatus> {\n    const settings = parseOriginSettings(value)\n    await writeManagedPrivateFile(this.ownedRoot, this.settingsFile, JSON.stringify(settings) + '\\n', 'origin')\n    this.settingsValue = settings\n    this.errorCode = undefined\n    return this.status()\n  }\n\n  async purge(): Promise<OriginConfigurationStatus> {\n    await removeManagedTree(this.ownedRoot, this.settingsFile, 'origin')\n    this.settingsValue = undefined\n    this.errorCode = undefined\n    return this.status()\n  }\n}\n","import type { MobileAccessControlStore } from './control.js'\nimport type { MobileAccessGateway } from './gateway.js'\nimport type { OriginConfigStore, OriginSettings } from './origin-proxy-config.js'\nimport type { RemoteProviderController } from './remote.js'\n\nexport type OriginState = 'off' | 'unavailable' | 'starting' | 'ready' | 'error'\n\n/** Ready means the private listener is ready, not that public ingress was tested. */\nexport interface OriginStatus {\n  readonly enabled: boolean\n  readonly state: OriginState\n  readonly origin?: string\n  readonly backendOrigin?: string\n  readonly errorCode?: string\n}\n\nexport interface OriginControllerOptions {\n  readonly store: MobileAccessControlStore\n  readonly config: OriginConfigStore\n  readonly createGateway: (settings: OriginSettings) => Promise<MobileAccessGateway>\n  readonly onStatus?: (status: OriginStatus) => void\n}\n\n/** Owns an authenticated HTTP gateway, with no tunnel process or public network probes. */\nexport class OriginController implements RemoteProviderController {\n  private enabled = false\n  private initialized = false\n  private disposed = false\n  private gatewayValue: MobileAccessGateway | undefined\n  private latest: OriginStatus = Object.freeze({ enabled: false, state: 'off' })\n  private queue: Promise<void> = Promise.resolve()\n\n  constructor(private readonly options: OriginControllerOptions) {}\n\n  async initialize(): Promise<void> {\n    await this.enqueue(async () => {\n      if (this.disposed) throw new Error('origin_controller_unavailable')\n      if (this.initialized) return\n      this.enabled = (await this.options.store.load()).enabled\n      this.initialized = true\n      if (this.enabled) await this.start()\n      else this.publish({ enabled: false, state: 'off' })\n    })\n  }\n\n  gateway(): MobileAccessGateway | undefined { return this.gatewayValue }\n  status(): OriginStatus { return this.latest }\n\n  async setEnabled(enabled: boolean): Promise<OriginStatus> {\n    this.assertAvailable()\n    await this.enqueue(async () => {\n      this.assertAvailable()\n      if (this.enabled === enabled && (!enabled || this.gatewayValue !== undefined)) return\n      if (!enabled) await this.stop()\n      await this.options.store.save({ version: 1, enabled })\n      this.enabled = enabled\n      if (enabled) await this.start()\n      else this.publish({ enabled: false, state: 'off' })\n    })\n    return this.status()\n  }\n\n  async reconnect(): Promise<OriginStatus> {\n    this.assertAvailable()\n    await this.enqueue(async () => {\n      this.assertAvailable()\n      if (!this.enabled) {\n        await this.options.store.save({ version: 1, enabled: true })\n        this.enabled = true\n      }\n      await this.stop()\n      await this.start()\n    })\n    return this.status()\n  }\n\n  /** Reset the switch, retaining both settings and shared remote device pairings. */\n  async reset(): Promise<OriginStatus> { return this.setEnabled(false) }\n\n  /** Stop the listener without changing the durable switch. */\n  async close(): Promise<void> {\n    this.disposed = true\n    await this.enqueue(async () => {\n      await this.stop()\n      this.publish({ enabled: this.enabled, state: 'off' })\n    })\n  }\n\n  private assertAvailable(): void {\n    if (!this.initialized || this.disposed) throw new Error('origin_controller_unavailable')\n  }\n\n  private enqueue(operation: () => Promise<void>): Promise<void> {\n    const task = this.queue.then(operation, operation)\n    this.queue = task.then(() => undefined, () => undefined)\n    return task\n  }\n\n  private publish(status: OriginStatus): void {\n    this.latest = Object.freeze({ ...status })\n    try { this.options.onStatus?.(this.latest) } catch { /* Observers do not own the listener. */ }\n  }\n\n  private async start(): Promise<void> {\n    const settings = this.options.config.settings()\n    if (settings === undefined) {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: this.options.config.status().errorCode ?? 'origin_config_missing' })\n      return\n    }\n    this.publish({ enabled: true, state: 'starting', origin: settings.publicOrigin })\n    let gateway: MobileAccessGateway\n    try { gateway = await this.options.createGateway(settings) } catch (error) {\n      const code = typeof error === 'object' && error !== null && 'code' in error ? error.code : undefined\n      this.publish({\n        enabled: true, state: 'error', origin: settings.publicOrigin,\n        errorCode: code === 'EADDRINUSE' ? 'origin_listen_port_in_use'\n          : code === 'EADDRNOTAVAIL' ? 'origin_listen_address_unavailable' : 'origin_gateway_start_failed',\n      })\n      return\n    }\n    this.gatewayValue = gateway\n    if (this.disposed) {\n      await this.stop()\n      return\n    }\n    this.publish({\n      enabled: true, state: 'ready', origin: settings.publicOrigin,\n      backendOrigin: 'http://' + settings.listenHost + ':' + String(gateway.address().port),\n    })\n  }\n\n  private async stop(): Promise<void> {\n    const gateway = this.gatewayValue\n    if (gateway === undefined) return\n    // Retain ownership on close failure so a later stop can retry cleanup.\n    await gateway.close()\n    this.gatewayValue = undefined\n    this.publish({ enabled: this.enabled, state: 'off' })\n  }\n}\n","import { execFile } from 'node:child_process'\nimport { createHash, randomBytes } from 'node:crypto'\nimport {\n  chmod,\n  copyFile,\n  lstat,\n  mkdir,\n  mkdtemp,\n  readFile,\n  rm,\n  writeFile,\n} from 'node:fs/promises'\nimport { isAbsolute, join, relative, resolve } from 'node:path'\nimport { downloadPinnedArtifact } from './component-download.js'\nimport { assertManagedParents, ensureManagedDirectory, removeManagedPaths, removeManagedTree, replaceManagedDirectory } from './managed-files.js'\n\n/**\n * Pinned cloudflared components fetched only after an explicit user action.\n *\n * Cloudflare ships bare executables for Windows and Linux but a `.tgz` for\n * macOS, so an artifact carries two digests: the bytes on the wire\n * (`downloadBytes`/`downloadSha256`) and the executable that ends up installed\n * (`executableBytes`/`executableSha256`). For bare artifacts the two pairs are\n * identical. `--no-autoupdate` is passed at runtime as well, so the pinned\n * bytes stay the bytes that were verified.\n */\ninterface CloudflaredArtifact {\n  readonly version: string\n  readonly platform: NodeJS.Platform\n  readonly arch: string\n  readonly downloadUrl: string\n  readonly downloadBytes: number\n  readonly downloadSha256: string\n  readonly executableName: string\n  /** Bytes of the installed executable; equals `downloadBytes` for bare artifacts. */\n  readonly executableBytes: number\n  readonly executableSha256: string\n  /** Set when the download is an archive rather than the executable itself. */\n  readonly archive?: CloudflaredArchive\n}\n\ninterface CloudflaredArchive {\n  readonly format: 'tgz'\n  /** Member basename to install, e.g. `cloudflared`. */\n  readonly member: string\n}\n\n/** Upper bound for `tar -t` output; a pinned release listing is a few lines. */\nconst MAX_ARCHIVE_LIST_BYTES = 1024 * 1024\nconst MAX_ARCHIVE_ENTRIES = 256\nconst DOWNLOAD_TIMEOUT_MS = 300_000\n\nconst CLOUDFLARED_VERSION = '2026.9.1'\n\nconst releases = [\n  {\n    version: CLOUDFLARED_VERSION,\n    platform: 'win32',\n    arch: 'x64',\n    downloadUrl: `https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-windows-amd64.exe`,\n    downloadBytes: 54_976_432,\n    downloadSha256: '2837888cc0f5d58f15b6dc478376de90b4d3ba5241c7947455d1e0a0df429712',\n    executableName: 'cloudflared.exe',\n    executableBytes: 54_976_432,\n    executableSha256: '2837888cc0f5d58f15b6dc478376de90b4d3ba5241c7947455d1e0a0df429712',\n  },\n  {\n    version: CLOUDFLARED_VERSION,\n    platform: 'linux',\n    arch: 'x64',\n    downloadUrl: `https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-amd64`,\n    downloadBytes: 39_838_488,\n    downloadSha256: '03f1f25d1cc93b9ad6c60569d44060bc4f17ed97075760ed8cfca4b12dcd68cc',\n    executableName: 'cloudflared',\n    executableBytes: 39_838_488,\n    executableSha256: '03f1f25d1cc93b9ad6c60569d44060bc4f17ed97075760ed8cfca4b12dcd68cc',\n  },\n  {\n    version: CLOUDFLARED_VERSION,\n    platform: 'linux',\n    arch: 'arm64',\n    downloadUrl: `https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-arm64`,\n    downloadBytes: 37_466_252,\n    downloadSha256: '3d97437c71848bd8df68041e12436b484a661d95073ea1937f01a845ce88faa3',\n    executableName: 'cloudflared',\n    executableBytes: 37_466_252,\n    executableSha256: '3d97437c71848bd8df68041e12436b484a661d95073ea1937f01a845ce88faa3',\n  },\n  // Cloudflare publishes macOS only as a `.tgz`, so these two carry distinct\n  // archive and executable digests: 21 MB of gzip in, a 39-42 MB Mach-O out.\n  {\n    version: CLOUDFLARED_VERSION,\n    platform: 'darwin',\n    arch: 'x64',\n    downloadUrl: `https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-darwin-amd64.tgz`,\n    downloadBytes: 21_118_723,\n    downloadSha256: 'ff0d3b51d5ff70eceef89d6b32145fee985018a2174596a5dbe405e2766e2ac4',\n    executableName: 'cloudflared',\n    executableBytes: 41_731_488,\n    executableSha256: '1ea07ae775b03236bd6be18ca1848d6bdc4af2f4f3bce398823b5a36e5761b75',\n    archive: { format: 'tgz', member: 'cloudflared' },\n  },\n  {\n    version: CLOUDFLARED_VERSION,\n    platform: 'darwin',\n    arch: 'arm64',\n    downloadUrl: `https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-darwin-arm64.tgz`,\n    downloadBytes: 19_217_478,\n    downloadSha256: 'c27ab8fd0aa489449e3d201eb02f957ef460a13b613662928b1b23394bf1bcfe',\n    executableName: 'cloudflared',\n    executableBytes: 38_893_072,\n    executableSha256: '9a0b19f67dc7a3011bc6b972c7ce06a5fcea8784ac6bd599ffa382ea4aeb5a6e',\n    archive: { format: 'tgz', member: 'cloudflared' },\n  },\n] as const satisfies readonly CloudflaredArtifact[]\n\n/** Pinned official cloudflared release metadata for supported desktop targets. */\nexport const CLOUDFLARED_COMPONENT_RELEASES: Readonly<Record<string, CloudflaredArtifact>> = Object.freeze(Object.fromEntries(\n  releases.map(release => [`${release.platform}-${release.arch}`, Object.freeze(release)]),\n))\n\n/**\n * Canonical release metadata. New code should select from\n * {@link CLOUDFLARED_COMPONENT_RELEASES} by platform and architecture; this\n * alias preserves the original Windows x64 entry for existing callers.\n */\nexport const CLOUDFLARED_COMPONENT_RELEASE = CLOUDFLARED_COMPONENT_RELEASES['win32-x64'] as CloudflaredArtifact\n\nconst DOWNLOAD_PAGE = 'https://github.com/cloudflare/cloudflared/releases'\nconst TERMS_URL = 'https://www.cloudflare.com/website-terms/'\n\n/**\n * Public, credential-free description of the managed cloudflared component.\n *\n * There is deliberately no `configured` flag: a quick tunnel needs no account,\n * token, or DNS record, so installation is the only precondition.\n */\nexport interface CloudflaredComponentStatus {\n  readonly supported: boolean\n  readonly installed: boolean\n  readonly version: string\n  readonly downloadBytes: number\n  readonly installedBytes: number\n  readonly sourceUrl: string\n  readonly downloadPage: string\n  readonly termsUrl: string\n  readonly storagePath: string\n  readonly errorCode?: string\n}\n\ninterface CloudflaredComponentManagerOptions {\n  readonly stateDirectory: string\n  readonly platform?: NodeJS.Platform\n  readonly arch?: string\n  readonly fetchArtifact?: (url: string, signal: AbortSignal) => Promise<Uint8Array>\n  readonly extractArtifact?: (archive: string, destination: string, member: string) => Promise<void>\n}\n\nfunction inside(parent: string, child: string): boolean {\n  const candidate = relative(parent, child)\n  return candidate !== '' && !candidate.startsWith('..') && !isAbsolute(candidate)\n}\n\nasync function sha256(file: string): Promise<string> {\n  return createHash('sha256').update(await readFile(file)).digest('hex')\n}\n\nasync function regularFile(file: string, expectedBytes?: number): Promise<boolean> {\n  try {\n    const stat = await lstat(file)\n    return stat.isFile() && !stat.isSymbolicLink() && (expectedBytes === undefined || stat.size === expectedBytes)\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false\n    throw error\n  }\n}\n\nasync function runCapture(file: string, args: readonly string[]): Promise<string> {\n  return new Promise<string>((resolveRun, reject) => {\n    execFile(file, [...args], {\n      windowsHide: true,\n      timeout: 120_000,\n      maxBuffer: MAX_ARCHIVE_LIST_BYTES,\n      encoding: 'utf8',\n    }, (error, stdout) => {\n      if (error === null) resolveRun(stdout)\n      else reject(error)\n    })\n  })\n}\n\n/** Reject absolute, traversing, or Windows-shaped archive members. */\nfunction validatedArchiveEntry(rawEntry: string): readonly string[] {\n  if (rawEntry.length === 0 || rawEntry.includes('\\\\') || rawEntry.includes('\\u0000')\n    || rawEntry.startsWith('/') || /^[a-zA-Z]:/u.test(rawEntry)) {\n    throw new Error('cloudflared_archive_path_invalid')\n  }\n  const segments = rawEntry.replace(/\\/$/u, '').split('/')\n  if (segments.some(segment => segment === '' || segment === '.' || segment === '..')) {\n    throw new Error('cloudflared_archive_path_invalid')\n  }\n  return segments\n}\n\n/** Select exactly one archive member named `member`, wherever it sits in the tree. */\nexport function selectCloudflaredArchiveEntry(entries: readonly string[], member: string): string {\n  if (entries.length === 0 || entries.length > MAX_ARCHIVE_ENTRIES) {\n    throw new Error('cloudflared_archive_entries_invalid')\n  }\n  let selected: string | undefined\n  for (const entry of entries) {\n    const segments = validatedArchiveEntry(entry)\n    if (segments.at(-1) === member) {\n      if (selected !== undefined) throw new Error('cloudflared_archive_executable_ambiguous')\n      selected = entry.replace(/\\/$/u, '')\n    }\n  }\n  if (selected === undefined) throw new Error('cloudflared_archive_executable_missing')\n  return selected\n}\n\n/**\n * Unpack the pinned member out of a `.tgz` using the system `tar`, which ships\n * with Windows 10+, macOS, and every supported Linux base.\n */\nasync function defaultExtractArtifact(archive: string, destination: string, member: string): Promise<void> {\n  const tar = process.platform === 'win32' ? 'tar.exe' : 'tar'\n  const listing = await runCapture(tar, ['-tzf', archive])\n  const entries = listing.split(/\\r?\\n/u).filter(entry => entry.length > 0)\n  const selected = selectCloudflaredArchiveEntry(entries, member)\n  const unpacked = join(destination, 'archive')\n  await mkdir(unpacked, { recursive: true, mode: 0o700 })\n  await runCapture(tar, ['-xzf', archive, '-C', unpacked, selected])\n  const extracted = join(unpacked, ...validatedArchiveEntry(selected))\n  if (!await regularFile(extracted)) throw new Error('cloudflared_archive_executable_invalid')\n  await copyFile(extracted, join(destination, member))\n}\n\nasync function defaultFetchArtifact(\n  url: string,\n  signal: AbortSignal,\n  expectedBytes: number,\n): Promise<Uint8Array> {\n  return downloadPinnedArtifact({\n    url,\n    expectedBytes,\n    errorPrefix: 'cloudflared',\n    signal,\n  })\n}\n\n/** Select the pinned artifact for one host, or undefined where unsupported. */\nfunction lookupRelease(platform: NodeJS.Platform, arch: string): CloudflaredArtifact | undefined {\n  return CLOUDFLARED_COMPONENT_RELEASES[`${platform}-${arch}`]\n}\n\n/** Owns the optional cloudflared binary inside DSH Mobile state. */\nexport class CloudflaredComponentManager {\n  readonly executable: string\n  readonly componentRoot: string\n  readonly componentStorage: string\n  readonly stateRoot: string\n  readonly logRoot: string\n  private readonly stagingRoot: string\n  private readonly stateDirectory: string\n  private readonly platform: NodeJS.Platform\n  private readonly arch: string\n  private readonly release: CloudflaredArtifact | undefined\n  private readonly fetchArtifact: (url: string, signal: AbortSignal) => Promise<Uint8Array>\n  private readonly extractArtifact: (archive: string, destination: string, member: string) => Promise<void>\n  private installed = false\n  private errorCode: string | undefined\n  private queue: Promise<void> = Promise.resolve()\n\n  constructor(options: CloudflaredComponentManagerOptions) {\n    if (!isAbsolute(options.stateDirectory)) throw new Error('cloudflared state directory must be absolute')\n    const stateDirectory = resolve(options.stateDirectory)\n    this.stateDirectory = stateDirectory\n    this.platform = options.platform ?? process.platform\n    this.arch = options.arch ?? process.arch\n    this.release = lookupRelease(this.platform, this.arch)\n    this.componentRoot = join(stateDirectory, 'components', 'cloudflared')\n    this.componentStorage = join(this.componentRoot, this.release?.version ?? CLOUDFLARED_VERSION)\n    this.executable = join(this.componentStorage, this.release?.executableName ?? 'cloudflared')\n    this.stateRoot = join(stateDirectory, 'state', 'cloudflared')\n    this.logRoot = join(stateDirectory, 'logs', 'cloudflared')\n    this.stagingRoot = join(stateDirectory, 'staging', 'cloudflared')\n    for (const child of [this.componentRoot, this.componentStorage, this.stateRoot, this.logRoot, this.stagingRoot]) {\n      if (!inside(stateDirectory, child)) throw new Error('cloudflared component path escaped its state directory')\n    }\n    const release = this.release\n    this.fetchArtifact = options.fetchArtifact\n      ?? ((url, signal) => defaultFetchArtifact(url, signal, release?.downloadBytes ?? 0))\n    this.extractArtifact = options.extractArtifact ?? defaultExtractArtifact\n  }\n\n  /** Inspect the managed binary without using any global cloudflared state. */\n  async initialize(): Promise<void> {\n    const release = this.release\n    this.installed = false\n    this.errorCode = undefined\n    try {\n      await assertManagedParents(this.stateDirectory, this.executable, 'cloudflared')\n      this.installed = release !== undefined && await regularFile(this.executable, release.executableBytes)\n      if (this.installed && release !== undefined && await sha256(this.executable) !== release.executableSha256) {\n        this.installed = false\n        this.errorCode = 'cloudflared_component_invalid'\n      }\n    } catch (_error) {\n      this.installed = false\n      this.errorCode = 'cloudflared_component_invalid'\n    }\n  }\n\n  /** Return a safe status that never includes machine-specific account data. */\n  status(): CloudflaredComponentStatus {\n    // Unsupported hosts still report the canonical entry so the panel can show\n    // what would be installed elsewhere; `supported` carries the actual gate.\n    const release = this.release ?? CLOUDFLARED_COMPONENT_RELEASE\n    return Object.freeze({\n      supported: this.release !== undefined,\n      installed: this.installed,\n      version: release.version,\n      downloadBytes: release.downloadBytes,\n      installedBytes: release.executableBytes,\n      sourceUrl: release.downloadUrl,\n      downloadPage: DOWNLOAD_PAGE,\n      termsUrl: TERMS_URL,\n      storagePath: this.componentRoot,\n      ...(this.errorCode === undefined ? {} : { errorCode: this.errorCode }),\n    })\n  }\n\n  /** Download, verify, and install the pinned cloudflared executable after explicit confirmation. */\n  install(): Promise<CloudflaredComponentStatus> {\n    return this.enqueue(async () => {\n      const release = this.release\n      if (release === undefined) throw new Error('cloudflared_component_unsupported')\n      await assertManagedParents(this.stateDirectory, this.executable, 'cloudflared')\n      await ensureManagedDirectory(this.stateDirectory, this.stagingRoot, 'cloudflared')\n      const staging = await mkdtemp(join(this.stagingRoot, 'install-'))\n      try {\n        const controller = new AbortController()\n        // The pinned artifact is tens of megabytes, so the transfer budget is\n        // larger than a control handshake: a slow but working link must not\n        // fail the install.\n        const timeout = setTimeout(() => { controller.abort() }, DOWNLOAD_TIMEOUT_MS)\n        timeout.unref()\n        let bytes: Uint8Array\n        try { bytes = await this.fetchArtifact(release.downloadUrl, controller.signal) } finally { clearTimeout(timeout) }\n        if (bytes.byteLength !== release.downloadBytes) {\n          throw new Error('cloudflared_download_size_mismatch')\n        }\n        const digest = createHash('sha256').update(bytes).digest('hex')\n        if (digest !== release.downloadSha256) throw new Error('cloudflared_download_hash_mismatch')\n        const staged = join(staging, release.executableName)\n        if (release.archive === undefined) {\n          // Bare artifacts *are* the executable, so the download pair is\n          // already the install pair.\n          await writeFile(staged, bytes, { flag: 'wx', mode: 0o600 })\n        } else {\n          const downloaded = join(staging, `${release.executableName}.download`)\n          await writeFile(downloaded, bytes, { flag: 'wx', mode: 0o600 })\n          try {\n            await this.extractArtifact(downloaded, staging, release.archive.member)\n          } finally {\n            await rm(downloaded, { force: true })\n          }\n        }\n        await chmod(staged, 0o700)\n        if (!await regularFile(staged, release.executableBytes)\n          || await sha256(staged) !== release.executableSha256) {\n          throw new Error('cloudflared_executable_hash_mismatch')\n        }\n        const candidate = join(this.componentRoot, `.install-${randomBytes(12).toString('hex')}`)\n        await ensureManagedDirectory(this.stateDirectory, candidate, 'cloudflared')\n        try {\n          await copyFile(staged, join(candidate, release.executableName))\n          await chmod(join(candidate, release.executableName), 0o700)\n          await replaceManagedDirectory(this.stateDirectory, this.componentStorage, candidate, 'cloudflared')\n        } catch (error) {\n          try { await removeManagedTree(this.stateDirectory, candidate, 'cloudflared') } catch (_cleanupError) {\n            process.emitWarning('cloudflared candidate cleanup failed', { code: 'DSH_MOBILE_COMPONENT_CLEANUP_FAILED' })\n          }\n          throw error\n        }\n        this.installed = true\n        this.errorCode = undefined\n      } catch (error) {\n        try {\n          await assertManagedParents(this.stateDirectory, this.executable, 'cloudflared')\n          this.installed = await regularFile(this.executable, release.executableBytes)\n            && await sha256(this.executable) === release.executableSha256\n        } catch (_inspectionError) { this.installed = false }\n        throw error\n      } finally {\n        await removeManagedTree(this.stateDirectory, staging, 'cloudflared')\n      }\n    })\n  }\n\n  /** Remove every cloudflared file owned by DSH Mobile without touching global state. */\n  purge(): Promise<CloudflaredComponentStatus> {\n    return this.enqueue(async () => {\n      await removeManagedPaths(this.stateDirectory, [this.componentRoot, this.stateRoot, this.logRoot, this.stagingRoot], 'cloudflared')\n      this.installed = false\n      this.errorCode = undefined\n    })\n  }\n\n  private enqueue(operation: () => Promise<void>): Promise<CloudflaredComponentStatus> {\n    const task = this.queue.then(operation, operation)\n    this.queue = task.then(() => undefined, () => undefined)\n    return task.then(() => this.status())\n  }\n}\n","import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'\nimport { lstat } from 'node:fs/promises'\nimport { createServer, type Server } from 'node:net'\nimport { isAbsolute } from 'node:path'\nimport type { CloudflaredTunnelMode, CloudflaredTunnelSettings } from './cloudflared-tunnel.js'\nimport type { MobileAccessControlState, MobileAccessControlStore } from './control.js'\nimport type { MobileAccessGateway } from './gateway.js'\nimport { settleRemoteResources, terminateRemoteProcess, type RemoteProviderController } from './remote.js'\n\nconst MAX_LOG_BUFFER_BYTES = 64 * 1024\n/**\n * A quick tunnel has to be allocated and registered with the Cloudflare edge\n * before the public hostname appears. That is slower than a cpolar control\n * handshake but still bounded; 60 s keeps a genuinely stalled client from\n * looking healthy for longer than a user will wait.\n */\nconst START_TIMEOUT_MS = 60_000\n/**\n * How many startup-timeout rounds a named tunnel may wait through while its\n * connector process is still alive. A rebooted PC often autostarts DSH before\n * Wi-Fi / VPN / DNS is usable; cloudflared retries the edge on its own, so\n * killing it after a single 60 s window turns a slow boot into a manual\n * reconnect loop. An exited connector (bad token, bad config) still fails fast\n * on the first round.\n */\nconst NAMED_STARTUP_ROUNDS = 5\nconst CLOUDFLARED_HOST_SUFFIX = '.trycloudflare.com'\n\n/**\n * Subdomains Cloudflare reserves for its own control plane.\n *\n * The quick-tunnel banner prints `https://api.trycloudflare.com` (the registration API) before it\n * prints the tunnel's own hostname, and that address satisfies a bare suffix check. Adopting it\n * would put the API host in the pairing QR code, where the phone gets `{\"code\":10005\",\"message\":\n * \"Method Not Allowed\"}` instead of DSH. A quick tunnel is always one random label under the\n * suffix, so the reserved single labels are refused outright.\n */\nconst RESERVED_CLOUDFLARED_LABELS: readonly string[] = Object.freeze(['api', 'www', 'update', 'login'])\n\n/** Product-facing states for the optional cloudflared remote transport. */\nexport type CloudflaredState = 'off' | 'unavailable' | 'starting' | 'connecting' | 'ready' | 'error'\n\n/** Safe cloudflared state returned only through the loopback DSH control route. */\nexport interface CloudflaredStatus {\n  readonly enabled: boolean\n  readonly state: CloudflaredState\n  readonly origin?: string\n  readonly errorCode?: string\n}\n\n/** Inputs for one cloudflared process and its authenticated DSH gateway. */\nexport interface CloudflaredControllerOptions {\n  readonly store: MobileAccessControlStore\n  readonly executable: string\n  /** Named-tunnel configuration; quick tunnels are used when it reports quick mode. */\n  readonly tunnel: { settings(): CloudflaredTunnelSettings }\n  readonly createGateway: (origin: string, listenPort: number) => Promise<MobileAccessGateway>\n  readonly onStatus?: (status: CloudflaredStatus) => void\n  /** Liveness bound for one startup-timeout round; defaults to the product timeout. */\n  readonly startupTimeoutMs?: number\n  /**\n   * Total startup-timeout rounds before a live named connector is given up on;\n   * defaults to NAMED_STARTUP_ROUNDS. Quick tunnels always use a single round.\n   */\n  readonly maxStartupRounds?: number\n  readonly spawnProcess?: (\n    executable: string,\n    args: readonly string[],\n    environment: NodeJS.ProcessEnv,\n  ) => ChildProcessWithoutNullStreams\n}\n\ninterface PortReservation {\n  readonly port: number\n  readonly release: () => Promise<void>\n}\n\nfunction publicStatus(status: CloudflaredStatus): CloudflaredStatus {\n  return Object.freeze({\n    enabled: status.enabled,\n    state: status.state,\n    ...(status.origin === undefined ? {} : { origin: status.origin }),\n    ...(status.errorCode === undefined ? {} : { errorCode: status.errorCode }),\n  })\n}\n\n/**\n * Whether a hostname is a quick-tunnel host: exactly one random label under the provider suffix,\n * never one of the reserved control-plane labels.\n */\nfunction isCloudflaredHost(hostname: string): boolean {\n  const lower = hostname.toLowerCase()\n  if (!lower.endsWith(CLOUDFLARED_HOST_SUFFIX)) return false\n  const label = lower.slice(0, -CLOUDFLARED_HOST_SUFFIX.length)\n  return label !== '' && !label.includes('.') && !RESERVED_CLOUDFLARED_LABELS.includes(label)\n}\n\n/**\n * Extract a validated public HTTPS origin from one cloudflared output line.\n *\n * Quick tunnels print the public hostname inside a decorated banner, so the\n * candidate is taken from the line and then re-parsed as a URL: a lookalike such\n * as `https://x.trycloudflare.com.evil.test` fails the hostname check instead of\n * being truncated into an accepted origin.\n */\nexport function parseCloudflaredOrigin(line: string): string | undefined {\n  if (!line.toLowerCase().includes('trycloudflare.com')) return undefined\n  const match = /https?:\\/\\/[^\\s\"'|<>]+/u.exec(line)\n  // A log line that merely mentions the provider suffix carries no origin, so it\n  // is ignored. Only a URL that is present but fails validation is a protocol\n  // violation worth failing the generation for.\n  if (match === null) return undefined\n  // Banner decoration can leave trailing punctuation attached to the hostname.\n  const candidate = match[0].replace(/[),.;:]+$/u, '')\n  let url: URL\n  try { url = new URL(candidate) } catch { throw new Error('invalid_cloudflared_origin') }\n  if (url.protocol !== 'https:' || url.port !== '' || !isCloudflaredHost(url.hostname)\n    || url.pathname !== '/' || url.search !== '' || url.hash !== ''\n    || url.username !== '' || url.password !== '') throw new Error('invalid_cloudflared_origin')\n  return url.origin\n}\n\n/**\n * Whether one cloudflared log line reports an established edge connection.\n *\n * A named tunnel prints no banner, so registration is the only signal that the\n * connector reached Cloudflare and the public hostname can serve traffic. Both\n * the current and the older wording are accepted; anything else is ignored so a\n * chatty log line cannot be mistaken for readiness.\n */\nexport function isCloudflaredRegistration(line: string): boolean {\n  return /registered tunnel connection/iu.test(line)\n    || /connection\\s+[0-9a-f][0-9a-f-]{7,}\\s+registered/iu.test(line)\n}\n\nasync function reserveLoopbackPort(requestedPort?: number): Promise<PortReservation> {\n  const server: Server = createServer(socket => { socket.destroy() })\n  await new Promise<void>((resolveListen, reject) => {\n    server.once('error', reject)\n    server.listen(requestedPort ?? 0, '127.0.0.1', () => {\n      server.off('error', reject)\n      resolveListen()\n    })\n  })\n  const address = server.address()\n  if (address === null || typeof address === 'string') {\n    server.close()\n    throw new Error('cloudflared_port_reservation_failed')\n  }\n  let released = false\n  return {\n    port: address.port,\n    release: async () => {\n      if (released) return\n      released = true\n      await new Promise<void>(resolveClose => { server.close(() => resolveClose()) })\n    },\n  }\n}\n\nfunction spawnCloudflaredProcess(\n  executable: string,\n  args: readonly string[],\n  environment: NodeJS.ProcessEnv,\n): ChildProcessWithoutNullStreams {\n  return spawn(executable, [...args], {\n    env: environment,\n    shell: false,\n    stdio: ['pipe', 'pipe', 'pipe'],\n    windowsHide: true,\n  })\n}\n\nfunction withoutProxyEnvironment(environment: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n  const blocked = new Set(['HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY', 'NO_PROXY'])\n  return Object.fromEntries(Object.entries(environment).filter(([name]) => !blocked.has(name.toUpperCase())))\n}\n\n/**\n * Owns an installed cloudflared client and a provider-specific DSH remote gateway.\n *\n * Quick tunnels allocate a random hostname and a random forward port on every\n * start. Named tunnels instead read an account token and a stable public\n * hostname from the tunnel store, forward to the configured loopback port, and\n * learn readiness from the connector's registration line rather than a banner.\n */\nexport class CloudflaredController implements RemoteProviderController {\n  private enabled = false\n  private initialized = false\n  private disposed = false\n  private child: ChildProcessWithoutNullStreams | undefined\n  private gatewayValue: MobileAccessGateway | undefined\n  private reservation: PortReservation | undefined\n  private generation = 0\n  private buffer = ''\n  private mode: CloudflaredTunnelMode = 'quick'\n  private namedOrigin: string | undefined\n  private latest: CloudflaredStatus = publicStatus({ enabled: false, state: 'off' })\n  private queue: Promise<void> = Promise.resolve()\n  private startupTimer: NodeJS.Timeout | undefined\n  private startupRounds = 0\n\n  constructor(private readonly options: CloudflaredControllerOptions) {\n    if (!isAbsolute(options.executable)) {\n      throw new Error('cloudflared executable path must be absolute')\n    }\n  }\n\n  /** Restore the remembered cloudflared switch independently from LAN and other providers. */\n  async initialize(initialState?: MobileAccessControlState): Promise<void> {\n    const state = initialState ?? await this.options.store.load()\n    this.enabled = state.enabled\n    this.initialized = true\n    if (this.enabled) await this.start()\n    else this.publish({ enabled: false, state: 'off' })\n  }\n\n  /** Return the active cloudflared-backed DSH gateway. */\n  gateway(): MobileAccessGateway | undefined {\n    return this.gatewayValue\n  }\n\n  /** Return state safe for the desktop control UI. */\n  status(): CloudflaredStatus {\n    return publicStatus(this.latest)\n  }\n\n  /** Enable or disable cloudflared without changing LAN or other provider state. */\n  async setEnabled(enabled: boolean): Promise<CloudflaredStatus> {\n    if (!this.initialized || this.disposed) throw new Error('cloudflared controller is unavailable')\n    await this.enqueue(async () => {\n      if (this.enabled === enabled && (enabled === false || this.child !== undefined)) return\n      await this.options.store.save({ version: 1, enabled })\n      this.enabled = enabled\n      if (!enabled) await this.stop()\n      if (enabled) await this.start()\n      else this.publish({ enabled: false, state: 'off' })\n    })\n    return this.status()\n  }\n\n  /** Restart cloudflared and allocate a fresh quick tunnel. */\n  async reconnect(): Promise<CloudflaredStatus> {\n    if (!this.initialized || this.disposed) throw new Error('cloudflared controller is unavailable')\n    await this.enqueue(async () => {\n      if (!this.enabled) {\n        await this.options.store.save({ version: 1, enabled: true })\n        this.enabled = true\n      }\n      await this.stop()\n      await this.start()\n    })\n    return this.status()\n  }\n\n  /** Disable cloudflared without deleting the installed component. */\n  async reset(): Promise<CloudflaredStatus> {\n    if (!this.initialized || this.disposed) throw new Error('cloudflared controller is unavailable')\n    await this.enqueue(async () => {\n      await this.options.store.save({ version: 1, enabled: false })\n      this.enabled = false\n      await this.stop()\n      this.publish({ enabled: false, state: 'off' })\n    })\n    return this.status()\n  }\n\n  /** Stop owned resources without changing the remembered switch. */\n  async close(): Promise<void> {\n    if (this.disposed) return\n    this.disposed = true\n    await this.enqueue(() => this.stop())\n  }\n\n  private enqueue(operation: () => Promise<void>): Promise<void> {\n    const task = this.queue.then(operation, operation)\n    this.queue = task.then(() => undefined, () => undefined)\n    return task\n  }\n\n  private publish(status: CloudflaredStatus): void {\n    this.latest = publicStatus(status)\n    try { this.options.onStatus?.(this.status()) } catch { /* UI observation cannot own runtime state. */ }\n  }\n\n  private async start(): Promise<void> {\n    const generation = ++this.generation\n    let executableEntry\n    try { executableEntry = await lstat(this.options.executable) } catch {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'cloudflared_component_missing' })\n      return\n    }\n    if (!executableEntry.isFile() || executableEntry.isSymbolicLink()) {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'cloudflared_component_invalid' })\n      return\n    }\n\n    const settings = this.options.tunnel.settings()\n    const named = settings.mode === 'named' ? settings : undefined\n    this.mode = settings.mode\n    this.namedOrigin = named === undefined ? undefined : `https://${named.hostname}`\n\n    let reservation: PortReservation\n    try {\n      reservation = await reserveLoopbackPort(named?.port)\n    } catch (error) {\n      // A bind conflict is the user's to resolve; anything else is an internal\n      // reservation failure and must not be reported as a busy port.\n      const conflict = (error as NodeJS.ErrnoException | undefined)?.code === 'EADDRINUSE'\n      this.publish({\n        enabled: true,\n        state: 'error',\n        errorCode: conflict\n          ? (named === undefined ? 'cloudflared_port_unavailable' : 'cloudflared_tunnel_port_unavailable')\n          : 'cloudflared_port_reservation_failed',\n      })\n      return\n    }\n    this.reservation = reservation\n    this.buffer = ''\n    this.startupRounds = 0\n    this.publish({ enabled: true, state: 'starting' })\n\n    if (named !== undefined) {\n      // Cloudflare already routes the public hostname to this exact port, so the\n      // gateway must be listening before the connector registers; the port has to\n      // survive restarts, which is why it is configuration rather than a choice.\n      const origin = this.namedOrigin as string\n      this.publish({ enabled: true, state: 'connecting', origin })\n      await reservation.release()\n      if (this.reservation === reservation) this.reservation = undefined\n      let gateway: MobileAccessGateway\n      try {\n        gateway = await this.options.createGateway(origin, reservation.port)\n      } catch (error) {\n        // Only a real bind conflict is a port problem; anything else (certificate,\n        // configuration, permissions) must not send the user chasing the port.\n        const conflict = (error as NodeJS.ErrnoException | undefined)?.code === 'EADDRINUSE'\n        this.publish({\n          enabled: true,\n          state: 'error',\n          errorCode: conflict ? 'cloudflared_tunnel_port_unavailable' : 'gateway_start_failed',\n        })\n        return\n      }\n      if (generation !== this.generation || !this.enabled || this.disposed) {\n        await gateway.close()\n        return\n      }\n      this.gatewayValue = gateway\n    }\n\n    // The local DSH remote gateway speaks plain HTTP, so neither flavour needs an\n    // origin TLS override. A named tunnel takes its token from the environment so\n    // the credential never appears in the process command line.\n    const args = named === undefined\n      ? ['tunnel', '--url', `http://127.0.0.1:${String(reservation.port)}`, '--no-autoupdate']\n      : ['tunnel', '--no-autoupdate', 'run']\n    const environment = withoutProxyEnvironment(process.env)\n    if (named !== undefined) environment.TUNNEL_TOKEN = named.token\n    const child = (this.options.spawnProcess ?? spawnCloudflaredProcess)(\n      this.options.executable,\n      args,\n      environment,\n    )\n    this.child = child\n    child.stdout.setEncoding('utf8')\n    child.stderr.setEncoding('utf8')\n    child.stdout.on('data', chunk => { this.consume(generation, String(chunk)) })\n    child.stderr.on('data', chunk => { this.consume(generation, String(chunk)) })\n    child.once('error', () => { void this.enqueue(() => this.failGeneration(generation, 'cloudflared_launch_failed')) })\n    child.once('close', code => {\n      if (generation !== this.generation || this.child !== child) return\n      this.child = undefined\n      if (this.enabled) void this.enqueue(() => this.failGeneration(generation, code === 0 ? 'cloudflared_stopped' : 'cloudflared_exited'))\n    })\n    this.armStartupTimer(generation)\n  }\n\n  private armStartupTimer(generation: number): void {\n    if (this.startupTimer !== undefined) clearTimeout(this.startupTimer)\n    this.startupTimer = setTimeout(() => {\n      void this.enqueue(() => this.checkStartupTimeout(generation))\n    }, this.options.startupTimeoutMs ?? START_TIMEOUT_MS)\n    this.startupTimer.unref()\n  }\n\n  /**\n   * Give a live named connector more time instead of killing it: it retries the\n   * edge on its own and usually registers once the rebooted network is usable.\n   * A dead connector, or an exhausted budget, fails the generation as before.\n   */\n  private async checkStartupTimeout(generation: number): Promise<void> {\n    if (generation !== this.generation || !this.enabled || this.disposed) return\n    if (this.latest.state === 'ready') return\n    const childAlive = this.child !== undefined && this.child.exitCode === null\n    const budget = this.options.maxStartupRounds ?? NAMED_STARTUP_ROUNDS\n    if (this.mode === 'named' && childAlive && this.startupRounds + 1 < budget) {\n      this.startupRounds += 1\n      this.armStartupTimer(generation)\n      return\n    }\n    await this.failGeneration(generation, 'cloudflared_start_timeout')\n  }\n\n  private consume(generation: number, chunk: string): void {\n    if (generation !== this.generation) return\n    this.buffer += chunk\n    if (Buffer.byteLength(this.buffer, 'utf8') > MAX_LOG_BUFFER_BYTES && !this.buffer.includes('\\n')) {\n      void this.enqueue(() => this.failGeneration(generation, 'cloudflared_invalid_output'))\n      return\n    }\n    while (true) {\n      const newline = this.buffer.indexOf('\\n')\n      if (newline < 0) return\n      const line = this.buffer.slice(0, newline).replace(/\\r$/u, '')\n      this.buffer = this.buffer.slice(newline + 1)\n      if (this.mode === 'named') {\n        // The public origin is configuration here, so the log is only read for the\n        // registration that proves the connector reached Cloudflare.\n        if (isCloudflaredRegistration(line)) void this.enqueue(() => this.confirmNamedReady(generation))\n        continue\n      }\n      let origin: string | undefined\n      try { origin = parseCloudflaredOrigin(line) } catch {\n        void this.enqueue(() => this.failGeneration(generation, 'cloudflared_invalid_origin'))\n        return\n      }\n      if (origin !== undefined) void this.enqueue(() => this.attachGateway(generation, origin))\n    }\n  }\n\n  /** Mark a named tunnel ready once the connector has registered with the edge. */\n  private async confirmNamedReady(generation: number): Promise<void> {\n    if (generation !== this.generation || !this.enabled || this.disposed) return\n    if (this.gatewayValue === undefined || this.latest.state === 'ready') return\n    if (this.startupTimer !== undefined) clearTimeout(this.startupTimer)\n    this.startupTimer = undefined\n    this.publish({ enabled: true, state: 'ready', ...(this.namedOrigin === undefined ? {} : { origin: this.namedOrigin }) })\n  }\n\n  private async attachGateway(generation: number, origin: string): Promise<void> {\n    if (generation !== this.generation || !this.enabled || this.disposed) return\n    const current = this.gatewayValue\n    if (current !== undefined) {\n      if (current.address().origin === origin) return\n      await this.rotateGateway(generation, origin, current)\n      return\n    }\n    const reservation = this.reservation\n    if (reservation === undefined) return\n    this.publish({ enabled: true, state: 'connecting', origin })\n    await reservation.release()\n    if (this.reservation === reservation) this.reservation = undefined\n    let gateway: MobileAccessGateway\n    try { gateway = await this.options.createGateway(origin, reservation.port) } catch {\n      await this.failGeneration(generation, 'gateway_start_failed')\n      return\n    }\n    if (generation !== this.generation || !this.enabled || this.disposed || this.child === undefined) {\n      await gateway.close()\n      return\n    }\n    this.gatewayValue = gateway\n    if (this.startupTimer !== undefined) clearTimeout(this.startupTimer)\n    this.startupTimer = undefined\n    this.publish({ enabled: true, state: 'ready', origin })\n  }\n\n  /** Replace the gateway authority when a quick tunnel restarts on a new hostname. */\n  private async rotateGateway(\n    generation: number,\n    origin: string,\n    current: MobileAccessGateway,\n  ): Promise<void> {\n    const listenPort = current.address().port\n    // A replacement must bind the same port cloudflared already forwards to.\n    // Stop exposing the closing instance before releasing that port.\n    if (this.gatewayValue === current) this.gatewayValue = undefined\n    this.publish({ enabled: true, state: 'connecting', origin })\n    try {\n      await current.close()\n    } catch {\n      await this.failGeneration(generation, 'gateway_start_failed')\n      return\n    }\n    if (generation !== this.generation || !this.enabled || this.disposed || this.child === undefined) return\n\n    let replacement: MobileAccessGateway\n    try { replacement = await this.options.createGateway(origin, listenPort) } catch {\n      await this.failGeneration(generation, 'gateway_start_failed')\n      return\n    }\n    if (generation !== this.generation || !this.enabled || this.disposed || this.child === undefined) {\n      await replacement.close()\n      return\n    }\n    this.gatewayValue = replacement\n    this.publish({ enabled: true, state: 'ready', origin })\n  }\n\n  private async failGeneration(generation: number, code: string): Promise<void> {\n    if (generation !== this.generation) return\n    await this.stopProcessAndGateway()\n    if (this.enabled) this.publish({ enabled: true, state: 'error', errorCode: code })\n  }\n\n  private async stop(): Promise<void> {\n    ++this.generation\n    await this.stopProcessAndGateway()\n  }\n\n  private async stopProcessAndGateway(): Promise<void> {\n    if (this.startupTimer !== undefined) clearTimeout(this.startupTimer)\n    this.startupTimer = undefined\n    const reservation = this.reservation\n    this.reservation = undefined\n    const child = this.child\n    this.child = undefined\n    const gateway = this.gatewayValue\n    this.gatewayValue = undefined\n    await settleRemoteResources([\n      () => reservation?.release(),\n      () => child !== undefined && child.exitCode === null ? terminateRemoteProcess(child) : undefined,\n      () => gateway?.close(),\n    ], 'cloudflared resource cleanup failed')\n  }\n}\n","import { lstat, readFile } from 'node:fs/promises'\nimport { isIP } from './ip.js'\nimport { isAbsolute, join, resolve } from 'node:path'\nimport { restrictPrivateFile } from './private-file.js'\nimport { assertManagedParents, removeManagedTree, writeManagedPrivateFile } from './managed-files.js'\n\nconst MAX_CONFIG_BYTES = 8 * 1024\nconst QUICK_TUNNEL_SUFFIX = '.trycloudflare.com'\n/** Cloudflare's own tunnel-routing domain; it can never be a public hostname. */\nconst TUNNEL_ROUTING_SUFFIX = '.cfargotunnel.com'\n/**\n * The bare registrable names behind those suffixes. A suffix test alone accepts\n * them, yet Cloudflare owns both apexes outright, so neither can ever be routed to\n * a customer tunnel.\n */\nconst RESERVED_APEX_NAMES: readonly string[] = Object.freeze([\n  QUICK_TUNNEL_SUFFIX.slice(1),\n  TUNNEL_ROUTING_SUFFIX.slice(1),\n])\n/** Ports below this need privileges on every supported platform. */\nconst MIN_PORT = 1024\nconst MAX_PORT = 65_535\n/**\n * The LAN gateway's HTTPS port, held by the plugin for as long as DSH runs. It is\n * never available to a tunnel, so a configuration naming it must be refused up\n * front rather than failing later as a generic \"port in use\".\n */\nconst RESERVED_LAN_GATEWAY_PORT = 3443\nconst MAX_TOKEN_LENGTH = 4096\n\n/** Which tunnel flavour the cloudflared provider runs. */\nexport type CloudflaredTunnelMode = 'quick' | 'named'\n\n/**\n * Cloudflared provider configuration.\n *\n * A quick tunnel owns nothing durable: cloudflared allocates a random hostname\n * and a random forward port every start. A named tunnel instead runs with an\n * account token, and its public hostname is routed by Cloudflare to the local\n * port recorded here, so that port must stay stable across restarts.\n */\nexport type CloudflaredTunnelSettings =\n  | { readonly version: 1; readonly mode: 'quick' }\n  | {\n    readonly version: 1\n    readonly mode: 'named'\n    readonly token: string\n    readonly hostname: string\n    readonly port: number\n  }\n\n/** Configuration metadata safe to hand to the desktop panel; never the token. */\nexport interface CloudflaredTunnelStatus {\n  readonly mode: CloudflaredTunnelMode\n  readonly configured: boolean\n  readonly hostname?: string\n  readonly port?: number\n  readonly storagePath: string\n  readonly errorCode?: string\n}\n\nfunction hostname(value: string): boolean {\n  if (value.length > 253 || !value.includes('.')) return false\n  return value.split('.').every(label => label.length >= 1 && label.length <= 63\n    && /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/u.test(label))\n}\n\n/**\n * Validate the public hostname Cloudflare routes to this tunnel.\n *\n * The name must be a real DNS name, not an IP literal or a wildcard, and it\n * cannot sit under Cloudflare's own control-plane suffixes: `trycloudflare.com`\n * belongs to quick tunnels, and a `cfargotunnel.com` name is the routing target\n * rather than a routable public address.\n */\nexport function validateCloudflaredTunnelHostname(value: unknown): string {\n  if (typeof value !== 'string' || value !== value.trim() || value.length === 0 || value.length > 253) {\n    throw new Error('cloudflared_tunnel_hostname_invalid')\n  }\n  const normalized = value.toLowerCase().replace(/\\.$/u, '')\n  // An IPv4 literal is dot-separated digits and would otherwise satisfy the label\n  // grammar, but Cloudflare never routes a tunnel hostname to an address.\n  if (isIP(normalized) !== 0 || !hostname(normalized) || normalized.includes('*')\n    || RESERVED_APEX_NAMES.includes(normalized)\n    || normalized.endsWith(QUICK_TUNNEL_SUFFIX) || normalized.endsWith(TUNNEL_ROUTING_SUFFIX)) {\n    throw new Error('cloudflared_tunnel_hostname_invalid')\n  }\n  return normalized\n}\n\n/** Validate the stable loopback port Cloudflare's ingress forwards to. */\nexport function validateCloudflaredTunnelPort(value: unknown): number {\n  if (!Number.isSafeInteger(value) || Number(value) < MIN_PORT || Number(value) > MAX_PORT) {\n    throw new Error('cloudflared_tunnel_port_invalid')\n  }\n  // The LAN gateway always owns 3443, so this is not a transient conflict and the\n  // user must be told which port to avoid instead of \"the port is busy\".\n  if (value === RESERVED_LAN_GATEWAY_PORT) throw new Error('cloudflared_tunnel_port_reserved')\n  return Number(value)\n}\n\n/**\n * Validate a connector token before durable storage.\n *\n * A token is a base64url-encoded JSON blob that carries the account, tunnel id\n * and tunnel secret; the provider passes it through the environment rather than\n * the command line, and it is never returned to any client.\n */\nexport function validateCloudflaredTunnelToken(value: unknown): string {\n  if (typeof value !== 'string' || value !== value.trim()\n    || value.length < 32 || value.length > MAX_TOKEN_LENGTH\n    || !/^[A-Za-z0-9_=+/-]+$/u.test(value)) {\n    throw new Error('cloudflared_tunnel_token_invalid')\n  }\n  return value\n}\n\n/** Parse tunnel settings at the request and filesystem boundaries. */\nexport function parseCloudflaredTunnelSettings(value: unknown): CloudflaredTunnelSettings {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n    throw new Error('cloudflared_tunnel_settings_invalid')\n  }\n  const record = value as Record<string, unknown>\n  const allowed = ['version', 'mode', 'token', 'hostname', 'port']\n  if (Reflect.ownKeys(record).some(key => !allowed.includes(String(key)))) {\n    throw new Error('cloudflared_tunnel_settings_invalid')\n  }\n  if (record.version !== undefined && record.version !== 1) {\n    throw new Error('cloudflared_tunnel_settings_invalid')\n  }\n  const mode = record.mode ?? 'quick'\n  if (mode === 'quick') {\n    if (record.token !== undefined || record.hostname !== undefined || record.port !== undefined) {\n      throw new Error('cloudflared_tunnel_settings_invalid')\n    }\n    return Object.freeze({ version: 1, mode: 'quick' })\n  }\n  if (mode !== 'named') throw new Error('cloudflared_tunnel_settings_invalid')\n  return Object.freeze({\n    version: 1,\n    mode: 'named',\n    token: validateCloudflaredTunnelToken(record.token),\n    hostname: validateCloudflaredTunnelHostname(record.hostname),\n    port: validateCloudflaredTunnelPort(record.port),\n  })\n}\n\n/**\n * Merge a partial panel request with the saved named-tunnel settings so a blank\n * field keeps its stored value. The token in particular is write-only, so the\n * panel submits an empty string to mean \"keep the existing connector token\".\n */\nexport function mergeSavedCloudflaredTunnelSettings(\n  partial: Readonly<Record<string, unknown>>,\n  saved: CloudflaredTunnelSettings | undefined,\n): CloudflaredTunnelSettings {\n  const requested = partial.mode ?? saved?.mode ?? 'quick'\n  // The named branch below hardcodes its mode, so an unrecognized value would be\n  // silently rewritten into a named tunnel. Validate here as strictly as the\n  // parser does, rather than letting this layer launder it.\n  if (requested !== 'quick' && requested !== 'named') {\n    throw new Error('cloudflared_tunnel_settings_invalid')\n  }\n  if (requested === 'quick') return parseCloudflaredTunnelSettings({ version: 1, mode: 'quick' })\n  const previous = saved?.mode === 'named' ? saved : undefined\n  const token = partial.token === '' || partial.token === undefined ? previous?.token : partial.token\n  const hostname = partial.hostname === '' || partial.hostname === undefined ? previous?.hostname : partial.hostname\n  const port = partial.port === undefined || partial.port === '' ? previous?.port : partial.port\n  if (token === undefined || hostname === undefined || port === undefined) {\n    throw new Error('cloudflared_tunnel_config_missing')\n  }\n  return parseCloudflaredTunnelSettings({ version: 1, mode: 'named', token, hostname, port })\n}\n\n/** Owns the private cloudflared tunnel configuration for one DSH installation. */\nexport class CloudflaredTunnelStore {\n  readonly stateRoot: string\n  readonly settingsFile: string\n  private settingsValue: CloudflaredTunnelSettings = Object.freeze({ version: 1, mode: 'quick' })\n  private errorCode: string | undefined\n\n  constructor(stateDirectory: string, private readonly ownedRoot = stateDirectory) {\n    if (!isAbsolute(stateDirectory)) throw new Error('cloudflared tunnel state directory must be absolute')\n    this.stateRoot = resolve(stateDirectory)\n    this.settingsFile = join(this.stateRoot, 'tunnel.json')\n  }\n\n  /** Load private settings while rejecting links, oversized files and unknown fields. */\n  async initialize(): Promise<void> {\n    this.settingsValue = Object.freeze({ version: 1, mode: 'quick' })\n    this.errorCode = undefined\n    try { await assertManagedParents(this.ownedRoot, this.settingsFile, 'cloudflared') } catch (_error) {\n      this.errorCode = 'cloudflared_tunnel_config_invalid'\n      return\n    }\n    let entry\n    try { entry = await lstat(this.settingsFile) } catch (error) {\n      if ((error as NodeJS.ErrnoException).code === 'ENOENT') return\n      throw error\n    }\n    if (!entry.isFile() || entry.isSymbolicLink() || entry.size > MAX_CONFIG_BYTES) {\n      this.errorCode = 'cloudflared_tunnel_config_invalid'\n      return\n    }\n    await restrictPrivateFile(this.settingsFile)\n    try {\n      this.settingsValue = parseCloudflaredTunnelSettings(JSON.parse(await readFile(this.settingsFile, 'utf8')) as unknown)\n      this.errorCode = undefined\n    } catch {\n      this.settingsValue = Object.freeze({ version: 1, mode: 'quick' })\n      this.errorCode = 'cloudflared_tunnel_config_invalid'\n    }\n  }\n\n  /** Return configuration metadata without exposing the connector token. */\n  status(): CloudflaredTunnelStatus {\n    const settings = this.settingsValue\n    return Object.freeze({\n      mode: settings.mode,\n      configured: settings.mode === 'named',\n      ...(settings.mode === 'named' ? { hostname: settings.hostname, port: settings.port } : {}),\n      storagePath: this.stateRoot,\n      ...(this.errorCode === undefined ? {} : { errorCode: this.errorCode }),\n    })\n  }\n\n  /** Return private settings only to the provider lifecycle. */\n  settings(): CloudflaredTunnelSettings {\n    return this.settingsValue\n  }\n\n  /** Atomically replace the tunnel configuration. */\n  async configure(value: unknown): Promise<CloudflaredTunnelStatus> {\n    const settings = parseCloudflaredTunnelSettings(value)\n    if (settings.mode === 'quick') await removeManagedTree(this.ownedRoot, this.settingsFile, 'cloudflared')\n    else {\n      try { await writeManagedPrivateFile(this.ownedRoot, this.settingsFile, `${JSON.stringify(settings)}\\n`, 'cloudflared') }\n      catch (error) {\n        if (error instanceof Error && error.message === 'cloudflared_config_target_invalid') {\n          throw new Error('cloudflared_tunnel_target_invalid', { cause: error })\n        }\n        throw error\n      }\n    }\n    this.settingsValue = settings\n    this.errorCode = undefined\n    return this.status()\n  }\n\n  /** Forget a named tunnel and its connector token. */\n  async purge(): Promise<CloudflaredTunnelStatus> {\n    await removeManagedTree(this.ownedRoot, this.settingsFile, 'cloudflared')\n    this.settingsValue = Object.freeze({ version: 1, mode: 'quick' })\n    this.errorCode = undefined\n    return this.status()\n  }\n}\n","/**\n * Host-side task-completion fan-out for phone notifications.\n *\n * The exact moment a run ends is known only on the Host (the phone page can\n * merely infer it from UI state), so this module watches the public\n * `session/event` bus for completed root turns and hands them to a hub that\n * fans out to every live mobile gateway. Phones render the text locally, so\n * no user content crosses this boundary — only opaque session and turn ids.\n */\n\n/** A completed root turn worth announcing on paired phones. */\nexport interface TaskCompletionEvent {\n  readonly sessionId: string\n  readonly turn: number\n}\n\n/** Minimal session shape read off the `session/event` bus. */\nexport interface TaskEventSession {\n  readonly id: unknown\n  readonly header?: { readonly parentSession?: unknown } | null | undefined\n}\n\n/**\n * Minimal turn event shape read off the `session/event` bus. Fields stay\n * unknown here and are validated at runtime below so this module never\n * depends on the harness session packages.\n */\nexport interface TaskTurnEvent {\n  readonly type: string\n  readonly data?: unknown\n}\n\n/** Structural slice of the Host context this module needs (keeps tests cordis-free). */\nexport interface TaskEventContext {\n  on(event: 'session/event', handler: (session: TaskEventSession, event: TaskTurnEvent) => void): () => void\n}\n\nexport interface TaskEventWatcherOptions {\n  /** Trailing debounce per session that merges turn-boundary bursts. */\n  readonly debounceMs?: number\n  readonly onTaskCompleted: (event: TaskCompletionEvent) => void\n  readonly log?: (event: string, fields: Readonly<Record<string, string | number | boolean>>) => void\n}\n\nexport const TASK_EVENT_DEBOUNCE_MS = 1_000\n\nfunction turnNumber(value: unknown): number {\n  return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : 0\n}\n\nfunction turnData(value: unknown): { turn: number; completed: boolean } {\n  if (value === null || typeof value !== 'object' || Array.isArray(value)) return { turn: 0, completed: false }\n  const record = value as Record<string, unknown>\n  const reason = record.reason as { readonly kind?: unknown } | string | null | undefined\n  const completed = typeof reason === 'string'\n    ? reason === 'completed'\n    : reason !== null && typeof reason === 'object' && (reason as { readonly kind?: unknown }).kind === 'completed'\n  return { turn: turnNumber(record.turn), completed }\n}\n\n/**\n * Subscribe to completed root turns. Subagent turns are skipped so one task\n * announces once, and rapid turn boundaries collapse into a single event.\n * Returns a disposer that also drops pending debounces.\n */\nexport function watchTaskCompletions(ctx: TaskEventContext, options: TaskEventWatcherOptions): () => void {\n  const debounceMs = options.debounceMs ?? TASK_EVENT_DEBOUNCE_MS\n  const pending = new Map<string, ReturnType<typeof setTimeout>>()\n  const disposeListener = ctx.on('session/event', (session, event) => {\n    if (event.type !== 'turn/end') return\n    const { turn, completed } = turnData(event.data)\n    if (!completed) return\n    if (session.header?.parentSession !== undefined && session.header?.parentSession !== null) return\n    const sessionId = String(session.id)\n    options.log?.('task-completed-observed', { sessionId, turn })\n    const previous = pending.get(sessionId)\n    if (previous !== undefined) clearTimeout(previous)\n    pending.set(sessionId, setTimeout(() => {\n      pending.delete(sessionId)\n      options.log?.('task-completed-announced', { sessionId, turn })\n      options.onTaskCompleted(Object.freeze({ sessionId, turn }))\n    }, debounceMs))\n  })\n  return () => {\n    disposeListener()\n    for (const timer of pending.values()) clearTimeout(timer)\n    pending.clear()\n  }\n}\n\n/** Receives fanned-out completion events (normally a mobile gateway). */\nexport interface TaskEventSink {\n  broadcastTaskEvent(event: TaskCompletionEvent): void\n}\n\n/** One subscription feeding every live gateway; gateways register on start. */\nexport class TaskEventHub {\n  private readonly sinks = new Set<TaskEventSink>()\n\n  /** Register a sink; returns its disposer. */\n  add(sink: TaskEventSink): () => void {\n    this.sinks.add(sink)\n    return () => { this.sinks.delete(sink) }\n  }\n\n  /** Fan out to a snapshot so a failing sink cannot break its siblings. */\n  broadcast(event: TaskCompletionEvent): void {\n    for (const sink of [...this.sinks]) {\n      try { sink.broadcastTaskEvent(event) } catch { /* A failing gateway must not break its siblings. */ }\n    }\n  }\n\n  /** Visible for tests. */\n  get size(): number {\n    return this.sinks.size\n  }\n}\n","import { execFileText as execFile } from './exec-file.js'\nimport { lookup } from 'node:dns/promises'\nimport type { ClientRequest, IncomingMessage } from 'node:http'\nimport { request as proxyRequest } from 'node:http'\nimport type { Socket } from 'node:net'\nimport type { TLSSocket } from 'node:tls'\nimport { connect as tlsConnect } from 'node:tls'\n\nimport type { RemoteProvider } from './remote.js'\nimport { DSH_MOBILE_VERSION, MINIMUM_ANDROID_APP_VERSION } from './version.js'\n\nexport type DiagnosticStatus = 'ok' | 'warning' | 'error' | 'info'\nexport type DiagnosticReason =\n  | 'versions-current'\n  | 'lan-setup-required' | 'network-unavailable' | 'network-interface' | 'network-fixed'\n  | 'lan-ready' | 'lan-off'\n  | 'firewall-ready' | 'firewall-missing' | 'firewall-unknown'\n  | 'remote-off' | 'remote-ready' | 'remote-origin-ready' | 'remote-rate-limited' | 'remote-fake-ip' | 'remote-unreachable'\n  | 'remote-needs-login' | 'remote-connecting' | 'remote-controller-error'\n  | 'competing-remote-channel'\n  | 'phone-network-unknown'\n\nexport interface DiagnosticFacts {\n  readonly provider?: RemoteProvider\n  readonly latencyMs?: number\n  readonly interfaceName?: string\n  readonly endpointSuffix?: string\n  readonly controllerCode?: string\n  /** The reachability answer came from the machine's configured relay egress. */\n  readonly viaProxy?: boolean\n}\n\n/** One user-facing diagnostic result with stable localization data and server fallback copy. */\nexport interface DiagnosticCheck {\n  readonly id: string\n  readonly status: DiagnosticStatus\n  readonly reason: DiagnosticReason\n  readonly facts?: DiagnosticFacts\n  readonly label: string\n  readonly detail: string\n  readonly action?: string\n}\n\n/** Runtime facts available without exposing credentials or local file paths. */\nexport interface DiagnosticSnapshot {\n  readonly dshVersion: string\n  /** Another plugin injects a remote transport before the DSH client boots. */\n  readonly competingRemoteChannelBoot?: boolean\n  readonly lan: {\n    readonly configured?: boolean\n    readonly running: boolean\n    readonly origin?: string\n    readonly configuredInterface?: string\n    readonly interfaceName?: string\n    readonly networkError?: string\n    readonly port?: number\n  }\n  readonly remote: {\n    readonly provider: RemoteProvider\n    readonly running: boolean\n    readonly state: string\n    readonly origin?: string\n    readonly errorCode?: string\n  }\n}\n\ninterface FirewallObservation {\n  readonly state: 'ready' | 'missing' | 'unknown' | 'not-applicable'\n}\n\ninterface RemoteObservation {\n  readonly state: 'ready' | 'rate-limited' | 'unreachable' | 'not-applicable'\n  readonly latencyMs?: number\n  readonly fakeIp?: boolean\n  readonly viaProxy?: boolean\n}\n\n/** Injectable probes keep diagnostics deterministic in tests. */\nexport interface DiagnosticProbes {\n  readonly firewall?: (port: number | undefined) => Promise<FirewallObservation>\n  readonly remote?: (origin: string | undefined) => Promise<RemoteObservation>\n}\n\n/** Sanitized diagnostic response copied by the desktop UI. */\nexport interface ConnectionDiagnostics {\n  readonly version: 1\n  readonly generatedAt: number\n  readonly overall: 'ok' | 'attention' | 'error'\n  readonly versions: {\n    readonly plugin: string\n    readonly dsh: string\n    readonly minimumAndroidApp: string\n  }\n  readonly summary: string\n  readonly checks: readonly DiagnosticCheck[]\n  readonly report: string\n}\n\n/** Recognize the active remote-web-ui boot hook without evaluating or modifying it. */\nexport function hasCompetingRemoteChannelBoot(rows: readonly { readonly kind: string; readonly text?: string }[]): boolean {\n  return rows.some(row => row.kind === 'script' && row.text?.includes('__DSH_REMOTE_CHANNEL_BOOT__') === true)\n}\n\nconst REMOTE_ERROR_GUIDANCE: Readonly<Record<string, string>> = Object.freeze({\n  component_missing: '重新安装完整插件包。',\n  funnel_permission_required: '继续完成 Tailscale Funnel 授权。',\n  funnel_https_required: '继续完成 Tailscale HTTPS 授权。',\n  funnel_start_failed: '重新打开授权页并允许 Funnel。',\n  funnel_start_timeout: '检查网络后点击“重新连接”。',\n  tailscale_dns_missing: '确认 Tailscale 登录仍有效后重新连接。',\n  sidecar_launch_failed: '重新安装完整插件包后重试。',\n  sidecar_stopped: '点击“重新连接”。',\n  sidecar_exited: '点击“重新连接”；仍失败时复制诊断报告。',\n  control_channel_failed: '点击“重新连接”。',\n  cpolar_component_missing: '先安装 cpolar 官方组件。',\n  cpolar_component_invalid: '彻底移除 cpolar 组件后重新安装。',\n  cpolar_config_missing: '保存 cpolar Authtoken 后重试。',\n  cpolar_config_invalid: '重新保存 cpolar Authtoken。',\n  cpolar_start_timeout: '检查网络后点击“重新连接”。',\n  cpolar_stopped: '点击“重新连接”。',\n  cpolar_exited: '点击“重新连接”；仍失败时复制诊断报告。',\n  cloudflared_component_missing: '先安装 cloudflared 官方组件。',\n  cloudflared_component_invalid: '彻底移除 cloudflared 组件后重新安装。',\n  cloudflared_port_unavailable: '无法分配本机远程网关端口，请重试。',\n  cloudflared_launch_failed: '重新安装 cloudflared 官方组件后重试。',\n  cloudflared_start_timeout: '检查网络后点击“重新连接”。',\n  cloudflared_stopped: '点击“重新连接”。',\n  cloudflared_exited: '点击“重新连接”；仍失败时复制诊断报告。',\n  cloudflared_invalid_output: 'cloudflared 返回了无法识别的状态。',\n  cloudflared_invalid_origin: 'cloudflared 返回的公网地址未通过校验。',\n  origin_config_missing: '先保存自有反向代理配置。',\n  origin_config_invalid: '重新保存自有反向代理配置。',\n  origin_listen_port_in_use: '更换 HTTP 后端端口；不要使用局域网的 3443、DSH 自身的 3080，或已被 cloudflared 隧道占用的 3444。',\n  origin_listen_address_unavailable: '监听地址不属于当前电脑，请重新选择本机的私网 IPv4 地址。',\n  origin_gateway_start_failed: '检查 HTTP 后端监听地址和端口后重新连接。',\n  frp_component_missing: '先安装 FRP 官方组件。',\n  frp_component_invalid: '彻底清理 FRP 组件后重新安装。',\n  frp_config_missing: '先保存自建 FRP 连接配置。',\n  frp_config_verify_failed: '检查服务器地址、端口、Token 和公开域名。',\n  frp_vhost_publicly_reachable: '将 frps 的 HTTP vhost 监听限制到 127.0.0.1。',\n  frp_vhost_probe_failed: '确认 VPS 地址可解析后重新连接。',\n  frp_launch_failed: '重新安装 FRP 官方组件后重试。',\n  frp_start_timeout: '确认 frps、Caddy 和域名解析正常后重新连接。',\n  frp_proxy_name_in_use: '该 frps 上已有同名代理：在另一台 DSH 电脑上关闭自建 FRP，或在 frps 上清掉该代理后重新连接。',\n  frp_remote_port_in_use: '公网入口端口被其他代理占用：改用其他入口端口后重新连接。',\n  frp_proxy_start_failed: '查看 frps 日志与 allowPorts，确认它能接受该代理名和入口端口。',\n  frp_discovery_mismatch: '公开域名连接到了另一台电脑，请核对 Caddy 与 frps 配置。',\n  frp_discovery_invalid: '公开域名返回了非 DSH Mobile 响应。',\n  frp_stopped: '点击“重新连接”。',\n  frp_exited: '检查 VPS 配置后重新连接；仍失败时复制诊断报告。',\n  gateway_start_failed: '确认 DSH 正在运行后重新连接。',\n})\n\nfunction check(\n  id: string,\n  status: DiagnosticStatus,\n  reason: DiagnosticReason,\n  label: string,\n  detail: string,\n  action?: string,\n  facts?: DiagnosticFacts,\n): DiagnosticCheck {\n  return Object.freeze({ id, status, reason, ...(facts === undefined ? {} : { facts: Object.freeze(facts) }), label, detail, ...(action === undefined ? {} : { action }) })\n}\n\nfunction maskLanOrigin(origin: string | undefined): string {\n  if (origin === undefined) return '未分配'\n  try {\n    const url = new URL(origin)\n    const octets = url.hostname.split('.')\n    const host = octets.length === 4 ? `${octets[0]}.${octets[1]}.${octets[2]}.x` : '局域网地址'\n    return `${url.protocol}//${host}${url.port === '' ? '' : `:${url.port}`}`\n  } catch {\n    return '地址格式无效'\n  }\n}\n\nfunction remoteSuffix(origin: string | undefined): string {\n  if (origin === undefined) return '未分配'\n  try {\n    const hostname = new URL(origin).hostname\n    if (hostname.endsWith('.ts.net')) return '*.ts.net'\n    if (hostname.endsWith('.trycloudflare.com')) return '*.trycloudflare.com'\n    for (const suffix of ['.cpolar.cn', '.cpolar.io', '.cpolar.top', '.cpolar.com']) {\n      if (hostname.endsWith(suffix)) return `*${suffix}`\n    }\n    return '公共 HTTPS 地址'\n  } catch {\n    return '地址格式无效'\n  }\n}\n\nfunction defaultFirewallProbe(platform: NodeJS.Platform = process.platform): (port: number | undefined) => Promise<FirewallObservation> {\n  return async (port) => {\n    if (platform !== 'win32') return { state: 'not-applicable' }\n    if (port === undefined) return { state: 'unknown' }\n    const script = [\n      \"$specs = @(@{ Name = 'DSH Mobile HTTPS'; Protocol = 'TCP' }, @{ Name = 'DSH Mobile Discovery'; Protocol = 'UDP' })\",\n      '$ready = $true',\n      '$specs | ForEach-Object {',\n      '  $spec = $_',\n      \"  $rule = Get-NetFirewallRule -DisplayName $spec.Name -ErrorAction SilentlyContinue | Where-Object { $_.Enabled -eq 'True' -and $_.Direction -eq 'Inbound' -and $_.Action -eq 'Allow' } | Select-Object -First 1\",\n      '  if ($null -eq $rule) { $ready = $false; return }',\n      '  $filters = @($rule | Get-NetFirewallPortFilter -ErrorAction SilentlyContinue)',\n      `  $matching = @($filters | Where-Object { $_.Protocol -eq $spec.Protocol -and ($_.LocalPort -eq 'Any' -or $_.LocalPort -eq '${String(port)}') })`,\n      '  if ($matching.Count -eq 0) { $ready = $false }',\n      '}',\n      \"if ($ready) { 'ready' } else { 'missing' }\",\n    ].join('; ')\n    try {\n      const result = await execFile('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', script], {\n        encoding: 'utf8',\n        timeout: 3_000,\n        windowsHide: true,\n      })\n      return { state: result.stdout.trim() === 'ready' ? 'ready' : 'missing' }\n    } catch {\n      return { state: 'unknown' }\n    }\n  }\n}\n\n/** Reserve one six-second window per egress so the desktop's 15-second request can finish. */\nexport function remoteDiagnosticTimeoutMs(_origin: string): number {\n  return 6_000\n}\n\ninterface RemoteHealthObservation {\n  readonly status: number\n  readonly latencyMs: number\n}\n\n/** One tunnel attempt through the machine's configured HTTP relay egress. */\nexport type ProxyHealthTunnel = (target: URL, proxy: URL, budgetMs: number) => Promise<RemoteHealthObservation>\n\n/** Raw observation from the direct (default) path, checked before any relay. */\nexport type DirectHealthProbe = (target: URL, budgetMs: number) => Promise<RemoteObservation>\n\nconst TUNNEL_HEADER_LIMIT_BYTES = 64 * 1024\n\nfunction proxyExcludedByNoProxy(target: URL, raw: string): boolean {\n  const text = raw.trim().toLowerCase()\n  if (text === '') return false\n  const hostname = target.hostname.toLowerCase()\n  const host = hostname.startsWith('[') && hostname.endsWith(']') ? hostname.slice(1, -1) : hostname\n  const targetPort = target.port === '' ? (target.protocol === 'https:' ? 443 : 80) : Number(target.port)\n  for (const entry of text.split(/[\\s,]+/)) {\n    let value = entry\n    if (value === '') continue\n    if (value === '*') return true\n    if (value.includes('/')) continue\n    let port: number | undefined\n    if (value.startsWith('[')) {\n      const bracket = value.indexOf(']')\n      if (bracket < 0) continue\n      const tail = value.slice(bracket + 1)\n      if (tail !== '') {\n        if (!/^:\\d+$/u.test(tail)) continue\n        port = Number(tail.slice(1))\n      }\n      value = value.slice(1, bracket)\n    } else if ((value.match(/:/gu) ?? []).length === 1) {\n      const separator = value.lastIndexOf(':')\n      const suffix = value.slice(separator + 1)\n      if (!/^\\d+$/u.test(suffix)) continue\n      port = Number(suffix)\n      value = value.slice(0, separator)\n    }\n    if (port !== undefined && port !== targetPort) continue\n    if (value.startsWith('*.')) value = value.slice(2)\n    else if (value.startsWith('.')) value = value.slice(1)\n    if (value === '') continue\n    if (host === value || host.endsWith(`.${value}`)) return true\n  }\n  return false\n}\n\n/**\n * Resolve the relay egress configured in the environment for `origin`.\n *\n * Honors `HTTPS_PROXY` (then `ALL_PROXY`, then the generic `HTTP_PROXY`) for an\n * HTTPS target, and `http_proxy`/`HTTP_PROXY`/`ALL_PROXY` for a plain one, unless\n * `NO_PROXY`/`no_proxy` covers the host. Only a plain `http://<host>:<port>`\n * relay is usable: SOCKS or a TLS-to-proxy configuration would need a different\n * tunnel, so absent that the probe keeps its direct semantics.\n */\nexport function configuredProxyFor(origin: string, env: NodeJS.ProcessEnv = process.env): URL | undefined {\n  let target: URL\n  try {\n    target = new URL(origin)\n  } catch {\n    return undefined\n  }\n  if (proxyExcludedByNoProxy(target, env.NO_PROXY ?? env.no_proxy ?? '')) return undefined\n  const isHttps = target.protocol === 'https:'\n  const candidates = isHttps\n    ? [env.https_proxy ?? env.HTTPS_PROXY, env.all_proxy ?? env.ALL_PROXY, env.http_proxy ?? env.HTTP_PROXY]\n    : [env.http_proxy ?? env.HTTP_PROXY, env.all_proxy ?? env.ALL_PROXY]\n  for (const candidate of candidates) {\n    if (typeof candidate !== 'string' || candidate.trim() === '') continue\n    try {\n      const proxy = new URL(candidate.trim())\n      if (proxy.protocol !== 'http:' || proxy.hostname === '') continue\n      return proxy\n    } catch {\n      continue\n    }\n  }\n  return undefined\n}\n\n/** One reachability probe through an HTTP relay: CONNECT, TLS, then a status line. */\nexport async function relayProbeThroughProxy(target: URL, proxy: URL, budgetMs = remoteDiagnosticTimeoutMs(target.origin)): Promise<RemoteHealthObservation> {\n  const started = performance.now()\n  return new Promise<RemoteHealthObservation>((resolve, reject) => {\n    let settled = false\n    let hopRequest: ClientRequest | undefined\n    let rawSocket: Socket | undefined\n    let secureSocket: TLSSocket | undefined\n    let timer: NodeJS.Timeout | undefined\n    const finish = (outcome: { readonly value?: RemoteHealthObservation; readonly error?: Error }): void => {\n      if (settled) return\n      settled = true\n      clearTimeout(timer)\n      secureSocket?.destroy()\n      rawSocket?.end()\n      rawSocket?.destroy()\n      hopRequest?.destroy()\n      if (outcome.error !== undefined) reject(outcome.error)\n      else resolve(outcome.value ?? { status: 0, latencyMs: 0 })\n    }\n    timer = setTimeout(() => { finish({ error: new Error('proxy_tunnel_timeout') }) }, Math.max(1, budgetMs))\n    timer.unref()\n    // The CONNECT target must always carry an explicit port: a bare hostname is\n    // resolved by the relay against its own default (port 80), which answers\n    // plaintext and breaks the TLS handshake with a wrong-version error.\n    const hopPort = target.port === '' ? (target.protocol === 'https:' ? 443 : 80) : Number(target.port)\n    const hopPath = `${target.hostname}:${hopPort}`\n    const headers: Record<string, string> = { host: hopPath, 'proxy-connection': 'keep-alive' }\n    if (proxy.username !== '') {\n      headers['proxy-authorization'] = `Basic ${Buffer.from(\n        `${decodeURIComponent(proxy.username)}:${decodeURIComponent(proxy.password)}`,\n        'utf8',\n      ).toString('base64')}`\n    }\n    hopRequest = proxyRequest({\n      host: proxy.hostname,\n      port: proxy.port === '' ? 80 : Number(proxy.port),\n      method: 'CONNECT',\n      path: hopPath,\n      headers,\n      agent: false,\n    })\n    hopRequest.once('connect', (response: IncomingMessage, socket: Socket) => {\n      if (settled) { socket.destroy(); return }\n      rawSocket = socket\n      if (response.statusCode !== 200) {\n        finish({ error: new Error(`proxy_tunnel_rejected_${response.statusCode ?? 'unknown'}`) })\n        return\n      }\n      const secure = tlsConnect({\n        socket,\n        servername: target.hostname,\n        rejectUnauthorized: true,\n      })\n      secureSocket = secure\n      secure.once('secureConnect', () => {\n        if (settled) return\n        secure.write([\n          `GET ${target.pathname}${target.search} HTTP/1.1`,\n          `Host: ${target.host}`,\n          'User-Agent: dsh-mobile-diagnostics',\n          'Accept-Encoding: identity',\n          'Connection: close',\n          '',\n          '',\n        ].join('\\r\\n'))\n      })\n      let buffered = Buffer.alloc(0)\n      secure.on('data', (chunk: Buffer) => {\n        buffered = Buffer.concat([buffered, chunk])\n        if (buffered.byteLength > TUNNEL_HEADER_LIMIT_BYTES) {\n          finish({ error: new Error('proxy_tunnel_oversized_response') })\n          return\n        }\n        const end = buffered.indexOf('\\r\\n\\r\\n')\n        if (end < 0) return\n        const statusLine = /^HTTP\\/\\d(?:\\.\\d)?\\s+(\\d{3})/u.exec(buffered.subarray(0, end).toString('latin1'))?.[1]\n        const status = Number.parseInt(statusLine ?? '', 10)\n        if (!Number.isSafeInteger(status) || status < 100) {\n          finish({ error: new Error('proxy_tunnel_invalid_response') })\n          return\n        }\n        finish({ value: { status, latencyMs: Math.max(0, Math.round(performance.now() - started)) } })\n      })\n      secure.once('error', (error: Error) => { finish({ error }) })\n      secure.once('close', () => { finish({ error: new Error('proxy_tunnel_closed') }) })\n    })\n    hopRequest.once('error', (error: Error) => { finish({ error }) })\n    hopRequest.end()\n  })\n}\n\n/** Bounded supplementary DNS context for a failed direct attempt. */\nasync function unreachableWithDnsContext(hostname: string, budgetMs: number): Promise<RemoteObservation> {\n  let fakeIp = false\n  let timer: NodeJS.Timeout | undefined\n  try {\n    const addresses = await Promise.race([\n      lookup(hostname, { all: true }),\n      new Promise<never>((_resolve, reject) => {\n        timer = setTimeout(() => { reject(new Error('dns_context_timeout')) }, Math.max(1, budgetMs))\n        timer.unref()\n      }),\n    ])\n    fakeIp = addresses.some(({ address }) => {\n      const [first, second] = address.split('.').map(Number)\n      return first === 198 && (second === 18 || second === 19)\n    })\n  } catch {\n    // DNS lookup is supplementary; the failed HTTPS probe remains authoritative.\n  } finally {\n    clearTimeout(timer)\n  }\n  return { state: 'unreachable', ...(fakeIp ? { fakeIp: true } : {}) }\n}\n\nasync function fetchRemoteHealth(target: URL, budgetMs: number): Promise<RemoteObservation> {\n  const started = performance.now()\n  try {\n    const response = await fetch(target, {\n      cache: 'no-store',\n      redirect: 'error',\n      signal: AbortSignal.timeout(Math.max(1, budgetMs - 500)),\n    })\n    const latencyMs = Math.max(0, Math.round(performance.now() - started))\n    if (response.status === 429) return { state: 'rate-limited', latencyMs }\n    return response.ok ? { state: 'ready', latencyMs } : { state: 'unreachable', latencyMs }\n  } catch {\n    return unreachableWithDnsContext(target.hostname, Math.max(1, budgetMs - (performance.now() - started)))\n  }\n}\n\n/** Explicit test seams: environment, the direct attempt, and the relay attempt. */\nexport interface RemoteHealthProbeOptions {\n  readonly env?: NodeJS.ProcessEnv\n  readonly direct?: DirectHealthProbe\n  readonly tunnel?: ProxyHealthTunnel\n}\n\n/**\n * Answer \"is the public endpoint reachable\" from the machine's own egress.\n *\n * A direct attempt stays authoritative first. When it fails and the environment\n * configures an HTTP relay that `NO_PROXY` does not exclude, one tunnelled\n * attempt runs: a self-managed Funnel origin otherwise resolves to this\n * machine's tailnet address, where nothing serves the funnel port locally, so\n * the direct measurement reports an outage while the relay's egress — the same\n * public path a phone takes — still succeeds. When both fail, the original\n * direct observation (including its Fake-IP context) stands unchanged.\n */\nexport async function probeRemoteHealth(\n  origin: string | undefined,\n  options: RemoteHealthProbeOptions = {},\n): Promise<RemoteObservation> {\n  if (origin === undefined) return { state: 'not-applicable' }\n  let target: URL\n  try {\n    target = new URL('/mobile-access/health', origin)\n  } catch {\n    return { state: 'not-applicable' }\n  }\n  const budgetMs = remoteDiagnosticTimeoutMs(origin)\n  const direct = options.direct ?? fetchRemoteHealth\n  const observation = await direct(target, budgetMs)\n  if (observation.state !== 'unreachable') return observation\n  const relay = configuredProxyFor(origin, options.env ?? process.env)\n  if (relay === undefined) return observation\n  const tunnel = options.tunnel ?? relayProbeThroughProxy\n  try {\n    const { status, latencyMs } = await tunnel(target, relay, budgetMs)\n    if (status === 429) return { state: 'rate-limited', latencyMs, viaProxy: true }\n    return status >= 200 && status < 300\n      ? { state: 'ready', latencyMs, viaProxy: true }\n      : observation\n  } catch {\n    return observation\n  }\n}\n\nasync function defaultRemoteProbe(origin: string | undefined): Promise<RemoteObservation> {\n  return probeRemoteHealth(origin)\n}\n\nfunction reportLine(entry: DiagnosticCheck): string {\n  return `[${entry.status.toUpperCase()}] ${entry.label}: ${entry.detail}${entry.action === undefined ? '' : ` ${entry.action}`}`\n}\n\n/** Run bounded read-only checks and return a report safe to paste into an issue. */\nexport async function collectConnectionDiagnostics(\n  snapshot: DiagnosticSnapshot,\n  probes: DiagnosticProbes = {},\n): Promise<ConnectionDiagnostics> {\n  const checks: DiagnosticCheck[] = []\n  const remoteProbe = snapshot.remote.provider !== 'origin' && snapshot.remote.running && snapshot.remote.state === 'ready' && snapshot.remote.origin !== undefined\n    ? (probes.remote ?? defaultRemoteProbe)(snapshot.remote.origin)\n    : Promise.resolve<RemoteObservation>({ state: 'not-applicable' })\n  const [firewall, remoteObservation] = await Promise.all([\n    (probes.firewall ?? defaultFirewallProbe())(snapshot.lan.port),\n    remoteProbe,\n  ])\n  checks.push(check(\n    'versions',\n    'ok',\n    'versions-current',\n    '版本兼容',\n    `插件 ${DSH_MOBILE_VERSION}，DSH ${snapshot.dshVersion}，Android App 最低 ${MINIMUM_ANDROID_APP_VERSION}。`,\n  ))\n\n  if (snapshot.competingRemoteChannelBoot === true) {\n    checks.push(check(\n      'remote-plugin-conflict', 'warning', 'competing-remote-channel', '第三方远程插件',\n      '检测到另一套远程请求通道脚本；手机页面可能进入该插件自己的配对流程。',\n      '在电脑端关闭 dsh-remote-web-ui 的远程访问后刷新，再使用 DSH Mobile 当前二维码配对；不要混用两种配对码。',\n    ))\n  }\n\n  if (snapshot.lan.configured === false) {\n    checks.push(check('network', 'error', 'lan-setup-required', '局域网配置', '尚未完成局域网初始化。', '返回局域网页选择网卡并完成配置。'))\n  } else if (snapshot.lan.networkError !== undefined) {\n    checks.push(check('network', 'error', 'network-unavailable', '局域网网卡', '已保存的网卡当前不可用。', '重新运行 dsh-mobile setup。'))\n  } else if (snapshot.lan.configuredInterface !== undefined) {\n    const interfaceName = snapshot.lan.interfaceName ?? snapshot.lan.configuredInterface\n    checks.push(check(\n      'network',\n      'ok',\n      'network-interface',\n      '局域网网卡',\n      `正在跟随 ${interfaceName}。`,\n      undefined,\n      { interfaceName },\n    ))\n  } else {\n    checks.push(check('network', 'info', 'network-fixed', '局域网网卡', '当前使用固定网络配置。'))\n  }\n\n  if (snapshot.lan.running && snapshot.lan.origin !== undefined) {\n    const endpointSuffix = maskLanOrigin(snapshot.lan.origin)\n    checks.push(check('lan', 'ok', 'lan-ready', '局域网网关', `已监听 ${endpointSuffix}，配对入口可用。`, undefined, { endpointSuffix }))\n  } else {\n    checks.push(check('lan', 'info', 'lan-off', '局域网网关', '当前未开启。', '需要手机直连时开启局域网访问。'))\n  }\n\n  if (firewall.state === 'ready') {\n    checks.push(check('firewall', 'ok', 'firewall-ready', 'Windows 防火墙', '局域网 TCP 与发现规则已启用。'))\n  } else if (firewall.state === 'missing') {\n    checks.push(check('firewall', 'warning', 'firewall-missing', 'Windows 防火墙', '未找到完整的局域网放行规则。', '以管理员身份重新运行 dsh-mobile setup。'))\n  } else if (firewall.state === 'unknown') {\n    checks.push(check('firewall', 'info', 'firewall-unknown', 'Windows 防火墙', '系统未允许插件读取防火墙状态。', '若手机找不到电脑，以管理员身份重新运行 setup。'))\n  }\n\n  if (!snapshot.remote.running || snapshot.remote.state === 'off') {\n    checks.push(check('remote', 'info', 'remote-off', '远程通道', '当前未启用。', undefined, { provider: snapshot.remote.provider }))\n  } else if (snapshot.remote.provider === 'origin' && snapshot.remote.state === 'ready') {\n    checks.push(check('remote', 'info', 'remote-origin-ready', '远程通道',\n      '私网 HTTP 后端已就绪；未检测公网 HTTPS、证书或 WebSocket 连通性。',\n      '在手机上经反向代理验证连接；代理须保留原始 Host（含端口）并支持 WebSocket。',\n      { provider: 'origin' }))\n  } else if (snapshot.remote.state === 'ready' && snapshot.remote.origin !== undefined) {\n    const endpointSuffix = remoteSuffix(snapshot.remote.origin)\n    const facts = {\n      provider: snapshot.remote.provider,\n      endpointSuffix,\n      ...(remoteObservation.latencyMs === undefined ? {} : { latencyMs: remoteObservation.latencyMs }),\n      ...(remoteObservation.viaProxy === true ? { viaProxy: true as const } : {}),\n    }\n    if (remoteObservation.state === 'ready') {\n      checks.push(check(\n        'remote',\n        remoteObservation.viaProxy === true ? 'warning' : 'ok',\n        'remote-ready',\n        '远程通道',\n        remoteObservation.viaProxy === true\n          ? `电脑经代理可访问 ${endpointSuffix}，但尚未验证手机能否连接。`\n          : `${snapshot.remote.provider} 公共地址 ${endpointSuffix} 可达，往返约 ${String(remoteObservation.latencyMs ?? 0)} ms。`,\n        remoteObservation.viaProxy === true ? '请在手机上测试远程连接。' : undefined,\n        facts,\n      ))\n    } else if (remoteObservation.state === 'rate-limited') {\n      checks.push(check(\n        'remote', 'warning', 'remote-rate-limited', '远程通道',\n        remoteObservation.viaProxy === true\n          ? '电脑经代理访问时观察到限流，尚未验证手机能否连接。'\n          : '公共地址可达，但本次检查观察到服务限流。',\n        '稍后重试；旧会话会按需加载以减少流量。', facts,\n      ))\n    } else if (snapshot.remote.provider === 'tailscale' && remoteObservation.fakeIp === true) {\n      checks.push(check(\n        'remote',\n        'error',\n        'remote-fake-ip',\n        '远程通道',\n        'Tailscale 地址被当前 VPN 或 DNS 代理接管，但 TLS 链路未建立。',\n        '切换 VPN 节点或代理模式；仍失败时改用 cpolar。',\n        facts,\n      ))\n    } else {\n      checks.push(check('remote', 'error', 'remote-unreachable', '远程通道', '提供方显示已就绪，但公共地址暂不可达。', '点击“重新连接”；仍失败时检查提供方状态。', facts))\n    }\n  } else if (snapshot.remote.state === 'starting' || snapshot.remote.state === 'connecting' || snapshot.remote.state === 'needs-login') {\n    const needsLogin = snapshot.remote.state === 'needs-login'\n    checks.push(check(\n      'remote',\n      'warning',\n      needsLogin ? 'remote-needs-login' : 'remote-connecting',\n      '远程通道',\n      needsLogin ? '等待完成 Tailscale 登录。' : '仍在建立连接。',\n      needsLogin ? '返回远程页继续登录。' : '等待片刻后重新检查。',\n      { provider: snapshot.remote.provider },\n    ))\n  } else {\n    const controllerCode = snapshot.remote.errorCode ?? snapshot.remote.state\n    checks.push(check(\n      'remote',\n      'error',\n      'remote-controller-error',\n      '远程通道',\n      `连接未建立（${controllerCode}）。`,\n      REMOTE_ERROR_GUIDANCE[controllerCode] ?? '返回远程页点击“重新连接”。',\n      { provider: snapshot.remote.provider, controllerCode },\n    ))\n  }\n\n  checks.push(check(\n    'phone-network',\n    'info',\n    'phone-network-unknown',\n    '手机网络',\n    '电脑无法判断路由器是否隔离了手机。',\n    '局域网仍失败时，确认手机与电脑在同一网络，并关闭访客网络或 AP 隔离。',\n  ))\n\n  const overall = checks.some(entry => entry.status === 'error')\n    ? 'error'\n    : checks.some(entry => entry.status === 'warning') ? 'attention' : 'ok'\n  const summary = overall === 'ok' ? '连接基础检查正常。' : overall === 'attention' ? '发现需要留意的项目。' : '发现会影响连接的问题。'\n  const report = [\n    'DSH Mobile 诊断报告',\n    `生成时间: ${new Date().toISOString()}`,\n    `版本: plugin=${DSH_MOBILE_VERSION}; dsh=${snapshot.dshVersion}; min-app=${MINIMUM_ANDROID_APP_VERSION}`,\n    `LAN: ${snapshot.lan.running ? 'on' : 'off'}; endpoint=${maskLanOrigin(snapshot.lan.origin)}`,\n    `Remote: provider=${snapshot.remote.provider}; state=${snapshot.remote.state}; endpoint=${remoteSuffix(snapshot.remote.origin)}`,\n    ...checks.map(reportLine),\n  ].join('\\n')\n  return Object.freeze({\n    version: 1,\n    generatedAt: Date.now(),\n    overall,\n    versions: Object.freeze({ plugin: DSH_MOBILE_VERSION, dsh: snapshot.dshVersion, minimumAndroidApp: MINIMUM_ANDROID_APP_VERSION }),\n    summary,\n    checks: Object.freeze(checks),\n    report,\n  })\n}\n","/**\n * Instructions handed to the DSH agent when the user runs `/mobile <task>`.\n * The agent edits files under the DSH home; this text is what tells it the\n * layout of the mobile-access customization surface so it does not guess.\n *\n * A snapshot of the current customization state (whether mobile.css /\n * mobile.js exist and which extensions are installed) is injected at the\n * top of the guide so the agent does not overwrite earlier work blindly.\n */\n\n/** One installed extension as seen by the agent. */\nexport interface MobileGuideExtensionState {\n  readonly id: string\n  readonly name: string\n  readonly version: string\n  /** Current local Host execution, omitted for ordinary Cordis-provided extensions. */\n  readonly executionMode?: 'in-process' | 'worker'\n  /** A stopped Worker needs explicit recovery; editing files is not a recovery action. */\n  readonly executionState?: 'ready' | 'unavailable'\n}\n\n/** Customization facts collected before steering the agent. */\nexport interface MobileGuideState {\n  /** Absolute path of the mobile-access directory the agent edits. */\n  readonly directory: string\n  /** True when the user's mobile.css exists (a custom style override). */\n  readonly hasCustomCss: boolean\n  /** True when the user's mobile.js exists (a custom script override). */\n  readonly hasCustomJs: boolean\n  /** Extensions currently installed under extensions/. */\n  readonly extensions: readonly MobileGuideExtensionState[]\n  /** Extensions whose host failed to activate. */\n  readonly failedExtensionCount: number\n}\n\n/** Compose the guide with the current customization state injected. */\nexport function buildMobileGuide(state: MobileGuideState): string {\n  const styleLine = state.hasCustomCss ? '存在（当前生效的自定义样式）' : '不存在（使用内置默认样式）'\n  const scriptLine = state.hasCustomJs ? '存在（当前生效的自定义脚本）' : '不存在（无自定义脚本）'\n  const extensionLines = state.extensions.length === 0\n    ? '（无）'\n    : state.extensions.map(entry => `- ${entry.id}（${entry.name} v${entry.version}）${entry.executionMode === undefined ? '' : ` · ${entry.executionMode}${entry.executionState === 'unavailable' ? ' · 当前不可用，需要显式重启扩展' : ''}`}`).join('\\n')\n  const failureLine = state.failedExtensionCount > 0\n    ? `注意：${state.failedExtensionCount} 个扩展的电脑端 host 激活失败，如改动相关扩展请先检查其 host.mjs 与 extension.json。`\n    : ''\n  const currentState = `## 手机端当前状态（改动前必读，避免覆盖已有定制）\n\n- 定制目录：${state.directory}（所有改动只允许在这里进行）\n- mobile.css：${styleLine}\n- mobile.js：${scriptLine}\n- 已安装扩展：\n${extensionLines}\n${failureLine}\n\n“恢复默认”操作说明：当用户要求恢复默认 / 还原初始外观时，删除 mobile.css 与 mobile.js 两个文件（删除后手机端自动回到内置默认外观，无需创建占位文件），并按需删除 extensions/ 下的扩展目录。\\n\\n`\n\n  return `${currentState}${MOBILE_CUSTOMIZATION_GUIDE_BODY}`\n}\n\n/**\n * Static body of the customization guide. Kept separate from the injected\n * state snapshot so the two concerns stay easy to edit independently.\n */\nconst MOBILE_CUSTOMIZATION_GUIDE_BODY = `你在为用户定制 DSH Mobile 的手机端。DSH Mobile 是一个把电脑上的 DeepSeek Harness 带到手机浏览器的插件，手机端界面和能力都来自本机文件。\n\n所有改动只允许在 $DSH_HOME/mobile-access/ 目录内进行，绝不修改 DeepSeek Harness 的源码或其他目录。$DSH_HOME 是 DeepSeek Harness 的配置目录（通常为 ~/.dsh），先确认它的实际路径再操作。\n\n手机端的能力分两层，按用户需求选择改动目标：\n\n1. 界面与交互 —— 只改外观和交互，不需要碰电脑的文件或程序：\n   - $DSH_HOME/mobile-access/mobile.css：手机端样式\n   - $DSH_HOME/mobile-access/mobile.js：手机端脚本，用 window.dshMobile.register(({ root }) => { ... }) 把内容挂载到 root，返回清理函数\n   - 保存后手机端几秒内自动应用，无需重启\n\n动手前先读已有的定制文件。若要调整 DSH 自带的输入框、侧栏或设置等现有界面，先确认当前 DSH 版本与手机页面模式（专用移动页面或 ?frontend=stock），只读核对运行页面的 DOM、属性和样式；本机有同版本前端源码时可参考相应组件，没有源码时可查看已安装的客户端产物，不必下载源码。优先使用扩展 API、插槽和稳定的 data-* 标记，不凭猜测依赖构建类名。只读查看不改变前述写入范围。\n\n2. 电脑端能力 —— 手机需要读电脑文件、执行命令或访问硬件时，创建扩展：\n   - 目录：$DSH_HOME/mobile-access/extensions/<id>/，id 用小写字母数字和连字符（如 media-remote）\n   - extension.json：{\"schemaVersion\":1,\"id\":\"<id>\",\"name\":\"显示名\",\"version\":\"0.1.0\",\"description\":\"说明\"}\n   - host.mjs：电脑端 Node.js 代码（可信本地代码，可读写文件、执行命令）。导出默认函数 (api) => { ... }，用 api.action('名称', { input, run }) 注册动作、api.route({ method, path, handle }) 注册路由、api.effect(fn) 注册清理。input 可以直接使用 api.schema.object(...) 等 Schemastery schema，也可以传入带 parse(value) 的适配器；两种形式都会在动作执行前校验并规范化输入。\n   - 执行方式见上方实际状态。默认 in-process；插件配置可按扩展选择 worker。Worker 中 api.context 只有 logger，不能调用 Cordis 服务；api.manifest、schema、action、route、effect 仍可用。不要把需要 Cordis 的扩展偷偷改成 Worker，也不要在 extension.json 中添加执行模式字段。\n   - 动作与路由的执行有时间预算：默认 30 秒（输入校验也计入），可用 api.action('名称', { input, run, timeoutMs }) 或 api.route({ ..., timeoutMs }) 按操作覆盖（1–300000 的整数毫秒）。超时或调用方取消后，调用方收到 500 extension_action_timeout / extension_route_timeout（或取消原因）；这只表示调用方不再等待，底层代码可能仍在运行并已产生副作用，请在 run / handle 中响应 signal 实现协作式取消。路由的预算到 handle() 返回响应为止，不影响已返回流的存活。若某扩展存在调用方已离开（超时或取消）但仍未结束的操作，后续对该扩展的新调用会收到 503 extension_busy，直到该操作真正结束。\n   - mobile.js：手机端脚本，用 window.dshMobile.define({ apiVersion:1, id:'<id>', activate(api) { ... } })，activate 返回清理函数\n   - mobile.css：手机端样式（可选）\n   - assets/：手机端静态资源（可选）\n   - mobile.js 里用 api.host.invoke('动作名', 输入) 调 host.mjs 的 action（请求会按 application/json 发送），api.host.fetch('/路由路径') 调 route，api.host.assetUrl('相对路径') 生成与当前版本绑定的资源地址\n   - DSH Web 可先用命令生成模板：dsh plugin --profile web exec dsh-mobile extension create <id> --name \"<名称>\"，再在模板上改；Desktop 请在上方实际定制目录创建文件，不要误改 Web profile\n\n安全约束：\n- host.mjs 拥有电脑用户的完整权限，绝不能放入不可信代码，也不要让手机端无条件执行任意命令\n- in-process 的同步阻塞会卡住网关事件循环，超时不能打断；Worker 可约束 JavaScript 阻塞，但不是安全沙箱，不约束全部原生内存，也不回滚副作用。两种模式都应响应 signal，避免编写不可取消的同步循环\n- Worker 终止后其他未完成调用会失败，已开始的操作不会自动重试。相同内容的停止实例需要操作者在电脑端“移动访问 → 扩展需要重启”中确认恢复；不要通过无意义改文件或自动重放原动作实现恢复\n- 所有改动只限 $DSH_HOME/mobile-access/，不要动 DeepSeek Harness 源码\n\n完成前请自检：\n- 改动涉及 mobile.js 或扩展的 mobile.js / host.mjs 时，先做语法检查再保存（如 node --check <file>），确保没有语法错误\n- 改动 DSH 现有界面后尽可能在实际手机页面核对效果；无法观察运行页面时，明确告诉用户尚未实测\n- 创建或修改扩展后，确认 extension.json 的 schemaVersion 为 1、id 与目录名一致、且 id 只含小写字母数字和连字符\n- 扩展的 host.mjs 若在完成前无法激活，先修正而不是留下损坏的扩展\n- 完成后检查自己实际写入了哪些文件，向用户简要说明改了什么、手机端会有什么变化`\n","import { createHash, randomBytes } from 'node:crypto'\nimport { spawn } from 'node:child_process'\nimport { lstat, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'\nimport { isIP } from './ip.js'\nimport { tmpdir } from 'node:os'\nimport { isAbsolute, join, resolve } from 'node:path'\nimport { validateFrpPublicOrigin, validateFrpServerAddress, validateFrpServerPort, validateFrpToken, type FrpSettings } from './frp-config.js'\nimport {\n  FRP_CADDY_IMPORT_LINE,\n  FRP_CADDY_SNIPPET_MARKER,\n  FRP_CADDY_SNIPPET_PATH,\n  createCaddySite,\n} from './frp-template.js'\nimport { isGloballyRoutableIpv4 } from './network.js'\n\nconst FRP_VERSION = '0.70.1'\nconst SSH_TIMEOUT_MS = 300_000\nconst MAX_OUTPUT_BYTES = 96 * 1024\n\nconst LINUX_ARTIFACTS = Object.freeze({\n  x64: Object.freeze({\n    directory: `frp_${FRP_VERSION}_linux_amd64`,\n    url: `https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_amd64.tar.gz`,\n    sha256: '333da23d1b9009d7c01638e9ba38cf4600f7d37d393f854e96ee1396adefa9a6',\n  }),\n  arm64: Object.freeze({\n    directory: `frp_${FRP_VERSION}_linux_arm64`,\n    url: `https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_arm64.tar.gz`,\n    sha256: '3990f396a9a490ee7f0e5f355287750ed41520064ed999eab443b5e9a78d773d',\n  }),\n})\n\nexport interface VpsDeploymentInput {\n  readonly sshUser: string\n  readonly sshPort: number\n  readonly sshKeyPath?: string\n  /**\n   * User-confirmed SHA256 host-key fingerprints (`SHA256:…`, one per server key).\n   * The deployment aborts unless every key the server currently presents is confirmed.\n   */\n  readonly hostFingerprints: readonly string[]\n}\n\n/** One SSH server host key with its OpenSSH-style SHA256 fingerprint. */\nexport interface VpsHostKey {\n  readonly keyType: string\n  readonly fingerprint: string\n}\n\nexport interface VpsDeploymentCheck {\n  readonly id: string\n  readonly status: 'ok' | 'warning' | 'error'\n  readonly detail: string\n}\n\nexport interface VpsDeploymentResult {\n  readonly version: 1\n  readonly deployed: boolean\n  readonly serverAddress: string\n  readonly publicOrigin: string\n  readonly checks: readonly VpsDeploymentCheck[]\n}\n\nexport interface VpsDeploymentOptions {\n  readonly runSsh?: (input: VpsDeploymentInput, serverAddress: string, script: string) => Promise<{ stdout: string; stderr: string }>\n  readonly runKeyscan?: (input: { readonly sshUser: unknown; readonly sshPort: unknown }, serverAddress: string) => Promise<string>\n  readonly runRemoteScript?: (input: VpsDeploymentInput, serverAddress: string, script: string) => Promise<{ stdout: string; stderr: string }>\n  readonly log?: (event: string, fields: Readonly<Record<string, string | number | boolean>>) => void\n}\n\nexport class VpsSshError extends Error {\n  readonly timedOut: boolean\n  readonly exitCode: number | null | undefined\n  readonly signal: NodeJS.Signals | null | undefined\n  constructor(message: string, readonly stdout: string, readonly stderr: string, options?: ErrorOptions & { readonly timedOut?: boolean; readonly exitCode?: number | null; readonly signal?: NodeJS.Signals | null }) {\n    super(message, options)\n    this.timedOut = options?.timedOut ?? false\n    this.exitCode = options?.exitCode\n    this.signal = options?.signal\n  }\n}\n\nfunction shellQuote(value: string): string {\n  return `'${value.replaceAll(\"'\", \"'\\\\''\")}'`\n}\n\n/**\n * Reject loopback, private, and other non-routable IPv4 literals as VPS SSH\n * targets. A self-hosted deployment always addresses a public server; the\n * shared frpc settings stay permissive so local loopback test rigs keep working.\n */\nfunction assertPublicSshTarget(serverAddress: string): void {\n  if (isIP(serverAddress) === 4 && !isGloballyRoutableIpv4(serverAddress)) {\n    throw new Error('vps_server_not_public')\n  }\n}\n\n/**\n * Validate a VPS address for every operation that opens a network connection\n * to it (scan, deploy, cleanup). IPv6 is unsupported by the SSH flow and\n * loopback/private targets are never valid VPS endpoints.\n */\nfunction validateVpsServerTarget(serverAddress: string): string {\n  const address = validateFrpServerAddress(serverAddress)\n  if (isIP(address) !== 0 && address.includes(':')) throw new Error('vps_ipv6_ssh_not_supported')\n  assertPublicSshTarget(address)\n  return address\n}\n\nfunction validSshUser(value: unknown): string {\n  if (typeof value !== 'string' || value.length < 1 || value.length > 64 || !/^[a-z_][a-z0-9_.-]*[$]?$/iu.test(value)) {\n    throw new Error('vps_ssh_user_invalid')\n  }\n  return value\n}\n\nfunction validSshPort(value: unknown): number {\n  if (!Number.isSafeInteger(value) || Number(value) < 1 || Number(value) > 65_535) throw new Error('vps_ssh_port_invalid')\n  return Number(value)\n}\n\nfunction validSshKeyPath(value: unknown): string | undefined {\n  if (value === undefined || value === '') return undefined\n  if (typeof value !== 'string' || !isAbsolute(value) || value.length > 4_096 || /[\\u0000-\\u001f\\u007f]/u.test(value)) {\n    throw new Error('vps_ssh_key_invalid')\n  }\n  return resolve(value)\n}\n\nexport function parseVpsDeploymentInput(value: unknown): VpsDeploymentInput {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('vps_deploy_input_invalid')\n  const record = value as Record<string, unknown>\n  if (Reflect.ownKeys(record).some(key => !['sshUser', 'sshPort', 'sshKeyPath', 'hostFingerprints'].includes(String(key)))) {\n    throw new Error('vps_deploy_input_invalid')\n  }\n  const sshKeyPath = validSshKeyPath(record.sshKeyPath)\n  return Object.freeze({\n    sshUser: validSshUser(record.sshUser),\n    sshPort: validSshPort(record.sshPort),\n    ...(sshKeyPath === undefined ? {} : { sshKeyPath }),\n    hostFingerprints: Object.freeze(parseVpsHostFingerprints(record.hostFingerprints)),\n  })\n}\n\n/** Validate user-confirmed SHA256 host-key fingerprints (`SHA256:…`). */\nexport function parseVpsHostFingerprints(value: unknown): string[] {\n  if (!Array.isArray(value) || value.length < 1 || value.length > 8) throw new Error('vps_host_key_unconfirmed')\n  const fingerprints: string[] = []\n  for (const entry of value) {\n    if (typeof entry !== 'string' || !/^SHA256:[A-Za-z0-9+/]{40,60}={0,2}$/u.test(entry) || entry.length > 96) {\n      throw new Error('vps_host_key_unconfirmed')\n    }\n    fingerprints.push(entry)\n  }\n  return [...new Set(fingerprints)]\n}\n\nconst SUPPORTED_HOST_KEY_TYPES = new Set([\n  'ssh-rsa',\n  'ecdsa-sha2-nistp256',\n  'ecdsa-sha2-nistp384',\n  'ecdsa-sha2-nistp521',\n  'ssh-ed25519',\n])\n\n/** Format a raw host public key the way OpenSSH displays it (`SHA256:…` without padding). */\nexport function fingerprintHostPublicKey(keyType: string, base64Key: string): string {\n  if (!SUPPORTED_HOST_KEY_TYPES.has(keyType)) throw new Error('vps_host_key_unsupported_type')\n  if (!/^[A-Za-z0-9+/]+={0,2}$/u.test(base64Key) || base64Key.length < 24 || base64Key.length > 1_024) {\n    throw new Error('vps_host_key_invalid')\n  }\n  const raw = Buffer.from(base64Key, 'base64')\n  if (raw.length < 16 || raw.length > 768) throw new Error('vps_host_key_invalid')\n  return `SHA256:${createHash('sha256').update(raw).digest('base64').replace(/=+$/u, '')}`\n}\n\nfunction parseKeyscanOutput(output: string): Array<{ keyType: string; base64Key: string }> {\n  const keys: Array<{ keyType: string; base64Key: string }> = []\n  for (const line of output.split(/\\r?\\n/u)) {\n    const trimmed = line.trim()\n    if (trimmed === '' || trimmed.startsWith('#')) continue\n    // Pinned known_hosts lines are rebuilt from the independently validated server address.\n    const match = /^(?:\\S+\\s+)?(ssh-rsa|ecdsa-sha2-nistp\\d+|ssh-ed25519)\\s+([A-Za-z0-9+/]+={0,2})(\\s|$)/u.exec(trimmed)\n    if (match?.[1] === undefined || match[2] === undefined) throw new Error('vps_host_key_invalid')\n    keys.push({ keyType: match[1], base64Key: match[2] })\n  }\n  return keys\n}\n\n/** Base SSH options shared by long deployment sessions. Keepalives survive NAT\n *  middleboxes during minute-long apt/pip phases; host identity stays pinned. */\nfunction sshSessionOptions(knownHostsFile: string): string[] {\n  return [\n    '-o', 'BatchMode=yes', '-o', 'ConnectTimeout=15',\n    '-o', 'ServerAliveInterval=15', '-o', 'ServerAliveCountMax=8',\n    '-o', 'StrictHostKeyChecking=yes', `-o UserKnownHostsFile=${knownHostsFile}`,\n  ]\n}\n\n/** Recognize usable public-key scan output without authenticating to the server. */\nfunction tryParseKeyscanOutput(output: string): Array<{ keyType: string; base64Key: string }> | undefined {\n  try {\n    return parseKeyscanOutput(output)\n  } catch {\n    return undefined\n  }\n}\n\nasync function gitBundledKeyscan(): Promise<string | undefined> {\n  if (process.platform !== 'win32') return undefined\n  const programFiles = process.env['ProgramFiles'] ?? 'C:\\\\Program Files'\n  const candidate = join(programFiles, 'Git', 'usr', 'bin', 'ssh-keyscan.exe')\n  try {\n    const entry = await lstat(candidate)\n    if (!entry.isFile()) return undefined\n  } catch {\n    return undefined\n  }\n  return candidate\n}\n\nasync function defaultRunKeyscan(input: { readonly sshUser: unknown; readonly sshPort: unknown }, serverAddress: string): Promise<string> {\n  const keyscan = process.platform === 'win32' ? 'ssh-keyscan.exe' : 'ssh-keyscan'\n  const args = ['-T', '10', '-p', String(input.sshPort), '-t', 'rsa,ecdsa,ed25519', serverAddress]\n  const first = await runProcess(keyscan, args, undefined, 30_000).catch(() => undefined)\n  if (first !== undefined && tryParseKeyscanOutput(first.stdout)?.length) return first.stdout\n  // Old keyscan binaries fail KEX against modern servers (non-zero exit, no\n  // keys); retry with the Git for Windows copy when present before giving up.\n  // Both alternatives are unauthenticated public-key scans.\n  const bundled = await gitBundledKeyscan()\n  if (bundled !== undefined) {\n    const second = await runProcess(bundled, args, undefined, 30_000).catch(() => undefined)\n    if (second !== undefined && tryParseKeyscanOutput(second.stdout)?.length) return second.stdout\n  }\n  return first?.stdout ?? ''\n}\n\nexport interface VpsSshFetchInput {\n  readonly sshUser: unknown\n  readonly sshPort: unknown\n  readonly sshKeyPath?: unknown\n}\n\n/** Obtain public host keys without using a private key, agent or unverified authenticated connection. */\nasync function scanHostKeys(\n  input: VpsSshFetchInput,\n  serverAddress: string,\n  options: VpsDeploymentOptions,\n): Promise<string> {\n  const runKeyscan = options.runKeyscan ?? defaultRunKeyscan\n  let scanned: string\n  try { scanned = await runKeyscan({ sshUser: input.sshUser, sshPort: input.sshPort }, serverAddress) }\n  catch (error) { throw new Error('vps_host_key_unavailable', { cause: error }) }\n  const keys = parseKeyscanOutput(scanned)\n  if (keys.length === 0) throw new Error('vps_host_key_unavailable')\n  return scanned\n}\n\n/**\n * Fetch the server's current host keys and return them with OpenSSH-style\n * fingerprints for the user to confirm out of band (for example against the\n * VPS console) before any destructive or authenticated deployment step.\n */\nexport async function fetchVpsHostKeys(\n  serverAddress: string,\n  input: VpsSshFetchInput,\n  options: VpsDeploymentOptions = {},\n): Promise<readonly VpsHostKey[]> {\n  const address = validateVpsServerTarget(serverAddress)\n  const sshUser = validSshUser(input.sshUser)\n  const sshPort = validSshPort(input.sshPort)\n  const output = await scanHostKeys({ sshUser, sshPort, sshKeyPath: input.sshKeyPath }, address, options)\n  const keys = parseKeyscanOutput(output)\n  if (keys.length === 0) throw new Error('vps_host_key_unavailable')\n  const seen = new Set<string>()\n  const hostKeys: VpsHostKey[] = []\n  for (const key of keys) {\n    const fingerprint = fingerprintHostPublicKey(key.keyType, key.base64Key)\n    if (seen.has(fingerprint)) continue\n    seen.add(fingerprint)\n    hostKeys.push(Object.freeze({ keyType: key.keyType, fingerprint }))\n  }\n  options.log?.('host-keys-fetched', { serverAddress: address, keyTypes: hostKeys.length })\n  return Object.freeze(hostKeys)\n}\n\n/**\n * Verify that every host key the server currently presents was confirmed by the\n * user, then return a pinned known_hosts body. Fails closed on rotation,\n * replacement, or unexpected extra keys.\n */\nexport function buildPinnedKnownHosts(\n  serverAddress: string,\n  sshPort: number,\n  keyscanOutput: string,\n  confirmedFingerprints: readonly string[],\n): string {\n  const address = validateFrpServerAddress(serverAddress)\n  const port = validSshPort(sshPort)\n  const confirmed = new Set(parseVpsHostFingerprints([...confirmedFingerprints]))\n  const keys = parseKeyscanOutput(keyscanOutput)\n  if (keys.length === 0) throw new Error('vps_host_key_unavailable')\n  const host = port === 22 ? address : `[${address}]:${port}`\n  const lines: string[] = []\n  for (const key of keys) {\n    const fingerprint = fingerprintHostPublicKey(key.keyType, key.base64Key)\n    if (!confirmed.has(fingerprint)) throw new Error('vps_host_key_mismatch')\n    lines.push(`${host} ${key.keyType} ${key.base64Key}`)\n  }\n  return `${lines.join('\\n')}\\n`\n}\n\nfunction safeOutput(value: string, token: string): string {\n  const redacted = token === '' ? value : value.replaceAll(token, '<redacted>')\n  return redacted.replace(/[\\u0000-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f]/gu, '').slice(0, 8_192).trim()\n}\n\nfunction parseChecks(stdout: string, stderr: string, token: string): readonly VpsDeploymentCheck[] {\n  const checks: VpsDeploymentCheck[] = []\n  for (const line of stdout.split(/\\r?\\n/u)) {\n    const match = /^DSH_MOBILE_CHECK\\s+([a-z0-9_-]+)\\s+(ok|warning|error)\\s+(.+)$/iu.exec(line)\n    if (match !== null) checks.push(Object.freeze({ id: match[1]!, status: match[2]!.toLowerCase() as VpsDeploymentCheck['status'], detail: safeOutput(match[3]!, token) }))\n  }\n  if (checks.length === 0 && stderr.trim() !== '') {\n    checks.push(Object.freeze({ id: 'remote-command', status: 'error', detail: safeOutput(stderr, token) || 'VPS 返回了未分类错误。' }))\n  }\n  return Object.freeze(checks)\n}\n\n/**\n * One-line failure detail for transport-level failures: prefer the failed\n * remote check, otherwise use the last stderr line (a `set -eu` abort has no\n * check line) instead of dumping the whole transcript into the UI.\n */\nfunction failureDetail(stdout: string, stderr: string, token: string): string {\n  const parsed = parseChecks(`${stdout}\\n${stderr}`, '', token)\n  const failed = parsed.find(check => check.status === 'error')\n  if (failed !== undefined) return failed.detail\n  for (const stream of [stderr, stdout]) {\n    const lines = stream.split(/\\r?\\n/u).map(line => line.trim()).filter(line => line !== '')\n    const last = lines[lines.length - 1]\n    if (last !== undefined) return safeOutput(last, token)\n  }\n  return ''\n}\n\nfunction deploymentScript(settings: FrpSettings): string {\n  const amd64 = LINUX_ARTIFACTS.x64\n  const arm64 = LINUX_ARTIFACTS.arm64\n  const config = [\n    'bindAddr = \"0.0.0.0\"',\n    `bindPort = ${String(settings.serverPort)}`,\n    'proxyBindAddr = \"127.0.0.1\"',\n    'vhostHTTPPort = 7080',\n    'auth.method = \"token\"',\n    `auth.token = ${JSON.stringify(settings.token)}`,\n    '',\n  ].join('\\n')\n  const publicHost = new URL(settings.publicOrigin).hostname\n  const publicIp = isGloballyRoutableIpv4(publicHost)\n  // The site content is shared with the manual template; only the wiring\n  // (snippet file + one import line) differs.\n  const caddySite = createCaddySite(publicHost)\n  const caddySnippet = `${FRP_CADDY_SNIPPET_MARKER}\\n${caddySite.trimEnd()}\\n`\n  const ipCertificateSetup = publicIp ? `\nexport DEBIAN_FRONTEND=noninteractive\napt-get install -y python3-venv\nif [ ! -x /opt/dsh-mobile/certbot-venv/bin/certbot ]; then\n  python3 -m venv /opt/dsh-mobile/certbot-venv\n  /opt/dsh-mobile/certbot-venv/bin/pip install --disable-pip-version-check 'certbot==5.8.0'\nfi\nsystemctl stop caddy.service || true\nif ! /opt/dsh-mobile/certbot-venv/bin/certbot certonly --standalone --preferred-profile shortlived --ip-address ${publicHost} --agree-tos --register-unsafely-without-email --non-interactive --keep-until-expiring; then\n  systemctl start caddy.service || true\n  fail \"公网 IP HTTPS 证书申请失败；请确认 80/tcp 可从公网访问。\"\nfi\ninstall -d -m 0750 -o caddy -g caddy /var/lib/caddy/dsh-mobile-certs\ninstall -m 0640 -o caddy -g caddy /etc/letsencrypt/live/${publicHost}/fullchain.pem /var/lib/caddy/dsh-mobile-certs/fullchain.pem\ninstall -m 0640 -o caddy -g caddy /etc/letsencrypt/live/${publicHost}/privkey.pem /var/lib/caddy/dsh-mobile-certs/privkey.pem\ncat > /usr/local/sbin/dsh-mobile-cert-renew <<'DSH_MOBILE_CERT_RENEW'\n#!/bin/sh\nset -eu\nsystemctl stop caddy.service\ntrap 'systemctl start caddy.service' EXIT\n/opt/dsh-mobile/certbot-venv/bin/certbot renew --cert-name ${publicHost} --preferred-profile shortlived --non-interactive\ninstall -d -m 0750 -o caddy -g caddy /var/lib/caddy/dsh-mobile-certs\ninstall -m 0640 -o caddy -g caddy /etc/letsencrypt/live/${publicHost}/fullchain.pem /var/lib/caddy/dsh-mobile-certs/fullchain.pem\ninstall -m 0640 -o caddy -g caddy /etc/letsencrypt/live/${publicHost}/privkey.pem /var/lib/caddy/dsh-mobile-certs/privkey.pem\nDSH_MOBILE_CERT_RENEW\nchmod 0755 /usr/local/sbin/dsh-mobile-cert-renew\ncat > /etc/systemd/system/dsh-mobile-cert-renew.service <<'DSH_MOBILE_CERT_SERVICE'\n[Unit]\nDescription=Renew DSH Mobile public IP TLS certificate\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=oneshot\nExecStart=/usr/local/sbin/dsh-mobile-cert-renew\nDSH_MOBILE_CERT_SERVICE\ncat > /etc/systemd/system/dsh-mobile-cert-renew.timer <<'DSH_MOBILE_CERT_TIMER'\n[Unit]\nDescription=Daily DSH Mobile public IP TLS certificate renewal check\n\n[Timer]\nOnCalendar=daily\nRandomizedDelaySec=2h\nPersistent=true\nUnit=dsh-mobile-cert-renew.service\n\n[Install]\nWantedBy=timers.target\nDSH_MOBILE_CERT_TIMER\ncheck certificate ok \"Let's Encrypt 公网 IP 证书已安装并启用每日自动续期。\"\n` : ''\n  return `#!/bin/sh\nset -eu\numask 077\n\nfail() { echo \"DSH_MOBILE_CHECK remote-command error $1\" >&2; exit 1; }\ncheck() { echo \"DSH_MOBILE_CHECK $1 $2 $3\"; }\n\n# Serialize concurrent deploys: two writers racing sed -i on the Caddyfile\n# can duplicate the import line and break validation. Uninstall takes the\n# same lock, so deploy and cleanup also exclude each other.\nif command -v flock >/dev/null 2>&1; then\n  exec 9>/tmp/dsh-mobile-deploy.lock\n  flock -n 9 || fail \"已有部署或清理正在进行，请稍后再试。\"\nfi\n\n[ \"$(id -u)\" = \"0\" ] || fail \"请使用 root SSH 账号。\"\ncommand -v systemctl >/dev/null 2>&1 || fail \"VPS 不支持 systemd。\"\ncommand -v tar >/dev/null 2>&1 || fail \"VPS 缺少 tar。\"\ncommand -v curl >/dev/null 2>&1 || fail \"VPS 缺少 curl。\"\ncommand -v sha256sum >/dev/null 2>&1 || fail \"VPS 缺少 sha256sum。\"\ncommand -v useradd >/dev/null 2>&1 || fail \"VPS 缺少 useradd。\"\n\nif [ -r /etc/os-release ]; then . /etc/os-release; else fail \"无法识别 VPS 系统。\"; fi\ncase \"\\${ID:-}\" in\n  debian|ubuntu) ;;\n  *) fail \"首版 VPS 部署只支持 Debian/Ubuntu。\" ;;\nesac\ncheck os ok \"\\${PRETTY_NAME:-Debian/Ubuntu}\"\n\nif command -v ss >/dev/null 2>&1 && ss -ltnH | awk '{print $4}' | grep -Eq '(^|:)${String(settings.serverPort)}$'; then\n  systemctl is-active --quiet dsh-mobile-frps.service || fail \"端口 ${String(settings.serverPort)} 已被占用。\"\nfi\n\nif ! command -v caddy >/dev/null 2>&1; then\n  export DEBIAN_FRONTEND=noninteractive\n  # A previous interrupted run may have left these files unreadable because\n  # the deployment uses umask 077. APT reads repositories as the _apt user.\n  chmod 0644 /usr/share/keyrings/caddy-stable-archive-keyring.gpg 2>/dev/null || true\n  chmod 0644 /etc/apt/sources.list.d/caddy-stable.list 2>/dev/null || true\n  apt-get update\n  apt-get install -y debian-keyring debian-archive-keyring apt-transport-https curl gnupg\n  curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor --yes -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg\n  curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' -o /etc/apt/sources.list.d/caddy-stable.list\n  chmod 0644 /usr/share/keyrings/caddy-stable-archive-keyring.gpg /etc/apt/sources.list.d/caddy-stable.list\n  apt-get update\n  apt-get install -y caddy\nfi\ncheck caddy ok \"Caddy 已安装。\"\n\n# The site lives in our own snippet file; the main Caddyfile only gains one\n# import line, so existing user content is never rewritten or merged.\ncaddy_import='${FRP_CADDY_IMPORT_LINE}'\ninstall -d -m 0755 /etc/caddy\ncaddyfile_ready=false\nif [ ! -e /etc/caddy/Caddyfile ]; then\n  printf '%s\\n' \"$caddy_import\" > /etc/caddy/Caddyfile\n  chmod 0644 /etc/caddy/Caddyfile\n  caddyfile_ready=true\nelif grep -Eq '^[[:space:]]*import[[:space:]]+/etc/caddy/dsh-mobile-dsh\\.caddy([[:space:]]|$)' /etc/caddy/Caddyfile; then\n  # The snippet may carry global options (IP mode default_sni), which must\n  # precede all site blocks after import inlining: rebuild the file with a\n  # single import on top. Removal uses grep -v with the exact gate pattern\n  # above (not sed -i, whose in-place delete proved unreliable here), and the\n  # result is verified to carry exactly one import before replacing the file.\n  {\n    printf '%s\\n' \"$caddy_import\"\n    grep -Ev '^[[:space:]]*import[[:space:]]+/etc/caddy/dsh-mobile-dsh\\.caddy([[:space:]]|$)' /etc/caddy/Caddyfile || true\n  } > /etc/caddy/Caddyfile.dsh-new\n  [ \"$(grep -Ec '^[[:space:]]*import[[:space:]]+/etc/caddy/dsh-mobile-dsh\\.caddy([[:space:]]|$)' /etc/caddy/Caddyfile.dsh-new)\" = 1 ] \\\n    || fail \"Caddyfile import 整理失败，未做任何修改。\"\n  cat /etc/caddy/Caddyfile.dsh-new > /etc/caddy/Caddyfile\n  rm -f /etc/caddy/Caddyfile.dsh-new\n  chmod 0644 /etc/caddy/Caddyfile\n  caddyfile_ready=true\nelif [ ! -s /etc/caddy/Caddyfile ]; then\n  printf '%s\\n' \"$caddy_import\" > /etc/caddy/Caddyfile\n  chmod 0644 /etc/caddy/Caddyfile\n  caddyfile_ready=true\nelif grep -q '^# DSH Mobile removed its site' /etc/caddy/Caddyfile; then\n  # Leftover placeholder from our own uninstall: drop only that line, then\n  # ensure the import exists exactly once (same grep -v + count discipline).\n  grep -Ev '^# DSH Mobile removed its site.*$' /etc/caddy/Caddyfile > /etc/caddy/Caddyfile.dsh-new || true\n  grep -Eq '^[[:space:]]*import[[:space:]]+/etc/caddy/dsh-mobile-dsh\\.caddy([[:space:]]|$)' /etc/caddy/Caddyfile.dsh-new \\\n    || printf '%s\\n' \"$caddy_import\" >> /etc/caddy/Caddyfile.dsh-new\n  [ \"$(grep -Ec '^[[:space:]]*import[[:space:]]+/etc/caddy/dsh-mobile-dsh\\.caddy([[:space:]]|$)' /etc/caddy/Caddyfile.dsh-new)\" = 1 ] \\\n    || fail \"Caddyfile import 整理失败，未做任何修改。\"\n  cat /etc/caddy/Caddyfile.dsh-new > /etc/caddy/Caddyfile\n  rm -f /etc/caddy/Caddyfile.dsh-new\n  chmod 0644 /etc/caddy/Caddyfile\n  caddyfile_ready=true\nelse\n  caddy_hash=\"$(sha256sum /etc/caddy/Caddyfile | awk '{print $1}')\"\n  if [ \"$caddy_hash\" = '66177d46fa761acb07208065db9b0274cb1b12c02ac43b9bfc9857b698b1ccfe' ]; then\n    printf '%s\\n' \"$caddy_import\" > /etc/caddy/Caddyfile\n    chmod 0644 /etc/caddy/Caddyfile\n    caddyfile_ready=true\n  fi\nfi\nif [ \"$caddyfile_ready\" != true ]; then\n  fail \"已有 Caddyfile，请先备份，然后加一行 ${FRP_CADDY_IMPORT_LINE}，或手动合并站点。\"\nfi\n\n${ipCertificateSetup}\n\narch=\"$(uname -m)\"\ncase \"$arch\" in\n  x86_64|amd64) url=${shellQuote(amd64.url)}; expected=${shellQuote(amd64.sha256)}; directory=${shellQuote(amd64.directory)} ;;\n  aarch64|arm64) url=${shellQuote(arm64.url)}; expected=${shellQuote(arm64.sha256)}; directory=${shellQuote(arm64.directory)} ;;\n  *) fail \"只支持 Linux x86_64 和 arm64。\" ;;\nesac\n\ntmp=\"$(mktemp -d /tmp/dsh-mobile-frp.XXXXXX)\"\ncleanup() { rm -rf \"$tmp\"; [ -z \"\\${DSH_MOBILE_FRP_ARCHIVE:-}\" ] || rm -f \"$DSH_MOBILE_FRP_ARCHIVE\"; }\ntrap cleanup EXIT HUP INT TERM\narchive=\"$tmp/frp.tar.gz\"\nif [ -n \"\\${DSH_MOBILE_FRP_ARCHIVE:-}\" ]; then\n  [ -f \"$DSH_MOBILE_FRP_ARCHIVE\" ] || fail \"上传的 frps 安装包不存在。\"\n  cp \"$DSH_MOBILE_FRP_ARCHIVE\" \"$archive\"\nelse\n  curl --fail --location --proto '=https' --tlsv1.2 --output \"$archive\" \"$url\"\nfi\nactual=\"$(sha256sum \"$archive\" | awk '{print $1}')\"\n[ \"$actual\" = \"$expected\" ] || fail \"frps 下载校验失败。\"\ntar -xzf \"$archive\" -C \"$tmp\" \"$directory/frps\"\n\ninstall -d -m 0755 /usr/local/libexec/dsh-mobile/frp/${FRP_VERSION}\ninstall -m 0755 \"$tmp/$directory/frps\" /usr/local/libexec/dsh-mobile/frp/${FRP_VERSION}/frps\n# The account must exist before anything references its group below.\ndsh_mobile_created=false\nif ! id -u dsh-mobile >/dev/null 2>&1; then\n  useradd --system --home-dir /nonexistent --shell /usr/sbin/nologin --no-create-home dsh-mobile\n  dsh_mobile_created=true\nfi\ninstall -d -m 0750 -o root -g dsh-mobile /etc/dsh-mobile\nif [ \"$dsh_mobile_created\" = true ]; then\n  # Ownership record: uninstall removes the account only when this deployment created it.\n  touch /etc/dsh-mobile/.owns-account\n  check account ok \"已创建 dsh-mobile 系统用户。\"\nelse\n  check account ok \"复用已有的 dsh-mobile 系统用户（卸载时将保留）。\"\nfi\ncat > /etc/dsh-mobile/frps.toml <<'DSH_MOBILE_FRPS_CONFIG'\n${config}DSH_MOBILE_FRPS_CONFIG\nchown root:dsh-mobile /etc/dsh-mobile/frps.toml\nchmod 0640 /etc/dsh-mobile/frps.toml\n\ncat > /etc/systemd/system/dsh-mobile-frps.service <<'DSH_MOBILE_FRPS_UNIT'\n[Unit]\nDescription=DSH Mobile self-hosted FRP server\nAfter=network-online.target\nWants=network-online.target\n\n[Service]\nType=simple\nUser=dsh-mobile\nGroup=dsh-mobile\nExecStart=/usr/local/libexec/dsh-mobile/frp/${FRP_VERSION}/frps -c /etc/dsh-mobile/frps.toml\nRestart=on-failure\nRestartSec=5s\nNoNewPrivileges=true\nPrivateTmp=true\nProtectHome=true\nProtectSystem=strict\n\n[Install]\nWantedBy=multi-user.target\nDSH_MOBILE_FRPS_UNIT\n\ncat > ${FRP_CADDY_SNIPPET_PATH} <<'DSH_MOBILE_CADDY_SNIPPET'\n${caddySnippet}DSH_MOBILE_CADDY_SNIPPET\nchmod 0644 ${FRP_CADDY_SNIPPET_PATH}\ncaddy validate --config /etc/caddy/Caddyfile\nsystemctl daemon-reload\n# Restart (not just start) so a redeploy over a running previous generation\n# actually picks up the new frps token and config instead of keeping the old\n# process alive with stale credentials.\nsystemctl enable dsh-mobile-frps.service\nsystemctl restart dsh-mobile-frps.service\nsystemctl enable --now caddy.service\n${publicIp ? 'systemctl enable --now dsh-mobile-cert-renew.timer' : ''}\nsystemctl reload caddy.service || systemctl restart caddy.service\n\nif command -v ufw >/dev/null 2>&1 && ufw status | grep -q '^Status: active'; then\n  ufw allow ${String(settings.serverPort)}/tcp comment 'DSH Mobile FRP control' >/dev/null\n  ufw allow 80/tcp comment 'DSH Mobile HTTPS redirect' >/dev/null\n  ufw allow 443/tcp comment 'DSH Mobile HTTPS' >/dev/null\n  check firewall ok \"UFW 已放行 FRP 控制端口和 HTTPS。\"\nelse\n  check firewall warning \"未修改系统防火墙；请确认 ${String(settings.serverPort)}/tcp、80/tcp、443/tcp 已放行。\"\nfi\n\nsystemctl is-active --quiet dsh-mobile-frps.service || fail \"frps 服务启动失败。\"\nsystemctl is-active --quiet caddy.service || fail \"Caddy 服务启动失败。\"\ncheck frps ok \"frps ${FRP_VERSION} 已启动，7080 仅绑定回环地址。\"\ncheck caddy ok \"Caddy 已加载 ${publicHost}。\"\necho DSH_MOBILE_DEPLOYMENT_OK\n`\n}\n\n/** Run one owned SSH/transfer utility; reject only after its process and stdio have closed. */\nexport async function runVpsProcess(command: string, args: readonly string[], stdin?: string, timeoutMs = SSH_TIMEOUT_MS): Promise<{ stdout: string; stderr: string }> {\n  return new Promise((resolveRun, rejectRun) => {\n    const child = spawn(command, args, { windowsHide: true, stdio: ['pipe', 'pipe', 'pipe'] })\n    let stdout = ''\n    let stderr = ''\n    const append = (current: string, chunk: Buffer): string => `${current}${chunk.toString('utf8')}`.slice(-MAX_OUTPUT_BYTES)\n    let timedOut = false\n    let failure: Error | undefined\n    let failureCode = 'vps_ssh_unavailable'\n    let forceTimer: NodeJS.Timeout | undefined\n    const terminate = (): void => {\n      child.kill()\n      forceTimer ??= setTimeout(() => {\n        if (child.exitCode === null && child.signalCode === null) child.kill('SIGKILL')\n        child.stdin.destroy(); child.stdout.destroy(); child.stderr.destroy()\n      }, 1000)\n      forceTimer.unref()\n    }\n    const timer = setTimeout(() => { timedOut = true; terminate() }, timeoutMs)\n    timer.unref()\n    child.stdout.on('data', chunk => { stdout = append(stdout, Buffer.from(chunk)) })\n    child.stderr.on('data', chunk => { stderr = append(stderr, Buffer.from(chunk)) })\n    child.once('error', error => { failure = error })\n    child.stdin.on('error', error => { failure = error; failureCode = 'vps_ssh_input_failed'; terminate() })\n    const failedOutput = (error:Error):void => { failure = error; failureCode = 'vps_ssh_transport_failed'; terminate() }\n    child.stdout.on('error',failedOutput);child.stderr.on('error',failedOutput)\n    child.once('close', (code, signal) => {\n      clearTimeout(timer)\n      if (forceTimer !== undefined) clearTimeout(forceTimer)\n      const facts = {timedOut,exitCode:code,signal,...(failure === undefined ? {} : {cause:failure})}\n      if (timedOut) rejectRun(new VpsSshError('vps_ssh_timeout',stdout,stderr,facts))\n      else if (failure !== undefined) rejectRun(new VpsSshError(child.pid === undefined ? 'vps_ssh_unavailable' : failureCode,stdout,stderr,facts))\n      else if (code !== 0) rejectRun(new VpsSshError(stderr.includes('Permission denied') ? 'vps_ssh_auth_failed' : 'vps_deploy_failed', stdout, stderr, facts))\n      else resolveRun({ stdout, stderr })\n    })\n    child.stdin.end(stdin, 'utf8')\n  })\n}\n\nconst runProcess = runVpsProcess\n\nasync function downloadArtifact(artifact: (typeof LINUX_ARTIFACTS)[keyof typeof LINUX_ARTIFACTS], file: string): Promise<number> {\n  const curl = process.platform === 'win32' ? 'curl.exe' : 'curl'\n  await runProcess(curl, [\n    ...(process.platform === 'win32' ? ['--ipv4'] : []),\n    '--fail', '--location', '--silent', '--show-error',\n    '--connect-timeout', '15', '--max-time', '180',\n    '--proto', '=https', '--tlsv1.2', '--output', file, artifact.url,\n  ], undefined, 200_000)\n  const bytes = await readFile(file)\n  if (createHash('sha256').update(bytes).digest('hex') !== artifact.sha256) throw new Error('vps_download_hash_mismatch')\n  return bytes.byteLength\n}\n\nasync function defaultRunSsh(\n  input: VpsDeploymentInput,\n  serverAddress: string,\n  script: string,\n  knownHostsFile: string,\n  log?: VpsDeploymentOptions['log'],\n): Promise<{ stdout: string; stderr: string }> {\n  const ssh = process.platform === 'win32' ? 'ssh.exe' : 'ssh'\n  const scp = process.platform === 'win32' ? 'scp.exe' : 'scp'\n  // The server identity is pinned to the user-confirmed fingerprints captured\n  // before deployment. Unknown or rotated keys abort instead of being accepted.\n  const common = sshSessionOptions(knownHostsFile)\n  if (input.sshKeyPath !== undefined) common.push('-i', input.sshKeyPath)\n  const target = `${input.sshUser}@${serverAddress}`\n  const probe = await runProcess(ssh, [...common, '-p', String(input.sshPort), target, 'uname -m'])\n  const architecture = probe.stdout.trim()\n  const artifact = architecture === 'x86_64' || architecture === 'amd64'\n    ? LINUX_ARTIFACTS.x64\n    : architecture === 'aarch64' || architecture === 'arm64' ? LINUX_ARTIFACTS.arm64 : undefined\n  if (artifact === undefined) throw new Error('vps_arch_unsupported')\n  log?.('architecture', { architecture })\n  const localDirectory = await mkdtemp(join(tmpdir(), 'dsh-mobile-frp-'))\n  const localArchive = join(localDirectory, 'frp.tar.gz')\n  const remoteArchive = `/tmp/dsh-mobile-frp-${randomBytes(12).toString('hex')}.tar.gz`\n  try {\n    log?.('download-start', { source: 'local', architecture })\n    const bytes = await downloadArtifact(artifact, localArchive)\n    log?.('download-complete', { source: 'local', bytes })\n    const scpResult = await runProcess(scp, [...common, '-P', String(input.sshPort), localArchive, `${target}:${remoteArchive}`])\n    log?.('upload-complete', { bytes, stderrBytes: Buffer.byteLength(scpResult.stderr) })\n    const remoteCommand = input.sshUser === 'root'\n      ? `env DSH_MOBILE_FRP_ARCHIVE=${shellQuote(remoteArchive)} sh -s`\n      : `sudo -n env DSH_MOBILE_FRP_ARCHIVE=${shellQuote(remoteArchive)} sh -s`\n    return await runProcess(ssh, [...common, '-p', String(input.sshPort), target, remoteCommand], script)\n  } finally {\n    await rm(localDirectory, { recursive: true, force: true })\n  }\n}\n\nexport async function deployVps(settings: FrpSettings, input: VpsDeploymentInput, options: VpsDeploymentOptions = {}): Promise<VpsDeploymentResult> {\n  const serverPort = validateFrpServerPort(settings.serverPort)\n  const token = validateFrpToken(settings.token)\n  const publicOrigin = validateFrpPublicOrigin(settings.publicOrigin)\n  const serverAddress = validateVpsServerTarget(settings.serverAddress)\n  const parsedInput = parseVpsDeploymentInput(input)\n  if (parsedInput.sshKeyPath !== undefined) {\n    const entry = await lstat(parsedInput.sshKeyPath).catch(() => undefined)\n    if (entry === undefined || !entry.isFile() || entry.isSymbolicLink()) throw new Error('vps_ssh_key_invalid')\n  }\n  // Pin the server identity before any authenticated connection: re-scan the\n  // host keys now and require every presented key to be user-confirmed, so a\n  // rotation between the UI preview and this deployment aborts safely.\n  const keyscanOutput = await scanHostKeys(\n    { sshUser: parsedInput.sshUser, sshPort: parsedInput.sshPort, sshKeyPath: parsedInput.sshKeyPath },\n    serverAddress,\n    options,\n  )\n  const knownHostsBody = buildPinnedKnownHosts(serverAddress, parsedInput.sshPort, keyscanOutput, parsedInput.hostFingerprints)\n  options.log?.('host-keys-verified', { serverAddress })\n  const runSsh = options.runSsh ?? (async (sshInput, host, scriptBody) => {\n    const workDirectory = await mkdtemp(join(tmpdir(), 'dsh-mobile-known-hosts-'))\n    try {\n      const knownHostsFile = join(workDirectory, 'known_hosts')\n      await writeFile(knownHostsFile, knownHostsBody, { encoding: 'utf8', mode: 0o600 })\n      return await defaultRunSsh(sshInput, host, scriptBody, knownHostsFile, options.log)\n    } finally {\n      await rm(workDirectory, { recursive: true, force: true })\n    }\n  })\n  options.log?.('validated', { serverAddress, serverPort, publicOrigin, sshUser: parsedInput.sshUser, sshPort: parsedInput.sshPort, keyProvided: parsedInput.sshKeyPath !== undefined })\n  let result: { stdout: string; stderr: string }\n  try {\n    options.log?.('ssh-start', { serverAddress, sshPort: parsedInput.sshPort })\n    result = await runSsh(parsedInput, serverAddress, deploymentScript({ ...settings, serverAddress, serverPort, token, publicOrigin }))\n    options.log?.('ssh-complete', { stdoutBytes: Buffer.byteLength(result.stdout), stderrBytes: Buffer.byteLength(result.stderr) })\n  } catch (error) {\n    if (error instanceof VpsSshError) {\n      // Prefer the failed remote check over raw output: the script reports\n      // failures through DSH_MOBILE_CHECK lines on either stream, and the raw\n      // concatenation would leak protocol framing into the UI.\n      const detail = failureDetail(error.stdout, error.stderr, token)\n      options.log?.('ssh-failed', { code: error.message, detail: detail || 'no remote output' })\n      throw new Error(detail === '' ? error.message : `${error.message}:${detail}`, { cause: error })\n    }\n    options.log?.('ssh-failed', { code: error instanceof Error ? error.message : 'unknown' })\n    throw error\n  }\n  const checks = parseChecks(result.stdout, result.stderr, token)\n  for (const check of checks) options.log?.('remote-check', { id: check.id, status: check.status, detail: check.detail })\n  if (!result.stdout.includes('DSH_MOBILE_DEPLOYMENT_OK')) {\n    if (checks.length === 0) throw new Error('vps_deploy_failed')\n    throw new Error(`vps_deploy_failed:${checks.map(check => check.detail).join(' ')}`)\n  }\n  return Object.freeze({ version: 1, deployed: true, serverAddress, publicOrigin, checks })\n}\n\nexport function vpsDeploymentScriptForTesting(settings: FrpSettings): string {\n  return deploymentScript(settings)\n}\n\nexport interface VpsUninstallInput {\n  readonly serverPort: unknown\n  /** Let's Encrypt certificate name to delete (public-IPv4 mode); omit for domain mode. */\n  readonly certName?: unknown\n}\n\nexport interface VpsUninstallResult {\n  readonly version: 1\n  readonly removed: boolean\n  readonly serverAddress: string\n  readonly checks: readonly VpsDeploymentCheck[]\n}\n\nfunction validCertName(value: unknown): string | undefined {\n  if (value === undefined || value === '') return undefined\n  if (typeof value !== 'string' || value.length > 253 || !/^[a-z0-9.-]+$/u.test(value)) throw new Error('vps_cert_name_invalid')\n  return value.toLowerCase()\n}\n\n/**\n * Build a reviewable uninstall script that removes only DSH Mobile-owned\n * server artifacts: its systemd units, config, binaries, venv, renew helper,\n * managed Caddy site, owned UFW rules, and optionally its IP certificate.\n * Existing non-DSH-Mobile Caddy content and firewall rules are never touched.\n */\nexport function createVpsUninstallScript(input: VpsUninstallInput): string {\n  const serverPort = validateFrpServerPort(input.serverPort)\n  const certName = validCertName(input.certName)\n  const certCleanup = certName === undefined ? '' : `\nif [ -x /opt/dsh-mobile/certbot-venv/bin/certbot ]; then\n  /opt/dsh-mobile/certbot-venv/bin/certbot delete --cert-name ${shellQuote(certName)} --non-interactive || true\nfi\n`\n  return `#!/bin/sh\n# DSH Mobile VPS uninstall. Review before running: only files, services, and\n# firewall rules created by the DSH Mobile deployment are removed.\nset -eu\numask 077\n\nfail() { echo \"DSH_MOBILE_CHECK remote-command error $1\" >&2; exit 1; }\ncheck() { echo \"DSH_MOBILE_CHECK $1 $2 $3\"; }\n\n# Same lock as the deploy script: cleanup and deployment exclude each other\n# so their Caddyfile surgeries never interleave.\nif command -v flock >/dev/null 2>&1; then\n  exec 9>/tmp/dsh-mobile-deploy.lock\n  flock -n 9 || fail \"已有部署或清理正在进行，请稍后再试。\"\nfi\n\n[ \"$(id -u)\" = \"0\" ] || fail \"请使用 root SSH 账号。\"\ncommand -v systemctl >/dev/null 2>&1 || fail \"VPS 不支持 systemd。\"\n\n# Ownership is decided before deleting anything: only an account created by a\n# DSH Mobile deployment (marker written at useradd time) may be removed below.\nowns_account=false\nif [ -f /etc/dsh-mobile/.owns-account ]; then owns_account=true; fi\n\nsystemctl disable --now dsh-mobile-cert-renew.timer >/dev/null 2>&1 || true\nsystemctl disable --now dsh-mobile-frps.service >/dev/null 2>&1 || true\nrm -f /etc/systemd/system/dsh-mobile-frps.service\nrm -f /etc/systemd/system/dsh-mobile-cert-renew.service\nrm -f /etc/systemd/system/dsh-mobile-cert-renew.timer\nsystemctl daemon-reload\ncheck services ok \"已停止并删除 dsh-mobile-frps 服务与证书续期定时器。\"\n${certCleanup}\nrm -rf /etc/dsh-mobile\nrm -rf /usr/local/libexec/dsh-mobile\nrm -rf /opt/dsh-mobile/certbot-venv\nrm -f /usr/local/sbin/dsh-mobile-cert-renew\nrm -rf /var/lib/caddy/dsh-mobile-certs\nrm -f ${FRP_CADDY_SNIPPET_PATH}\ncheck files ok \"已删除 DSH Mobile 配置、二进制与证书文件。\"\n\nif grep -Eq '^[[:space:]]*import[[:space:]]+/etc/caddy/dsh-mobile-dsh\\.caddy([[:space:]]|$)' /etc/caddy/Caddyfile 2>/dev/null; then\n  # Rebuild without our import line (grep -v with the gate pattern, verified\n  # to remove every copy), keeping all user content byte-identical otherwise.\n  grep -Ev '^[[:space:]]*import[[:space:]]+/etc/caddy/dsh-mobile-dsh\\.caddy([[:space:]]|$)' /etc/caddy/Caddyfile > /etc/caddy/Caddyfile.dsh-new || true\n  if grep -Eq '^[[:space:]]*import[[:space:]]+/etc/caddy/dsh-mobile-dsh\\.caddy([[:space:]]|$)' /etc/caddy/Caddyfile.dsh-new; then\n    rm -f /etc/caddy/Caddyfile.dsh-new\n    fail \"Caddyfile import 移除失败，未做任何修改。\"\n  fi\n  cat /etc/caddy/Caddyfile.dsh-new > /etc/caddy/Caddyfile\n  rm -f /etc/caddy/Caddyfile.dsh-new\n  if [ ! -s /etc/caddy/Caddyfile ]; then\n    printf '# DSH Mobile removed its site; the remaining Caddyfile was empty.\\n' > /etc/caddy/Caddyfile\n    chmod 0644 /etc/caddy/Caddyfile\n  fi\n  if command -v caddy >/dev/null 2>&1; then\n    caddy validate --config /etc/caddy/Caddyfile && systemctl reload caddy.service || systemctl restart caddy.service || true\n  fi\n  check caddy ok \"已移除 DSH Mobile 站点引入；其余 Caddy 配置保持原样。\"\nelif [ -f /etc/caddy/Caddyfile ] && grep -q '^# Managed by DSH Mobile$' /etc/caddy/Caddyfile; then\n  # A legacy marker does not establish ownership of subsequently added sites.\n  check caddy warning \"已保留旧版 Caddyfile；请手动移除 DSH Mobile 站点，不要删除其他站点。\"\nelse\n  check caddy ok \"Caddyfile 非 DSH Mobile 管理，保持原样。\"\nfi\n\nif command -v ufw >/dev/null 2>&1 && ufw status 2>/dev/null | grep -q '^Status: active'; then\n  for rule in $(ufw status numbered 2>/dev/null | grep 'DSH Mobile' | sed -E 's/^\\\\[ *([0-9]+)\\\\].*/\\\\1/' | sort -rn); do\n    yes | ufw delete \"$rule\" >/dev/null 2>&1 || true\n  done\n  check firewall ok \"已删除带 DSH Mobile 标记的 UFW 规则（FRP 控制端口 ${String(serverPort)}、80、443）。\"\nelse\n  check firewall ok \"UFW 未启用或无需调整。\"\nfi\n\nif [ \"$owns_account\" = true ]; then\n  if id dsh-mobile >/dev/null 2>&1; then\n    if pgrep -u dsh-mobile >/dev/null 2>&1; then\n      fail \"dsh-mobile 用户仍有运行中的进程，已保留该用户；请先停止相关进程后重试。\"\n    fi\n    userdel dsh-mobile || fail \"删除 dsh-mobile 系统用户失败。\"\n    check account ok \"已删除本次部署创建的 dsh-mobile 系统用户。\"\n  else\n    check account ok \"dsh-mobile 系统用户已不存在，无需删除。\"\n  fi\nelse\n  check account ok \"dsh-mobile 系统用户非本次部署创建，已保留。\"\nfi\n\necho DSH_MOBILE_UNINSTALL_OK\n`\n}\n\nasync function runRemoteScript(\n  input: VpsDeploymentInput,\n  serverAddress: string,\n  script: string,\n  environment: Readonly<Record<string, string>>,\n  knownHostsFile: string,\n  log?: VpsDeploymentOptions['log'],\n): Promise<{ stdout: string; stderr: string }> {\n  const ssh = process.platform === 'win32' ? 'ssh.exe' : 'ssh'\n  const parsedInput = parseVpsDeploymentInput(input)\n  const common = sshSessionOptions(knownHostsFile)\n  if (parsedInput.sshKeyPath !== undefined) common.push('-i', parsedInput.sshKeyPath)\n  const target = `${parsedInput.sshUser}@${serverAddress}`\n  const remoteCommand = parsedInput.sshUser === 'root' ? 'sh -s' : 'sudo -n sh -s'\n  const envPrefix = Object.entries(environment).map(([key, value]) => `${key}=${shellQuote(value)}`).join(' ')\n  log?.('uninstall-ssh-start', { serverAddress })\n  return await runProcess(ssh, [...common, '-p', String(parsedInput.sshPort), target, `${envPrefix} ${remoteCommand}`.trim()], script)\n}\n\n/** Remove DSH Mobile-owned server artifacts over a pinned SSH connection. */\nexport async function uninstallVps(\n  serverAddress: string,\n  uninstall: VpsUninstallInput,\n  input: VpsDeploymentInput,\n  options: VpsDeploymentOptions = {},\n): Promise<VpsUninstallResult> {\n  const address = validateVpsServerTarget(serverAddress)\n  const parsedInput = parseVpsDeploymentInput(input)\n  // Identity is verified with a fresh scan immediately before this destructive\n  // action: every presented key must still be user-confirmed.\n  const keyscanOutput = await scanHostKeys(\n    { sshUser: parsedInput.sshUser, sshPort: parsedInput.sshPort, sshKeyPath: parsedInput.sshKeyPath },\n    address,\n    options,\n  )\n  const knownHostsBody = buildPinnedKnownHosts(address, parsedInput.sshPort, keyscanOutput, parsedInput.hostFingerprints)\n  options.log?.('host-keys-verified', { serverAddress: address })\n  const script = createVpsUninstallScript(uninstall)\n  options.log?.('uninstall-start', { serverAddress: address })\n  const runRemote = options.runRemoteScript ?? (async (sshInput, host, scriptBody) => {\n    const workDirectory = await mkdtemp(join(tmpdir(), 'dsh-mobile-known-hosts-'))\n    try {\n      const knownHostsFile = join(workDirectory, 'known_hosts')\n      await writeFile(knownHostsFile, knownHostsBody, { encoding: 'utf8', mode: 0o600 })\n      return await runRemoteScript(sshInput, host, scriptBody, {}, knownHostsFile, options.log)\n    } finally {\n      await rm(workDirectory, { recursive: true, force: true })\n    }\n  })\n  let result: { stdout: string; stderr: string }\n  try {\n    result = await runRemote(parsedInput, address, script)\n  } catch (error) {\n    if (error instanceof VpsSshError) {\n      // runProcess labels transport failures as deploy errors; relabel them\n      // and prefer the failed remote check over raw output (see deployVps).\n      const detail = failureDetail(error.stdout, error.stderr, '')\n      const code = error.message === 'vps_deploy_failed' ? 'vps_uninstall_failed' : error.message\n      options.log?.('uninstall-failed', { code, detail: detail || 'no remote output' })\n      throw new Error(detail === '' ? code : `${code}:${detail}`, { cause: error })\n    }\n    options.log?.('uninstall-failed', { code: error instanceof Error ? error.message : 'unknown' })\n    throw error\n  }\n  const checks = parseChecks(result.stdout, result.stderr, '')\n  for (const check of checks) options.log?.('remote-check', { id: check.id, status: check.status, detail: check.detail })\n  if (!result.stdout.includes('DSH_MOBILE_UNINSTALL_OK')) {\n    if (checks.length === 0) throw new Error('vps_uninstall_failed')\n    throw new Error(`vps_uninstall_failed:${checks.map(check => check.detail).join(' ')}`)\n  }\n  return Object.freeze({ version: 1, removed: true, serverAddress: address, checks })\n}\n","import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'\nimport { lstat } from 'node:fs/promises'\nimport { dirname, isAbsolute, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { MobileAccessControlState, MobileAccessControlStore } from './control.js'\nimport type { MobileAccessGateway } from './gateway.js'\nimport { settleRemoteResources, terminateRemoteProcess, type RemoteProviderController } from './remote.js'\nimport { assertManagedParents, ensureManagedDirectory, removeManagedTree } from './managed-files.js'\n\nconst MAX_PROTOCOL_LINE_BYTES = 16 * 1024\nconst FUNNEL_START_TIMEOUT_MS = 45_000\n\n/** Product-facing states for the independent Tailscale Funnel transport. */\nexport type FunnelState = 'off' | 'unavailable' | 'starting' | 'needs-login' | 'connecting' | 'ready' | 'error'\n\n/** Safe state returned only through the loopback DSH control route. */\nexport interface FunnelStatus {\n  readonly enabled: boolean\n  readonly state: FunnelState\n  readonly origin?: string\n  readonly loginUrl?: string\n  readonly setupUrl?: string\n  readonly errorCode?: string\n}\n\ninterface FunnelEvent {\n  readonly version: 1\n  readonly type: 'login' | 'ready' | 'serving' | 'error'\n  readonly url?: string\n  readonly origin?: string\n  readonly code?: string\n}\n\n/** Construction inputs for one Funnel lifecycle independent from the LAN gateway. */\nexport interface FunnelControllerOptions {\n  readonly store: MobileAccessControlStore\n  readonly executable: string\n  readonly stateDirectory: string\n  /** The plugin's owned Mobile state root; direct callers own the explicit state-directory parent. */\n  readonly ownedRoot?: string\n  readonly hostname: string\n  readonly createGateway: (origin: string) => Promise<MobileAccessGateway>\n  readonly onStatus?: (status: FunnelStatus) => void\n}\n\nfunction publicStatus(status: FunnelStatus): FunnelStatus {\n  return Object.freeze({\n    enabled: status.enabled,\n    state: status.state,\n    ...(status.origin === undefined ? {} : { origin: status.origin }),\n    ...(status.loginUrl === undefined ? {} : { loginUrl: status.loginUrl }),\n    ...(status.setupUrl === undefined ? {} : { setupUrl: status.setupUrl }),\n    ...(status.errorCode === undefined ? {} : { errorCode: status.errorCode }),\n  })\n}\n\nconst FUNNEL_SETUP_URLS = new Set([\n  'https://tailscale.com/s/no-funnel',\n  'https://tailscale.com/s/https',\n])\n\nfunction parseSetupUrl(value: unknown): string | undefined {\n  if (value === undefined) return undefined\n  if (typeof value !== 'string' || value.length > 2048) throw new Error('invalid_sidecar_protocol')\n  const url = new URL(value)\n  const normalized = url.toString().replace(/\\/$/u, '')\n  const officialInteractive = url.protocol === 'https:' && url.hostname === 'login.tailscale.com'\n    && url.port === '' && url.username === '' && url.password === ''\n  if (!FUNNEL_SETUP_URLS.has(normalized) && !officialInteractive) throw new Error('invalid_sidecar_protocol')\n  return officialInteractive ? url.toString() : normalized\n}\n\nfunction parseOrigin(value: unknown): string {\n  if (typeof value !== 'string' || value.length > 512) throw new Error('invalid_funnel_origin')\n  let url: URL\n  try { url = new URL(value) } catch { throw new Error('invalid_funnel_origin') }\n  if (url.protocol !== 'https:' || !url.hostname.endsWith('.ts.net') || url.port !== ''\n    || url.pathname !== '/' || url.search !== '' || url.hash !== ''\n    || url.username !== '' || url.password !== '') throw new Error('invalid_funnel_origin')\n  return url.origin\n}\n\n/** Parse one sidecar protocol line while restricting every browser-opened URL. */\nexport function parseFunnelEvent(line: string): FunnelEvent {\n  if (Buffer.byteLength(line, 'utf8') === 0 || Buffer.byteLength(line, 'utf8') > MAX_PROTOCOL_LINE_BYTES) {\n    throw new Error('invalid_sidecar_protocol')\n  }\n  let value: unknown\n  try { value = JSON.parse(line) as unknown } catch { throw new Error('invalid_sidecar_protocol') }\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('invalid_sidecar_protocol')\n  const record = value as Record<string, unknown>\n  if (record.version !== 1 || typeof record.type !== 'string') throw new Error('invalid_sidecar_protocol')\n  if (record.type === 'login') {\n    if (typeof record.url !== 'string' || record.url.length > 2048) throw new Error('invalid_sidecar_protocol')\n    const url = new URL(record.url)\n    if (url.protocol !== 'https:' || url.hostname !== 'login.tailscale.com') throw new Error('invalid_sidecar_protocol')\n    return Object.freeze({ version: 1, type: 'login', url: url.toString() })\n  }\n  if (record.type === 'ready' || record.type === 'serving') {\n    return Object.freeze({ version: 1, type: record.type, origin: parseOrigin(record.origin) })\n  }\n  if (record.type === 'error') {\n    if (typeof record.code !== 'string' || !/^[a-z][a-z0-9_]{0,63}$/u.test(record.code)) {\n      throw new Error('invalid_sidecar_protocol')\n    }\n    const setupUrl = parseSetupUrl(record.url)\n    return Object.freeze({ version: 1, type: 'error', code: record.code, ...(setupUrl === undefined ? {} : { url: setupUrl }) })\n  }\n  throw new Error('invalid_sidecar_protocol')\n}\n\nfunction withoutProvisioningSecrets(environment: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n  const blocked = new Set(['TS_AUTHKEY', 'TAILSCALE_AUTHKEY', 'TS_OAUTH_CLIENT_SECRET'])\n  return Object.fromEntries(Object.entries(environment).filter(([name]) => !blocked.has(name.toUpperCase())))\n}\n\n/** Owns the source-built tsnet sidecar, remote gateway, and persisted remote switch. */\nexport class FunnelController implements RemoteProviderController {\n  private enabled = false\n  private initialized = false\n  private disposed = false\n  private child: ChildProcessWithoutNullStreams | undefined\n  private gatewayValue: MobileAccessGateway | undefined\n  private generation = 0\n  private buffer = ''\n  private latest: FunnelStatus = publicStatus({ enabled: false, state: 'off' })\n  private queue: Promise<void> = Promise.resolve()\n  private closeTask: Promise<void> | undefined\n  private startTimer: NodeJS.Timeout | undefined\n  private readonly ownedRoot: string\n\n  constructor(private readonly options: FunnelControllerOptions) {\n    if (!isAbsolute(options.executable) || !isAbsolute(options.stateDirectory)) {\n      throw new Error('Funnel paths must be absolute')\n    }\n    this.ownedRoot = options.ownedRoot ?? dirname(resolve(options.stateDirectory))\n    if (!isAbsolute(this.ownedRoot) || resolve(this.ownedRoot) === resolve(options.stateDirectory)) throw new Error('Funnel state must be a child of its owned root')\n  }\n\n  /** Restore the remote switch without coupling it to LAN availability. */\n  async initialize(initialState?: MobileAccessControlState): Promise<void> {\n    try { await this.assertStateParents() } catch (_error) {\n      this.enabled = false\n      this.initialized = true\n      this.publish({ enabled: false, state: 'unavailable', errorCode: 'funnel_state_invalid' })\n      return\n    }\n    const state = initialState ?? await this.options.store.load()\n    this.enabled = state.enabled\n    this.initialized = true\n    if (this.enabled) await this.start()\n    else this.publish({ enabled: false, state: 'off' })\n  }\n\n  /** Return the currently attached authenticated remote gateway. */\n  gateway(): MobileAccessGateway | undefined {\n    return this.gatewayValue\n  }\n\n  /** Return state safe for the local desktop control UI. */\n  status(): FunnelStatus {\n    return publicStatus(this.latest)\n  }\n\n  /** Enable or disable Funnel without changing the LAN listener. */\n  async setEnabled(enabled: boolean): Promise<FunnelStatus> {\n    if (!this.initialized || this.disposed) throw new Error('Funnel controller is unavailable')\n    await this.enqueue(async () => {\n      const ownsResources = this.child !== undefined || this.gatewayValue !== undefined\n      if (this.enabled === enabled && (enabled ? this.child !== undefined : !ownsResources && this.latest.state === 'off')) return\n      if (!enabled) {\n        // A damaged state directory must never prevent an already-owned process\n        // or gateway from being stopped. Keep the durable switch untouched when\n        // validation fails, so a repaired directory can be retried safely.\n        try { await this.assertStateParents() } catch (error) {\n          try { await this.stop() } catch (cleanupError) {\n            this.publish({ enabled: this.enabled, state: 'error', errorCode: 'funnel_cleanup_failed' })\n            throw new AggregateError([error, cleanupError], 'Funnel state validation and cleanup failed')\n          }\n          this.publish({ enabled: this.enabled, state: 'unavailable', errorCode: 'funnel_state_invalid' })\n          throw error\n        }\n        // Persist before changing in-memory ownership. A failed write leaves the\n        // working tunnel intact and the same operation remains retryable.\n        await this.options.store.save({ version: 1, enabled: false })\n        this.enabled = false\n        try { await this.stop() } catch (error) {\n          this.publish({ enabled: false, state: 'error', errorCode: 'funnel_cleanup_failed' })\n          throw error\n        }\n        this.publish({ enabled: false, state: 'off' })\n        return\n      }\n      try { await this.assertStateParents() } catch (error) {\n        this.publish({ enabled: this.enabled, state: 'unavailable', errorCode: 'funnel_state_invalid' })\n        throw error\n      }\n      await this.options.store.save({ version: 1, enabled: true })\n      this.enabled = true\n      // A previous failed disable may have stopped publishing state while still\n      // retaining a resource whose cleanup failed. Reconcile it before restart.\n      if (ownsResources) await this.stop()\n      await this.start()\n    })\n    return this.status()\n  }\n\n  /** Restart a failed or interrupted Funnel session while retaining sign-in state. */\n  async reconnect(): Promise<FunnelStatus> {\n    if (!this.initialized || this.disposed) throw new Error('Funnel controller is unavailable')\n    await this.enqueue(async () => {\n      try { await this.assertStateParents() } catch (error) {\n        this.publish({ enabled: this.enabled, state: 'unavailable', errorCode: 'funnel_state_invalid' })\n        throw error\n      }\n      if (!this.enabled) {\n        await this.options.store.save({ version: 1, enabled: true })\n        this.enabled = true\n      }\n      await this.stop()\n      await this.start()\n    })\n    return this.status()\n  }\n\n  /** Disable Funnel and remove only its private Tailscale node state. */\n  async reset(): Promise<FunnelStatus> {\n    if (!this.initialized || this.disposed) throw new Error('Funnel controller is unavailable')\n    await this.enqueue(async () => {\n      try {\n        await assertManagedParents(this.ownedRoot, this.options.stateDirectory, 'funnel')\n        const selected = await lstat(this.options.stateDirectory).catch(error => {\n          if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n          return undefined\n        })\n        if (selected !== undefined && (selected.isSymbolicLink() || !selected.isDirectory())) {\n          await removeManagedTree(this.ownedRoot, this.options.stateDirectory, 'funnel')\n        }\n      } catch (error) {\n        this.publish({ enabled: this.enabled, state: 'off', errorCode: 'funnel_state_invalid' })\n        throw error\n      }\n      await this.options.store.save({ version: 1, enabled: false })\n      this.enabled = false\n      await this.stop()\n      try {\n        await removeManagedTree(this.ownedRoot, this.options.stateDirectory, 'funnel')\n        await this.assertStateParents()\n        // A configured control file can belong to the node directory just removed.\n        await this.options.store.save({ version: 1, enabled: false })\n      } catch (error) {\n        this.publish({ enabled: false, state: 'off', errorCode: 'funnel_state_invalid' })\n        throw error\n      }\n      this.publish({ enabled: false, state: 'off' })\n    })\n    return this.status()\n  }\n\n  /** Stop all remote resources without modifying the remembered switch. */\n  close(): Promise<void> {\n    if (this.closeTask !== undefined) return this.closeTask\n    this.disposed = true\n    const task = this.enqueue(() => this.stop())\n    this.closeTask = task.catch((error: unknown) => {\n      this.closeTask = undefined\n      throw error\n    })\n    return this.closeTask\n  }\n\n  private enqueue(operation: () => Promise<void>): Promise<void> {\n    const task = this.queue.then(operation, operation)\n    this.queue = task.then(() => undefined, () => undefined)\n    return task\n  }\n\n  private publish(status: FunnelStatus): void {\n    this.latest = publicStatus(status)\n    try { this.options.onStatus?.(this.status()) } catch { /* UI observation cannot own runtime state. */ }\n  }\n\n  private async assertStateParents(): Promise<void> {\n    await assertManagedParents(this.ownedRoot, this.options.stateDirectory, 'funnel')\n    try {\n      const entry = await lstat(this.options.stateDirectory)\n      if (!entry.isDirectory() || entry.isSymbolicLink()) throw new Error('funnel_path_invalid')\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n    }\n  }\n\n  private async start(): Promise<void> {\n    const generation = ++this.generation\n    let entry\n    try { entry = await lstat(this.options.executable) } catch {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'component_missing' })\n      return\n    }\n    if (!entry.isFile() || entry.isSymbolicLink()) {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'component_invalid' })\n      return\n    }\n    try {\n      await this.assertStateParents()\n      await ensureManagedDirectory(this.ownedRoot, this.options.stateDirectory, 'funnel')\n    } catch (_error) {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'funnel_state_invalid' })\n      return\n    }\n    this.buffer = ''\n    this.publish({ enabled: true, state: 'starting' })\n    const child = spawn(this.options.executable, [\n      '--state-dir', resolve(this.options.stateDirectory),\n      '--hostname', this.options.hostname,\n    ], {\n      env: withoutProvisioningSecrets(process.env),\n      shell: false,\n      stdio: ['pipe', 'pipe', 'pipe'],\n      windowsHide: true,\n    })\n    this.child = child\n    this.clearStartTimer()\n    this.startTimer = setTimeout(() => {\n      void this.enqueue(() => this.failGeneration(generation, 'funnel_start_timeout'))\n    }, FUNNEL_START_TIMEOUT_MS)\n    this.startTimer.unref()\n    child.stderr.resume()\n    child.stdout.setEncoding('utf8')\n    child.stdout.on('data', chunk => { this.consume(generation, String(chunk)) })\n    child.once('error', () => {\n      void this.enqueue(() => this.failGeneration(generation, 'sidecar_launch_failed'))\n    })\n    child.once('close', code => {\n      if (generation !== this.generation || this.child !== child) return\n      this.child = undefined\n      if (this.enabled) {\n        void this.enqueue(() => this.failGeneration(generation, code === 0 ? 'sidecar_stopped' : 'sidecar_exited'))\n      }\n    })\n  }\n\n  private consume(generation: number, chunk: string): void {\n    if (generation !== this.generation) return\n    this.buffer += chunk\n    if (Buffer.byteLength(this.buffer, 'utf8') > MAX_PROTOCOL_LINE_BYTES && !this.buffer.includes('\\n')) {\n      void this.enqueue(() => this.failGeneration(generation, 'invalid_sidecar_protocol'))\n      return\n    }\n    while (true) {\n      const newline = this.buffer.indexOf('\\n')\n      if (newline < 0) return\n      const line = this.buffer.slice(0, newline).replace(/\\r$/u, '')\n      this.buffer = this.buffer.slice(newline + 1)\n      let event: FunnelEvent\n      try { event = parseFunnelEvent(line) } catch {\n        void this.enqueue(() => this.failGeneration(generation, 'invalid_sidecar_protocol'))\n        return\n      }\n      void this.enqueue(() => this.handleEvent(generation, event))\n    }\n  }\n\n  private async handleEvent(generation: number, event: FunnelEvent): Promise<void> {\n    if (generation !== this.generation || !this.enabled) return\n    this.clearStartTimer()\n    if (event.type === 'login') {\n      this.publish({ enabled: true, state: 'needs-login', loginUrl: event.url! })\n      return\n    }\n    if (event.type === 'error') {\n      await this.failGeneration(generation, event.code ?? 'funnel_failed', event.url)\n      return\n    }\n    const origin = parseOrigin(event.origin)\n    if (event.type === 'ready') {\n      let gateway: MobileAccessGateway\n      try {\n        await this.gatewayValue?.close()\n        this.gatewayValue = undefined\n        gateway = await this.options.createGateway(origin)\n      } catch {\n        await this.failGeneration(generation, 'gateway_start_failed')\n        return\n      }\n      if (generation !== this.generation || !this.enabled) {\n        await gateway.close()\n        return\n      }\n      this.gatewayValue = gateway\n      const address = gateway.address()\n      const child = this.child\n      if (child === undefined) {\n        await this.failGeneration(generation, 'sidecar_stopped')\n        return\n      }\n      child.stdin.write(\n        `${JSON.stringify({ version: 1, type: 'serve', target: `http://${address.host}:${String(address.port)}` })}\\n`,\n        error => {\n          if (error !== null && error !== undefined) {\n            void this.enqueue(() => this.failGeneration(generation, 'control_channel_failed'))\n          }\n        },\n      )\n      this.publish({ enabled: true, state: 'connecting', origin })\n      return\n    }\n    this.publish({ enabled: true, state: 'ready', origin })\n  }\n\n  private async failGeneration(generation: number, code: string, setupUrl?: string): Promise<void> {\n    if (generation !== this.generation) return\n    await this.stopProcessAndGateway()\n    if (this.enabled) this.publish({ enabled: true, state: 'error', errorCode: code, ...(setupUrl === undefined ? {} : { setupUrl }) })\n  }\n\n  private async stop(): Promise<void> {\n    ++this.generation\n    await this.stopProcessAndGateway()\n  }\n\n  private async stopProcessAndGateway(): Promise<void> {\n    this.clearStartTimer()\n    const child = this.child\n    const gateway = this.gatewayValue\n    await settleRemoteResources([\n      async () => {\n        child?.stdin.end()\n        if (child !== undefined && child.exitCode === null) await terminateRemoteProcess(child)\n        if (this.child === child) this.child = undefined\n      },\n      async () => {\n        if (gateway !== undefined) {\n          await gateway.close()\n          if (this.gatewayValue === gateway) this.gatewayValue = undefined\n        }\n      },\n    ], 'Funnel resource cleanup failed')\n  }\n\n  private clearStartTimer(): void {\n    if (this.startTimer === undefined) return\n    clearTimeout(this.startTimer)\n    this.startTimer = undefined\n  }\n}\n\n/** Locate the current platform's bundled Funnel executable, with one local development override. */\nexport function funnelExecutable(importMetaUrl: string, environment: NodeJS.ProcessEnv = process.env): string {\n  const override = environment.DSH_MOBILE_FUNNEL_SIDECAR\n  if (override !== undefined) {\n    if (!isAbsolute(override)) throw new Error('DSH_MOBILE_FUNNEL_SIDECAR must be an absolute path')\n    return resolve(override)\n  }\n  const suffix = process.platform === 'win32' ? '.exe' : ''\n  const file = `dsh-mobile-funnel-${process.platform}-${process.arch}${suffix}`\n  return resolve(fileURLToPath(new URL(`../bin/${file}`, importMetaUrl)))\n}\n","import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'\nimport { lstat } from 'node:fs/promises'\nimport { createServer, type Server } from 'node:net'\nimport { isAbsolute, resolve } from 'node:path'\nimport type { MobileAccessControlState, MobileAccessControlStore } from './control.js'\nimport type { MobileAccessGateway } from './gateway.js'\nimport { settleRemoteResources, terminateRemoteProcess, type RemoteProviderController } from './remote.js'\n\nconst MAX_LOG_BUFFER_BYTES = 64 * 1024\nconst START_TIMEOUT_MS = 45_000\nconst CPOLAR_HOST_SUFFIXES = Object.freeze(['.cpolar.cn', '.cpolar.io', '.cpolar.top', '.cpolar.com'])\n\n/** Product-facing states for the optional cpolar remote transport. */\nexport type CpolarState = 'off' | 'unavailable' | 'starting' | 'connecting' | 'ready' | 'error'\n\n/** Safe cpolar state returned only through the loopback DSH control route. */\nexport interface CpolarStatus {\n  readonly enabled: boolean\n  readonly state: CpolarState\n  readonly origin?: string\n  readonly errorCode?: string\n}\n\n/** Inputs for one cpolar process and its authenticated DSH gateway. */\nexport interface CpolarControllerOptions {\n  readonly store: MobileAccessControlStore\n  readonly executable: string\n  readonly configFile: string\n  readonly region?: string\n  readonly createGateway: (origin: string, listenPort: number) => Promise<MobileAccessGateway>\n  readonly onStatus?: (status: CpolarStatus) => void\n  readonly spawnProcess?: (\n    executable: string,\n    args: readonly string[],\n    environment: NodeJS.ProcessEnv,\n  ) => ChildProcessWithoutNullStreams\n}\n\ninterface PortReservation {\n  readonly port: number\n  readonly release: () => Promise<void>\n}\n\nfunction publicStatus(status: CpolarStatus): CpolarStatus {\n  return Object.freeze({\n    enabled: status.enabled,\n    state: status.state,\n    ...(status.origin === undefined ? {} : { origin: status.origin }),\n    ...(status.errorCode === undefined ? {} : { errorCode: status.errorCode }),\n  })\n}\n\nfunction isCpolarHost(hostname: string): boolean {\n  return CPOLAR_HOST_SUFFIXES.some(suffix => hostname.endsWith(suffix))\n}\n\n/** Extract a validated public HTTPS origin from one cpolar log line. */\nexport function parseCpolarOrigin(line: string): string | undefined {\n  if (!line.includes('Tunnel established at ')) return undefined\n  const match = /Tunnel established at (https:\\/\\/[^\"\\s]+)/u.exec(line)\n  if (match === null) return undefined\n  let url: URL\n  try { url = new URL(match[1]!) } catch { throw new Error('invalid_cpolar_origin') }\n  if (url.protocol !== 'https:' || url.port !== '' || !isCpolarHost(url.hostname)\n    || url.pathname !== '/' || url.search !== '' || url.hash !== ''\n    || url.username !== '' || url.password !== '') throw new Error('invalid_cpolar_origin')\n  return url.origin\n}\n\nasync function reserveLoopbackPort(): Promise<PortReservation> {\n  const server: Server = createServer(socket => { socket.destroy() })\n  await new Promise<void>((resolveListen, reject) => {\n    server.once('error', reject)\n    server.listen(0, '127.0.0.1', () => {\n      server.off('error', reject)\n      resolveListen()\n    })\n  })\n  const address = server.address()\n  if (address === null || typeof address === 'string') {\n    server.close()\n    throw new Error('cpolar_port_reservation_failed')\n  }\n  let released = false\n  return {\n    port: address.port,\n    release: async () => {\n      if (released) return\n      released = true\n      await new Promise<void>(resolveClose => { server.close(() => resolveClose()) })\n    },\n  }\n}\n\nfunction spawnCpolarProcess(\n  executable: string,\n  args: readonly string[],\n  environment: NodeJS.ProcessEnv,\n): ChildProcessWithoutNullStreams {\n  return spawn(executable, [...args], {\n    env: environment,\n    shell: false,\n    stdio: ['pipe', 'pipe', 'pipe'],\n    windowsHide: true,\n  })\n}\n\nfunction withoutProxyEnvironment(environment: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n  const blocked = new Set(['HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY', 'NO_PROXY'])\n  return Object.fromEntries(Object.entries(environment).filter(([name]) => !blocked.has(name.toUpperCase())))\n}\n\n/** Owns an installed cpolar client and a provider-specific DSH remote gateway. */\nexport class CpolarController implements RemoteProviderController {\n  private enabled = false\n  private initialized = false\n  private disposed = false\n  private child: ChildProcessWithoutNullStreams | undefined\n  private gatewayValue: MobileAccessGateway | undefined\n  private reservation: PortReservation | undefined\n  private generation = 0\n  private buffer = ''\n  private latest: CpolarStatus = publicStatus({ enabled: false, state: 'off' })\n  private queue: Promise<void> = Promise.resolve()\n  private startupTimer: NodeJS.Timeout | undefined\n\n  constructor(private readonly options: CpolarControllerOptions) {\n    if (!isAbsolute(options.executable) || !isAbsolute(options.configFile)) {\n      throw new Error('cpolar paths must be absolute')\n    }\n    if (options.region !== undefined && !/^[a-z][a-z0-9_]{0,31}$/u.test(options.region)) {\n      throw new Error('cpolar region is invalid')\n    }\n  }\n\n  /** Restore the remembered cpolar switch independently from LAN and Funnel state. */\n  async initialize(initialState?: MobileAccessControlState): Promise<void> {\n    const state = initialState ?? await this.options.store.load()\n    this.enabled = state.enabled\n    this.initialized = true\n    if (this.enabled) await this.start()\n    else this.publish({ enabled: false, state: 'off' })\n  }\n\n  /** Return the active cpolar-backed DSH gateway. */\n  gateway(): MobileAccessGateway | undefined {\n    return this.gatewayValue\n  }\n\n  /** Return state safe for the desktop control UI. */\n  status(): CpolarStatus {\n    return publicStatus(this.latest)\n  }\n\n  /** Enable or disable cpolar without changing LAN or Tailscale state. */\n  async setEnabled(enabled: boolean): Promise<CpolarStatus> {\n    if (!this.initialized || this.disposed) throw new Error('cpolar controller is unavailable')\n    await this.enqueue(async () => {\n      if (this.enabled === enabled && (enabled === false || this.child !== undefined)) return\n      await this.options.store.save({ version: 1, enabled })\n      this.enabled = enabled\n      if (!enabled) await this.stop()\n      if (enabled) await this.start()\n      else this.publish({ enabled: false, state: 'off' })\n    })\n    return this.status()\n  }\n\n  /** Restart cpolar while retaining its account configuration and DSH device store. */\n  async reconnect(): Promise<CpolarStatus> {\n    if (!this.initialized || this.disposed) throw new Error('cpolar controller is unavailable')\n    await this.enqueue(async () => {\n      if (!this.enabled) {\n        await this.options.store.save({ version: 1, enabled: true })\n        this.enabled = true\n      }\n      await this.stop()\n      await this.start()\n    })\n    return this.status()\n  }\n\n  /** Disable cpolar without modifying the user's cpolar account or global tunnels. */\n  async reset(): Promise<CpolarStatus> {\n    if (!this.initialized || this.disposed) throw new Error('cpolar controller is unavailable')\n    await this.enqueue(async () => {\n      await this.options.store.save({ version: 1, enabled: false })\n      this.enabled = false\n      await this.stop()\n      this.publish({ enabled: false, state: 'off' })\n    })\n    return this.status()\n  }\n\n  /** Stop owned resources without changing the remembered switch. */\n  async close(): Promise<void> {\n    if (this.disposed) return\n    this.disposed = true\n    await this.enqueue(() => this.stop())\n  }\n\n  private enqueue(operation: () => Promise<void>): Promise<void> {\n    const task = this.queue.then(operation, operation)\n    this.queue = task.then(() => undefined, () => undefined)\n    return task\n  }\n\n  private publish(status: CpolarStatus): void {\n    this.latest = publicStatus(status)\n    try { this.options.onStatus?.(this.status()) } catch { /* UI observation cannot own runtime state. */ }\n  }\n\n  private async start(): Promise<void> {\n    const generation = ++this.generation\n    let executableEntry\n    try { executableEntry = await lstat(this.options.executable) } catch {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'cpolar_component_missing' })\n      return\n    }\n    if (!executableEntry.isFile() || executableEntry.isSymbolicLink()) {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'cpolar_component_invalid' })\n      return\n    }\n    let configEntry\n    try { configEntry = await lstat(this.options.configFile) } catch {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'cpolar_config_missing' })\n      return\n    }\n    if (!configEntry.isFile() || configEntry.isSymbolicLink()) {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'cpolar_config_invalid' })\n      return\n    }\n\n    let reservation: PortReservation\n    try { reservation = await reserveLoopbackPort() } catch {\n      this.publish({ enabled: true, state: 'error', errorCode: 'cpolar_port_unavailable' })\n      return\n    }\n    this.reservation = reservation\n    this.buffer = ''\n    this.publish({ enabled: true, state: 'starting' })\n    const args = [\n      'http',\n      `-config=${resolve(this.options.configFile)}`,\n      ...(this.options.region === undefined ? [] : [`-region=${this.options.region}`]),\n      '-inspect-addr=false',\n      '-redirect-https=true',\n      '-log=stdout',\n      '-log-level=INFO',\n      String(reservation.port),\n    ]\n    const child = (this.options.spawnProcess ?? spawnCpolarProcess)(\n      this.options.executable,\n      args,\n      withoutProxyEnvironment(process.env),\n    )\n    this.child = child\n    child.stdout.setEncoding('utf8')\n    child.stderr.setEncoding('utf8')\n    child.stdout.on('data', chunk => { this.consume(generation, String(chunk)) })\n    child.stderr.on('data', chunk => { this.consume(generation, String(chunk)) })\n    child.once('error', () => { void this.enqueue(() => this.failGeneration(generation, 'cpolar_launch_failed')) })\n    child.once('close', code => {\n      if (generation !== this.generation || this.child !== child) return\n      this.child = undefined\n      if (this.enabled) void this.enqueue(() => this.failGeneration(generation, code === 0 ? 'cpolar_stopped' : 'cpolar_exited'))\n    })\n    this.startupTimer = setTimeout(() => {\n      void this.enqueue(() => this.failGeneration(generation, 'cpolar_start_timeout'))\n    }, START_TIMEOUT_MS)\n    this.startupTimer.unref()\n  }\n\n  private consume(generation: number, chunk: string): void {\n    if (generation !== this.generation) return\n    this.buffer += chunk\n    if (Buffer.byteLength(this.buffer, 'utf8') > MAX_LOG_BUFFER_BYTES && !this.buffer.includes('\\n')) {\n      void this.enqueue(() => this.failGeneration(generation, 'cpolar_invalid_output'))\n      return\n    }\n    while (true) {\n      const newline = this.buffer.indexOf('\\n')\n      if (newline < 0) return\n      const line = this.buffer.slice(0, newline).replace(/\\r$/u, '')\n      this.buffer = this.buffer.slice(newline + 1)\n      let origin: string | undefined\n      try { origin = parseCpolarOrigin(line) } catch {\n        void this.enqueue(() => this.failGeneration(generation, 'cpolar_invalid_origin'))\n        return\n      }\n      if (origin !== undefined) void this.enqueue(() => this.attachGateway(generation, origin))\n    }\n  }\n\n  private async attachGateway(generation: number, origin: string): Promise<void> {\n    if (generation !== this.generation || !this.enabled || this.disposed) return\n    const current = this.gatewayValue\n    if (current !== undefined) {\n      if (current.address().origin === origin) return\n      await this.rotateGateway(generation, origin, current)\n      return\n    }\n    const reservation = this.reservation\n    if (reservation === undefined) return\n    this.publish({ enabled: true, state: 'connecting', origin })\n    await reservation.release()\n    if (this.reservation === reservation) this.reservation = undefined\n    let gateway: MobileAccessGateway\n    try { gateway = await this.options.createGateway(origin, reservation.port) } catch {\n      await this.failGeneration(generation, 'gateway_start_failed')\n      return\n    }\n    if (generation !== this.generation || !this.enabled || this.disposed || this.child === undefined) {\n      await gateway.close()\n      return\n    }\n    this.gatewayValue = gateway\n    if (this.startupTimer !== undefined) clearTimeout(this.startupTimer)\n    this.startupTimer = undefined\n    this.publish({ enabled: true, state: 'ready', origin })\n  }\n\n  /** Replace the gateway authority when cpolar rotates a temporary public origin. */\n  private async rotateGateway(\n    generation: number,\n    origin: string,\n    current: MobileAccessGateway,\n  ): Promise<void> {\n    const listenPort = current.address().port\n    // A replacement must bind the same port cpolar already forwards to. Stop\n    // exposing the closing instance before releasing that port.\n    if (this.gatewayValue === current) this.gatewayValue = undefined\n    this.publish({ enabled: true, state: 'connecting', origin })\n    try {\n      await current.close()\n    } catch {\n      await this.failGeneration(generation, 'gateway_start_failed')\n      return\n    }\n    if (generation !== this.generation || !this.enabled || this.disposed || this.child === undefined) return\n\n    let replacement: MobileAccessGateway\n    try { replacement = await this.options.createGateway(origin, listenPort) } catch {\n      await this.failGeneration(generation, 'gateway_start_failed')\n      return\n    }\n    if (generation !== this.generation || !this.enabled || this.disposed || this.child === undefined) {\n      await replacement.close()\n      return\n    }\n    this.gatewayValue = replacement\n    this.publish({ enabled: true, state: 'ready', origin })\n  }\n\n  private async failGeneration(generation: number, code: string): Promise<void> {\n    if (generation !== this.generation) return\n    await this.stopProcessAndGateway()\n    if (this.enabled) this.publish({ enabled: true, state: 'error', errorCode: code })\n  }\n\n  private async stop(): Promise<void> {\n    ++this.generation\n    await this.stopProcessAndGateway()\n  }\n\n  private async stopProcessAndGateway(): Promise<void> {\n    if (this.startupTimer !== undefined) clearTimeout(this.startupTimer)\n    this.startupTimer = undefined\n    const reservation = this.reservation\n    this.reservation = undefined\n    const child = this.child\n    this.child = undefined\n    const gateway = this.gatewayValue\n    this.gatewayValue = undefined\n    await settleRemoteResources([\n      () => reservation?.release(),\n      () => child !== undefined && child.exitCode === null ? terminateRemoteProcess(child) : undefined,\n      () => gateway?.close(),\n    ], 'cpolar resource cleanup failed')\n  }\n}\n","import { assertManagedParents, ensureManagedDirectory, removeManagedTree, renameManagedPath, writeManagedPrivateFile } from './managed-files.js'\n\n/** Refuse link-shaped ancestors within Caddy's owned state root. */\nexport async function assertCaddyParents(root: string, target: string): Promise<void> {\n  await assertManagedParents(root, target, 'caddy')\n}\n\n/** Move a Caddy-owned path, preserving bounded Windows retries and ownership checks. */\nexport async function renameCaddyPath(root: string, source: string, destination: string): Promise<void> {\n  await renameManagedPath(root, source, destination, 'caddy')\n}\n\n/** Create a real Caddy directory, securing fresh directories and preserving existing ACLs. */\nexport async function ensureCaddyDirectory(root: string, directory: string): Promise<void> {\n  await ensureManagedDirectory(root, directory, 'caddy')\n}\n\n/** Atomically replace one private Caddy configuration file. */\nexport async function writeCaddyPrivateFile(root: string, file: string, body: string): Promise<void> {\n  await writeManagedPrivateFile(root, file, body, 'caddy')\n}\n\n/** Delete only Caddy-owned children; unlink junctions and symlinks themselves. */\nexport async function removeCaddyTree(root: string, target: string): Promise<void> {\n  await removeManagedTree(root, target, 'caddy')\n}\n","import { createHash, randomBytes } from 'node:crypto'\nimport { chmod, lstat, mkdtemp, readFile, writeFile } from 'node:fs/promises'\nimport { isAbsolute, join, resolve } from 'node:path'\nimport { assertCaddyParents, ensureCaddyDirectory, removeCaddyTree, renameCaddyPath } from './caddy-files.js'\nimport { downloadPinnedArtifact } from './component-download.js'\nimport { execFileText } from './exec-file.js'\n\nexport const CADDY_VERSION = '2.11.6'\nexport const CADDY_DNS_PLUGIN_VERSION = 'v0.4.3'\nexport const CADDY_DOWNLOAD_PAGE = 'https://caddyserver.com/download'\n\n/** An immutable release asset with independent wire and installed-byte checks. */\nexport interface CaddyArtifact {\n  readonly version: string\n  readonly platform: NodeJS.Platform\n  readonly arch: string\n  readonly downloadUrl: string\n  readonly downloadBytes: number\n  readonly downloadSha256: string\n  readonly executableName: string\n  readonly executableBytes: number\n  readonly executableSha256: string\n  readonly dnsPluginVersion: string\n}\n\n// The custom-download service returned v2.11.7 when v2.11.6 was requested.\n// Production installation stays disabled until immutable assets have been published and verified.\nexport const CADDY_COMPONENT_RELEASES: Readonly<Record<string, CaddyArtifact>> = Object.freeze({})\nexport const CADDY_COMPONENT_RELEASE = Object.freeze({ version: CADDY_VERSION, dnsPluginVersion: CADDY_DNS_PLUGIN_VERSION })\nexport type CaddyDnsProvider = 'tencentcloud'\n\nexport function isCaddyDnsProvider(value: unknown): value is CaddyDnsProvider { return value === 'tencentcloud' }\n\nexport interface CaddyComponentStatus {\n  readonly supported: boolean\n  readonly installed: boolean\n  readonly version: string\n  readonly downloadBytes: number\n  readonly installedBytes: number\n  readonly sourceUrl: string\n  readonly downloadPage: string\n  readonly storagePath: string\n  readonly errorCode?: string\n}\n\ninterface CaddyComponentManagerOptions {\n  readonly stateDirectory: string\n  readonly platform?: NodeJS.Platform\n  readonly arch?: string\n  /** Instance-local artifact metadata for tests or a verified immutable release. */\n  readonly artifact?: CaddyArtifact\n  readonly fetchArtifact?: (url: string, signal: AbortSignal) => Promise<Uint8Array>\n  readonly inspectExecutable?: (executable: string) => Promise<{ version: string; modules: string }>\n  readonly promoteDirectory?: (source: string, destination: string) => Promise<void>\n}\n\nasync function digest(file: string): Promise<string> { return createHash('sha256').update(await readFile(file)).digest('hex') }\n\n/** Minimal process environment for version/module checks, without ambient API credentials or proxy overrides. */\nexport function caddyInspectionEnvironment(environment: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {\n  const result: NodeJS.ProcessEnv = {}\n  for (const name of ['SystemRoot', 'WINDIR', 'TEMP', 'TMP', 'LANG', 'LC_ALL']) {\n    if (environment[name] !== undefined) result[name] = environment[name]\n  }\n  return result\n}\n\nasync function inspect(executable: string): Promise<{ version: string; modules: string }> {\n  const options = { env: caddyInspectionEnvironment(), timeout: 15_000, maxBuffer: 256 * 1024 }\n  const version = (await execFileText(executable, ['version'], options)).stdout.trim()\n  const modules = (await execFileText(executable, ['list-modules', '--versions'], options)).stdout\n  return { version, modules }\n}\n\n/** Owns only the optional pinned executable; runtime configuration belongs to CaddyConfigStore. */\nexport class CaddyComponentManager {\n  readonly executable: string\n  readonly componentRoot: string\n  readonly componentStorage: string\n  readonly logRoot: string\n  private readonly stateDirectory: string\n  private readonly stagingRoot: string\n  private readonly artifact: CaddyArtifact | undefined\n  private readonly fetchArtifact: (url: string, signal: AbortSignal) => Promise<Uint8Array>\n  private readonly inspectExecutable: (executable: string) => Promise<{ version: string; modules: string }>\n  private readonly promote: (source: string, destination: string) => Promise<void>\n  private installed = false\n  private errorCode: string | undefined\n  private queue: Promise<void> = Promise.resolve()\n\n  constructor(options: CaddyComponentManagerOptions) {\n    if (!isAbsolute(options.stateDirectory)) throw new Error('caddy state directory must be absolute')\n    this.stateDirectory = resolve(options.stateDirectory)\n    const platform = options.platform ?? process.platform\n    const arch = options.arch ?? process.arch\n    const artifact = options.artifact ?? CADDY_COMPONENT_RELEASES[`${platform}-${arch}`]\n    if (artifact !== undefined && (artifact.platform !== platform || artifact.arch !== arch\n      || !/^https:\\/\\//u.test(artifact.downloadUrl) || !/^[a-f0-9]{64}$/u.test(artifact.downloadSha256)\n      || !/^[a-f0-9]{64}$/u.test(artifact.executableSha256) || artifact.downloadBytes < 1 || artifact.executableBytes < 1\n      || !/^[a-z0-9.-]+$/u.test(artifact.executableName))) throw new Error('caddy_artifact_invalid')\n    this.artifact = artifact\n    this.componentRoot = join(this.stateDirectory, 'components', 'caddy')\n    this.componentStorage = join(this.componentRoot, artifact?.version ?? CADDY_VERSION)\n    this.executable = join(this.componentStorage, artifact?.executableName ?? (platform === 'win32' ? 'caddy.exe' : 'caddy'))\n    this.logRoot = join(this.stateDirectory, 'caddy', 'logs')\n    this.stagingRoot = join(this.stateDirectory, 'staging', 'caddy')\n    this.fetchArtifact = options.fetchArtifact ?? ((url, signal) => downloadPinnedArtifact({ url, signal, expectedBytes: artifact?.downloadBytes ?? 0, errorPrefix: 'caddy' }))\n    this.inspectExecutable = options.inspectExecutable ?? inspect\n    this.promote = options.promoteDirectory ?? ((source, destination) => renameCaddyPath(this.stateDirectory, source, destination))\n  }\n\n  /** Recheck a pinned executable before launching; no unverified local binary can run. */\n  async ensureExecutable(): Promise<void> {\n    const artifact = this.artifact\n    if (artifact === undefined) throw new Error('caddy_component_unavailable')\n    await assertCaddyParents(this.stateDirectory, this.executable)\n    const entry = await lstat(this.executable)\n    if (!entry.isFile() || entry.isSymbolicLink() || entry.size !== artifact.executableBytes\n      || await digest(this.executable) !== artifact.executableSha256) throw new Error('caddy_component_invalid')\n    await this.verifyMetadata(this.executable, artifact)\n  }\n\n  async initialize(): Promise<void> {\n    this.installed = false; this.errorCode = undefined\n    if (this.artifact === undefined) { this.errorCode = 'caddy_component_unavailable'; return }\n    try { await this.ensureExecutable(); this.installed = true } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') this.errorCode = 'caddy_component_invalid'\n    }\n  }\n\n  status(): CaddyComponentStatus {\n    const artifact = this.artifact\n    return Object.freeze({ supported: artifact !== undefined, installed: this.installed,\n      version: artifact?.version ?? CADDY_VERSION, downloadBytes: artifact?.downloadBytes ?? 0,\n      installedBytes: this.installed ? artifact?.executableBytes ?? 0 : 0,\n      sourceUrl: artifact?.downloadUrl ?? CADDY_DOWNLOAD_PAGE, downloadPage: CADDY_DOWNLOAD_PAGE, storagePath: this.componentRoot,\n      ...(this.errorCode === undefined ? {} : { errorCode: this.errorCode }),\n    })\n  }\n\n  /** Explicit installation verifies bytes and reported modules before preserving-old promotion. */\n  install(): Promise<CaddyComponentStatus> {\n    return this.enqueue(async () => {\n      const artifact = this.artifact\n      if (artifact === undefined) throw new Error('caddy_component_unavailable')\n      await ensureCaddyDirectory(this.stateDirectory, this.stagingRoot)\n      await ensureCaddyDirectory(this.stateDirectory, this.componentRoot)\n      const staging = await mkdtemp(join(this.stagingRoot, 'install-'))\n      const candidate = join(this.componentRoot, '.install-' + randomBytes(12).toString('hex'))\n      const backup = join(this.componentRoot, '.previous-' + randomBytes(12).toString('hex'))\n      let previous = false\n      let promoted = false\n      let failed = false\n      try {\n        const controller = new AbortController()\n        const timeout = setTimeout(() => { controller.abort() }, 600_000)\n        timeout.unref()\n        let bytes: Uint8Array\n        try { bytes = await this.fetchArtifact(artifact.downloadUrl, controller.signal) } finally { clearTimeout(timeout) }\n        if (bytes.byteLength !== artifact.downloadBytes) throw new Error('caddy_download_size_mismatch')\n        if (createHash('sha256').update(bytes).digest('hex') !== artifact.downloadSha256) throw new Error('caddy_download_hash_mismatch')\n        await ensureCaddyDirectory(this.stateDirectory, candidate)\n        const executable = join(candidate, artifact.executableName)\n        await writeFile(executable, bytes, { flag: 'wx', mode: 0o700 })\n        await chmod(executable, 0o700)\n        if (bytes.byteLength !== artifact.executableBytes || await digest(executable) !== artifact.executableSha256) throw new Error('caddy_executable_hash_mismatch')\n        await this.verifyMetadata(executable, artifact)\n        try {\n          const entry = await lstat(this.componentStorage)\n          if (!entry.isDirectory() || entry.isSymbolicLink()) throw new Error('caddy_path_invalid')\n          await renameCaddyPath(this.stateDirectory, this.componentStorage, backup); previous = true\n        } catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error }\n        try { await this.promote(candidate, this.componentStorage); promoted = true } catch (error) {\n          if (previous) {\n            try { await renameCaddyPath(this.stateDirectory, backup, this.componentStorage); previous = false } catch (rollbackError) {\n              this.installed = false; this.errorCode = 'caddy_component_invalid'\n              // Keep the only old bytes in backup and expose both failures without claiming a usable installation.\n              throw new AggregateError([error, rollbackError], 'caddy_component_rollback_failed', { cause: error })\n            }\n          }\n          throw error\n        }\n        this.installed = true; this.errorCode = undefined\n      } catch (error) { failed = true; throw error } finally {\n        // A busy cleanup must not replace the original verification/promotion error.\n        let cleanupError: unknown\n        for (const path of [staging, candidate, ...(previous && promoted ? [backup] : [])]) {\n          try { await removeCaddyTree(this.stateDirectory, path) } catch (error) { cleanupError ??= error }\n        }\n        if (!failed && cleanupError !== undefined) throw cleanupError\n      }\n    })\n  }\n\n  /** Remove optional component files; callers stop the controller and purge runtime configuration separately. */\n  purge(): Promise<CaddyComponentStatus> {\n    return this.enqueue(async () => {\n      await removeCaddyTree(this.stateDirectory, this.componentRoot)\n      await removeCaddyTree(this.stateDirectory, this.stagingRoot)\n      this.installed = false; this.errorCode = this.artifact === undefined ? 'caddy_component_unavailable' : undefined\n    })\n  }\n\n  private async verifyMetadata(executable: string, artifact: CaddyArtifact): Promise<void> {\n    const info = await this.inspectExecutable(executable)\n    if (!info.version.startsWith('v' + artifact.version + ' ')) throw new Error('caddy_executable_version_mismatch')\n    const nonstandard = info.modules.split(/\\r?\\n/u).filter(line => line.startsWith('dns.providers.'))\n    if (nonstandard.length !== 1 || nonstandard[0] !== 'dns.providers.tencentcloud ' + artifact.dnsPluginVersion\n      || !info.modules.includes('Non-standard modules: 1')) throw new Error('caddy_executable_modules_mismatch')\n  }\n\n  private enqueue(operation: () => Promise<void>): Promise<CaddyComponentStatus> {\n    const task = this.queue.then(operation, operation)\n    this.queue = task.then(() => undefined, () => undefined)\n    return task.then(() => this.status())\n  }\n}\n","import { lstat, readFile } from 'node:fs/promises'\nimport { isAbsolute, join, resolve } from 'node:path'\nimport { assertCaddyParents, ensureCaddyDirectory, removeCaddyTree, writeCaddyPrivateFile } from './caddy-files.js'\nimport { isCaddyDnsProvider, type CaddyDnsProvider } from './caddy-component.js'\nimport { validateOriginPublicOrigin } from './origin-proxy-config.js'\nimport { isIP } from './ip.js'\nimport { restrictPrivateFile } from './private-file.js'\n\nexport const DEFAULT_CADDY_LISTEN_PORT = 8443\nconst MAX_CONFIG_BYTES = 16 * 1024\n\n/** Public HTTPS address and local TLS listener; a router may map their ports differently. */\nexport interface CaddySettings {\n  readonly version: 1\n  readonly publicOrigin: string\n  readonly dnsProvider: CaddyDnsProvider\n  readonly listenPort: number\n}\n\n/** DNS-01 credentials persisted only in the private authoritative configuration file. */\nexport interface CaddyCredentials { readonly secretId: string; readonly secretKey: string }\n\nexport interface CaddyConfigurationStatus {\n  readonly configured: boolean\n  readonly credentialsConfigured: boolean\n  readonly storagePath: string\n  readonly publicOrigin?: string\n  readonly dnsProvider?: CaddyDnsProvider\n  readonly listenPort?: number\n  readonly errorCode?: string\n}\n\n/** Inject only the DNS credentials needed by the managed child. */\nexport function caddyCredentialEnvironment(provider: CaddyDnsProvider, credentials: CaddyCredentials): Record<string, string> {\n  if (!isCaddyDnsProvider(provider)) throw new Error('caddy_dns_provider_invalid')\n  return { TENCENTCLOUD_SECRET_ID: credentials.secretId, TENCENTCLOUD_SECRET_KEY: credentials.secretKey }\n}\n\n/** Validate saved or administrative settings, including ports reserved by DSH. */\nexport function parseCaddySettings(value: unknown): CaddySettings {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('caddy_settings_invalid')\n  const record = value as Record<string, unknown>\n  if (Reflect.ownKeys(record).some(key => !['version', 'publicOrigin', 'dnsProvider', 'listenPort'].includes(String(key)))\n    || (record.version !== undefined && record.version !== 1)) throw new Error('caddy_settings_invalid')\n  if (!isCaddyDnsProvider(record.dnsProvider)) throw new Error('caddy_dns_provider_invalid')\n  const listenPort = record.listenPort ?? DEFAULT_CADDY_LISTEN_PORT\n  if (!Number.isSafeInteger(listenPort) || Number(listenPort) < 1024 || Number(listenPort) > 65535) throw new Error('caddy_listen_port_invalid')\n  if ([3444, 3443, 3080].includes(Number(listenPort))) throw new Error('caddy_listen_port_reserved')\n  const publicOrigin = validateOriginPublicOrigin(record.publicOrigin)\n  if (isIP(new URL(publicOrigin).hostname) !== 0) throw new Error('caddy_domain_required')\n  return Object.freeze({ version: 1, publicOrigin, dnsProvider: record.dnsProvider, listenPort: Number(listenPort) })\n}\n\nfunction parseCredentials(value: unknown): CaddyCredentials {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('caddy_credentials_invalid')\n  const record = value as Record<string, unknown>\n  if (Reflect.ownKeys(record).some(key => key !== 'secretId' && key !== 'secretKey')) throw new Error('caddy_credentials_invalid')\n  const { secretId, secretKey } = record\n  if (typeof secretId !== 'string' || typeof secretKey !== 'string' || secretId.length === 0 || secretKey.length === 0\n    || secretId.length > 512 || secretKey.length > 512 || /[\\s\\u0000-\\u001f\\u007f]/u.test(secretId + secretKey)) throw new Error('caddy_credentials_invalid')\n  return Object.freeze({ secretId, secretKey })\n}\n\n/** Render a single TLS site, with no admin API, config autosave, or embedded DNS secrets. */\nexport function renderCaddyfile(settings: CaddySettings, stateDirectory: string, backendPort = 3444): string {\n  const validated = parseCaddySettings(settings)\n  if (!Number.isSafeInteger(backendPort) || backendPort < 1 || backendPort > 65535) throw new Error('caddy_backend_port_invalid')\n  const root = resolve(stateDirectory, 'caddy')\n  const dataDirectory = join(root, 'data').replaceAll('\\\\', '/')\n  const hostname = new URL(validated.publicOrigin).hostname\n  return [\n    '{', '\\tadmin off', '\\tpersist_config off', '\\tauto_https disable_redirects',\n    `\\tstorage file_system ${JSON.stringify(dataDirectory)}`,\n    // DNS module errors can contain provider response details; raw child logs are not persisted.\n    '\\tlog {', '\\t\\toutput discard', '\\t}', '}', '',\n    `https://${hostname}:${String(validated.listenPort)} {`, '\\ttls {', '\\t\\tdns tencentcloud {',\n    '\\t\\t\\tsecret_id {env.TENCENTCLOUD_SECRET_ID}', '\\t\\t\\tsecret_key {env.TENCENTCLOUD_SECRET_KEY}', '\\t\\t}', '\\t}',\n    `\\treverse_proxy 127.0.0.1:${String(backendPort)} {`,\n    '\\t\\theader_up Host {http.request.hostport}', '\\t\\ttransport http {', '\\t\\t\\tkeepalive off', '\\t\\t\\tdial_timeout 5s', '\\t\\t}', '\\t}', '}', '',\n  ].join('\\n')\n}\n\n/** Owns one atomic configuration record and every Caddy-created private file. */\nexport class CaddyConfigStore {\n  readonly rootDirectory: string\n  readonly settingsFile: string\n  readonly envFile: string\n  readonly caddyfile: string\n  readonly dataDirectory: string\n  readonly configDirectory: string\n  readonly logsDirectory: string\n  private settingsValue: CaddySettings | undefined\n  private credentialsValue: CaddyCredentials | undefined\n  private errorCodeValue: string | undefined\n  private queue: Promise<void> = Promise.resolve()\n\n  constructor(private readonly stateDirectory: string) {\n    if (!isAbsolute(stateDirectory)) throw new Error('caddy config state directory must be absolute')\n    this.rootDirectory = resolve(stateDirectory, 'caddy')\n    this.settingsFile = join(this.rootDirectory, 'config.json')\n    this.envFile = this.settingsFile\n    this.caddyfile = join(this.rootDirectory, 'Caddyfile')\n    this.dataDirectory = join(this.rootDirectory, 'data')\n    this.configDirectory = join(this.rootDirectory, 'xdg-config')\n    this.logsDirectory = join(this.rootDirectory, 'logs')\n  }\n\n  settings(): CaddySettings | undefined { return this.settingsValue }\n  credentials(): CaddyCredentials | undefined { return this.credentialsValue }\n  errorCode(): string | undefined { return this.errorCodeValue }\n\n  status(): CaddyConfigurationStatus {\n    const settings = this.settingsValue\n    return Object.freeze({ configured: settings !== undefined && this.credentialsValue !== undefined, credentialsConfigured: this.credentialsValue !== undefined,\n      storagePath: this.rootDirectory,\n      ...(settings === undefined ? {} : { publicOrigin: settings.publicOrigin, listenPort: settings.listenPort, dnsProvider: settings.dnsProvider }),\n      ...(this.errorCodeValue === undefined ? {} : { errorCode: this.errorCodeValue }),\n    })\n  }\n\n  async initialize(): Promise<void> {\n    await this.enqueue(async () => {\n      this.settingsValue = undefined; this.credentialsValue = undefined; this.errorCodeValue = undefined\n      await assertCaddyParents(this.stateDirectory, this.settingsFile)\n      let entry\n      try { entry = await lstat(this.settingsFile) } catch (error) {\n        if ((error as NodeJS.ErrnoException).code === 'ENOENT') return\n        throw error\n      }\n      if (!entry.isFile() || entry.isSymbolicLink() || entry.size > MAX_CONFIG_BYTES) { this.errorCodeValue = 'caddy_config_invalid'; return }\n      await restrictPrivateFile(this.settingsFile)\n      try {\n        const record: unknown = JSON.parse(await readFile(this.settingsFile, 'utf8'))\n        if (typeof record !== 'object' || record === null || Array.isArray(record)) throw new Error('invalid')\n        const values = record as Record<string, unknown>\n        if (Reflect.ownKeys(values).some(key => key !== 'settings' && key !== 'credentials')) throw new Error('invalid')\n        const settings = parseCaddySettings(values.settings)\n        const credentials = parseCredentials(values.credentials)\n        this.settingsValue = settings; this.credentialsValue = credentials\n      } catch { this.errorCodeValue = 'caddy_config_invalid' }\n    })\n  }\n\n  /** Atomically save validated settings and credentials; omitted or both-blank secrets retain saved ones. */\n  configure(value: unknown, credentialInput?: unknown): Promise<void> {\n    return this.enqueue(async () => {\n      const settings = parseCaddySettings(value)\n      const blank = typeof credentialInput === 'object' && credentialInput !== null && !Array.isArray(credentialInput)\n        && (credentialInput as Record<string, unknown>).secretId === '' && (credentialInput as Record<string, unknown>).secretKey === ''\n        && Reflect.ownKeys(credentialInput).every(key => key === 'secretId' || key === 'secretKey')\n      const credentials = credentialInput === undefined || blank ? this.credentialsValue : parseCredentials(credentialInput)\n      if (credentials === undefined) throw new Error('caddy_credentials_missing')\n      await writeCaddyPrivateFile(this.stateDirectory, this.settingsFile, JSON.stringify({ settings, credentials }) + '\\n')\n      this.settingsValue = settings; this.credentialsValue = credentials; this.errorCodeValue = undefined\n    })\n  }\n\n  /** Write derived runtime files after authoritative settings are available. */\n  prepareCaddyfile(backendPort: number): Promise<void> {\n    return this.enqueue(async () => {\n      const settings = this.settingsValue\n      if (settings === undefined || this.credentialsValue === undefined) throw new Error('caddy_config_missing')\n      for (const directory of [this.dataDirectory, this.configDirectory, this.logsDirectory]) await ensureCaddyDirectory(this.stateDirectory, directory)\n      await writeCaddyPrivateFile(this.stateDirectory, this.caddyfile, renderCaddyfile(settings, this.stateDirectory, backendPort))\n    })\n  }\n\n  /** Remove credentials, certificates, private keys, configuration, logs, and runtime cache. */\n  purge(): Promise<void> {\n    return this.enqueue(async () => {\n      await removeCaddyTree(this.stateDirectory, this.rootDirectory)\n      this.settingsValue = undefined; this.credentialsValue = undefined; this.errorCodeValue = undefined\n    })\n  }\n\n  private enqueue(operation: () => Promise<void>): Promise<void> {\n    const task = this.queue.then(operation, operation)\n    this.queue = task.then(() => undefined, () => undefined)\n    return task\n  }\n}\n","import { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process'\nimport type { MobileAccessControlStore } from './control.js'\nimport type { MobileAccessGateway } from './gateway.js'\nimport type { CaddyComponentManager } from './caddy-component.js'\nimport { caddyInspectionEnvironment } from './caddy-component.js'\nimport { caddyCredentialEnvironment, type CaddyConfigStore, type CaddySettings } from './caddy-config.js'\nimport { execFileText } from './exec-file.js'\nimport { defaultProbeDiscovery } from './frp.js'\nimport { settleRemoteResources, terminateRemoteProcess, type RemoteProviderController } from './remote.js'\n\nexport type CaddyState = 'off' | 'unavailable' | 'starting' | 'ready' | 'error'\nexport interface CaddyStatus {\n  readonly enabled: boolean\n  readonly state: CaddyState\n  readonly origin?: string\n  readonly backendOrigin?: string\n  readonly errorCode?: string\n}\n\nexport interface CaddyControllerOptions {\n  readonly store: MobileAccessControlStore\n  readonly component: Pick<CaddyComponentManager, 'executable' | 'ensureExecutable' | 'status'>\n  readonly config: CaddyConfigStore\n  readonly instanceId: string\n  readonly createGateway: (settings: CaddySettings) => Promise<MobileAccessGateway>\n  readonly onStatus?: (status: CaddyStatus) => void\n  readonly startupTimeoutMs?: number\n  readonly probeIntervalMs?: number\n  readonly probeDiscovery?: (origin: string, expectedInstanceId: string, signal: AbortSignal) => Promise<boolean>\n  readonly validateConfig?: (executable: string, caddyfile: string, environment: NodeJS.ProcessEnv, signal: AbortSignal) => Promise<void>\n  readonly spawnProcess?: (executable: string, args: readonly string[], environment: NodeJS.ProcessEnv) => ChildProcessWithoutNullStreams\n  readonly terminateProcess?: (child: ChildProcessWithoutNullStreams) => Promise<void>\n}\n\n/** Private directories override Caddy's platform defaults; ambient API keys and admin/proxy overrides are omitted. */\nexport function caddyProcessEnvironment(config: CaddyConfigStore, settings: CaddySettings, environment: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {\n  const credentials = config.credentials()\n  if (credentials === undefined) throw new Error('caddy_credentials_missing')\n  return { ...caddyInspectionEnvironment(environment), ...caddyCredentialEnvironment(settings.dnsProvider, credentials),\n    HOME: config.rootDirectory, USERPROFILE: config.rootDirectory, APPDATA: config.configDirectory,\n    LOCALAPPDATA: config.dataDirectory, XDG_DATA_HOME: config.dataDirectory, XDG_CONFIG_HOME: config.configDirectory,\n  }\n}\n\nfunction spawnCaddy(executable: string, args: readonly string[], environment: NodeJS.ProcessEnv): ChildProcessWithoutNullStreams {\n  return spawn(executable, [...args], { env: environment, shell: false, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true })\n}\n\nasync function validate(executable: string, caddyfile: string, environment: NodeJS.ProcessEnv, signal: AbortSignal): Promise<void> {\n  try { await execFileText(executable, ['adapt', '--config', caddyfile, '--adapter', 'caddyfile'], {\n    env: environment, signal, timeout: 15_000, maxBuffer: 256 * 1024,\n  }) } catch { throw new Error('caddy_config_validation_failed') }\n}\n\n/** Owns Caddy and a loopback Gateway until both have stopped; ready requires verified public TLS and instance identity. */\nexport class CaddyController implements RemoteProviderController {\n  private enabled = false\n  private initialized = false\n  private disposed = false\n  private child: ChildProcessWithoutNullStreams | undefined\n  private gatewayValue: MobileAccessGateway | undefined\n  private generation = 0\n  private startupAbort: AbortController | undefined\n  private latest: CaddyStatus = Object.freeze({ enabled: false, state: 'off' })\n  private queue: Promise<void> = Promise.resolve()\n  private closeTask: Promise<void> | undefined\n\n  constructor(private readonly options: CaddyControllerOptions) {}\n\n  initialize(): Promise<void> {\n    return this.enqueue(async () => {\n      if (this.initialized) return\n      if (this.disposed) throw new Error('caddy_controller_unavailable')\n      this.enabled = (await this.options.store.load()).enabled\n      this.initialized = true\n      if (this.enabled) await this.start()\n    })\n  }\n\n  gateway(): MobileAccessGateway | undefined { return this.latest.state === 'ready' ? this.gatewayValue : undefined }\n  status(): CaddyStatus { return this.latest }\n  /** Cancel a readiness attempt before its owning coordinator waits for queued teardown. */\n  cancelPendingStart(): void { this.startupAbort?.abort() }\n\n  setEnabled(enabled: boolean): Promise<CaddyStatus> {\n    if (!enabled) this.startupAbort?.abort()\n    return this.enqueue(async () => {\n      this.assertAvailable()\n      if (this.enabled === enabled && (!enabled || this.latest.state === 'ready')) return\n      if (!enabled) await this.stop()\n      await this.options.store.save({ version: 1, enabled })\n      this.enabled = enabled\n      if (enabled) await this.start()\n      else this.publish({ enabled: false, state: 'off' })\n    }).then(() => this.status())\n  }\n\n  reconnect(): Promise<CaddyStatus> {\n    this.startupAbort?.abort()\n    return this.enqueue(async () => {\n      this.assertAvailable()\n      await this.stop()\n      await this.options.store.save({ version: 1, enabled: true })\n      this.enabled = true\n      await this.start()\n    }).then(() => this.status())\n  }\n\n  reset(): Promise<CaddyStatus> { return this.setEnabled(false) }\n\n  close(): Promise<void> {\n    this.disposed = true\n    this.startupAbort?.abort()\n    this.closeTask ??= this.enqueue(async () => { await this.stop(); this.publish({ enabled: this.enabled, state: 'off' }) })\n      .catch((error: unknown) => { this.closeTask = undefined; throw error })\n    return this.closeTask\n  }\n\n  private assertAvailable(): void { if (!this.initialized || this.disposed) throw new Error('caddy_controller_unavailable') }\n  private enqueue(operation: () => Promise<void>): Promise<void> {\n    const task = this.queue.then(operation, operation)\n    this.queue = task.then(() => undefined, () => undefined)\n    return task\n  }\n  private publish(status: CaddyStatus): void {\n    this.latest = Object.freeze(status)\n    try { this.options.onStatus?.(this.latest) } catch { /* Observers do not own process lifecycle. */ }\n  }\n\n  private async start(): Promise<void> {\n    const generation = ++this.generation\n    const startup = new AbortController()\n    this.startupAbort = startup\n    const settings = this.options.config.settings()\n    if (settings === undefined || this.options.config.credentials() === undefined) {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'caddy_config_missing' }); this.startupAbort = undefined; return\n    }\n    if (!this.options.component.status().supported) {\n      this.publish({ enabled: true, state: 'unavailable', errorCode: 'caddy_component_unavailable' }); this.startupAbort = undefined; return\n    }\n    this.publish({ enabled: true, state: 'starting', origin: settings.publicOrigin })\n    let childFailure: string | undefined\n    const deadline = setTimeout(() => { startup.abort() }, this.options.startupTimeoutMs ?? 120_000)\n    deadline.unref()\n    try {\n      await this.options.component.ensureExecutable()\n      if (startup.signal.aborted || this.disposed) throw new Error('caddy_start_cancelled')\n      const gateway = await this.options.createGateway(settings)\n      this.gatewayValue = gateway\n      if (startup.signal.aborted || this.disposed) throw new Error('caddy_start_cancelled')\n      await this.options.config.prepareCaddyfile(gateway.address().port)\n      const environment = caddyProcessEnvironment(this.options.config, settings)\n      await (this.options.validateConfig ?? validate)(this.options.component.executable, this.options.config.caddyfile, environment, startup.signal)\n      if (startup.signal.aborted || this.disposed) throw new Error('caddy_start_cancelled')\n      const child = (this.options.spawnProcess ?? spawnCaddy)(this.options.component.executable,\n        ['run', '--config', this.options.config.caddyfile, '--adapter', 'caddyfile'], environment)\n      this.child = child\n      // No provider response or DNS credentials enter DSH logs, and pipes cannot fill and stall the child.\n      child.stdout.resume(); child.stderr.resume(); child.stdin.end()\n      const failed = (code: string): void => {\n        if (generation !== this.generation || this.child !== child) return\n        childFailure = code\n        startup.abort()\n        if (this.latest.state === 'ready') {\n          void this.enqueue(async () => {\n            if (generation !== this.generation) return\n            await this.stop()\n            if (this.enabled && !this.disposed) this.publish({ enabled: true, state: 'error', errorCode: code })\n          }).catch(() => { this.publish({ enabled: this.enabled, state: 'error', errorCode: 'caddy_cleanup_failed' }) })\n        }\n      }\n      child.once('error', () => { failed('caddy_launch_failed') })\n      child.once('close', () => { failed('caddy_exited') })\n      const probe = this.options.probeDiscovery ?? ((origin, expected, signal) => defaultProbeDiscovery({ origin }, expected, signal))\n      while (true) {\n        if (startup.signal.aborted || this.disposed) throw new Error(childFailure ?? 'caddy_start_timeout')\n        let ready = false\n        try { ready = await probe(settings.publicOrigin, this.options.instanceId, startup.signal) } catch (error) {\n          if (error instanceof Error && (error.message === 'frp_discovery_mismatch' || error.message === 'frp_discovery_invalid')) {\n            throw new Error('caddy_public_identity_invalid')\n          }\n        }\n        if (startup.signal.aborted || this.disposed || generation !== this.generation) throw new Error(childFailure ?? 'caddy_start_timeout')\n        if (ready) break\n        await this.waitForProbe(startup.signal)\n      }\n      this.publish({ enabled: true, state: 'ready', origin: settings.publicOrigin, backendOrigin: 'http://127.0.0.1:' + String(gateway.address().port) })\n    } catch (error) {\n      // Intentional termination must not replace the startup failure with a child-close event.\n      ++this.generation\n      await this.stopResources()\n      if (!this.disposed) this.publish({ enabled: this.enabled, state: 'error', errorCode: childFailure\n        ?? (error instanceof Error && error.message.startsWith('caddy_') ? error.message\n          : (error as NodeJS.ErrnoException).code === 'EADDRINUSE' ? 'caddy_backend_port_in_use' : 'caddy_start_failed') })\n    } finally {\n      clearTimeout(deadline)\n      if (this.startupAbort === startup) this.startupAbort = undefined\n    }\n  }\n\n  private waitForProbe(signal: AbortSignal): Promise<void> {\n    if (signal.aborted) return Promise.resolve()\n    return new Promise(resolve => {\n      const done = (): void => { clearTimeout(timer); signal.removeEventListener('abort', done); resolve() }\n      const timer = setTimeout(done, this.options.probeIntervalMs ?? 1000)\n      timer.unref(); signal.addEventListener('abort', done, { once: true })\n    })\n  }\n  private async stop(): Promise<void> { ++this.generation; this.startupAbort?.abort(); await this.stopResources() }\n  private async stopResources(): Promise<void> {\n    const child = this.child\n    const gateway = this.gatewayValue\n    await settleRemoteResources([\n      async () => {\n        if (child !== undefined) {\n          await (this.options.terminateProcess ?? terminateRemoteProcess)(child)\n          if (this.child === child) this.child = undefined\n        }\n      },\n      async () => { if (gateway !== undefined) { await gateway.close(); if (this.gatewayValue === gateway) this.gatewayValue = undefined } },\n    ], 'caddy cleanup failed')\n  }\n}\n","import { lstat, readFile } from 'node:fs/promises'\nimport { dirname, isAbsolute } from 'node:path'\nimport type { MobileAccessControlState, MobileAccessControlStore } from './control.js'\nimport type { MobileAccessGateway } from './gateway.js'\nimport { assertCaddyParents, writeCaddyPrivateFile } from './caddy-files.js'\nimport { restrictPrivateFile } from './private-file.js'\nimport { settleRemoteResources, type RemoteProviderController, type RemoteProviderStatus } from './remote.js'\n\nexport type OriginUpstreamMode = 'external' | 'managed'\nexport interface OriginModeState { readonly version: 1; readonly mode: OriginUpstreamMode }\nexport interface OriginModeStore { load(): Promise<OriginModeState>; save(value: OriginModeState): Promise<void> }\n\n/** Children never independently restore a durable enabled switch. */\nexport function createVolatileRemoteControlStore(): MobileAccessControlStore {\n  let value: MobileAccessControlState = { version: 1, enabled: false }\n  return { load: async () => value, save: async state => { value = Object.freeze({ ...state }) } }\n}\n\nfunction parseMode(value: unknown): OriginModeState {\n  if (typeof value !== 'object' || value === null || Array.isArray(value)) throw new Error('origin_mode_invalid')\n  const record = value as Record<string, unknown>\n  if (record.version !== 1 || (record.mode !== 'external' && record.mode !== 'managed')\n    || Reflect.ownKeys(record).some(key => key !== 'version' && key !== 'mode')) throw new Error('origin_mode_invalid')\n  return Object.freeze({ version: 1, mode: record.mode })\n}\n\n/** Persist only origin's upstream mode, defaulting to the existing external-proxy behavior. */\nexport class JsonOriginModeStore implements OriginModeStore {\n  constructor(readonly file: string) { if (!isAbsolute(file)) throw new Error('origin mode file must be absolute') }\n  async load(): Promise<OriginModeState> {\n    await assertCaddyParents(dirname(this.file), this.file)\n    let entry\n    try { entry = await lstat(this.file) } catch (error) {\n      if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { version: 1, mode: 'external' }\n      throw error\n    }\n    if (!entry.isFile() || entry.isSymbolicLink() || entry.size > 1024) throw new Error('origin_mode_invalid')\n    await restrictPrivateFile(this.file)\n    return parseMode(JSON.parse(await readFile(this.file, 'utf8')))\n  }\n  async save(value: OriginModeState): Promise<void> {\n    await writeCaddyPrivateFile(dirname(this.file), this.file, JSON.stringify(parseMode(value)) + '\\n')\n  }\n}\n\nexport interface ManagedOriginStatus extends RemoteProviderStatus { readonly mode: OriginUpstreamMode }\nexport interface ManagedOriginControllerOptions {\n  readonly store: MobileAccessControlStore\n  readonly modeStore: OriginModeStore\n  readonly external: RemoteProviderController\n  readonly managed: RemoteProviderController & { cancelPendingStart?(): void }\n}\n\n/** One origin-provider owner selects exactly one upstream; external settings and shared device records remain untouched. */\nexport class ManagedOriginController implements RemoteProviderController {\n  private selected: OriginUpstreamMode = 'external'\n  private enabled = false\n  private initialized = false\n  private disposed = false\n  private queue: Promise<void> = Promise.resolve()\n  private closeTask: Promise<void> | undefined\n\n  constructor(private readonly options: ManagedOriginControllerOptions) {}\n  mode(): OriginUpstreamMode { return this.selected }\n  status(): ManagedOriginStatus { return Object.freeze({ ...this.controller().status(), enabled: this.enabled, mode: this.selected }) }\n  gateway(): MobileAccessGateway | undefined { return this.enabled ? this.controller().gateway() : undefined }\n\n  initialize(initialState?: MobileAccessControlState): Promise<void> {\n    return this.enqueue(async () => {\n      if (this.initialized) return\n      if (this.disposed) throw new Error('origin_controller_unavailable')\n      this.selected = (await this.options.modeStore.load()).mode\n      this.enabled = (initialState ?? await this.options.store.load()).enabled\n      await this.options.external.initialize()\n      await this.options.managed.initialize()\n      await this.options.external.setEnabled(false)\n      await this.options.managed.setEnabled(false)\n      this.initialized = true\n      if (this.enabled && !this.disposed) await this.controller().setEnabled(true)\n    })\n  }\n\n  selectMode(mode: OriginUpstreamMode): Promise<ManagedOriginStatus> {\n    if (mode !== this.selected) this.options.managed.cancelPendingStart?.()\n    return this.enqueue(async () => {\n      this.assertAvailable()\n      if (mode !== 'external' && mode !== 'managed') throw new Error('origin_mode_invalid')\n      if (mode === this.selected) return\n      const previous = this.controller()\n      await previous.setEnabled(false)\n      try { await this.options.modeStore.save({ version: 1, mode }) } catch (error) {\n        if (this.enabled && !this.disposed) await previous.setEnabled(true)\n        throw error\n      }\n      this.selected = mode\n      if (this.enabled && !this.disposed) {\n        try { await this.controller().setEnabled(true) } catch (error) {\n          await this.stopBoth()\n          throw error\n        }\n      }\n    }).then(() => this.status())\n  }\n\n  setEnabled(enabled: boolean): Promise<ManagedOriginStatus> {\n    if (!enabled) this.options.managed.cancelPendingStart?.()\n    return this.enqueue(async () => {\n      this.assertAvailable()\n      await this.options.store.save({ version: 1, enabled })\n      if (!enabled) await this.stopBoth()\n      this.enabled = enabled\n      if (enabled && !this.disposed) {\n        try { await this.controller().setEnabled(true) } catch (error) { await this.stopBoth(); throw error }\n      }\n    }).then(() => this.status())\n  }\n  reconnect(): Promise<ManagedOriginStatus> {\n    this.options.managed.cancelPendingStart?.()\n    return this.enqueue(async () => {\n      this.assertAvailable()\n      await this.options.store.save({ version: 1, enabled: true })\n      await this.stopBoth()\n      this.enabled = true\n      if (!this.disposed) {\n        try { await this.controller().reconnect() } catch (error) { await this.stopBoth(); throw error }\n      }\n    }).then(() => this.status())\n  }\n  reset(): Promise<ManagedOriginStatus> { return this.setEnabled(false) }\n  close(): Promise<void> {\n    this.disposed = true\n    // Closing managed immediately cancels a public readiness probe ahead of queued work.\n    this.closeTask ??= settleRemoteResources([() => this.options.external.close(), () => this.options.managed.close()])\n      .then(() => this.queue)\n      .catch((error: unknown) => { this.closeTask = undefined; throw error })\n    return this.closeTask\n  }\n  private controller(): RemoteProviderController { return this.options[this.selected] }\n  private assertAvailable(): void { if (!this.initialized || this.disposed) throw new Error('origin_controller_unavailable') }\n  private stopBoth(): Promise<void> { return settleRemoteResources([\n    async () => { await this.options.external.setEnabled(false) }, async () => { await this.options.managed.setEnabled(false) },\n  ]) }\n  private enqueue(operation: () => Promise<void>): Promise<void> {\n    const task = this.queue.then(operation, operation)\n    this.queue = task.then(() => undefined, () => undefined)\n    return task\n  }\n}\n","import { spawn, type ChildProcess } from 'node:child_process'\nimport { readFile } from 'node:fs/promises'\nimport { isAbsolute, join } from 'node:path'\nimport { createRequire } from 'node:module'\nimport type { Context } from '@deepseek-ai/cordis'\nimport { DSH_MOBILE_VERSION } from './version.js'\n\nconst PACKAGE_NAME = 'dsh-mobile'\nconst NPM_LATEST_URL = 'https://registry.npmjs.org/dsh-mobile/latest'\nconst ANDROID_RELEASE_DESCRIPTOR_URL = 'https://raw.githubusercontent.com/saya-ch/dsh-mobile/main/apps/mobile/release.json'\nconst GITHUB_RELEASE_API = 'https://api.github.com/repos/saya-ch/dsh-mobile/releases/tags/'\nconst GITHUB_RELEASES_URL = 'https://github.com/saya-ch/dsh-mobile/releases'\nconst RELEASE_NOTES_MAX_CHARS = 4000\nconst STATUS_CACHE_MS = 10 * 60_000\nconst REQUEST_TIMEOUT_MS = 8_000\nconst UPDATE_TIMEOUT_MS = 120_000\nconst UPDATE_TERMINATION_GRACE_MS = 1_500\nconst bundledAndroidRelease: unknown = createRequire(import.meta.url)('../apps/mobile/release.json')\n\nconst NUMERIC_VERSION_IDENTIFIER = '(?:0|[1-9]\\\\d*)'\nconst WILDCARD_VERSION_IDENTIFIER = '(?:[xX*])'\nconst PARTIAL_VERSION = `(?:${WILDCARD_VERSION_IDENTIFIER}|${NUMERIC_VERSION_IDENTIFIER}(?:\\\\.(?:${WILDCARD_VERSION_IDENTIFIER}|${NUMERIC_VERSION_IDENTIFIER}(?:\\\\.(?:${WILDCARD_VERSION_IDENTIFIER}|${NUMERIC_VERSION_IDENTIFIER}))?))?)`\nconst FULL_VERSION = `${NUMERIC_VERSION_IDENTIFIER}\\\\.${NUMERIC_VERSION_IDENTIFIER}\\\\.${NUMERIC_VERSION_IDENTIFIER}(?:-[0-9A-Za-z-]+(?:\\\\.[0-9A-Za-z-]+)*)?(?:\\\\+[0-9A-Za-z-]+(?:\\\\.[0-9A-Za-z-]+)*)?`\nconst RANGE_VERSION = `(?:${FULL_VERSION}|${PARTIAL_VERSION})`\nconst COMPARATOR = new RegExp(`^(?:<=|>=|<|>|=|~|\\\\^)?${RANGE_VERSION}$`, 'u')\nconst HYPHEN_RANGE = new RegExp(`^${RANGE_VERSION} +[-] +${RANGE_VERSION}$`, 'u')\nconst DIST_TAG = /^[A-Za-z][A-Za-z0-9._-]{0,127}$/u\n\ninterface Semver {\n  readonly core: readonly [number, number, number]\n  readonly prerelease: readonly (number | string)[]\n}\n\n/** Release information safe to return through the loopback administration API. */\nexport interface PluginReleaseStatus {\n  readonly installedVersion: string\n  readonly latestVersion?: string\n  readonly updateAvailable: boolean\n  readonly updateSupported: boolean\n  readonly androidVersion?: string\n  readonly androidDownloadUrl: string\n  /** Trimmed GitHub release notes for the selected npm version. */\n  readonly releaseNotes?: string\n}\n\n/** Result returned after the profile package has been replaced successfully. */\nexport interface PluginUpdateResult {\n  readonly installedVersion: string\n  readonly restartRequired: true\n}\n\ninterface PluginReleaseManagerOptions {\n  readonly profileDirectory: string | undefined\n  readonly installedVersion?: string\n  readonly fetch?: typeof globalThis.fetch\n  readonly runUpdate?: (profileDirectory: string, version: string) => Promise<void>\n  readonly readInstalledVersion?: (profileDirectory: string) => Promise<string | undefined>\n  readonly now?: () => number\n  readonly updateProcess?: PnpmUpdateRuntime\n}\n\ninterface UpdateProcessExit {\n  readonly code: number | null\n  readonly signal: NodeJS.Signals | null\n}\n\ninterface UpdateProcessRequest {\n  readonly command: string\n  readonly args: readonly string[]\n  readonly cwd: string\n  readonly detached: boolean\n  readonly platform: NodeJS.Platform\n  readonly shell: false\n}\n\ninterface ManagedUpdateProcess {\n  readonly completion: Promise<UpdateProcessExit>\n  readonly stderr?: NodeJS.ReadableStream\n  terminateTree(): Promise<void>\n}\n\ninterface UpdateDeadline {\n  readonly promise: Promise<void>\n  cancel(): void\n}\n\ninterface PnpmUpdateRuntime {\n  readonly platform?: NodeJS.Platform\n  readonly timeoutMs?: number\n  readonly windowsCommandInterpreter?: string\n  readonly start?: (request: UpdateProcessRequest) => ManagedUpdateProcess\n  readonly deadline?: (timeoutMs: number) => UpdateDeadline\n}\n\nfunction parseSemver(value: string): Semver | undefined {\n  const match = /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-([0-9A-Za-z.-]+))?(?:\\+[0-9A-Za-z.-]+)?$/u.exec(value)\n  if (match === null) return undefined\n  const core = [Number(match[1]), Number(match[2]), Number(match[3])] as const\n  if (core.some(part => !Number.isSafeInteger(part))) return undefined\n  const prerelease = match[4] === undefined\n    ? []\n    : match[4].split('.').map((part): number | string => /^\\d+$/u.test(part) ? Number(part) : part)\n  if (prerelease.some(part => typeof part === 'number' && !Number.isSafeInteger(part))) return undefined\n  return Object.freeze({ core, prerelease: Object.freeze(prerelease) })\n}\n\n/** Compare two strict SemVer strings, including prerelease precedence. */\nexport function comparePluginVersions(left: string, right: string): number | undefined {\n  const a = parseSemver(left)\n  const b = parseSemver(right)\n  if (a === undefined || b === undefined) return undefined\n  for (let index = 0; index < a.core.length; index += 1) {\n    const difference = a.core[index]! - b.core[index]!\n    if (difference !== 0) return Math.sign(difference)\n  }\n  if (a.prerelease.length === 0 || b.prerelease.length === 0) {\n    return a.prerelease.length === b.prerelease.length ? 0 : a.prerelease.length === 0 ? 1 : -1\n  }\n  const length = Math.max(a.prerelease.length, b.prerelease.length)\n  for (let index = 0; index < length; index += 1) {\n    const leftPart = a.prerelease[index]\n    const rightPart = b.prerelease[index]\n    if (leftPart === undefined || rightPart === undefined) return leftPart === undefined ? -1 : 1\n    if (leftPart === rightPart) continue\n    if (typeof leftPart === 'number' && typeof rightPart === 'number') return Math.sign(leftPart - rightPart)\n    if (typeof leftPart === 'number') return -1\n    if (typeof rightPart === 'number') return 1\n    return leftPart < rightPart ? -1 : 1\n  }\n  return 0\n}\n\nfunction isComparatorSet(value: string): boolean {\n  if (HYPHEN_RANGE.test(value)) return true\n  const normalized = value.replace(/(<=|>=|<|>|=|~|\\^) +/gu, '$1')\n  const comparators = normalized.split(/ +/u)\n  return comparators.length > 0 && comparators.every(comparator => COMPARATOR.test(comparator))\n}\n\nfunction isNpmVersionRange(value: string): boolean {\n  if (!/^[0-9xX*<>=~^|.+\\- ]+$/u.test(value)) return false\n  const alternatives = value.split(/ *\\|\\| */u)\n  return alternatives.length > 0 && alternatives.every(alternative => alternative !== '' && isComparatorSet(alternative))\n}\n\n/** Return whether pnpm may safely replace this profile dependency from an npm version, range, or tag. */\nexport function isRegistryPluginSpec(value: unknown): value is string {\n  if (typeof value !== 'string' || value.trim() !== value || value === '' || /[\\u0000-\\u001f\\u007f]/u.test(value)) return false\n  if (/\\.(?:tgz|tar(?:\\.gz)?)$/iu.test(value)) return false\n  return parseSemver(value) !== undefined || isNpmVersionRange(value) || DIST_TAG.test(value)\n}\n\n/** Resolve the DSH profile named by the current launcher arguments. */\nexport function launchedProfileName(argv: readonly string[]): string {\n  for (let index = 0; index < argv.length; index += 1) {\n    if (argv[index] === '--profile') {\n      const candidate = argv[index + 1]\n      if (candidate !== undefined && /^[\\w.-]+$/u.test(candidate)) return candidate\n    }\n    const match = /^--profile=([\\w.-]+)$/u.exec(argv[index] ?? '')\n    if (match?.[1] !== undefined) return match[1]\n  }\n  return 'web'\n}\n\ninterface DesktopProfiles {\n  readonly current?: { readonly dir?: string }\n}\n\n/** Resolve the launcher-owned Desktop profile, or the CLI profile outside Desktop. */\nexport function releaseProfileDirectory(ctx: Pick<Context, 'get'>, dshHome: string, argv: readonly string[]): string | undefined {\n  const desktopProfiles = ctx.get('desktopProfiles') as DesktopProfiles | undefined\n  const desktopDirectory = desktopProfiles?.current?.dir\n  if (typeof desktopDirectory === 'string' && isAbsolute(desktopDirectory)) return desktopDirectory\n  // Desktop selects its profile outside argv; never update an unrelated Web profile.\n  if (desktopProfiles !== undefined || ctx.get('desktopRuntime') !== undefined) return undefined\n  return join(dshHome, 'profiles', launchedProfileName(argv))\n}\n\nasync function profileDependencySpec(profileDirectory: string): Promise<string | undefined> {\n  try {\n    const manifest = JSON.parse(await readFile(join(profileDirectory, 'package.json'), 'utf8')) as {\n      readonly dependencies?: Readonly<Record<string, unknown>>\n    }\n    const value = manifest.dependencies?.[PACKAGE_NAME]\n    return typeof value === 'string' ? value : undefined\n  } catch {\n    return undefined\n  }\n}\n\nasync function fetchNpmVersion(fetcher: typeof globalThis.fetch): Promise<string | undefined> {\n  const response = await fetcher(NPM_LATEST_URL, {\n    headers: { accept: 'application/json', 'user-agent': 'dsh-mobile-release-check' },\n    signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n  })\n  if (!response.ok) return undefined\n  const payload = await response.json() as { readonly version?: unknown }\n  return typeof payload.version === 'string' && parseSemver(payload.version) !== undefined\n    ? payload.version\n    : undefined\n}\n\ninterface AndroidRelease {\n  readonly version: string\n  readonly downloadUrl: string\n}\n\nfunction androidRelease(version: unknown, tag: unknown): AndroidRelease | undefined {\n  if (typeof version !== 'string' || !/^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$/u.test(version)\n    || parseSemver(version) === undefined || (tag !== `v${version}` && tag !== `android-v${version}`)) return undefined\n  return Object.freeze({\n    version,\n    downloadUrl: `https://github.com/saya-ch/dsh-mobile/releases/download/${tag}/dsh-mobile-android-v${version}.apk`,\n  })\n}\n\nfunction androidReleaseDescriptor(payload: unknown): AndroidRelease | undefined {\n  if (typeof payload !== 'object' || payload === null) return undefined\n  const fields = payload as { readonly version?: unknown; readonly releaseTag?: unknown; readonly versionCode?: unknown }\n  return Number.isSafeInteger(fields.versionCode) && Number(fields.versionCode) > 0\n    ? androidRelease(fields.version, fields.releaseTag)\n    : undefined\n}\n\nasync function fetchAndroidRelease(fetcher: typeof globalThis.fetch): Promise<AndroidRelease | undefined> {\n  const fallback = androidReleaseDescriptor(bundledAndroidRelease)\n  try {\n    const response = await fetcher(ANDROID_RELEASE_DESCRIPTOR_URL, {\n      redirect: 'error',\n      headers: { accept: 'application/json', 'user-agent': 'dsh-mobile-release-check' },\n      signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n    })\n    if (response.ok) {\n      const release = androidReleaseDescriptor(await response.json())\n      if (release !== undefined) {\n        return fallback !== undefined && comparePluginVersions(release.version, fallback.version) === -1 ? fallback : release\n      }\n    }\n  } catch {\n    // The package's verified App pointer remains available when the network lookup fails.\n  }\n  return fallback\n}\n\n/** Best-effort body of the selected npm version's GitHub release, trimmed to a bounded size. */\nasync function fetchReleaseNotes(fetcher: typeof globalThis.fetch, version: string): Promise<string | undefined> {\n  const response = await fetcher(`${GITHUB_RELEASE_API}${encodeURIComponent(`v${version}`)}`, {\n    headers: { accept: 'application/vnd.github+json', 'user-agent': 'dsh-mobile-release-check' },\n    signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n  })\n  if (!response.ok) return undefined\n  const payload = await response.json() as { readonly body?: unknown }\n  if (typeof payload.body !== 'string') return undefined\n  const notes = payload.body.trim()\n  return notes === '' ? undefined : notes.slice(0, RELEASE_NOTES_MAX_CHARS)\n}\n\nasync function readProfileInstalledVersion(profileDirectory: string): Promise<string | undefined> {\n  try {\n    const manifestPath = createRequire(join(profileDirectory, 'package.json')).resolve(`${PACKAGE_NAME}/package.json`)\n    const manifest = JSON.parse(await readFile(manifestPath, 'utf8')) as { readonly version?: unknown }\n    return typeof manifest.version === 'string' ? manifest.version : undefined\n  } catch {\n    return undefined\n  }\n}\n\nfunction childCompletion(child: ChildProcess): Promise<UpdateProcessExit> {\n  return new Promise<UpdateProcessExit>((resolveCompletion, rejectCompletion) => {\n    child.once('error', rejectCompletion)\n    child.once('close', (code, signal) => { resolveCompletion({ code, signal }) })\n  })\n}\n\nfunction createDeadline(timeoutMs: number): UpdateDeadline {\n  let timer: NodeJS.Timeout | undefined\n  const promise = new Promise<void>(resolveTimeout => {\n    timer = setTimeout(resolveTimeout, timeoutMs)\n    timer.unref()\n  })\n  return {\n    promise,\n    cancel: () => {\n      if (timer !== undefined) clearTimeout(timer)\n      timer = undefined\n    },\n  }\n}\n\nasync function taskkillProcessTree(pid: number): Promise<void> {\n  const killer = spawn('taskkill.exe', ['/PID', String(pid), '/T', '/F'], {\n    shell: false,\n    windowsHide: true,\n    stdio: 'ignore',\n  })\n  const result = await childCompletion(killer)\n  if (result.code !== 0) throw new Error('plugin_update_tree_termination_failed')\n}\n\nasync function completionWithin(completion: Promise<UpdateProcessExit>, timeoutMs: number): Promise<boolean> {\n  let timer: NodeJS.Timeout | undefined\n  try {\n    return await Promise.race([\n      completion.then(() => true, () => true),\n      new Promise<false>(resolveTimeout => {\n        timer = setTimeout(() => { resolveTimeout(false) }, timeoutMs)\n        timer.unref()\n      }),\n    ])\n  } finally {\n    if (timer !== undefined) clearTimeout(timer)\n  }\n}\n\nfunction processMissing(error: unknown): boolean {\n  return (error as NodeJS.ErrnoException).code === 'ESRCH'\n}\n\nasync function terminateProcessTree(child: ChildProcess, completion: Promise<UpdateProcessExit>, platform: NodeJS.Platform): Promise<void> {\n  if (child.exitCode !== null || child.signalCode !== null) return\n  const pid = child.pid\n  if (pid === undefined) {\n    child.kill('SIGKILL')\n    if (!await completionWithin(completion, UPDATE_TERMINATION_GRACE_MS)) {\n      throw new Error('plugin_update_tree_termination_timeout')\n    }\n    return\n  }\n  if (platform === 'win32') {\n    try { await taskkillProcessTree(pid) } catch (error) {\n      if (child.exitCode === null && child.signalCode === null) child.kill('SIGKILL')\n      if (!await completionWithin(completion, UPDATE_TERMINATION_GRACE_MS)) {\n        throw new AggregateError([error, new Error('plugin_update_tree_termination_timeout')], 'plugin update tree termination failed')\n      }\n      throw error\n    }\n    if (!await completionWithin(completion, UPDATE_TERMINATION_GRACE_MS)) {\n      if (child.exitCode === null && child.signalCode === null) child.kill('SIGKILL')\n      if (!await completionWithin(completion, UPDATE_TERMINATION_GRACE_MS)) {\n        throw new Error('plugin_update_tree_termination_timeout')\n      }\n    }\n    return\n  }\n  try { process.kill(-pid, 'SIGTERM') } catch (error) {\n    if (!processMissing(error)) throw error\n    if (!await completionWithin(completion, UPDATE_TERMINATION_GRACE_MS)) {\n      throw new Error('plugin_update_tree_termination_timeout')\n    }\n    return\n  }\n  if (await completionWithin(completion, UPDATE_TERMINATION_GRACE_MS)) return\n  try { process.kill(-pid, 'SIGKILL') } catch (error) {\n    if (!processMissing(error)) throw error\n  }\n  if (!await completionWithin(completion, UPDATE_TERMINATION_GRACE_MS)) {\n    throw new Error('plugin_update_tree_termination_timeout')\n  }\n}\n\nfunction startUpdateProcess(request: UpdateProcessRequest): ManagedUpdateProcess {\n  const child = spawn(request.command, [...request.args], {\n    cwd: request.cwd,\n    detached: request.detached,\n    shell: request.shell,\n    windowsHide: true,\n    stdio: ['ignore', 'ignore', 'pipe'],\n  })\n  const completion = childCompletion(child)\n  return {\n    completion,\n    ...(child.stderr === null ? {} : { stderr: child.stderr }),\n    terminateTree: async () => terminateProcessTree(child, completion, request.platform),\n  }\n}\n\nfunction updateFailure(cause?: unknown): Error {\n  return cause === undefined ? new Error('plugin_update_failed') : new Error('plugin_update_failed', { cause })\n}\n\nasync function runPnpmUpdate(profileDirectory: string, version: string, runtime: PnpmUpdateRuntime = {}): Promise<void> {\n  if (parseSemver(version) === undefined) throw new Error('plugin_update_unavailable')\n  const platform = runtime.platform ?? process.platform\n  const packageSpec = `${PACKAGE_NAME}@${version}`\n  const managed = (runtime.start ?? startUpdateProcess)({\n    command: platform === 'win32'\n      ? (runtime.windowsCommandInterpreter ?? process.env.ComSpec ?? 'cmd.exe')\n      : 'pnpm',\n    args: platform === 'win32'\n      ? ['/d', '/s', '/c', 'pnpm.cmd', 'add', packageSpec]\n      : ['add', packageSpec],\n    cwd: profileDirectory,\n    detached: platform !== 'win32',\n    platform,\n    shell: false,\n  })\n  let diagnostics = ''\n  managed.stderr?.on('data', chunk => {\n    if (diagnostics.length < 4096) diagnostics += Buffer.from(chunk).toString('utf8').slice(0, 4096 - diagnostics.length)\n  })\n  const completion = managed.completion.then(\n    result => ({ kind: 'exit' as const, result }),\n    error => ({ kind: 'error' as const, error }),\n  )\n  const deadline = (runtime.deadline ?? createDeadline)(runtime.timeoutMs ?? UPDATE_TIMEOUT_MS)\n  const first = await Promise.race([\n    completion,\n    deadline.promise.then(() => ({ kind: 'timeout' as const })),\n  ])\n  deadline.cancel()\n  if (first.kind === 'error') throw updateFailure(first.error)\n  if (first.kind === 'exit') {\n    if (first.result.code === 0) return\n    const detail = diagnostics.trim() || `pnpm exited with ${first.result.signal ?? String(first.result.code)}`\n    throw updateFailure(new Error(detail))\n  }\n  let terminationError: unknown\n  try { await managed.terminateTree() } catch (error) { terminationError = error }\n  if (terminationError !== undefined) throw updateFailure(terminationError)\n  const stopped = await completion\n  if (stopped.kind === 'error') throw updateFailure(stopped.error)\n  throw updateFailure(new Error('plugin update timed out'))\n}\n\n/** Cached npm/GitHub release lookup and guarded profile-local package update. */\nexport class PluginReleaseManager {\n  private readonly profileDirectory: string | undefined\n  private readonly installedVersion: string\n  private readonly fetcher: typeof globalThis.fetch\n  private readonly runner: (profileDirectory: string, version: string) => Promise<void>\n  private readonly installedVersionReader: (profileDirectory: string) => Promise<string | undefined>\n  private readonly now: () => number\n  private cache: { readonly expiresAt: number; readonly status: PluginReleaseStatus } | undefined\n  private activeUpdate: Promise<PluginUpdateResult> | undefined\n\n  constructor(options: PluginReleaseManagerOptions) {\n    this.profileDirectory = options.profileDirectory\n    this.installedVersion = options.installedVersion ?? DSH_MOBILE_VERSION\n    this.fetcher = options.fetch ?? globalThis.fetch\n    this.runner = options.runUpdate ?? ((profileDirectory, version) => runPnpmUpdate(profileDirectory, version, options.updateProcess))\n    this.installedVersionReader = options.readInstalledVersion ?? readProfileInstalledVersion\n    this.now = options.now ?? Date.now\n  }\n\n  /** Read cached release metadata and suppress external lookup failures. */\n  async status(force = false): Promise<PluginReleaseStatus> {\n    if (!force && this.cache !== undefined && this.cache.expiresAt > this.now()) return this.cache.status\n    const dependencySpec = this.profileDirectory === undefined ? undefined : await profileDependencySpec(this.profileDirectory)\n    const updateSupported = isRegistryPluginSpec(dependencySpec)\n    const npmVersion = fetchNpmVersion(this.fetcher)\n    const [npmResult, androidResult, notesResult] = await Promise.allSettled([\n      npmVersion,\n      fetchAndroidRelease(this.fetcher),\n      npmVersion.then(version => version === undefined ? undefined : fetchReleaseNotes(this.fetcher, version)),\n    ])\n    const latestVersion = npmResult.status === 'fulfilled' ? npmResult.value : undefined\n    const android = androidResult.status === 'fulfilled' ? androidResult.value : undefined\n    const releaseNotes = notesResult.status === 'fulfilled' ? notesResult.value : undefined\n    const comparison = latestVersion === undefined\n      ? undefined\n      : comparePluginVersions(latestVersion, this.installedVersion)\n    const status: PluginReleaseStatus = Object.freeze({\n      installedVersion: this.installedVersion,\n      ...(latestVersion === undefined ? {} : { latestVersion }),\n      updateAvailable: updateSupported && comparison === 1,\n      updateSupported,\n      ...(android === undefined ? {} : { androidVersion: android.version }),\n      androidDownloadUrl: android?.downloadUrl ?? GITHUB_RELEASES_URL,\n      ...(releaseNotes === undefined ? {} : { releaseNotes }),\n    })\n    this.cache = { expiresAt: this.now() + STATUS_CACHE_MS, status }\n    return status\n  }\n\n  /** Install the latest npm release into the active profile, then require a DSH restart. */\n  async update(): Promise<PluginUpdateResult> {\n    if (this.activeUpdate !== undefined) return this.activeUpdate\n    this.activeUpdate = this.updateOnce()\n    try { return await this.activeUpdate }\n    finally { this.activeUpdate = undefined }\n  }\n\n  private async updateOnce(): Promise<PluginUpdateResult> {\n    const profileDirectory = this.profileDirectory\n    if (profileDirectory === undefined) throw new Error('plugin_update_unsupported')\n    const status = await this.status(true)\n    if (!status.updateSupported) throw new Error('plugin_update_unsupported')\n    if (!status.updateAvailable || status.latestVersion === undefined) throw new Error('plugin_update_unavailable')\n    await this.runner(profileDirectory, status.latestVersion)\n    const installed = await this.installedVersionReader(profileDirectory)\n    if (installed !== status.latestVersion) throw new Error('plugin_update_failed')\n    this.cache = undefined\n    return Object.freeze({ installedVersion: installed, restartRequired: true })\n  }\n}\n","import { constants, type WriteStream } from 'node:fs'\nimport { lstat, open, type FileHandle } from 'node:fs/promises'\nimport { finished } from 'node:stream/promises'\nimport { join } from 'node:path'\nimport { Logger, type Context, type Exporter, type Message } from '@deepseek-ai/cordis'\nimport { assertManagedParents, ensureManagedDirectory, removeManagedTree, renameManagedPath } from './managed-files.js'\nimport { restrictPrivateFile } from './private-file.js'\n\nconst MAX_LOG_BYTES = 5 * 1024 * 1024\nconst MAX_QUEUED_BYTES = 256 * 1024\nconst PATH_PREFIX = 'mobile_log'\n\n/** Stream acquisition seam used by owner-local I/O failure fixtures. */\nexport interface MobileFileLoggerOptions { readonly createStream?: (handle: FileHandle) => WriteStream }\n\nasync function regularLogFile(file: string): Promise<Awaited<ReturnType<typeof lstat>> | undefined> {\n  try {\n    const entry = await lstat(file)\n    if (!entry.isFile() || entry.isSymbolicLink()) throw new Error('mobile_log_target_invalid')\n    return entry\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n    throw error\n  }\n}\n\n/** Open a private append-only file before registering a safely disposable Cordis exporter. */\nexport async function installMobileFileLogger(ctx: Context, stateDirectory: string, options: MobileFileLoggerOptions = {}): Promise<string> {\n  const directory = join(stateDirectory, 'logs')\n  const file = join(directory, 'dsh-mobile.log')\n  const previous = `${file}.1`\n  await ensureManagedDirectory(stateDirectory, directory, PATH_PREFIX)\n  const entry = await regularLogFile(file)\n  if (entry !== undefined && entry.size >= MAX_LOG_BYTES) {\n    await regularLogFile(previous)\n    await removeManagedTree(stateDirectory, previous, PATH_PREFIX)\n    await renameManagedPath(stateDirectory, file, previous, PATH_PREFIX)\n    await regularLogFile(previous)\n    await restrictPrivateFile(previous)\n  }\n  await assertManagedParents(stateDirectory, file, PATH_PREFIX)\n  await regularLogFile(file)\n  const handle = await open(file, constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | (constants.O_NOFOLLOW ?? 0), 0o600)\n  let stream: WriteStream\n  try {\n    const opened = await handle.stat()\n    const actual = await regularLogFile(file)\n    if (!opened.isFile() || actual === undefined || actual.dev !== opened.dev || actual.ino !== opened.ino) throw new Error('mobile_log_target_invalid')\n    await assertManagedParents(stateDirectory, file, PATH_PREFIX)\n    await handle.chmod(0o600)\n    await restrictPrivateFile(file)\n    stream = options.createStream?.(handle) ?? handle.createWriteStream({ encoding: 'utf8', autoClose: true })\n  } catch (error) { await handle.close(); throw error }\n\n  let stopped = false\n  let removeExporter: (() => Promise<void>) | undefined\n  const stopLogging = (error: unknown): void => {\n    if (stopped) return\n    stopped = true\n    try { void Promise.resolve(removeExporter?.()).catch(() => undefined) }\n    catch (disposeError) { void disposeError /* This exporter is already gated against further writes. */ }\n    stream.destroy()\n    const candidate = error as { readonly code?: unknown } | null\n    const code = candidate !== null && typeof candidate === 'object' && typeof candidate.code === 'string' ? candidate.code : 'write_failed'\n    // This exporter is stopped first, so warning delivery cannot recursively write to the failed file.\n    try { ctx.logger('dsh-mobile').warn('file logging disabled (%s); other logging remains available', code) }\n    catch (loggerError) { void loggerError /* A diagnostic sink failure cannot crash DSH. */ }\n  }\n  stream.on('error', stopLogging)\n  const closed = finished(stream, { cleanup: true }).catch(error => { stopLogging(error) })\n  const exporter: Exporter = {\n    colors: false,\n    maxLength: 16 * 1024,\n    levels: { default: -1, 'dsh-mobile': 3 },\n    export(message: Message): void {\n      if (stopped || message.name !== 'dsh-mobile') return\n      try {\n        const record = { timestamp: new Date(message.ts).toISOString(), level: message.type, logger: message.name, message: Logger.format(exporter, message) }\n        const line = `${JSON.stringify(record)}\\n`\n        if (stream.writableLength + Buffer.byteLength(line) > MAX_QUEUED_BYTES) { stopLogging(Object.assign(new Error('file log queue exhausted'), { code: 'backpressure' })); return }\n        stream.write(line)\n      } catch (error) { stopLogging(error) }\n    },\n  }\n  try {\n    removeExporter = ctx.logger.exporter(exporter)\n    ctx.effect(() => async () => {\n      stopped = true\n      await removeExporter?.()\n      stream.end()\n      await closed\n    }, 'dsh-mobile file logger')\n  } catch (error) {\n    stopped = true; stream.destroy(); await closed\n    await removeExporter?.()\n    throw error\n  }\n  return file\n}\n","import { randomBytes } from 'node:crypto'\nimport { lstat, mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname, isAbsolute, resolve } from 'node:path'\nimport { restrictPrivateFile } from './private-file.js'\n\nconst INSTALLATION_ID_PATTERN = /^[a-f0-9]{64}\\n$/u\nconst INSTALLATION_ID_BYTES = 65\n\nasync function readInstallationId(file: string): Promise<string> {\n  const entry = await lstat(file)\n  if (!entry.isFile() || entry.isSymbolicLink() || entry.size !== INSTALLATION_ID_BYTES) {\n    throw new Error('installation_id_invalid')\n  }\n  const contents = await readFile(file, 'utf8')\n  if (!INSTALLATION_ID_PATTERN.test(contents)) throw new Error('installation_id_invalid')\n  await restrictPrivateFile(file)\n  return contents.slice(0, -1)\n}\n\n/** Keep one random plugin identity across setup changes, restarts, and FRP resets. */\nexport async function loadOrCreateInstallationId(file: string): Promise<string> {\n  if (!isAbsolute(file)) throw new Error('installation ID path must be absolute')\n  const target = resolve(file)\n  await mkdir(dirname(target), { recursive: true, mode: 0o700 })\n  try {\n    await writeFile(target, `${randomBytes(32).toString('hex')}\\n`, { flag: 'wx', mode: 0o600 })\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error\n  }\n  return readInstallationId(target)\n}\n","import { execFileText as execFile } from './exec-file.js'\nimport { mkdir, writeFile } from 'node:fs/promises'\nimport { dirname, isAbsolute, join } from 'node:path'\nimport {\n  ensureManagedCa,\n  refreshManagedServerCertificate,\n  type LanNetwork,\n  type ManagedSetup,\n} from './managed-setup.js'\nimport { restrictPrivateFile } from './private-file.js'\n\nconst FIREWALL_TCP_RULE = 'DSH Mobile HTTPS'\nconst FIREWALL_UDP_RULE = 'DSH Mobile Discovery'\n\n/** Files and active address produced by one explicit LAN setup confirmation. */\nexport interface ManagedLanSetupResult {\n  readonly setup: ManagedSetup\n  readonly network: LanNetwork\n  readonly origin: string\n  readonly androidCertificate: string\n}\n\n/** Inputs required to prepare the managed LAN listener without starting it. */\nexport interface ManagedLanSetupOptions {\n  readonly setupFile: string\n  readonly controlFile: string\n  readonly network: LanNetwork\n  readonly listenPort: number\n  readonly dshPort: number\n  readonly configureFirewall: boolean\n}\n\nasync function runElevatedPowerShell(script: string): Promise<void> {\n  const encoded = Buffer.from(script, 'utf16le').toString('base64')\n  const launch = [\n    \"$ErrorActionPreference = 'Stop'; $process = Start-Process -FilePath 'powershell.exe' -Verb RunAs -WindowStyle Hidden -Wait -PassThru\",\n    `  -ArgumentList @('-NoProfile','-NonInteractive','-EncodedCommand','${encoded}')`,\n    '; exit $process.ExitCode',\n  ].join(' ')\n  await execFile('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', launch], { windowsHide: true })\n}\n\n/** Install the two Windows inbound rules used by the managed LAN listener. */\nexport async function configureWindowsFirewall(port: number): Promise<void> {\n  if (process.platform !== 'win32') return\n  const script = [\n    \"$ErrorActionPreference = 'Stop'\",\n    `Get-NetFirewallRule -DisplayName '${FIREWALL_TCP_RULE}' -ErrorAction SilentlyContinue | Remove-NetFirewallRule`,\n    `Get-NetFirewallRule -DisplayName '${FIREWALL_UDP_RULE}' -ErrorAction SilentlyContinue | Remove-NetFirewallRule`,\n    `New-NetFirewallRule -DisplayName '${FIREWALL_TCP_RULE}' -Direction Inbound -Action Allow -Protocol TCP -LocalPort ${String(port)} -RemoteAddress LocalSubnet -Profile Any | Out-Null`,\n    `New-NetFirewallRule -DisplayName '${FIREWALL_UDP_RULE}' -Direction Inbound -Action Allow -Protocol UDP -LocalPort ${String(port)} -RemoteAddress LocalSubnet -Profile Any | Out-Null`,\n  ].join('; ')\n  await runElevatedPowerShell(script)\n}\n\n/** Remove only the two Windows firewall rules owned by DSH Mobile. */\nexport async function removeWindowsFirewall(): Promise<void> {\n  if (process.platform !== 'win32') return\n  await runElevatedPowerShell([\n    \"$ErrorActionPreference = 'Stop'\",\n    `Get-NetFirewallRule -DisplayName '${FIREWALL_TCP_RULE}' -ErrorAction SilentlyContinue | Remove-NetFirewallRule`,\n    `Get-NetFirewallRule -DisplayName '${FIREWALL_UDP_RULE}' -ErrorAction SilentlyContinue | Remove-NetFirewallRule`,\n  ].join('; '))\n}\n\n/** Generate private TLS material and persist a managed setup selected by the user. */\nexport async function prepareManagedLanSetup(options: ManagedLanSetupOptions): Promise<ManagedLanSetupResult> {\n  if (!isAbsolute(options.setupFile) || !isAbsolute(options.controlFile)) {\n    throw new Error('managed LAN setup paths must be absolute')\n  }\n  if (!Number.isSafeInteger(options.listenPort) || options.listenPort < 1024 || options.listenPort > 65535) {\n    throw new Error('managed LAN listenPort must be from 1024 through 65535')\n  }\n  if (!Number.isSafeInteger(options.dshPort) || options.dshPort < 1024 || options.dshPort > 65535) {\n    throw new Error('managed LAN dshPort must be from 1024 through 65535')\n  }\n  const directory = dirname(options.setupFile)\n  const tlsDirectory = join(directory, 'tls')\n  await mkdir(tlsDirectory, { recursive: true, mode: 0o700 })\n  const managedTls: ManagedSetup['tls'] = {\n    mode: 'managed',\n    caCertFile: join(tlsDirectory, 'ca.pem'),\n    caKeyFile: join(tlsDirectory, 'ca-key.pem'),\n    certFile: join(tlsDirectory, 'server-cert.pem'),\n    keyFile: join(tlsDirectory, 'server-key.pem'),\n  }\n  const ca = await ensureManagedCa(managedTls, {\n    certFile: join(tlsDirectory, 'cert.pem'),\n    keyFile: join(tlsDirectory, 'key.pem'),\n  })\n  const setup: ManagedSetup = {\n    version: 2,\n    networkInterface: options.network.name,\n    listenPort: options.listenPort,\n    upstreamOrigin: `http://127.0.0.1:${String(options.dshPort)}`,\n    tls: managedTls,\n  }\n  await refreshManagedServerCertificate(setup, options.network.address)\n  const androidCertificate = join(tlsDirectory, 'dsh-mobile-ca.cer')\n  await writeFile(androidCertificate, ca.raw, { mode: 0o600 })\n  await Promise.all([\n    ...Object.values(managedTls).filter(value => value !== 'managed').map(file => restrictPrivateFile(file)),\n    restrictPrivateFile(androidCertificate),\n  ])\n  if (options.configureFirewall) await configureWindowsFirewall(options.listenPort)\n  await Promise.all([\n    writeFile(options.setupFile, `${JSON.stringify({\n      ...setup,\n      tls: Object.fromEntries(Object.entries(setup.tls)\n        .map(([key, value]) => [key, typeof value === 'string' ? value.replaceAll('\\\\', '/') : value])),\n    }, null, 2)}\\n`, { mode: 0o600 }),\n    writeFile(options.controlFile, '{\"version\":1,\"enabled\":true}\\n', { mode: 0o600 }),\n  ])\n  await Promise.all([restrictPrivateFile(options.setupFile), restrictPrivateFile(options.controlFile)])\n  return Object.freeze({\n    setup: Object.freeze(setup),\n    network: Object.freeze({ ...options.network }),\n    origin: `https://${options.network.address}:${String(options.listenPort)}`,\n    androidCertificate,\n  })\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { assertManagedParents } from './managed-files.js'\nimport { boundContextSummary, createUserMessage } from '@deepseek-ai/dsh-llm/message'\ndeclare module '@deepseek-ai/dsh-llm' {\n  interface MessageSourceMap {\n    'plugin:dsh-mobile': {\n      kind: 'plugin:dsh-mobile'\n      form: 'notice'\n      summary: string\n    }\n  }\n}\n// Side-effect type import: activates dsh-commands' Context augmentation so\n// `ctx.commands` and its handler types resolve without a runtime dependency.\nimport type {} from '@deepseek-ai/dsh-commands'\nimport type { WebRoute } from '@deepseek-ai/dsh-host-webserver'\nimport type { IncomingMessage } from 'node:http'\nimport { createRequire } from 'node:module'\nimport { X509Certificate } from 'node:crypto'\nimport { copyFile, lstat, readFile, rm } from 'node:fs/promises'\nimport { dirname, isAbsolute, join, resolve } from 'node:path'\nimport { parseControlFile, parseGatewayConfig, type PluginConfig, type ResolvedGatewayConfig } from './config.js'\nimport { collectConnectionDiagnostics, hasCompetingRemoteChannelBoot } from './diagnostics.js'\nimport { buildMobileGuide, type MobileGuideState } from './mobile-guide.js'\nimport { createVpsUninstallScript, deployVps, fetchVpsHostKeys, parseVpsDeploymentInput, uninstallVps } from './vps-deploy.js'\nimport { TaskEventHub, watchTaskCompletions } from './task-events.js'\nimport {\n  FollowingMobileAccessRuntime,\n  JsonMobileAccessControlStore,\n  MobileAccessGatewayController,\n  type MobileAccessRuntime,\n} from './control.js'\nimport { MobileAccessGateway, ClientModuleConflictError } from './gateway.js'\nimport { ClientModulePreferenceStore } from './client-module-preferences.js'\nimport { createMobileAccessService, MobileExtensionError, type MobileAccessService } from './extensions.js'\nimport { listComputerImages, readComputerImage } from './computer-images.js'\nimport {\n  HttpError,\n  LOCAL_ADMIN_PREFIX,\n  assertLocalAdminTrust,\n  parseRequestTarget,\n  readJsonObject,\n  sendFailure,\n  sendJson,\n} from './http-security.js'\nimport { JsonDeviceStore } from './storage.js'\nimport { BlockedUpgradePathLog, WebSocketPathStore } from './websocket-paths.js'\nimport { FunnelController, funnelExecutable } from './funnel.js'\nimport { CpolarController } from './cpolar.js'\nimport { CpolarComponentManager, type CpolarComponentStatus } from './cpolar-component.js'\nimport { CloudflaredComponentManager, type CloudflaredComponentStatus } from './cloudflared-component.js'\nimport { CloudflaredController } from './cloudflared.js'\nimport {\n  CloudflaredTunnelStore,\n  mergeSavedCloudflaredTunnelSettings,\n  type CloudflaredTunnelStatus,\n} from './cloudflared-tunnel.js'\nimport { FrpComponentManager, type FrpComponentStatus } from './frp-component.js'\nimport {\n  FrpConfigStore,\n  frpProxyName,\n  isFrpSelfSignedIngress,\n  mergeSavedFrpSettings,\n  mergeSavedFrpTarget,\n  resolveFrpPublicPort,\n  resolveFrpEntryProbe,\n  resolveFrpVhostHttpPort,\n  type FrpConfigurationStatus,\n  type FrpSettings,\n} from './frp-config.js'\nimport { createFrpAttachTemplate } from './frp-attach.js'\nimport { createFrpAttachPlan } from './frp-attach-plan.js'\nimport { defaultProbeDiscovery, FrpController } from './frp.js'\nimport { ensureFrpIngressCertificate, frpIngressPaths, frpIngressSelfCheck, purgeFrpIngressCertificates, type FrpIngressCertificate } from './frp-ingress.js'\nimport { CaddyComponentManager, type CaddyComponentStatus } from './caddy-component.js'\nimport { CaddyConfigStore } from './caddy-config.js'\nimport { CaddyController } from './caddy.js'\nimport { ManagedOriginController, JsonOriginModeStore, createVolatileRemoteControlStore } from './managed-origin.js'\nimport { OriginConfigStore, parseOriginSettings, validateOriginListenPort, type OriginConfigurationStatus, type OriginSettings } from './origin-proxy-config.js'\nimport { OriginController } from './origin-proxy.js'\nimport { PluginReleaseManager, releaseProfileDirectory } from './release-update.js'\nimport { installMobileFileLogger } from './file-logger.js'\nimport { loadOrCreateInstallationId } from './installation-id.js'\nimport {\n  configuredRemoteProvider,\n  JsonRemoteProviderStore,\n  prepareDisabledRemoteProviders,\n  RemoteProviderCoordinator,\n  REMOTE_PROVIDERS,\n  type RemoteProvider,\n  type RemoteProviderController,\n  type RemoteProviderStatus,\n} from './remote.js'\nimport { parseAuthority, parseCidr, probeTcpReachable } from './network.js'\nimport {\n  availableLanNetworks,\n  isNetworkSelectionError,\n  materializeManagedSetup,\n  parseAdditionalTrustedNetworks,\n  parseManagedSetup,\n  saveManagedTrustedNetworks,\n  preferredLanInterfaceNames,\n  selectLanNetwork,\n  type ManagedSetup,\n} from './managed-setup.js'\nimport { prepareManagedLanSetup, type ManagedLanSetupResult } from './lan-setup.js'\n\n/** Stable Cordis plugin name. */\nexport const name = 'dsh-mobile'\n\n/** The stock WebServer serves the control card; Connection authenticates the loopback DSH origin. */\nexport const inject = ['webServer', 'commands', 'connection']\n\n/** Run cleanup steps in ownership order and report every failure after all steps settle. */\nexport async function settleCleanupSteps(steps: readonly (() => void | Promise<void>)[]): Promise<void> {\n  const errors: unknown[] = []\n  for (const step of steps) {\n    try { await step() } catch (error) { errors.push(error) }\n  }\n  if (errors.length === 1 && errors[0] instanceof Error) throw errors[0]\n  if (errors.length > 0) throw new AggregateError(errors, 'DSH Mobile cleanup failed')\n}\n\ninterface BrowserAuthenticatedConnection {\n  authenticatedUrl?: (baseUrl: string) => string\n  requestRejection?: (request: IncomingMessage) => 401 | 403 | undefined\n}\n\n/**\n * Resolve the DSH launch-token URL the gateway exchanges for its upstream cookie.\n *\n * A layer that disables DSH browser authentication — dsh-lan-access with\n * `noAuth: true` replaces `authenticatedUrl` with one returning the bare origin\n * — produces a URL with no query string, so it cannot carry a launch token. That\n * is a legitimate \"this upstream needs no browser auth\" signal: report no URL and\n * the gateway proxies without a cookie instead of failing every route with\n * `upstream_unavailable`. A token-bearing URL keeps the existing exchange, and a\n * connection service that is absent or returns a malformed URL keeps failing\n * closed. Only parsing is guarded: a connection service that throws still fails\n * plugin activation loudly rather than silently proxying without authentication.\n */\nexport function upstreamAuthenticatedUrl(ctx: Context, upstreamOrigin: URL): string | undefined {\n  const connection = (ctx as Context & { readonly connection?: BrowserAuthenticatedConnection }).connection\n  if (typeof connection?.authenticatedUrl !== 'function') return undefined\n  const authenticatedUrl = connection.authenticatedUrl(upstreamOrigin.origin)\n  try {\n    return new URL(authenticatedUrl).search === '' ? undefined : authenticatedUrl\n  } catch {\n    return undefined\n  }\n}\n\nfunction installedDshVersion(): string {\n  try {\n    const manifest = createRequire(import.meta.url)('@deepseek-ai/dsh-host-webserver/package.json') as unknown\n    if (manifest === null || typeof manifest !== 'object') return 'unknown'\n    const version = (manifest as { readonly version?: unknown }).version\n    return typeof version === 'string' && version !== '' ? version : 'unknown'\n  } catch {\n    return 'unknown'\n  }\n}\n\nfunction mapAdminError(error: unknown): HttpError {\n  if (error instanceof HttpError) return error\n  if (error instanceof MobileExtensionError) return new HttpError(error.status, error.code)\n  const code = (error as NodeJS.ErrnoException).code\n  if (error instanceof Error && error.message.includes('spawn UNKNOWN')) {\n    return new HttpError(409, 'frp_component_launch_failed')\n  }\n  if (code === 'EADDRNOTAVAIL') return new HttpError(409, 'network_address_changed')\n  if (code === 'EADDRINUSE') return new HttpError(409, 'listen_port_in_use')\n  if (error instanceof Error && error.message.startsWith('saved LAN interface ')) {\n    return new HttpError(409, 'network_interface_unavailable')\n  }\n  if (error instanceof Error && error.message === 'cpolar_authtoken_invalid') {\n    return new HttpError(400, 'cpolar_authtoken_invalid')\n  }\n  if (error instanceof Error && error.message.startsWith('cpolar_')) {\n    return new HttpError(409, error.message)\n  }\n  // Component download and hash failures carry their own stable code, so the panel can show why an\n  // install failed instead of a generic server error.\n  if (error instanceof Error && error.message.startsWith('cloudflared_')) {\n    return new HttpError(409, error.message)\n  }\n  if (error instanceof Error && [\n    'frp_server_address_invalid',\n    'frp_server_port_invalid',\n    'frp_token_invalid',\n    'frp_public_origin_invalid',\n    'frp_settings_invalid',\n  ].includes(error.message)) return new HttpError(400, error.message)\n  // Attach-mode codes are environment/precondition conflicts by design:\n  // `frp_attach_mode_requires_vhost_port` (the user's frps port is unknown),\n  // `frp_attach_cert_unknown` (the ingress certificate is missing or unusable),\n  // and `frp_entry_tls_invalid` (the requested entry mode cannot be provisioned)\n  // all map to 409 here, while a reachable plaintext vhost keeps the upstream\n  // `frp_vhost_publicly_reachable` / `frp_vhost_probe_failed` codes.\n  if (error instanceof Error && error.message.startsWith('frp_')) {\n    return new HttpError(409, error.message)\n  }\n  if (error instanceof Error && [\n    'origin_settings_invalid', 'origin_public_origin_invalid', 'origin_listen_host_invalid',\n    'origin_listen_port_invalid', 'origin_listen_port_reserved', 'origin_allowed_cidrs_invalid',\n  ].includes(error.message)) return new HttpError(400, error.message)\n  if (error instanceof Error && error.message.startsWith('origin_')) {\n    return new HttpError(409, error.message)\n  }\n  if (error instanceof Error && error.message.startsWith('vps_')) {\n    return new HttpError(409, error.message)\n  }\n  if (error instanceof Error && error.message === 'plugin_update_failed') {\n    return new HttpError(500, error.message)\n  }\n  if (error instanceof Error && error.message.startsWith('plugin_update_')) {\n    return new HttpError(409, error.message)\n  }\n  if (error instanceof Error && error.message.startsWith('lan_setup_')) {\n    return new HttpError(409, error.message)\n  }\n  return new HttpError(500, 'internal_error')\n}\n\nconst SETUP_KEYS = new Set([\n  'version', 'publicOrigin', 'listenHost', 'listenPort', 'upstreamOrigin',\n  'publicAuthorities', 'allowedCidrs', 'instanceId', 'pairingCaFile', 'tls',\n])\n\n/** True when path names a regular file (not a directory or symlink). */\nasync function existsRegularFile(path: string): Promise<boolean> {\n  try {\n    const info = await lstat(path)\n    return info.isFile() && !info.isSymbolicLink()\n  } catch {\n    return false\n  }\n}\n\ntype LoadedSetup = {\n  readonly kind: 'fixed'\n  readonly config: PluginConfig\n} | {\n  readonly kind: 'unconfigured'\n  readonly config: PluginConfig\n  readonly setupFile: string\n} | {\n  readonly kind: 'managed'\n  readonly config: PluginConfig\n  readonly setup: ManagedSetup\n  readonly setupFile: string\n}\n\nfunction withoutSetupKeys(config: PluginConfig): PluginConfig {\n  const merged = { ...config } as Record<string, unknown>\n  for (const key of SETUP_KEYS) if (key !== 'version') delete merged[key]\n  return merged as unknown as PluginConfig\n}\n\nasync function loadSetup(config: PluginConfig): Promise<LoadedSetup> {\n  if (config.setupFile === undefined) return { kind: 'fixed', config }\n  if (!isAbsolute(config.setupFile)) throw new Error('setupFile must be an absolute file path')\n  let source: string\n  try {\n    source = await readFile(resolve(config.setupFile), 'utf8')\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n      return { kind: 'unconfigured', config, setupFile: resolve(config.setupFile) }\n    }\n    throw error\n  }\n  let parsed: unknown\n  try { parsed = JSON.parse(source) as unknown }\n  catch (error) { throw new Error('mobile setup file is not valid JSON', { cause: error }) }\n  if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n    throw new Error('mobile setup file must be an object')\n  }\n  const record = parsed as Record<string, unknown>\n  if (record.version === 2) {\n    return { kind: 'managed', config: withoutSetupKeys(config), setup: parseManagedSetup(record), setupFile: resolve(config.setupFile) }\n  }\n  if (record.version !== 1 || Reflect.ownKeys(record).some(key => typeof key !== 'string' || !SETUP_KEYS.has(key))) {\n    throw new Error('mobile setup file has an unsupported format')\n  }\n  const { version: _version, ...setup } = record\n  delete setup.upstreamOrigin\n  return {\n    kind: 'fixed',\n    config: { ...withoutSetupKeys(config), ...setup } as unknown as PluginConfig,\n  }\n}\n\nfunction loopbackTemplate(loaded: LoadedSetup, webServerPort: number): ResolvedGatewayConfig {\n  const base = withoutSetupKeys(loaded.config)\n  const activeUpstreamOrigin = `http://127.0.0.1:${String(webServerPort)}`\n  return parseGatewayConfig({\n    ...base,\n    ...(loaded.kind === 'managed'\n      ? { upstreamOrigin: activeUpstreamOrigin }\n      : { upstreamOrigin: loaded.config.upstreamOrigin ?? activeUpstreamOrigin }),\n    listenHost: '127.0.0.1',\n    listenPort: 0,\n    publicAuthorities: ['127.0.0.1'],\n    allowedCidrs: ['127.0.0.0/8'],\n    tls: { mode: 'disabled' },\n  })\n}\n\nasync function stableInstanceId(loaded: LoadedSetup, template: ResolvedGatewayConfig): Promise<string> {\n  if (loaded.kind !== 'managed') return loaded.config.instanceId ?? template.instanceId\n  const certificate = new X509Certificate(await readFile(loaded.setup.tls.caCertFile))\n  return certificate.fingerprint256.replaceAll(':', '').toLowerCase()\n}\n\nexport function remoteGatewayConfig(\n  template: ResolvedGatewayConfig,\n  publicOrigin: string,\n  stateFile: string,\n  instanceId: string,\n  listenPort = 0,\n): ResolvedGatewayConfig {\n  const origin = new URL(publicOrigin)\n  if (origin.protocol !== 'https:' || origin.username !== '' || origin.password !== ''\n    || origin.pathname !== '/' || origin.search !== '' || origin.hash !== '') {\n    throw new Error('remote public origin must be an HTTPS origin')\n  }\n  // The gateway listens on an ephemeral loopback port behind Funnel, while the\n  // public authority is HTTPS on 443. Keep that external port explicit so the\n  // trust policy never substitutes the private listener port into QR URLs.\n  const publicAuthority = origin.port === '' ? `${origin.hostname}:443` : origin.host\n  const { pairingCaFile: _pairingCaFile, ...shared } = template\n  return Object.freeze({\n    ...shared,\n    listenHost: '127.0.0.1',\n    listenPort,\n    authorities: Object.freeze([parseAuthority(publicAuthority)]),\n    allowedCidrs: Object.freeze([parseCidr('127.0.0.0/8')]),\n    stateFile,\n    instanceId,\n    tls: Object.freeze({ mode: 'disabled' }),\n    publicTls: true,\n    discovery: false,\n  })\n}\n\n/**\n * Gateway config for the self-signed FRP ingress.\n *\n * Unlike {@link remoteGatewayConfig}, the gateway itself is the TLS endpoint:\n * frps only forwards raw TCP, so the listener speaks HTTPS with the leaf that\n * `pairingCaFile` signed, and the pairing CA is deliberately retained so the\n * gateway can serve `GET /mobile-access/ca.cer` for the app to pin. The listener\n * stays on loopback because the public entry is the frps TCP proxy, never a\n * direct bind.\n */\nexport function frpIngressGatewayConfig(\n  template: ResolvedGatewayConfig,\n  settings: FrpSettings,\n  stateFile: string,\n  ingress: Pick<FrpIngressCertificate, 'paths' | 'caFingerprint'>,\n  listenPort = 0,\n): ResolvedGatewayConfig {\n  if (!isFrpSelfSignedIngress(settings)) throw new Error('frp_entry_tls_invalid')\n  const publicHost = new URL(settings.publicOrigin).hostname\n  const publicAuthority = `${publicHost}:${String(resolveFrpPublicPort(settings))}`\n  const { pairingCaFile: _templateCaFile, ...shared } = template\n  return Object.freeze({\n    ...shared,\n    listenHost: '127.0.0.1',\n    listenPort,\n    authorities: Object.freeze([parseAuthority(publicAuthority)]),\n    // Only frpc originates the connection, from the same computer.\n    allowedCidrs: Object.freeze([parseCidr('127.0.0.0/8')]),\n    stateFile,\n    // The app validates `instance` against the CA it pins (gateway.ts checks the\n    // same fingerprint), so this channel must use the CA fingerprint, not the\n    // plugin-wide installation id.\n    instanceId: ingress.caFingerprint,\n    pairingCaFile: ingress.paths.caCertFile,\n    tls: Object.freeze({ mode: 'provided', certFile: ingress.paths.certFile, keyFile: ingress.paths.keyFile }),\n    publicTls: true,\n    discovery: false,\n  })\n}\n\n/**\n * CA the FRP start-up self-check must pin, read from the ingress directory.\n *\n * The self-signed entry presents a leaf signed by this CA, which is absent from\n * the system trust store, so the probe must anchor it exactly as the app does\n * when it pins `pairingCaFile`. The public-CA entry answers with a publicly\n * trusted certificate and therefore returns `undefined` (system trust store).\n * An unreadable self-signed CA fails explicitly: falling back to the system\n * trust store would hide a broken pairing identity behind a start timeout.\n */\nexport async function readFrpIngressTrustAnchor(settings: FrpSettings, stateFile: string, ownedRoot: string = dirname(stateFile)): Promise<string | undefined> {\n  if (!isFrpSelfSignedIngress(settings)) return undefined\n  try {\n    const file = frpIngressPaths(stateFile).caCertFile\n    await assertManagedParents(ownedRoot, file, 'frp_ingress')\n    const entry = await lstat(file)\n    if (!entry.isFile() || entry.isSymbolicLink()) throw new Error('frp_ingress_file_invalid')\n    return await readFile(file, 'utf8')\n  } catch (error) {\n    throw new Error('frp_ingress_ca_invalid', { cause: error })\n  }\n}\n\n/** Reuse remote HTTPS policy while binding a separately validated private HTTP origin. */\nexport function originGatewayConfig(\n  template: ResolvedGatewayConfig,\n  settings: OriginSettings,\n  stateFile: string,\n  instanceId: string,\n  listenPort = settings.listenPort,\n): ResolvedGatewayConfig {\n  const validated = parseOriginSettings(settings)\n  // Port zero is available only to in-process tests, never to saved settings.\n  if (listenPort !== 0) validateOriginListenPort(listenPort)\n  return Object.freeze({\n    ...remoteGatewayConfig(template, validated.publicOrigin, stateFile, instanceId, listenPort),\n    listenHost: validated.listenHost,\n    allowedCidrs: Object.freeze(validated.allowedCidrs.map(parseCidr)),\n  })\n}\n\nfunction remoteControlPayload(\n  provider: RemoteProvider,\n  status: RemoteProviderStatus,\n  gateway: MobileAccessGateway | undefined,\n  providerStatuses: Readonly<Record<RemoteProvider, RemoteProviderStatus>>,\n  cpolarComponent: CpolarComponentStatus,\n  cloudflaredComponent: CloudflaredComponentStatus,\n  cloudflaredConfiguration: CloudflaredTunnelStatus,\n  frpComponent: FrpComponentStatus,\n  frpConfiguration: FrpConfigurationStatus,\n  originConfiguration: OriginConfigurationStatus,\n  caddyComponentStatus: CaddyComponentStatus,\n): Record<string, unknown> {\n  return {\n    provider,\n    running: status.enabled,\n    state: status.state,\n    ...(status.origin === undefined ? {} : { origin: status.origin }),\n    ...(status.backendOrigin === undefined ? {} : { backendOrigin: status.backendOrigin }),\n    ...(status.loginUrl === undefined ? {} : { loginUrl: status.loginUrl }),\n    ...(status.setupUrl === undefined ? {} : { setupUrl: status.setupUrl }),\n    ...(status.errorCode === undefined ? {} : { errorCode: status.errorCode }),\n    ...(gateway === undefined ? {} : { extensions: gateway.extensionStatus() }),\n    providers: {\n      tailscale: { bundled: true, running: providerStatuses.tailscale.enabled, state: providerStatuses.tailscale.state },\n      cpolar: {\n        bundled: false,\n        running: providerStatuses.cpolar.enabled,\n        state: providerStatuses.cpolar.state,\n        component: cpolarComponent,\n      },\n      cloudflared: {\n        bundled: false,\n        running: providerStatuses.cloudflared.enabled,\n        state: providerStatuses.cloudflared.state,\n        component: cloudflaredComponent,\n        configuration: cloudflaredConfiguration,\n      },\n      frp: {\n        bundled: false,\n        running: providerStatuses.frp.enabled,\n        state: providerStatuses.frp.state,\n        component: frpComponent,\n        configuration: frpConfiguration,\n      },\n      origin: {\n        bundled: true,\n        running: providerStatuses.origin.enabled,\n        state: providerStatuses.origin.state,\n        configuration: originConfiguration,\n        component: caddyComponentStatus,\n      },\n    },\n  }\n}\n\n/** Mount the resident control route and its optional authenticated LAN gateway. */\nexport async function apply(ctx: Context, config: PluginConfig): Promise<void> {\n  const dshVersion = installedDshVersion()\n  const loaded = await loadSetup(config)\n  const mobileAccess: MobileAccessService = createMobileAccessService(ctx)\n  const template = loopbackTemplate(loaded, ctx.webServer.port)\n  const upstreamLoginUrl = upstreamAuthenticatedUrl(ctx, template.upstreamOrigin)\n  const instanceId = await stableInstanceId(loaded, template)\n  const stateDirectory = dirname(template.stateFile)\n  const logFile = await installMobileFileLogger(ctx, stateDirectory)\n  const logger = ctx.logger('dsh-mobile')\n  logger.info('logging initialized file=%s', logFile)\n  // Completed root turns fan out to every live mobile gateway, whose phones\n  // render the notification text locally. One subscription serves all paths.\n  const taskEventHub = new TaskEventHub()\n  const disposeTaskEvents = watchTaskCompletions(ctx, {\n    onTaskCompleted: event => taskEventHub.broadcast(event),\n    log(event, fields) { logger.info('task event=%s fields=%o', event, fields) },\n  })\n  const remoteDirectory = join(stateDirectory, 'remote')\n  const configuredDshHome = process.env.DSH_HOME?.trim()\n  const dshHome = configuredDshHome === undefined || configuredDshHome === ''\n    ? dirname(stateDirectory)\n    : resolve(configuredDshHome)\n  const releaseManager = new PluginReleaseManager({\n    profileDirectory: releaseProfileDirectory(ctx, dshHome, process.argv.slice(2)),\n  })\n  const remoteProviderStore = new JsonRemoteProviderStore(\n    join(remoteDirectory, 'provider.json'),\n    configuredRemoteProvider(process.env),\n  )\n  const initialRemoteProvider = (await remoteProviderStore.load()).provider\n  const cpolarComponent = new CpolarComponentManager({ stateDirectory })\n  await cpolarComponent.initialize()\n  const cloudflaredComponent = new CloudflaredComponentManager({ stateDirectory })\n  await cloudflaredComponent.initialize()\n  const frpComponent = new FrpComponentManager({ stateDirectory })\n  await frpComponent.initialize()\n  // FRP registration persists across LAN setup changes, while the gateway's\n  // pairing identity may change when an unconfigured setup becomes managed.\n  const frpIdentity = await loadOrCreateInstallationId(join(stateDirectory, 'installation-id'))\n  const frpConfig = new FrpConfigStore(join(remoteDirectory, 'frp', 'config'), frpProxyName(frpIdentity), stateDirectory)\n  await frpConfig.initialize()\n  const originConfig = new OriginConfigStore(join(remoteDirectory, 'origin', 'config'), stateDirectory)\n  await originConfig.initialize()\n  const caddyComponent = new CaddyComponentManager({ stateDirectory })\n  await caddyComponent.initialize()\n  const caddyConfig = new CaddyConfigStore(stateDirectory)\n  await caddyConfig.initialize()\n  const cloudflaredTunnel = new CloudflaredTunnelStore(join(remoteDirectory, 'cloudflared'), stateDirectory)\n  await cloudflaredTunnel.initialize()\n  const unregisterBuiltin = mobileAccess.registerExtension({\n    schemaVersion: 1,\n    id: 'computer-images',\n    name: 'Computer images',\n    version: '1.0.0',\n    description: 'Authenticated computer-side image browser',\n    routes: [\n      {\n        method: 'GET', path: 'list',\n        async handle(request) {\n          return { status: 200, contentType: 'application/json; charset=utf-8', body: JSON.stringify(await listComputerImages(request.query.get('path'))) }\n        },\n      },\n      {\n        method: 'GET', path: 'image',\n        async handle(request) {\n          const image = await readComputerImage(request.query.get('path'))\n          return { status: 200, contentType: image.contentType, headers: { 'content-disposition': `inline; filename*=UTF-8''${encodeURIComponent(image.name)}` }, body: image.body }\n        },\n      },\n    ],\n  })\n  // One upgrade-path policy shared by the LAN gateway and every remote\n  // gateway: admin approvals apply immediately, no restart required.\n  const webSocketPaths = new WebSocketPathStore(join(stateDirectory, 'websocket-paths.json'))\n  await webSocketPaths.load()\n  const blockedUpgradePaths = new BlockedUpgradePathLog()\n  const clientModulePreferences = new ClientModulePreferenceStore(join(stateDirectory, 'client-modules.json'), template.excludedClientModules)\n  await clientModulePreferences.initialize()\n  let lanGateway: MobileAccessGateway | undefined\n  let preparedLanSetup: ManagedLanSetupResult | undefined\n  let trustedNetworksRestartRequired = false\n  let trustedNetworksWrite: Promise<void> = Promise.resolve()\n  let adminClosing = false\n  const startGateway = async (candidateConfig: PluginConfig): Promise<MobileAccessRuntime> => {\n    const resolved = parseGatewayConfig({\n      ...candidateConfig,\n      upstreamOrigin: template.upstreamOrigin.origin,\n    })\n    const candidate = new MobileAccessGateway(\n      resolved,\n      new JsonDeviceStore(resolved.stateFile, resolved.maxDevices),\n      mobileAccess,\n      upstreamLoginUrl,\n      webSocketPaths,\n      blockedUpgradePaths,\n      (source, code) => { logger.warn('%s discovery degraded while DSH remains available: %s', source, code) },\n      clientModulePreferences,\n    )\n    await candidate.start()\n    lanGateway = candidate\n    const removeTaskSink = taskEventHub.add(candidate)\n    return {\n      close: async () => {\n        if (lanGateway === candidate) lanGateway = undefined\n        removeTaskSink()\n        await candidate.close()\n      },\n    }\n  }\n  const startRuntime = async (): Promise<MobileAccessRuntime> => {\n    if (loaded.kind === 'unconfigured') throw new Error(preparedLanSetup === undefined ? 'lan_setup_required' : 'lan_setup_restart_required')\n    if (loaded.kind === 'fixed') return startGateway(loaded.config)\n    const following = new FollowingMobileAccessRuntime(async () => {\n      const network = selectLanNetwork(undefined, loaded.setup.networkInterface)\n      return {\n        key: `${network.name}\\0${network.address}\\0${network.cidr}`,\n        start: async () => startGateway({\n          ...loaded.config,\n          ...await materializeManagedSetup(loaded.setup),\n        }),\n      }\n    }, (error) => {\n      process.emitWarning(`DSH Mobile could not follow the current LAN address: ${error instanceof Error ? error.message : String(error)}`, {\n        code: 'DSH_MOBILE_NETWORK_REFRESH',\n      })\n    })\n    try {\n      await following.initialize(2_000)\n    } catch (error) {\n      // A missing saved interface (Wi-Fi/Ethernet switch, docked laptop…)\n      // must not take down all of DSH: stay dormant with the poller armed so\n      // a returning network recovers on its own. Anything else is a real\n      // failure and still fails boot loudly.\n      if (!isNetworkSelectionError(error)) throw error\n      const detail = error instanceof Error ? error.message : String(error)\n      process.emitWarning(\n        `DSH Mobile: ${detail}; mobile access stays dormant until the network returns or setup is re-run — DSH itself keeps running.`,\n        { code: 'DSH_MOBILE_NETWORK_UNAVAILABLE' },\n      )\n      following.beginPolling(2_000)\n    }\n    return following\n  }\n  const lanControlFile = parseControlFile(config.controlFile)\n  const lanControlStore = new JsonMobileAccessControlStore(lanControlFile, config.initiallyEnabled)\n  if (loaded.kind === 'unconfigured' && (await lanControlStore.load()).enabled) {\n    await lanControlStore.save({ version: 1, enabled: false })\n  }\n  const lanController = new MobileAccessGatewayController(lanControlStore, startRuntime)\n  const remoteDeviceFile = join(remoteDirectory, 'devices.json')\n  const legacyCpolarDeviceFile = join(remoteDirectory, 'cpolar', 'devices.json')\n  if (initialRemoteProvider === 'cpolar') {\n    try {\n      await lstat(remoteDeviceFile)\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n      try { await copyFile(legacyCpolarDeviceFile, remoteDeviceFile) } catch (copyError) {\n        if ((copyError as NodeJS.ErrnoException).code !== 'ENOENT') throw copyError\n      }\n    }\n  }\n  const createRemoteGateway = async (publicOrigin: string, listenPort = 0): Promise<MobileAccessGateway> => {\n      const resolved = remoteGatewayConfig(\n        template,\n        publicOrigin,\n        remoteDeviceFile,\n        instanceId,\n        listenPort,\n      )\n      const candidate = new MobileAccessGateway(\n        resolved,\n        new JsonDeviceStore(resolved.stateFile, resolved.maxDevices),\n        mobileAccess,\n        upstreamLoginUrl,\n        webSocketPaths,\n        blockedUpgradePaths,\n        undefined,\n        clientModulePreferences,\n      )\n      await candidate.start()\n      return candidate\n  }\n  /**\n   * Gateway factory for the FRP provider.\n   *\n   * The public-CA entry keeps the ordinary Caddy-fronted remote gateway. The\n   * self-signed entry terminates TLS inside the gateway, so it first materializes\n   * a leaf the pairing CA signed for the public IPv4 and then binds the ingress\n   * configuration that keeps that CA pinned.\n   */\n  const createFrpGateway = async (publicOrigin: string, settings: FrpSettings): Promise<MobileAccessGateway> => {\n    if (!isFrpSelfSignedIngress(settings)) return createRemoteGateway(publicOrigin)\n    const ingress = await ensureFrpIngressCertificate(settings, remoteDeviceFile, Date.now(), undefined, stateDirectory)\n    const resolved = frpIngressGatewayConfig(template, settings, remoteDeviceFile, ingress)\n    const candidate = new MobileAccessGateway(\n      resolved,\n      new JsonDeviceStore(resolved.stateFile, resolved.maxDevices),\n      mobileAccess,\n      upstreamLoginUrl,\n      webSocketPaths,\n      blockedUpgradePaths,\n      undefined,\n      clientModulePreferences,\n    )\n    try { await candidate.start() } catch (error) {\n      await candidate.close()\n      throw error\n    }\n    return candidate\n  }\n  const createOriginGateway = async (settings: OriginSettings): Promise<MobileAccessGateway> => {\n    const resolved = originGatewayConfig(template, settings, remoteDeviceFile, instanceId)\n    const candidate = new MobileAccessGateway(\n      resolved, new JsonDeviceStore(resolved.stateFile, resolved.maxDevices), mobileAccess,\n      upstreamLoginUrl, webSocketPaths, blockedUpgradePaths, undefined, clientModulePreferences,\n    )\n    try { await candidate.start() } catch (error) {\n      await candidate.close()\n      throw error\n    }\n    return candidate\n  }\n  const tailscaleStore = new JsonMobileAccessControlStore(join(remoteDirectory, 'control.json'), false)\n  const cpolarStore = new JsonMobileAccessControlStore(join(remoteDirectory, 'cpolar', 'control.json'), false)\n  const cloudflaredStore = new JsonMobileAccessControlStore(join(remoteDirectory, 'cloudflared', 'control.json'), false)\n  const frpStore = new JsonMobileAccessControlStore(join(remoteDirectory, 'frp', 'control.json'), false)\n  const originStore = new JsonMobileAccessControlStore(join(remoteDirectory, 'origin', 'control.json'), false)\n  const caddyController = new CaddyController({\n    store: createVolatileRemoteControlStore(),\n    component: caddyComponent,\n    config: caddyConfig,\n    instanceId,\n    createGateway: settings => createRemoteGateway(settings.publicOrigin),\n  })\n  const originController = new ManagedOriginController({\n    store: originStore,\n    modeStore: new JsonOriginModeStore(join(remoteDirectory, 'origin', 'upstream.json')),\n    external: new OriginController({ store: createVolatileRemoteControlStore(), config: originConfig, createGateway: createOriginGateway }),\n    managed: caddyController,\n  })\n  const remoteControllers: Record<RemoteProvider, RemoteProviderController> = {\n    tailscale: new FunnelController({\n      store: tailscaleStore,\n      executable: funnelExecutable(import.meta.url),\n      stateDirectory: join(remoteDirectory, 'tailscale'),\n      ownedRoot: stateDirectory,\n      hostname: `dsh-${instanceId.slice(0, 12)}`,\n      createGateway: createRemoteGateway,\n    }),\n    cpolar: new CpolarController({\n      store: cpolarStore,\n      executable: cpolarComponent.executable,\n      configFile: cpolarComponent.configFile,\n      createGateway: createRemoteGateway,\n    }),\n    cloudflared: new CloudflaredController({\n      store: cloudflaredStore,\n      executable: cloudflaredComponent.executable,\n      tunnel: cloudflaredTunnel,\n      createGateway: createRemoteGateway,\n    }),\n    frp: new FrpController({\n      store: frpStore,\n      executable: frpComponent.executable,\n      config: frpConfig,\n      instanceId,\n      createGateway: createFrpGateway,\n      /**\n       * Hand the start-up self-check the CA the app itself pins.\n       *\n       * Only this module knows where the ingress material lives, so the anchor is\n       * read here from the ingress directory instead of being guessed downstream.\n       */\n      resolveDiscoveryTrustAnchor: settings => readFrpIngressTrustAnchor(settings, remoteDeviceFile, stateDirectory),\n      maintainIngressCertificate: async (settings, gateway) => {\n        await ensureFrpIngressCertificate(settings, remoteDeviceFile, Date.now(), gateway.config.instanceId, stateDirectory)\n        await gateway.refreshProvidedTls()\n      },\n    }),\n    origin: originController,\n  }\n  const remoteProviders = new RemoteProviderCoordinator(initialRemoteProvider, remoteControllers, remoteProviderStore)\n  const remoteController = () => remoteProviders.controller()\n  // Remote gateways rotate inside their controllers; forward through the\n  // current instance so stale gateways never receive events.\n  for (const provider of REMOTE_PROVIDERS) {\n    const controller = remoteControllers[provider]\n    taskEventHub.add({ broadcastTaskEvent: event => { controller.gateway()?.broadcastTaskEvent(event) } })\n  }\n  const remotePayload = (): Record<string, unknown> => ({ ...remoteControlPayload(\n    remoteProviders.selected,\n    remoteController().status(),\n    remoteController().gateway(),\n    {\n      tailscale: remoteControllers.tailscale.status(),\n      cpolar: remoteControllers.cpolar.status(),\n      cloudflared: remoteControllers.cloudflared.status(),\n      frp: remoteControllers.frp.status(),\n      origin: remoteControllers.origin.status(),\n    },\n    cpolarComponent.status(),\n    cloudflaredComponent.status(),\n    cloudflaredTunnel.status(),\n    frpComponent.status(),\n    frpConfig.status(),\n    originConfig.status(),\n    caddyComponent.status(),\n  ), originMode: originController.mode(), caddyConfiguration: caddyConfig.status(), caddyState: caddyController.status() })\n  const lanPayload = (): Record<string, unknown> => ({\n    ...(loaded.kind === 'unconfigured' ? {\n      configured: preparedLanSetup !== undefined,\n      restartRequired: preparedLanSetup !== undefined,\n    } : {}),\n    running: lanController.isRunning(),\n    origin: lanGateway?.address().origin,\n    ...(preparedLanSetup === undefined ? {} : { pendingOrigin: preparedLanSetup.origin }),\n    ...(lanGateway === undefined ? {} : { extensions: lanGateway.extensionStatus() }),\n  })\n  const lanSetupPayload = async (): Promise<Record<string, unknown>> => {\n    if (loaded.kind !== 'unconfigured' || preparedLanSetup !== undefined) return lanPayload()\n    const networks = availableLanNetworks()\n    const preferred = await preferredLanInterfaceNames()\n    let recommendedAddress: string | undefined\n    try { recommendedAddress = selectLanNetwork(undefined, undefined, undefined, preferred).address } catch { /* user chooses when selection is ambiguous */ }\n    return {\n      ...lanPayload(),\n      networks: networks.map(network => ({\n        name: network.name,\n        address: network.address,\n        cidr: network.cidr,\n        recommended: network.address === recommendedAddress,\n      })),\n      listenPort: 3443,\n      windowsFirewall: process.platform === 'win32',\n    }\n  }\n\n  const trustedNetworksPayload = async (): Promise<Record<string, unknown>> => {\n    if (loaded.kind !== 'managed') return { supported: false }\n    const saved = parseManagedSetup(JSON.parse(await readFile(loaded.setupFile, 'utf8')))\n    return {\n      supported: true,\n      extraAllowedCidrs: saved.extraAllowedCidrs ?? [],\n      restartRequired: trustedNetworksRestartRequired,\n      windowsFirewall: process.platform === 'win32',\n    }\n  }\n  const diagnosticsPayload = async (): Promise<Record<string, unknown>> => {\n    let interfaceName: string | undefined\n    let networkError: string | undefined\n    if (loaded.kind === 'managed') {\n      try { interfaceName = selectLanNetwork(undefined, loaded.setup.networkInterface).name }\n      catch { networkError = 'network_interface_unavailable' }\n    }\n    const remote = remoteController().status()\n    const frpOrigin = remote.origin\n    const frpSettings = remoteProviders.selected === 'frp' ? frpConfig.settings() : undefined\n    const frpGateway = remoteControllers.frp.gateway()\n    const pinnedFrpProbe = frpSettings !== undefined && isFrpSelfSignedIngress(frpSettings)\n      && frpGateway !== undefined && frpOrigin !== undefined\n      ? async (): Promise<{ state: 'ready' | 'unreachable'; latencyMs?: number }> => {\n          try {\n            const trustAnchorPem = await readFrpIngressTrustAnchor(frpSettings, remoteDeviceFile, stateDirectory)\n            if (trustAnchorPem === undefined) return { state: 'unreachable' }\n            const started = performance.now()\n            const reachable = await defaultProbeDiscovery(\n              { origin: frpOrigin, trustAnchorPem },\n              frpGateway.config.instanceId,\n              AbortSignal.timeout(5_500),\n            )\n            return reachable\n              ? { state: 'ready', latencyMs: Math.max(0, Math.round(performance.now() - started)) }\n              : { state: 'unreachable' }\n          } catch {\n            return { state: 'unreachable' }\n          }\n        }\n      : undefined\n    return collectConnectionDiagnostics({\n      dshVersion,\n      competingRemoteChannelBoot: hasCompetingRemoteChannelBoot(ctx.webServer.collectIndexInjections?.() ?? []),\n      lan: {\n        configured: loaded.kind !== 'unconfigured' || preparedLanSetup !== undefined,\n        running: lanController.isRunning(),\n        ...(lanGateway === undefined ? {} : { origin: lanGateway.address().origin, port: lanGateway.address().port }),\n        ...(loaded.kind === 'managed' ? { configuredInterface: loaded.setup.networkInterface, port: loaded.setup.listenPort } : {}),\n        ...(interfaceName === undefined ? {} : { interfaceName }),\n        ...(networkError === undefined ? {} : { networkError }),\n      },\n      remote: {\n        provider: remoteProviders.selected,\n        running: remote.enabled,\n        state: remote.state,\n        ...(remote.origin === undefined ? {} : { origin: remote.origin }),\n        ...(remote.errorCode === undefined ? {} : { errorCode: remote.errorCode }),\n      },\n    }, pinnedFrpProbe === undefined ? {} : { remote: pinnedFrpProbe }) as unknown as Record<string, unknown>\n  }\n\n  const authenticateDesktopAdmin = (request: IncomingMessage): boolean => {\n    const connection = (ctx as Context & { readonly connection?: BrowserAuthenticatedConnection }).connection\n    return typeof connection?.requestRejection === 'function'\n      && connection.requestRejection(request) === undefined\n  }\n\n  const adminRoute: WebRoute = {\n    kind: 'prefix',\n    path: LOCAL_ADMIN_PREFIX,\n    handler: async (request, response) => {\n      try {\n        const target = parseRequestTarget(request.url)\n        assertLocalAdminTrust(request, request.method === 'POST', () => authenticateDesktopAdmin(request))\n        if (adminClosing) throw new HttpError(503, 'unavailable')\n        if (target.search !== '') throw new HttpError(400, 'bad_request')\n        const lanControl = target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/control`\n          || target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/lan/control`\n        if (request.method === 'GET' && lanControl) {\n          sendJson(response, 200, lanPayload(), false)\n          return\n        }\n        if (request.method === 'GET' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/lan/setup`) {\n          sendJson(response, 200, await lanSetupPayload(), false)\n          return\n        }\n        if (target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/client-modules`) {\n          const gateway = lanGateway ?? remoteController().gateway()\n          if (gateway === undefined) throw new HttpError(409, 'mobile_access_not_running')\n          const operation = new AbortController()\n          const abort = (): void => { operation.abort() }\n          response.once('close', abort)\n          try {\n            if (request.method === 'GET') {\n              sendJson(response, 200, await gateway.describeClientModules(undefined, operation.signal), false)\n              return\n            }\n            if (request.method !== 'POST') throw new HttpError(405, 'method_not_allowed')\n            const body = await readJsonObject(request, template.maxBodyBytes)\n            if (Object.keys(body).length !== 1 || Object.keys(body).some(key => key !== 'reset' && key !== 'excludedClientModules')) throw new HttpError(400, 'bad_request')\n            const view = body.reset === true\n              ? await gateway.resetClientModules(undefined, operation.signal)\n              : await gateway.configureClientModules(body.excludedClientModules, undefined, operation.signal)\n            sendJson(response, 200, view, false)\n          } catch (error) {\n            if (!(error instanceof ClientModuleConflictError)) throw error\n            sendJson(response, 409, { error: 'excluded_client_modules_invalid', detail: error.detail }, false)\n          } finally {\n            response.removeListener('close', abort)\n            operation.abort()\n          }\n          return\n        }\n        if (target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/lan/trusted-networks`) {\n          if (request.method === 'GET') {\n            sendJson(response, 200, await trustedNetworksPayload(), false)\n            return\n          }\n          if (request.method !== 'POST') throw new HttpError(405, 'method_not_allowed')\n          if (loaded.kind !== 'managed') throw new HttpError(409, 'lan_trusted_networks_unavailable')\n          const body = await readJsonObject(request, 4096)\n          let values: readonly string[]\n          try { values = parseAdditionalTrustedNetworks(body.extraAllowedCidrs) }\n          catch { throw new HttpError(400, 'lan_trusted_networks_invalid') }\n          const write = trustedNetworksWrite.then(async () => {\n            if (adminClosing) throw new HttpError(503, 'unavailable')\n            await saveManagedTrustedNetworks(loaded.setupFile, values)\n            trustedNetworksRestartRequired = true\n          })\n          trustedNetworksWrite = write.catch(() => undefined)\n          await write\n          sendJson(response, 200, await trustedNetworksPayload(), false)\n          return\n        }\n        if (request.method === 'GET' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/diagnostics`) {\n          sendJson(response, 200, await diagnosticsPayload(), false)\n          return\n        }\n        if (request.method === 'GET' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/release`) {\n          sendJson(response, 200, await releaseManager.status(), false)\n          return\n        }\n        if (request.method === 'GET' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/extensions/hosts`) {\n          sendJson(response, 200, mobileAccess.hostStatus(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/extensions/recover`) {\n          const body = await readJsonObject(request, 4096)\n          if (typeof body.id !== 'string' || body.confirm !== true) throw new HttpError(400, 'bad_request')\n          await mobileAccess.recoverExtension(body.id)\n          sendJson(response, 200, mobileAccess.hostStatus(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/release/update`) {\n          await readJsonObject(request, 4096)\n          sendJson(response, 200, await releaseManager.update(), false)\n          return\n        }\n        if (request.method === 'POST' && lanControl) {\n          const body = await readJsonObject(request, 4096)\n          if (typeof body.running !== 'boolean') throw new HttpError(400, 'bad_request')\n          if (body.running && loaded.kind === 'unconfigured') {\n            throw new HttpError(409, preparedLanSetup === undefined ? 'lan_setup_required' : 'lan_setup_restart_required')\n          }\n          await lanController.setRunning(body.running)\n          sendJson(response, 200, lanPayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/lan/setup`) {\n          const body = await readJsonObject(request, 4096)\n          if (loaded.kind !== 'unconfigured') throw new HttpError(409, 'lan_setup_already_configured')\n          if (preparedLanSetup !== undefined) {\n            sendJson(response, 200, await lanSetupPayload(), false)\n            return\n          }\n          if (body.confirm !== true || typeof body.address !== 'string') throw new HttpError(400, 'bad_request')\n          const network = availableLanNetworks().find(candidate => candidate.address === body.address)\n          if (network === undefined) throw new HttpError(409, 'lan_setup_network_unavailable')\n          try {\n            preparedLanSetup = await prepareManagedLanSetup({\n              setupFile: loaded.setupFile,\n              controlFile: lanControlFile,\n              network,\n              listenPort: 3443,\n              dshPort: ctx.webServer.port,\n              configureFirewall: body.configureFirewall !== false,\n            })\n          } catch (error) {\n            logger.error('managed LAN setup failed: %s', error instanceof Error ? error.stack ?? error.message : String(error))\n            throw new HttpError(409, 'lan_setup_failed')\n          }\n          sendJson(response, 200, await lanSetupPayload(), false)\n          return\n        }\n        if (request.method === 'GET' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/control`) {\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/provider`) {\n          const body = await readJsonObject(request, 4096)\n          if (body.provider !== 'tailscale' && body.provider !== 'cpolar' && body.provider !== 'cloudflared'\n            && body.provider !== 'frp' && body.provider !== 'origin') {\n            throw new HttpError(400, 'bad_request')\n          }\n          await remoteProviders.select(body.provider)\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/origin/configure`) {\n          const body = await readJsonObject(request, 8192)\n          await remoteProviders.mutate(async () => {\n            await originConfig.configure(body)\n            if (remoteControllers.origin.status().enabled) await remoteControllers.origin.reconnect()\n          })\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/origin/purge`) {\n          const body = await readJsonObject(request, 4096)\n          if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n          await remoteProviders.mutate(async () => {\n            await remoteControllers.origin.setEnabled(false)\n            await originConfig.purge()\n          })\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/cpolar/component/install`) {\n          const body = await readJsonObject(request, 4096)\n          if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n          logger.info('cpolar component install started')\n          try {\n            await remoteProviders.mutate(async () => cpolarComponent.install())\n            logger.info('cpolar component install completed')\n          } catch (error) {\n            const cause = error instanceof Error && error.cause instanceof Error ? error.cause : undefined\n            logger.error('cpolar component install failed: %s%s',\n              error instanceof Error ? error.stack ?? error.message : String(error),\n              cause === undefined ? '' : `; cause: ${cause.message}`)\n            throw error\n          }\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/cpolar/configure`) {\n          const body = await readJsonObject(request, 4096)\n          await remoteProviders.mutate(async () => cpolarComponent.configure(body.authtoken))\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/cpolar/component/purge`) {\n          const body = await readJsonObject(request, 4096)\n          if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n          await remoteProviders.mutate(async () => {\n            await remoteControllers.cpolar.setEnabled(false)\n            await cpolarComponent.purge()\n          })\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/cloudflared/component/install`) {\n          const body = await readJsonObject(request, 4096)\n          if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n          logger.info('cloudflared component install started')\n          try {\n            await remoteProviders.mutate(async () => cloudflaredComponent.install())\n            logger.info('cloudflared component install completed')\n          } catch (error) {\n            logger.error('cloudflared component install failed: %s', error instanceof Error ? error.stack ?? error.message : String(error))\n            throw error\n          }\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/cloudflared/component/purge`) {\n          const body = await readJsonObject(request, 4096)\n          if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n          await remoteProviders.mutate(async () => {\n            await remoteControllers.cloudflared.setEnabled(false)\n            await cloudflaredComponent.purge()\n          })\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/caddy/component/install`) {\n          const body = await readJsonObject(request, 4096)\n          if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n          logger.info('caddy component install started')\n          try {\n            await remoteProviders.mutate(async () => caddyComponent.install())\n            logger.info('caddy component install completed')\n          } catch (error) {\n            logger.error('caddy component install failed: %s', error instanceof Error ? error.stack ?? error.message : String(error))\n            throw error\n          }\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/caddy/settings`) {\n          const body = await readJsonObject(request, 8192)\n          if (body.connect !== undefined && typeof body.connect !== 'boolean') throw new HttpError(400, 'bad_request')\n          const configure = async (): Promise<void> => {\n            if (body.connect === true && !caddyComponent.status().installed) throw new HttpError(409, 'caddy_component_unavailable')\n            await caddyConfig.configure(body.settings, { secretId: body.secretId ?? '', secretKey: body.secretKey ?? '' })\n            if (body.connect === true) {\n              await originController.setEnabled(false)\n              await originController.selectMode('managed')\n              await originController.reconnect()\n            } else if (originController.mode() === 'managed' && originController.status().enabled) await originController.reconnect()\n          }\n          if (body.connect === true) await remoteProviders.mutateSelected('origin', configure)\n          else await remoteProviders.mutate(configure)\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/origin/mode`) {\n          const body = await readJsonObject(request, 4096)\n          if (body.mode !== 'external' && body.mode !== 'managed') throw new HttpError(400, 'bad_request')\n          const mode = body.mode\n          if (mode === 'managed' && !caddyComponent.status().installed) throw new HttpError(409, 'caddy_component_unavailable')\n          await remoteProviders.mutate(async () => { await originController.selectMode(mode) })\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/caddy/component/purge`) {\n          const body = await readJsonObject(request, 4096)\n          if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n          await remoteProviders.mutate(async () => {\n            if (originController.mode() === 'managed') {\n              await originController.setEnabled(false)\n              await originController.selectMode('external')\n            }\n            await caddyComponent.purge()\n            await caddyConfig.purge()\n          })\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/cloudflared/tunnel`) {\n          const body = await readJsonObject(request, 8192)\n          await remoteProviders.mutate(async () => {\n            await cloudflaredTunnel.configure(mergeSavedCloudflaredTunnelSettings(body, cloudflaredTunnel.settings()))\n            // A live connector is bound to the previous hostname, port and token, so\n            // the new configuration only takes effect through a restart.\n            if (remoteControllers.cloudflared.status().enabled) await remoteControllers.cloudflared.reconnect()\n          })\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/cloudflared/tunnel/purge`) {\n          const body = await readJsonObject(request, 4096)\n          if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n          await remoteProviders.mutate(async () => {\n            await remoteControllers.cloudflared.setEnabled(false)\n            await cloudflaredTunnel.purge()\n          })\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/frp/component/install`) {\n          const body = await readJsonObject(request, 4096)\n          if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n          logger.info('frpc component install started')\n          try {\n            await remoteProviders.mutate(async () => frpComponent.install())\n            logger.info('frpc component install completed')\n          } catch (error) {\n            logger.error('frpc component install failed: %s', error instanceof Error ? error.stack ?? error.message : String(error))\n            throw error\n          }\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/frp/configure`) {\n          const body = await readJsonObject(request, 4096)\n          await remoteProviders.mutate(async () => {\n            await frpConfig.configure(body)\n            if (remoteControllers.frp.status().enabled) await remoteControllers.frp.reconnect()\n          })\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/frp/attach-plan`) {\n          const body = await readJsonObject(request, 8192)\n          // Read-only preview: blank fields keep their saved values, and nothing\n          // on the VPS or the local filesystem is touched.\n          const settings = mergeSavedFrpSettings(body, frpConfig.settings())\n          // This route is callable by any same-origin client script. Never return\n          // the saved token, even if a caller asks for an unmasked preview.\n          // The preview must carry the same proxy name the provider writes, so a\n          // copied frpc.toml registers exactly like the managed one.\n          const options = { configFile: frpConfig.runtimeConfigFile, proxyName: frpConfig.proxyName }\n          logger.info('frp attach plan requested mode=%s entryTls=%s vhostHttpPort=%d',\n            settings.mode ?? 'deploy', settings.entryTls ?? 'public-ip-cert', resolveFrpVhostHttpPort(settings))\n          sendJson(response, 200, {\n            ...remotePayload(),\n            frpAttachPlan: createFrpAttachPlan(settings, options),\n            frpAttachTemplate: createFrpAttachTemplate(settings, options),\n          }, false)\n          return\n        }\n        if (request.method === 'GET' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/frp/self-check`) {\n          const settings = frpConfig.settings()\n          if (settings === undefined) throw new HttpError(409, 'frp_config_missing')\n          const check = await frpIngressSelfCheck(settings, remoteDeviceFile, stateDirectory)\n          // TCP reachability is advisory; only authenticated discovery verifies\n          // that the public tunnel reaches this DSH instance.\n          const entry = resolveFrpEntryProbe(settings)\n          const [frpsReachable, entryReachable] = await Promise.all([\n            probeTcpReachable(settings.serverAddress, settings.serverPort),\n            probeTcpReachable(entry.host, entry.port),\n          ])\n          sendJson(response, 200, {\n            ...remotePayload(),\n            frpSelfCheck: {\n              ...check,\n              // Only stable booleans and the CA fingerprint leave this route: no\n              // token, no key material, and no private file paths.\n              frpsReachable,\n              entryReachable,\n              frpc: remoteController().status(),\n              component: frpComponent.status(),\n            },\n          }, false)\n          return\n        }\n        if (request.method === 'GET' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/websocket-paths`) {\n          sendJson(response, 200, { paths: webSocketPaths.list() }, false)\n          return\n        }\n        if (request.method === 'GET' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/websocket-paths/blocked`) {\n          sendJson(response, 200, { blocked: blockedUpgradePaths.report() }, false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/websocket-paths`) {\n          const body = await readJsonObject(request, 4096)\n          if (!Array.isArray(body.paths)) throw new HttpError(400, 'bad_request')\n          const paths = await webSocketPaths.replace(body.paths)\n          logger.info('websocket upgrade paths updated count=%d paths=%o', paths.length, paths)\n          sendJson(response, 200, { paths }, false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/frp/vps/host-keys`) {\n          const body = await readJsonObject(request, 8192)\n          const serverAddress = typeof body.serverAddress === 'string' ? body.serverAddress : ''\n          logger.info('vps host keys requested host=%s sshUser=%s sshPort=%d',\n            serverAddress, String(body.sshUser), Number(body.sshPort))\n          const hostKeys = await fetchVpsHostKeys(serverAddress, {\n            sshUser: body.sshUser,\n            sshPort: body.sshPort,\n            ...(body.sshKeyPath === undefined || body.sshKeyPath === '' ? {} : { sshKeyPath: body.sshKeyPath }),\n          }, {\n            log(event, fields) { logger.info('vps host keys event=%s fields=%o', event, fields) },\n          })\n          for (const key of hostKeys) logger.info('vps host key host=%s type=%s fingerprint=%s', serverAddress, key.keyType, key.fingerprint)\n          sendJson(response, 200, { ...remotePayload(), vpsHostKeys: hostKeys }, false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/frp/vps/deploy`) {\n          const body = await readJsonObject(request, 8192)\n          if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n          logger.info('vps deploy requested host=%s port=%d sshUser=%s sshPort=%d keyProvided=%s fingerprints=%s',\n            String(body.serverAddress), Number(body.serverPort), String(body.sshUser), Number(body.sshPort), body.sshKeyPath === undefined ? 'false' : 'true',\n            Array.isArray(body.hostFingerprints) ? String(body.hostFingerprints.length) : 'none')\n          const deployment = await remoteProviders.mutate(async () => {\n            // Blank fields keep their saved values so a saved token can stay empty.\n            const settings = mergeSavedFrpSettings(body, frpConfig.settings())\n            const result = await deployVps(settings, parseVpsDeploymentInput({\n              sshUser: body.sshUser,\n              sshPort: body.sshPort,\n              ...(body.sshKeyPath === undefined ? {} : { sshKeyPath: body.sshKeyPath }),\n              hostFingerprints: body.hostFingerprints,\n            }), {\n              log(event, fields) { logger.info('vps deploy event=%s fields=%o', event, fields) },\n            })\n            await frpConfig.configure(settings)\n            logger.info('vps deploy completed host=%s origin=%s checks=%d', settings.serverAddress, settings.publicOrigin, result.checks.length)\n            return result\n          })\n          sendJson(response, 200, { ...remotePayload(), vpsDeployment: deployment }, false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/frp/vps/uninstall-script`) {\n          const body = await readJsonObject(request, 4096)\n          const savedTarget = mergeSavedFrpTarget(body, frpConfig.settings())\n          const script = createVpsUninstallScript({\n            serverPort: savedTarget.serverPort,\n            ...(body.certName === undefined || body.certName === '' ? {} : { certName: body.certName }),\n          })\n          sendJson(response, 200, { ...remotePayload(), vpsUninstallScript: script }, false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/frp/vps/uninstall`) {\n          const body = await readJsonObject(request, 8192)\n          if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n          logger.info('vps uninstall requested host=%s sshUser=%s sshPort=%d',\n            String(body.serverAddress), String(body.sshUser), Number(body.sshPort))\n          const removal = await remoteProviders.mutate(async () => {\n            const savedTarget = mergeSavedFrpTarget(body, frpConfig.settings())\n            const result = await uninstallVps(savedTarget.serverAddress, {\n              serverPort: savedTarget.serverPort,\n              ...(body.certName === undefined || body.certName === '' ? {} : { certName: body.certName }),\n            }, parseVpsDeploymentInput({\n              sshUser: body.sshUser,\n              sshPort: body.sshPort,\n              ...(body.sshKeyPath === undefined ? {} : { sshKeyPath: body.sshKeyPath }),\n              hostFingerprints: body.hostFingerprints,\n            }), {\n              log(event, fields) { logger.info('vps uninstall event=%s fields=%o', event, fields) },\n            })\n            logger.info('vps uninstall completed host=%s checks=%d', result.serverAddress, result.checks.length)\n            return result\n          })\n          sendJson(response, 200, { ...remotePayload(), vpsUninstall: removal }, false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/frp/component/purge`) {\n          const body = await readJsonObject(request, 4096)\n          if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n          await remoteProviders.mutate(async () => {\n            await remoteControllers.frp.setEnabled(false)\n            await settleCleanupSteps([\n              () => frpComponent.purge().then(() => undefined),\n              () => frpConfig.purge().then(() => undefined),\n              () => purgeFrpIngressCertificates(remoteDeviceFile, stateDirectory),\n            ])\n          })\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/control`) {\n          const body = await readJsonObject(request, 4096)\n          const running = body.running\n          if (typeof running !== 'boolean') throw new HttpError(400, 'bad_request')\n          await remoteProviders.mutate(async controller => controller.setEnabled(running))\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/reconnect`) {\n          await readJsonObject(request, 4096)\n          await remoteProviders.mutate(async controller => controller.reconnect())\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (request.method === 'POST' && target.decodedPathname === `${LOCAL_ADMIN_PREFIX}/remote/reset`) {\n          const body = await readJsonObject(request, 4096)\n          if (body.confirm !== true) throw new HttpError(400, 'bad_request')\n          await remoteProviders.mutate(async controller => {\n            await controller.reset()\n            await rm(remoteDeviceFile, { force: true })\n          })\n          sendJson(response, 200, remotePayload(), false)\n          return\n        }\n        if (target.decodedPathname.startsWith(`${LOCAL_ADMIN_PREFIX}/remote/`)) {\n          const active = remoteController().gateway()\n          if (active === undefined) throw new HttpError(409, 'gateway_stopped')\n          await active.localAdminRoute(`${LOCAL_ADMIN_PREFIX}/remote`, authenticateDesktopAdmin).handler(request, response)\n          return\n        }\n        if (target.decodedPathname.startsWith(`${LOCAL_ADMIN_PREFIX}/lan/`)) {\n          const active = lanGateway\n          if (active === undefined) throw new HttpError(409, 'gateway_stopped')\n          await active.localAdminRoute(`${LOCAL_ADMIN_PREFIX}/lan`, authenticateDesktopAdmin).handler(request, response)\n          return\n        }\n        const active = lanGateway\n        if (active === undefined) throw new HttpError(409, 'gateway_stopped')\n        await active.localAdminRoute(LOCAL_ADMIN_PREFIX, authenticateDesktopAdmin).handler(request, response)\n      } catch (error) {\n        const mapped = mapAdminError(error)\n        if (response.headersSent) response.destroy()\n        else sendFailure(response, mapped.status, mapped.code, false)\n      }\n    },\n  }\n\n  await ctx.effect(async () => {\n    const unregister = ctx.webServer.register(adminRoute)\n    const stopAdmin = (): void => { adminClosing = true; unregister() }\n    const disposeMobileCommand = ctx.commands.register({\n      name: 'mobile',\n      description: '定制手机界面或添加电脑能力',\n      input: { hint: '<要做什么>' },\n      handler: async ({ agent, rawInput }) => {\n        const task = rawInput.trim()\n        if (task === '') return { kind: 'error', text: '请带上需求，例如：/mobile 把手机端改成深色主题' }\n        // Collect the current customization state so the guide does not\n        // overwrite earlier /mobile work blindly.\n        const hostStates = new Map(mobileAccess.hostStatus().hosts.map(host => [host.id, host]))\n        const state: MobileGuideState = {\n          directory: stateDirectory,\n          hasCustomCss: await existsRegularFile(template.customCssFile),\n          hasCustomJs: await existsRegularFile(template.customScriptFile),\n          extensions: mobileAccess.manifest().map(entry => {\n            const host = hostStates.get(entry.id)\n            return { id: entry.id, name: entry.name, version: entry.version,\n              ...(host === undefined ? {} : { executionMode: host.mode, executionState: host.state }) }\n          }),\n          failedExtensionCount: mobileAccess.status().failed,\n        }\n        const guide = buildMobileGuide(state)\n        // A plugin-source message renders as a collapsed context-injection row\n        // (label \"dsh-mobile\", one-line notice summary) instead of a user bubble,\n        // while steering still wakes the agent with the full guide as input.\n        agent.steer(createUserMessage({\n          content: [{ type: 'text', text: `${guide}\\n\\n用户需求：${task}` }],\n          source: {\n            kind: 'plugin:dsh-mobile',\n            form: 'notice',\n            summary: boundContextSummary(`/mobile ${task}`),\n          },\n        }))\n        return { kind: 'success', text: '已把需求交给 DSH 处理，改动会在手机端几秒内生效。' }\n      },\n    })\n    try {\n      await mobileAccess.startLocal(template.extensionsDir, ctx, { hostExecution: template.hostExecution })\n      await lanController.initialize()\n      const stores: Record<RemoteProvider, JsonMobileAccessControlStore> = {\n        tailscale: tailscaleStore,\n        cpolar: cpolarStore,\n        cloudflared: cloudflaredStore,\n        frp: frpStore,\n        origin: originStore,\n      }\n      const prepared = await prepareDisabledRemoteProviders(remoteProviders.selected, stores)\n      for (const provider of REMOTE_PROVIDERS) {\n        if (provider === remoteProviders.selected) await remoteControllers[provider].initialize()\n        else await remoteControllers[provider].initialize(prepared.get(provider))\n      }\n      // Broadcast discovery degrades silently when its UDP port cannot be bound, which\n      // otherwise leaves \"the phone cannot find this computer\" with no visible cause.\n      const lanDiscovery = lanGateway?.discoveryStatus()\n      if (lanDiscovery !== undefined && !lanDiscovery.broadcast) {\n        logger.warn(\n          'broadcast discovery is unavailable (%s); mDNS is still published, so pair manually or free the UDP port',\n          lanDiscovery.errorCode ?? 'unknown_cause',\n        )\n      }\n      if (lanDiscovery?.mobileAssetsErrorCode !== undefined) {\n        logger.warn(\n          'a bundled mobile asset is missing (%s); the phone frontend will serve without it',\n          lanDiscovery.mobileAssetsErrorCode,\n        )\n      }\n    } catch (error) {\n      try {\n        await settleCleanupSteps([\n          stopAdmin,\n          () => trustedNetworksWrite,\n          disposeMobileCommand,\n          disposeTaskEvents,\n          async () => {\n            const results = await Promise.allSettled(Object.values(remoteControllers).map(controller => controller.close()))\n            const failures = results.filter(result => result.status === 'rejected').map(result => result.reason as unknown)\n            if (failures.length > 0) throw new AggregateError(failures, 'remote provider cleanup failed')\n          },\n          () => lanController.close(),\n          () => mobileAccess.stopLocal(),\n          unregisterBuiltin,\n        ])\n      } catch (cleanupError) {\n        throw new AggregateError([error, cleanupError], 'DSH Mobile initialization and cleanup failed')\n      }\n      throw error\n    }\n    return async () => {\n      await settleCleanupSteps([\n        stopAdmin,\n        () => trustedNetworksWrite,\n        disposeMobileCommand,\n        disposeTaskEvents,\n        async () => {\n          const results = await Promise.allSettled(Object.values(remoteControllers).map(controller => controller.close()))\n          const failures = results.filter(result => result.status === 'rejected').map(result => result.reason as unknown)\n          if (failures.length > 0) throw new AggregateError(failures, 'remote provider cleanup failed')\n        },\n        () => lanController.close(),\n        () => mobileAccess.stopLocal(),\n        unregisterBuiltin,\n      ])\n    }\n  }, 'dsh-mobile: independent LAN and selectable remote providers with /mobile command')\n}\n"],"mappings":"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"}