@dev-anywhere/relay 0.3.13 → 0.4.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.
Files changed (36) hide show
  1. package/dist/{chunk-DFVUNUQH.js → chunk-ERH2EO6I.js} +1612 -153
  2. package/dist/chunk-ERH2EO6I.js.map +1 -0
  3. package/dist/handlers/client.d.ts +3 -1
  4. package/dist/handlers/client.d.ts.map +1 -1
  5. package/dist/heartbeat.d.ts.map +1 -1
  6. package/dist/index.js +16 -3
  7. package/dist/index.js.map +1 -1
  8. package/dist/runtime-env.d.ts +6 -0
  9. package/dist/runtime-env.d.ts.map +1 -1
  10. package/dist/server.d.ts +16 -0
  11. package/dist/server.d.ts.map +1 -1
  12. package/dist/server.js +1 -1
  13. package/dist/voice/asr-ws.d.ts +8 -0
  14. package/dist/voice/asr-ws.d.ts.map +1 -0
  15. package/dist/voice/bailian-asr.d.ts +35 -0
  16. package/dist/voice/bailian-asr.d.ts.map +1 -0
  17. package/dist/voice/bailian-endpoints.d.ts +4 -0
  18. package/dist/voice/bailian-endpoints.d.ts.map +1 -0
  19. package/dist/voice/bailian-provider.d.ts +13 -0
  20. package/dist/voice/bailian-provider.d.ts.map +1 -0
  21. package/dist/voice/bailian-tts.d.ts +33 -0
  22. package/dist/voice/bailian-tts.d.ts.map +1 -0
  23. package/dist/voice/capabilities.d.ts +21 -0
  24. package/dist/voice/capabilities.d.ts.map +1 -0
  25. package/dist/voice/client-controls.d.ts +7 -0
  26. package/dist/voice/client-controls.d.ts.map +1 -0
  27. package/dist/voice/config-store.d.ts +22 -0
  28. package/dist/voice/config-store.d.ts.map +1 -0
  29. package/dist/voice/config-test.d.ts +22 -0
  30. package/dist/voice/config-test.d.ts.map +1 -0
  31. package/dist/voice/provider.d.ts +41 -0
  32. package/dist/voice/provider.d.ts.map +1 -0
  33. package/dist/voice/tts-ws.d.ts +8 -0
  34. package/dist/voice/tts-ws.d.ts.map +1 -0
  35. package/package.json +2 -2
  36. package/dist/chunk-DFVUNUQH.js.map +0 -1
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import {
3
3
  RELAY_VERSION,
4
4
  createRelayServer,
5
5
  parseRelayChaosFromEnv
6
- } from "./chunk-DFVUNUQH.js";
6
+ } from "./chunk-ERH2EO6I.js";
7
7
 
8
8
  // ../../packages/shared/dist/logger.js
9
9
  import { lstatSync, mkdirSync, readdirSync, renameSync, statSync, symlinkSync, unlinkSync } from "fs";
@@ -165,8 +165,14 @@ function parsePositiveInt(value, fallback, source) {
165
165
  function nonEmpty(value) {
166
166
  return value && value.length > 0 ? value : void 0;
167
167
  }
168
+ function parseVoiceRegion(value) {
169
+ if (!value) return void 0;
170
+ if (value === "cn" || value === "intl") return value;
171
+ throw new Error(`Invalid BAILIAN_REGION=${JSON.stringify(value)}: expected cn or intl`);
172
+ }
168
173
  function loadRelayRuntimeEnv(env2 = process.env) {
169
174
  const dataDirRaw = env2.DATA_DIR ?? DEFAULT_DATA_DIR;
175
+ const voiceRegion = parseVoiceRegion(env2.BAILIAN_REGION);
170
176
  return {
171
177
  port: parsePort(env2.PORT, DEFAULT_PORT, "PORT"),
172
178
  dataDir: dataDirRaw.length > 0 ? dataDirRaw : void 0,
@@ -179,7 +185,13 @@ function loadRelayRuntimeEnv(env2 = process.env) {
179
185
  clientToken: nonEmpty(env2.RELAY_CLIENT_TOKEN),
180
186
  allowedOrigins: (env2.ALLOWED_ORIGINS ?? "").split(",").map((s) => s.trim()).filter((s) => s.length > 0),
181
187
  logLevel: env2.LOG_LEVEL ?? "info",
182
- chaos: parseRelayChaosFromEnv(env2)
188
+ chaos: parseRelayChaosFromEnv(env2),
189
+ voiceDefaults: {
190
+ ...voiceRegion ? { region: voiceRegion } : {},
191
+ ...nonEmpty(env2.BAILIAN_ASR_MODEL) ? { asrModel: env2.BAILIAN_ASR_MODEL } : {},
192
+ ...nonEmpty(env2.BAILIAN_TTS_MODEL) ? { ttsModel: env2.BAILIAN_TTS_MODEL } : {},
193
+ ...nonEmpty(env2.BAILIAN_TTS_VOICE) ? { ttsVoice: env2.BAILIAN_TTS_VOICE } : {}
194
+ }
183
195
  };
184
196
  }
185
197
 
@@ -226,7 +238,8 @@ var relay = createRelayServer({
226
238
  proxyToken: env.proxyToken,
227
239
  clientToken: env.clientToken,
228
240
  allowedOrigins: env.allowedOrigins,
229
- chaos: env.chaos
241
+ chaos: env.chaos,
242
+ voiceDefaults: env.voiceDefaults
230
243
  });
231
244
  relay.httpServer.listen(env.port, () => {
232
245
  const addr = relay.httpServer.address();
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 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 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}\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\nexport function loadRelayRuntimeEnv(env: NodeJS.ProcessEnv = process.env): RelayRuntimeEnv {\n const dataDirRaw = env.DATA_DIR ?? DEFAULT_DATA_DIR;\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 };\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\n\nUsage:\n dev-anywhere-relay [options]\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});\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 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 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 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\n\nUsage:\n dev-anywhere-relay [options]\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"]}
@@ -8,6 +8,12 @@ interface RelayRuntimeEnv {
8
8
  allowedOrigins: string[];
9
9
  logLevel: string;
10
10
  chaos: RelayChaosOptions;
11
+ voiceDefaults: {
12
+ region?: "cn" | "intl";
13
+ asrModel?: string;
14
+ ttsModel?: string;
15
+ ttsVoice?: string;
16
+ };
11
17
  }
12
18
  export declare function loadRelayRuntimeEnv(env?: NodeJS.ProcessEnv): RelayRuntimeEnv;
13
19
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-env.d.ts","sourceRoot":"","sources":["../src/runtime-env.ts"],"names":[],"mappings":"AAGA,OAAO,EAA0B,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAM5E,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IAEb,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAE1B,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAIhC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,iBAAiB,CAAC;CAC1B;AAwBD,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,eAAe,CAmBzF"}
1
+ {"version":3,"file":"runtime-env.d.ts","sourceRoot":"","sources":["../src/runtime-env.ts"],"names":[],"mappings":"AAGA,OAAO,EAA0B,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAM5E,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IAEb,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAE1B,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAIhC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,iBAAiB,CAAC;IACzB,aAAa,EAAE;QACb,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;CACH;AA8BD,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,eAAe,CA0BzF"}
package/dist/server.d.ts CHANGED
@@ -2,6 +2,11 @@ import { type Server } from "node:http";
2
2
  import type { Logger } from "@dev-anywhere/shared/logger";
3
3
  import { RelayRegistry } from "./registry.js";
4
4
  import { type RelayChaosOptions } from "./chaos.js";
5
+ import { type VoiceAsrClientFactory } from "./voice/asr-ws.js";
6
+ import { type VoiceTtsClientFactory } from "./voice/tts-ws.js";
7
+ import type { VoiceCapabilitiesProvider } from "./voice/capabilities.js";
8
+ import type { VoiceConfigTester } from "./voice/config-test.js";
9
+ import { type VoiceProviderRegistry } from "./voice/provider.js";
5
10
  export interface RelayServerOptions {
6
11
  port?: number;
7
12
  heartbeatInterval?: number;
@@ -12,6 +17,17 @@ export interface RelayServerOptions {
12
17
  allowedOrigins?: readonly string[];
13
18
  chaos?: RelayChaosOptions;
14
19
  fontAssetDir?: string;
20
+ voiceDefaults?: {
21
+ region?: "cn" | "intl";
22
+ asrModel?: string;
23
+ ttsModel?: string;
24
+ ttsVoice?: string;
25
+ };
26
+ voiceAsrClientFactory?: VoiceAsrClientFactory;
27
+ voiceTtsClientFactory?: VoiceTtsClientFactory;
28
+ voiceCapabilitiesProvider?: VoiceCapabilitiesProvider;
29
+ voiceConfigTester?: VoiceConfigTester;
30
+ voiceProviderRegistry?: VoiceProviderRegistry;
15
31
  }
16
32
  export interface RelayServer {
17
33
  httpServer: Server;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAKtD,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,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,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;CACvB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAMD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW,CAmL1E"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAKtD,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;AAE9F,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,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,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;AAMD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW,CA4O1E"}
package/dist/server.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createRelayServer
4
- } from "./chunk-DFVUNUQH.js";
4
+ } from "./chunk-ERH2EO6I.js";
5
5
  export {
6
6
  createRelayServer
7
7
  };
@@ -0,0 +1,8 @@
1
+ import { WebSocket } from "ws";
2
+ import type { Logger } from "@dev-anywhere/shared/logger";
3
+ import type { BailianAsrClient, BailianAsrConfig } from "./bailian-asr.js";
4
+ import type { VoiceConfigStore } from "./config-store.js";
5
+ import type { VoiceProviderRegistry } from "./provider.js";
6
+ export type VoiceAsrClientFactory = (config: BailianAsrConfig) => BailianAsrClient;
7
+ export declare function handleVoiceAsrConnection(ws: WebSocket, store: VoiceConfigStore, logger: Logger, providers: VoiceProviderRegistry): void;
8
+ //# sourceMappingURL=asr-ws.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asr-ws.d.ts","sourceRoot":"","sources":["../../src/voice/asr-ws.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAgB,MAAM,IAAI,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAA0B,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAEnF,MAAM,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;AAkCnF,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,SAAS,EACb,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,qBAAqB,GAC/B,IAAI,CAoDN"}
@@ -0,0 +1,35 @@
1
+ import { EventEmitter } from "node:events";
2
+ import { type BailianRegion } from "./bailian-endpoints.js";
3
+ type SocketOptions = {
4
+ headers?: Record<string, string>;
5
+ };
6
+ type ProviderSocket = EventEmitter & {
7
+ readyState: number;
8
+ send: (data: string | Buffer) => void;
9
+ close: (code?: number, reason?: string) => void;
10
+ };
11
+ export type BailianAsrEvent = "ready" | "partial" | "final" | "error" | "closed";
12
+ export type BailianAsrSocketFactory = (url: string, options: SocketOptions) => ProviderSocket;
13
+ export interface BailianAsrConfig {
14
+ apiKey: string;
15
+ region: BailianRegion;
16
+ model: string;
17
+ sampleRate: number;
18
+ language: string;
19
+ }
20
+ export interface BailianAsrClient {
21
+ on(event: "ready", handler: () => void): this;
22
+ on(event: "partial" | "final", handler: (text: string) => void): this;
23
+ on(event: "error", handler: (error: Error) => void): this;
24
+ on(event: "closed", handler: (code?: number, reason?: string) => void): this;
25
+ sendPcm(chunk: Buffer): void;
26
+ stop(): void;
27
+ close(): void;
28
+ }
29
+ interface BailianAsrClientOptions {
30
+ socketFactory?: BailianAsrSocketFactory;
31
+ eventIdFactory?: () => string;
32
+ }
33
+ export declare function createBailianAsrClient(config: BailianAsrConfig, options?: BailianAsrClientOptions): BailianAsrClient;
34
+ export {};
35
+ //# sourceMappingURL=bailian-asr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bailian-asr.d.ts","sourceRoot":"","sources":["../../src/voice/bailian-asr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEhF,KAAK,aAAa,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC;AAC1D,KAAK,cAAc,GAAG,YAAY,GAAG;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACtC,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;AACjF,MAAM,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;AAE9F,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC9C,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IACtE,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1D,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC7E,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;CACf;AAED,UAAU,uBAAuB;IAC/B,aAAa,CAAC,EAAE,uBAAuB,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,MAAM,CAAC;CAC/B;AAgMD,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAMlB"}
@@ -0,0 +1,4 @@
1
+ export type BailianRegion = "cn" | "intl";
2
+ export declare function bailianRealtimeUrl(region: BailianRegion, model?: string): string;
3
+ export declare function bailianInferenceUrl(region: BailianRegion): string;
4
+ //# sourceMappingURL=bailian-endpoints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bailian-endpoints.d.ts","sourceRoot":"","sources":["../../src/voice/bailian-endpoints.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,MAAM,CAAC;AAO1C,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAGhF;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAEjE"}
@@ -0,0 +1,13 @@
1
+ import { type BailianAsrClient, type BailianAsrConfig } from "./bailian-asr.js";
2
+ import { type BailianTtsClient, type BailianTtsConfig } from "./bailian-tts.js";
3
+ import { type VoiceCapabilitiesProvider } from "./capabilities.js";
4
+ import { type VoiceConfigTester } from "./config-test.js";
5
+ import type { VoiceProviderAdapter } from "./provider.js";
6
+ export interface BailianVoiceProviderOptions {
7
+ asrClientFactory?: (config: BailianAsrConfig) => BailianAsrClient;
8
+ ttsClientFactory?: (config: BailianTtsConfig) => BailianTtsClient;
9
+ capabilitiesProvider?: VoiceCapabilitiesProvider;
10
+ configTester?: VoiceConfigTester;
11
+ }
12
+ export declare function createBailianVoiceProvider(options?: BailianVoiceProviderOptions): VoiceProviderAdapter;
13
+ //# sourceMappingURL=bailian-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bailian-provider.d.ts","sourceRoot":"","sources":["../../src/voice/bailian-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,KAAK,yBAAyB,EAC/B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAkC,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAE1D,MAAM,WAAW,2BAA2B;IAC1C,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;IAClE,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;IAClE,oBAAoB,CAAC,EAAE,yBAAyB,CAAC;IACjD,YAAY,CAAC,EAAE,iBAAiB,CAAC;CAClC;AAOD,wBAAgB,0BAA0B,CACxC,OAAO,GAAE,2BAAgC,GACxC,oBAAoB,CAuCtB"}
@@ -0,0 +1,33 @@
1
+ import { EventEmitter } from "node:events";
2
+ import { type BailianRegion } from "./bailian-endpoints.js";
3
+ type SocketOptions = {
4
+ headers?: Record<string, string>;
5
+ };
6
+ type ProviderSocket = EventEmitter & {
7
+ readyState: number;
8
+ send: (data: string | Buffer) => void;
9
+ close: (code?: number, reason?: string) => void;
10
+ };
11
+ export type BailianTtsSocketFactory = (url: string, options: SocketOptions) => ProviderSocket;
12
+ export interface BailianTtsConfig {
13
+ apiKey: string;
14
+ region: BailianRegion;
15
+ model: string;
16
+ voice: string;
17
+ sampleRate: number;
18
+ }
19
+ export interface BailianTtsClient {
20
+ on(event: "started" | "finished", handler: () => void): this;
21
+ on(event: "audio", handler: (chunk: Buffer) => void): this;
22
+ on(event: "error", handler: (error: Error) => void): this;
23
+ on(event: "closed", handler: (code?: number, reason?: string) => void): this;
24
+ speak(text: string): void;
25
+ close(): void;
26
+ }
27
+ interface BailianTtsClientOptions {
28
+ socketFactory?: BailianTtsSocketFactory;
29
+ taskIdFactory?: () => string;
30
+ }
31
+ export declare function createBailianTtsClient(config: BailianTtsConfig, options?: BailianTtsClientOptions): BailianTtsClient;
32
+ export {};
33
+ //# sourceMappingURL=bailian-tts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bailian-tts.d.ts","sourceRoot":"","sources":["../../src/voice/bailian-tts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEjF,KAAK,aAAa,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC;AAC1D,KAAK,cAAc,GAAG,YAAY,GAAG;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IACtC,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;AAE9F,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC7D,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC3D,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1D,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC7E,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,IAAI,IAAI,CAAC;CACf;AAED,UAAU,uBAAuB;IAC/B,aAAa,CAAC,EAAE,uBAAuB,CAAC;IACxC,aAAa,CAAC,EAAE,MAAM,MAAM,CAAC;CAC9B;AA6JD,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAMlB"}
@@ -0,0 +1,21 @@
1
+ import { type VoiceCapabilities } from "@dev-anywhere/shared";
2
+ import type { StoredVoiceConfig } from "./config-store.js";
3
+ type FetchResponse = {
4
+ ok: boolean;
5
+ json: () => Promise<unknown>;
6
+ };
7
+ type FetchLike = (url: string, init?: {
8
+ method?: string;
9
+ headers?: Record<string, string>;
10
+ body?: string;
11
+ }) => Promise<FetchResponse>;
12
+ export interface VoiceCapabilitiesProvider {
13
+ read: (config: StoredVoiceConfig) => Promise<VoiceCapabilities>;
14
+ }
15
+ interface BailianVoiceCapabilitiesProviderOptions {
16
+ fetchImpl?: FetchLike;
17
+ now?: () => number;
18
+ }
19
+ export declare function createBailianVoiceCapabilitiesProvider(options?: BailianVoiceCapabilitiesProviderOptions): VoiceCapabilitiesProvider;
20
+ export {};
21
+ //# sourceMappingURL=capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../src/voice/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EAEvB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,KAAK,aAAa,GAAG;IACnB,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9B,CAAC;AACF,KAAK,SAAS,GAAG,CACf,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;IACL,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,KACE,OAAO,CAAC,aAAa,CAAC,CAAC;AAE5B,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACjE;AAED,UAAU,uCAAuC;IAC/C,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AA2DD,wBAAgB,sCAAsC,CACpD,OAAO,GAAE,uCAA4C,GACpD,yBAAyB,CAoB3B"}
@@ -0,0 +1,7 @@
1
+ import { type RelayControlMessage } from "@dev-anywhere/shared";
2
+ import type { Logger } from "@dev-anywhere/shared/logger";
3
+ import type { WebSocket } from "ws";
4
+ import type { VoiceConfigStore } from "./config-store.js";
5
+ import type { VoiceProviderRegistry } from "./provider.js";
6
+ export declare function handleVoiceConfigControl(msg: RelayControlMessage, ws: WebSocket, store: VoiceConfigStore, logger: Logger, providers?: VoiceProviderRegistry): boolean;
7
+ //# sourceMappingURL=client-controls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-controls.d.ts","sourceRoot":"","sources":["../../src/voice/client-controls.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAE3D,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,mBAAmB,EACxB,EAAE,EAAE,SAAS,EACb,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,qBAAqB,GAChC,OAAO,CA4JT"}
@@ -0,0 +1,22 @@
1
+ import { type VoiceConfigUpdate, type VoiceProviderConfig } from "@dev-anywhere/shared";
2
+ export interface StoredVoiceConfig {
3
+ provider: "aliyun-bailian";
4
+ apiKey?: string;
5
+ region: "cn" | "intl";
6
+ asrModel: string;
7
+ ttsModel: string;
8
+ ttsVoice: string;
9
+ turnIdleSeconds: number;
10
+ }
11
+ interface VoiceConfigStoreOptions {
12
+ dataDir?: string;
13
+ defaults?: Partial<Omit<StoredVoiceConfig, "provider" | "apiKey">>;
14
+ }
15
+ export interface VoiceConfigStore {
16
+ read: () => VoiceProviderConfig;
17
+ update: (update: VoiceConfigUpdate) => VoiceProviderConfig;
18
+ readSecret: () => StoredVoiceConfig;
19
+ }
20
+ export declare function createVoiceConfigStore(options?: VoiceConfigStoreOptions): VoiceConfigStore;
21
+ export {};
22
+ //# sourceMappingURL=config-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-store.d.ts","sourceRoot":"","sources":["../../src/voice/config-store.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACzB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,uBAAuB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC;CACpE;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,mBAAmB,CAAC;IAChC,MAAM,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,mBAAmB,CAAC;IAC3D,UAAU,EAAE,MAAM,iBAAiB,CAAC;CACrC;AA2DD,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,gBAAgB,CAiD9F"}
@@ -0,0 +1,22 @@
1
+ import type { VoiceConfigUpdate } from "@dev-anywhere/shared";
2
+ import { type BailianAsrClient, type BailianAsrConfig } from "./bailian-asr.js";
3
+ import { type BailianTtsClient, type BailianTtsConfig } from "./bailian-tts.js";
4
+ import type { StoredVoiceConfig } from "./config-store.js";
5
+ export interface VoiceConfigTestResult {
6
+ audio?: Buffer;
7
+ sampleRate?: number;
8
+ transcript?: string;
9
+ }
10
+ export interface VoiceConfigTester {
11
+ test: (config: StoredVoiceConfig) => Promise<VoiceConfigTestResult>;
12
+ }
13
+ interface BailianVoiceConfigTesterOptions {
14
+ ttsClientFactory?: (config: BailianTtsConfig) => BailianTtsClient;
15
+ asrClientFactory?: (config: BailianAsrConfig) => BailianAsrClient;
16
+ sampleText?: string;
17
+ timeoutMs?: number;
18
+ }
19
+ export declare function mergeVoiceConfigForTest(current: StoredVoiceConfig, update?: VoiceConfigUpdate): StoredVoiceConfig;
20
+ export declare function createBailianVoiceConfigTester(options?: BailianVoiceConfigTesterOptions): VoiceConfigTester;
21
+ export {};
22
+ //# sourceMappingURL=config-test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-test.d.ts","sourceRoot":"","sources":["../../src/voice/config-test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACrE;AAED,UAAU,+BAA+B;IACvC,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;IAClE,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAMD,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,iBAAiB,EAC1B,MAAM,CAAC,EAAE,iBAAiB,GACzB,iBAAiB,CAYnB;AAED,wBAAgB,8BAA8B,CAC5C,OAAO,GAAE,+BAAoC,GAC5C,iBAAiB,CA2BnB"}
@@ -0,0 +1,41 @@
1
+ import type { VoiceCapabilities, VoiceProviderConfig } from "@dev-anywhere/shared";
2
+ import type { StoredVoiceConfig } from "./config-store.js";
3
+ import type { VoiceConfigTestResult } from "./config-test.js";
4
+ export type VoiceProviderId = VoiceProviderConfig["provider"];
5
+ export interface VoiceAsrProviderClient {
6
+ on(event: "ready", handler: () => void): this;
7
+ on(event: "partial" | "final", handler: (text: string) => void): this;
8
+ on(event: "error", handler: (error: Error) => void): this;
9
+ on(event: "closed", handler: (code?: number, reason?: string) => void): this;
10
+ sendPcm(chunk: Buffer): void;
11
+ stop(): void;
12
+ close(): void;
13
+ }
14
+ export interface VoiceTtsProviderClient {
15
+ on(event: "started" | "finished", handler: () => void): this;
16
+ on(event: "audio", handler: (chunk: Buffer) => void): this;
17
+ on(event: "error", handler: (error: Error) => void): this;
18
+ on(event: "closed", handler: (code?: number, reason?: string) => void): this;
19
+ speak(text: string): void;
20
+ close(): void;
21
+ }
22
+ export interface VoiceAsrProviderOptions {
23
+ sampleRate: number;
24
+ language: string;
25
+ }
26
+ export interface VoiceTtsProviderOptions {
27
+ sampleRate: number;
28
+ }
29
+ export interface VoiceProviderAdapter {
30
+ id: VoiceProviderId;
31
+ createAsrClient: (config: StoredVoiceConfig, options: VoiceAsrProviderOptions) => VoiceAsrProviderClient;
32
+ createTtsClient: (config: StoredVoiceConfig, options: VoiceTtsProviderOptions) => VoiceTtsProviderClient;
33
+ readCapabilities: (config: StoredVoiceConfig) => Promise<VoiceCapabilities>;
34
+ testConfig: (config: StoredVoiceConfig) => Promise<VoiceConfigTestResult>;
35
+ }
36
+ export interface VoiceProviderRegistry {
37
+ current: (config: StoredVoiceConfig) => VoiceProviderAdapter;
38
+ require: (providerId: string) => VoiceProviderAdapter;
39
+ }
40
+ export declare function createVoiceProviderRegistry(adapters: readonly VoiceProviderAdapter[]): VoiceProviderRegistry;
41
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/voice/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAE9D,MAAM,MAAM,eAAe,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;AAE9D,MAAM,WAAW,sBAAsB;IACrC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC9C,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IACtE,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1D,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC7E,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC7D,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC3D,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IAC1D,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;IAC7E,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,IAAI,IAAI,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,eAAe,CAAC;IACpB,eAAe,EAAE,CACf,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,uBAAuB,KAC7B,sBAAsB,CAAC;IAC5B,eAAe,EAAE,CACf,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,uBAAuB,KAC7B,sBAAsB,CAAC;IAC5B,gBAAgB,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC5E,UAAU,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;CAC3E;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,oBAAoB,CAAC;IAC7D,OAAO,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,oBAAoB,CAAC;CACvD;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,GACxC,qBAAqB,CAqBvB"}
@@ -0,0 +1,8 @@
1
+ import { WebSocket } from "ws";
2
+ import type { Logger } from "@dev-anywhere/shared/logger";
3
+ import type { BailianTtsClient, BailianTtsConfig } from "./bailian-tts.js";
4
+ import type { VoiceConfigStore } from "./config-store.js";
5
+ import type { VoiceProviderRegistry } from "./provider.js";
6
+ export type VoiceTtsClientFactory = (config: BailianTtsConfig) => BailianTtsClient;
7
+ export declare function handleVoiceTtsConnection(ws: WebSocket, store: VoiceConfigStore, logger: Logger, providers: VoiceProviderRegistry): void;
8
+ //# sourceMappingURL=tts-ws.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tts-ws.d.ts","sourceRoot":"","sources":["../../src/voice/tts-ws.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAgB,MAAM,IAAI,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,KAAK,EAAqB,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,qBAAqB,EAA0B,MAAM,eAAe,CAAC;AAEnF,MAAM,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;AA2FnF,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,SAAS,EACb,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,qBAAqB,GAC/B,IAAI,CA4IN"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev-anywhere/relay",
3
- "version": "0.3.13",
3
+ "version": "0.4.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",
@@ -54,7 +54,7 @@
54
54
  "@types/node": "^22.15.30",
55
55
  "@types/ws": "^8.18.1",
56
56
  "vitest": "^4.1.2",
57
- "@dev-anywhere/shared": "0.3.13"
57
+ "@dev-anywhere/shared": "0.4.2"
58
58
  },
59
59
  "scripts": {
60
60
  "build": "tsup && rm -f tsconfig.build.tsbuildinfo && tsc -p tsconfig.build.json --emitDeclarationOnly --outDir dist",