@lakphy/local-router 0.3.0 → 0.3.3

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/README.md CHANGED
@@ -99,6 +99,7 @@ local-router version
99
99
  - `--host <host>`:指定监听地址
100
100
  - `--port <port>`:指定监听端口
101
101
  - `--daemon`:后台运行
102
+ - `--idle-timeout <sec>`:设置 Bun 连接空闲超时(默认 600 秒,设为 `0` 可关闭)
102
103
 
103
104
  ## 请求入口(给你的应用调用)
104
105
 
@@ -195,6 +196,25 @@ curl -X POST "http://127.0.0.1:4099/openai-completions/v1/chat/completions" \
195
196
  - `routes` 引用的 provider 是否存在
196
197
  - 配置文件是否是合法 JSON5
197
198
 
199
+
200
+ ### 运行较久请求出现 `[Bun.serve]: request timed out after 10 seconds` 怎么办?
201
+
202
+ 这是 Bun 服务端连接空闲超时触发导致的(常见于长流式响应或慢速上游)。
203
+
204
+ 可在启动时放宽超时:
205
+
206
+ ```sh
207
+ local-router start --idle-timeout 600
208
+ # 或彻底关闭空闲超时
209
+ local-router start --idle-timeout 0
210
+ ```
211
+
212
+ 也支持环境变量:
213
+
214
+ ```sh
215
+ LOCAL_ROUTER_IDLE_TIMEOUT=600 local-router start
216
+ ```
217
+
198
218
  ### 如何升级?
199
219
 
200
220
  ```sh
@@ -218,8 +218,8 @@
218
218
  "type": "string",
219
219
  "enum": ["off", "masked", "full"],
220
220
  "default": "off",
221
- "description": "请求体与响应体的记录策略。off:不记录 body 内容(推荐日常使用);masked:脱敏后记录(当前版本行为同 full,后续将完善字段级脱敏);full:完整记录所有内容(仅建议调试时临时开启,注意隐私风险)。",
222
- "markdownDescription": "请求体与响应体的记录策略:\n- `off`:不记录 body 内容(推荐日常使用)\n- `masked`:脱敏后记录(当前版本行为同 `full`,后续完善)\n- `full`:完整记录所有内容(仅调试时使用)"
221
+ "description": "请求体与响应体的记录策略。off:不记录 body 内容(推荐日常使用);full:完整记录所有内容(仅建议调试时临时开启,注意隐私风险)。为兼容旧配置,masked 仍被接受,但当前行为等同于 full",
222
+ "markdownDescription": "请求体与响应体的记录策略:\n- `off`:不记录 body 内容(推荐日常使用)\n- `full`:完整记录所有内容(仅调试时使用)\n- `masked`:兼容旧配置,当前行为等同于 `full`"
223
223
  }
224
224
  }
225
225
  },
package/dist/cli.js CHANGED
@@ -10440,7 +10440,7 @@ var DEFAULT_CONFIG = `{
10440
10440
  // \u65E5\u5FD7\u914D\u7F6E\uFF08\u53EF\u9009\uFF0C\u4E0D\u914D\u7F6E\u5219\u4E0D\u542F\u7528\u65E5\u5FD7\u8BB0\u5F55\uFF09
10441
10441
  // log: {
10442
10442
  // enabled: true,
10443
- // bodyPolicy: "off", // off | masked | full
10443
+ // bodyPolicy: "off", // off | full
10444
10444
  // streams: {
10445
10445
  // enabled: true,
10446
10446
  // maxBytesPerRequest: 10485760, // 10MB
@@ -51823,7 +51823,6 @@ var MAX_QUERY_LIMIT = 200;
51823
51823
  var DEFAULT_QUERY_LIMIT = 50;
51824
51824
  var MAX_EXPORT_ROWS = 5000;
51825
51825
  var MAX_Q_LENGTH = 200;
51826
- var SENSITIVE_FIELD_PATTERN = /(authorization|token|cookie|password|passphrase|secret|api[_-]?key)/i;
51827
51826
  function encodeBase64Url(value) {
51828
51827
  return Buffer.from(value, "utf-8").toString("base64url");
51829
51828
  }
@@ -52039,34 +52038,6 @@ function eventToSummary(item) {
52039
52038
  sessionId: identity.sessionId
52040
52039
  };
52041
52040
  }
52042
- function maskValue(value) {
52043
- if (value == null)
52044
- return value;
52045
- if (typeof value === "string") {
52046
- return value.length > 4 ? `${value.slice(0, 2)}****` : "****";
52047
- }
52048
- if (typeof value === "number" || typeof value === "boolean") {
52049
- return "****";
52050
- }
52051
- return "****";
52052
- }
52053
- function maskSensitiveDeep(value, parentKey = "") {
52054
- if (Array.isArray(value)) {
52055
- return value.map((item) => maskSensitiveDeep(item, parentKey));
52056
- }
52057
- if (value && typeof value === "object") {
52058
- const output = {};
52059
- for (const [key2, child] of Object.entries(value)) {
52060
- if (SENSITIVE_FIELD_PATTERN.test(key2) || SENSITIVE_FIELD_PATTERN.test(parentKey)) {
52061
- output[key2] = maskValue(child);
52062
- } else {
52063
- output[key2] = maskSensitiveDeep(child, key2);
52064
- }
52065
- }
52066
- return output;
52067
- }
52068
- return value;
52069
- }
52070
52041
  function detectBodyPolicy(event) {
52071
52042
  const hasRequestBody = event.request_body !== undefined;
52072
52043
  const hasResponseBody = event.response_body !== undefined;
@@ -52139,53 +52110,53 @@ function readStreamContent(baseDir, streamFile) {
52139
52110
  }
52140
52111
  }
52141
52112
  async function buildLogEventDetail(id, parsed, location, context2) {
52142
- const maskedEvent = maskSensitiveDeep(parsed);
52143
- const level = getLevel(maskedEvent);
52144
- const statusClass = getStatusClass2(maskedEvent);
52145
- const bodyPolicy = detectBodyPolicy(maskedEvent);
52146
- const requestBodyAvailable = maskedEvent.request_body !== undefined;
52147
- const responseBodyAvailable = maskedEvent.response_body !== undefined;
52148
- const streamCaptured = Boolean(maskedEvent.stream_file);
52149
- const { content: streamContent, warning: streamWarning } = readStreamContent(resolveLogBaseDir(context2.logConfig), maskedEvent.stream_file);
52113
+ const event = parsed;
52114
+ const level = getLevel(event);
52115
+ const statusClass = getStatusClass2(event);
52116
+ const bodyPolicy = detectBodyPolicy(event);
52117
+ const requestBodyAvailable = event.request_body !== undefined;
52118
+ const responseBodyAvailable = event.response_body !== undefined;
52119
+ const streamCaptured = Boolean(event.stream_file);
52120
+ const { content: streamContent, warning: streamWarning } = readStreamContent(resolveLogBaseDir(context2.logConfig), event.stream_file);
52150
52121
  return {
52151
52122
  id,
52152
52123
  summary: {
52153
52124
  id,
52154
- ts: maskedEvent.ts_start,
52125
+ ts: event.ts_start,
52155
52126
  level,
52156
- provider: maskedEvent.provider,
52157
- routeType: maskedEvent.route_type,
52158
- routeRuleKey: maskedEvent.route_rule_key,
52159
- requestId: maskedEvent.request_id,
52160
- latencyMs: Math.max(0, maskedEvent.latency_ms ?? 0),
52161
- upstreamStatus: maskedEvent.upstream_status ?? 0,
52127
+ provider: event.provider,
52128
+ routeType: event.route_type,
52129
+ routeRuleKey: event.route_rule_key,
52130
+ requestId: event.request_id,
52131
+ latencyMs: Math.max(0, event.latency_ms ?? 0),
52132
+ upstreamStatus: event.upstream_status ?? 0,
52162
52133
  statusClass,
52163
52134
  hasError: level === "error",
52164
- model: maskedEvent.model_out || maskedEvent.model_in,
52165
- modelIn: maskedEvent.model_in,
52166
- modelOut: maskedEvent.model_out
52135
+ model: event.model_out || event.model_in,
52136
+ modelIn: event.model_in,
52137
+ modelOut: event.model_out
52167
52138
  },
52168
52139
  request: {
52169
- method: maskedEvent.method,
52170
- path: maskedEvent.path,
52171
- contentType: maskedEvent.content_type_req,
52172
- requestHeadersMasked: maskedEvent.request_headers_masked,
52173
- requestBody: maskedEvent.request_body ?? null
52140
+ method: event.method,
52141
+ path: event.path,
52142
+ contentType: event.content_type_req,
52143
+ requestHeaders: event.request_headers,
52144
+ requestBody: event.request_body ?? null
52174
52145
  },
52175
52146
  response: {
52176
- upstreamStatus: maskedEvent.upstream_status ?? 0,
52177
- contentType: maskedEvent.content_type_res,
52178
- responseHeaders: maskedEvent.response_headers,
52179
- responseBody: maskedEvent.response_body ?? null
52147
+ upstreamStatus: event.upstream_status ?? 0,
52148
+ contentType: event.content_type_res,
52149
+ responseHeaders: event.response_headers,
52150
+ responseBody: event.response_body ?? null
52180
52151
  },
52181
52152
  upstream: {
52182
- targetUrl: maskedEvent.target_url,
52183
- proxyUrl: maskedEvent.proxy_url ?? null,
52184
- providerRequestId: maskedEvent.provider_request_id,
52185
- errorType: maskedEvent.error_type,
52186
- errorMessage: maskedEvent.error_message,
52187
- isStream: maskedEvent.is_stream,
52188
- streamFile: maskedEvent.stream_file ?? null,
52153
+ targetUrl: event.target_url,
52154
+ proxyUrl: event.proxy_url ?? null,
52155
+ providerRequestId: event.provider_request_id,
52156
+ errorType: event.error_type,
52157
+ errorMessage: event.error_message,
52158
+ isStream: event.is_stream,
52159
+ streamFile: event.stream_file ?? null,
52189
52160
  streamContent
52190
52161
  },
52191
52162
  capture: {
@@ -52194,11 +52165,11 @@ async function buildLogEventDetail(id, parsed, location, context2) {
52194
52165
  responseBodyAvailable,
52195
52166
  streamCaptured,
52196
52167
  truncatedHints: [
52197
- ...buildTruncatedHints(maskedEvent, context2.logConfig?.bodyPolicy ?? bodyPolicy),
52168
+ ...buildTruncatedHints(event, context2.logConfig?.bodyPolicy ?? bodyPolicy),
52198
52169
  ...streamWarning ? [streamWarning] : []
52199
52170
  ]
52200
52171
  },
52201
- rawEvent: maskedEvent,
52172
+ rawEvent: event,
52202
52173
  location
52203
52174
  };
52204
52175
  }
@@ -52910,13 +52881,6 @@ function startLogStorageBackgroundTask(logConfig) {
52910
52881
  // src/logger.ts
52911
52882
  import { appendFileSync, existsSync as existsSync6, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
52912
52883
  import { join as join7 } from "path";
52913
- var SENSITIVE_HEADERS = new Set([
52914
- "authorization",
52915
- "x-api-key",
52916
- "cookie",
52917
- "set-cookie",
52918
- "proxy-authorization"
52919
- ]);
52920
52884
 
52921
52885
  class Logger {
52922
52886
  baseDir;
@@ -52997,14 +52961,10 @@ function getLogger() {
52997
52961
  function resetLogger() {
52998
52962
  instance = null;
52999
52963
  }
53000
- function maskHeaders(headers) {
52964
+ function collectHeaders(headers) {
53001
52965
  const result = {};
53002
52966
  headers.forEach((value, key2) => {
53003
- if (SENSITIVE_HEADERS.has(key2.toLowerCase())) {
53004
- result[key2] = value.length > 4 ? `${value.slice(0, 4)}****` : "****";
53005
- } else {
53006
- result[key2] = value;
53007
- }
52967
+ result[key2] = value;
53008
52968
  });
53009
52969
  return result;
53010
52970
  }
@@ -53016,19 +52976,8 @@ function extractProviderRequestId(headers) {
53016
52976
  }
53017
52977
  return null;
53018
52978
  }
53019
- function maskUrlCredentials(rawUrl) {
53020
- try {
53021
- const parsed = new URL(rawUrl);
53022
- if (!parsed.username && !parsed.password)
53023
- return rawUrl;
53024
- if (parsed.username)
53025
- parsed.username = "****";
53026
- if (parsed.password)
53027
- parsed.password = "****";
53028
- return parsed.toString();
53029
- } catch {
53030
- return rawUrl;
53031
- }
52979
+ function normalizeUrl(rawUrl) {
52980
+ return rawUrl;
53032
52981
  }
53033
52982
 
53034
52983
  // src/openapi.ts
@@ -53475,7 +53424,7 @@ var openAPISpec = {
53475
53424
  method: { type: "string" },
53476
53425
  path: { type: "string" },
53477
53426
  contentType: { type: ["string", "null"] },
53478
- requestHeadersMasked: {
53427
+ requestHeaders: {
53479
53428
  type: "object",
53480
53429
  additionalProperties: { type: "string" }
53481
53430
  },
@@ -54195,14 +54144,14 @@ function buildLogEvent(logMeta, targetUrl, proxyUrl, tsEnd, overrides) {
54195
54144
  provider: logMeta.provider,
54196
54145
  model_in: logMeta.modelIn,
54197
54146
  model_out: logMeta.modelOut,
54198
- target_url: maskUrlCredentials(targetUrl),
54199
- proxy_url: proxyUrl ? maskUrlCredentials(proxyUrl) : null,
54147
+ target_url: normalizeUrl(targetUrl),
54148
+ proxy_url: proxyUrl ? normalizeUrl(proxyUrl) : null,
54200
54149
  is_stream: logMeta.isStream,
54201
54150
  upstream_status: 0,
54202
54151
  content_type_req: logMeta.contentTypeReq,
54203
54152
  content_type_res: null,
54204
54153
  user_agent: logMeta.userAgent,
54205
- request_headers_masked: logMeta.requestHeadersMasked,
54154
+ request_headers: logMeta.requestHeaders,
54206
54155
  response_headers: {},
54207
54156
  request_bytes: logMeta.requestBytes,
54208
54157
  response_bytes: null,
@@ -54382,7 +54331,7 @@ function createModelRoutingHandler(options) {
54382
54331
  contentTypeReq: c2.req.header("content-type") ?? null,
54383
54332
  userAgent: c2.req.header("user-agent") ?? null,
54384
54333
  requestBytes: Buffer.byteLength(body, "utf-8"),
54385
- requestHeadersMasked: maskHeaders(c2.req.raw.headers)
54334
+ requestHeaders: collectHeaders(c2.req.raw.headers)
54386
54335
  };
54387
54336
  return proxyRequest(c2, {
54388
54337
  targetUrl,
@@ -55203,12 +55152,29 @@ function createAppRuntimeFromConfigPath(configPath) {
55203
55152
  }
55204
55153
 
55205
55154
  // src/server.ts
55155
+ var DEFAULT_IDLE_TIMEOUT_SECONDS = 600;
55156
+ function resolveIdleTimeoutSeconds(explicit) {
55157
+ if (typeof explicit === "number" && Number.isFinite(explicit) && explicit >= 0) {
55158
+ return explicit;
55159
+ }
55160
+ const fromEnv = process.env.LOCAL_ROUTER_IDLE_TIMEOUT;
55161
+ if (!fromEnv) {
55162
+ return DEFAULT_IDLE_TIMEOUT_SECONDS;
55163
+ }
55164
+ const parsed = Number.parseInt(fromEnv, 10);
55165
+ if (Number.isFinite(parsed) && parsed >= 0) {
55166
+ return parsed;
55167
+ }
55168
+ return DEFAULT_IDLE_TIMEOUT_SECONDS;
55169
+ }
55206
55170
  function startServer(options) {
55207
55171
  const runtime = createAppRuntimeFromConfigPath(options.configPath);
55172
+ const idleTimeout = resolveIdleTimeoutSeconds(options.idleTimeoutSeconds);
55208
55173
  const server = Bun.serve({
55209
55174
  fetch: runtime.app.fetch,
55210
55175
  hostname: options.host,
55211
- port: options.port
55176
+ port: options.port,
55177
+ idleTimeout
55212
55178
  });
55213
55179
  const host = server.hostname;
55214
55180
  const port = server.port;
@@ -55284,7 +55250,8 @@ function parseSharedFlags(args) {
55284
55250
  options: {
55285
55251
  config: { type: "string" },
55286
55252
  host: { type: "string" },
55287
- port: { type: "string" }
55253
+ port: { type: "string" },
55254
+ "idle-timeout": { type: "string" }
55288
55255
  },
55289
55256
  allowPositionals: true,
55290
55257
  strict: false
@@ -55294,10 +55261,16 @@ function parseSharedFlags(args) {
55294
55261
  if (portRaw && !Number.isFinite(port)) {
55295
55262
  throw new Error(`\u65E0\u6548\u7AEF\u53E3: ${portRaw}`);
55296
55263
  }
55264
+ const idleTimeoutRaw = parsed.values["idle-timeout"];
55265
+ const idleTimeoutSeconds = idleTimeoutRaw ? Number.parseInt(idleTimeoutRaw, 10) : undefined;
55266
+ if (idleTimeoutRaw && (!Number.isFinite(idleTimeoutSeconds) || idleTimeoutSeconds < 0)) {
55267
+ throw new Error(`\u65E0\u6548 idle-timeout: ${idleTimeoutRaw}`);
55268
+ }
55297
55269
  return {
55298
55270
  config: parsed.values.config,
55299
55271
  host: parsed.values.host,
55300
- port
55272
+ port,
55273
+ idleTimeoutSeconds
55301
55274
  };
55302
55275
  }
55303
55276
  async function checkHealth(baseUrl, timeoutMs = 1500) {
@@ -55343,12 +55316,14 @@ async function runServerProcess(opts) {
55343
55316
  if (!Number.isFinite(port)) {
55344
55317
  throw new Error(`\u65E0\u6548\u7AEF\u53E3: ${opts.port ?? process.env.PORT}`);
55345
55318
  }
55319
+ const idleTimeoutSeconds = opts.idleTimeoutSeconds ?? Number.parseInt(process.env.LOCAL_ROUTER_IDLE_TIMEOUT ?? "", 10);
55346
55320
  let running;
55347
55321
  try {
55348
55322
  running = startServer({
55349
55323
  configPath: ensured.path,
55350
55324
  host,
55351
- port
55325
+ port,
55326
+ idleTimeoutSeconds: Number.isFinite(idleTimeoutSeconds) ? idleTimeoutSeconds : undefined
55352
55327
  });
55353
55328
  } catch (err) {
55354
55329
  const code = err?.code;
@@ -55422,6 +55397,9 @@ async function startDaemon(flags) {
55422
55397
  if (typeof flags.port === "number") {
55423
55398
  childArgs.push("--port", String(flags.port));
55424
55399
  }
55400
+ if (typeof flags.idleTimeoutSeconds === "number") {
55401
+ childArgs.push("--idle-timeout", String(flags.idleTimeoutSeconds));
55402
+ }
55425
55403
  childArgs.push("--log-file", files.daemonLog);
55426
55404
  const child = Bun.spawn([process.execPath, ...childArgs], {
55427
55405
  stdin: "ignore",
@@ -55947,18 +55925,19 @@ Usage:
55947
55925
  local-router <command> [options]
55948
55926
 
55949
55927
  Commands:
55950
- start [--daemon] [--config <path>] [--host <host>] [--port <port>]
55928
+ start [--daemon] [--config <path>] [--host <host>] [--port <port>] [--idle-timeout <sec>]
55951
55929
  stop
55952
- restart [--daemon] [--config <path>] [--host <host>] [--port <port>]
55930
+ restart [--daemon] [--config <path>] [--host <host>] [--port <port>] [--idle-timeout <sec>]
55953
55931
  status [--json]
55954
55932
  logs [--follow] [--lines <n>]
55955
55933
  init [--config <path>] [--force]
55956
55934
  config <subcommand> [...args]
55935
+ get-route --type <route-type> [--model-alias <alias>] [--config <path>]
55957
55936
  health
55958
55937
  version
55959
55938
 
55960
55939
  Hidden commands:
55961
- __run-server --mode <daemon|foreground> [--config] [--host] [--port] [--log-file]
55940
+ __run-server --mode <daemon|foreground> [--config] [--host] [--port] [--idle-timeout] [--log-file]
55962
55941
  `);
55963
55942
  }
55964
55943
  async function printVersion() {
@@ -55988,7 +55967,8 @@ async function cmdStart(args) {
55988
55967
  mode: "foreground",
55989
55968
  config: flags.config,
55990
55969
  host: flags.host,
55991
- port: flags.port
55970
+ port: flags.port,
55971
+ idleTimeoutSeconds: flags.idleTimeoutSeconds
55992
55972
  });
55993
55973
  }
55994
55974
  async function cmdStop() {
@@ -56119,6 +56099,52 @@ async function cmdInit(args) {
56119
56099
  const result = ensureConfigFile(configPath);
56120
56100
  console.log(result.created ? `\u5DF2\u521D\u59CB\u5316\u914D\u7F6E: ${result.path}` : `\u914D\u7F6E\u5DF2\u5B58\u5728: ${result.path}`);
56121
56101
  }
56102
+ function formatRouteTarget(target) {
56103
+ return `${target.provider} / ${target.model}`;
56104
+ }
56105
+ async function cmdGetRoute(args) {
56106
+ const parsed = parseArgs3({
56107
+ args,
56108
+ options: {
56109
+ type: { type: "string" },
56110
+ "model-alias": { type: "string" },
56111
+ model: { type: "string" },
56112
+ config: { type: "string" }
56113
+ },
56114
+ allowPositionals: true,
56115
+ strict: false
56116
+ });
56117
+ const routeType = parsed.values.type;
56118
+ if (!routeType) {
56119
+ throw new Error("\u7528\u6CD5: local-router get-route --type <route-type> [--model-alias <alias>] [--config <path>]");
56120
+ }
56121
+ const configPath = resolveConfigPath(parsed.values.config);
56122
+ const config2 = loadConfig(configPath);
56123
+ const modelMap = config2.routes[routeType];
56124
+ if (!modelMap) {
56125
+ throw new Error(`route type \u4E0D\u5B58\u5728: ${routeType}`);
56126
+ }
56127
+ const modelAlias = parsed.values["model-alias"] ?? parsed.values.model;
56128
+ if (modelAlias) {
56129
+ const target = modelMap[modelAlias] ?? modelMap["*"];
56130
+ if (!target) {
56131
+ throw new Error(`\u672A\u547D\u4E2D\u8DEF\u7531\u4E14\u7F3A\u5C11\u515C\u5E95: ${routeType}`);
56132
+ }
56133
+ console.log(formatRouteTarget(target));
56134
+ return;
56135
+ }
56136
+ const chunks = [];
56137
+ for (const [alias, target] of Object.entries(modelMap)) {
56138
+ if (alias === "*")
56139
+ continue;
56140
+ chunks.push(`${alias} : ${formatRouteTarget(target)}`);
56141
+ }
56142
+ const fallback = modelMap["*"];
56143
+ if (fallback) {
56144
+ chunks.push(`default : ${formatRouteTarget(fallback)}`);
56145
+ }
56146
+ console.log(chunks.join(" | "));
56147
+ }
56122
56148
  async function cmdHealth() {
56123
56149
  await cleanupIfStale();
56124
56150
  const state = readRuntimeState();
@@ -56141,6 +56167,7 @@ async function cmdRunServer(args) {
56141
56167
  config: { type: "string" },
56142
56168
  host: { type: "string" },
56143
56169
  port: { type: "string" },
56170
+ "idle-timeout": { type: "string" },
56144
56171
  "log-file": { type: "string" }
56145
56172
  },
56146
56173
  allowPositionals: true,
@@ -56149,11 +56176,14 @@ async function cmdRunServer(args) {
56149
56176
  const mode = parsed.values.mode === "daemon" ? "daemon" : "foreground";
56150
56177
  const portRaw = parsed.values.port;
56151
56178
  const port = portRaw ? Number.parseInt(portRaw, 10) : undefined;
56179
+ const idleTimeoutRaw = parsed.values["idle-timeout"];
56180
+ const idleTimeoutSeconds = idleTimeoutRaw ? Number.parseInt(idleTimeoutRaw, 10) : undefined;
56152
56181
  await runServerProcess({
56153
56182
  mode,
56154
56183
  config: parsed.values.config,
56155
56184
  host: parsed.values.host,
56156
56185
  port,
56186
+ idleTimeoutSeconds: Number.isFinite(idleTimeoutSeconds) ? idleTimeoutSeconds : undefined,
56157
56187
  logFile: parsed.values["log-file"]
56158
56188
  });
56159
56189
  }
@@ -56184,6 +56214,9 @@ async function main() {
56184
56214
  case "config":
56185
56215
  await cmdConfig(rest);
56186
56216
  return;
56217
+ case "get-route":
56218
+ await cmdGetRoute(rest);
56219
+ return;
56187
56220
  case "version":
56188
56221
  await printVersion();
56189
56222
  return;