@dev-anywhere/relay 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/web/assets/{fvad-CKXL4ckP.js → fvad-oSUTPVOe.js} +1 -1
- package/assets/web/assets/index-BVDmlZok.css +41 -0
- package/assets/web/assets/{index-Ba6B8Wrv.js → index-BeQpXrcf.js} +184 -184
- package/assets/web/assets/{jmuxer.min-DxI99rgK.js → jmuxer.min-BcaOPF7j.js} +1 -1
- package/assets/web/index.html +2 -2
- package/assets/web/sw.js +1 -1
- package/dist/{chunk-27ZHYXYL.js → chunk-RGMU7VLD.js} +869 -594
- package/dist/chunk-RGMU7VLD.js.map +1 -0
- package/dist/client-registration-admission.d.ts +14 -0
- package/dist/client-registration-admission.d.ts.map +1 -0
- package/dist/handlers/client.d.ts +1 -1
- package/dist/handlers/client.d.ts.map +1 -1
- package/dist/handlers/proxy.d.ts +1 -1
- package/dist/handlers/proxy.d.ts.map +1 -1
- package/dist/health.d.ts.map +1 -1
- package/dist/index.js +551 -51
- package/dist/index.js.map +1 -1
- package/dist/proxy-upgrade-bootstrap.d.ts +13 -0
- package/dist/proxy-upgrade-bootstrap.d.ts.map +1 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -1
- package/package.json +3 -3
- package/assets/web/assets/index-CTJCtPHc.css +0 -41
- package/dist/chunk-27ZHYXYL.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../packages/shared/src/logger.ts","../src/runtime-env.ts","../src/index.ts"],"sourcesContent":["import {\n lstatSync,\n mkdirSync,\n readdirSync,\n renameSync,\n statSync,\n symlinkSync,\n unlinkSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport pino from \"pino\";\n\nexport type { Logger } from \"pino\";\n\nexport interface CreateLoggerOptions {\n name: string;\n level?: string;\n logDir?: string;\n retention?: number;\n stdout?: boolean;\n silent?: boolean;\n // 同步落盘:sonic-boom 默认异步 open + 异步 write,测试里需要在断言前看到文件,\n // 或在 afterEach 删目录前确保后台 worker 已经退出,必须开同步。生产保留异步以避免热路径阻塞。\n sync?: boolean;\n}\n\nconst DEFAULT_LOG_DIR = `${homedir()}/.dev-anywhere/logs`;\nconst DEFAULT_LOG_RETENTION = 50;\n\nconst PROCESS_LOG_RUN_ID = sanitizeRunId(\n `${new Date().toISOString().replace(/[:.]/g, \"-\")}-${process.pid}`,\n);\n\nfunction sanitizeRunId(runId: string): string {\n return runId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n}\n\nfunction linkLatestLog(logDir: string, name: string, filePath: string, runId: string): void {\n const latestPath = join(logDir, `${name}.log`);\n\n try {\n const stat = lstatSync(latestPath);\n if (stat.isSymbolicLink()) {\n unlinkSync(latestPath);\n } else {\n renameSync(latestPath, join(logDir, `${name}-legacy-${runId}.log`));\n }\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") return;\n }\n\n try {\n symlinkSync(basename(filePath), latestPath);\n } catch {\n // 日志本体仍然写入 run-specific 文件;latest 链接失败不应阻塞服务启动。\n }\n}\n\nfunction resolveRetention(retention: number | undefined): number {\n if (retention === undefined) return DEFAULT_LOG_RETENTION;\n return Number.isFinite(retention) && retention >= 0\n ? Math.floor(retention)\n : DEFAULT_LOG_RETENTION;\n}\n\nfunction pruneOldLogs(\n logDir: string,\n name: string,\n currentFilePath: string,\n retention: number | undefined,\n): void {\n const keep = resolveRetention(retention);\n if (keep === 0) return;\n\n const currentFileName = basename(currentFilePath);\n const prefix = `${name}-`;\n const candidates = readdirSync(logDir)\n .filter(\n (entry) => entry.startsWith(prefix) && entry.endsWith(\".log\") && entry !== currentFileName,\n )\n .map((entry) => {\n const path = join(logDir, entry);\n try {\n return { path, mtimeMs: statSync(path).mtimeMs };\n } catch {\n return null;\n }\n })\n .filter((entry): entry is { path: string; mtimeMs: number } => entry !== null)\n .sort((a, b) => b.mtimeMs - a.mtimeMs);\n\n for (const stale of candidates.slice(Math.max(0, keep - 1))) {\n try {\n unlinkSync(stale.path);\n } catch {\n // 日志清理失败不能影响主进程启动。\n }\n }\n}\n\n// SonicBoom 实例的最小结构契约(pino.destination 返回它,但 pino 类型只暴露 DestinationStream\n// 接口,没有 fd / flushSync / once,所以这里手写一个结构类型用于 flushLogger)。\ninterface SonicLikeDestination {\n fd?: number;\n _writing?: boolean;\n flushSync?: () => void;\n once?: (event: string, cb: (...args: unknown[]) => void) => void;\n}\n\ninterface LoggerMeta {\n materialized: boolean;\n destination: SonicLikeDestination | null;\n}\n\nconst loggerMetaMap = new WeakMap<pino.Logger, LoggerMeta>();\n\nfunction buildPinoLogger(options: CreateLoggerOptions): {\n logger: pino.Logger;\n destination: SonicLikeDestination | null;\n} {\n const {\n name,\n level = \"info\",\n logDir = DEFAULT_LOG_DIR,\n retention,\n stdout = false,\n silent = false,\n sync = false,\n } = options;\n\n if (silent) {\n return { logger: pino({ level: \"silent\" }), destination: null };\n }\n\n mkdirSync(logDir, { recursive: true });\n\n const runId = PROCESS_LOG_RUN_ID;\n const filePath = join(logDir, `${name}-${runId}.log`);\n linkLatestLog(logDir, name, filePath, runId);\n pruneOldLogs(logDir, name, filePath, retention);\n const destination = pino.destination({ dest: filePath, sync }) as unknown as SonicLikeDestination;\n const streams: pino.StreamEntry[] = [{ stream: destination as pino.DestinationStream }];\n\n if (stdout) {\n streams.unshift({ stream: process.stdout });\n }\n\n return { logger: pino({ level }, pino.multistream(streams)), destination };\n}\n\n// 返回一个 lazy proxy:调用 createLogger 本身不触发 mkdirSync / pino.destination\n// 等任何文件 IO,只有第一次实际访问 logger 的方法/属性时才构造底层 pino Logger。\n// 这样 `dev-anywhere -v` / `dev-anywhere init` 等不需要写日志的命令路径不会\n// 落地空 log 文件,也避免异步 SonicBoom 在 process.exit 时未 ready 的 race。\nexport function createLogger(options: CreateLoggerOptions): pino.Logger {\n let real: pino.Logger | null = null;\n const meta: LoggerMeta = { materialized: false, destination: null };\n const ensure = (): pino.Logger => {\n if (!real) {\n const built = buildPinoLogger(options);\n real = built.logger;\n meta.materialized = true;\n meta.destination = built.destination;\n }\n return real;\n };\n\n const proxy = new Proxy(Object.create(null) as pino.Logger, {\n get(_target, prop) {\n const target = ensure();\n const value = Reflect.get(target, prop, target);\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n set(_target, prop, value) {\n return Reflect.set(ensure(), prop, value);\n },\n has(_target, prop) {\n return Reflect.has(ensure(), prop);\n },\n ownKeys() {\n return Reflect.ownKeys(ensure());\n },\n getOwnPropertyDescriptor(_target, prop) {\n return Reflect.getOwnPropertyDescriptor(ensure(), prop);\n },\n });\n\n loggerMetaMap.set(proxy, meta);\n return proxy;\n}\n\n// 进程退出前等 sonic-boom 真正落盘。`pino.flush(cb)` 在 destination 还没 ready\n// (fs.open 异步未完成)时会立刻回调 err=undefined 撒谎成功,但文件还是空的,所以\n// 这里直接走 sonic-boom 的 ready 事件 + flushSync 路径。\n// - 未实例化(lazy proxy 没被访问过) → no-op,不会触发文件 IO 副作用。\n// - silent / stdout-only(destination 为 null) → no-op。\n// - timeoutMs 是兜底,确保异常情况下不会卡住进程退出。\nexport async function flushLogger(logger: pino.Logger, timeoutMs = 200): Promise<void> {\n const meta = loggerMetaMap.get(logger);\n if (!meta || !meta.materialized) return;\n const dest = meta.destination;\n if (!dest) return;\n\n if (dest.fd == null || dest.fd < 0) {\n const opened = await new Promise<boolean>((resolve) => {\n const timer = setTimeout(() => resolve(false), timeoutMs);\n dest.once?.(\"ready\", () => {\n clearTimeout(timer);\n resolve(true);\n });\n dest.once?.(\"error\", () => {\n clearTimeout(timer);\n resolve(false);\n });\n });\n if (!opened) return;\n }\n\n // SonicBoom emits `ready` before it starts writing data queued while the file was opening.\n // Calling flushSync during that in-flight async write only fsyncs the still-empty file. Wait\n // for `drain` first, then synchronously flush anything that was queued behind that write.\n if (dest._writing) {\n const drained = await new Promise<boolean>((resolve) => {\n const timer = setTimeout(() => resolve(false), timeoutMs);\n dest.once?.(\"drain\", () => {\n clearTimeout(timer);\n resolve(true);\n });\n dest.once?.(\"error\", () => {\n clearTimeout(timer);\n resolve(false);\n });\n });\n if (!drained) return;\n }\n\n try {\n dest.flushSync?.();\n } catch {\n // 文件描述符已关闭、磁盘满等极端情况下吞掉异常,避免把退出路径变成崩溃路径。\n }\n}\n","// Relay 运行时环境变量的单一入口。和 proxy 侧 runtime-env.ts 同一思路:\n// 类型化输出 + 一次性校验,避免 parseInt / 默认值散落在 index.ts 和 chaos.ts。\nimport { homedir } from \"node:os\";\nimport { parseRelayChaosFromEnv, type RelayChaosOptions } from \"./chaos.js\";\n\nconst DEFAULT_DATA_DIR = `${homedir()}/.dev-anywhere/relay-data`;\nconst DEFAULT_PORT = 3100;\nconst DEFAULT_HEARTBEAT_INTERVAL = 30000;\n\ninterface RelayRuntimeEnv {\n port: number;\n // DATA_DIR 显式置 \"\" 表示关闭持久化目录;未设置时回落到 ~/.dev-anywhere/relay-data。\n dataDir: string | undefined;\n heartbeatInterval: number;\n // 任一 token 未设置(或空串)→ 对应端点关闭鉴权(仅 dev 可用)。\n proxyToken: string | undefined;\n clientToken: string | undefined;\n // ALLOWED_ORIGINS=https://app.example.com,https://www.example.com — 逗号分隔。\n // 空 / 未设置 = 不校验 (向后兼容; 本地 dev / Capacitor / file:// 等场景需要)。\n // 公网部署务必设置, 防 CSWSH。\n allowedOrigins: string[];\n logLevel: string;\n chaos: RelayChaosOptions;\n voiceDefaults: {\n region?: \"cn\" | \"intl\";\n asrModel?: string;\n ttsModel?: string;\n ttsVoice?: string;\n };\n}\n\nfunction parsePort(value: string | undefined, fallback: number, source: string): number {\n if (!value) return fallback;\n const port = Number(value);\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw new Error(`Invalid ${source}=${JSON.stringify(value)}: expected TCP port 1-65535`);\n }\n return port;\n}\n\nfunction parsePositiveInt(value: string | undefined, fallback: number, source: string): number {\n if (!value) return fallback;\n const n = Number(value);\n if (!Number.isInteger(n) || n <= 0) {\n throw new Error(`Invalid ${source}=${JSON.stringify(value)}: expected positive integer`);\n }\n return n;\n}\n\nfunction nonEmpty(value: string | undefined): string | undefined {\n return value && value.length > 0 ? value : undefined;\n}\n\nfunction parseVoiceRegion(value: string | undefined): \"cn\" | \"intl\" | undefined {\n if (!value) return undefined;\n if (value === \"cn\" || value === \"intl\") return value;\n throw new Error(`Invalid BAILIAN_REGION=${JSON.stringify(value)}: expected cn or intl`);\n}\n\nexport function loadRelayRuntimeEnv(env: NodeJS.ProcessEnv = process.env): RelayRuntimeEnv {\n const dataDirRaw = env.DATA_DIR ?? DEFAULT_DATA_DIR;\n const voiceRegion = parseVoiceRegion(env.BAILIAN_REGION);\n return {\n port: parsePort(env.PORT, DEFAULT_PORT, \"PORT\"),\n dataDir: dataDirRaw.length > 0 ? dataDirRaw : undefined,\n heartbeatInterval: parsePositiveInt(\n env.HEARTBEAT_INTERVAL,\n DEFAULT_HEARTBEAT_INTERVAL,\n \"HEARTBEAT_INTERVAL\",\n ),\n proxyToken: nonEmpty(env.RELAY_PROXY_TOKEN),\n clientToken: nonEmpty(env.RELAY_CLIENT_TOKEN),\n allowedOrigins: (env.ALLOWED_ORIGINS ?? \"\")\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0),\n logLevel: env.LOG_LEVEL ?? \"info\",\n chaos: parseRelayChaosFromEnv(env),\n voiceDefaults: {\n ...(voiceRegion ? { region: voiceRegion } : {}),\n ...(nonEmpty(env.BAILIAN_ASR_MODEL) ? { asrModel: env.BAILIAN_ASR_MODEL } : {}),\n ...(nonEmpty(env.BAILIAN_TTS_MODEL) ? { ttsModel: env.BAILIAN_TTS_MODEL } : {}),\n ...(nonEmpty(env.BAILIAN_TTS_VOICE) ? { ttsVoice: env.BAILIAN_TTS_VOICE } : {}),\n },\n };\n}\n","import { createLogger, flushLogger } from \"@dev-anywhere/shared/logger\";\nimport { createRelayServer } from \"./server.js\";\nimport { loadRelayRuntimeEnv } from \"./runtime-env.js\";\nimport { RELAY_VERSION } from \"./version.js\";\n\nfunction printHelp(): void {\n console.log(`DEV Anywhere Relay and Web Server\n\nUsage:\n dev-anywhere-relay [options]\n\nThe bundled Web client, HTTP API, and WebSocket endpoints share the same port.\n\nOptions:\n -h, --help Show this help message\n -v, --version Print version\n\nEnvironment:\n PORT HTTP/WebSocket listen port (default: 3100)\n RELAY_PROXY_TOKEN Optional token for /proxy connections\n RELAY_CLIENT_TOKEN Optional token for /client connections\n DATA_DIR Relay persistence directory; empty disables persistence\n LOG_LEVEL Log level (default: info)\n HEARTBEAT_INTERVAL Proxy/client heartbeat interval in ms (default: 30000)\n`);\n}\n\nconst args = process.argv.slice(2);\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\n printHelp();\n process.exit(0);\n}\nif (args.includes(\"--version\") || args.includes(\"-v\")) {\n console.log(RELAY_VERSION);\n process.exit(0);\n}\n\nconst env = loadRelayRuntimeEnv();\n\nconst logger = createLogger({\n name: \"relay\",\n level: env.logLevel,\n stdout: true,\n});\n\nconst relay = createRelayServer({\n port: env.port,\n logger,\n dataDir: env.dataDir,\n heartbeatInterval: env.heartbeatInterval,\n proxyToken: env.proxyToken,\n clientToken: env.clientToken,\n allowedOrigins: env.allowedOrigins,\n chaos: env.chaos,\n voiceDefaults: env.voiceDefaults,\n});\n\nrelay.httpServer.listen(env.port, () => {\n const addr = relay.httpServer.address();\n const actualPort = typeof addr === \"object\" && addr ? addr.port : env.port;\n logger.info({ port: actualPort }, \"Relay server started\");\n});\n\nasync function shutdown(): Promise<void> {\n logger.info(\"Shutting down relay server\");\n await relay.close();\n await flushLogger(logger);\n process.exit(0);\n}\n\nprocess.on(\"SIGTERM\", () => {\n shutdown();\n});\nprocess.on(\"SIGINT\", () => {\n shutdown();\n});\n"],"mappings":"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","names":["logger","homedir","homedir","env"]}
|
|
1
|
+
{"version":3,"sources":["../../../packages/shared/src/logger.ts","../src/runtime-env.ts","../src/index.ts"],"sourcesContent":["import {\n lstatSync,\n linkSync,\n mkdirSync,\n readFileSync,\n readdirSync,\n renameSync,\n statSync,\n symlinkSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { randomUUID } from \"node:crypto\";\nimport { homedir } from \"node:os\";\nimport { basename, join } from \"node:path\";\nimport pino from \"pino\";\n\nexport type { Logger } from \"pino\";\n\nexport interface CreateLoggerOptions {\n name: string;\n level?: string;\n logDir?: string;\n retention?: number;\n // A live process must never be able to grow one log file without bound. The limit is applied\n // to serialized UTF-8 bytes and rotation keeps at most maxFilesPerRun files for this process.\n maxFileBytes?: number;\n maxFilesPerRun?: number;\n maxRecordBytes?: number;\n retentionBytes?: number;\n stdout?: boolean;\n silent?: boolean;\n // 同步落盘:sonic-boom 默认异步 open + 异步 write,测试里需要在断言前看到文件,\n // 或在 afterEach 删目录前确保后台 worker 已经退出,必须开同步。生产保留异步以避免热路径阻塞。\n sync?: boolean;\n}\n\nconst DEFAULT_LOG_DIR = `${homedir()}/.dev-anywhere/logs`;\nconst DEFAULT_LOG_RETENTION = 50;\nconst DEFAULT_LOG_RETENTION_BYTES = 256 * 1024 * 1024;\nconst DEFAULT_MAX_FILE_BYTES = 16 * 1024 * 1024;\nconst DEFAULT_MAX_FILES_PER_RUN = 2;\nconst DEFAULT_MAX_RECORD_BYTES = 256 * 1024;\nconst DEFAULT_MAX_STDOUT_BUFFER_BYTES = 1024 * 1024;\nconst LOG_IO_OPERATION_TIMEOUT_MS = 5_000;\nconst LOG_RUN_LEASE_SUFFIX = \".active\";\nconst LOG_RUN_LEASE_CANDIDATE_MARKER = `${LOG_RUN_LEASE_SUFFIX}.candidate-`;\n\nconst PROCESS_LOG_RUN_ID = sanitizeRunId(\n `${new Date().toISOString().replace(/[:.]/g, \"-\")}-${process.pid}`,\n);\n\nfunction sanitizeRunId(runId: string): string {\n return runId.replace(/[^a-zA-Z0-9._-]/g, \"_\");\n}\n\nfunction linkLatestLog(logDir: string, name: string, filePath: string, runId: string): void {\n const latestPath = join(logDir, `${name}.log`);\n\n try {\n const stat = lstatSync(latestPath);\n if (stat.isSymbolicLink()) {\n unlinkSync(latestPath);\n } else {\n renameSync(latestPath, join(logDir, `${name}-legacy-${runId}.log`));\n }\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"ENOENT\") return;\n }\n\n try {\n symlinkSync(basename(filePath), latestPath);\n } catch {\n // 日志本体仍然写入 run-specific 文件;latest 链接失败不应阻塞服务启动。\n }\n}\n\nfunction resolveRetention(retention: number | undefined): number {\n if (retention === undefined) return DEFAULT_LOG_RETENTION;\n return Number.isFinite(retention) && retention >= 0\n ? Math.floor(retention)\n : DEFAULT_LOG_RETENTION;\n}\n\nfunction resolvePositiveInteger(value: number | undefined, fallback: number): number {\n return value !== undefined && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;\n}\n\ninterface LogRunLease {\n version: 1;\n pid: number;\n runId: string;\n fileName: string;\n}\n\nfunction leasePathForLog(filePath: string): string {\n return `${filePath}${LOG_RUN_LEASE_SUFFIX}`;\n}\n\nfunction createLogRunLease(filePath: string, runId: string): void {\n const lease: LogRunLease = {\n version: 1,\n pid: process.pid,\n runId,\n fileName: basename(filePath),\n };\n const leasePath = leasePathForLog(filePath);\n const candidatePath = `${leasePath}.candidate-${process.pid}-${randomUUID()}`;\n let candidateCreated = false;\n try {\n // Publish through a hard link only after the same-directory candidate has been completely\n // written and closed. Unlike writing directly to the final path, readers can therefore never\n // observe an empty or partially serialized lease, and link(2) retains O_EXCL semantics.\n writeFileSync(candidatePath, `${JSON.stringify(lease)}\\n`, { flag: \"wx\" });\n candidateCreated = true;\n linkSync(candidatePath, leasePath);\n } finally {\n if (candidateCreated) {\n try {\n unlinkSync(candidatePath);\n } catch {\n // A crash or unlink failure can leave a valid candidate. A future logger run reclaims it\n // once its owner is known to be dead.\n }\n }\n }\n}\n\nfunction isProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n return (error as NodeJS.ErrnoException).code !== \"ESRCH\";\n }\n}\n\ntype LogRunLeaseReadResult =\n | { state: \"missing\" }\n | { state: \"invalid\" }\n | { state: \"valid\"; lease: LogRunLease };\n\nfunction readLogRunLease(leasePath: string, expectedFileName: string): LogRunLeaseReadResult {\n let raw: string;\n try {\n raw = readFileSync(leasePath, \"utf-8\");\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === \"ENOENT\"\n ? { state: \"missing\" }\n : { state: \"invalid\" };\n }\n\n try {\n const parsed = JSON.parse(raw) as Partial<LogRunLease>;\n const pid = parsed.pid;\n if (\n parsed.version !== 1 ||\n !Number.isSafeInteger(pid) ||\n typeof pid !== \"number\" ||\n pid <= 0 ||\n typeof parsed.runId !== \"string\" ||\n parsed.runId.length === 0 ||\n parsed.fileName !== expectedFileName\n ) {\n throw new Error(\"Invalid log run lease\");\n }\n return { state: \"valid\", lease: parsed as LogRunLease };\n } catch {\n // A malformed lease might be a concurrently published or externally damaged ownership\n // record. Fail closed: neither the lease nor its corresponding log may be deleted.\n return { state: \"invalid\" };\n }\n}\n\nfunction hasLiveLogRunLease(filePath: string): boolean {\n const leasePath = leasePathForLog(filePath);\n const result = readLogRunLease(leasePath, basename(filePath));\n if (result.state === \"missing\") return false;\n if (result.state === \"invalid\") return true;\n\n if (isProcessAlive(result.lease.pid)) return true;\n try {\n unlinkSync(leasePath);\n } catch {\n // The owning process is gone, so the log is stale even if its lease cannot be removed.\n }\n return false;\n}\n\nfunction removeOwnedLogRunLease(filePath: string, runId: string): void {\n const leasePath = leasePathForLog(filePath);\n const result = readLogRunLease(leasePath, basename(filePath));\n if (\n result.state !== \"valid\" ||\n result.lease.pid !== process.pid ||\n result.lease.runId !== runId\n ) {\n return;\n }\n try {\n unlinkSync(leasePath);\n } catch {\n // Cleanup is best effort. A valid lease left behind is reclaimable after this process exits.\n }\n}\n\nfunction parseLeaseEntry(\n entry: string,\n name: string,\n): { fileName: string; candidate: boolean } | null {\n const prefix = `${name}-`;\n if (!entry.startsWith(prefix)) return null;\n if (entry.endsWith(LOG_RUN_LEASE_SUFFIX)) {\n const fileName = entry.slice(0, -LOG_RUN_LEASE_SUFFIX.length);\n return fileName.endsWith(\".log\") ? { fileName, candidate: false } : null;\n }\n\n const markerIndex = entry.lastIndexOf(LOG_RUN_LEASE_CANDIDATE_MARKER);\n if (markerIndex < 0 || markerIndex + LOG_RUN_LEASE_CANDIDATE_MARKER.length >= entry.length) {\n return null;\n }\n const fileName = entry.slice(0, markerIndex);\n return fileName.endsWith(\".log\") ? { fileName, candidate: true } : null;\n}\n\nfunction pruneOrphanedLogRunLeases(logDir: string, name: string): void {\n for (const entry of readdirSync(logDir)) {\n const parsedEntry = parseLeaseEntry(entry, name);\n if (!parsedEntry) continue;\n\n const leasePath = join(logDir, entry);\n const result = readLogRunLease(leasePath, parsedEntry.fileName);\n if (result.state !== \"valid\" || isProcessAlive(result.lease.pid)) continue;\n\n let correspondingLogExists = false;\n try {\n statSync(join(logDir, parsedEntry.fileName));\n correspondingLogExists = true;\n } catch {\n // A missing log makes a valid dead-owner lease an orphan.\n }\n if (!parsedEntry.candidate && correspondingLogExists) continue;\n\n try {\n unlinkSync(leasePath);\n } catch {\n // A concurrent cleanup or filesystem error must not prevent logger startup.\n }\n }\n}\n\nfunction removeLogAndLease(filePath: string): void {\n unlinkSync(filePath);\n try {\n unlinkSync(leasePathForLog(filePath));\n } catch {\n // Missing or concurrently removed stale leases need no further cleanup.\n }\n}\n\nfunction pruneOldLogs(\n logDir: string,\n name: string,\n currentFilePath: string,\n retention: number | undefined,\n retentionBytes: number | undefined,\n): void {\n const keep = resolveRetention(retention);\n const byteBudget = resolvePositiveInteger(retentionBytes, DEFAULT_LOG_RETENTION_BYTES);\n pruneOrphanedLogRunLeases(logDir, name);\n if (keep === 0) return;\n\n const currentFileName = basename(currentFilePath);\n const prefix = `${name}-`;\n const candidates = readdirSync(logDir)\n .filter(\n (entry) => entry.startsWith(prefix) && entry.endsWith(\".log\") && entry !== currentFileName,\n )\n .map((entry) => {\n const path = join(logDir, entry);\n try {\n const stat = statSync(path);\n return { path, mtimeMs: stat.mtimeMs, size: stat.size };\n } catch {\n return null;\n }\n })\n .filter((entry): entry is { path: string; mtimeMs: number; size: number } => entry !== null)\n .sort((a, b) => b.mtimeMs - a.mtimeMs);\n\n const retained: typeof candidates = [];\n let retainedBytes = 0;\n for (const candidate of candidates) {\n if (hasLiveLogRunLease(candidate.path)) {\n retained.push(candidate);\n retainedBytes += candidate.size;\n continue;\n }\n const withinCount = keep === 0 || retained.length < Math.max(0, keep - 1);\n const withinBytes = retainedBytes + candidate.size <= byteBudget;\n if (withinCount && withinBytes) {\n retained.push(candidate);\n retainedBytes += candidate.size;\n continue;\n }\n try {\n removeLogAndLease(candidate.path);\n } catch {\n // 日志清理失败不能影响主进程启动。\n }\n }\n}\n\n// SonicBoom 实例的最小结构契约(pino.destination 返回它,但 pino 类型只暴露 DestinationStream\n// 接口,没有 fd / flushSync / once,所以这里手写一个结构类型用于 flushLogger)。\ninterface SonicLikeDestination {\n fd?: number;\n _writing?: boolean;\n sync?: boolean;\n write?: (data: string) => boolean | void;\n reopen?: (filePath?: string) => void;\n flushSync?: () => void;\n on?: (event: string, cb: (...args: unknown[]) => void) => void;\n off?: (event: string, cb: (...args: unknown[]) => void) => void;\n once?: (event: string, cb: (...args: unknown[]) => void) => void;\n listenerCount?: (event: string) => number;\n}\n\nfunction waitForDestinationEvent(\n destination: SonicLikeDestination,\n event: string,\n deadline?: number,\n): Promise<boolean> {\n if (!destination.on || !destination.off) return Promise.resolve(false);\n const addListener = destination.on.bind(destination);\n const removeListener = destination.off.bind(destination);\n const remaining = deadline === undefined ? undefined : deadline - Date.now();\n if (remaining !== undefined && remaining <= 0) return Promise.resolve(false);\n\n return new Promise<boolean>((resolve) => {\n let settled = false;\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n const cleanup = () => {\n if (timer) clearTimeout(timer);\n removeListener(event, onEvent);\n removeListener(\"error\", onError);\n };\n const settle = (result: boolean) => {\n if (settled) return;\n settled = true;\n cleanup();\n resolve(result);\n };\n const onEvent = () => settle(true);\n const onError = () => settle(false);\n\n addListener(event, onEvent);\n addListener(\"error\", onError);\n if (remaining !== undefined) {\n timer = setTimeout(() => settle(false), remaining);\n timer.unref?.();\n }\n });\n}\n\ninterface WritableLikeDestination {\n writableLength?: number;\n write(data: string): boolean | void;\n}\n\nclass BoundedWritableDestination implements pino.DestinationStream {\n private droppedRecords = 0;\n private saturated = false;\n\n constructor(\n private readonly destination: WritableLikeDestination,\n private readonly maxPendingBytes: number,\n ) {}\n\n write(serialized: string): void {\n if (this.saturated) return;\n const bytes = Buffer.byteLength(serialized);\n const pendingBytes = this.destination.writableLength;\n if (\n bytes > this.maxPendingBytes ||\n typeof pendingBytes !== \"number\" ||\n !Number.isFinite(pendingBytes)\n ) {\n this.droppedRecords += 1;\n return;\n }\n\n const droppedDiagnostic =\n this.droppedRecords > 0\n ? `${JSON.stringify({\n level: 40,\n time: Date.now(),\n msg: \"Log records were dropped while stdout was backpressured\",\n dropped: this.droppedRecords,\n })}\\n`\n : null;\n const diagnosticBytes = droppedDiagnostic ? Buffer.byteLength(droppedDiagnostic) : 0;\n if (pendingBytes + diagnosticBytes + bytes > this.maxPendingBytes) {\n this.droppedRecords += 1;\n return;\n }\n\n try {\n if (droppedDiagnostic) this.destination.write(droppedDiagnostic);\n this.destination.write(serialized);\n this.droppedRecords = 0;\n } catch {\n this.saturated = true;\n }\n }\n}\n\nclass BoundedLogDestination implements pino.DestinationStream, SonicLikeDestination {\n private currentBytes = 0;\n private rotating = false;\n private saturated = false;\n private droppedDuringRotation = 0;\n private pendingRecord: string | null = null;\n private rotationPromise: Promise<void> | null = null;\n private readonly rotationWaiters = new Set<() => void>();\n\n constructor(\n private readonly destination: SonicLikeDestination,\n private readonly filePath: string,\n private readonly runId: string,\n private readonly logDir: string,\n private readonly name: string,\n private readonly retention: number | undefined,\n private readonly retentionBytes: number | undefined,\n private readonly maxFileBytes: number,\n private readonly maxFilesPerRun: number,\n private readonly maxRecordBytes: number,\n initialBytes: number,\n ) {\n this.currentBytes = initialBytes;\n // A filesystem failure in SonicBoom must not turn diagnostics into an uncaught process\n // exception. Stop accepting further records; the application can keep serving and the\n // already-enforced byte bound still holds.\n this.destination.on?.(\"error\", () => {\n this.rotating = false;\n this.saturated = true;\n if (this.destination.fd == null || this.destination.fd < 0) {\n removeOwnedLogRunLease(this.filePath, this.runId);\n }\n });\n }\n\n get fd(): number | undefined {\n return this.destination.fd;\n }\n\n get _writing(): boolean | undefined {\n return this.destination._writing;\n }\n\n once(event: string, cb: (...args: unknown[]) => void): void {\n this.destination.once?.(event, cb);\n }\n\n on(event: string, cb: (...args: unknown[]) => void): void {\n this.destination.on?.(event, cb);\n }\n\n off(event: string, cb: (...args: unknown[]) => void): void {\n this.destination.off?.(event, cb);\n }\n\n listenerCount(event: string): number {\n return this.destination.listenerCount?.(event) ?? 0;\n }\n\n write(serialized: string): void {\n if (this.saturated) return;\n const record = this.boundRecord(serialized);\n if (!record) return;\n const bytes = Buffer.byteLength(record);\n\n if (this.rotating) {\n this.droppedDuringRotation += 1;\n return;\n }\n if (this.currentBytes + bytes > this.maxFileBytes) {\n this.startRotation(record);\n return;\n }\n\n this.writeActiveRecord(record);\n }\n\n flushSync(): void {\n this.destination.flushSync?.();\n }\n\n async waitForRotation(deadline: number): Promise<boolean> {\n while (this.rotationPromise) {\n const remaining = deadline - Date.now();\n if (remaining <= 0) return false;\n const settled = await new Promise<boolean>((resolve) => {\n let finished = false;\n const waiter = () => finish(true);\n const timer = setTimeout(() => finish(false), remaining);\n timer.unref?.();\n const finish = (result: boolean) => {\n if (finished) return;\n finished = true;\n clearTimeout(timer);\n this.rotationWaiters.delete(waiter);\n resolve(result);\n };\n\n this.rotationWaiters.add(waiter);\n if (!this.rotationPromise) finish(true);\n });\n if (!settled) return false;\n }\n return true;\n }\n\n private boundRecord(serialized: string): string | null {\n const bytes = Buffer.byteLength(serialized);\n if (bytes <= this.maxRecordBytes && bytes <= this.maxFileBytes) return serialized;\n return this.boundDiagnostic({\n level: 40,\n time: Date.now(),\n msg: \"Log entry omitted because it exceeded the configured byte limit\",\n originalBytes: bytes,\n });\n }\n\n private boundDiagnostic(value: Record<string, unknown>): string | null {\n const serialized = `${JSON.stringify(value)}\\n`;\n const bytes = Buffer.byteLength(serialized);\n return bytes <= this.maxRecordBytes && bytes <= this.maxFileBytes ? serialized : null;\n }\n\n private segmentPath(index: number): string {\n return this.filePath.replace(/\\.log$/, `.${index}.log`);\n }\n\n private writeActiveRecord(record: string): boolean {\n const bytes = Buffer.byteLength(record);\n if (!this.destination.write || this.currentBytes + bytes > this.maxFileBytes) return false;\n this.currentBytes += bytes;\n try {\n this.destination.write(record);\n return !this.saturated;\n } catch {\n this.saturated = true;\n return false;\n }\n }\n\n private startRotation(pendingRecord: string): void {\n if (this.rotating || this.saturated) return;\n this.rotating = true;\n this.pendingRecord = pendingRecord;\n\n const tracked = Promise.resolve()\n .then(() => this.performRotation())\n .catch(() => {\n this.saturated = true;\n this.rotating = false;\n this.pendingRecord = null;\n this.droppedDuringRotation = 0;\n })\n .finally(() => {\n if (this.rotationPromise === tracked) this.rotationPromise = null;\n for (const waiter of this.rotationWaiters) waiter();\n this.rotationWaiters.clear();\n });\n this.rotationPromise = tracked;\n }\n\n private async performRotation(): Promise<void> {\n if (!this.destination.reopen) throw new Error(\"Log destination cannot be reopened\");\n const deadline = Date.now() + LOG_IO_OPERATION_TIMEOUT_MS;\n\n if (this.destination.fd == null || this.destination.fd < 0) {\n if (!(await waitForDestinationEvent(this.destination, \"ready\", deadline))) {\n throw new Error(\"Log destination did not become ready\");\n }\n }\n if (this.destination._writing) {\n if (!(await waitForDestinationEvent(this.destination, \"drain\", deadline))) {\n throw new Error(\"Log destination did not drain\");\n }\n }\n\n this.rotateFiles();\n this.destination.reopen(this.filePath);\n if (!(await waitForDestinationEvent(this.destination, \"ready\", deadline))) {\n throw new Error(\"Rotated log destination did not become ready\");\n }\n pruneOldLogs(this.logDir, this.name, this.filePath, this.retention, this.retentionBytes);\n\n this.currentBytes = 0;\n const pendingRecord = this.pendingRecord;\n this.pendingRecord = null;\n const dropped = this.droppedDuringRotation;\n this.droppedDuringRotation = 0;\n this.rotating = false;\n\n if (pendingRecord && !this.writeActiveRecord(pendingRecord)) return;\n if (dropped === 0 || this.saturated) return;\n const diagnostic = this.boundDiagnostic({\n level: 40,\n time: Date.now(),\n msg: \"Log records were dropped while rotating the active file\",\n dropped,\n });\n if (diagnostic && this.currentBytes + Buffer.byteLength(diagnostic) <= this.maxFileBytes) {\n this.writeActiveRecord(diagnostic);\n }\n }\n\n private rotateFiles(): void {\n if (this.maxFilesPerRun > 1) {\n try {\n unlinkSync(this.segmentPath(this.maxFilesPerRun - 1));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n for (let index = this.maxFilesPerRun - 2; index >= 1; index -= 1) {\n try {\n renameSync(this.segmentPath(index), this.segmentPath(index + 1));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n }\n }\n renameSync(this.filePath, this.segmentPath(1));\n } else {\n unlinkSync(this.filePath);\n }\n }\n}\n\ninterface FlushOperation {\n promise: Promise<void>;\n settled: boolean;\n waiters: Set<() => void>;\n}\n\ninterface LoggerMeta {\n materialized: boolean;\n destination: BoundedLogDestination | null;\n flushOperation: FlushOperation | null;\n}\n\nconst loggerMetaMap = new WeakMap<pino.Logger, LoggerMeta>();\n\nasync function flushDestination(\n destination: BoundedLogDestination,\n deadline: number,\n): Promise<void> {\n while (true) {\n if (!(await destination.waitForRotation(deadline))) return;\n\n if (destination.fd == null || destination.fd < 0) {\n if (!(await waitForDestinationEvent(destination, \"ready\", deadline))) return;\n continue;\n }\n if (destination._writing) {\n if (!(await waitForDestinationEvent(destination, \"drain\", deadline))) return;\n continue;\n }\n\n try {\n destination.flushSync();\n } catch {\n // 文件描述符已关闭、磁盘满等极端情况下吞掉异常,避免把退出路径变成崩溃路径。\n }\n return;\n }\n}\n\nfunction resolveFlushTimeout(timeoutMs: number): number {\n return Number.isFinite(timeoutMs) && timeoutMs >= 0 ? Math.floor(timeoutMs) : 200;\n}\n\nfunction startFlushOperation(meta: LoggerMeta, destination: BoundedLogDestination): FlushOperation {\n const operation: FlushOperation = {\n promise: flushDestination(destination, Date.now() + LOG_IO_OPERATION_TIMEOUT_MS),\n settled: false,\n waiters: new Set(),\n };\n meta.flushOperation = operation;\n\n const finish = () => {\n if (operation.settled) return;\n operation.settled = true;\n if (meta.flushOperation === operation) meta.flushOperation = null;\n for (const waiter of operation.waiters) waiter();\n operation.waiters.clear();\n };\n void operation.promise.then(finish, finish);\n return operation;\n}\n\nfunction waitForFlushOperation(operation: FlushOperation, timeoutMs: number): Promise<void> {\n if (operation.settled || timeoutMs <= 0) return Promise.resolve();\n\n return new Promise<void>((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n operation.waiters.delete(finish);\n resolve();\n };\n const timer = setTimeout(finish, timeoutMs);\n\n operation.waiters.add(finish);\n if (operation.settled) {\n finish();\n return;\n }\n });\n}\n\nfunction buildPinoLogger(options: CreateLoggerOptions): {\n logger: pino.Logger;\n destination: BoundedLogDestination | null;\n} {\n const {\n name,\n level = \"info\",\n logDir = DEFAULT_LOG_DIR,\n retention,\n retentionBytes,\n maxFileBytes: requestedMaxFileBytes,\n maxFilesPerRun: requestedMaxFilesPerRun,\n maxRecordBytes: requestedMaxRecordBytes,\n stdout = false,\n silent = false,\n sync = false,\n } = options;\n\n if (silent) {\n return { logger: pino({ level: \"silent\" }), destination: null };\n }\n\n mkdirSync(logDir, { recursive: true });\n\n const runId = `${PROCESS_LOG_RUN_ID}-${randomUUID()}`;\n const filePath = join(logDir, `${name}-${runId}.log`);\n createLogRunLease(filePath, runId);\n try {\n linkLatestLog(logDir, name, filePath, runId);\n pruneOldLogs(logDir, name, filePath, retention, retentionBytes);\n const maxFileBytes = resolvePositiveInteger(requestedMaxFileBytes, DEFAULT_MAX_FILE_BYTES);\n const maxFilesPerRun = resolvePositiveInteger(\n requestedMaxFilesPerRun,\n DEFAULT_MAX_FILES_PER_RUN,\n );\n const maxRecordBytes = Math.min(\n maxFileBytes,\n resolvePositiveInteger(requestedMaxRecordBytes, DEFAULT_MAX_RECORD_BYTES),\n );\n const sonicDestination = pino.destination({\n dest: filePath,\n sync,\n // Bound data queued while the filesystem is stalled. Dropping diagnostics is preferable to\n // allowing a logging failure to consume the application's heap.\n maxLength: Math.min(maxFileBytes, 1024 * 1024),\n }) as unknown as SonicLikeDestination;\n let initialBytes = 0;\n try {\n initialBytes = statSync(filePath).size;\n } catch {\n // A new run normally reaches this branch because SonicBoom creates the file asynchronously.\n }\n const destination = new BoundedLogDestination(\n sonicDestination,\n filePath,\n runId,\n logDir,\n name,\n retention,\n retentionBytes,\n maxFileBytes,\n maxFilesPerRun,\n maxRecordBytes,\n initialBytes,\n );\n const streams: pino.StreamEntry[] = [{ stream: destination }];\n\n if (stdout) {\n streams.unshift({\n stream: new BoundedWritableDestination(process.stdout, DEFAULT_MAX_STDOUT_BUFFER_BYTES),\n });\n }\n\n return { logger: pino({ level }, pino.multistream(streams)), destination };\n } catch (error) {\n removeOwnedLogRunLease(filePath, runId);\n throw error;\n }\n}\n\n// 返回一个 lazy proxy:调用 createLogger 本身不触发 mkdirSync / pino.destination\n// 等任何文件 IO,只有第一次实际访问 logger 的方法/属性时才构造底层 pino Logger。\n// 这样 `dev-anywhere -v` / `dev-anywhere init` 等不需要写日志的命令路径不会\n// 落地空 log 文件,也避免异步 SonicBoom 在 process.exit 时未 ready 的 race。\nexport function createLogger(options: CreateLoggerOptions): pino.Logger {\n let real: pino.Logger | null = null;\n const meta: LoggerMeta = { materialized: false, destination: null, flushOperation: null };\n const ensure = (): pino.Logger => {\n if (!real) {\n const built = buildPinoLogger(options);\n real = built.logger;\n meta.materialized = true;\n meta.destination = built.destination;\n }\n return real;\n };\n\n const proxy = new Proxy(Object.create(null) as pino.Logger, {\n get(_target, prop) {\n const target = ensure();\n const value = Reflect.get(target, prop, target);\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n set(_target, prop, value) {\n return Reflect.set(ensure(), prop, value);\n },\n has(_target, prop) {\n return Reflect.has(ensure(), prop);\n },\n ownKeys() {\n return Reflect.ownKeys(ensure());\n },\n getOwnPropertyDescriptor(_target, prop) {\n return Reflect.getOwnPropertyDescriptor(ensure(), prop);\n },\n });\n\n loggerMetaMap.set(proxy, meta);\n return proxy;\n}\n\n// 进程退出前等 sonic-boom 真正落盘。`pino.flush(cb)` 在 destination 还没 ready\n// (fs.open 异步未完成)时会立刻回调 err=undefined 撒谎成功,但文件还是空的,所以\n// 这里直接走 sonic-boom 的 ready 事件 + flushSync 路径。\n// - 未实例化(lazy proxy 没被访问过) → no-op,不会触发文件 IO 副作用。\n// - silent / stdout-only(destination 为 null) → no-op。\n// - timeoutMs 是兜底,确保异常情况下不会卡住进程退出。\nexport async function flushLogger(logger: pino.Logger, timeoutMs = 200): Promise<void> {\n const meta = loggerMetaMap.get(logger);\n if (!meta || !meta.materialized) return;\n const dest = meta.destination;\n if (!dest) return;\n const operation = meta.flushOperation ?? startFlushOperation(meta, dest);\n await waitForFlushOperation(operation, resolveFlushTimeout(timeoutMs));\n}\n","// Relay 运行时环境变量的单一入口。和 proxy 侧 runtime-env.ts 同一思路:\n// 类型化输出 + 一次性校验,避免 parseInt / 默认值散落在 index.ts 和 chaos.ts。\nimport { homedir } from \"node:os\";\nimport { parseRelayChaosFromEnv, type RelayChaosOptions } from \"./chaos.js\";\n\nconst DEFAULT_DATA_DIR = `${homedir()}/.dev-anywhere/relay-data`;\nconst DEFAULT_PORT = 3100;\nconst DEFAULT_HEARTBEAT_INTERVAL = 30000;\n\ninterface RelayRuntimeEnv {\n port: number;\n // DATA_DIR 显式置 \"\" 表示关闭持久化目录;未设置时回落到 ~/.dev-anywhere/relay-data。\n dataDir: string | undefined;\n heartbeatInterval: number;\n // 任一 token 未设置(或空串)→ 对应端点关闭鉴权(仅 dev 可用)。\n proxyToken: string | undefined;\n clientToken: string | undefined;\n // ALLOWED_ORIGINS=https://app.example.com,https://www.example.com — 逗号分隔。\n // 空 / 未设置 = 不校验 (向后兼容; 本地 dev / Capacitor / file:// 等场景需要)。\n // 公网部署务必设置, 防 CSWSH。\n allowedOrigins: string[];\n logLevel: string;\n chaos: RelayChaosOptions;\n voiceDefaults: {\n region?: \"cn\" | \"intl\";\n asrModel?: string;\n ttsModel?: string;\n ttsVoice?: string;\n };\n}\n\nfunction parsePort(value: string | undefined, fallback: number, source: string): number {\n if (!value) return fallback;\n const port = Number(value);\n if (!Number.isInteger(port) || port < 1 || port > 65535) {\n throw new Error(`Invalid ${source}=${JSON.stringify(value)}: expected TCP port 1-65535`);\n }\n return port;\n}\n\nfunction parsePositiveInt(value: string | undefined, fallback: number, source: string): number {\n if (!value) return fallback;\n const n = Number(value);\n if (!Number.isInteger(n) || n <= 0) {\n throw new Error(`Invalid ${source}=${JSON.stringify(value)}: expected positive integer`);\n }\n return n;\n}\n\nfunction nonEmpty(value: string | undefined): string | undefined {\n return value && value.length > 0 ? value : undefined;\n}\n\nfunction parseVoiceRegion(value: string | undefined): \"cn\" | \"intl\" | undefined {\n if (!value) return undefined;\n if (value === \"cn\" || value === \"intl\") return value;\n throw new Error(`Invalid BAILIAN_REGION=${JSON.stringify(value)}: expected cn or intl`);\n}\n\nexport function loadRelayRuntimeEnv(env: NodeJS.ProcessEnv = process.env): RelayRuntimeEnv {\n const dataDirRaw = env.DATA_DIR ?? DEFAULT_DATA_DIR;\n const voiceRegion = parseVoiceRegion(env.BAILIAN_REGION);\n return {\n port: parsePort(env.PORT, DEFAULT_PORT, \"PORT\"),\n dataDir: dataDirRaw.length > 0 ? dataDirRaw : undefined,\n heartbeatInterval: parsePositiveInt(\n env.HEARTBEAT_INTERVAL,\n DEFAULT_HEARTBEAT_INTERVAL,\n \"HEARTBEAT_INTERVAL\",\n ),\n proxyToken: nonEmpty(env.RELAY_PROXY_TOKEN),\n clientToken: nonEmpty(env.RELAY_CLIENT_TOKEN),\n allowedOrigins: (env.ALLOWED_ORIGINS ?? \"\")\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0),\n logLevel: env.LOG_LEVEL ?? \"info\",\n chaos: parseRelayChaosFromEnv(env),\n voiceDefaults: {\n ...(voiceRegion ? { region: voiceRegion } : {}),\n ...(nonEmpty(env.BAILIAN_ASR_MODEL) ? { asrModel: env.BAILIAN_ASR_MODEL } : {}),\n ...(nonEmpty(env.BAILIAN_TTS_MODEL) ? { ttsModel: env.BAILIAN_TTS_MODEL } : {}),\n ...(nonEmpty(env.BAILIAN_TTS_VOICE) ? { ttsVoice: env.BAILIAN_TTS_VOICE } : {}),\n },\n };\n}\n","import { createLogger, flushLogger } from \"@dev-anywhere/shared/logger\";\nimport { createRelayServer } from \"./server.js\";\nimport { loadRelayRuntimeEnv } from \"./runtime-env.js\";\nimport { RELAY_VERSION } from \"./version.js\";\n\nfunction printHelp(): void {\n console.log(`DEV Anywhere Relay and Web Server\n\nUsage:\n dev-anywhere-relay [options]\n\nThe bundled Web client, HTTP API, and WebSocket endpoints share the same port.\n\nOptions:\n -h, --help Show this help message\n -v, --version Print version\n\nEnvironment:\n PORT HTTP/WebSocket listen port (default: 3100)\n RELAY_PROXY_TOKEN Optional token for /proxy connections\n RELAY_CLIENT_TOKEN Optional token for /client connections\n DATA_DIR Relay persistence directory; empty disables persistence\n LOG_LEVEL Log level (default: info)\n HEARTBEAT_INTERVAL Proxy/client heartbeat interval in ms (default: 30000)\n`);\n}\n\nconst args = process.argv.slice(2);\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\n printHelp();\n process.exit(0);\n}\nif (args.includes(\"--version\") || args.includes(\"-v\")) {\n console.log(RELAY_VERSION);\n process.exit(0);\n}\n\nconst env = loadRelayRuntimeEnv();\n\nconst logger = createLogger({\n name: \"relay\",\n level: env.logLevel,\n stdout: true,\n});\n\nconst relay = createRelayServer({\n port: env.port,\n logger,\n dataDir: env.dataDir,\n heartbeatInterval: env.heartbeatInterval,\n proxyToken: env.proxyToken,\n clientToken: env.clientToken,\n allowedOrigins: env.allowedOrigins,\n chaos: env.chaos,\n voiceDefaults: env.voiceDefaults,\n});\n\nrelay.httpServer.listen(env.port, () => {\n const addr = relay.httpServer.address();\n const actualPort = typeof addr === \"object\" && addr ? addr.port : env.port;\n logger.info({ port: actualPort }, \"Relay server started\");\n});\n\nasync function shutdown(): Promise<void> {\n logger.info(\"Shutting down relay server\");\n await relay.close();\n await flushLogger(logger);\n process.exit(0);\n}\n\nprocess.on(\"SIGTERM\", () => {\n shutdown();\n});\nprocess.on(\"SIGINT\", () => {\n shutdown();\n});\n"],"mappings":"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","names":["fileName","logger","homedir","homedir","env"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { WebSocket } from "ws";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
declare const ProxyUpgradeBootstrapRequestSchema: z.ZodObject<{
|
|
4
|
+
type: z.ZodLiteral<"proxy_register">;
|
|
5
|
+
proxyId: z.ZodString;
|
|
6
|
+
name: z.ZodOptional<z.ZodString>;
|
|
7
|
+
proxyVersion: z.ZodLiteral<"0.8.1">;
|
|
8
|
+
}, z.core.$strict>;
|
|
9
|
+
type ProxyUpgradeBootstrapRequest = z.infer<typeof ProxyUpgradeBootstrapRequestSchema>;
|
|
10
|
+
export declare function parseProxyUpgradeBootstrapRequest(raw: string, relayVersion: string): ProxyUpgradeBootstrapRequest | null;
|
|
11
|
+
export declare function sendProxyUpgradeBootstrapResponse(ws: WebSocket, relayVersion: string): void;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=proxy-upgrade-bootstrap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy-upgrade-bootstrap.d.ts","sourceRoot":"","sources":["../src/proxy-upgrade-bootstrap.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,QAAA,MAAM,kCAAkC;;;;;kBAO7B,CAAC;AAEZ,KAAK,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kCAAkC,CAAC,CAAC;AAsBvF,wBAAgB,iCAAiC,CAC/C,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,GACnB,4BAA4B,GAAG,IAAI,CAYrC;AAED,wBAAgB,iCAAiC,CAAC,EAAE,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CAc3F"}
|
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ import { type VoiceProviderRegistry } from "./voice/provider.js";
|
|
|
10
10
|
export interface RelayServerOptions {
|
|
11
11
|
port?: number;
|
|
12
12
|
heartbeatInterval?: number;
|
|
13
|
+
proxyAdmissionTimeoutMs?: number;
|
|
14
|
+
clientAdmissionTimeoutMs?: number;
|
|
13
15
|
logger: Logger;
|
|
14
16
|
dataDir?: string;
|
|
15
17
|
proxyToken?: string;
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsC,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAM5E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAK9C,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEtE,OAAO,EAA4B,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACzF,OAAO,EAA4B,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAEzF,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAA+B,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAQ9F,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsC,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAM5E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAK9C,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEtE,OAAO,EAA4B,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AACzF,OAAO,EAA4B,KAAK,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAEzF,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAA+B,KAAK,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAQ9F,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,uBAAuB,CAAC,EAAE,MAAM,CAAC;IAGjC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,WAAW,CAAC,EAAE,MAAM,CAAC;IAIrB,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC7B,aAAa,CAAC,EAAE;QACd,MAAM,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;QACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;IAC9C,yBAAyB,CAAC,EAAE,yBAAyB,CAAC;IACtD,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,qBAAqB,CAAC,EAAE,qBAAqB,CAAC;CAC/C;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AA6BD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW,CA4V1E"}
|
package/dist/server.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dev-anywhere/relay",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "Relay server for DEV Anywhere — bridges local AI CLI proxies to remote web clients via WebSocket.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -57,10 +57,10 @@
|
|
|
57
57
|
"@types/node": "^22.15.30",
|
|
58
58
|
"@types/ws": "^8.18.1",
|
|
59
59
|
"vitest": "^4.1.2",
|
|
60
|
-
"@dev-anywhere/shared": "0.9.
|
|
60
|
+
"@dev-anywhere/shared": "0.9.2"
|
|
61
61
|
},
|
|
62
62
|
"scripts": {
|
|
63
|
-
"build": "tsup && node scripts/copy-web-assets.mjs &&
|
|
63
|
+
"build": "tsup && node scripts/copy-web-assets.mjs && node -e \"require('node:fs').rmSync('tsconfig.build.tsbuildinfo', { force: true })\" && tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist",
|
|
64
64
|
"dev": "tsx src/index.ts",
|
|
65
65
|
"test": "bash ../../scripts/test/vitest.sh",
|
|
66
66
|
"typecheck": "tsc --noEmit"
|