{"version":3,"file":"index.mjs","names":["parseIpv4","parsePublicOrigin","execFile","regularFile","createHttpsServer","createHttpServer","requestHttp","request","FRP_VERSION","releases","inside","regularFile","sha256","defaultExtractArtifact","defaultFetchArtifact","MAX_SETTINGS_BYTES","hostname","atomicPrivateWrite","START_TIMEOUT_MS","publicStatus","DEFAULT_VHOST_HTTP_PORT","RESERVED_LAN_GATEWAY_PORT","atomicPrivateWrite","releases","DOWNLOAD_PAGE","TERMS_URL","inside","sha256","regularFile","defaultFetchArtifact","MAX_LOG_BUFFER_BYTES","START_TIMEOUT_MS","publicStatus","reserveLoopbackPort","withoutProxyEnvironment","hostname","execFile","publicStatus","execFile","execFile"],"sources":["../src/access.ts","../src/network.ts","../src/config.ts","../src/exec-file.ts","../src/private-file.ts","../src/control.ts","../src/local-admin-host.ts","../src/http-security.ts","../src/mobile-compat-bootstrap.ts","../src/version.ts","../src/computer-images.ts","../src/extensions.ts","../src/auth-pages.ts","../src/gateway.ts","../src/storage.ts","../src/frp-component.ts","../src/websocket-paths.ts","../src/frp-template.ts","../src/frp-config.ts","../src/remote.ts","../src/frp.ts","../src/origin-proxy-config.ts","../src/origin-proxy.ts","../src/component-download.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/cpolar-component.ts","../src/release-update.ts","../src/file-logger.ts","../src/managed-setup.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    if (deviceToken.length > 512) throw new AccessError(401, 'authentication_failed')\n    return this.exclusive(async () => {\n      const now = this.now()\n      const tokenDigest = digest(deviceToken)\n      const index = this.devices.findIndex(device => timingSafeEqual(Buffer.from(device.tokenDigest, 'hex'), tokenDigest))\n      const device = this.devices[index]\n      if (device === undefined) {\n        throw new AccessError(401, 'authentication_failed')\n      }\n      if (device.revokedAt !== undefined) throw new AccessError(401, 'device_revoked')\n      if (device.expiresAt <= now) throw new AccessError(401, 'device_expired')\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    if (deviceToken.length > 512) throw new AccessError(401, 'authentication_failed')\n    return this.exclusive(async () => {\n      const now = this.now()\n      const tokenDigest = digest(deviceToken)\n      const index = this.devices.findIndex(device => timingSafeEqual(Buffer.from(device.tokenDigest, 'hex'), tokenDigest))\n      const device = this.devices[index]\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      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  /** 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","import { isIP } from 'node:net'\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","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 'node:net'\nimport { isLoopbackAddress, parseAuthority, parseCidr, type AuthoritySpec, type ParsedCidr } from './network.js'\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  /** 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  /** 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  upstreamTimeoutMs?: number\n  rateLimitWindowMs?: number\n  maxPairingAttempts?: number\n  maxRateLimitKeys?: number\n}\n\n/** Resolved, validated security and resource limits. */\nexport interface ResolvedGatewayConfig {\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 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 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  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  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  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 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\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  const mode = value?.mode ?? 'provided'\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    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    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    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 { execFileText as execFile } from './exec-file.js'\n\nlet userSidTask: Promise<string> | undefined\n\nasync function currentWindowsUserSid(): Promise<string> {\n  userSidTask ??= execFile('whoami.exe', ['/user', '/fo', 'csv', '/nh'], {\n    encoding: 'utf8',\n    windowsHide: true,\n    timeout: 10_000,\n  }).then(({ stdout }) => {\n    const match = /,\"(S-\\d(?:-\\d+)+)\"\\s*$/u.exec(stdout.trim())\n    if (match?.[1] === undefined) throw new Error('unable to resolve the current Windows user SID')\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. */\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 execFile('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, 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  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 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], '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","/** Browser-safe desktop-admin Host checks. Do not import Node APIs here. */\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.\n */\nexport function isDesktopAdminSurface(\n  hostname: string,\n  search = '',\n  frontend?: string,\n): boolean {\n  const query = search.startsWith('?') ? search.slice(1) : search\n  return 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 { 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  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(request: IncomingMessage, requireBrowserOrigin: boolean): 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  // Mutating admin requests are browser-only. Fetch metadata is optional on\n  // older clients, so a missing Sec-Fetch-Site must not make a missing Origin\n  // acceptable; Origin is the stable CSRF signal across supported browsers.\n  if (requireBrowserOrigin && origin === undefined) {\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 script to anchor to. The bundle is an\n * enhancement for WebViews without Iterator helpers, so a document this function\n * cannot place it in must still be served: throwing here took the entire dedicated\n * mobile frontend down with a 502.\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","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","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'\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\nasync function withActivationTimeout<T>(promise: Promise<T>, id: string, signal: AbortSignal): Promise<T> {\n  let timer: NodeJS.Timeout | undefined\n  let onAbort: (() => void) | undefined\n  try {\n    return await Promise.race([\n      promise,\n      new Promise<never>((_, reject) => {\n          timer = setTimeout(() => reject(new MobileExtensionError('host_load_timeout', `extension ${id} activation timed out`, 500)), HOST_ACTIVATION_TIMEOUT_MS)\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  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  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}\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\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\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\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  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  }\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 normalized: MobileHostRoute = { ...route, method, path: normalizeRoutePath(route.path) }\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({ ...definition.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  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\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    return Object.freeze({ loaded: this.registered.size + this.local.size, failed: this.failures.size })\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  /** 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    let parsed: unknown\n    try { parsed = parseActionInput(action.input, input) } catch { throw new MobileExtensionError('invalid_action_input', 'action input is invalid', 400) }\n    const lifetime = 'host' in extension ? combineSignalLifetime(extension.controller.signal, context.signal) : undefined\n    const signal = lifetime?.signal ?? context.signal\n    try { return await action.run({ ...context, signal }, parsed) } catch (error) {\n      if (error instanceof MobileExtensionError) throw error\n      throw new MobileExtensionError('extension_failed', 'extension action failed', 500)\n    } finally { lifetime?.cleanup() }\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        : pathname === candidate.path || pathname.startsWith(`${candidate.path}/`)\n    })\n    if (route === undefined) throw new MobileExtensionError('route_not_found', 'route not found', 404)\n    const lifetime = 'host' in extension ? combineSignalLifetime(extension.controller.signal, request.signal) : undefined\n    let releaseLifetime = true\n    try {\n      const routeRequest = lifetime === undefined ? request : { ...request, signal: lifetime.signal }\n      const result = await route.handle(routeRequest)\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 (lifetime !== undefined && isReadable(result.body)) {\n        releaseLifetime = false\n        releaseSignalLifetimeWhenStreamSettles(result.body, lifetime.cleanup)\n      }\n      return result\n    } catch (error) {\n      if (error instanceof MobileExtensionError) throw error\n      throw new MobileExtensionError('extension_failed', 'extension route failed', 500)\n    } finally { if (releaseLifetime) lifetime?.cleanup() }\n  }\n\n  /** Start the local directory watcher; an absent directory is intentionally inert. */\n  async startLocal(root: string, context: Context): Promise<void> {\n    const targetRoot = resolve(root)\n    if (this.localRoot !== undefined && resolve(this.localRoot) !== targetRoot) await this.stopLocal()\n    if (this.localTimer !== undefined) clearInterval(this.localTimer)\n    const lifecycle = ++this.localLifecycle\n    this.localRoot = targetRoot; this.localContext = context; 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    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)\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) void abortAndDisposeLocal(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      this.failures.set(failingName, 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      void abortAndDisposeLocal([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      void abortAndDisposeLocal([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\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\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}\n\nasync function loadLocalExtension(directory: string, context: Context, known?: LocalExtensionFingerprint, parentSignal?: AbortSignal): 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    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)\n    const host = validateDefinition({ ...manifest, actions, routes })\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 })\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/** 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 deviceName: string\n  readonly pair: string\n  readonly pairing: string\n  readonly pairFailed: 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    pairFailed: 'Pairing failed', unavailable: 'The computer is unavailable.',\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    pairFailed: '配对失败', 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    pairFailed: 'Abbinamento non riuscito', unavailable: 'Il computer non è disponibile.',\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<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\" required></label>\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 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  form.addEventListener('submit', async (event) => {\n    event.preventDefault()\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: token.value, label: label.value || undefined }),\n      })\n      if (!response.ok) {\n        status.value = ${JSON.stringify(copy.pairFailed)}\n        return\n      }\n      location.replace('/')\n    } catch {\n      status.value = ${JSON.stringify(copy.unavailable)}\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 { extname } 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, isIP, type AddressInfo, type Socket } from 'node:net'\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 { ensureMobileCompatibility, MOBILE_COMPAT_PATH } from './mobile-compat-bootstrap.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  parseCookies,\n  parseRequestTarget,\n  readJsonObject,\n  sendFailure,\n  sendJson,\n  SESSION_COOKIE,\n  setSecurityHeaders,\n  WS_PATHS,\n} from './http-security.js'\nimport type { BlockedUpgradePathEntry, BlockedUpgradePathLog } from './websocket-paths.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  EXTENSION_LIMITS,\n  MobileExtensionError,\n  type MobileAccessService,\n  type MobileRouteRequest,\n  type MobileRouteResponse,\n} from './extensions.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 MOBILE_HISTORY_PAGE_MESSAGES = 10\nconst SESSION_HISTORY_PATH = '/api/session.history'\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_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])\nconst MOBILE_CSRF_FETCH_BOOTSTRAP = `(()=>{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(`${CSRF_COOKIE}=`)};const token=document.cookie.split(';').map(value=>value.trim()).find(value=>value.startsWith(prefix))?.slice(prefix.length);if(token!==undefined)headers.set(${JSON.stringify(CSRF_HEADER)},token)}return nativeFetch(input,{...init,headers})};})();`\n// Paired pages use the gateway's authenticated HTTP carrier; streams retain DSH's WebSocket transport.\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}})();`\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  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}\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\n/**\n * Parse one upstream boot manifest and rewire the layout entry onto the\n * gateway-owned layout module. The layout entry's URL and revision become the\n * local `mobile-layout.js` path; the dedicated frontend is authenticated in the\n * gateway, so the requested layout needs no upstream address.\n */\nexport function parseMobileBootPlan(html: 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    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 planEntries = layoutBatch.entries.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  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  })\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 rewriteMobileIndexWithBatch(\n  html: string,\n  options: { readonly sizes?: ReadonlyMap<string, number>; readonly passThrough?: ReadonlySet<string> } = {},\n): RewrittenMobileIndex {\n  const plan = parseMobileBootPlan(html)\n  const remoteSettings = orderAuthenticatedSettings(plan.entries, plan.slotProvider)\n  let batches: readonly MobileBootBatchPlan[] = []\n  if (plan.batches !== undefined && plan.layoutBatch !== undefined && plan.planEntries !== undefined) {\n    const split = splitMobileBootBatch(\n      plan.planEntries,\n      options.sizes ?? new Map(),\n      options.passThrough ?? new Set(),\n    )\n    const at = plan.batches.indexOf(plan.layoutBatch)\n    if (at < 0) throw new Error('upstream DSH boot manifest has no unique application layout batch')\n    plan.batches.splice(at, 1, ...split.rows)\n    batches = Object.freeze(split.plans)\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 = `${transportBootstrap}${MOBILE_CSRF_FETCH_BOOTSTRAP}window.__DSH_MOBILE_FRONTEND__=\"dedicated\";${plan.assignment}${JSON.stringify(plan.parsed)};`\n  return Object.freeze({\n    html: ensureMobileViewport(ensureMobileCompatibility(`${html.slice(0, plan.replaceStart)}${replacement}${html.slice(plan.replaceEnd)}`)),\n    batches,\n  })\n}\n\n/** Replace only DSH's layout client module while retaining its complete plugin graph. */\nexport function rewriteMobileIndex(html: string): string {\n  return rewriteMobileIndexWithBatch(html).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 = [\n    'accept', 'accept-encoding', 'accept-language', 'content-encoding', 'content-length', 'content-type',\n    'if-match', 'if-modified-since', 'if-none-match', 'if-unmodified-since', 'range', 'user-agent',\n  ] as const\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 shouldCompressResponse(request: IncomingMessage, response: IncomingMessage): boolean {\n  const pathname = request.url?.split('?', 1)[0] ?? ''\n  const compressibleRequest = (request.method === 'GET'\n      && (pathname.startsWith('/plugins/') || pathname.startsWith('/assets/')))\n    || (request.method === 'POST' && pathname === SESSION_HISTORY_PATH)\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    && acceptsGzip(request.headers['accept-encoding'])\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  // Only a delivered artifact is immutable. A rev-bearing URL is unique per\n  // build, so a 200 for it can never change — but an error for the same URL is\n  // not that artifact. Stamping `max-age=31536000, immutable` onto a failure\n  // lets the WebView cache the rejection for a year: `rev` is a per-host-start\n  // nonce, so once the host restarts the bundle URL the page already holds is\n  // rejected, and the poisoned entry makes the plugin fail on every later boot\n  // until the browser cache is cleared. Upstream DSH only attaches its\n  // immutable directive on the success path; failures there carry no\n  // cache-control at all, so the gateway keeps `no-store` from\n  // setSecurityHeaders instead.\n  if (statusCode !== 200) 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 isJsonRecord(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction mobileHistoryRequestBody(request: IncomingMessage, body: Buffer): Buffer {\n  if (request.method !== 'POST' || request.url?.split('?', 1)[0] !== SESSION_HISTORY_PATH) return body\n  let parsed: unknown\n  try {\n    parsed = JSON.parse(body.toString('utf8'))\n  } catch {\n    return body\n  }\n  if (!isJsonRecord(parsed) || parsed.method !== 'session.history' || !isJsonRecord(parsed.payload)) return body\n  const requested = parsed.payload.maxMessages\n  if (typeof requested === 'number' && Number.isInteger(requested) && requested > 0 && requested <= MOBILE_HISTORY_PAGE_MESSAGES) {\n    return body\n  }\n  return Buffer.from(JSON.stringify({\n    ...parsed,\n    payload: { ...parsed.payload, maxMessages: MOBILE_HISTORY_PAGE_MESSAGES },\n  }))\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 requestCookies(request: IncomingMessage): ReadonlyMap<string, string> {\n  const cookies = parseCookies(request.headers.cookie)\n  if (cookies === undefined) throw new HttpError(401, 'authentication_failed')\n  return cookies\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 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\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  ) {\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        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      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  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 sessionToken = requestCookies(request).get(SESSION_COOKIE)\n    if (sessionToken === undefined) throw new HttpError(401, 'authentication_failed')\n    return this.access.authorizeSession(sessionToken)\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    ])\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    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 deviceToken = requestCookies(request).get(DEVICE_COOKIE)\n    if (deviceToken === undefined) throw new HttpError(401, 'authentication_failed')\n    let result\n    try {\n      result = await this.access.renew(deviceToken)\n    } catch (error) {\n      if (error instanceof AccessError && error.status === 401) {\n        response.setHeader('Set-Cookie', cookie(DEVICE_COOKIE, '', {\n          tls: this.tlsEnabled,\n          httpOnly: true,\n          path: '/mobile-access/auth/renew',\n          maxAgeSeconds: 0,\n        }))\n      }\n      throw error\n    }\n    this.setSessionCookies(response, result, Date.now())\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    ])\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 requestedExtension = extensionTarget(target.decodedPathname)\n    const requestedMobileBootBatch = mobileBootBatchKey(target.decodedPathname)\n    const customAsset = request.method === 'GET'\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\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 (request.method !== 'GET' && request.method !== 'HEAD' && request.method !== 'POST'\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    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 ifNoneMatch = headerValue(request.headers, 'if-none-match')\n        if (ifNoneMatch !== undefined && ifNoneMatch === etag) {\n          setSecurityHeaders(response, this.tlsEnabled)\n          response.writeHead(304)\n          response.end()\n          return\n        }\n        setSecurityHeaders(response, this.tlsEnabled)\n        const responseHeaders: Record<string, string | number> = {\n          'Content-Type': customAsset.contentType,\n          'Content-Length': body.byteLength,\n          'ETag': etag,\n        }\n        if (mtime !== undefined) responseHeaders['Last-Modified'] = mtime.toUTCString()\n        response.writeHead(200, responseHeaders)\n        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    if (request.method === 'GET' && 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 (headerValue(request.headers, 'if-none-match') === etag) {\n          setSecurityHeaders(response, this.tlsEnabled); response.writeHead(304); 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        if (headerValue(request.headers, 'if-none-match') === file.digest) {\n          setSecurityHeaders(response, this.tlsEnabled); response.writeHead(304); 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: file.digest })\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      response.once('close', () => { 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        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      } 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      response.once('close', () => { 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    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    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 Error('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  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    try {\n      const upstreamHeaders = sanitizeRequestHeaders(request, this.config.upstreamOrigin)\n      const upstreamCookie = await this.upstreamCookieHeader()\n      if (upstreamCookie !== undefined) upstreamHeaders.cookie = upstreamCookie\n      upstreamHeaders['accept-encoding'] = 'identity'\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: '/',\n          headers: upstreamHeaders,\n          agent: false,\n        })\n        holder.request = upstreamRequest\n        upstreamRequest.setTimeout(this.config.upstreamTimeoutMs, () => {\n          upstreamRequest.destroy(new Error('upstream timeout'))\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 > 4 * 1024 * 1024) throw new HttpError(502, 'upstream_unavailable')\n        chunks.push(buffer)\n      }\n      let body: Buffer\n      try {\n        const html = Buffer.concat(chunks).toString('utf8')\n        const plan = parseMobileBootPlan(html)\n        const options = plan.planEntries === undefined\n          ? {}\n          : await this.resolveMobileBootSizes(plan.planEntries)\n        const rewritten = rewriteMobileIndexWithBatch(html, options)\n        for (const batch of rewritten.batches) this.rememberMobileBootBatch(batch)\n        body = Buffer.from(rewritten.html)\n      } catch {\n        throw new HttpError(502, 'upstream_unavailable')\n      }\n      const headers = sanitizeResponseHeaders(proxied.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      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  ): 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        const index = cursor++\n        const source = candidates[index]!.url\n        const size = await this.upstreamBundleSize(source)\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): Promise<number | undefined> {\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    const upstreamCookie = await this.upstreamCookieHeader()\n    let upstreamRequest: ClientRequest | undefined\n    try {\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 {\n      return undefined\n    } finally {\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 (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.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 upstream. Pass-through client bundles (`GET /plugins`)\n   * receive bounded transient retries — the upstream resets a fraction of fresh\n   * connections — matching the resilience the merged-batch assembly already has.\n   * A request is only retried before any byte reached the client.\n   */\n  private async proxyHttp(\n    request: IncomingMessage,\n    response: ServerResponse,\n    authorization: SessionAuthorization,\n  ): Promise<void> {\n    const retryable = request.method === 'GET'\n      && request.url?.split('?', 1)[0]?.startsWith('/plugins/') === true\n    if (!retryable) {\n      try {\n        await this.proxyHttpOnce(request, response, authorization)\n      } catch (error) {\n        if (error instanceof HttpError) throw error\n        if (response.headersSent) response.destroy()\n        else throw new HttpError(502, 'upstream_unavailable')\n      }\n      return\n    }\n    const delay = (attempt: number): Promise<void> => (\n      new Promise(resolve => setTimeout(resolve, MOBILE_BOOT_RETRY_DELAY_MS * attempt))\n    )\n    for (let attempt = 1; attempt <= MOBILE_BOOT_UPSTREAM_ATTEMPTS; attempt++) {\n      try {\n        await this.proxyHttpOnce(request, response, authorization)\n        return\n      } catch (error) {\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 === MOBILE_BOOT_UPSTREAM_ATTEMPTS) throw new HttpError(502, 'upstream_unavailable')\n        await delay(attempt)\n      }\n    }\n    throw new HttpError(502, 'upstream_unavailable')\n  }\n\n  private async proxyHttpOnce(\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 holder: { request?: ClientRequest } = {}\n    const operation = this.allocateRequest(authorization, response, holder)\n    let bodyDone: Promise<void> | undefined\n    try {\n      const bufferedBody = request.method === 'POST' && request.url?.split('?', 1)[0] === SESSION_HISTORY_PATH\n        ? mobileHistoryRequestBody(request, await readBoundedBody(request, this.config.maxBodyBytes))\n        : undefined\n      const upstreamHeaders = sanitizeRequestHeaders(request, this.config.upstreamOrigin)\n      const upstreamCookie = await this.upstreamCookieHeader()\n      if (upstreamCookie !== undefined) upstreamHeaders.cookie = upstreamCookie\n      if (bufferedBody !== undefined) upstreamHeaders['content-length'] = String(bufferedBody.byteLength)\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 Error('upstream timeout'))\n        })\n        upstreamRequest.once('response', resolve)\n        upstreamRequest.once('error', reject)\n        if (bufferedBody === undefined) {\n          bodyDone = pipeline(request, new ByteLimitTransform(this.config.maxBodyBytes), upstreamRequest)\n        } else {\n          upstreamRequest.end(bufferedBody)\n          bodyDone = Promise.resolve()\n        }\n        void bodyDone.catch(reject)\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 compressed = shouldCompressResponse(request, proxied)\n      if (compressed) {\n        delete headers['accept-ranges']\n        delete headers['content-length']\n        delete headers.etag\n        headers['content-encoding'] = 'gzip'\n        addVaryAcceptEncoding(headers)\n      }\n      response.writeHead(statusCode, headers)\n      await Promise.all([\n        bodyDone,\n        compressed ? 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      operation.release()\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    const 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\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      const active = this.activeWebSockets.get(id)\n      if (active !== undefined) clearTimeout(active.timer)\n      this.activeWebSockets.delete(id)\n    }\n    client.once('close', () => { upstream.destroy(); cleanup() })\n    upstream.once('close', () => { client.destroy(); cleanup() })\n    upstream.setTimeout(this.config.upstreamTimeoutMs, closeBoth)\n    try {\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(prefix: string = LOCAL_ADMIN_PREFIX): 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)\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            const pairUrl = `${this.address().origin}/mobile-access/pair#instance=${this.config.instanceId}&token=${opened.token}`\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: `dsh1.${this.config.instanceId}.${opened.token}`,\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            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            await this.access.resetDevices()\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    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    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 { 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  rename,\n  rm,\n  stat,\n  writeFile,\n} from 'node:fs/promises'\nimport { basename, isAbsolute, join, relative, resolve } from 'node:path'\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\nasync function replaceDirectory(target: string, candidate: string): Promise<void> {\n  const backup = `${target}.previous-${randomBytes(12).toString('hex')}`\n  let previous = false\n  try {\n    try {\n      await rename(target, backup)\n      previous = true\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n    }\n    try {\n      await rename(candidate, target)\n    } catch (error) {\n      if (previous) {\n        try { await rename(backup, target) } catch (restoreError) {\n          throw new AggregateError([error, restoreError], 'frp_component_replace_failed')\n        }\n      }\n      throw error\n    }\n    if (previous) await rm(backup, { recursive: true, force: true })\n  } finally {\n    await rm(candidate, { recursive: true, force: true })\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  const response = await fetch(artifact.downloadUrl, { redirect: 'follow', signal })\n  if (!response.ok) throw new Error(`frp_download_http_${String(response.status)}`)\n  const finalUrl = new URL(response.url)\n  const officialHost = finalUrl.hostname === 'github.com' || finalUrl.hostname.endsWith('.githubusercontent.com')\n  if (finalUrl.protocol !== 'https:' || !officialHost) throw new Error('frp_download_origin_invalid')\n  const lengthHeader = response.headers.get('content-length')\n  const declaredLength = lengthHeader === null ? undefined : Number(lengthHeader)\n  if (declaredLength !== undefined && (!Number.isFinite(declaredLength) || declaredLength !== artifact.downloadBytes)) {\n    throw new Error('frp_download_size_mismatch')\n  }\n  if (response.body === null) throw new Error('frp_download_empty')\n  const chunks: Uint8Array[] = []\n  let received = 0\n  const reader = response.body.getReader()\n  while (true) {\n    const result = await reader.read()\n    if (result.done) break\n    received += result.value.byteLength\n    if (received > artifact.downloadBytes) {\n      await reader.cancel()\n      throw new Error('frp_download_size_mismatch')\n    }\n    chunks.push(result.value)\n  }\n  if (received !== artifact.downloadBytes) throw new Error('frp_download_size_mismatch')\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\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 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    const stateDirectory = resolve(options.stateDirectory)\n    if (!isAbsolute(stateDirectory)) throw new Error('frp state directory must be absolute')\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 = await regularFile(this.executable)\n    this.installedBytes = this.installed ? (await stat(this.executable)).size : 0\n    if (this.installed) {\n      try {\n        const version = await this.inspectExecutable(this.executable)\n        if (version !== FRP_VERSION) throw new Error('frp_component_version_mismatch')\n        this.errorCode = undefined\n      } catch {\n        this.installed = false\n        this.errorCode = 'frp_component_invalid'\n      }\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 mkdir(this.stagingRoot, { recursive: true, mode: 0o700 })\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 mkdir(candidate, { recursive: true, mode: 0o700 })\n        const candidateExecutable = join(candidate, artifact.executableName)\n        await copyFile(extracted, candidateExecutable)\n        await chmod(candidateExecutable, 0o700)\n        await replaceDirectory(this.componentStorage, candidate)\n        this.installed = true\n        this.installedBytes = (await stat(this.executable)).size\n        this.errorCode = undefined\n      } finally {\n        await rm(staging, { recursive: true, force: true })\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 Promise.all([\n        rm(this.componentRoot, { recursive: true, force: true }),\n        rm(this.logRoot, { recursive: true, force: true }),\n        rm(this.stagingRoot, { recursive: true, force: true }),\n      ])\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 { 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","/** 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\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\n/** Build the Caddy site for one public host (without markers or import wiring). */\nexport function createCaddySite(publicHost: string, certDir: string = FRP_CADDY_IP_CERT_DIR): string {\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(FRP_VHOST_HTTP_PORT)}`,\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(FRP_VHOST_HTTP_PORT)}`,\n    '}',\n    '',\n  ].join('\\n')\n}\n\n/** Manual certbot steps for a public-IPv4 origin (Caddy cannot issue IP certificates itself). */\nfunction 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/** Build the only supported frps config and Caddy snippet from validated user inputs. */\nexport function createRestrictedFrpServerTemplate(serverPort: number, token: string, publicOrigin: string): 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  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(FRP_VHOST_HTTP_PORT)}`,\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).trimEnd(),\n    '',\n  ]\n  if (publicIpv4Address(publicHost)) lines.push(manualIpCertificateGuide(publicHost), '')\n  return lines.join('\\n')\n}\n","import { randomBytes } from 'node:crypto'\nimport { isIP } from 'node:net'\nimport { lstat, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { basename, dirname, isAbsolute, join, resolve } from 'node:path'\nimport { isGloballyRoutableIpv4 } from './network.js'\nimport { restrictPrivateFile } from './private-file.js'\nimport { createRestrictedFrpServerTemplate, FRP_VHOST_HTTP_PORT } from './frp-template.js'\n\nconst MAX_SETTINGS_BYTES = 8 * 1024\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\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  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/** 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/** Parse FRP settings at the loopback request and filesystem boundaries. */\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 => !['version', 'serverAddress', 'serverPort', 'token', 'publicOrigin'].includes(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  return Object.freeze({\n    version: 1,\n    serverAddress: validateFrpServerAddress(record.serverAddress),\n    serverPort: validateFrpServerPort(record.serverPort),\n    token: validateFrpToken(record.token),\n    publicOrigin: validateFrpPublicOrigin(record.publicOrigin),\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 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  }\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/** Build the single-purpose frpc configuration for the current loopback gateway. */\nexport function createFrpcToml(settings: FrpSettings, localPort: number): string {\n  if (!Number.isSafeInteger(localPort) || localPort < 1 || localPort > 65_535) throw new Error('frp_local_port_invalid')\n  const hostnameValue = new URL(settings.publicOrigin).hostname\n  return [\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 = \"dsh-mobile\"',\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}\n\nasync function atomicPrivateWrite(file: string, body: string): Promise<void> {\n  const directory = dirname(file)\n  await mkdir(directory, { recursive: true, mode: 0o700 })\n  try {\n    const current = await lstat(file)\n    if (!current.isFile() || current.isSymbolicLink()) throw new Error('frp_config_target_invalid')\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n  }\n  const temporary = join(directory, `.${basename(file)}.${randomBytes(12).toString('hex')}.tmp`)\n  try {\n    await writeFile(temporary, body, { encoding: 'utf8', flag: 'wx', mode: 0o600 })\n    await rename(temporary, file)\n    await restrictPrivateFile(file)\n  } catch (error) {\n    await rm(temporary, { force: true })\n    throw error\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  private settingsValue: FrpSettings | undefined\n  private errorCode: string | undefined\n\n  constructor(stateDirectory: string) {\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  }\n\n  /** Load private settings while rejecting links, oversized files, and unknown fields. */\n  async initialize(): Promise<void> {\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  /** Return configuration metadata without exposing the FRP token. */\n  status(): FrpConfigurationStatus {\n    const settings = this.settingsValue\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: FRP_VHOST_HTTP_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(): 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 atomicPrivateWrite(this.settingsFile, `${JSON.stringify(settings)}\\n`)\n    await rm(this.runtimeConfigFile, { force: true })\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 atomicPrivateWrite(this.runtimeConfigFile, createFrpcToml(settings, localPort))\n    return this.runtimeConfigFile\n  }\n\n  /** Remove only configuration files owned by the FRP provider. */\n  async purge(): Promise<FrpConfigurationStatus> {\n    await rm(this.stateRoot, { recursive: true, force: true })\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 }\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 { 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  initialize(): 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/** 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  /** 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 { connect } from 'node:net'\nimport { isAbsolute } from 'node:path'\nimport type { MobileAccessControlStore } from './control.js'\nimport type { FrpConfigStore } from './frp-config.js'\nimport { DEFAULT_VHOST_HTTP_PORT } 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\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/** 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  readonly instanceId: string\n  readonly createGateway: (origin: string) => 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?: (origin: string, expectedInstanceId: string, signal: AbortSignal) => Promise<boolean>\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\nasync function defaultProbeDiscovery(origin: string, expectedInstanceId: string, signal: AbortSignal): Promise<boolean> {\n  const requestController = new AbortController()\n  const abort = (): void => { requestController.abort() }\n  signal.addEventListener('abort', abort, { once: true })\n  const timeout = setTimeout(abort, DISCOVERY_REQUEST_TIMEOUT_MS)\n  timeout.unref()\n  try {\n    const response = await fetch(`${origin}/mobile-access/discovery`, {\n      method: 'GET',\n      redirect: 'error',\n      cache: 'no-store',\n      signal: requestController.signal,\n      headers: { accept: 'application/json' },\n    })\n    if (!response.ok) return false\n    let value: unknown\n    try { value = JSON.parse(new TextDecoder().decode(await boundedResponseBytes(response))) 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  } finally {\n    clearTimeout(timeout)\n    signal.removeEventListener('abort', abort)\n  }\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\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  }\n\n  /** Restore the remembered FRP switch without changing LAN or other providers. */\n  async initialize(): Promise<void> {\n    const state = 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      if (!enabled) await this.stop()\n      this.enabled = enabled\n      await this.options.store.save({ version: 1, enabled })\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        this.enabled = true\n        await this.options.store.save({ version: 1, 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.stop()\n      this.enabled = false\n      await this.options.store.save({ version: 1, enabled: false })\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    this.publish({ enabled: true, state: 'starting', origin: settings.publicOrigin })\n    let exposed: boolean\n    try {\n      exposed = await (this.options.probeVhostExposure ?? defaultProbeVhostExposure)(\n        settings.serverAddress,\n        DEFAULT_VHOST_HTTP_PORT,\n      )\n    } catch {\n      this.publish({ enabled: true, state: 'error', origin: settings.publicOrigin, errorCode: 'frp_vhost_probe_failed' })\n      return\n    }\n    if (exposed) {\n      this.publish({ enabled: true, state: 'error', origin: settings.publicOrigin, errorCode: 'frp_vhost_publicly_reachable' })\n      return\n    }\n    let gateway: MobileAccessGateway\n    try { gateway = await this.options.createGateway(settings.publicOrigin) } catch {\n      this.publish({ enabled: true, state: 'error', origin: settings.publicOrigin, errorCode: '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    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    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      if (generation !== this.generation || this.child !== child) return\n      this.child = undefined\n      if (this.enabled) void this.enqueue(() => this.failGeneration(generation, code === 0 ? 'frp_stopped' : 'frp_exited'))\n    })\n    this.publish({ enabled: true, state: 'connecting', origin: settings.publicOrigin })\n    const controller = new AbortController()\n    this.startupAbort = controller\n    void this.waitForDiscovery(generation, settings.publicOrigin, controller.signal)\n  }\n\n  private async waitForDiscovery(generation: number, origin: string, signal: AbortSignal): Promise<void> {\n    const deadline = Date.now() + (this.options.startTimeoutMs ?? START_TIMEOUT_MS)\n    const probe = this.options.probeDiscovery ?? defaultProbeDiscovery\n    while (!signal.aborted && Date.now() < deadline) {\n      try {\n        if (await probe(origin, this.options.instanceId, 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 })\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 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    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 { randomBytes } from 'node:crypto'\nimport { lstat, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { isIP } from 'node:net'\nimport { basename, dirname, isAbsolute, join, resolve } from 'node:path'\nimport { addressAllowed, isGloballyRoutableIpv4, isLoopbackAddress, parseCidr } from './network.js'\nimport { restrictPrivateFile } from './private-file.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\nasync function atomicPrivateWrite(file: string, body: string): Promise<void> {\n  const directory = dirname(file)\n  await mkdir(directory, { recursive: true, mode: 0o700 })\n  try {\n    const current = await lstat(file)\n    if (!current.isFile() || current.isSymbolicLink()) throw new Error('origin_config_target_invalid')\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n  }\n  const temporary = join(directory, '.' + basename(file) + '.' + randomBytes(12).toString('hex') + '.tmp')\n  try {\n    await writeFile(temporary, body, { encoding: 'utf8', flag: 'wx', mode: 0o600 })\n    await rename(temporary, file)\n    await restrictPrivateFile(file)\n  } catch (error) {\n    await rm(temporary, { force: true })\n    throw error\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) {\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    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 atomicPrivateWrite(this.settingsFile, JSON.stringify(settings) + '\\n')\n    this.settingsValue = settings\n    this.errorCode = undefined\n    return this.status()\n  }\n\n  async purge(): Promise<OriginConfigurationStatus> {\n    await rm(this.settingsFile, { force: true })\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","/**\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/** 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  const location = response.headers.get('location')\n  if (location === null) throw new Error(`${request.errorPrefix}_download_redirect_missing`)\n  let target: URL\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  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  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  const reader = response.body.getReader()\n  let received = 0\n  while (true) {\n    const chunk = await reader.read()\n    if (chunk.done) break\n    if (chunk.value.byteLength > bytes.byteLength - received) {\n      await reader.cancel()\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}\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 {\n  chmod,\n  copyFile,\n  lstat,\n  mkdir,\n  mkdtemp,\n  readFile,\n  rename,\n  rm,\n  writeFile,\n} from 'node:fs/promises'\nimport { isAbsolute, join, relative, resolve } from 'node:path'\nimport { downloadPinnedArtifact } from './component-download.js'\n\n/**\n * Pinned cloudflared components fetched only after an explicit user action.\n *\n * Unlike the cpolar archive each artifact IS the executable: there is nothing\n * to unpack, so the download digest and the installed digest are the same pair.\n * `--no-autoupdate` is passed at runtime as well, so the pinned bytes stay the\n * 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}\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  },\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  },\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  },\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}\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 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 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 installed = false\n  private errorCode: string | undefined\n  private queue: Promise<void> = Promise.resolve()\n\n  constructor(options: CloudflaredComponentManagerOptions) {\n    const stateDirectory = resolve(options.stateDirectory)\n    if (!isAbsolute(stateDirectory)) throw new Error('cloudflared state directory must be absolute')\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  }\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 = release !== undefined && await regularFile(this.executable, release.downloadBytes)\n    if (this.installed && release !== undefined && await sha256(this.executable) !== release.downloadSha256) {\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.downloadBytes,\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 mkdir(this.stagingRoot, { recursive: true, mode: 0o700 })\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() }, 300_000)\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        await writeFile(staged, bytes, { flag: 'wx', mode: 0o600 })\n        await chmod(staged, 0o700)\n        if (!await regularFile(staged, release.downloadBytes)\n          || await sha256(staged) !== release.downloadSha256) {\n          throw new Error('cloudflared_executable_hash_mismatch')\n        }\n        const candidate = join(this.componentRoot, `.install-${randomBytes(12).toString('hex')}`)\n        await mkdir(candidate, { recursive: true, mode: 0o700 })\n        await copyFile(staged, join(candidate, release.executableName))\n        await chmod(join(candidate, release.executableName), 0o700)\n        await rm(this.componentStorage, { recursive: true, force: true })\n        await rename(candidate, this.componentStorage)\n        this.installed = true\n        this.errorCode = undefined\n      } finally {\n        await rm(staging, { recursive: true, force: true })\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 Promise.all([\n        rm(this.componentRoot, { recursive: true, force: true }),\n        rm(this.stateRoot, { recursive: true, force: true }),\n        rm(this.logRoot, { recursive: true, force: true }),\n        rm(this.stagingRoot, { recursive: true, force: true }),\n      ])\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 { 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(): Promise<void> {\n    const state = 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      if (!enabled) await this.stop()\n      this.enabled = enabled\n      await this.options.store.save({ version: 1, enabled })\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        this.enabled = true\n        await this.options.store.save({ version: 1, 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.stop()\n      this.enabled = false\n      await this.options.store.save({ version: 1, enabled: false })\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 { randomBytes } from 'node:crypto'\nimport { lstat, mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises'\nimport { isIP } from 'node:net'\nimport { basename, dirname, isAbsolute, join, resolve } from 'node:path'\nimport { restrictPrivateFile } from './private-file.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\nasync function atomicPrivateWrite(file: string, body: string): Promise<void> {\n  const directory = dirname(file)\n  await mkdir(directory, { recursive: true, mode: 0o700 })\n  try {\n    const current = await lstat(file)\n    if (!current.isFile() || current.isSymbolicLink()) throw new Error('cloudflared_tunnel_target_invalid')\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n  }\n  const temporary = join(directory, `.${basename(file)}.${randomBytes(12).toString('hex')}.tmp`)\n  try {\n    await writeFile(temporary, body, { encoding: 'utf8', flag: 'wx', mode: 0o600 })\n    await rename(temporary, file)\n    await restrictPrivateFile(file)\n  } catch (error) {\n    await rm(temporary, { force: true })\n    throw error\n  }\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) {\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    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 rm(this.settingsFile, { force: true })\n    else await atomicPrivateWrite(this.settingsFile, `${JSON.stringify(settings)}\\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 rm(this.settingsFile, { force: true })\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'\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  | '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}\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  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}\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\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_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/** Allow remote relays enough time to answer without making diagnostics unbounded. */\nexport function remoteDiagnosticTimeoutMs(origin: string): number {\n  const hostname = new URL(origin).hostname.toLowerCase()\n  if (hostname.endsWith('.ts.net') || hostname.includes('.cpolar.')) return 10_000\n  return 10_000\n}\n\nasync function defaultRemoteProbe(origin: string | undefined): Promise<RemoteObservation> {\n  if (origin === undefined) return { state: 'not-applicable' }\n  const hostname = new URL(origin).hostname\n  const started = performance.now()\n  try {\n    const response = await fetch(new URL('/mobile-access/health', origin), {\n      cache: 'no-store',\n      redirect: 'error',\n      signal: AbortSignal.timeout(remoteDiagnosticTimeoutMs(origin)),\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    let fakeIp = false\n    try {\n      const addresses = await lookup(hostname, { all: true })\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    }\n    return { state: 'unreachable', ...(fakeIp ? { fakeIp: true } : {}) }\n  }\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.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 = { provider: snapshot.remote.provider, endpointSuffix, ...(remoteObservation.latencyMs === undefined ? {} : { latencyMs: remoteObservation.latencyMs }) }\n    if (remoteObservation.state === 'ready') {\n      checks.push(check('remote', 'ok', 'remote-ready', '远程通道', `${snapshot.remote.provider} 公共地址 ${endpointSuffix} 可达，往返约 ${String(remoteObservation.latencyMs ?? 0)} ms。`, undefined, facts))\n    } else if (remoteObservation.state === 'rate-limited') {\n      checks.push(check('remote', 'warning', 'remote-rate-limited', '远程通道', '公共地址可达，但本次检查观察到服务限流。', '稍后重试；旧会话会按需加载以减少流量。', facts))\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}\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}）`).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\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   - 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 plugin --profile web exec dsh-mobile extension create <id> --name \"<名称>\"，再在模板上改\n\n安全约束：\n- host.mjs 拥有电脑用户的完整权限，绝不能放入不可信代码，也不要让手机端无条件执行任意命令\n- 所有改动只限 $DSH_HOME/mobile-access/，不要动 DeepSeek Harness 源码\n\n完成前请自检：\n- 改动涉及 mobile.js 或扩展的 mobile.js / host.mjs 时，先做语法检查再保存（如 node --check <file>），确保没有语法错误\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 'node:net'\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 runSshFetch?: (input: VpsSshFetchInput, 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  constructor(message: string, readonly stdout: string, readonly stderr: string, options?: ErrorOptions) {\n    super(message, options)\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    // The host field is optional: ssh-cat fallback lines carry only type and key.\n    // It is discarded anyway; pinned known_hosts lines are rebuilt from the\n    // validated server address, so accepting host-less lines is safe.\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/** Lenient scan probe: garbage fails the whole fetch, comment-only output falls back. */\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  // An empty result lets the caller fall back to an authenticated read.\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/**\n * Read the server's public host keys over an authenticated connection with a\n * throwaway known_hosts file. Fallback for keyscan binaries that cannot\n * negotiate with modern servers; output feeds the same confirm-and-pin pipeline.\n */\nasync function defaultRunSshFetch(input: VpsSshFetchInput, serverAddress: string): Promise<string> {\n  const ssh = process.platform === 'win32' ? 'ssh.exe' : 'ssh'\n  const sshUser = validSshUser(input.sshUser)\n  const sshPort = validSshPort(input.sshPort)\n  const sshKeyPath = validSshKeyPath(input.sshKeyPath)\n  const nullDevice = process.platform === 'win32' ? 'NUL' : '/dev/null'\n  const args = [\n    '-o', 'BatchMode=yes', '-o', 'ConnectTimeout=15',\n    '-o', 'StrictHostKeyChecking=no', `-o UserKnownHostsFile=${nullDevice}`,\n    ...(sshKeyPath === undefined ? [] : ['-i', sshKeyPath]),\n    '-p', String(sshPort), `${sshUser}@${serverAddress}`, 'cat /etc/ssh/ssh_host_*_key.pub',\n  ]\n  const { stdout } = await runProcess(ssh, args, undefined, 30_000).catch((error: unknown) => {\n    throw new VpsSshError('vps_host_key_unavailable', '', error instanceof Error ? error.message : String(error))\n  })\n  const lines: string[] = []\n  for (const line of stdout.split(/\\r?\\n/u)) {\n    const match = /^(ssh-rsa|ecdsa-sha2-nistp\\d+|ssh-ed25519)\\s+([A-Za-z0-9+/]+={0,2})(\\s|$)/u.exec(line.trim())\n    if (match?.[1] !== undefined && match[2] !== undefined) lines.push(`${serverAddress} ${match[1]} ${match[2]}`)\n  }\n  return lines.length === 0 ? stdout : `${lines.join('\\n')}\\n`\n}\n\n/**\n * Scan host keys with keyscan first, then fall back to an authenticated read\n * when the local keyscan binary cannot negotiate with the server. Both paths\n * feed the same confirm-and-pin pipeline, so a fallback never weakens the\n * user-confirmation gate.\n */\nasync function scanHostKeys(\n  input: VpsSshFetchInput,\n  serverAddress: string,\n  options: VpsDeploymentOptions,\n): Promise<string> {\n  const runKeyscan = options.runKeyscan ?? defaultRunKeyscan\n  // A rejecting keyscan (old binary failing KEX, missing binary, DNS error)\n  // is equivalent to an empty scan: fall through to the authenticated read.\n  const scanned = await runKeyscan({ sshUser: input.sshUser, sshPort: input.sshPort }, serverAddress).catch(() => '')\n  if (tryParseKeyscanOutput(scanned)?.length) return scanned\n  options.log?.('host-keys-keyscan-empty', { serverAddress })\n  const runSshFetch = options.runSshFetch ?? defaultRunSshFetch\n  const fetched = await runSshFetch(input, serverAddress)\n  if (tryParseKeyscanOutput(fetched)?.length) {\n    options.log?.('host-keys-ssh-fallback', { serverAddress })\n    return fetched\n  }\n  throw new Error('vps_host_key_unavailable')\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  elif grep -q '^# Managed by DSH Mobile$' /etc/caddy/Caddyfile; then\n    # Legacy whole-file layout: the entire file is ours by construction.\n    printf '%s\\n' \"$caddy_import\" > /etc/caddy/Caddyfile\n    chmod 0644 /etc/caddy/Caddyfile\n    caddyfile_ready=true\n  elif grep -q '^:80[[:space:]]*{' /etc/caddy/Caddyfile \\\n    && grep -q 'root [*] /usr/share/caddy' /etc/caddy/Caddyfile \\\n    && grep -q '^[[:space:]]*file_server[[:space:]]*$' /etc/caddy/Caddyfile; 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\nasync function runProcess(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    const timer = setTimeout(() => { child.kill(); rejectRun(new VpsSshError('vps_ssh_timeout', stdout, stderr)) }, 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 => { clearTimeout(timer); rejectRun(new VpsSshError('vps_ssh_unavailable', stdout, stderr, { cause: error })) })\n    child.once('close', code => {\n      clearTimeout(timer)\n      if (code !== 0) rejectRun(new VpsSshError(stderr.includes('Permission denied') ? 'vps_ssh_auth_failed' : 'vps_deploy_failed', stdout, stderr))\n      else resolveRun({ stdout, stderr })\n    })\n    child.stdin.end(stdin, 'utf8')\n  })\n}\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  # Legacy whole-file layout (pre-snippet releases): the entire file is ours.\n  printf '# DSH Mobile removed its site. Restore your own Caddyfile or reinstall the Caddy defaults.\\\\n' > /etc/caddy/Caddyfile\n  chmod 0644 /etc/caddy/Caddyfile\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 站点；请按需恢复自己的配置。\"\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, rm } from 'node:fs/promises'\nimport { isAbsolute, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { MobileAccessControlStore } from './control.js'\nimport type { MobileAccessGateway } from './gateway.js'\nimport { settleRemoteResources, terminateRemoteProcess, type RemoteProviderController } from './remote.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  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 startTimer: NodeJS.Timeout | undefined\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  }\n\n  /** Restore the remote switch without coupling it to LAN availability. */\n  async initialize(): Promise<void> {\n    const state = 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      if (this.enabled === enabled && (enabled === false || this.child !== undefined)) return\n      if (!enabled) await this.stop()\n      this.enabled = enabled\n      await this.options.store.save({ version: 1, enabled })\n      if (enabled) await this.start()\n      else this.publish({ enabled: false, state: 'off' })\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      if (!this.enabled) {\n        this.enabled = true\n        await this.options.store.save({ version: 1, 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      await this.stop()\n      this.enabled = false\n      await this.options.store.save({ version: 1, enabled: false })\n      await rm(resolve(this.options.stateDirectory), { recursive: true, force: true })\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  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: 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 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    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    this.child = undefined\n    const gateway = this.gatewayValue\n    this.gatewayValue = undefined\n    await settleRemoteResources([\n      async () => {\n        child?.stdin.end()\n        if (child !== undefined && child.exitCode === null) await terminateRemoteProcess(child)\n      },\n      () => gateway?.close(),\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 { 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(): Promise<void> {\n    const state = 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      if (!enabled) await this.stop()\n      this.enabled = enabled\n      await this.options.store.save({ version: 1, enabled })\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        this.enabled = true\n        await this.options.store.save({ version: 1, 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.stop()\n      this.enabled = false\n      await this.options.store.save({ version: 1, enabled: false })\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 { 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  rename,\n  rm,\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'\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\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): Promise<void> {\n  if (process.platform !== 'win32') throw new Error('cpolar_component_unsupported')\n  const unpacked = join(destination, 'archive')\n  const administrative = join(destination, 'administrative')\n  await mkdir(unpacked, { recursive: true, mode: 0o700 })\n  await mkdir(administrative, { recursive: true, mode: 0o700 })\n  await run('tar.exe', ['-xf', archive, '-C', unpacked])\n  const archiveEntries = await readdir(unpacked, { recursive: true })\n  const msiRelative = archiveEntries.find(entry => entry.toLowerCase().endsWith('.msi'))\n  if (msiRelative === undefined) throw new Error('cpolar_installer_missing')\n  await run('msiexec.exe', ['/a', join(unpacked, msiRelative), '/qn', `TARGETDIR=${administrative}`])\n  const installedEntries = await readdir(administrative, { recursive: true })\n  const executableRelative = installedEntries.find(entry => basename(entry).toLowerCase() === executableName.toLowerCase())\n  if (executableRelative === undefined) throw new Error('cpolar_executable_missing')\n  await copyFile(join(administrative, executableRelative), join(destination, executableName))\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' ? '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)\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 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    const stateDirectory = resolve(options.stateDirectory)\n    if (!isAbsolute(stateDirectory)) throw new Error('cpolar state directory must be absolute')\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 = 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  }\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, verify, and administratively extract cpolar after explicit confirmation. */\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 mkdir(this.stagingRoot, { recursive: true, mode: 0o700 })\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(release.downloadUrl, controller.signal) } 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 writeFile(archive, bytes, { flag: 'wx', mode: 0o600 })\n        await this.extractArtifact(archive, staging)\n        const extracted = join(staging, release.executableName)\n        if (!await regularFile(extracted, release.executableBytes)\n          || await sha256(extracted) !== release.executableSha256) {\n          throw new Error('cpolar_executable_hash_mismatch')\n        }\n        const candidate = join(this.componentRoot, `.install-${randomBytes(12).toString('hex')}`)\n        await mkdir(candidate, { recursive: true, mode: 0o700 })\n        await copyFile(extracted, join(candidate, release.executableName))\n        await chmod(join(candidate, release.executableName), 0o700)\n        await rm(this.componentStorage, { recursive: true, force: true })\n        await rename(candidate, this.componentStorage)\n        this.installed = true\n        this.errorCode = undefined\n      } finally {\n        await rm(staging, { recursive: true, force: true })\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      await mkdir(this.stateRoot, { recursive: true, mode: 0o700 })\n      const temporary = join(this.stateRoot, `.cpolar.${randomBytes(12).toString('hex')}.tmp`)\n      const body = `authtoken: ${JSON.stringify(token)}\\nconsole_ui: false\\nupdate: false\\ninspect_db_size: -1\\n`\n      try {\n        await writeFile(temporary, body, { encoding: 'utf8', flag: 'wx', mode: 0o600 })\n        await rename(temporary, this.configFile)\n        await restrictPrivateFile(this.configFile)\n      } catch (error) {\n        await rm(temporary, { force: true })\n        throw error\n      }\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 Promise.all([\n        rm(this.componentRoot, { recursive: true, force: true }),\n        rm(this.stateRoot, { recursive: true, force: true }),\n        rm(this.logRoot, { recursive: true, force: true }),\n        rm(this.stagingRoot, { recursive: true, force: true }),\n      ])\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","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 GITHUB_LATEST_URL = 'https://github.com/saya-ch/dsh-mobile/releases/latest'\nconst GITHUB_API_LATEST_URL = 'https://api.github.com/repos/saya-ch/dsh-mobile/releases/latest'\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\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 body of the latest GitHub release (What’s new + notices). */\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\nfunction githubReleaseVersion(location: string | null, responseUrl: string): string | undefined {\n  let url: URL\n  try { url = new URL(location ?? responseUrl, GITHUB_LATEST_URL) }\n  catch { return undefined }\n  if (url.origin !== 'https://github.com' || url.username !== '' || url.password !== '' || url.search !== '' || url.hash !== '') return undefined\n  const prefix = '/saya-ch/dsh-mobile/releases/tag/v'\n  if (!url.pathname.startsWith(prefix)) return undefined\n  let version: string\n  try { version = decodeURIComponent(url.pathname.slice(prefix.length)) } catch { return undefined }\n  return parseSemver(version) === undefined ? undefined : version\n}\n\nfunction androidReleaseDownloadUrl(version: string | undefined): string {\n  if (version === undefined) return GITHUB_RELEASES_URL\n  const tag = `v${version}`\n  return `https://github.com/saya-ch/dsh-mobile/releases/download/${encodeURIComponent(tag)}/dsh-mobile-android-${encodeURIComponent(tag)}.apk`\n}\n\nasync function fetchAndroidVersion(fetcher: typeof globalThis.fetch): Promise<string | undefined> {\n  const response = await fetcher(GITHUB_LATEST_URL, {\n    method: 'GET',\n    redirect: 'manual',\n    headers: { accept: 'text/html', 'user-agent': 'dsh-mobile-release-check' },\n    signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),\n  })\n  return githubReleaseVersion(response.headers.get('location'), response.url)\n}\n\n/** Best-effort body of the latest GitHub release, trimmed to a bounded size. */\nasync function fetchReleaseNotes(fetcher: typeof globalThis.fetch): Promise<string | undefined> {\n  const response = await fetcher(GITHUB_API_LATEST_URL, {\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 [npmResult, androidResult, notesResult] = await Promise.allSettled([\n      fetchNpmVersion(this.fetcher),\n      fetchAndroidVersion(this.fetcher),\n      fetchReleaseNotes(this.fetcher),\n    ])\n    const latestVersion = npmResult.status === 'fulfilled' ? npmResult.value : undefined\n    const androidVersion = 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      ...(androidVersion === undefined ? {} : { androidVersion }),\n      androidDownloadUrl: androidReleaseDownloadUrl(androidVersion),\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 { createWriteStream, type WriteStream } from 'node:fs'\nimport { lstat, mkdir, rename, rm } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { Logger, type Context, type Exporter, type Message } from '@deepseek-ai/cordis'\n\nconst MAX_LOG_BYTES = 5 * 1024 * 1024\n\n/** Install a plugin-scoped Cordis exporter backed by a private UTF-8 log file. */\nexport async function installMobileFileLogger(ctx: Context, stateDirectory: string): Promise<string> {\n  const directory = join(stateDirectory, 'logs')\n  const file = join(directory, 'dsh-mobile.log')\n  const previous = `${file}.1`\n  await mkdir(directory, { recursive: true, mode: 0o700 })\n  const entry = await lstat(file).catch(() => undefined)\n  if (entry !== undefined && entry.isFile() && !entry.isSymbolicLink() && entry.size >= MAX_LOG_BYTES) {\n    await rm(previous, { force: true })\n    await rename(file, previous)\n  }\n  const stream: WriteStream = createWriteStream(file, { flags: 'a', encoding: 'utf8', mode: 0o600 })\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 (message.name !== 'dsh-mobile') return\n      const record = {\n        timestamp: new Date(message.ts).toISOString(),\n        level: message.type,\n        logger: message.name,\n        message: Logger.format(exporter, message),\n      }\n      stream.write(`${JSON.stringify(record)}\\n`)\n    },\n  }\n  ctx.logger.exporter(exporter)\n  ctx.effect(() => () => { stream.end() }, 'dsh-mobile file logger')\n  return file\n}\n","import {\n  X509Certificate,\n  createPrivateKey,\n  createPublicKey,\n} from 'node:crypto'\nimport { execFileText as execFile } from './exec-file.js'\nimport { mkdir, readFile, rename, 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'\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  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'].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    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\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\nasync function atomicWrite(file: string, contents: string | Uint8Array): Promise<void> {\n  const directory = dirname(file)\n  await mkdir(directory, { recursive: true, mode: 0o700 })\n  const temporary = join(directory, `.${basename(file)}.${process.pid}.tmp`)\n  await writeFile(temporary, contents, { mode: 0o600 })\n  await rename(temporary, file)\n  await restrictPrivateFile(file)\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/** 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 Promise.all([restrictPrivateFile(setup.tls.caCertFile), restrictPrivateFile(setup.tls.caKeyFile)])\n  const [caCert, caKey] = await Promise.all([\n    readFile(setup.tls.caCertFile, 'utf8'),\n    readFile(setup.tls.caKeyFile, 'utf8'),\n  ])\n  assertMatchingCa(caCert, caKey)\n  const now = new Date()\n  const notAfter = new Date(now)\n  notAfter.setDate(notAfter.getDate() + 397)\n  const server = await generate([{ name: 'commonName', value: 'DeepSeek Harness Mobile' }], {\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: [{ type: 7, ip: address }] },\n    ],\n  })\n  await Promise.all([\n    atomicWrite(setup.tls.certFile, server.cert),\n    atomicWrite(setup.tls.keyFile, server.private),\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: [network.cidr],\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 { 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 { 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 { 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 } 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 } from './gateway.js'\nimport { createMobileAccessService, 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 { FrpConfigStore, mergeSavedFrpSettings, mergeSavedFrpTarget, type FrpConfigurationStatus } from './frp-config.js'\nimport { FrpController } from './frp.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 {\n  configuredRemoteProvider,\n  JsonRemoteProviderStore,\n  RemoteProviderCoordinator,\n  REMOTE_PROVIDERS,\n  type RemoteProvider,\n  type RemoteProviderController,\n  type RemoteProviderStatus,\n} from './remote.js'\nimport { parseAuthority, parseCidr } from './network.js'\nimport {\n  availableLanNetworks,\n  isNetworkSelectionError,\n  materializeManagedSetup,\n  parseManagedSetup,\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}\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  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  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}\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) }\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/** 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): 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      },\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  const frpConfig = new FrpConfigStore(join(remoteDirectory, 'frp', 'config'))\n  await frpConfig.initialize()\n  const originConfig = new OriginConfigStore(join(remoteDirectory, 'origin', 'config'))\n  await originConfig.initialize()\n  const cloudflaredTunnel = new CloudflaredTunnelStore(join(remoteDirectory, 'cloudflared'))\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  let lanGateway: MobileAccessGateway | undefined\n  let preparedLanSetup: ManagedLanSetupResult | undefined\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    )\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      )\n      await candidate.start()\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,\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 remoteControllers: Record<RemoteProvider, RemoteProviderController> = {\n    tailscale: new FunnelController({\n      store: tailscaleStore,\n      executable: funnelExecutable(import.meta.url),\n      stateDirectory: join(remoteDirectory, 'tailscale'),\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: createRemoteGateway,\n    }),\n    origin: new OriginController({ store: originStore, config: originConfig, createGateway: createOriginGateway }),\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  )\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  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    return collectConnectionDiagnostics({\n      dshVersion,\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    }) as unknown as Record<string, unknown>\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')\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 (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 === '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          await remoteProviders.mutate(async () => cpolarComponent.install())\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/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 === '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 Promise.all([frpComponent.purge(), frpConfig.purge()])\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`).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`).handler(request, response)\n          return\n        }\n        const active = lanGateway\n        if (active === undefined) throw new HttpError(409, 'gateway_stopped')\n        await active.localAdminRoute().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 disposeMobileCommand = ctx.commands.register({\n      name: 'mobile',\n      description: '按需求修改 DSH Mobile 的手机端界面或添加电脑端能力',\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 state: MobileGuideState = {\n          directory: stateDirectory,\n          hasCustomCss: await existsRegularFile(template.customCssFile),\n          hasCustomJs: await existsRegularFile(template.customScriptFile),\n          extensions: mobileAccess.manifest().map(entry => ({\n            id: entry.id,\n            name: entry.name,\n            version: entry.version,\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)\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      await Promise.all((Object.keys(stores) as RemoteProvider[])\n        .filter(provider => provider !== remoteProviders.selected)\n        .map(provider => stores[provider].save({ version: 1, enabled: false })))\n      for (const provider of REMOTE_PROVIDERS) await remoteControllers[provider].initialize()\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          unregister,\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        unregister,\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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"}