@lakphy/local-router 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +177 -134
- package/dist/entry.js +153 -110
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -11167,7 +11167,7 @@ __export(exports_config_extra, {
|
|
|
11167
11167
|
configBackupsList: () => configBackupsList
|
|
11168
11168
|
});
|
|
11169
11169
|
import { existsSync as existsSync9, readdirSync, readFileSync as readFileSync8, statSync as statSync4 } from "fs";
|
|
11170
|
-
import { dirname as dirname4, join as
|
|
11170
|
+
import { dirname as dirname4, join as join12 } from "path";
|
|
11171
11171
|
import { parseArgs as parseArgs2 } from "util";
|
|
11172
11172
|
function maskApiKey(k) {
|
|
11173
11173
|
if (k.length <= 8)
|
|
@@ -11252,7 +11252,7 @@ async function configDiff(args, flags) {
|
|
|
11252
11252
|
const against = parsed.values.against;
|
|
11253
11253
|
let beforePath;
|
|
11254
11254
|
if (!against) {
|
|
11255
|
-
const backupDir =
|
|
11255
|
+
const backupDir = join12(dirname4(path), ".backups");
|
|
11256
11256
|
if (!existsSync9(backupDir)) {
|
|
11257
11257
|
throw new CliError("CONFIG_NOT_FOUND", "\u6CA1\u6709\u5907\u4EFD\u53EF\u5BF9\u6BD4", {
|
|
11258
11258
|
hint: "\u6307\u5B9A --against <path|backup-id>"
|
|
@@ -11262,16 +11262,16 @@ async function configDiff(args, flags) {
|
|
|
11262
11262
|
if (files.length === 0) {
|
|
11263
11263
|
throw new CliError("CONFIG_NOT_FOUND", "\u5907\u4EFD\u76EE\u5F55\u4E3A\u7A7A");
|
|
11264
11264
|
}
|
|
11265
|
-
beforePath =
|
|
11265
|
+
beforePath = join12(backupDir, files[0]);
|
|
11266
11266
|
} else if (existsSync9(against)) {
|
|
11267
11267
|
beforePath = against;
|
|
11268
11268
|
} else {
|
|
11269
|
-
const backupDir =
|
|
11270
|
-
const candidate =
|
|
11269
|
+
const backupDir = join12(dirname4(path), ".backups");
|
|
11270
|
+
const candidate = join12(backupDir, `config-${against}.json5`);
|
|
11271
11271
|
if (existsSync9(candidate))
|
|
11272
11272
|
beforePath = candidate;
|
|
11273
|
-
else if (existsSync9(
|
|
11274
|
-
beforePath =
|
|
11273
|
+
else if (existsSync9(join12(backupDir, against)))
|
|
11274
|
+
beforePath = join12(backupDir, against);
|
|
11275
11275
|
else {
|
|
11276
11276
|
throw new CliError("CONFIG_NOT_FOUND", `--against \u4E0D\u5B58\u5728: ${against}`);
|
|
11277
11277
|
}
|
|
@@ -11426,11 +11426,11 @@ ${result.diff}`
|
|
|
11426
11426
|
});
|
|
11427
11427
|
}
|
|
11428
11428
|
function listBackups(configPath) {
|
|
11429
|
-
const dir =
|
|
11429
|
+
const dir = join12(dirname4(configPath), ".backups");
|
|
11430
11430
|
if (!existsSync9(dir))
|
|
11431
11431
|
return [];
|
|
11432
11432
|
return readdirSync(dir).filter((f) => f.startsWith("config-") && f.endsWith(".json5")).map((f) => {
|
|
11433
|
-
const full =
|
|
11433
|
+
const full = join12(dir, f);
|
|
11434
11434
|
const st = statSync4(full);
|
|
11435
11435
|
return {
|
|
11436
11436
|
id: f.replace(/^config-/, "").replace(/\.json5$/, ""),
|
|
@@ -11677,7 +11677,7 @@ import { parseArgs as parseArgs3 } from "util";
|
|
|
11677
11677
|
|
|
11678
11678
|
// src/cli/process.ts
|
|
11679
11679
|
init_config();
|
|
11680
|
-
import { closeSync as
|
|
11680
|
+
import { closeSync as closeSync3, openSync as openSync3, readFileSync as readFileSync7, statSync as statSync3 } from "fs";
|
|
11681
11681
|
import { setTimeout as sleep } from "timers/promises";
|
|
11682
11682
|
import { parseArgs } from "util";
|
|
11683
11683
|
|
|
@@ -55041,7 +55041,15 @@ function subscribeLogEvents(subscriber) {
|
|
|
55041
55041
|
}
|
|
55042
55042
|
|
|
55043
55043
|
// src/logger.ts
|
|
55044
|
-
import {
|
|
55044
|
+
import {
|
|
55045
|
+
appendFileSync,
|
|
55046
|
+
closeSync as closeSync2,
|
|
55047
|
+
existsSync as existsSync7,
|
|
55048
|
+
mkdirSync as mkdirSync4,
|
|
55049
|
+
openSync as openSync2,
|
|
55050
|
+
statSync as statSync2,
|
|
55051
|
+
writeSync
|
|
55052
|
+
} from "fs";
|
|
55045
55053
|
import { join as join9 } from "path";
|
|
55046
55054
|
class Logger {
|
|
55047
55055
|
baseDir;
|
|
@@ -55105,22 +55113,73 @@ class Logger {
|
|
|
55105
55113
|
console.error("[logger] \u4E8B\u4EF6\u65E5\u5FD7\u5199\u5165\u5931\u8D25:", err);
|
|
55106
55114
|
}
|
|
55107
55115
|
}
|
|
55108
|
-
|
|
55109
|
-
if (!this._enabled || !this._streamsEnabled)
|
|
55110
|
-
return
|
|
55116
|
+
openStreamCapture(requestId, dateStr) {
|
|
55117
|
+
if (!this._enabled || !this._streamsEnabled) {
|
|
55118
|
+
return makeNoopStreamCaptureHandle();
|
|
55119
|
+
}
|
|
55120
|
+
const maxStreamBytes = this.maxStreamBytes;
|
|
55121
|
+
const truncationMarker = Buffer.from(`
|
|
55122
|
+
[TRUNCATED]`);
|
|
55123
|
+
let filePath;
|
|
55124
|
+
let fd;
|
|
55111
55125
|
try {
|
|
55112
55126
|
const dir = this.ensureStreamDateDir(dateStr);
|
|
55113
|
-
|
|
55114
|
-
|
|
55115
|
-
[TRUNCATED]` : content;
|
|
55116
|
-
writeFileSync4(filePath, toWrite);
|
|
55117
|
-
return filePath;
|
|
55127
|
+
filePath = join9(dir, `${requestId}.sse.raw`);
|
|
55128
|
+
fd = openSync2(filePath, "a");
|
|
55118
55129
|
} catch (err) {
|
|
55119
|
-
console.error("[logger] \u6D41\u5F0F\u65E5\u5FD7\
|
|
55120
|
-
return
|
|
55130
|
+
console.error("[logger] \u6D41\u5F0F\u65E5\u5FD7\u6253\u5F00\u5931\u8D25:", err);
|
|
55131
|
+
return makeNoopStreamCaptureHandle();
|
|
55121
55132
|
}
|
|
55133
|
+
let bytes = 0;
|
|
55134
|
+
let truncated = false;
|
|
55135
|
+
let finalized = false;
|
|
55136
|
+
return {
|
|
55137
|
+
filePath,
|
|
55138
|
+
write(chunk) {
|
|
55139
|
+
if (finalized || truncated || fd == null)
|
|
55140
|
+
return;
|
|
55141
|
+
try {
|
|
55142
|
+
if (bytes + chunk.byteLength > maxStreamBytes) {
|
|
55143
|
+
const remaining = Math.max(0, maxStreamBytes - bytes);
|
|
55144
|
+
if (remaining > 0) {
|
|
55145
|
+
writeSync(fd, chunk.subarray(0, remaining));
|
|
55146
|
+
bytes += remaining;
|
|
55147
|
+
}
|
|
55148
|
+
writeSync(fd, truncationMarker);
|
|
55149
|
+
truncated = true;
|
|
55150
|
+
return;
|
|
55151
|
+
}
|
|
55152
|
+
writeSync(fd, chunk);
|
|
55153
|
+
bytes += chunk.byteLength;
|
|
55154
|
+
} catch (err) {
|
|
55155
|
+
console.error("[logger] \u6D41\u5F0F\u65E5\u5FD7\u5199\u5165\u5931\u8D25:", err);
|
|
55156
|
+
truncated = true;
|
|
55157
|
+
}
|
|
55158
|
+
},
|
|
55159
|
+
finalize() {
|
|
55160
|
+
if (finalized)
|
|
55161
|
+
return { bytesWritten: bytes, truncated, filePath };
|
|
55162
|
+
finalized = true;
|
|
55163
|
+
if (fd != null) {
|
|
55164
|
+
try {
|
|
55165
|
+
closeSync2(fd);
|
|
55166
|
+
} catch {}
|
|
55167
|
+
fd = null;
|
|
55168
|
+
}
|
|
55169
|
+
return { bytesWritten: bytes, truncated, filePath };
|
|
55170
|
+
}
|
|
55171
|
+
};
|
|
55122
55172
|
}
|
|
55123
55173
|
}
|
|
55174
|
+
function makeNoopStreamCaptureHandle() {
|
|
55175
|
+
return {
|
|
55176
|
+
filePath: null,
|
|
55177
|
+
write() {},
|
|
55178
|
+
finalize() {
|
|
55179
|
+
return { bytesWritten: 0, truncated: false, filePath: null };
|
|
55180
|
+
}
|
|
55181
|
+
};
|
|
55182
|
+
}
|
|
55124
55183
|
var instance = null;
|
|
55125
55184
|
function initLogger(baseDir, config2) {
|
|
55126
55185
|
instance = new Logger(baseDir, config2);
|
|
@@ -56512,11 +56571,6 @@ class PluginManager {
|
|
|
56512
56571
|
}
|
|
56513
56572
|
}
|
|
56514
56573
|
|
|
56515
|
-
// src/proxy.ts
|
|
56516
|
-
import { appendFile, readFile, unlink } from "fs/promises";
|
|
56517
|
-
import { tmpdir as tmpdir2 } from "os";
|
|
56518
|
-
import { join as join11 } from "path";
|
|
56519
|
-
|
|
56520
56574
|
// src/plugin-engine.ts
|
|
56521
56575
|
async function executeRequestPlugins(plugins, ctx, url2, headers, body) {
|
|
56522
56576
|
let currentUrl = url2;
|
|
@@ -56706,28 +56760,6 @@ function buildLogEvent(logMeta, targetUrl, proxyUrl, tsEnd, overrides) {
|
|
|
56706
56760
|
...overrides
|
|
56707
56761
|
};
|
|
56708
56762
|
}
|
|
56709
|
-
function createTempStreamCapturePath(requestId) {
|
|
56710
|
-
return join11(tmpdir2(), `local-router-stream-${requestId}-${Date.now()}.sse.raw`);
|
|
56711
|
-
}
|
|
56712
|
-
async function appendTempStreamCapture(filePath, chunk) {
|
|
56713
|
-
await appendFile(filePath, chunk);
|
|
56714
|
-
}
|
|
56715
|
-
async function flushTempCaptureToLogger(tempPath, requestId, dateStr, logger) {
|
|
56716
|
-
if (!logger)
|
|
56717
|
-
return null;
|
|
56718
|
-
try {
|
|
56719
|
-
const text2 = await readFile(tempPath, "utf-8").catch((err) => {
|
|
56720
|
-
if (err.code === "ENOENT")
|
|
56721
|
-
return "";
|
|
56722
|
-
throw err;
|
|
56723
|
-
});
|
|
56724
|
-
return logger.writeStreamFile(requestId, dateStr, text2);
|
|
56725
|
-
} finally {
|
|
56726
|
-
await unlink(tempPath).catch(() => {
|
|
56727
|
-
return;
|
|
56728
|
-
});
|
|
56729
|
-
}
|
|
56730
|
-
}
|
|
56731
56763
|
async function proxyRequest(c2, options) {
|
|
56732
56764
|
const { logMeta, plugins, pluginConfigs } = options;
|
|
56733
56765
|
const logger = getLogger();
|
|
@@ -56735,19 +56767,20 @@ async function proxyRequest(c2, options) {
|
|
|
56735
56767
|
const hasPlugins = plugins && plugins.length > 0;
|
|
56736
56768
|
let targetUrl = options.targetUrl;
|
|
56737
56769
|
let headers = buildUpstreamHeaders(c2.req.raw.headers, options.apiKey, options.authType);
|
|
56738
|
-
let
|
|
56770
|
+
let currentBody = options.body;
|
|
56771
|
+
const pluginCtx = Object.freeze({
|
|
56772
|
+
requestId: logMeta.requestId,
|
|
56773
|
+
provider: logMeta.provider,
|
|
56774
|
+
modelIn: logMeta.modelIn,
|
|
56775
|
+
modelOut: logMeta.modelOut,
|
|
56776
|
+
routeType: logMeta.routeType,
|
|
56777
|
+
isStream: logMeta.isStream
|
|
56778
|
+
});
|
|
56779
|
+
const wantsBodyLog = shouldLog && logger?.bodyPolicy !== "off";
|
|
56780
|
+
const requestBodySnapshot = wantsBodyLog ? JSON.parse(JSON.stringify(options.body)) : undefined;
|
|
56739
56781
|
const pluginLogOverrides = {};
|
|
56740
56782
|
if (hasPlugins) {
|
|
56741
|
-
const
|
|
56742
|
-
const ctx = {
|
|
56743
|
-
requestId: logMeta.requestId,
|
|
56744
|
-
provider: logMeta.provider,
|
|
56745
|
-
modelIn: logMeta.modelIn,
|
|
56746
|
-
modelOut: logMeta.modelOut,
|
|
56747
|
-
routeType: logMeta.routeType,
|
|
56748
|
-
isStream: logMeta.isStream
|
|
56749
|
-
};
|
|
56750
|
-
const result = await executeRequestPlugins(plugins, ctx, targetUrl, headers, bodyObj);
|
|
56783
|
+
const result = await executeRequestPlugins(plugins, pluginCtx, targetUrl, headers, currentBody);
|
|
56751
56784
|
if (pluginConfigs) {
|
|
56752
56785
|
pluginLogOverrides.plugins_request = pluginConfigs;
|
|
56753
56786
|
}
|
|
@@ -56756,20 +56789,20 @@ async function proxyRequest(c2, options) {
|
|
|
56756
56789
|
pluginLogOverrides.request_url_after_plugins = targetUrl;
|
|
56757
56790
|
}
|
|
56758
56791
|
headers = result.headers;
|
|
56759
|
-
|
|
56760
|
-
|
|
56761
|
-
bodyStr = newBodyStr;
|
|
56792
|
+
if (result.body !== currentBody) {
|
|
56793
|
+
currentBody = result.body;
|
|
56762
56794
|
pluginLogOverrides.request_body_after_plugins = result.body;
|
|
56763
56795
|
}
|
|
56764
56796
|
}
|
|
56765
|
-
const
|
|
56797
|
+
const wireBody = JSON.stringify(currentBody);
|
|
56798
|
+
const requestBody = requestBodySnapshot;
|
|
56766
56799
|
const proxy = options.proxy?.trim() ? options.proxy.trim() : undefined;
|
|
56767
56800
|
let upstreamRes;
|
|
56768
56801
|
try {
|
|
56769
56802
|
upstreamRes = await fetch(targetUrl, {
|
|
56770
56803
|
method: c2.req.method,
|
|
56771
56804
|
headers,
|
|
56772
|
-
body:
|
|
56805
|
+
body: wireBody,
|
|
56773
56806
|
...proxy ? { proxy } : {},
|
|
56774
56807
|
decompress: true
|
|
56775
56808
|
});
|
|
@@ -56799,15 +56832,7 @@ async function proxyRequest(c2, options) {
|
|
|
56799
56832
|
let sseHeaders = responseHeaders;
|
|
56800
56833
|
let sseTransform = null;
|
|
56801
56834
|
if (hasPlugins) {
|
|
56802
|
-
const
|
|
56803
|
-
requestId: logMeta.requestId,
|
|
56804
|
-
provider: logMeta.provider,
|
|
56805
|
-
modelIn: logMeta.modelIn,
|
|
56806
|
-
modelOut: logMeta.modelOut,
|
|
56807
|
-
routeType: logMeta.routeType,
|
|
56808
|
-
isStream: logMeta.isStream
|
|
56809
|
-
};
|
|
56810
|
-
const sseResult = await createSSEPluginTransform(plugins, ctx, upstreamRes.status, responseHeaders);
|
|
56835
|
+
const sseResult = await createSSEPluginTransform(plugins, pluginCtx, upstreamRes.status, responseHeaders);
|
|
56811
56836
|
sseStatus = sseResult.status;
|
|
56812
56837
|
sseHeaders = sseResult.headers;
|
|
56813
56838
|
sseTransform = sseResult.transform;
|
|
@@ -56816,47 +56841,71 @@ async function proxyRequest(c2, options) {
|
|
|
56816
56841
|
}
|
|
56817
56842
|
}
|
|
56818
56843
|
if (!shouldLog) {
|
|
56819
|
-
const
|
|
56820
|
-
return new Response(
|
|
56844
|
+
const outputBody = sseTransform ? upstreamRes.body.pipeThrough(sseTransform) : upstreamRes.body;
|
|
56845
|
+
return new Response(outputBody, {
|
|
56821
56846
|
status: sseStatus,
|
|
56822
56847
|
headers: sseHeaders
|
|
56823
56848
|
});
|
|
56824
56849
|
}
|
|
56825
|
-
const
|
|
56826
|
-
|
|
56827
|
-
|
|
56828
|
-
|
|
56829
|
-
|
|
56830
|
-
|
|
56831
|
-
|
|
56832
|
-
|
|
56833
|
-
|
|
56834
|
-
|
|
56835
|
-
|
|
56836
|
-
|
|
56837
|
-
|
|
56850
|
+
const capture = logger?.openStreamCapture(logMeta.requestId, dateStr) ?? null;
|
|
56851
|
+
let upstreamBytes = 0;
|
|
56852
|
+
let writeEventCalled = false;
|
|
56853
|
+
const finalizeAndWriteEvent = () => {
|
|
56854
|
+
if (writeEventCalled)
|
|
56855
|
+
return;
|
|
56856
|
+
writeEventCalled = true;
|
|
56857
|
+
const captureResult = capture?.finalize() ?? {
|
|
56858
|
+
bytesWritten: 0,
|
|
56859
|
+
truncated: false,
|
|
56860
|
+
filePath: null
|
|
56861
|
+
};
|
|
56862
|
+
logger?.writeEvent(buildLogEvent(logMeta, targetUrl, proxy, Date.now(), {
|
|
56863
|
+
upstream_status: sseStatus,
|
|
56864
|
+
content_type_res: contentTypeRes,
|
|
56865
|
+
response_headers: sseHeaders,
|
|
56866
|
+
stream_bytes: upstreamBytes,
|
|
56867
|
+
provider_request_id: providerRequestId,
|
|
56868
|
+
...captureResult.filePath != null && { stream_file: captureResult.filePath },
|
|
56869
|
+
...captureResult.bytesWritten > 0 && {
|
|
56870
|
+
stream_file_bytes: captureResult.bytesWritten
|
|
56871
|
+
},
|
|
56872
|
+
...captureResult.truncated && { stream_file_truncated: true },
|
|
56873
|
+
...requestBody !== undefined && { request_body: requestBody },
|
|
56874
|
+
...pluginLogOverrides
|
|
56875
|
+
}));
|
|
56876
|
+
};
|
|
56877
|
+
const upstreamReader = upstreamRes.body.getReader();
|
|
56878
|
+
const tappedStream = new ReadableStream({
|
|
56879
|
+
async pull(controller) {
|
|
56880
|
+
try {
|
|
56881
|
+
const { done, value } = await upstreamReader.read();
|
|
56882
|
+
if (done) {
|
|
56883
|
+
controller.close();
|
|
56884
|
+
finalizeAndWriteEvent();
|
|
56885
|
+
return;
|
|
56886
|
+
}
|
|
56887
|
+
upstreamBytes += value.byteLength;
|
|
56888
|
+
capture?.write(value);
|
|
56889
|
+
controller.enqueue(value);
|
|
56890
|
+
} catch (err) {
|
|
56891
|
+
finalizeAndWriteEvent();
|
|
56892
|
+
controller.error(err);
|
|
56893
|
+
}
|
|
56894
|
+
},
|
|
56895
|
+
cancel(reason) {
|
|
56896
|
+
try {
|
|
56897
|
+
upstreamReader.cancel(reason).catch(() => {
|
|
56898
|
+
return;
|
|
56899
|
+
});
|
|
56900
|
+
} finally {
|
|
56901
|
+
finalizeAndWriteEvent();
|
|
56838
56902
|
}
|
|
56839
|
-
streamFile = await flushTempCaptureToLogger(tempPath, logMeta.requestId, dateStr, logger);
|
|
56840
|
-
} catch (err) {
|
|
56841
|
-
await unlink(tempPath).catch(() => {
|
|
56842
|
-
return;
|
|
56843
|
-
});
|
|
56844
|
-
console.error("[logger] \u6D41\u5F0F\u65E5\u5FD7\u5904\u7406\u5931\u8D25:", err);
|
|
56845
|
-
} finally {
|
|
56846
|
-
logger?.writeEvent(buildLogEvent(logMeta, targetUrl, proxy, Date.now(), {
|
|
56847
|
-
upstream_status: sseStatus,
|
|
56848
|
-
content_type_res: contentTypeRes,
|
|
56849
|
-
response_headers: sseHeaders,
|
|
56850
|
-
stream_bytes: streamBytes,
|
|
56851
|
-
provider_request_id: providerRequestId,
|
|
56852
|
-
...streamFile != null && { stream_file: streamFile },
|
|
56853
|
-
...requestBody !== undefined && { request_body: requestBody },
|
|
56854
|
-
...pluginLogOverrides
|
|
56855
|
-
}));
|
|
56856
56903
|
}
|
|
56857
|
-
})
|
|
56858
|
-
|
|
56859
|
-
|
|
56904
|
+
});
|
|
56905
|
+
let stream = tappedStream;
|
|
56906
|
+
if (sseTransform)
|
|
56907
|
+
stream = stream.pipeThrough(sseTransform);
|
|
56908
|
+
return new Response(stream, {
|
|
56860
56909
|
status: sseStatus,
|
|
56861
56910
|
headers: sseHeaders
|
|
56862
56911
|
});
|
|
@@ -56865,15 +56914,7 @@ async function proxyRequest(c2, options) {
|
|
|
56865
56914
|
let responseStatus = upstreamRes.status;
|
|
56866
56915
|
let finalResponseHeaders = responseHeaders;
|
|
56867
56916
|
if (hasPlugins) {
|
|
56868
|
-
const
|
|
56869
|
-
requestId: logMeta.requestId,
|
|
56870
|
-
provider: logMeta.provider,
|
|
56871
|
-
modelIn: logMeta.modelIn,
|
|
56872
|
-
modelOut: logMeta.modelOut,
|
|
56873
|
-
routeType: logMeta.routeType,
|
|
56874
|
-
isStream: logMeta.isStream
|
|
56875
|
-
};
|
|
56876
|
-
const result = await executeJsonResponsePlugins(plugins, ctx, upstreamRes.status, responseHeaders, responseText);
|
|
56917
|
+
const result = await executeJsonResponsePlugins(plugins, pluginCtx, upstreamRes.status, responseHeaders, responseText);
|
|
56877
56918
|
if (pluginConfigs) {
|
|
56878
56919
|
pluginLogOverrides.plugins_response = pluginConfigs;
|
|
56879
56920
|
}
|
|
@@ -56950,8 +56991,10 @@ function createModelRoutingHandler(options) {
|
|
|
56950
56991
|
return c2.json({ error: `provider "${target.provider}" \u672A\u5728\u914D\u7F6E\u4E2D\u5B9A\u4E49` }, 500);
|
|
56951
56992
|
}
|
|
56952
56993
|
payload.model = target.model;
|
|
56953
|
-
const body = JSON.stringify(payload);
|
|
56954
56994
|
const targetUrl = buildTargetUrl(provider.base);
|
|
56995
|
+
const contentLengthHeader = c2.req.header("content-length");
|
|
56996
|
+
const parsedContentLength = contentLengthHeader ? Number(contentLengthHeader) : NaN;
|
|
56997
|
+
const requestBytes = Number.isInteger(parsedContentLength) && parsedContentLength >= 0 ? parsedContentLength : Buffer.byteLength(JSON.stringify(payload), "utf-8");
|
|
56955
56998
|
const logMeta = {
|
|
56956
56999
|
requestId: crypto.randomUUID(),
|
|
56957
57000
|
tsStart: Date.now(),
|
|
@@ -56965,7 +57008,7 @@ function createModelRoutingHandler(options) {
|
|
|
56965
57008
|
path: c2.req.path,
|
|
56966
57009
|
contentTypeReq: c2.req.header("content-type") ?? null,
|
|
56967
57010
|
userAgent: c2.req.header("user-agent") ?? null,
|
|
56968
|
-
requestBytes
|
|
57011
|
+
requestBytes,
|
|
56969
57012
|
requestHeaders: collectHeaders(c2.req.raw.headers)
|
|
56970
57013
|
};
|
|
56971
57014
|
const plugins = pluginManager?.getPlugins(target.provider) ?? [];
|
|
@@ -56975,7 +57018,7 @@ function createModelRoutingHandler(options) {
|
|
|
56975
57018
|
apiKey: provider.apiKey,
|
|
56976
57019
|
proxy: provider.proxy,
|
|
56977
57020
|
authType,
|
|
56978
|
-
body,
|
|
57021
|
+
body: payload,
|
|
56979
57022
|
logMeta,
|
|
56980
57023
|
plugins: plugins.length > 0 ? plugins : undefined,
|
|
56981
57024
|
pluginConfigs: pluginConfigs.length > 0 ? pluginConfigs.map((lp) => ({
|
|
@@ -57904,24 +57947,24 @@ async function startServer(options) {
|
|
|
57904
57947
|
}
|
|
57905
57948
|
|
|
57906
57949
|
// src/cli/runtime.ts
|
|
57907
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync6, rmSync, writeFileSync as
|
|
57950
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync6, rmSync, writeFileSync as writeFileSync4 } from "fs";
|
|
57908
57951
|
import { homedir as homedir2 } from "os";
|
|
57909
|
-
import { join as
|
|
57952
|
+
import { join as join11, resolve as resolve7 } from "path";
|
|
57910
57953
|
function getRuntimeDirs() {
|
|
57911
57954
|
const override = process.env.LOCAL_ROUTER_RUNTIME_DIR;
|
|
57912
|
-
const root2 = override?.trim() ? override.trim() :
|
|
57955
|
+
const root2 = override?.trim() ? override.trim() : join11(homedir2(), ".local-router");
|
|
57913
57956
|
return {
|
|
57914
57957
|
root: root2,
|
|
57915
|
-
run:
|
|
57916
|
-
logs:
|
|
57958
|
+
run: join11(root2, "run"),
|
|
57959
|
+
logs: join11(root2, "logs")
|
|
57917
57960
|
};
|
|
57918
57961
|
}
|
|
57919
57962
|
function getRuntimeFiles() {
|
|
57920
57963
|
const dirs = getRuntimeDirs();
|
|
57921
57964
|
return {
|
|
57922
|
-
pid:
|
|
57923
|
-
state:
|
|
57924
|
-
daemonLog:
|
|
57965
|
+
pid: join11(dirs.run, "local-router.pid"),
|
|
57966
|
+
state: join11(dirs.run, "status.json"),
|
|
57967
|
+
daemonLog: join11(dirs.logs, "daemon.log")
|
|
57925
57968
|
};
|
|
57926
57969
|
}
|
|
57927
57970
|
function ensureRuntimeDirs() {
|
|
@@ -57933,9 +57976,9 @@ function ensureRuntimeDirs() {
|
|
|
57933
57976
|
function writeRuntimeState(state) {
|
|
57934
57977
|
ensureRuntimeDirs();
|
|
57935
57978
|
const files = getRuntimeFiles();
|
|
57936
|
-
|
|
57979
|
+
writeFileSync4(files.pid, `${state.pid}
|
|
57937
57980
|
`, "utf-8");
|
|
57938
|
-
|
|
57981
|
+
writeFileSync4(files.state, JSON.stringify(state, null, 2), "utf-8");
|
|
57939
57982
|
}
|
|
57940
57983
|
function readRuntimeState() {
|
|
57941
57984
|
const files = getRuntimeFiles();
|
|
@@ -58094,8 +58137,8 @@ async function startDaemon(flags) {
|
|
|
58094
58137
|
}
|
|
58095
58138
|
ensureRuntimeDirs();
|
|
58096
58139
|
const files = getRuntimeFiles();
|
|
58097
|
-
const stdoutFd =
|
|
58098
|
-
const stderrFd =
|
|
58140
|
+
const stdoutFd = openSync3(files.daemonLog, "a");
|
|
58141
|
+
const stderrFd = openSync3(files.daemonLog, "a");
|
|
58099
58142
|
const childArgs = [process.argv[1] ?? "src/cli.ts", "__run-server", "--mode", "daemon"];
|
|
58100
58143
|
if (flags.config) {
|
|
58101
58144
|
childArgs.push("--config", resolveConfigArgPath(flags.config));
|
|
@@ -58116,8 +58159,8 @@ async function startDaemon(flags) {
|
|
|
58116
58159
|
stderr: stderrFd,
|
|
58117
58160
|
detached: true
|
|
58118
58161
|
});
|
|
58119
|
-
|
|
58120
|
-
|
|
58162
|
+
closeSync3(stdoutFd);
|
|
58163
|
+
closeSync3(stderrFd);
|
|
58121
58164
|
child.unref();
|
|
58122
58165
|
for (let i = 0;i < 24; i += 1) {
|
|
58123
58166
|
await sleep(250);
|
package/dist/entry.js
CHANGED
|
@@ -53899,7 +53899,15 @@ function subscribeLogEvents(subscriber) {
|
|
|
53899
53899
|
}
|
|
53900
53900
|
|
|
53901
53901
|
// src/logger.ts
|
|
53902
|
-
import {
|
|
53902
|
+
import {
|
|
53903
|
+
appendFileSync,
|
|
53904
|
+
closeSync as closeSync2,
|
|
53905
|
+
existsSync as existsSync7,
|
|
53906
|
+
mkdirSync as mkdirSync3,
|
|
53907
|
+
openSync as openSync2,
|
|
53908
|
+
statSync as statSync2,
|
|
53909
|
+
writeSync
|
|
53910
|
+
} from "fs";
|
|
53903
53911
|
import { join as join8 } from "path";
|
|
53904
53912
|
class Logger {
|
|
53905
53913
|
baseDir;
|
|
@@ -53963,22 +53971,73 @@ class Logger {
|
|
|
53963
53971
|
console.error("[logger] \u4E8B\u4EF6\u65E5\u5FD7\u5199\u5165\u5931\u8D25:", err);
|
|
53964
53972
|
}
|
|
53965
53973
|
}
|
|
53966
|
-
|
|
53967
|
-
if (!this._enabled || !this._streamsEnabled)
|
|
53968
|
-
return
|
|
53974
|
+
openStreamCapture(requestId, dateStr) {
|
|
53975
|
+
if (!this._enabled || !this._streamsEnabled) {
|
|
53976
|
+
return makeNoopStreamCaptureHandle();
|
|
53977
|
+
}
|
|
53978
|
+
const maxStreamBytes = this.maxStreamBytes;
|
|
53979
|
+
const truncationMarker = Buffer.from(`
|
|
53980
|
+
[TRUNCATED]`);
|
|
53981
|
+
let filePath;
|
|
53982
|
+
let fd;
|
|
53969
53983
|
try {
|
|
53970
53984
|
const dir = this.ensureStreamDateDir(dateStr);
|
|
53971
|
-
|
|
53972
|
-
|
|
53973
|
-
[TRUNCATED]` : content;
|
|
53974
|
-
writeFileSync3(filePath, toWrite);
|
|
53975
|
-
return filePath;
|
|
53985
|
+
filePath = join8(dir, `${requestId}.sse.raw`);
|
|
53986
|
+
fd = openSync2(filePath, "a");
|
|
53976
53987
|
} catch (err) {
|
|
53977
|
-
console.error("[logger] \u6D41\u5F0F\u65E5\u5FD7\
|
|
53978
|
-
return
|
|
53988
|
+
console.error("[logger] \u6D41\u5F0F\u65E5\u5FD7\u6253\u5F00\u5931\u8D25:", err);
|
|
53989
|
+
return makeNoopStreamCaptureHandle();
|
|
53979
53990
|
}
|
|
53991
|
+
let bytes = 0;
|
|
53992
|
+
let truncated = false;
|
|
53993
|
+
let finalized = false;
|
|
53994
|
+
return {
|
|
53995
|
+
filePath,
|
|
53996
|
+
write(chunk) {
|
|
53997
|
+
if (finalized || truncated || fd == null)
|
|
53998
|
+
return;
|
|
53999
|
+
try {
|
|
54000
|
+
if (bytes + chunk.byteLength > maxStreamBytes) {
|
|
54001
|
+
const remaining = Math.max(0, maxStreamBytes - bytes);
|
|
54002
|
+
if (remaining > 0) {
|
|
54003
|
+
writeSync(fd, chunk.subarray(0, remaining));
|
|
54004
|
+
bytes += remaining;
|
|
54005
|
+
}
|
|
54006
|
+
writeSync(fd, truncationMarker);
|
|
54007
|
+
truncated = true;
|
|
54008
|
+
return;
|
|
54009
|
+
}
|
|
54010
|
+
writeSync(fd, chunk);
|
|
54011
|
+
bytes += chunk.byteLength;
|
|
54012
|
+
} catch (err) {
|
|
54013
|
+
console.error("[logger] \u6D41\u5F0F\u65E5\u5FD7\u5199\u5165\u5931\u8D25:", err);
|
|
54014
|
+
truncated = true;
|
|
54015
|
+
}
|
|
54016
|
+
},
|
|
54017
|
+
finalize() {
|
|
54018
|
+
if (finalized)
|
|
54019
|
+
return { bytesWritten: bytes, truncated, filePath };
|
|
54020
|
+
finalized = true;
|
|
54021
|
+
if (fd != null) {
|
|
54022
|
+
try {
|
|
54023
|
+
closeSync2(fd);
|
|
54024
|
+
} catch {}
|
|
54025
|
+
fd = null;
|
|
54026
|
+
}
|
|
54027
|
+
return { bytesWritten: bytes, truncated, filePath };
|
|
54028
|
+
}
|
|
54029
|
+
};
|
|
53980
54030
|
}
|
|
53981
54031
|
}
|
|
54032
|
+
function makeNoopStreamCaptureHandle() {
|
|
54033
|
+
return {
|
|
54034
|
+
filePath: null,
|
|
54035
|
+
write() {},
|
|
54036
|
+
finalize() {
|
|
54037
|
+
return { bytesWritten: 0, truncated: false, filePath: null };
|
|
54038
|
+
}
|
|
54039
|
+
};
|
|
54040
|
+
}
|
|
53982
54041
|
var instance = null;
|
|
53983
54042
|
function initLogger(baseDir, config2) {
|
|
53984
54043
|
instance = new Logger(baseDir, config2);
|
|
@@ -55370,11 +55429,6 @@ class PluginManager {
|
|
|
55370
55429
|
}
|
|
55371
55430
|
}
|
|
55372
55431
|
|
|
55373
|
-
// src/proxy.ts
|
|
55374
|
-
import { appendFile, readFile, unlink } from "fs/promises";
|
|
55375
|
-
import { tmpdir as tmpdir2 } from "os";
|
|
55376
|
-
import { join as join10 } from "path";
|
|
55377
|
-
|
|
55378
55432
|
// src/plugin-engine.ts
|
|
55379
55433
|
async function executeRequestPlugins(plugins, ctx, url2, headers, body) {
|
|
55380
55434
|
let currentUrl = url2;
|
|
@@ -55564,28 +55618,6 @@ function buildLogEvent(logMeta, targetUrl, proxyUrl, tsEnd, overrides) {
|
|
|
55564
55618
|
...overrides
|
|
55565
55619
|
};
|
|
55566
55620
|
}
|
|
55567
|
-
function createTempStreamCapturePath(requestId) {
|
|
55568
|
-
return join10(tmpdir2(), `local-router-stream-${requestId}-${Date.now()}.sse.raw`);
|
|
55569
|
-
}
|
|
55570
|
-
async function appendTempStreamCapture(filePath, chunk) {
|
|
55571
|
-
await appendFile(filePath, chunk);
|
|
55572
|
-
}
|
|
55573
|
-
async function flushTempCaptureToLogger(tempPath, requestId, dateStr, logger) {
|
|
55574
|
-
if (!logger)
|
|
55575
|
-
return null;
|
|
55576
|
-
try {
|
|
55577
|
-
const text2 = await readFile(tempPath, "utf-8").catch((err) => {
|
|
55578
|
-
if (err.code === "ENOENT")
|
|
55579
|
-
return "";
|
|
55580
|
-
throw err;
|
|
55581
|
-
});
|
|
55582
|
-
return logger.writeStreamFile(requestId, dateStr, text2);
|
|
55583
|
-
} finally {
|
|
55584
|
-
await unlink(tempPath).catch(() => {
|
|
55585
|
-
return;
|
|
55586
|
-
});
|
|
55587
|
-
}
|
|
55588
|
-
}
|
|
55589
55621
|
async function proxyRequest(c2, options) {
|
|
55590
55622
|
const { logMeta, plugins, pluginConfigs } = options;
|
|
55591
55623
|
const logger = getLogger();
|
|
@@ -55593,19 +55625,20 @@ async function proxyRequest(c2, options) {
|
|
|
55593
55625
|
const hasPlugins = plugins && plugins.length > 0;
|
|
55594
55626
|
let targetUrl = options.targetUrl;
|
|
55595
55627
|
let headers = buildUpstreamHeaders(c2.req.raw.headers, options.apiKey, options.authType);
|
|
55596
|
-
let
|
|
55628
|
+
let currentBody = options.body;
|
|
55629
|
+
const pluginCtx = Object.freeze({
|
|
55630
|
+
requestId: logMeta.requestId,
|
|
55631
|
+
provider: logMeta.provider,
|
|
55632
|
+
modelIn: logMeta.modelIn,
|
|
55633
|
+
modelOut: logMeta.modelOut,
|
|
55634
|
+
routeType: logMeta.routeType,
|
|
55635
|
+
isStream: logMeta.isStream
|
|
55636
|
+
});
|
|
55637
|
+
const wantsBodyLog = shouldLog && logger?.bodyPolicy !== "off";
|
|
55638
|
+
const requestBodySnapshot = wantsBodyLog ? JSON.parse(JSON.stringify(options.body)) : undefined;
|
|
55597
55639
|
const pluginLogOverrides = {};
|
|
55598
55640
|
if (hasPlugins) {
|
|
55599
|
-
const
|
|
55600
|
-
const ctx = {
|
|
55601
|
-
requestId: logMeta.requestId,
|
|
55602
|
-
provider: logMeta.provider,
|
|
55603
|
-
modelIn: logMeta.modelIn,
|
|
55604
|
-
modelOut: logMeta.modelOut,
|
|
55605
|
-
routeType: logMeta.routeType,
|
|
55606
|
-
isStream: logMeta.isStream
|
|
55607
|
-
};
|
|
55608
|
-
const result = await executeRequestPlugins(plugins, ctx, targetUrl, headers, bodyObj);
|
|
55641
|
+
const result = await executeRequestPlugins(plugins, pluginCtx, targetUrl, headers, currentBody);
|
|
55609
55642
|
if (pluginConfigs) {
|
|
55610
55643
|
pluginLogOverrides.plugins_request = pluginConfigs;
|
|
55611
55644
|
}
|
|
@@ -55614,20 +55647,20 @@ async function proxyRequest(c2, options) {
|
|
|
55614
55647
|
pluginLogOverrides.request_url_after_plugins = targetUrl;
|
|
55615
55648
|
}
|
|
55616
55649
|
headers = result.headers;
|
|
55617
|
-
|
|
55618
|
-
|
|
55619
|
-
bodyStr = newBodyStr;
|
|
55650
|
+
if (result.body !== currentBody) {
|
|
55651
|
+
currentBody = result.body;
|
|
55620
55652
|
pluginLogOverrides.request_body_after_plugins = result.body;
|
|
55621
55653
|
}
|
|
55622
55654
|
}
|
|
55623
|
-
const
|
|
55655
|
+
const wireBody = JSON.stringify(currentBody);
|
|
55656
|
+
const requestBody = requestBodySnapshot;
|
|
55624
55657
|
const proxy = options.proxy?.trim() ? options.proxy.trim() : undefined;
|
|
55625
55658
|
let upstreamRes;
|
|
55626
55659
|
try {
|
|
55627
55660
|
upstreamRes = await fetch(targetUrl, {
|
|
55628
55661
|
method: c2.req.method,
|
|
55629
55662
|
headers,
|
|
55630
|
-
body:
|
|
55663
|
+
body: wireBody,
|
|
55631
55664
|
...proxy ? { proxy } : {},
|
|
55632
55665
|
decompress: true
|
|
55633
55666
|
});
|
|
@@ -55657,15 +55690,7 @@ async function proxyRequest(c2, options) {
|
|
|
55657
55690
|
let sseHeaders = responseHeaders;
|
|
55658
55691
|
let sseTransform = null;
|
|
55659
55692
|
if (hasPlugins) {
|
|
55660
|
-
const
|
|
55661
|
-
requestId: logMeta.requestId,
|
|
55662
|
-
provider: logMeta.provider,
|
|
55663
|
-
modelIn: logMeta.modelIn,
|
|
55664
|
-
modelOut: logMeta.modelOut,
|
|
55665
|
-
routeType: logMeta.routeType,
|
|
55666
|
-
isStream: logMeta.isStream
|
|
55667
|
-
};
|
|
55668
|
-
const sseResult = await createSSEPluginTransform(plugins, ctx, upstreamRes.status, responseHeaders);
|
|
55693
|
+
const sseResult = await createSSEPluginTransform(plugins, pluginCtx, upstreamRes.status, responseHeaders);
|
|
55669
55694
|
sseStatus = sseResult.status;
|
|
55670
55695
|
sseHeaders = sseResult.headers;
|
|
55671
55696
|
sseTransform = sseResult.transform;
|
|
@@ -55674,47 +55699,71 @@ async function proxyRequest(c2, options) {
|
|
|
55674
55699
|
}
|
|
55675
55700
|
}
|
|
55676
55701
|
if (!shouldLog) {
|
|
55677
|
-
const
|
|
55678
|
-
return new Response(
|
|
55702
|
+
const outputBody = sseTransform ? upstreamRes.body.pipeThrough(sseTransform) : upstreamRes.body;
|
|
55703
|
+
return new Response(outputBody, {
|
|
55679
55704
|
status: sseStatus,
|
|
55680
55705
|
headers: sseHeaders
|
|
55681
55706
|
});
|
|
55682
55707
|
}
|
|
55683
|
-
const
|
|
55684
|
-
|
|
55685
|
-
|
|
55686
|
-
|
|
55687
|
-
|
|
55688
|
-
|
|
55689
|
-
|
|
55690
|
-
|
|
55691
|
-
|
|
55692
|
-
|
|
55693
|
-
|
|
55694
|
-
|
|
55695
|
-
|
|
55708
|
+
const capture = logger?.openStreamCapture(logMeta.requestId, dateStr) ?? null;
|
|
55709
|
+
let upstreamBytes = 0;
|
|
55710
|
+
let writeEventCalled = false;
|
|
55711
|
+
const finalizeAndWriteEvent = () => {
|
|
55712
|
+
if (writeEventCalled)
|
|
55713
|
+
return;
|
|
55714
|
+
writeEventCalled = true;
|
|
55715
|
+
const captureResult = capture?.finalize() ?? {
|
|
55716
|
+
bytesWritten: 0,
|
|
55717
|
+
truncated: false,
|
|
55718
|
+
filePath: null
|
|
55719
|
+
};
|
|
55720
|
+
logger?.writeEvent(buildLogEvent(logMeta, targetUrl, proxy, Date.now(), {
|
|
55721
|
+
upstream_status: sseStatus,
|
|
55722
|
+
content_type_res: contentTypeRes,
|
|
55723
|
+
response_headers: sseHeaders,
|
|
55724
|
+
stream_bytes: upstreamBytes,
|
|
55725
|
+
provider_request_id: providerRequestId,
|
|
55726
|
+
...captureResult.filePath != null && { stream_file: captureResult.filePath },
|
|
55727
|
+
...captureResult.bytesWritten > 0 && {
|
|
55728
|
+
stream_file_bytes: captureResult.bytesWritten
|
|
55729
|
+
},
|
|
55730
|
+
...captureResult.truncated && { stream_file_truncated: true },
|
|
55731
|
+
...requestBody !== undefined && { request_body: requestBody },
|
|
55732
|
+
...pluginLogOverrides
|
|
55733
|
+
}));
|
|
55734
|
+
};
|
|
55735
|
+
const upstreamReader = upstreamRes.body.getReader();
|
|
55736
|
+
const tappedStream = new ReadableStream({
|
|
55737
|
+
async pull(controller) {
|
|
55738
|
+
try {
|
|
55739
|
+
const { done, value } = await upstreamReader.read();
|
|
55740
|
+
if (done) {
|
|
55741
|
+
controller.close();
|
|
55742
|
+
finalizeAndWriteEvent();
|
|
55743
|
+
return;
|
|
55744
|
+
}
|
|
55745
|
+
upstreamBytes += value.byteLength;
|
|
55746
|
+
capture?.write(value);
|
|
55747
|
+
controller.enqueue(value);
|
|
55748
|
+
} catch (err) {
|
|
55749
|
+
finalizeAndWriteEvent();
|
|
55750
|
+
controller.error(err);
|
|
55751
|
+
}
|
|
55752
|
+
},
|
|
55753
|
+
cancel(reason) {
|
|
55754
|
+
try {
|
|
55755
|
+
upstreamReader.cancel(reason).catch(() => {
|
|
55756
|
+
return;
|
|
55757
|
+
});
|
|
55758
|
+
} finally {
|
|
55759
|
+
finalizeAndWriteEvent();
|
|
55696
55760
|
}
|
|
55697
|
-
streamFile = await flushTempCaptureToLogger(tempPath, logMeta.requestId, dateStr, logger);
|
|
55698
|
-
} catch (err) {
|
|
55699
|
-
await unlink(tempPath).catch(() => {
|
|
55700
|
-
return;
|
|
55701
|
-
});
|
|
55702
|
-
console.error("[logger] \u6D41\u5F0F\u65E5\u5FD7\u5904\u7406\u5931\u8D25:", err);
|
|
55703
|
-
} finally {
|
|
55704
|
-
logger?.writeEvent(buildLogEvent(logMeta, targetUrl, proxy, Date.now(), {
|
|
55705
|
-
upstream_status: sseStatus,
|
|
55706
|
-
content_type_res: contentTypeRes,
|
|
55707
|
-
response_headers: sseHeaders,
|
|
55708
|
-
stream_bytes: streamBytes,
|
|
55709
|
-
provider_request_id: providerRequestId,
|
|
55710
|
-
...streamFile != null && { stream_file: streamFile },
|
|
55711
|
-
...requestBody !== undefined && { request_body: requestBody },
|
|
55712
|
-
...pluginLogOverrides
|
|
55713
|
-
}));
|
|
55714
55761
|
}
|
|
55715
|
-
})
|
|
55716
|
-
|
|
55717
|
-
|
|
55762
|
+
});
|
|
55763
|
+
let stream = tappedStream;
|
|
55764
|
+
if (sseTransform)
|
|
55765
|
+
stream = stream.pipeThrough(sseTransform);
|
|
55766
|
+
return new Response(stream, {
|
|
55718
55767
|
status: sseStatus,
|
|
55719
55768
|
headers: sseHeaders
|
|
55720
55769
|
});
|
|
@@ -55723,15 +55772,7 @@ async function proxyRequest(c2, options) {
|
|
|
55723
55772
|
let responseStatus = upstreamRes.status;
|
|
55724
55773
|
let finalResponseHeaders = responseHeaders;
|
|
55725
55774
|
if (hasPlugins) {
|
|
55726
|
-
const
|
|
55727
|
-
requestId: logMeta.requestId,
|
|
55728
|
-
provider: logMeta.provider,
|
|
55729
|
-
modelIn: logMeta.modelIn,
|
|
55730
|
-
modelOut: logMeta.modelOut,
|
|
55731
|
-
routeType: logMeta.routeType,
|
|
55732
|
-
isStream: logMeta.isStream
|
|
55733
|
-
};
|
|
55734
|
-
const result = await executeJsonResponsePlugins(plugins, ctx, upstreamRes.status, responseHeaders, responseText);
|
|
55775
|
+
const result = await executeJsonResponsePlugins(plugins, pluginCtx, upstreamRes.status, responseHeaders, responseText);
|
|
55735
55776
|
if (pluginConfigs) {
|
|
55736
55777
|
pluginLogOverrides.plugins_response = pluginConfigs;
|
|
55737
55778
|
}
|
|
@@ -55808,8 +55849,10 @@ function createModelRoutingHandler(options) {
|
|
|
55808
55849
|
return c2.json({ error: `provider "${target.provider}" \u672A\u5728\u914D\u7F6E\u4E2D\u5B9A\u4E49` }, 500);
|
|
55809
55850
|
}
|
|
55810
55851
|
payload.model = target.model;
|
|
55811
|
-
const body = JSON.stringify(payload);
|
|
55812
55852
|
const targetUrl = buildTargetUrl(provider.base);
|
|
55853
|
+
const contentLengthHeader = c2.req.header("content-length");
|
|
55854
|
+
const parsedContentLength = contentLengthHeader ? Number(contentLengthHeader) : NaN;
|
|
55855
|
+
const requestBytes = Number.isInteger(parsedContentLength) && parsedContentLength >= 0 ? parsedContentLength : Buffer.byteLength(JSON.stringify(payload), "utf-8");
|
|
55813
55856
|
const logMeta = {
|
|
55814
55857
|
requestId: crypto.randomUUID(),
|
|
55815
55858
|
tsStart: Date.now(),
|
|
@@ -55823,7 +55866,7 @@ function createModelRoutingHandler(options) {
|
|
|
55823
55866
|
path: c2.req.path,
|
|
55824
55867
|
contentTypeReq: c2.req.header("content-type") ?? null,
|
|
55825
55868
|
userAgent: c2.req.header("user-agent") ?? null,
|
|
55826
|
-
requestBytes
|
|
55869
|
+
requestBytes,
|
|
55827
55870
|
requestHeaders: collectHeaders(c2.req.raw.headers)
|
|
55828
55871
|
};
|
|
55829
55872
|
const plugins = pluginManager?.getPlugins(target.provider) ?? [];
|
|
@@ -55833,7 +55876,7 @@ function createModelRoutingHandler(options) {
|
|
|
55833
55876
|
apiKey: provider.apiKey,
|
|
55834
55877
|
proxy: provider.proxy,
|
|
55835
55878
|
authType,
|
|
55836
|
-
body,
|
|
55879
|
+
body: payload,
|
|
55837
55880
|
logMeta,
|
|
55838
55881
|
plugins: plugins.length > 0 ? plugins : undefined,
|
|
55839
55882
|
pluginConfigs: pluginConfigs.length > 0 ? pluginConfigs.map((lp) => ({
|