@lakphy/local-router 0.3.1 → 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,9 +55925,9 @@ 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]
@@ -55959,7 +55937,7 @@ Commands:
55959
55937
  version
55960
55938
 
55961
55939
  Hidden commands:
55962
- __run-server --mode <daemon|foreground> [--config] [--host] [--port] [--log-file]
55940
+ __run-server --mode <daemon|foreground> [--config] [--host] [--port] [--idle-timeout] [--log-file]
55963
55941
  `);
55964
55942
  }
55965
55943
  async function printVersion() {
@@ -55989,7 +55967,8 @@ async function cmdStart(args) {
55989
55967
  mode: "foreground",
55990
55968
  config: flags.config,
55991
55969
  host: flags.host,
55992
- port: flags.port
55970
+ port: flags.port,
55971
+ idleTimeoutSeconds: flags.idleTimeoutSeconds
55993
55972
  });
55994
55973
  }
55995
55974
  async function cmdStop() {
@@ -56188,6 +56167,7 @@ async function cmdRunServer(args) {
56188
56167
  config: { type: "string" },
56189
56168
  host: { type: "string" },
56190
56169
  port: { type: "string" },
56170
+ "idle-timeout": { type: "string" },
56191
56171
  "log-file": { type: "string" }
56192
56172
  },
56193
56173
  allowPositionals: true,
@@ -56196,11 +56176,14 @@ async function cmdRunServer(args) {
56196
56176
  const mode = parsed.values.mode === "daemon" ? "daemon" : "foreground";
56197
56177
  const portRaw = parsed.values.port;
56198
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;
56199
56181
  await runServerProcess({
56200
56182
  mode,
56201
56183
  config: parsed.values.config,
56202
56184
  host: parsed.values.host,
56203
56185
  port,
56186
+ idleTimeoutSeconds: Number.isFinite(idleTimeoutSeconds) ? idleTimeoutSeconds : undefined,
56204
56187
  logFile: parsed.values["log-file"]
56205
56188
  });
56206
56189
  }
package/dist/entry.js CHANGED
@@ -51279,7 +51279,7 @@ var DEFAULT_CONFIG = `{
51279
51279
  // \u65E5\u5FD7\u914D\u7F6E\uFF08\u53EF\u9009\uFF0C\u4E0D\u914D\u7F6E\u5219\u4E0D\u542F\u7528\u65E5\u5FD7\u8BB0\u5F55\uFF09
51280
51280
  // log: {
51281
51281
  // enabled: true,
51282
- // bodyPolicy: "off", // off | masked | full
51282
+ // bodyPolicy: "off", // off | full
51283
51283
  // streams: {
51284
51284
  // enabled: true,
51285
51285
  // maxBytesPerRequest: 10485760, // 10MB
@@ -51807,7 +51807,6 @@ var MAX_QUERY_LIMIT = 200;
51807
51807
  var DEFAULT_QUERY_LIMIT = 50;
51808
51808
  var MAX_EXPORT_ROWS = 5000;
51809
51809
  var MAX_Q_LENGTH = 200;
51810
- var SENSITIVE_FIELD_PATTERN = /(authorization|token|cookie|password|passphrase|secret|api[_-]?key)/i;
51811
51810
  function encodeBase64Url(value) {
51812
51811
  return Buffer.from(value, "utf-8").toString("base64url");
51813
51812
  }
@@ -52023,34 +52022,6 @@ function eventToSummary(item) {
52023
52022
  sessionId: identity.sessionId
52024
52023
  };
52025
52024
  }
52026
- function maskValue(value) {
52027
- if (value == null)
52028
- return value;
52029
- if (typeof value === "string") {
52030
- return value.length > 4 ? `${value.slice(0, 2)}****` : "****";
52031
- }
52032
- if (typeof value === "number" || typeof value === "boolean") {
52033
- return "****";
52034
- }
52035
- return "****";
52036
- }
52037
- function maskSensitiveDeep(value, parentKey = "") {
52038
- if (Array.isArray(value)) {
52039
- return value.map((item) => maskSensitiveDeep(item, parentKey));
52040
- }
52041
- if (value && typeof value === "object") {
52042
- const output = {};
52043
- for (const [key2, child] of Object.entries(value)) {
52044
- if (SENSITIVE_FIELD_PATTERN.test(key2) || SENSITIVE_FIELD_PATTERN.test(parentKey)) {
52045
- output[key2] = maskValue(child);
52046
- } else {
52047
- output[key2] = maskSensitiveDeep(child, key2);
52048
- }
52049
- }
52050
- return output;
52051
- }
52052
- return value;
52053
- }
52054
52025
  function detectBodyPolicy(event) {
52055
52026
  const hasRequestBody = event.request_body !== undefined;
52056
52027
  const hasResponseBody = event.response_body !== undefined;
@@ -52123,53 +52094,53 @@ function readStreamContent(baseDir, streamFile) {
52123
52094
  }
52124
52095
  }
52125
52096
  async function buildLogEventDetail(id, parsed, location, context2) {
52126
- const maskedEvent = maskSensitiveDeep(parsed);
52127
- const level = getLevel(maskedEvent);
52128
- const statusClass = getStatusClass2(maskedEvent);
52129
- const bodyPolicy = detectBodyPolicy(maskedEvent);
52130
- const requestBodyAvailable = maskedEvent.request_body !== undefined;
52131
- const responseBodyAvailable = maskedEvent.response_body !== undefined;
52132
- const streamCaptured = Boolean(maskedEvent.stream_file);
52133
- const { content: streamContent, warning: streamWarning } = readStreamContent(resolveLogBaseDir(context2.logConfig), maskedEvent.stream_file);
52097
+ const event = parsed;
52098
+ const level = getLevel(event);
52099
+ const statusClass = getStatusClass2(event);
52100
+ const bodyPolicy = detectBodyPolicy(event);
52101
+ const requestBodyAvailable = event.request_body !== undefined;
52102
+ const responseBodyAvailable = event.response_body !== undefined;
52103
+ const streamCaptured = Boolean(event.stream_file);
52104
+ const { content: streamContent, warning: streamWarning } = readStreamContent(resolveLogBaseDir(context2.logConfig), event.stream_file);
52134
52105
  return {
52135
52106
  id,
52136
52107
  summary: {
52137
52108
  id,
52138
- ts: maskedEvent.ts_start,
52109
+ ts: event.ts_start,
52139
52110
  level,
52140
- provider: maskedEvent.provider,
52141
- routeType: maskedEvent.route_type,
52142
- routeRuleKey: maskedEvent.route_rule_key,
52143
- requestId: maskedEvent.request_id,
52144
- latencyMs: Math.max(0, maskedEvent.latency_ms ?? 0),
52145
- upstreamStatus: maskedEvent.upstream_status ?? 0,
52111
+ provider: event.provider,
52112
+ routeType: event.route_type,
52113
+ routeRuleKey: event.route_rule_key,
52114
+ requestId: event.request_id,
52115
+ latencyMs: Math.max(0, event.latency_ms ?? 0),
52116
+ upstreamStatus: event.upstream_status ?? 0,
52146
52117
  statusClass,
52147
52118
  hasError: level === "error",
52148
- model: maskedEvent.model_out || maskedEvent.model_in,
52149
- modelIn: maskedEvent.model_in,
52150
- modelOut: maskedEvent.model_out
52119
+ model: event.model_out || event.model_in,
52120
+ modelIn: event.model_in,
52121
+ modelOut: event.model_out
52151
52122
  },
52152
52123
  request: {
52153
- method: maskedEvent.method,
52154
- path: maskedEvent.path,
52155
- contentType: maskedEvent.content_type_req,
52156
- requestHeadersMasked: maskedEvent.request_headers_masked,
52157
- requestBody: maskedEvent.request_body ?? null
52124
+ method: event.method,
52125
+ path: event.path,
52126
+ contentType: event.content_type_req,
52127
+ requestHeaders: event.request_headers,
52128
+ requestBody: event.request_body ?? null
52158
52129
  },
52159
52130
  response: {
52160
- upstreamStatus: maskedEvent.upstream_status ?? 0,
52161
- contentType: maskedEvent.content_type_res,
52162
- responseHeaders: maskedEvent.response_headers,
52163
- responseBody: maskedEvent.response_body ?? null
52131
+ upstreamStatus: event.upstream_status ?? 0,
52132
+ contentType: event.content_type_res,
52133
+ responseHeaders: event.response_headers,
52134
+ responseBody: event.response_body ?? null
52164
52135
  },
52165
52136
  upstream: {
52166
- targetUrl: maskedEvent.target_url,
52167
- proxyUrl: maskedEvent.proxy_url ?? null,
52168
- providerRequestId: maskedEvent.provider_request_id,
52169
- errorType: maskedEvent.error_type,
52170
- errorMessage: maskedEvent.error_message,
52171
- isStream: maskedEvent.is_stream,
52172
- streamFile: maskedEvent.stream_file ?? null,
52137
+ targetUrl: event.target_url,
52138
+ proxyUrl: event.proxy_url ?? null,
52139
+ providerRequestId: event.provider_request_id,
52140
+ errorType: event.error_type,
52141
+ errorMessage: event.error_message,
52142
+ isStream: event.is_stream,
52143
+ streamFile: event.stream_file ?? null,
52173
52144
  streamContent
52174
52145
  },
52175
52146
  capture: {
@@ -52178,11 +52149,11 @@ async function buildLogEventDetail(id, parsed, location, context2) {
52178
52149
  responseBodyAvailable,
52179
52150
  streamCaptured,
52180
52151
  truncatedHints: [
52181
- ...buildTruncatedHints(maskedEvent, context2.logConfig?.bodyPolicy ?? bodyPolicy),
52152
+ ...buildTruncatedHints(event, context2.logConfig?.bodyPolicy ?? bodyPolicy),
52182
52153
  ...streamWarning ? [streamWarning] : []
52183
52154
  ]
52184
52155
  },
52185
- rawEvent: maskedEvent,
52156
+ rawEvent: event,
52186
52157
  location
52187
52158
  };
52188
52159
  }
@@ -52894,13 +52865,6 @@ function startLogStorageBackgroundTask(logConfig) {
52894
52865
  // src/logger.ts
52895
52866
  import { appendFileSync, existsSync as existsSync6, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
52896
52867
  import { join as join7 } from "path";
52897
- var SENSITIVE_HEADERS = new Set([
52898
- "authorization",
52899
- "x-api-key",
52900
- "cookie",
52901
- "set-cookie",
52902
- "proxy-authorization"
52903
- ]);
52904
52868
 
52905
52869
  class Logger {
52906
52870
  baseDir;
@@ -52981,14 +52945,10 @@ function getLogger() {
52981
52945
  function resetLogger() {
52982
52946
  instance = null;
52983
52947
  }
52984
- function maskHeaders(headers) {
52948
+ function collectHeaders(headers) {
52985
52949
  const result = {};
52986
52950
  headers.forEach((value, key2) => {
52987
- if (SENSITIVE_HEADERS.has(key2.toLowerCase())) {
52988
- result[key2] = value.length > 4 ? `${value.slice(0, 4)}****` : "****";
52989
- } else {
52990
- result[key2] = value;
52991
- }
52951
+ result[key2] = value;
52992
52952
  });
52993
52953
  return result;
52994
52954
  }
@@ -53000,19 +52960,8 @@ function extractProviderRequestId(headers) {
53000
52960
  }
53001
52961
  return null;
53002
52962
  }
53003
- function maskUrlCredentials(rawUrl) {
53004
- try {
53005
- const parsed = new URL(rawUrl);
53006
- if (!parsed.username && !parsed.password)
53007
- return rawUrl;
53008
- if (parsed.username)
53009
- parsed.username = "****";
53010
- if (parsed.password)
53011
- parsed.password = "****";
53012
- return parsed.toString();
53013
- } catch {
53014
- return rawUrl;
53015
- }
52963
+ function normalizeUrl(rawUrl) {
52964
+ return rawUrl;
53016
52965
  }
53017
52966
 
53018
52967
  // src/openapi.ts
@@ -53459,7 +53408,7 @@ var openAPISpec = {
53459
53408
  method: { type: "string" },
53460
53409
  path: { type: "string" },
53461
53410
  contentType: { type: ["string", "null"] },
53462
- requestHeadersMasked: {
53411
+ requestHeaders: {
53463
53412
  type: "object",
53464
53413
  additionalProperties: { type: "string" }
53465
53414
  },
@@ -54179,14 +54128,14 @@ function buildLogEvent(logMeta, targetUrl, proxyUrl, tsEnd, overrides) {
54179
54128
  provider: logMeta.provider,
54180
54129
  model_in: logMeta.modelIn,
54181
54130
  model_out: logMeta.modelOut,
54182
- target_url: maskUrlCredentials(targetUrl),
54183
- proxy_url: proxyUrl ? maskUrlCredentials(proxyUrl) : null,
54131
+ target_url: normalizeUrl(targetUrl),
54132
+ proxy_url: proxyUrl ? normalizeUrl(proxyUrl) : null,
54184
54133
  is_stream: logMeta.isStream,
54185
54134
  upstream_status: 0,
54186
54135
  content_type_req: logMeta.contentTypeReq,
54187
54136
  content_type_res: null,
54188
54137
  user_agent: logMeta.userAgent,
54189
- request_headers_masked: logMeta.requestHeadersMasked,
54138
+ request_headers: logMeta.requestHeaders,
54190
54139
  response_headers: {},
54191
54140
  request_bytes: logMeta.requestBytes,
54192
54141
  response_bytes: null,
@@ -54366,7 +54315,7 @@ function createModelRoutingHandler(options) {
54366
54315
  contentTypeReq: c2.req.header("content-type") ?? null,
54367
54316
  userAgent: c2.req.header("user-agent") ?? null,
54368
54317
  requestBytes: Buffer.byteLength(body, "utf-8"),
54369
- requestHeadersMasked: maskHeaders(c2.req.raw.headers)
54318
+ requestHeaders: collectHeaders(c2.req.raw.headers)
54370
54319
  };
54371
54320
  return proxyRequest(c2, {
54372
54321
  targetUrl,