@lakphy/local-router 0.5.5 → 0.5.7
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/config.schema.json +2 -2
- package/dist/cli.js +1239 -693
- package/dist/entry.js +1081 -639
- package/dist/web/assets/index-D1WTE7QU.js +192 -0
- package/dist/web/assets/index-DrH6dT5r.css +2 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-BxjdLPIh.js +0 -190
- package/dist/web/assets/index-Dc2P7nS-.css +0 -2
package/dist/cli.js
CHANGED
|
@@ -9179,257 +9179,6 @@ var init_output = __esm(() => {
|
|
|
9179
9179
|
init_global_flags();
|
|
9180
9180
|
});
|
|
9181
9181
|
|
|
9182
|
-
// src/cli/runtime.ts
|
|
9183
|
-
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync3 } from "fs";
|
|
9184
|
-
import { homedir as homedir2 } from "os";
|
|
9185
|
-
import { join as join3, resolve as resolve2 } from "path";
|
|
9186
|
-
function getRuntimeDirs() {
|
|
9187
|
-
const override = process.env.LOCAL_ROUTER_RUNTIME_DIR;
|
|
9188
|
-
const root = override?.trim() ? override.trim() : join3(homedir2(), ".local-router");
|
|
9189
|
-
return {
|
|
9190
|
-
root,
|
|
9191
|
-
run: join3(root, "run"),
|
|
9192
|
-
logs: join3(root, "logs")
|
|
9193
|
-
};
|
|
9194
|
-
}
|
|
9195
|
-
function getRuntimeFiles() {
|
|
9196
|
-
const dirs = getRuntimeDirs();
|
|
9197
|
-
return {
|
|
9198
|
-
pid: join3(dirs.run, "local-router.pid"),
|
|
9199
|
-
state: join3(dirs.run, "status.json"),
|
|
9200
|
-
daemonLog: join3(dirs.logs, "daemon.log")
|
|
9201
|
-
};
|
|
9202
|
-
}
|
|
9203
|
-
function ensureRuntimeDirs() {
|
|
9204
|
-
const dirs = getRuntimeDirs();
|
|
9205
|
-
mkdirSync3(dirs.root, { recursive: true });
|
|
9206
|
-
mkdirSync3(dirs.run, { recursive: true });
|
|
9207
|
-
mkdirSync3(dirs.logs, { recursive: true });
|
|
9208
|
-
}
|
|
9209
|
-
function writeRuntimeState(state) {
|
|
9210
|
-
ensureRuntimeDirs();
|
|
9211
|
-
const files = getRuntimeFiles();
|
|
9212
|
-
writeFileSync3(files.pid, `${state.pid}
|
|
9213
|
-
`, "utf-8");
|
|
9214
|
-
writeFileSync3(files.state, JSON.stringify(state, null, 2), "utf-8");
|
|
9215
|
-
}
|
|
9216
|
-
function readRuntimeState() {
|
|
9217
|
-
const files = getRuntimeFiles();
|
|
9218
|
-
if (!existsSync2(files.state)) {
|
|
9219
|
-
return null;
|
|
9220
|
-
}
|
|
9221
|
-
try {
|
|
9222
|
-
return JSON.parse(readFileSync4(files.state, "utf-8"));
|
|
9223
|
-
} catch {
|
|
9224
|
-
return null;
|
|
9225
|
-
}
|
|
9226
|
-
}
|
|
9227
|
-
function clearRuntimeFiles() {
|
|
9228
|
-
const files = getRuntimeFiles();
|
|
9229
|
-
rmSync(files.pid, { force: true });
|
|
9230
|
-
rmSync(files.state, { force: true });
|
|
9231
|
-
}
|
|
9232
|
-
function resolveConfigArgPath(pathValue) {
|
|
9233
|
-
return resolve2(pathValue);
|
|
9234
|
-
}
|
|
9235
|
-
var init_runtime = () => {};
|
|
9236
|
-
|
|
9237
|
-
// src/cli/autostart.ts
|
|
9238
|
-
import { execSync } from "child_process";
|
|
9239
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
9240
|
-
import { homedir as homedir3, platform } from "os";
|
|
9241
|
-
import { dirname as dirname2, join as join4 } from "path";
|
|
9242
|
-
function getDaemonLogPath() {
|
|
9243
|
-
return getRuntimeDirs().logs + "/daemon.log";
|
|
9244
|
-
}
|
|
9245
|
-
function getLaunchAgentPath() {
|
|
9246
|
-
return join4(homedir3(), "Library", "LaunchAgents", `${LABEL}.plist`);
|
|
9247
|
-
}
|
|
9248
|
-
function buildPlist(opts) {
|
|
9249
|
-
const logPath = getDaemonLogPath();
|
|
9250
|
-
const args = [opts.execPath, ...opts.args].map((a) => ` <string>${escapeXml(a)}</string>`).join(`
|
|
9251
|
-
`);
|
|
9252
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
9253
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
9254
|
-
<plist version="1.0">
|
|
9255
|
-
<dict>
|
|
9256
|
-
<key>Label</key>
|
|
9257
|
-
<string>${escapeXml(opts.label)}</string>
|
|
9258
|
-
<key>ProgramArguments</key>
|
|
9259
|
-
<array>
|
|
9260
|
-
${args}
|
|
9261
|
-
</array>
|
|
9262
|
-
<key>RunAtLoad</key>
|
|
9263
|
-
<true/>
|
|
9264
|
-
<key>KeepAlive</key>
|
|
9265
|
-
<false/>
|
|
9266
|
-
<key>StandardOutPath</key>
|
|
9267
|
-
<string>${escapeXml(logPath)}</string>
|
|
9268
|
-
<key>StandardErrorPath</key>
|
|
9269
|
-
<string>${escapeXml(logPath)}</string>
|
|
9270
|
-
</dict>
|
|
9271
|
-
</plist>
|
|
9272
|
-
`;
|
|
9273
|
-
}
|
|
9274
|
-
function escapeXml(s) {
|
|
9275
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
9276
|
-
}
|
|
9277
|
-
function createMacosManager() {
|
|
9278
|
-
const plistPath = getLaunchAgentPath();
|
|
9279
|
-
return {
|
|
9280
|
-
platform: "macos",
|
|
9281
|
-
async isInstalled() {
|
|
9282
|
-
return existsSync3(plistPath);
|
|
9283
|
-
},
|
|
9284
|
-
async install(opts) {
|
|
9285
|
-
const dir = dirname2(plistPath);
|
|
9286
|
-
if (!existsSync3(dir))
|
|
9287
|
-
mkdirSync4(dir, { recursive: true });
|
|
9288
|
-
writeFileSync4(plistPath, buildPlist(opts), "utf-8");
|
|
9289
|
-
try {
|
|
9290
|
-
execSync(`launchctl bootout gui/$(id -u) ${plistPath} 2>/dev/null`, { stdio: "ignore" });
|
|
9291
|
-
} catch {}
|
|
9292
|
-
execSync(`launchctl bootstrap gui/$(id -u) ${plistPath}`, { stdio: "ignore" });
|
|
9293
|
-
},
|
|
9294
|
-
async uninstall() {
|
|
9295
|
-
if (!existsSync3(plistPath))
|
|
9296
|
-
return;
|
|
9297
|
-
try {
|
|
9298
|
-
execSync(`launchctl bootout gui/$(id -u) ${plistPath}`, { stdio: "ignore" });
|
|
9299
|
-
} catch {}
|
|
9300
|
-
rmSync2(plistPath, { force: true });
|
|
9301
|
-
},
|
|
9302
|
-
getServicePath() {
|
|
9303
|
-
return plistPath;
|
|
9304
|
-
}
|
|
9305
|
-
};
|
|
9306
|
-
}
|
|
9307
|
-
function getSystemdUnitPath() {
|
|
9308
|
-
return join4(homedir3(), ".config", "systemd", "user", "local-router.service");
|
|
9309
|
-
}
|
|
9310
|
-
function buildUnit(opts) {
|
|
9311
|
-
const logPath = getDaemonLogPath();
|
|
9312
|
-
const execStart = [opts.execPath, ...opts.args].join(" ");
|
|
9313
|
-
return `[Unit]
|
|
9314
|
-
Description=Local Router API Gateway
|
|
9315
|
-
After=network-online.target
|
|
9316
|
-
|
|
9317
|
-
[Service]
|
|
9318
|
-
Type=simple
|
|
9319
|
-
ExecStart=${execStart}
|
|
9320
|
-
Restart=on-failure
|
|
9321
|
-
RestartSec=5
|
|
9322
|
-
StandardOutput=append:${logPath}
|
|
9323
|
-
StandardError=append:${logPath}
|
|
9324
|
-
|
|
9325
|
-
[Install]
|
|
9326
|
-
WantedBy=default.target
|
|
9327
|
-
`;
|
|
9328
|
-
}
|
|
9329
|
-
function createLinuxManager() {
|
|
9330
|
-
const unitPath = getSystemdUnitPath();
|
|
9331
|
-
return {
|
|
9332
|
-
platform: "linux",
|
|
9333
|
-
async isInstalled() {
|
|
9334
|
-
if (!existsSync3(unitPath))
|
|
9335
|
-
return false;
|
|
9336
|
-
try {
|
|
9337
|
-
const out = execSync("systemctl --user is-enabled local-router 2>/dev/null", {
|
|
9338
|
-
encoding: "utf-8"
|
|
9339
|
-
}).trim();
|
|
9340
|
-
return out === "enabled";
|
|
9341
|
-
} catch {
|
|
9342
|
-
return false;
|
|
9343
|
-
}
|
|
9344
|
-
},
|
|
9345
|
-
async install(opts) {
|
|
9346
|
-
const dir = dirname2(unitPath);
|
|
9347
|
-
if (!existsSync3(dir))
|
|
9348
|
-
mkdirSync4(dir, { recursive: true });
|
|
9349
|
-
writeFileSync4(unitPath, buildUnit(opts), "utf-8");
|
|
9350
|
-
execSync("systemctl --user daemon-reload", { stdio: "ignore" });
|
|
9351
|
-
execSync("systemctl --user enable local-router", { stdio: "ignore" });
|
|
9352
|
-
},
|
|
9353
|
-
async uninstall() {
|
|
9354
|
-
try {
|
|
9355
|
-
execSync("systemctl --user disable local-router", { stdio: "ignore" });
|
|
9356
|
-
} catch {}
|
|
9357
|
-
rmSync2(unitPath, { force: true });
|
|
9358
|
-
try {
|
|
9359
|
-
execSync("systemctl --user daemon-reload", { stdio: "ignore" });
|
|
9360
|
-
} catch {}
|
|
9361
|
-
},
|
|
9362
|
-
getServicePath() {
|
|
9363
|
-
return unitPath;
|
|
9364
|
-
}
|
|
9365
|
-
};
|
|
9366
|
-
}
|
|
9367
|
-
function createWindowsManager() {
|
|
9368
|
-
return {
|
|
9369
|
-
platform: "windows",
|
|
9370
|
-
async isInstalled() {
|
|
9371
|
-
try {
|
|
9372
|
-
execSync(`reg query "${WIN_REG_KEY}" /v ${WIN_REG_VALUE}`, { stdio: "ignore" });
|
|
9373
|
-
return true;
|
|
9374
|
-
} catch {
|
|
9375
|
-
return false;
|
|
9376
|
-
}
|
|
9377
|
-
},
|
|
9378
|
-
async install(opts) {
|
|
9379
|
-
const cmd = [opts.execPath, ...opts.args].map((a) => `"${a}"`).join(" ");
|
|
9380
|
-
execSync(`reg add "${WIN_REG_KEY}" /v ${WIN_REG_VALUE} /t REG_SZ /d "${cmd}" /f`, {
|
|
9381
|
-
stdio: "ignore"
|
|
9382
|
-
});
|
|
9383
|
-
},
|
|
9384
|
-
async uninstall() {
|
|
9385
|
-
try {
|
|
9386
|
-
execSync(`reg delete "${WIN_REG_KEY}" /v ${WIN_REG_VALUE} /f`, { stdio: "ignore" });
|
|
9387
|
-
} catch {}
|
|
9388
|
-
},
|
|
9389
|
-
getServicePath() {
|
|
9390
|
-
return `${WIN_REG_KEY}\\${WIN_REG_VALUE}`;
|
|
9391
|
-
}
|
|
9392
|
-
};
|
|
9393
|
-
}
|
|
9394
|
-
function createUnsupportedManager() {
|
|
9395
|
-
return {
|
|
9396
|
-
platform: "unsupported",
|
|
9397
|
-
async isInstalled() {
|
|
9398
|
-
return false;
|
|
9399
|
-
},
|
|
9400
|
-
async install() {
|
|
9401
|
-
throw new Error("\u5F53\u524D\u5E73\u53F0\u4E0D\u652F\u6301\u81EA\u542F\u52A8");
|
|
9402
|
-
},
|
|
9403
|
-
async uninstall() {
|
|
9404
|
-
throw new Error("\u5F53\u524D\u5E73\u53F0\u4E0D\u652F\u6301\u81EA\u542F\u52A8");
|
|
9405
|
-
},
|
|
9406
|
-
getServicePath() {
|
|
9407
|
-
return "";
|
|
9408
|
-
}
|
|
9409
|
-
};
|
|
9410
|
-
}
|
|
9411
|
-
function createAutostartManager() {
|
|
9412
|
-
const p = platform();
|
|
9413
|
-
if (p === "darwin")
|
|
9414
|
-
return createMacosManager();
|
|
9415
|
-
if (p === "linux")
|
|
9416
|
-
return createLinuxManager();
|
|
9417
|
-
if (p === "win32")
|
|
9418
|
-
return createWindowsManager();
|
|
9419
|
-
return createUnsupportedManager();
|
|
9420
|
-
}
|
|
9421
|
-
function getAutostartExecArgs() {
|
|
9422
|
-
const script = process.argv[1] ?? "dist/cli.js";
|
|
9423
|
-
return {
|
|
9424
|
-
execPath: process.execPath,
|
|
9425
|
-
args: [script, "__run-server", "--mode", "daemon"]
|
|
9426
|
-
};
|
|
9427
|
-
}
|
|
9428
|
-
var LABEL = "com.lakphy.local-router", WIN_REG_KEY = "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", WIN_REG_VALUE = "LocalRouter";
|
|
9429
|
-
var init_autostart = __esm(() => {
|
|
9430
|
-
init_runtime();
|
|
9431
|
-
});
|
|
9432
|
-
|
|
9433
9182
|
// node_modules/.bun/@ai-sdk+provider@3.0.8/node_modules/@ai-sdk/provider/dist/index.mjs
|
|
9434
9183
|
function getErrorMessage(error) {
|
|
9435
9184
|
if (error == null) {
|
|
@@ -27547,14 +27296,14 @@ async function delay(delayInMs, options) {
|
|
|
27547
27296
|
return Promise.resolve();
|
|
27548
27297
|
}
|
|
27549
27298
|
const signal = options == null ? undefined : options.abortSignal;
|
|
27550
|
-
return new Promise((
|
|
27299
|
+
return new Promise((resolve2, reject) => {
|
|
27551
27300
|
if (signal == null ? undefined : signal.aborted) {
|
|
27552
27301
|
reject(createAbortError());
|
|
27553
27302
|
return;
|
|
27554
27303
|
}
|
|
27555
27304
|
const timeoutId = setTimeout(() => {
|
|
27556
27305
|
cleanup();
|
|
27557
|
-
|
|
27306
|
+
resolve2();
|
|
27558
27307
|
}, delayInMs);
|
|
27559
27308
|
const cleanup = () => {
|
|
27560
27309
|
clearTimeout(timeoutId);
|
|
@@ -29012,7 +28761,7 @@ function createProviderToolFactoryWithOutputSchema({
|
|
|
29012
28761
|
supportsDeferredResults
|
|
29013
28762
|
});
|
|
29014
28763
|
}
|
|
29015
|
-
async function
|
|
28764
|
+
async function resolve2(value) {
|
|
29016
28765
|
if (typeof value === "function") {
|
|
29017
28766
|
value = value();
|
|
29018
28767
|
}
|
|
@@ -29051,13 +28800,13 @@ var DelayedPromise = class {
|
|
|
29051
28800
|
if (this._promise) {
|
|
29052
28801
|
return this._promise;
|
|
29053
28802
|
}
|
|
29054
|
-
this._promise = new Promise((
|
|
28803
|
+
this._promise = new Promise((resolve2, reject) => {
|
|
29055
28804
|
if (this.status.type === "resolved") {
|
|
29056
|
-
|
|
28805
|
+
resolve2(this.status.value);
|
|
29057
28806
|
} else if (this.status.type === "rejected") {
|
|
29058
28807
|
reject(this.status.error);
|
|
29059
28808
|
}
|
|
29060
|
-
this._resolve =
|
|
28809
|
+
this._resolve = resolve2;
|
|
29061
28810
|
this._reject = reject;
|
|
29062
28811
|
});
|
|
29063
28812
|
return this._promise;
|
|
@@ -31515,11 +31264,11 @@ var VERSION2 = "3.0.58", anthropicErrorDataSchema, anthropicFailedResponseHandle
|
|
|
31515
31264
|
betas,
|
|
31516
31265
|
headers
|
|
31517
31266
|
}) {
|
|
31518
|
-
return combineHeaders(await
|
|
31267
|
+
return combineHeaders(await resolve2(this.config.headers), headers, betas.size > 0 ? { "anthropic-beta": Array.from(betas).join(",") } : {});
|
|
31519
31268
|
}
|
|
31520
31269
|
async getBetasFromHeaders(requestHeaders) {
|
|
31521
31270
|
var _a16, _b16;
|
|
31522
|
-
const configHeaders = await
|
|
31271
|
+
const configHeaders = await resolve2(this.config.headers);
|
|
31523
31272
|
const configBetaHeader = (_a16 = configHeaders["anthropic-beta"]) != null ? _a16 : "";
|
|
31524
31273
|
const requestBetaHeader = (_b16 = requestHeaders == null ? undefined : requestHeaders["anthropic-beta"]) != null ? _b16 : "";
|
|
31525
31274
|
return new Set([
|
|
@@ -42350,7 +42099,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
42350
42099
|
try {
|
|
42351
42100
|
const { value } = await getFromApi({
|
|
42352
42101
|
url: `${this.config.baseURL}/config`,
|
|
42353
|
-
headers: await
|
|
42102
|
+
headers: await resolve2(this.config.headers()),
|
|
42354
42103
|
successfulResponseHandler: createJsonResponseHandler(gatewayAvailableModelsResponseSchema),
|
|
42355
42104
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
42356
42105
|
errorSchema: exports_external.any(),
|
|
@@ -42368,7 +42117,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
42368
42117
|
const baseUrl = new URL(this.config.baseURL);
|
|
42369
42118
|
const { value } = await getFromApi({
|
|
42370
42119
|
url: `${baseUrl.origin}/v1/credits`,
|
|
42371
|
-
headers: await
|
|
42120
|
+
headers: await resolve2(this.config.headers()),
|
|
42372
42121
|
successfulResponseHandler: createJsonResponseHandler(gatewayCreditsResponseSchema),
|
|
42373
42122
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
42374
42123
|
errorSchema: exports_external.any(),
|
|
@@ -42401,7 +42150,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
42401
42150
|
async doGenerate(options) {
|
|
42402
42151
|
const { args, warnings } = await this.getArgs(options);
|
|
42403
42152
|
const { abortSignal } = options;
|
|
42404
|
-
const resolvedHeaders = await
|
|
42153
|
+
const resolvedHeaders = await resolve2(this.config.headers());
|
|
42405
42154
|
try {
|
|
42406
42155
|
const {
|
|
42407
42156
|
responseHeaders,
|
|
@@ -42409,7 +42158,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
42409
42158
|
rawValue: rawResponse
|
|
42410
42159
|
} = await postJsonToApi({
|
|
42411
42160
|
url: this.getUrl(),
|
|
42412
|
-
headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, false), await
|
|
42161
|
+
headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, false), await resolve2(this.config.o11yHeaders)),
|
|
42413
42162
|
body: args,
|
|
42414
42163
|
successfulResponseHandler: createJsonResponseHandler(exports_external.any()),
|
|
42415
42164
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
@@ -42432,11 +42181,11 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
42432
42181
|
async doStream(options) {
|
|
42433
42182
|
const { args, warnings } = await this.getArgs(options);
|
|
42434
42183
|
const { abortSignal } = options;
|
|
42435
|
-
const resolvedHeaders = await
|
|
42184
|
+
const resolvedHeaders = await resolve2(this.config.headers());
|
|
42436
42185
|
try {
|
|
42437
42186
|
const { value: response, responseHeaders } = await postJsonToApi({
|
|
42438
42187
|
url: this.getUrl(),
|
|
42439
|
-
headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, true), await
|
|
42188
|
+
headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, true), await resolve2(this.config.o11yHeaders)),
|
|
42440
42189
|
body: args,
|
|
42441
42190
|
successfulResponseHandler: createEventSourceResponseHandler(exports_external.any()),
|
|
42442
42191
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
@@ -42521,7 +42270,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
42521
42270
|
providerOptions
|
|
42522
42271
|
}) {
|
|
42523
42272
|
var _a92;
|
|
42524
|
-
const resolvedHeaders = await
|
|
42273
|
+
const resolvedHeaders = await resolve2(this.config.headers());
|
|
42525
42274
|
try {
|
|
42526
42275
|
const {
|
|
42527
42276
|
responseHeaders,
|
|
@@ -42529,7 +42278,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
42529
42278
|
rawValue
|
|
42530
42279
|
} = await postJsonToApi({
|
|
42531
42280
|
url: this.getUrl(),
|
|
42532
|
-
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await
|
|
42281
|
+
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve2(this.config.o11yHeaders)),
|
|
42533
42282
|
body: {
|
|
42534
42283
|
values,
|
|
42535
42284
|
...providerOptions ? { providerOptions } : {}
|
|
@@ -42585,7 +42334,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
42585
42334
|
abortSignal
|
|
42586
42335
|
}) {
|
|
42587
42336
|
var _a92, _b92, _c, _d;
|
|
42588
|
-
const resolvedHeaders = await
|
|
42337
|
+
const resolvedHeaders = await resolve2(this.config.headers());
|
|
42589
42338
|
try {
|
|
42590
42339
|
const {
|
|
42591
42340
|
responseHeaders,
|
|
@@ -42593,7 +42342,7 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
42593
42342
|
rawValue
|
|
42594
42343
|
} = await postJsonToApi({
|
|
42595
42344
|
url: this.getUrl(),
|
|
42596
|
-
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await
|
|
42345
|
+
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve2(this.config.o11yHeaders)),
|
|
42597
42346
|
body: {
|
|
42598
42347
|
prompt,
|
|
42599
42348
|
n,
|
|
@@ -42668,11 +42417,11 @@ var import_oidc, import_oidc2, marker17 = "vercel.ai.gateway.error", symbol18, _
|
|
|
42668
42417
|
abortSignal
|
|
42669
42418
|
}) {
|
|
42670
42419
|
var _a92;
|
|
42671
|
-
const resolvedHeaders = await
|
|
42420
|
+
const resolvedHeaders = await resolve2(this.config.headers());
|
|
42672
42421
|
try {
|
|
42673
42422
|
const { responseHeaders, value: responseBody } = await postJsonToApi({
|
|
42674
42423
|
url: this.getUrl(),
|
|
42675
|
-
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await
|
|
42424
|
+
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve2(this.config.o11yHeaders), { accept: "text/event-stream" }),
|
|
42676
42425
|
body: {
|
|
42677
42426
|
prompt,
|
|
42678
42427
|
n,
|
|
@@ -46662,8 +46411,8 @@ function writeToServerResponse({
|
|
|
46662
46411
|
break;
|
|
46663
46412
|
const canContinue = response.write(value);
|
|
46664
46413
|
if (!canContinue) {
|
|
46665
|
-
await new Promise((
|
|
46666
|
-
response.once("drain",
|
|
46414
|
+
await new Promise((resolve3) => {
|
|
46415
|
+
response.once("drain", resolve3);
|
|
46667
46416
|
});
|
|
46668
46417
|
}
|
|
46669
46418
|
}
|
|
@@ -47424,15 +47173,15 @@ async function consumeStream({
|
|
|
47424
47173
|
}
|
|
47425
47174
|
}
|
|
47426
47175
|
function createResolvablePromise() {
|
|
47427
|
-
let
|
|
47176
|
+
let resolve3;
|
|
47428
47177
|
let reject;
|
|
47429
47178
|
const promise2 = new Promise((res, rej) => {
|
|
47430
|
-
|
|
47179
|
+
resolve3 = res;
|
|
47431
47180
|
reject = rej;
|
|
47432
47181
|
});
|
|
47433
47182
|
return {
|
|
47434
47183
|
promise: promise2,
|
|
47435
|
-
resolve:
|
|
47184
|
+
resolve: resolve3,
|
|
47436
47185
|
reject
|
|
47437
47186
|
};
|
|
47438
47187
|
}
|
|
@@ -48014,7 +47763,7 @@ var import_api, import_api2, __defProp2, __export2 = (target, all) => {
|
|
|
48014
47763
|
const schema = asSchema(inputSchema);
|
|
48015
47764
|
return {
|
|
48016
47765
|
name: "object",
|
|
48017
|
-
responseFormat:
|
|
47766
|
+
responseFormat: resolve2(schema.jsonSchema).then((jsonSchema2) => ({
|
|
48018
47767
|
type: "json",
|
|
48019
47768
|
schema: jsonSchema2,
|
|
48020
47769
|
...name21 != null && { name: name21 },
|
|
@@ -48075,7 +47824,7 @@ var import_api, import_api2, __defProp2, __export2 = (target, all) => {
|
|
|
48075
47824
|
const elementSchema = asSchema(inputElementSchema);
|
|
48076
47825
|
return {
|
|
48077
47826
|
name: "array",
|
|
48078
|
-
responseFormat:
|
|
47827
|
+
responseFormat: resolve2(elementSchema.jsonSchema).then((jsonSchema2) => {
|
|
48079
47828
|
const { $schema, ...itemSchema } = jsonSchema2;
|
|
48080
47829
|
return {
|
|
48081
47830
|
type: "json",
|
|
@@ -52573,7 +52322,7 @@ var init_path = () => {};
|
|
|
52573
52322
|
var ENCODINGS, ENCODINGS_ORDERED_KEYS, DEFAULT_DOCUMENT = "index.html", serveStatic = (options) => {
|
|
52574
52323
|
const root = options.root ?? "./";
|
|
52575
52324
|
const optionPath = options.path;
|
|
52576
|
-
const
|
|
52325
|
+
const join3 = options.join ?? defaultJoin;
|
|
52577
52326
|
return async (c, next) => {
|
|
52578
52327
|
if (c.finalized) {
|
|
52579
52328
|
return next();
|
|
@@ -52592,9 +52341,9 @@ var ENCODINGS, ENCODINGS_ORDERED_KEYS, DEFAULT_DOCUMENT = "index.html", serveSta
|
|
|
52592
52341
|
return next();
|
|
52593
52342
|
}
|
|
52594
52343
|
}
|
|
52595
|
-
let path =
|
|
52344
|
+
let path = join3(root, !optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename) : filename);
|
|
52596
52345
|
if (options.isDir && await options.isDir(path)) {
|
|
52597
|
-
path =
|
|
52346
|
+
path = join3(path, DEFAULT_DOCUMENT);
|
|
52598
52347
|
}
|
|
52599
52348
|
const getContent = options.getContent;
|
|
52600
52349
|
let content = await getContent(path, c);
|
|
@@ -52642,7 +52391,7 @@ var init_serve_static = __esm(() => {
|
|
|
52642
52391
|
|
|
52643
52392
|
// node_modules/.bun/hono@4.12.5/node_modules/hono/dist/adapter/bun/serve-static.js
|
|
52644
52393
|
import { stat } from "fs/promises";
|
|
52645
|
-
import { join as
|
|
52394
|
+
import { join as join3 } from "path";
|
|
52646
52395
|
var serveStatic2 = (options) => {
|
|
52647
52396
|
return async function serveStatic22(c, next) {
|
|
52648
52397
|
const getContent = async (path) => {
|
|
@@ -52660,7 +52409,7 @@ var serveStatic2 = (options) => {
|
|
|
52660
52409
|
return serveStatic({
|
|
52661
52410
|
...options,
|
|
52662
52411
|
getContent,
|
|
52663
|
-
join:
|
|
52412
|
+
join: join3,
|
|
52664
52413
|
isDir
|
|
52665
52414
|
})(c, next);
|
|
52666
52415
|
};
|
|
@@ -52826,6 +52575,257 @@ var init_bun = __esm(() => {
|
|
|
52826
52575
|
init_server();
|
|
52827
52576
|
});
|
|
52828
52577
|
|
|
52578
|
+
// src/cli/runtime.ts
|
|
52579
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync4, rmSync, writeFileSync as writeFileSync3 } from "fs";
|
|
52580
|
+
import { homedir as homedir2 } from "os";
|
|
52581
|
+
import { join as join4, resolve as resolve3 } from "path";
|
|
52582
|
+
function getRuntimeDirs() {
|
|
52583
|
+
const override = process.env.LOCAL_ROUTER_RUNTIME_DIR;
|
|
52584
|
+
const root = override?.trim() ? override.trim() : join4(homedir2(), ".local-router");
|
|
52585
|
+
return {
|
|
52586
|
+
root,
|
|
52587
|
+
run: join4(root, "run"),
|
|
52588
|
+
logs: join4(root, "logs")
|
|
52589
|
+
};
|
|
52590
|
+
}
|
|
52591
|
+
function getRuntimeFiles() {
|
|
52592
|
+
const dirs = getRuntimeDirs();
|
|
52593
|
+
return {
|
|
52594
|
+
pid: join4(dirs.run, "local-router.pid"),
|
|
52595
|
+
state: join4(dirs.run, "status.json"),
|
|
52596
|
+
daemonLog: join4(dirs.logs, "daemon.log")
|
|
52597
|
+
};
|
|
52598
|
+
}
|
|
52599
|
+
function ensureRuntimeDirs() {
|
|
52600
|
+
const dirs = getRuntimeDirs();
|
|
52601
|
+
mkdirSync3(dirs.root, { recursive: true });
|
|
52602
|
+
mkdirSync3(dirs.run, { recursive: true });
|
|
52603
|
+
mkdirSync3(dirs.logs, { recursive: true });
|
|
52604
|
+
}
|
|
52605
|
+
function writeRuntimeState(state) {
|
|
52606
|
+
ensureRuntimeDirs();
|
|
52607
|
+
const files = getRuntimeFiles();
|
|
52608
|
+
writeFileSync3(files.pid, `${state.pid}
|
|
52609
|
+
`, "utf-8");
|
|
52610
|
+
writeFileSync3(files.state, JSON.stringify(state, null, 2), "utf-8");
|
|
52611
|
+
}
|
|
52612
|
+
function readRuntimeState() {
|
|
52613
|
+
const files = getRuntimeFiles();
|
|
52614
|
+
if (!existsSync2(files.state)) {
|
|
52615
|
+
return null;
|
|
52616
|
+
}
|
|
52617
|
+
try {
|
|
52618
|
+
return JSON.parse(readFileSync4(files.state, "utf-8"));
|
|
52619
|
+
} catch {
|
|
52620
|
+
return null;
|
|
52621
|
+
}
|
|
52622
|
+
}
|
|
52623
|
+
function clearRuntimeFiles() {
|
|
52624
|
+
const files = getRuntimeFiles();
|
|
52625
|
+
rmSync(files.pid, { force: true });
|
|
52626
|
+
rmSync(files.state, { force: true });
|
|
52627
|
+
}
|
|
52628
|
+
function resolveConfigArgPath(pathValue) {
|
|
52629
|
+
return resolve3(pathValue);
|
|
52630
|
+
}
|
|
52631
|
+
var init_runtime = () => {};
|
|
52632
|
+
|
|
52633
|
+
// src/cli/autostart.ts
|
|
52634
|
+
import { execSync } from "child_process";
|
|
52635
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
52636
|
+
import { homedir as homedir3, platform } from "os";
|
|
52637
|
+
import { dirname as dirname3, join as join5 } from "path";
|
|
52638
|
+
function getDaemonLogPath() {
|
|
52639
|
+
return getRuntimeDirs().logs + "/daemon.log";
|
|
52640
|
+
}
|
|
52641
|
+
function getLaunchAgentPath() {
|
|
52642
|
+
return join5(homedir3(), "Library", "LaunchAgents", `${LABEL}.plist`);
|
|
52643
|
+
}
|
|
52644
|
+
function buildPlist(opts) {
|
|
52645
|
+
const logPath = getDaemonLogPath();
|
|
52646
|
+
const args = [opts.execPath, ...opts.args].map((a) => ` <string>${escapeXml(a)}</string>`).join(`
|
|
52647
|
+
`);
|
|
52648
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
52649
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
52650
|
+
<plist version="1.0">
|
|
52651
|
+
<dict>
|
|
52652
|
+
<key>Label</key>
|
|
52653
|
+
<string>${escapeXml(opts.label)}</string>
|
|
52654
|
+
<key>ProgramArguments</key>
|
|
52655
|
+
<array>
|
|
52656
|
+
${args}
|
|
52657
|
+
</array>
|
|
52658
|
+
<key>RunAtLoad</key>
|
|
52659
|
+
<true/>
|
|
52660
|
+
<key>KeepAlive</key>
|
|
52661
|
+
<false/>
|
|
52662
|
+
<key>StandardOutPath</key>
|
|
52663
|
+
<string>${escapeXml(logPath)}</string>
|
|
52664
|
+
<key>StandardErrorPath</key>
|
|
52665
|
+
<string>${escapeXml(logPath)}</string>
|
|
52666
|
+
</dict>
|
|
52667
|
+
</plist>
|
|
52668
|
+
`;
|
|
52669
|
+
}
|
|
52670
|
+
function escapeXml(s) {
|
|
52671
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
52672
|
+
}
|
|
52673
|
+
function createMacosManager() {
|
|
52674
|
+
const plistPath = getLaunchAgentPath();
|
|
52675
|
+
return {
|
|
52676
|
+
platform: "macos",
|
|
52677
|
+
async isInstalled() {
|
|
52678
|
+
return existsSync3(plistPath);
|
|
52679
|
+
},
|
|
52680
|
+
async install(opts) {
|
|
52681
|
+
const dir = dirname3(plistPath);
|
|
52682
|
+
if (!existsSync3(dir))
|
|
52683
|
+
mkdirSync4(dir, { recursive: true });
|
|
52684
|
+
writeFileSync4(plistPath, buildPlist(opts), "utf-8");
|
|
52685
|
+
try {
|
|
52686
|
+
execSync(`launchctl bootout gui/$(id -u) ${plistPath} 2>/dev/null`, { stdio: "ignore" });
|
|
52687
|
+
} catch {}
|
|
52688
|
+
execSync(`launchctl bootstrap gui/$(id -u) ${plistPath}`, { stdio: "ignore" });
|
|
52689
|
+
},
|
|
52690
|
+
async uninstall() {
|
|
52691
|
+
if (!existsSync3(plistPath))
|
|
52692
|
+
return;
|
|
52693
|
+
try {
|
|
52694
|
+
execSync(`launchctl bootout gui/$(id -u) ${plistPath}`, { stdio: "ignore" });
|
|
52695
|
+
} catch {}
|
|
52696
|
+
rmSync2(plistPath, { force: true });
|
|
52697
|
+
},
|
|
52698
|
+
getServicePath() {
|
|
52699
|
+
return plistPath;
|
|
52700
|
+
}
|
|
52701
|
+
};
|
|
52702
|
+
}
|
|
52703
|
+
function getSystemdUnitPath() {
|
|
52704
|
+
return join5(homedir3(), ".config", "systemd", "user", "local-router.service");
|
|
52705
|
+
}
|
|
52706
|
+
function buildUnit(opts) {
|
|
52707
|
+
const logPath = getDaemonLogPath();
|
|
52708
|
+
const execStart = [opts.execPath, ...opts.args].join(" ");
|
|
52709
|
+
return `[Unit]
|
|
52710
|
+
Description=Local Router API Gateway
|
|
52711
|
+
After=network-online.target
|
|
52712
|
+
|
|
52713
|
+
[Service]
|
|
52714
|
+
Type=simple
|
|
52715
|
+
ExecStart=${execStart}
|
|
52716
|
+
Restart=on-failure
|
|
52717
|
+
RestartSec=5
|
|
52718
|
+
StandardOutput=append:${logPath}
|
|
52719
|
+
StandardError=append:${logPath}
|
|
52720
|
+
|
|
52721
|
+
[Install]
|
|
52722
|
+
WantedBy=default.target
|
|
52723
|
+
`;
|
|
52724
|
+
}
|
|
52725
|
+
function createLinuxManager() {
|
|
52726
|
+
const unitPath = getSystemdUnitPath();
|
|
52727
|
+
return {
|
|
52728
|
+
platform: "linux",
|
|
52729
|
+
async isInstalled() {
|
|
52730
|
+
if (!existsSync3(unitPath))
|
|
52731
|
+
return false;
|
|
52732
|
+
try {
|
|
52733
|
+
const out = execSync("systemctl --user is-enabled local-router 2>/dev/null", {
|
|
52734
|
+
encoding: "utf-8"
|
|
52735
|
+
}).trim();
|
|
52736
|
+
return out === "enabled";
|
|
52737
|
+
} catch {
|
|
52738
|
+
return false;
|
|
52739
|
+
}
|
|
52740
|
+
},
|
|
52741
|
+
async install(opts) {
|
|
52742
|
+
const dir = dirname3(unitPath);
|
|
52743
|
+
if (!existsSync3(dir))
|
|
52744
|
+
mkdirSync4(dir, { recursive: true });
|
|
52745
|
+
writeFileSync4(unitPath, buildUnit(opts), "utf-8");
|
|
52746
|
+
execSync("systemctl --user daemon-reload", { stdio: "ignore" });
|
|
52747
|
+
execSync("systemctl --user enable local-router", { stdio: "ignore" });
|
|
52748
|
+
},
|
|
52749
|
+
async uninstall() {
|
|
52750
|
+
try {
|
|
52751
|
+
execSync("systemctl --user disable local-router", { stdio: "ignore" });
|
|
52752
|
+
} catch {}
|
|
52753
|
+
rmSync2(unitPath, { force: true });
|
|
52754
|
+
try {
|
|
52755
|
+
execSync("systemctl --user daemon-reload", { stdio: "ignore" });
|
|
52756
|
+
} catch {}
|
|
52757
|
+
},
|
|
52758
|
+
getServicePath() {
|
|
52759
|
+
return unitPath;
|
|
52760
|
+
}
|
|
52761
|
+
};
|
|
52762
|
+
}
|
|
52763
|
+
function createWindowsManager() {
|
|
52764
|
+
return {
|
|
52765
|
+
platform: "windows",
|
|
52766
|
+
async isInstalled() {
|
|
52767
|
+
try {
|
|
52768
|
+
execSync(`reg query "${WIN_REG_KEY}" /v ${WIN_REG_VALUE}`, { stdio: "ignore" });
|
|
52769
|
+
return true;
|
|
52770
|
+
} catch {
|
|
52771
|
+
return false;
|
|
52772
|
+
}
|
|
52773
|
+
},
|
|
52774
|
+
async install(opts) {
|
|
52775
|
+
const cmd = [opts.execPath, ...opts.args].map((a) => `"${a}"`).join(" ");
|
|
52776
|
+
execSync(`reg add "${WIN_REG_KEY}" /v ${WIN_REG_VALUE} /t REG_SZ /d "${cmd}" /f`, {
|
|
52777
|
+
stdio: "ignore"
|
|
52778
|
+
});
|
|
52779
|
+
},
|
|
52780
|
+
async uninstall() {
|
|
52781
|
+
try {
|
|
52782
|
+
execSync(`reg delete "${WIN_REG_KEY}" /v ${WIN_REG_VALUE} /f`, { stdio: "ignore" });
|
|
52783
|
+
} catch {}
|
|
52784
|
+
},
|
|
52785
|
+
getServicePath() {
|
|
52786
|
+
return `${WIN_REG_KEY}\\${WIN_REG_VALUE}`;
|
|
52787
|
+
}
|
|
52788
|
+
};
|
|
52789
|
+
}
|
|
52790
|
+
function createUnsupportedManager() {
|
|
52791
|
+
return {
|
|
52792
|
+
platform: "unsupported",
|
|
52793
|
+
async isInstalled() {
|
|
52794
|
+
return false;
|
|
52795
|
+
},
|
|
52796
|
+
async install() {
|
|
52797
|
+
throw new Error("\u5F53\u524D\u5E73\u53F0\u4E0D\u652F\u6301\u81EA\u542F\u52A8");
|
|
52798
|
+
},
|
|
52799
|
+
async uninstall() {
|
|
52800
|
+
throw new Error("\u5F53\u524D\u5E73\u53F0\u4E0D\u652F\u6301\u81EA\u542F\u52A8");
|
|
52801
|
+
},
|
|
52802
|
+
getServicePath() {
|
|
52803
|
+
return "";
|
|
52804
|
+
}
|
|
52805
|
+
};
|
|
52806
|
+
}
|
|
52807
|
+
function createAutostartManager() {
|
|
52808
|
+
const p = platform();
|
|
52809
|
+
if (p === "darwin")
|
|
52810
|
+
return createMacosManager();
|
|
52811
|
+
if (p === "linux")
|
|
52812
|
+
return createLinuxManager();
|
|
52813
|
+
if (p === "win32")
|
|
52814
|
+
return createWindowsManager();
|
|
52815
|
+
return createUnsupportedManager();
|
|
52816
|
+
}
|
|
52817
|
+
function getAutostartExecArgs() {
|
|
52818
|
+
const script = process.argv[1] ?? "dist/cli.js";
|
|
52819
|
+
return {
|
|
52820
|
+
execPath: process.execPath,
|
|
52821
|
+
args: [script, "__run-server", "--mode", "daemon"]
|
|
52822
|
+
};
|
|
52823
|
+
}
|
|
52824
|
+
var LABEL = "com.lakphy.local-router", WIN_REG_KEY = "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", WIN_REG_VALUE = "LocalRouter";
|
|
52825
|
+
var init_autostart = __esm(() => {
|
|
52826
|
+
init_runtime();
|
|
52827
|
+
});
|
|
52828
|
+
|
|
52829
52829
|
// src/config-store.ts
|
|
52830
52830
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
52831
52831
|
import { resolve as resolve4 } from "path";
|
|
@@ -52922,387 +52922,8 @@ var init_crypto = __esm(() => {
|
|
|
52922
52922
|
ECDH_PARAMS = { name: "ECDH", namedCurve: "P-256" };
|
|
52923
52923
|
});
|
|
52924
52924
|
|
|
52925
|
-
// src/log-metrics.ts
|
|
52926
|
-
import { createReadStream, existsSync as existsSync4 } from "fs";
|
|
52927
|
-
import { join as join6 } from "path";
|
|
52928
|
-
import { createInterface } from "readline";
|
|
52929
|
-
function isLogMetricsWindow(value) {
|
|
52930
|
-
return value === "1h" || value === "6h" || value === "24h";
|
|
52931
|
-
}
|
|
52932
|
-
function toPercent(numerator, denominator) {
|
|
52933
|
-
if (denominator <= 0)
|
|
52934
|
-
return 0;
|
|
52935
|
-
return Number((numerator / denominator * 100).toFixed(2));
|
|
52936
|
-
}
|
|
52937
|
-
function toDayStart(ms) {
|
|
52938
|
-
const date5 = new Date(ms);
|
|
52939
|
-
return Date.UTC(date5.getUTCFullYear(), date5.getUTCMonth(), date5.getUTCDate());
|
|
52940
|
-
}
|
|
52941
|
-
function listDateStrings(fromMs, toMs) {
|
|
52942
|
-
const result = [];
|
|
52943
|
-
for (let day = toDayStart(fromMs);day <= toDayStart(toMs); day += 24 * 60 * 60 * 1000) {
|
|
52944
|
-
result.push(new Date(day).toISOString().slice(0, 10));
|
|
52945
|
-
}
|
|
52946
|
-
return result;
|
|
52947
|
-
}
|
|
52948
|
-
function getStatusClass(event) {
|
|
52949
|
-
if (event.error_type)
|
|
52950
|
-
return "network_error";
|
|
52951
|
-
const status = event.upstream_status ?? 0;
|
|
52952
|
-
if (status >= 200 && status < 300)
|
|
52953
|
-
return "2xx";
|
|
52954
|
-
if (status >= 400 && status < 500)
|
|
52955
|
-
return "4xx";
|
|
52956
|
-
if (status >= 500)
|
|
52957
|
-
return "5xx";
|
|
52958
|
-
return "network_error";
|
|
52959
|
-
}
|
|
52960
|
-
function isErrorEvent(event) {
|
|
52961
|
-
if (event.error_type)
|
|
52962
|
-
return true;
|
|
52963
|
-
const status = event.upstream_status ?? 0;
|
|
52964
|
-
return status < 200 || status >= 400;
|
|
52965
|
-
}
|
|
52966
|
-
function percentile(sortedNumbers, ratio) {
|
|
52967
|
-
if (sortedNumbers.length === 0)
|
|
52968
|
-
return 0;
|
|
52969
|
-
const index = Math.min(sortedNumbers.length - 1, Math.ceil(sortedNumbers.length * ratio) - 1);
|
|
52970
|
-
return Math.round(sortedNumbers[index]);
|
|
52971
|
-
}
|
|
52972
|
-
function createEmptyMetrics(window2, nowMs, source, warnings = []) {
|
|
52973
|
-
const fromMs = nowMs - WINDOW_MS[window2];
|
|
52974
|
-
const bucketMs = BUCKET_MS[window2];
|
|
52975
|
-
const bucketCount = Math.max(1, Math.ceil((nowMs - fromMs) / bucketMs));
|
|
52976
|
-
const series = Array.from({ length: bucketCount }, (_, i) => ({
|
|
52977
|
-
ts: new Date(fromMs + i * bucketMs).toISOString(),
|
|
52978
|
-
requests: 0,
|
|
52979
|
-
errors: 0,
|
|
52980
|
-
avgLatencyMs: 0
|
|
52981
|
-
}));
|
|
52982
|
-
return {
|
|
52983
|
-
window: window2,
|
|
52984
|
-
from: new Date(fromMs).toISOString(),
|
|
52985
|
-
to: new Date(nowMs).toISOString(),
|
|
52986
|
-
generatedAt: new Date(nowMs).toISOString(),
|
|
52987
|
-
source,
|
|
52988
|
-
summary: {
|
|
52989
|
-
totalRequests: 0,
|
|
52990
|
-
successRequests: 0,
|
|
52991
|
-
errorRequests: 0,
|
|
52992
|
-
successRate: 0,
|
|
52993
|
-
avgLatencyMs: 0,
|
|
52994
|
-
p95LatencyMs: 0,
|
|
52995
|
-
totalRequestBytes: 0,
|
|
52996
|
-
totalResponseBytes: 0
|
|
52997
|
-
},
|
|
52998
|
-
series,
|
|
52999
|
-
topProviders: [],
|
|
53000
|
-
topRouteTypes: [],
|
|
53001
|
-
statusClasses: {
|
|
53002
|
-
"2xx": 0,
|
|
53003
|
-
"4xx": 0,
|
|
53004
|
-
"5xx": 0,
|
|
53005
|
-
network_error: 0
|
|
53006
|
-
},
|
|
53007
|
-
warnings
|
|
53008
|
-
};
|
|
53009
|
-
}
|
|
53010
|
-
async function getLogMetrics(options) {
|
|
53011
|
-
const window2 = options.window ?? "24h";
|
|
53012
|
-
const refresh = options.refresh === true;
|
|
53013
|
-
const nowMs = options.nowMs ?? Date.now();
|
|
53014
|
-
const logEnabled = options.logConfig?.enabled !== false && !!options.logConfig;
|
|
53015
|
-
if (!logEnabled) {
|
|
53016
|
-
return createEmptyMetrics(window2, nowMs, {
|
|
53017
|
-
logEnabled: false,
|
|
53018
|
-
baseDir: null,
|
|
53019
|
-
filesScanned: 0,
|
|
53020
|
-
linesScanned: 0,
|
|
53021
|
-
partial: false
|
|
53022
|
-
}, ["\u65E5\u5FD7\u672A\u542F\u7528"]);
|
|
53023
|
-
}
|
|
53024
|
-
const baseDir = resolveLogBaseDir(options.logConfig);
|
|
53025
|
-
const cacheKey = `${baseDir}:${window2}`;
|
|
53026
|
-
const cached2 = metricsCache.get(cacheKey);
|
|
53027
|
-
if (!refresh && cached2 && cached2.expiresAt > nowMs) {
|
|
53028
|
-
return cached2.value;
|
|
53029
|
-
}
|
|
53030
|
-
const eventsDir = join6(baseDir, "events");
|
|
53031
|
-
if (!existsSync4(eventsDir)) {
|
|
53032
|
-
const empty = createEmptyMetrics(window2, nowMs, {
|
|
53033
|
-
logEnabled: true,
|
|
53034
|
-
baseDir,
|
|
53035
|
-
filesScanned: 0,
|
|
53036
|
-
linesScanned: 0,
|
|
53037
|
-
partial: false
|
|
53038
|
-
}, ["\u65E5\u5FD7\u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u6682\u65E0\u53EF\u5206\u6790\u6570\u636E"]);
|
|
53039
|
-
metricsCache.set(cacheKey, { expiresAt: nowMs + CACHE_TTL_MS, value: empty });
|
|
53040
|
-
return empty;
|
|
53041
|
-
}
|
|
53042
|
-
const fromMs = nowMs - WINDOW_MS[window2];
|
|
53043
|
-
const bucketMs = BUCKET_MS[window2];
|
|
53044
|
-
const bucketCount = Math.max(1, Math.ceil((nowMs - fromMs) / bucketMs));
|
|
53045
|
-
const buckets = Array.from({ length: bucketCount }, () => ({
|
|
53046
|
-
requests: 0,
|
|
53047
|
-
errors: 0,
|
|
53048
|
-
latencySum: 0,
|
|
53049
|
-
latencyCount: 0
|
|
53050
|
-
}));
|
|
53051
|
-
const providerAgg = new Map;
|
|
53052
|
-
const routeTypeAgg = new Map;
|
|
53053
|
-
const latencies = [];
|
|
53054
|
-
const statusClasses = {
|
|
53055
|
-
"2xx": 0,
|
|
53056
|
-
"4xx": 0,
|
|
53057
|
-
"5xx": 0,
|
|
53058
|
-
network_error: 0
|
|
53059
|
-
};
|
|
53060
|
-
let filesScanned = 0;
|
|
53061
|
-
let linesScanned = 0;
|
|
53062
|
-
let parseErrors = 0;
|
|
53063
|
-
let partial2 = false;
|
|
53064
|
-
let totalRequests = 0;
|
|
53065
|
-
let successRequests = 0;
|
|
53066
|
-
let errorRequests = 0;
|
|
53067
|
-
let totalLatency = 0;
|
|
53068
|
-
let totalRequestBytes = 0;
|
|
53069
|
-
let totalResponseBytes = 0;
|
|
53070
|
-
const warnings = [];
|
|
53071
|
-
const dateStrings = listDateStrings(fromMs, nowMs);
|
|
53072
|
-
for (const dateStr of dateStrings) {
|
|
53073
|
-
if (linesScanned >= MAX_LINES_SCANNED) {
|
|
53074
|
-
partial2 = true;
|
|
53075
|
-
break;
|
|
53076
|
-
}
|
|
53077
|
-
const filePath = join6(eventsDir, `${dateStr}.jsonl`);
|
|
53078
|
-
if (!existsSync4(filePath))
|
|
53079
|
-
continue;
|
|
53080
|
-
filesScanned += 1;
|
|
53081
|
-
try {
|
|
53082
|
-
const stream = createReadStream(filePath, { encoding: "utf-8" });
|
|
53083
|
-
const rl = createInterface({ input: stream, crlfDelay: Number.POSITIVE_INFINITY });
|
|
53084
|
-
for await (const line of rl) {
|
|
53085
|
-
if (linesScanned >= MAX_LINES_SCANNED) {
|
|
53086
|
-
partial2 = true;
|
|
53087
|
-
rl.close();
|
|
53088
|
-
stream.destroy();
|
|
53089
|
-
break;
|
|
53090
|
-
}
|
|
53091
|
-
linesScanned += 1;
|
|
53092
|
-
if (!line.trim())
|
|
53093
|
-
continue;
|
|
53094
|
-
let event;
|
|
53095
|
-
try {
|
|
53096
|
-
event = JSON.parse(line);
|
|
53097
|
-
} catch {
|
|
53098
|
-
parseErrors += 1;
|
|
53099
|
-
continue;
|
|
53100
|
-
}
|
|
53101
|
-
if (!event.ts_start)
|
|
53102
|
-
continue;
|
|
53103
|
-
const ts = Date.parse(event.ts_start);
|
|
53104
|
-
if (!Number.isFinite(ts) || ts < fromMs || ts > nowMs)
|
|
53105
|
-
continue;
|
|
53106
|
-
totalRequests += 1;
|
|
53107
|
-
const isError = isErrorEvent(event);
|
|
53108
|
-
if (isError) {
|
|
53109
|
-
errorRequests += 1;
|
|
53110
|
-
} else {
|
|
53111
|
-
successRequests += 1;
|
|
53112
|
-
}
|
|
53113
|
-
const latency = Number.isFinite(event.latency_ms) ? Math.max(0, event.latency_ms ?? 0) : 0;
|
|
53114
|
-
totalLatency += latency;
|
|
53115
|
-
latencies.push(latency);
|
|
53116
|
-
totalRequestBytes += Math.max(0, event.request_bytes ?? 0);
|
|
53117
|
-
totalResponseBytes += Math.max(0, event.response_bytes ?? 0) + Math.max(0, event.stream_bytes ?? 0);
|
|
53118
|
-
const bucketIndex = Math.min(bucketCount - 1, Math.max(0, Math.floor((ts - fromMs) / bucketMs)));
|
|
53119
|
-
const bucket = buckets[bucketIndex];
|
|
53120
|
-
bucket.requests += 1;
|
|
53121
|
-
bucket.latencySum += latency;
|
|
53122
|
-
bucket.latencyCount += 1;
|
|
53123
|
-
if (isError)
|
|
53124
|
-
bucket.errors += 1;
|
|
53125
|
-
const providerKey = event.provider || "unknown";
|
|
53126
|
-
const providerRow = providerAgg.get(providerKey) ?? {
|
|
53127
|
-
requests: 0,
|
|
53128
|
-
errors: 0,
|
|
53129
|
-
latencySum: 0
|
|
53130
|
-
};
|
|
53131
|
-
providerRow.requests += 1;
|
|
53132
|
-
providerRow.latencySum += latency;
|
|
53133
|
-
if (isError)
|
|
53134
|
-
providerRow.errors += 1;
|
|
53135
|
-
providerAgg.set(providerKey, providerRow);
|
|
53136
|
-
const routeTypeKey = event.route_type || "unknown";
|
|
53137
|
-
const routeTypeRow = routeTypeAgg.get(routeTypeKey) ?? {
|
|
53138
|
-
requests: 0,
|
|
53139
|
-
errors: 0,
|
|
53140
|
-
latencySum: 0
|
|
53141
|
-
};
|
|
53142
|
-
routeTypeRow.requests += 1;
|
|
53143
|
-
routeTypeRow.latencySum += latency;
|
|
53144
|
-
if (isError)
|
|
53145
|
-
routeTypeRow.errors += 1;
|
|
53146
|
-
routeTypeAgg.set(routeTypeKey, routeTypeRow);
|
|
53147
|
-
statusClasses[getStatusClass(event)] += 1;
|
|
53148
|
-
}
|
|
53149
|
-
} catch (err) {
|
|
53150
|
-
warnings.push(`\u8BFB\u53D6\u65E5\u5FD7\u6587\u4EF6\u5931\u8D25: ${filePath} (${err instanceof Error ? err.message : String(err)})`);
|
|
53151
|
-
partial2 = true;
|
|
53152
|
-
}
|
|
53153
|
-
}
|
|
53154
|
-
if (parseErrors > 0) {
|
|
53155
|
-
warnings.push(`\u5DF2\u8DF3\u8FC7 ${parseErrors} \u884C\u65E0\u6548 JSON \u65E5\u5FD7`);
|
|
53156
|
-
}
|
|
53157
|
-
if (partial2) {
|
|
53158
|
-
warnings.push("\u65E5\u5FD7\u626B\u63CF\u5DF2\u90E8\u5206\u622A\u65AD\uFF0C\u7ED3\u679C\u53EF\u80FD\u4E0D\u5B8C\u6574");
|
|
53159
|
-
}
|
|
53160
|
-
latencies.sort((a, b) => a - b);
|
|
53161
|
-
const series = buckets.map((bucket, index) => ({
|
|
53162
|
-
ts: new Date(fromMs + index * bucketMs).toISOString(),
|
|
53163
|
-
requests: bucket.requests,
|
|
53164
|
-
errors: bucket.errors,
|
|
53165
|
-
avgLatencyMs: bucket.latencyCount > 0 ? Math.round(bucket.latencySum / bucket.latencyCount) : 0
|
|
53166
|
-
}));
|
|
53167
|
-
const topProviders = Array.from(providerAgg.entries()).map(([key, row]) => ({
|
|
53168
|
-
key,
|
|
53169
|
-
requests: row.requests,
|
|
53170
|
-
errorRate: toPercent(row.errors, row.requests),
|
|
53171
|
-
avgLatencyMs: row.requests > 0 ? Math.round(row.latencySum / row.requests) : 0
|
|
53172
|
-
})).sort((a, b) => b.requests - a.requests).slice(0, TOP_LIMIT);
|
|
53173
|
-
const topRouteTypes = Array.from(routeTypeAgg.entries()).map(([key, row]) => ({
|
|
53174
|
-
key,
|
|
53175
|
-
requests: row.requests,
|
|
53176
|
-
errorRate: toPercent(row.errors, row.requests)
|
|
53177
|
-
})).sort((a, b) => b.requests - a.requests).slice(0, TOP_LIMIT);
|
|
53178
|
-
const response = {
|
|
53179
|
-
window: window2,
|
|
53180
|
-
from: new Date(fromMs).toISOString(),
|
|
53181
|
-
to: new Date(nowMs).toISOString(),
|
|
53182
|
-
generatedAt: new Date(nowMs).toISOString(),
|
|
53183
|
-
source: {
|
|
53184
|
-
logEnabled: true,
|
|
53185
|
-
baseDir,
|
|
53186
|
-
filesScanned,
|
|
53187
|
-
linesScanned,
|
|
53188
|
-
partial: partial2
|
|
53189
|
-
},
|
|
53190
|
-
summary: {
|
|
53191
|
-
totalRequests,
|
|
53192
|
-
successRequests,
|
|
53193
|
-
errorRequests,
|
|
53194
|
-
successRate: toPercent(successRequests, totalRequests),
|
|
53195
|
-
avgLatencyMs: totalRequests > 0 ? Math.round(totalLatency / totalRequests) : 0,
|
|
53196
|
-
p95LatencyMs: percentile(latencies, 0.95),
|
|
53197
|
-
totalRequestBytes,
|
|
53198
|
-
totalResponseBytes
|
|
53199
|
-
},
|
|
53200
|
-
series,
|
|
53201
|
-
topProviders,
|
|
53202
|
-
topRouteTypes,
|
|
53203
|
-
statusClasses,
|
|
53204
|
-
warnings
|
|
53205
|
-
};
|
|
53206
|
-
metricsCache.set(cacheKey, {
|
|
53207
|
-
expiresAt: nowMs + CACHE_TTL_MS,
|
|
53208
|
-
value: response
|
|
53209
|
-
});
|
|
53210
|
-
return response;
|
|
53211
|
-
}
|
|
53212
|
-
var WINDOW_MS, BUCKET_MS, TOP_LIMIT = 5, MAX_LINES_SCANNED = 250000, CACHE_TTL_MS = 15000, metricsCache;
|
|
53213
|
-
var init_log_metrics = __esm(() => {
|
|
53214
|
-
init_config();
|
|
53215
|
-
WINDOW_MS = {
|
|
53216
|
-
"1h": 60 * 60 * 1000,
|
|
53217
|
-
"6h": 6 * 60 * 60 * 1000,
|
|
53218
|
-
"24h": 24 * 60 * 60 * 1000
|
|
53219
|
-
};
|
|
53220
|
-
BUCKET_MS = {
|
|
53221
|
-
"1h": 5 * 60 * 1000,
|
|
53222
|
-
"6h": 15 * 60 * 1000,
|
|
53223
|
-
"24h": 30 * 60 * 1000
|
|
53224
|
-
};
|
|
53225
|
-
metricsCache = new Map;
|
|
53226
|
-
});
|
|
53227
|
-
|
|
53228
|
-
// src/log-session-identity.ts
|
|
53229
|
-
function toRecord(value) {
|
|
53230
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
53231
|
-
return null;
|
|
53232
|
-
return value;
|
|
53233
|
-
}
|
|
53234
|
-
function extractUserIdRawFromRequestBody(requestBody) {
|
|
53235
|
-
const requestBodyRecord = toRecord(requestBody);
|
|
53236
|
-
const metadata = toRecord(requestBodyRecord?.metadata);
|
|
53237
|
-
if (!metadata) {
|
|
53238
|
-
return {
|
|
53239
|
-
hasMetadata: false,
|
|
53240
|
-
userIdRaw: null
|
|
53241
|
-
};
|
|
53242
|
-
}
|
|
53243
|
-
const userId = metadata.user_id;
|
|
53244
|
-
if (typeof userId !== "string" || userId.trim() === "") {
|
|
53245
|
-
return {
|
|
53246
|
-
hasMetadata: true,
|
|
53247
|
-
userIdRaw: null
|
|
53248
|
-
};
|
|
53249
|
-
}
|
|
53250
|
-
return {
|
|
53251
|
-
hasMetadata: true,
|
|
53252
|
-
userIdRaw: userId
|
|
53253
|
-
};
|
|
53254
|
-
}
|
|
53255
|
-
function parseUserSessionFromJsonFormat(userIdRaw) {
|
|
53256
|
-
let parsed;
|
|
53257
|
-
try {
|
|
53258
|
-
parsed = JSON.parse(userIdRaw);
|
|
53259
|
-
} catch {
|
|
53260
|
-
return null;
|
|
53261
|
-
}
|
|
53262
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
53263
|
-
return null;
|
|
53264
|
-
const obj = parsed;
|
|
53265
|
-
const sessionId = typeof obj.session_id === "string" ? obj.session_id.trim() : "";
|
|
53266
|
-
if (!sessionId)
|
|
53267
|
-
return null;
|
|
53268
|
-
const userKey = (typeof obj.account_uuid === "string" ? obj.account_uuid.trim() : "") || (typeof obj.device_id === "string" ? obj.device_id.trim() : "");
|
|
53269
|
-
return { userKey: userKey || sessionId, sessionId };
|
|
53270
|
-
}
|
|
53271
|
-
function parseUserSessionFromUserIdRaw(userIdRaw) {
|
|
53272
|
-
if (userIdRaw.trimStart().startsWith("{")) {
|
|
53273
|
-
return parseUserSessionFromJsonFormat(userIdRaw);
|
|
53274
|
-
}
|
|
53275
|
-
const index = userIdRaw.indexOf(USER_SESSION_DELIMITER);
|
|
53276
|
-
if (index <= 0)
|
|
53277
|
-
return null;
|
|
53278
|
-
const userKey = userIdRaw.slice(0, index).trim();
|
|
53279
|
-
const sessionId = userIdRaw.slice(index + USER_SESSION_DELIMITER.length).trim();
|
|
53280
|
-
if (!userKey || !sessionId)
|
|
53281
|
-
return null;
|
|
53282
|
-
return { userKey, sessionId };
|
|
53283
|
-
}
|
|
53284
|
-
function resolveLogSessionIdentity(requestBody) {
|
|
53285
|
-
const { hasMetadata, userIdRaw } = extractUserIdRawFromRequestBody(requestBody);
|
|
53286
|
-
if (!userIdRaw) {
|
|
53287
|
-
return {
|
|
53288
|
-
hasMetadata,
|
|
53289
|
-
userIdRaw: null,
|
|
53290
|
-
userKey: null,
|
|
53291
|
-
sessionId: null
|
|
53292
|
-
};
|
|
53293
|
-
}
|
|
53294
|
-
const parsed = parseUserSessionFromUserIdRaw(userIdRaw);
|
|
53295
|
-
return {
|
|
53296
|
-
hasMetadata,
|
|
53297
|
-
userIdRaw,
|
|
53298
|
-
userKey: parsed?.userKey ?? null,
|
|
53299
|
-
sessionId: parsed?.sessionId ?? null
|
|
53300
|
-
};
|
|
53301
|
-
}
|
|
53302
|
-
var USER_SESSION_DELIMITER = "_account__session_";
|
|
53303
|
-
|
|
53304
52925
|
// src/token-usage.ts
|
|
53305
|
-
import { existsSync as
|
|
52926
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6, statSync } from "fs";
|
|
53306
52927
|
import { resolve as resolve5 } from "path";
|
|
53307
52928
|
function asRecord(value) {
|
|
53308
52929
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
@@ -53395,7 +53016,7 @@ function inferProviderStyle(usage, providerHint) {
|
|
|
53395
53016
|
}
|
|
53396
53017
|
return "unknown";
|
|
53397
53018
|
}
|
|
53398
|
-
function
|
|
53019
|
+
function createEmptyMetrics(input) {
|
|
53399
53020
|
return {
|
|
53400
53021
|
schemaVersion: 1,
|
|
53401
53022
|
source: input.source,
|
|
@@ -53451,7 +53072,7 @@ function hasAnyTokenSignal(metrics) {
|
|
|
53451
53072
|
function normalizeUsageObject(input) {
|
|
53452
53073
|
const { usage, source, rawUsagePath, providerHint } = input;
|
|
53453
53074
|
const providerStyle = inferProviderStyle(usage, providerHint);
|
|
53454
|
-
const metrics =
|
|
53075
|
+
const metrics = createEmptyMetrics({
|
|
53455
53076
|
source,
|
|
53456
53077
|
providerStyle,
|
|
53457
53078
|
rawUsage: usage,
|
|
@@ -53824,7 +53445,7 @@ function safeReadStreamFile(streamFile, baseDir) {
|
|
|
53824
53445
|
const resolved = resolve5(candidate);
|
|
53825
53446
|
if (!resolved.endsWith(".sse.raw"))
|
|
53826
53447
|
continue;
|
|
53827
|
-
if (!
|
|
53448
|
+
if (!existsSync4(resolved))
|
|
53828
53449
|
continue;
|
|
53829
53450
|
const stats = statSync(resolved);
|
|
53830
53451
|
if (stats.size > MAX_STREAM_USAGE_BYTES) {
|
|
@@ -53884,6 +53505,435 @@ var init_token_usage = __esm(() => {
|
|
|
53884
53505
|
MAX_STREAM_USAGE_BYTES = 25 * 1024 * 1024;
|
|
53885
53506
|
});
|
|
53886
53507
|
|
|
53508
|
+
// src/log-metrics.ts
|
|
53509
|
+
import { createReadStream, existsSync as existsSync5 } from "fs";
|
|
53510
|
+
import { join as join6 } from "path";
|
|
53511
|
+
import { createInterface } from "readline";
|
|
53512
|
+
function isLogMetricsWindow(value) {
|
|
53513
|
+
return value === "1h" || value === "6h" || value === "24h";
|
|
53514
|
+
}
|
|
53515
|
+
function toPercent(numerator, denominator) {
|
|
53516
|
+
if (denominator <= 0)
|
|
53517
|
+
return 0;
|
|
53518
|
+
return Number((numerator / denominator * 100).toFixed(2));
|
|
53519
|
+
}
|
|
53520
|
+
function toDayStart(ms) {
|
|
53521
|
+
const date5 = new Date(ms);
|
|
53522
|
+
return Date.UTC(date5.getUTCFullYear(), date5.getUTCMonth(), date5.getUTCDate());
|
|
53523
|
+
}
|
|
53524
|
+
function listDateStrings(fromMs, toMs) {
|
|
53525
|
+
const result = [];
|
|
53526
|
+
for (let day = toDayStart(fromMs);day <= toDayStart(toMs); day += 24 * 60 * 60 * 1000) {
|
|
53527
|
+
result.push(new Date(day).toISOString().slice(0, 10));
|
|
53528
|
+
}
|
|
53529
|
+
return result;
|
|
53530
|
+
}
|
|
53531
|
+
function getStatusClass(event) {
|
|
53532
|
+
if (event.error_type)
|
|
53533
|
+
return "network_error";
|
|
53534
|
+
const status = event.upstream_status ?? 0;
|
|
53535
|
+
if (status >= 200 && status < 300)
|
|
53536
|
+
return "2xx";
|
|
53537
|
+
if (status >= 400 && status < 500)
|
|
53538
|
+
return "4xx";
|
|
53539
|
+
if (status >= 500)
|
|
53540
|
+
return "5xx";
|
|
53541
|
+
return "network_error";
|
|
53542
|
+
}
|
|
53543
|
+
function isErrorEvent(event) {
|
|
53544
|
+
if (event.error_type)
|
|
53545
|
+
return true;
|
|
53546
|
+
const status = event.upstream_status ?? 0;
|
|
53547
|
+
return status < 200 || status >= 400;
|
|
53548
|
+
}
|
|
53549
|
+
function percentile(sortedNumbers, ratio) {
|
|
53550
|
+
if (sortedNumbers.length === 0)
|
|
53551
|
+
return 0;
|
|
53552
|
+
const index = Math.min(sortedNumbers.length - 1, Math.ceil(sortedNumbers.length * ratio) - 1);
|
|
53553
|
+
return Math.round(sortedNumbers[index]);
|
|
53554
|
+
}
|
|
53555
|
+
function createEmptyMetrics2(window2, nowMs, source, warnings = []) {
|
|
53556
|
+
const fromMs = nowMs - WINDOW_MS[window2];
|
|
53557
|
+
const bucketMs = BUCKET_MS[window2];
|
|
53558
|
+
const bucketCount = Math.max(1, Math.ceil((nowMs - fromMs) / bucketMs));
|
|
53559
|
+
const series = Array.from({ length: bucketCount }, (_, i) => ({
|
|
53560
|
+
ts: new Date(fromMs + i * bucketMs).toISOString(),
|
|
53561
|
+
requests: 0,
|
|
53562
|
+
errors: 0,
|
|
53563
|
+
avgLatencyMs: 0
|
|
53564
|
+
}));
|
|
53565
|
+
return {
|
|
53566
|
+
window: window2,
|
|
53567
|
+
from: new Date(fromMs).toISOString(),
|
|
53568
|
+
to: new Date(nowMs).toISOString(),
|
|
53569
|
+
generatedAt: new Date(nowMs).toISOString(),
|
|
53570
|
+
source,
|
|
53571
|
+
summary: {
|
|
53572
|
+
totalRequests: 0,
|
|
53573
|
+
successRequests: 0,
|
|
53574
|
+
errorRequests: 0,
|
|
53575
|
+
successRate: 0,
|
|
53576
|
+
avgLatencyMs: 0,
|
|
53577
|
+
p95LatencyMs: 0,
|
|
53578
|
+
totalRequestBytes: 0,
|
|
53579
|
+
totalResponseBytes: 0
|
|
53580
|
+
},
|
|
53581
|
+
tokens: {
|
|
53582
|
+
usageCount: 0,
|
|
53583
|
+
inputTokens: 0,
|
|
53584
|
+
outputTokens: 0,
|
|
53585
|
+
totalTokens: 0,
|
|
53586
|
+
cachedInputTokens: 0,
|
|
53587
|
+
cacheHitInputTokens: 0,
|
|
53588
|
+
cacheHitRateDenominatorTokens: 0,
|
|
53589
|
+
cacheHitRate: 0,
|
|
53590
|
+
reasoningTokens: 0,
|
|
53591
|
+
cost: null
|
|
53592
|
+
},
|
|
53593
|
+
series,
|
|
53594
|
+
topProviders: [],
|
|
53595
|
+
topRouteTypes: [],
|
|
53596
|
+
statusClasses: {
|
|
53597
|
+
"2xx": 0,
|
|
53598
|
+
"4xx": 0,
|
|
53599
|
+
"5xx": 0,
|
|
53600
|
+
network_error: 0
|
|
53601
|
+
},
|
|
53602
|
+
warnings
|
|
53603
|
+
};
|
|
53604
|
+
}
|
|
53605
|
+
async function getLogMetrics(options) {
|
|
53606
|
+
const window2 = options.window ?? "24h";
|
|
53607
|
+
const refresh = options.refresh === true;
|
|
53608
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
53609
|
+
const logEnabled = options.logConfig?.enabled !== false && !!options.logConfig;
|
|
53610
|
+
if (!logEnabled) {
|
|
53611
|
+
return createEmptyMetrics2(window2, nowMs, {
|
|
53612
|
+
logEnabled: false,
|
|
53613
|
+
baseDir: null,
|
|
53614
|
+
filesScanned: 0,
|
|
53615
|
+
linesScanned: 0,
|
|
53616
|
+
partial: false
|
|
53617
|
+
}, ["\u65E5\u5FD7\u672A\u542F\u7528"]);
|
|
53618
|
+
}
|
|
53619
|
+
const baseDir = resolveLogBaseDir(options.logConfig);
|
|
53620
|
+
const cacheKey = `${baseDir}:${window2}`;
|
|
53621
|
+
const cached2 = metricsCache.get(cacheKey);
|
|
53622
|
+
if (!refresh && cached2 && cached2.expiresAt > nowMs) {
|
|
53623
|
+
return cached2.value;
|
|
53624
|
+
}
|
|
53625
|
+
const eventsDir = join6(baseDir, "events");
|
|
53626
|
+
if (!existsSync5(eventsDir)) {
|
|
53627
|
+
const empty = createEmptyMetrics2(window2, nowMs, {
|
|
53628
|
+
logEnabled: true,
|
|
53629
|
+
baseDir,
|
|
53630
|
+
filesScanned: 0,
|
|
53631
|
+
linesScanned: 0,
|
|
53632
|
+
partial: false
|
|
53633
|
+
}, ["\u65E5\u5FD7\u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u6682\u65E0\u53EF\u5206\u6790\u6570\u636E"]);
|
|
53634
|
+
metricsCache.set(cacheKey, { expiresAt: nowMs + CACHE_TTL_MS, value: empty });
|
|
53635
|
+
return empty;
|
|
53636
|
+
}
|
|
53637
|
+
const fromMs = nowMs - WINDOW_MS[window2];
|
|
53638
|
+
const bucketMs = BUCKET_MS[window2];
|
|
53639
|
+
const bucketCount = Math.max(1, Math.ceil((nowMs - fromMs) / bucketMs));
|
|
53640
|
+
const buckets = Array.from({ length: bucketCount }, () => ({
|
|
53641
|
+
requests: 0,
|
|
53642
|
+
errors: 0,
|
|
53643
|
+
latencySum: 0,
|
|
53644
|
+
latencyCount: 0
|
|
53645
|
+
}));
|
|
53646
|
+
const providerAgg = new Map;
|
|
53647
|
+
const routeTypeAgg = new Map;
|
|
53648
|
+
const latencies = [];
|
|
53649
|
+
const statusClasses = {
|
|
53650
|
+
"2xx": 0,
|
|
53651
|
+
"4xx": 0,
|
|
53652
|
+
"5xx": 0,
|
|
53653
|
+
network_error: 0
|
|
53654
|
+
};
|
|
53655
|
+
let filesScanned = 0;
|
|
53656
|
+
let linesScanned = 0;
|
|
53657
|
+
let parseErrors = 0;
|
|
53658
|
+
let partial2 = false;
|
|
53659
|
+
let totalRequests = 0;
|
|
53660
|
+
let successRequests = 0;
|
|
53661
|
+
let errorRequests = 0;
|
|
53662
|
+
let totalLatency = 0;
|
|
53663
|
+
let totalRequestBytes = 0;
|
|
53664
|
+
let totalResponseBytes = 0;
|
|
53665
|
+
let tokenUsageCount = 0;
|
|
53666
|
+
let tokenInput = 0;
|
|
53667
|
+
let tokenOutput = 0;
|
|
53668
|
+
let tokenTotal = 0;
|
|
53669
|
+
let tokenCachedInput = 0;
|
|
53670
|
+
let tokenCacheHitInput = 0;
|
|
53671
|
+
let tokenCacheHitDenominator = 0;
|
|
53672
|
+
let tokenReasoning = 0;
|
|
53673
|
+
let tokenCost = 0;
|
|
53674
|
+
let tokenCostSeen = false;
|
|
53675
|
+
const warnings = [];
|
|
53676
|
+
const dateStrings = listDateStrings(fromMs, nowMs);
|
|
53677
|
+
for (const dateStr of dateStrings) {
|
|
53678
|
+
if (linesScanned >= MAX_LINES_SCANNED) {
|
|
53679
|
+
partial2 = true;
|
|
53680
|
+
break;
|
|
53681
|
+
}
|
|
53682
|
+
const filePath = join6(eventsDir, `${dateStr}.jsonl`);
|
|
53683
|
+
if (!existsSync5(filePath))
|
|
53684
|
+
continue;
|
|
53685
|
+
filesScanned += 1;
|
|
53686
|
+
try {
|
|
53687
|
+
const stream = createReadStream(filePath, { encoding: "utf-8" });
|
|
53688
|
+
const rl = createInterface({ input: stream, crlfDelay: Number.POSITIVE_INFINITY });
|
|
53689
|
+
for await (const line of rl) {
|
|
53690
|
+
if (linesScanned >= MAX_LINES_SCANNED) {
|
|
53691
|
+
partial2 = true;
|
|
53692
|
+
rl.close();
|
|
53693
|
+
stream.destroy();
|
|
53694
|
+
break;
|
|
53695
|
+
}
|
|
53696
|
+
linesScanned += 1;
|
|
53697
|
+
if (!line.trim())
|
|
53698
|
+
continue;
|
|
53699
|
+
let event;
|
|
53700
|
+
try {
|
|
53701
|
+
event = JSON.parse(line);
|
|
53702
|
+
} catch {
|
|
53703
|
+
parseErrors += 1;
|
|
53704
|
+
continue;
|
|
53705
|
+
}
|
|
53706
|
+
if (!event.ts_start)
|
|
53707
|
+
continue;
|
|
53708
|
+
const ts = Date.parse(event.ts_start);
|
|
53709
|
+
if (!Number.isFinite(ts) || ts < fromMs || ts > nowMs)
|
|
53710
|
+
continue;
|
|
53711
|
+
totalRequests += 1;
|
|
53712
|
+
const isError = isErrorEvent(event);
|
|
53713
|
+
if (isError) {
|
|
53714
|
+
errorRequests += 1;
|
|
53715
|
+
} else {
|
|
53716
|
+
successRequests += 1;
|
|
53717
|
+
}
|
|
53718
|
+
const latency = Number.isFinite(event.latency_ms) ? Math.max(0, event.latency_ms ?? 0) : 0;
|
|
53719
|
+
totalLatency += latency;
|
|
53720
|
+
latencies.push(latency);
|
|
53721
|
+
totalRequestBytes += Math.max(0, event.request_bytes ?? 0);
|
|
53722
|
+
totalResponseBytes += Math.max(0, event.response_bytes ?? 0) + Math.max(0, event.stream_bytes ?? 0);
|
|
53723
|
+
const bucketIndex = Math.min(bucketCount - 1, Math.max(0, Math.floor((ts - fromMs) / bucketMs)));
|
|
53724
|
+
const bucket = buckets[bucketIndex];
|
|
53725
|
+
bucket.requests += 1;
|
|
53726
|
+
bucket.latencySum += latency;
|
|
53727
|
+
bucket.latencyCount += 1;
|
|
53728
|
+
if (isError)
|
|
53729
|
+
bucket.errors += 1;
|
|
53730
|
+
const providerKey = event.provider || "unknown";
|
|
53731
|
+
const providerRow = providerAgg.get(providerKey) ?? {
|
|
53732
|
+
requests: 0,
|
|
53733
|
+
errors: 0,
|
|
53734
|
+
latencySum: 0
|
|
53735
|
+
};
|
|
53736
|
+
providerRow.requests += 1;
|
|
53737
|
+
providerRow.latencySum += latency;
|
|
53738
|
+
if (isError)
|
|
53739
|
+
providerRow.errors += 1;
|
|
53740
|
+
providerAgg.set(providerKey, providerRow);
|
|
53741
|
+
const routeTypeKey = event.route_type || "unknown";
|
|
53742
|
+
const routeTypeRow = routeTypeAgg.get(routeTypeKey) ?? {
|
|
53743
|
+
requests: 0,
|
|
53744
|
+
errors: 0,
|
|
53745
|
+
latencySum: 0
|
|
53746
|
+
};
|
|
53747
|
+
routeTypeRow.requests += 1;
|
|
53748
|
+
routeTypeRow.latencySum += latency;
|
|
53749
|
+
if (isError)
|
|
53750
|
+
routeTypeRow.errors += 1;
|
|
53751
|
+
routeTypeAgg.set(routeTypeKey, routeTypeRow);
|
|
53752
|
+
statusClasses[getStatusClass(event)] += 1;
|
|
53753
|
+
const usage = extractTokenUsageSummaryFromLogEvent(event, { baseDir });
|
|
53754
|
+
if (usage) {
|
|
53755
|
+
tokenUsageCount += 1;
|
|
53756
|
+
tokenInput += Math.max(0, usage.inputTokens ?? 0);
|
|
53757
|
+
tokenOutput += Math.max(0, usage.outputTokens ?? 0);
|
|
53758
|
+
tokenTotal += Math.max(0, usage.totalTokens ?? 0);
|
|
53759
|
+
tokenCachedInput += Math.max(0, usage.cachedInputTokens ?? 0);
|
|
53760
|
+
tokenCacheHitInput += Math.max(0, usage.cacheHitInputTokens ?? 0);
|
|
53761
|
+
tokenCacheHitDenominator += Math.max(0, usage.cacheHitRateDenominatorTokens ?? 0);
|
|
53762
|
+
tokenReasoning += Math.max(0, usage.reasoningTokens ?? 0);
|
|
53763
|
+
if (typeof usage.cost === "number" && Number.isFinite(usage.cost)) {
|
|
53764
|
+
tokenCost += usage.cost;
|
|
53765
|
+
tokenCostSeen = true;
|
|
53766
|
+
}
|
|
53767
|
+
}
|
|
53768
|
+
}
|
|
53769
|
+
} catch (err) {
|
|
53770
|
+
warnings.push(`\u8BFB\u53D6\u65E5\u5FD7\u6587\u4EF6\u5931\u8D25: ${filePath} (${err instanceof Error ? err.message : String(err)})`);
|
|
53771
|
+
partial2 = true;
|
|
53772
|
+
}
|
|
53773
|
+
}
|
|
53774
|
+
if (parseErrors > 0) {
|
|
53775
|
+
warnings.push(`\u5DF2\u8DF3\u8FC7 ${parseErrors} \u884C\u65E0\u6548 JSON \u65E5\u5FD7`);
|
|
53776
|
+
}
|
|
53777
|
+
if (partial2) {
|
|
53778
|
+
warnings.push("\u65E5\u5FD7\u626B\u63CF\u5DF2\u90E8\u5206\u622A\u65AD\uFF0C\u7ED3\u679C\u53EF\u80FD\u4E0D\u5B8C\u6574");
|
|
53779
|
+
}
|
|
53780
|
+
latencies.sort((a, b) => a - b);
|
|
53781
|
+
const series = buckets.map((bucket, index) => ({
|
|
53782
|
+
ts: new Date(fromMs + index * bucketMs).toISOString(),
|
|
53783
|
+
requests: bucket.requests,
|
|
53784
|
+
errors: bucket.errors,
|
|
53785
|
+
avgLatencyMs: bucket.latencyCount > 0 ? Math.round(bucket.latencySum / bucket.latencyCount) : 0
|
|
53786
|
+
}));
|
|
53787
|
+
const topProviders = Array.from(providerAgg.entries()).map(([key, row]) => ({
|
|
53788
|
+
key,
|
|
53789
|
+
requests: row.requests,
|
|
53790
|
+
errorRate: toPercent(row.errors, row.requests),
|
|
53791
|
+
avgLatencyMs: row.requests > 0 ? Math.round(row.latencySum / row.requests) : 0
|
|
53792
|
+
})).sort((a, b) => b.requests - a.requests).slice(0, TOP_LIMIT);
|
|
53793
|
+
const topRouteTypes = Array.from(routeTypeAgg.entries()).map(([key, row]) => ({
|
|
53794
|
+
key,
|
|
53795
|
+
requests: row.requests,
|
|
53796
|
+
errorRate: toPercent(row.errors, row.requests)
|
|
53797
|
+
})).sort((a, b) => b.requests - a.requests).slice(0, TOP_LIMIT);
|
|
53798
|
+
const response = {
|
|
53799
|
+
window: window2,
|
|
53800
|
+
from: new Date(fromMs).toISOString(),
|
|
53801
|
+
to: new Date(nowMs).toISOString(),
|
|
53802
|
+
generatedAt: new Date(nowMs).toISOString(),
|
|
53803
|
+
source: {
|
|
53804
|
+
logEnabled: true,
|
|
53805
|
+
baseDir,
|
|
53806
|
+
filesScanned,
|
|
53807
|
+
linesScanned,
|
|
53808
|
+
partial: partial2
|
|
53809
|
+
},
|
|
53810
|
+
summary: {
|
|
53811
|
+
totalRequests,
|
|
53812
|
+
successRequests,
|
|
53813
|
+
errorRequests,
|
|
53814
|
+
successRate: toPercent(successRequests, totalRequests),
|
|
53815
|
+
avgLatencyMs: totalRequests > 0 ? Math.round(totalLatency / totalRequests) : 0,
|
|
53816
|
+
p95LatencyMs: percentile(latencies, 0.95),
|
|
53817
|
+
totalRequestBytes,
|
|
53818
|
+
totalResponseBytes
|
|
53819
|
+
},
|
|
53820
|
+
tokens: {
|
|
53821
|
+
usageCount: tokenUsageCount,
|
|
53822
|
+
inputTokens: tokenInput,
|
|
53823
|
+
outputTokens: tokenOutput,
|
|
53824
|
+
totalTokens: tokenTotal,
|
|
53825
|
+
cachedInputTokens: tokenCachedInput,
|
|
53826
|
+
cacheHitInputTokens: tokenCacheHitInput,
|
|
53827
|
+
cacheHitRateDenominatorTokens: tokenCacheHitDenominator,
|
|
53828
|
+
cacheHitRate: toPercent(tokenCacheHitInput, tokenCacheHitDenominator),
|
|
53829
|
+
reasoningTokens: tokenReasoning,
|
|
53830
|
+
cost: tokenCostSeen ? Number(tokenCost.toFixed(6)) : null
|
|
53831
|
+
},
|
|
53832
|
+
series,
|
|
53833
|
+
topProviders,
|
|
53834
|
+
topRouteTypes,
|
|
53835
|
+
statusClasses,
|
|
53836
|
+
warnings
|
|
53837
|
+
};
|
|
53838
|
+
metricsCache.set(cacheKey, {
|
|
53839
|
+
expiresAt: nowMs + CACHE_TTL_MS,
|
|
53840
|
+
value: response
|
|
53841
|
+
});
|
|
53842
|
+
return response;
|
|
53843
|
+
}
|
|
53844
|
+
var WINDOW_MS, BUCKET_MS, TOP_LIMIT = 5, MAX_LINES_SCANNED = 250000, CACHE_TTL_MS = 15000, metricsCache;
|
|
53845
|
+
var init_log_metrics = __esm(() => {
|
|
53846
|
+
init_config();
|
|
53847
|
+
init_token_usage();
|
|
53848
|
+
WINDOW_MS = {
|
|
53849
|
+
"1h": 60 * 60 * 1000,
|
|
53850
|
+
"6h": 6 * 60 * 60 * 1000,
|
|
53851
|
+
"24h": 24 * 60 * 60 * 1000
|
|
53852
|
+
};
|
|
53853
|
+
BUCKET_MS = {
|
|
53854
|
+
"1h": 5 * 60 * 1000,
|
|
53855
|
+
"6h": 15 * 60 * 1000,
|
|
53856
|
+
"24h": 30 * 60 * 1000
|
|
53857
|
+
};
|
|
53858
|
+
metricsCache = new Map;
|
|
53859
|
+
});
|
|
53860
|
+
|
|
53861
|
+
// src/log-session-identity.ts
|
|
53862
|
+
function toRecord(value) {
|
|
53863
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
53864
|
+
return null;
|
|
53865
|
+
return value;
|
|
53866
|
+
}
|
|
53867
|
+
function extractUserIdRawFromRequestBody(requestBody) {
|
|
53868
|
+
const requestBodyRecord = toRecord(requestBody);
|
|
53869
|
+
const metadata = toRecord(requestBodyRecord?.metadata);
|
|
53870
|
+
if (!metadata) {
|
|
53871
|
+
return {
|
|
53872
|
+
hasMetadata: false,
|
|
53873
|
+
userIdRaw: null
|
|
53874
|
+
};
|
|
53875
|
+
}
|
|
53876
|
+
const userId = metadata.user_id;
|
|
53877
|
+
if (typeof userId !== "string" || userId.trim() === "") {
|
|
53878
|
+
return {
|
|
53879
|
+
hasMetadata: true,
|
|
53880
|
+
userIdRaw: null
|
|
53881
|
+
};
|
|
53882
|
+
}
|
|
53883
|
+
return {
|
|
53884
|
+
hasMetadata: true,
|
|
53885
|
+
userIdRaw: userId
|
|
53886
|
+
};
|
|
53887
|
+
}
|
|
53888
|
+
function parseUserSessionFromJsonFormat(userIdRaw) {
|
|
53889
|
+
let parsed;
|
|
53890
|
+
try {
|
|
53891
|
+
parsed = JSON.parse(userIdRaw);
|
|
53892
|
+
} catch {
|
|
53893
|
+
return null;
|
|
53894
|
+
}
|
|
53895
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
53896
|
+
return null;
|
|
53897
|
+
const obj = parsed;
|
|
53898
|
+
const sessionId = typeof obj.session_id === "string" ? obj.session_id.trim() : "";
|
|
53899
|
+
if (!sessionId)
|
|
53900
|
+
return null;
|
|
53901
|
+
const userKey = (typeof obj.account_uuid === "string" ? obj.account_uuid.trim() : "") || (typeof obj.device_id === "string" ? obj.device_id.trim() : "");
|
|
53902
|
+
return { userKey: userKey || sessionId, sessionId };
|
|
53903
|
+
}
|
|
53904
|
+
function parseUserSessionFromUserIdRaw(userIdRaw) {
|
|
53905
|
+
if (userIdRaw.trimStart().startsWith("{")) {
|
|
53906
|
+
return parseUserSessionFromJsonFormat(userIdRaw);
|
|
53907
|
+
}
|
|
53908
|
+
const index = userIdRaw.indexOf(USER_SESSION_DELIMITER);
|
|
53909
|
+
if (index <= 0)
|
|
53910
|
+
return null;
|
|
53911
|
+
const userKey = userIdRaw.slice(0, index).trim();
|
|
53912
|
+
const sessionId = userIdRaw.slice(index + USER_SESSION_DELIMITER.length).trim();
|
|
53913
|
+
if (!userKey || !sessionId)
|
|
53914
|
+
return null;
|
|
53915
|
+
return { userKey, sessionId };
|
|
53916
|
+
}
|
|
53917
|
+
function resolveLogSessionIdentity(requestBody) {
|
|
53918
|
+
const { hasMetadata, userIdRaw } = extractUserIdRawFromRequestBody(requestBody);
|
|
53919
|
+
if (!userIdRaw) {
|
|
53920
|
+
return {
|
|
53921
|
+
hasMetadata,
|
|
53922
|
+
userIdRaw: null,
|
|
53923
|
+
userKey: null,
|
|
53924
|
+
sessionId: null
|
|
53925
|
+
};
|
|
53926
|
+
}
|
|
53927
|
+
const parsed = parseUserSessionFromUserIdRaw(userIdRaw);
|
|
53928
|
+
return {
|
|
53929
|
+
hasMetadata,
|
|
53930
|
+
userIdRaw,
|
|
53931
|
+
userKey: parsed?.userKey ?? null,
|
|
53932
|
+
sessionId: parsed?.sessionId ?? null
|
|
53933
|
+
};
|
|
53934
|
+
}
|
|
53935
|
+
var USER_SESSION_DELIMITER = "_account__session_";
|
|
53936
|
+
|
|
53887
53937
|
// src/log-index.ts
|
|
53888
53938
|
import { Database } from "bun:sqlite";
|
|
53889
53939
|
import {
|
|
@@ -54275,6 +54325,31 @@ function buildWhereClause(query, options = {}) {
|
|
|
54275
54325
|
usesFts
|
|
54276
54326
|
};
|
|
54277
54327
|
}
|
|
54328
|
+
function buildSessionsWhereClause(query) {
|
|
54329
|
+
const pseudo = {
|
|
54330
|
+
fromMs: query.fromMs,
|
|
54331
|
+
toMs: query.toMs,
|
|
54332
|
+
levels: [],
|
|
54333
|
+
providers: [],
|
|
54334
|
+
routeTypes: [],
|
|
54335
|
+
models: [],
|
|
54336
|
+
modelIns: [],
|
|
54337
|
+
modelOuts: [],
|
|
54338
|
+
users: query.users,
|
|
54339
|
+
sessions: query.sessions,
|
|
54340
|
+
statusClasses: [],
|
|
54341
|
+
hasError: null,
|
|
54342
|
+
q: query.q,
|
|
54343
|
+
sort: "time_desc",
|
|
54344
|
+
limit: 1,
|
|
54345
|
+
cursor: null
|
|
54346
|
+
};
|
|
54347
|
+
const { whereSql, params } = buildWhereClause(pseudo);
|
|
54348
|
+
return { whereSql, params };
|
|
54349
|
+
}
|
|
54350
|
+
function sortIndexedCountItems(map2) {
|
|
54351
|
+
return Array.from(map2.entries()).map(([key, count]) => ({ key, count })).sort((a, b) => b.count - a.count || a.key.localeCompare(b.key));
|
|
54352
|
+
}
|
|
54278
54353
|
|
|
54279
54354
|
class LogIndex {
|
|
54280
54355
|
baseDir;
|
|
@@ -54482,6 +54557,163 @@ class LogIndex {
|
|
|
54482
54557
|
}
|
|
54483
54558
|
};
|
|
54484
54559
|
}
|
|
54560
|
+
querySessions(query) {
|
|
54561
|
+
const startedAt = performance.now();
|
|
54562
|
+
const { whereSql, params } = buildSessionsWhereClause(query);
|
|
54563
|
+
const aggregatedWhere = `${whereSql} AND e.user_key IS NOT NULL AND e.session_id IS NOT NULL`;
|
|
54564
|
+
const summaryRow = this.db.query(`
|
|
54565
|
+
SELECT
|
|
54566
|
+
COUNT(*) AS totalRequests,
|
|
54567
|
+
COALESCE(SUM(has_metadata), 0) AS metadataRequests,
|
|
54568
|
+
COUNT(DISTINCT user_key) AS uniqueUsers,
|
|
54569
|
+
COUNT(DISTINCT CASE
|
|
54570
|
+
WHEN user_key IS NOT NULL AND session_id IS NOT NULL
|
|
54571
|
+
THEN user_key || ' ' || session_id
|
|
54572
|
+
END) AS uniqueSessions
|
|
54573
|
+
FROM log_events e
|
|
54574
|
+
${whereSql}
|
|
54575
|
+
`).get(...params);
|
|
54576
|
+
const userRows = this.db.query(`
|
|
54577
|
+
SELECT
|
|
54578
|
+
user_key AS userKey,
|
|
54579
|
+
COUNT(*) AS requestCount,
|
|
54580
|
+
MIN(ts_ms) AS firstMs,
|
|
54581
|
+
MAX(ts_ms) AS lastMs,
|
|
54582
|
+
COUNT(DISTINCT session_id) AS sessionCount
|
|
54583
|
+
FROM log_events e
|
|
54584
|
+
${aggregatedWhere}
|
|
54585
|
+
GROUP BY user_key
|
|
54586
|
+
`).all(...params);
|
|
54587
|
+
const sessionRows = this.db.query(`
|
|
54588
|
+
SELECT
|
|
54589
|
+
user_key AS userKey,
|
|
54590
|
+
session_id AS sessionId,
|
|
54591
|
+
COUNT(*) AS requestCount,
|
|
54592
|
+
MIN(ts_ms) AS firstMs,
|
|
54593
|
+
MAX(ts_ms) AS lastMs
|
|
54594
|
+
FROM log_events e
|
|
54595
|
+
${aggregatedWhere}
|
|
54596
|
+
GROUP BY user_key, session_id
|
|
54597
|
+
`).all(...params);
|
|
54598
|
+
const userModelRows = this.db.query(`
|
|
54599
|
+
SELECT user_key AS userKey, model AS key, COUNT(*) AS count
|
|
54600
|
+
FROM log_events e
|
|
54601
|
+
${aggregatedWhere}
|
|
54602
|
+
GROUP BY user_key, model
|
|
54603
|
+
`).all(...params);
|
|
54604
|
+
const userProviderRows = this.db.query(`
|
|
54605
|
+
SELECT user_key AS userKey, provider AS key, COUNT(*) AS count
|
|
54606
|
+
FROM log_events e
|
|
54607
|
+
${aggregatedWhere}
|
|
54608
|
+
GROUP BY user_key, provider
|
|
54609
|
+
`).all(...params);
|
|
54610
|
+
const userRouteRows = this.db.query(`
|
|
54611
|
+
SELECT user_key AS userKey, route_type AS key, COUNT(*) AS count
|
|
54612
|
+
FROM log_events e
|
|
54613
|
+
${aggregatedWhere}
|
|
54614
|
+
GROUP BY user_key, route_type
|
|
54615
|
+
`).all(...params);
|
|
54616
|
+
const sessionModelRows = this.db.query(`
|
|
54617
|
+
SELECT user_key AS userKey, session_id AS sessionId, model AS key, COUNT(*) AS count
|
|
54618
|
+
FROM log_events e
|
|
54619
|
+
${aggregatedWhere}
|
|
54620
|
+
GROUP BY user_key, session_id, model
|
|
54621
|
+
`).all(...params);
|
|
54622
|
+
const latestRows = this.db.query(`
|
|
54623
|
+
SELECT userKey, sessionId, request_id AS latestRequestId
|
|
54624
|
+
FROM (
|
|
54625
|
+
SELECT
|
|
54626
|
+
user_key AS userKey,
|
|
54627
|
+
session_id AS sessionId,
|
|
54628
|
+
request_id,
|
|
54629
|
+
ROW_NUMBER() OVER (
|
|
54630
|
+
PARTITION BY user_key, session_id ORDER BY ts_ms DESC, id DESC
|
|
54631
|
+
) AS rn
|
|
54632
|
+
FROM log_events e
|
|
54633
|
+
${aggregatedWhere}
|
|
54634
|
+
)
|
|
54635
|
+
WHERE rn = 1
|
|
54636
|
+
`).all(...params);
|
|
54637
|
+
const userModels = new Map;
|
|
54638
|
+
const userProviders = new Map;
|
|
54639
|
+
const userRoutes = new Map;
|
|
54640
|
+
const sessionModels = new Map;
|
|
54641
|
+
const latestBySession = new Map;
|
|
54642
|
+
const addCount = (target, groupKey, key, count) => {
|
|
54643
|
+
if (!key)
|
|
54644
|
+
return;
|
|
54645
|
+
let inner = target.get(groupKey);
|
|
54646
|
+
if (!inner) {
|
|
54647
|
+
inner = new Map;
|
|
54648
|
+
target.set(groupKey, inner);
|
|
54649
|
+
}
|
|
54650
|
+
inner.set(key, count);
|
|
54651
|
+
};
|
|
54652
|
+
for (const row of userModelRows)
|
|
54653
|
+
addCount(userModels, row.userKey, row.key, row.count);
|
|
54654
|
+
for (const row of userProviderRows)
|
|
54655
|
+
addCount(userProviders, row.userKey, row.key, row.count);
|
|
54656
|
+
for (const row of userRouteRows)
|
|
54657
|
+
addCount(userRoutes, row.userKey, row.key, row.count);
|
|
54658
|
+
for (const row of sessionModelRows) {
|
|
54659
|
+
addCount(sessionModels, `${row.userKey}\x00${row.sessionId}`, row.key, row.count);
|
|
54660
|
+
}
|
|
54661
|
+
for (const row of latestRows) {
|
|
54662
|
+
latestBySession.set(`${row.userKey}\x00${row.sessionId}`, row.latestRequestId);
|
|
54663
|
+
}
|
|
54664
|
+
const sessionsByUser = new Map;
|
|
54665
|
+
for (const row of sessionRows) {
|
|
54666
|
+
const sessionKey = `${row.userKey}\x00${row.sessionId}`;
|
|
54667
|
+
const session = {
|
|
54668
|
+
sessionId: row.sessionId,
|
|
54669
|
+
requestCount: row.requestCount,
|
|
54670
|
+
firstSeenAt: new Date(row.firstMs).toISOString(),
|
|
54671
|
+
lastSeenAt: new Date(row.lastMs).toISOString(),
|
|
54672
|
+
models: sortIndexedCountItems(sessionModels.get(sessionKey) ?? new Map),
|
|
54673
|
+
latestRequestId: latestBySession.get(sessionKey) ?? ""
|
|
54674
|
+
};
|
|
54675
|
+
const list = sessionsByUser.get(row.userKey);
|
|
54676
|
+
if (list) {
|
|
54677
|
+
list.push(session);
|
|
54678
|
+
} else {
|
|
54679
|
+
sessionsByUser.set(row.userKey, [session]);
|
|
54680
|
+
}
|
|
54681
|
+
}
|
|
54682
|
+
const users = userRows.map((row) => {
|
|
54683
|
+
const sessions = (sessionsByUser.get(row.userKey) ?? []).sort((a, b) => {
|
|
54684
|
+
if (a.requestCount !== b.requestCount)
|
|
54685
|
+
return b.requestCount - a.requestCount;
|
|
54686
|
+
return Date.parse(b.lastSeenAt) - Date.parse(a.lastSeenAt);
|
|
54687
|
+
});
|
|
54688
|
+
return {
|
|
54689
|
+
userKey: row.userKey,
|
|
54690
|
+
requestCount: row.requestCount,
|
|
54691
|
+
sessionCount: row.sessionCount,
|
|
54692
|
+
firstSeenAt: new Date(row.firstMs).toISOString(),
|
|
54693
|
+
lastSeenAt: new Date(row.lastMs).toISOString(),
|
|
54694
|
+
models: sortIndexedCountItems(userModels.get(row.userKey) ?? new Map),
|
|
54695
|
+
providers: sortIndexedCountItems(userProviders.get(row.userKey) ?? new Map),
|
|
54696
|
+
routeTypes: sortIndexedCountItems(userRoutes.get(row.userKey) ?? new Map),
|
|
54697
|
+
sessions
|
|
54698
|
+
};
|
|
54699
|
+
}).sort((a, b) => {
|
|
54700
|
+
if (a.requestCount !== b.requestCount)
|
|
54701
|
+
return b.requestCount - a.requestCount;
|
|
54702
|
+
return Date.parse(b.lastSeenAt) - Date.parse(a.lastSeenAt);
|
|
54703
|
+
});
|
|
54704
|
+
return {
|
|
54705
|
+
from: new Date(query.fromMs).toISOString(),
|
|
54706
|
+
to: new Date(query.toMs).toISOString(),
|
|
54707
|
+
summary: {
|
|
54708
|
+
totalRequests: Number(summaryRow.totalRequests) || 0,
|
|
54709
|
+
metadataRequests: Number(summaryRow.metadataRequests) || 0,
|
|
54710
|
+
uniqueUsers: Number(summaryRow.uniqueUsers) || 0,
|
|
54711
|
+
uniqueSessions: Number(summaryRow.uniqueSessions) || 0
|
|
54712
|
+
},
|
|
54713
|
+
users,
|
|
54714
|
+
queryMs: Math.round((performance.now() - startedAt) * 100) / 100
|
|
54715
|
+
};
|
|
54716
|
+
}
|
|
54485
54717
|
configure() {
|
|
54486
54718
|
this.db.exec(`
|
|
54487
54719
|
PRAGMA journal_mode = WAL;
|
|
@@ -54864,6 +55096,65 @@ async function queryIndexedLogEvents(logConfig, query) {
|
|
|
54864
55096
|
};
|
|
54865
55097
|
}
|
|
54866
55098
|
}
|
|
55099
|
+
async function queryIndexedLogSessions(logConfig, query) {
|
|
55100
|
+
if (!logConfig || logConfig.enabled === false) {
|
|
55101
|
+
return {
|
|
55102
|
+
from: new Date(query.fromMs).toISOString(),
|
|
55103
|
+
to: new Date(query.toMs).toISOString(),
|
|
55104
|
+
summary: { totalRequests: 0, metadataRequests: 0, uniqueUsers: 0, uniqueSessions: 0 },
|
|
55105
|
+
users: [],
|
|
55106
|
+
meta: {
|
|
55107
|
+
scannedFiles: 0,
|
|
55108
|
+
scannedLines: 0,
|
|
55109
|
+
parseErrors: 0,
|
|
55110
|
+
truncated: false,
|
|
55111
|
+
indexUsed: true,
|
|
55112
|
+
indexFresh: true,
|
|
55113
|
+
queryMs: 0
|
|
55114
|
+
}
|
|
55115
|
+
};
|
|
55116
|
+
}
|
|
55117
|
+
const baseDir = resolveLogBaseDir(logConfig);
|
|
55118
|
+
const index = getLogIndex(baseDir);
|
|
55119
|
+
if (!index)
|
|
55120
|
+
return null;
|
|
55121
|
+
try {
|
|
55122
|
+
const freshness = await index.ensureRangeIndexed(query.fromMs, query.toMs);
|
|
55123
|
+
const result = index.querySessions(query);
|
|
55124
|
+
return {
|
|
55125
|
+
from: result.from,
|
|
55126
|
+
to: result.to,
|
|
55127
|
+
summary: result.summary,
|
|
55128
|
+
users: result.users,
|
|
55129
|
+
meta: {
|
|
55130
|
+
scannedFiles: freshness.scannedFiles,
|
|
55131
|
+
scannedLines: freshness.scannedLines,
|
|
55132
|
+
parseErrors: freshness.parseErrors,
|
|
55133
|
+
truncated: false,
|
|
55134
|
+
indexUsed: true,
|
|
55135
|
+
indexFresh: true,
|
|
55136
|
+
queryMs: result.queryMs
|
|
55137
|
+
}
|
|
55138
|
+
};
|
|
55139
|
+
} catch (err) {
|
|
55140
|
+
return {
|
|
55141
|
+
from: new Date(query.fromMs).toISOString(),
|
|
55142
|
+
to: new Date(query.toMs).toISOString(),
|
|
55143
|
+
summary: { totalRequests: 0, metadataRequests: 0, uniqueUsers: 0, uniqueSessions: 0 },
|
|
55144
|
+
users: [],
|
|
55145
|
+
meta: {
|
|
55146
|
+
scannedFiles: 0,
|
|
55147
|
+
scannedLines: 0,
|
|
55148
|
+
parseErrors: 0,
|
|
55149
|
+
truncated: false,
|
|
55150
|
+
indexUsed: false,
|
|
55151
|
+
indexFresh: false,
|
|
55152
|
+
queryMs: 0,
|
|
55153
|
+
fallbackReason: err instanceof Error ? err.message : String(err)
|
|
55154
|
+
}
|
|
55155
|
+
};
|
|
55156
|
+
}
|
|
55157
|
+
}
|
|
54867
55158
|
function getIndexedLogEventDetail(logConfig, id) {
|
|
54868
55159
|
if (!logConfig || logConfig.enabled === false)
|
|
54869
55160
|
return null;
|
|
@@ -55543,7 +55834,7 @@ async function scanEvents(baseDir, query) {
|
|
|
55543
55834
|
};
|
|
55544
55835
|
}
|
|
55545
55836
|
function isLogQueryWindow(value) {
|
|
55546
|
-
return value === "1h" || value === "6h" || value === "24h";
|
|
55837
|
+
return value === "1h" || value === "6h" || value === "24h" || value === "7d" || value === "1mo" || value === "1y";
|
|
55547
55838
|
}
|
|
55548
55839
|
function getLogQueryWindowMs(window2) {
|
|
55549
55840
|
return WINDOW_MS2[window2];
|
|
@@ -55860,7 +56151,10 @@ var init_log_query = __esm(() => {
|
|
|
55860
56151
|
WINDOW_MS2 = {
|
|
55861
56152
|
"1h": 60 * 60 * 1000,
|
|
55862
56153
|
"6h": 6 * 60 * 60 * 1000,
|
|
55863
|
-
"24h": 24 * 60 * 60 * 1000
|
|
56154
|
+
"24h": 24 * 60 * 60 * 1000,
|
|
56155
|
+
"7d": 7 * 24 * 60 * 60 * 1000,
|
|
56156
|
+
"1mo": 30 * 24 * 60 * 60 * 1000,
|
|
56157
|
+
"1y": 365 * 24 * 60 * 60 * 1000
|
|
55864
56158
|
};
|
|
55865
56159
|
});
|
|
55866
56160
|
|
|
@@ -56049,7 +56343,7 @@ function compileRealtimeQuery(input) {
|
|
|
56049
56343
|
const nowMs = Date.now();
|
|
56050
56344
|
const windowRaw = parseStringValue(query.window) ?? "24h";
|
|
56051
56345
|
if (!isLogQueryWindow(windowRaw)) {
|
|
56052
|
-
throw new Error("window \u53C2\u6570\u4EC5\u652F\u6301 1h | 6h | 24h");
|
|
56346
|
+
throw new Error("window \u53C2\u6570\u4EC5\u652F\u6301 1h | 6h | 24h | 7d | 1mo | 1y");
|
|
56053
56347
|
}
|
|
56054
56348
|
const from = parseStringValue(query.from);
|
|
56055
56349
|
const to = parseStringValue(query.to);
|
|
@@ -56639,6 +56933,23 @@ async function queryLogSessions(context2, input) {
|
|
|
56639
56933
|
if (!logEnabled) {
|
|
56640
56934
|
return createEmptyResult(normalized.fromMs, normalized.toMs);
|
|
56641
56935
|
}
|
|
56936
|
+
const indexed = await queryIndexedLogSessions(context2.logConfig, {
|
|
56937
|
+
fromMs: normalized.fromMs,
|
|
56938
|
+
toMs: normalized.toMs,
|
|
56939
|
+
users: normalized.users,
|
|
56940
|
+
sessions: normalized.sessions,
|
|
56941
|
+
q: normalized.q
|
|
56942
|
+
});
|
|
56943
|
+
if (indexed?.meta.indexUsed) {
|
|
56944
|
+
return {
|
|
56945
|
+
from: indexed.from,
|
|
56946
|
+
to: indexed.to,
|
|
56947
|
+
summary: indexed.summary,
|
|
56948
|
+
users: indexed.users,
|
|
56949
|
+
meta: indexed.meta
|
|
56950
|
+
};
|
|
56951
|
+
}
|
|
56952
|
+
const fallbackReason = indexed?.meta.fallbackReason;
|
|
56642
56953
|
const baseDir = resolveLogBaseDir(context2.logConfig);
|
|
56643
56954
|
const eventsDir = join9(baseDir, "events");
|
|
56644
56955
|
if (!existsSync8(eventsDir)) {
|
|
@@ -56762,13 +57073,16 @@ async function queryLogSessions(context2, input) {
|
|
|
56762
57073
|
scannedFiles,
|
|
56763
57074
|
scannedLines,
|
|
56764
57075
|
parseErrors,
|
|
56765
|
-
truncated
|
|
57076
|
+
truncated,
|
|
57077
|
+
indexUsed: false,
|
|
57078
|
+
...fallbackReason ? { fallbackReason } : {}
|
|
56766
57079
|
}
|
|
56767
57080
|
};
|
|
56768
57081
|
}
|
|
56769
57082
|
var MAX_LINES_SCANNED3 = 250000, MAX_Q_LENGTH3 = 200;
|
|
56770
57083
|
var init_log_sessions = __esm(() => {
|
|
56771
57084
|
init_config();
|
|
57085
|
+
init_log_index();
|
|
56772
57086
|
});
|
|
56773
57087
|
|
|
56774
57088
|
// src/log-storage.ts
|
|
@@ -57141,6 +57455,97 @@ var init_openapi = __esm(() => {
|
|
|
57141
57455
|
}
|
|
57142
57456
|
}
|
|
57143
57457
|
},
|
|
57458
|
+
"/api/models": {
|
|
57459
|
+
get: {
|
|
57460
|
+
tags: ["Health"],
|
|
57461
|
+
summary: "\u55C5\u63A2\u53EF\u7528\u6A21\u578B\u8DEF\u7531",
|
|
57462
|
+
description: "\u8FD4\u56DE\u672C\u673A\u6307\u5B9A\u534F\u8BAE\u4E0B\u53EF\u7528\u7684\u6A21\u578B\u8DEF\u7531\u522B\u540D\uFF08routes[protocol] \u7684 key\uFF0C\u6392\u9664 * \u901A\u914D\uFF09\u3002\u4F9B\u5C40\u57DF\u7F51\u5185\u5176\u4ED6 local-router \u63A2\u6D4B\u4F7F\u7528\u3002",
|
|
57463
|
+
parameters: [
|
|
57464
|
+
{
|
|
57465
|
+
name: "protocol",
|
|
57466
|
+
in: "query",
|
|
57467
|
+
required: true,
|
|
57468
|
+
schema: {
|
|
57469
|
+
type: "string",
|
|
57470
|
+
enum: ["openai-completions", "openai-responses", "anthropic-messages"]
|
|
57471
|
+
},
|
|
57472
|
+
description: "\u534F\u8BAE\u7C7B\u578B"
|
|
57473
|
+
}
|
|
57474
|
+
],
|
|
57475
|
+
responses: {
|
|
57476
|
+
"200": {
|
|
57477
|
+
description: "\u53EF\u7528\u6A21\u578B\u8DEF\u7531\u5217\u8868",
|
|
57478
|
+
content: {
|
|
57479
|
+
"application/json": {
|
|
57480
|
+
schema: {
|
|
57481
|
+
type: "object",
|
|
57482
|
+
properties: {
|
|
57483
|
+
protocol: { type: "string", example: "anthropic-messages" },
|
|
57484
|
+
models: {
|
|
57485
|
+
type: "array",
|
|
57486
|
+
items: { type: "string" },
|
|
57487
|
+
example: ["claude-3-5-sonnet", "claude-3-opus"]
|
|
57488
|
+
}
|
|
57489
|
+
}
|
|
57490
|
+
}
|
|
57491
|
+
}
|
|
57492
|
+
}
|
|
57493
|
+
},
|
|
57494
|
+
"400": { description: "\u534F\u8BAE\u53C2\u6570\u7F3A\u5931\u6216\u65E0\u6548" }
|
|
57495
|
+
}
|
|
57496
|
+
}
|
|
57497
|
+
},
|
|
57498
|
+
"/api/providers/discover": {
|
|
57499
|
+
get: {
|
|
57500
|
+
tags: ["Health"],
|
|
57501
|
+
summary: "\u53D1\u73B0\u5C40\u57DF\u7F51 local-router \u7684\u6A21\u578B",
|
|
57502
|
+
description: "\u7531\u672C\u673A server \u4EE3\u4E3A\u8BF7\u6C42\u5BF9\u7AEF local-router \u7684 /api/models\uFF08\u89C4\u907F\u6D4F\u89C8\u5668\u8DE8\u57DF\uFF09\uFF0C\u8FD4\u56DE\u5BF9\u7AEF\u67D0\u534F\u8BAE\u4E0B\u7684\u53EF\u7528\u6A21\u578B\u8DEF\u7531\u3002",
|
|
57503
|
+
parameters: [
|
|
57504
|
+
{
|
|
57505
|
+
name: "ip",
|
|
57506
|
+
in: "query",
|
|
57507
|
+
required: true,
|
|
57508
|
+
schema: { type: "string" },
|
|
57509
|
+
description: "\u5BF9\u7AEF IP"
|
|
57510
|
+
},
|
|
57511
|
+
{
|
|
57512
|
+
name: "port",
|
|
57513
|
+
in: "query",
|
|
57514
|
+
required: false,
|
|
57515
|
+
schema: { type: "string", default: "4099" },
|
|
57516
|
+
description: "\u5BF9\u7AEF\u7AEF\u53E3\uFF0C\u9ED8\u8BA4 4099"
|
|
57517
|
+
},
|
|
57518
|
+
{
|
|
57519
|
+
name: "protocol",
|
|
57520
|
+
in: "query",
|
|
57521
|
+
required: true,
|
|
57522
|
+
schema: {
|
|
57523
|
+
type: "string",
|
|
57524
|
+
enum: ["openai-completions", "openai-responses", "anthropic-messages"]
|
|
57525
|
+
},
|
|
57526
|
+
description: "\u534F\u8BAE\u7C7B\u578B"
|
|
57527
|
+
}
|
|
57528
|
+
],
|
|
57529
|
+
responses: {
|
|
57530
|
+
"200": {
|
|
57531
|
+
description: "\u5BF9\u7AEF\u53EF\u7528\u6A21\u578B\u8DEF\u7531\u5217\u8868",
|
|
57532
|
+
content: {
|
|
57533
|
+
"application/json": {
|
|
57534
|
+
schema: {
|
|
57535
|
+
type: "object",
|
|
57536
|
+
properties: {
|
|
57537
|
+
protocol: { type: "string", example: "anthropic-messages" },
|
|
57538
|
+
models: { type: "array", items: { type: "string" } }
|
|
57539
|
+
}
|
|
57540
|
+
}
|
|
57541
|
+
}
|
|
57542
|
+
}
|
|
57543
|
+
},
|
|
57544
|
+
"400": { description: "\u53C2\u6570\u7F3A\u5931" },
|
|
57545
|
+
"502": { description: "\u65E0\u6CD5\u8FDE\u63A5\u5BF9\u7AEF\u6216\u5BF9\u7AEF\u8FD4\u56DE\u9519\u8BEF" }
|
|
57546
|
+
}
|
|
57547
|
+
}
|
|
57548
|
+
},
|
|
57144
57549
|
"/api/metrics/logs": {
|
|
57145
57550
|
get: {
|
|
57146
57551
|
tags: ["Health"],
|
|
@@ -57299,7 +57704,7 @@ var init_openapi = __esm(() => {
|
|
|
57299
57704
|
required: false,
|
|
57300
57705
|
schema: {
|
|
57301
57706
|
type: "string",
|
|
57302
|
-
enum: ["1h", "6h", "24h"],
|
|
57707
|
+
enum: ["1h", "6h", "24h", "7d", "1mo", "1y"],
|
|
57303
57708
|
default: "24h"
|
|
57304
57709
|
},
|
|
57305
57710
|
description: "\u65F6\u95F4\u7A97\u53E3\uFF08\u5F53\u672A\u63D0\u4F9B from/to \u65F6\u751F\u6548\uFF09"
|
|
@@ -57629,7 +58034,7 @@ var init_openapi = __esm(() => {
|
|
|
57629
58034
|
required: false,
|
|
57630
58035
|
schema: {
|
|
57631
58036
|
type: "string",
|
|
57632
|
-
enum: ["1h", "6h", "24h"],
|
|
58037
|
+
enum: ["1h", "6h", "24h", "7d", "1mo", "1y"],
|
|
57633
58038
|
default: "24h"
|
|
57634
58039
|
},
|
|
57635
58040
|
description: "\u65F6\u95F4\u7A97\u53E3"
|
|
@@ -57750,7 +58155,7 @@ var init_openapi = __esm(() => {
|
|
|
57750
58155
|
required: false,
|
|
57751
58156
|
schema: {
|
|
57752
58157
|
type: "string",
|
|
57753
|
-
enum: ["1h", "6h", "24h"],
|
|
58158
|
+
enum: ["1h", "6h", "24h", "7d", "1mo", "1y"],
|
|
57754
58159
|
default: "1h"
|
|
57755
58160
|
}
|
|
57756
58161
|
},
|
|
@@ -59138,6 +59543,43 @@ function createAdminApiRoutes(store, pluginManager, registerCleanup) {
|
|
|
59138
59543
|
routeTypes: Object.keys(ROUTE_REGISTRY)
|
|
59139
59544
|
});
|
|
59140
59545
|
});
|
|
59546
|
+
api2.get("/models", (c) => {
|
|
59547
|
+
const protocol = c.req.query("protocol");
|
|
59548
|
+
const routeTypes = Object.keys(ROUTE_REGISTRY);
|
|
59549
|
+
if (!protocol || !routeTypes.includes(protocol)) {
|
|
59550
|
+
return c.json({ error: "invalid or missing protocol", routeTypes }, 400);
|
|
59551
|
+
}
|
|
59552
|
+
const routes = store.get().routes[protocol] ?? {};
|
|
59553
|
+
const models = Object.keys(routes).filter((k) => k !== "*");
|
|
59554
|
+
return c.json({ protocol, models });
|
|
59555
|
+
});
|
|
59556
|
+
api2.get("/providers/discover", async (c) => {
|
|
59557
|
+
const ip = c.req.query("ip");
|
|
59558
|
+
const portStr = c.req.query("port") ?? "4099";
|
|
59559
|
+
const protocol = c.req.query("protocol");
|
|
59560
|
+
if (!ip || !protocol) {
|
|
59561
|
+
return c.json({ error: "ip and protocol are required" }, 400);
|
|
59562
|
+
}
|
|
59563
|
+
const port = Number(portStr);
|
|
59564
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
59565
|
+
return c.json({ error: "\u7AEF\u53E3\u65E0\u6548\uFF0C\u5FC5\u987B\u662F 1-65535 \u7684\u6574\u6570" }, 400);
|
|
59566
|
+
}
|
|
59567
|
+
if (!isLoopbackAddress(ip) && !isLanAddress(ip)) {
|
|
59568
|
+
return c.json({ error: "\u4EC5\u652F\u6301\u5C40\u57DF\u7F51\u6216\u672C\u673A IP \u5730\u5740" }, 400);
|
|
59569
|
+
}
|
|
59570
|
+
const url2 = `http://${ip}:${port}/api/models?protocol=${encodeURIComponent(protocol)}`;
|
|
59571
|
+
try {
|
|
59572
|
+
const res = await fetch(url2, { signal: AbortSignal.timeout(5000) });
|
|
59573
|
+
if (!res.ok) {
|
|
59574
|
+
const body = await res.json().catch(() => ({}));
|
|
59575
|
+
return c.json({ error: body.error ?? `remote returned ${res.status}` }, 502);
|
|
59576
|
+
}
|
|
59577
|
+
const data = await res.json();
|
|
59578
|
+
return c.json(data);
|
|
59579
|
+
} catch (err) {
|
|
59580
|
+
return c.json({ error: `\u65E0\u6CD5\u8FDE\u63A5\u5BF9\u7AEF local-router: ${err instanceof Error ? err.message : err}` }, 502);
|
|
59581
|
+
}
|
|
59582
|
+
});
|
|
59141
59583
|
api2.get("/config/schema", (c) => {
|
|
59142
59584
|
try {
|
|
59143
59585
|
return c.json(schemaJson);
|
|
@@ -59260,7 +59702,7 @@ function createAdminApiRoutes(store, pluginManager, registerCleanup) {
|
|
|
59260
59702
|
try {
|
|
59261
59703
|
const windowRaw = c.req.query("window") ?? "24h";
|
|
59262
59704
|
if (!isLogQueryWindow(windowRaw)) {
|
|
59263
|
-
return c.json({ error: "window \u53C2\u6570\u4EC5\u652F\u6301 1h | 6h | 24h" }, 400);
|
|
59705
|
+
return c.json({ error: "window \u53C2\u6570\u4EC5\u652F\u6301 1h | 6h | 24h | 7d | 1mo | 1y" }, 400);
|
|
59264
59706
|
}
|
|
59265
59707
|
const range = resolveLogQueryRange({
|
|
59266
59708
|
window: windowRaw,
|
|
@@ -59311,7 +59753,7 @@ function createAdminApiRoutes(store, pluginManager, registerCleanup) {
|
|
|
59311
59753
|
try {
|
|
59312
59754
|
const windowRaw = c.req.query("window") ?? "24h";
|
|
59313
59755
|
if (!isLogQueryWindow(windowRaw)) {
|
|
59314
|
-
return c.json({ error: "window \u53C2\u6570\u4EC5\u652F\u6301 1h | 6h | 24h" }, 400);
|
|
59756
|
+
return c.json({ error: "window \u53C2\u6570\u4EC5\u652F\u6301 1h | 6h | 24h | 7d | 1mo | 1y" }, 400);
|
|
59315
59757
|
}
|
|
59316
59758
|
const range = resolveLogQueryRange({
|
|
59317
59759
|
window: windowRaw,
|
|
@@ -59350,7 +59792,7 @@ function createAdminApiRoutes(store, pluginManager, registerCleanup) {
|
|
|
59350
59792
|
try {
|
|
59351
59793
|
const windowRaw = c.req.query("window") ?? "24h";
|
|
59352
59794
|
if (!isLogQueryWindow(windowRaw)) {
|
|
59353
|
-
return c.json({ error: "window \u53C2\u6570\u4EC5\u652F\u6301 1h | 6h | 24h" }, 400);
|
|
59795
|
+
return c.json({ error: "window \u53C2\u6570\u4EC5\u652F\u6301 1h | 6h | 24h | 7d | 1mo | 1y" }, 400);
|
|
59354
59796
|
}
|
|
59355
59797
|
const range = resolveLogQueryRange({
|
|
59356
59798
|
window: windowRaw,
|
|
@@ -59400,7 +59842,7 @@ function createAdminApiRoutes(store, pluginManager, registerCleanup) {
|
|
|
59400
59842
|
const target = c.req.raw;
|
|
59401
59843
|
const windowRaw = c.req.query("window") ?? "1h";
|
|
59402
59844
|
if (!isLogQueryWindow(windowRaw)) {
|
|
59403
|
-
return c.json({ error: "window \u53C2\u6570\u4EC5\u652F\u6301 1h | 6h | 24h" }, 400);
|
|
59845
|
+
return c.json({ error: "window \u53C2\u6570\u4EC5\u652F\u6301 1h | 6h | 24h | 7d | 1mo | 1y" }, 400);
|
|
59404
59846
|
}
|
|
59405
59847
|
const sortRaw = c.req.query("sort") ?? "time_desc";
|
|
59406
59848
|
if (!validateSort(sortRaw)) {
|
|
@@ -59721,7 +60163,6 @@ async function createAppRuntimeFromConfigPath(configPath, listen) {
|
|
|
59721
60163
|
}
|
|
59722
60164
|
var ROUTE_REGISTRY;
|
|
59723
60165
|
var init_src = __esm(() => {
|
|
59724
|
-
init_autostart();
|
|
59725
60166
|
init_dist4();
|
|
59726
60167
|
init_dist5();
|
|
59727
60168
|
init_dist6();
|
|
@@ -59729,6 +60170,7 @@ var init_src = __esm(() => {
|
|
|
59729
60170
|
init_dist9();
|
|
59730
60171
|
init_dist10();
|
|
59731
60172
|
init_bun();
|
|
60173
|
+
init_autostart();
|
|
59732
60174
|
init_config();
|
|
59733
60175
|
init_config_store();
|
|
59734
60176
|
init_config_validate();
|
|
@@ -61223,6 +61665,7 @@ Commands:
|
|
|
61223
61665
|
config provider list [--json] [--config <path>]
|
|
61224
61666
|
config provider show <name> [--show-secrets] [--config <path>]
|
|
61225
61667
|
config provider add <name> --type <type> --base <url> --api-key <key> --model <name> [--image-input] [--reasoning] [--proxy <url>] [--dry-run] [--config <path>]
|
|
61668
|
+
config provider add-lan <ip> --type <protocol> [--port 4099] [--dry-run] [--config <path>]
|
|
61226
61669
|
config provider set <name> [--base <url>] [--api-key <key>] [--proxy <url>] [--dry-run] [--config <path>]
|
|
61227
61670
|
config provider remove <name> [--force] [--dry-run] [--config <path>]
|
|
61228
61671
|
config provider model list <provider> [--config <path>]
|
|
@@ -61402,6 +61845,89 @@ async function handleProviderAdd(args, flags) {
|
|
|
61402
61845
|
}
|
|
61403
61846
|
});
|
|
61404
61847
|
}
|
|
61848
|
+
async function handleProviderAddLan(args, flags) {
|
|
61849
|
+
return runCommand({
|
|
61850
|
+
command: "config.provider.add-lan",
|
|
61851
|
+
flags,
|
|
61852
|
+
fn: async (ctx) => {
|
|
61853
|
+
const [ip, ...flagArgs] = args;
|
|
61854
|
+
ensureNoFlag("ip", ip);
|
|
61855
|
+
if (!ip) {
|
|
61856
|
+
throw new CliError("USAGE_ERROR", "ip \u5FC5\u586B", {
|
|
61857
|
+
hint: "\u7528\u6CD5: config provider add-lan <ip> --type <protocol> [--port 4099]"
|
|
61858
|
+
});
|
|
61859
|
+
}
|
|
61860
|
+
const parsed = parseArgs3({
|
|
61861
|
+
args: flagArgs,
|
|
61862
|
+
options: {
|
|
61863
|
+
type: { type: "string" },
|
|
61864
|
+
port: { type: "string", default: "4099" },
|
|
61865
|
+
"dry-run": { type: "boolean", default: false },
|
|
61866
|
+
config: { type: "string" }
|
|
61867
|
+
},
|
|
61868
|
+
allowPositionals: true,
|
|
61869
|
+
strict: false
|
|
61870
|
+
});
|
|
61871
|
+
const type = parsed.values.type;
|
|
61872
|
+
if (!type || !providerTypes().includes(type)) {
|
|
61873
|
+
throw new CliError("USAGE_ERROR", "type \u5FC5\u586B\u4E14\u5FC5\u987B\u662F openai-completions/openai-responses/anthropic-messages", { details: { acceptable: providerTypes() } });
|
|
61874
|
+
}
|
|
61875
|
+
const portStr = parsed.values.port ?? "4099";
|
|
61876
|
+
const port = Number(portStr);
|
|
61877
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
61878
|
+
throw new CliError("USAGE_ERROR", `\u7AEF\u53E3\u65E0\u6548: ${portStr}\uFF08\u5FC5\u987B\u662F 1-65535 \u7684\u6574\u6570\uFF09`);
|
|
61879
|
+
}
|
|
61880
|
+
const name21 = `${ip}-${type}`;
|
|
61881
|
+
const { path, config: config2 } = readConfig(parsed.values.config);
|
|
61882
|
+
if (config2.providers[name21]) {
|
|
61883
|
+
throw new CliError("PROVIDER_EXISTS", `provider \u5DF2\u5B58\u5728: ${name21}`, {
|
|
61884
|
+
hint: "\u4F7F\u7528 `config provider set` \u4FEE\u6539\u5B57\u6BB5"
|
|
61885
|
+
});
|
|
61886
|
+
}
|
|
61887
|
+
const url2 = `http://${ip}:${port}/api/models?protocol=${encodeURIComponent(type)}`;
|
|
61888
|
+
let models;
|
|
61889
|
+
try {
|
|
61890
|
+
const res = await fetch(url2, { signal: AbortSignal.timeout(5000) });
|
|
61891
|
+
if (!res.ok) {
|
|
61892
|
+
const body = await res.json().catch(() => ({}));
|
|
61893
|
+
throw new CliError("UPSTREAM_UNREACHABLE", `\u5BF9\u7AEF\u8FD4\u56DE\u9519\u8BEF: ${body.error ?? res.status}`, {
|
|
61894
|
+
details: { url: url2 }
|
|
61895
|
+
});
|
|
61896
|
+
}
|
|
61897
|
+
const data = await res.json();
|
|
61898
|
+
models = Array.isArray(data.models) ? data.models : [];
|
|
61899
|
+
} catch (err) {
|
|
61900
|
+
if (err instanceof CliError)
|
|
61901
|
+
throw err;
|
|
61902
|
+
throw new CliError("UPSTREAM_UNREACHABLE", `\u65E0\u6CD5\u8FDE\u63A5\u5BF9\u7AEF local-router: ${err instanceof Error ? err.message : err}`, { details: { url: url2 } });
|
|
61903
|
+
}
|
|
61904
|
+
if (models.length === 0) {
|
|
61905
|
+
throw new CliError("USAGE_ERROR", `\u5BF9\u7AEF\u5728\u534F\u8BAE "${type}" \u4E0B\u6CA1\u6709\u53EF\u7528\u7684\u6A21\u578B\u8DEF\u7531\uFF0C\u65E0\u6CD5\u521B\u5EFA provider`, { hint: "\u786E\u8BA4\u5BF9\u7AEF\u5DF2\u4E3A\u8BE5\u534F\u8BAE\u914D\u7F6E\u4E86\u5177\u4F53\u6A21\u578B\u8DEF\u7531\uFF08\u800C\u975E\u4EC5 * \u515C\u5E95\uFF09" });
|
|
61906
|
+
}
|
|
61907
|
+
const modelMap = {};
|
|
61908
|
+
for (const m of models) {
|
|
61909
|
+
modelMap[m] = { "image-input": false, reasoning: false };
|
|
61910
|
+
}
|
|
61911
|
+
config2.providers[name21] = {
|
|
61912
|
+
type,
|
|
61913
|
+
base: `http://${ip}:${port}/${type}`,
|
|
61914
|
+
apiKey: "no_key",
|
|
61915
|
+
models: modelMap
|
|
61916
|
+
};
|
|
61917
|
+
const result = applyConfigChange(path, config2, { dryRun: parsed.values["dry-run"] });
|
|
61918
|
+
emitResult(ctx, {
|
|
61919
|
+
command: "config.provider.add-lan",
|
|
61920
|
+
data: { provider: name21, models: models.length, ...result },
|
|
61921
|
+
md: {
|
|
61922
|
+
heading: `config.provider.add-lan \xB7 ${name21} \xB7 ${result.written ? "\u2713" : "dry-run"}`,
|
|
61923
|
+
data: applyResultToMd(result, `provider ${name21} (${models.length} \u4E2A\u6A21\u578B)`),
|
|
61924
|
+
hints: result.written ? ["\u70ED\u52A0\u8F7D: `local-router config apply`"] : ["\u6267\u884C\u5199\u5165: \u53BB\u6389 `--dry-run`"]
|
|
61925
|
+
},
|
|
61926
|
+
text: result.written ? `\u5DF2\u6DFB\u52A0 provider: ${name21}\uFF08\u55C5\u63A2\u5230 ${models.length} \u4E2A\u6A21\u578B\uFF09` : applyResultToText(result)
|
|
61927
|
+
});
|
|
61928
|
+
}
|
|
61929
|
+
});
|
|
61930
|
+
}
|
|
61405
61931
|
async function handleProviderSet(args, flags) {
|
|
61406
61932
|
return runCommand({
|
|
61407
61933
|
command: "config.provider.set",
|
|
@@ -62024,6 +62550,8 @@ async function handleProvider(args, flags) {
|
|
|
62024
62550
|
return handleProviderShow(rest, flags);
|
|
62025
62551
|
case "add":
|
|
62026
62552
|
return handleProviderAdd(rest, flags);
|
|
62553
|
+
case "add-lan":
|
|
62554
|
+
return handleProviderAddLan(rest, flags);
|
|
62027
62555
|
case "set":
|
|
62028
62556
|
return handleProviderSet(rest, flags);
|
|
62029
62557
|
case "remove":
|
|
@@ -62131,7 +62659,11 @@ async function dispatchConfig(group, rest, flags) {
|
|
|
62131
62659
|
init_registry();
|
|
62132
62660
|
var PROVIDER_TYPE_ENUM = ["openai-completions", "openai-responses", "anthropic-messages"];
|
|
62133
62661
|
var COMMON_CONFIG_FLAG = { name: "config", type: "string", description: "\u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84" };
|
|
62134
|
-
var DRY_RUN_FLAG = {
|
|
62662
|
+
var DRY_RUN_FLAG = {
|
|
62663
|
+
name: "dry-run",
|
|
62664
|
+
type: "boolean",
|
|
62665
|
+
description: "\u53EA\u9884\u89C8 diff\uFF0C\u4E0D\u5199\u5165"
|
|
62666
|
+
};
|
|
62135
62667
|
function forward(prefix) {
|
|
62136
62668
|
return async (args, flags) => cmdConfig([...prefix, ...args], flags);
|
|
62137
62669
|
}
|
|
@@ -62148,10 +62680,7 @@ defineCommand({
|
|
|
62148
62680
|
defineCommand({
|
|
62149
62681
|
name: "config diff",
|
|
62150
62682
|
summary: "\u4E0E\u5907\u4EFD\u6216\u6307\u5B9A\u6587\u4EF6\u5BF9\u6BD4",
|
|
62151
|
-
flags: [
|
|
62152
|
-
{ name: "against", type: "string", description: "\u5907\u4EFD id \u6216\u8DEF\u5F84" },
|
|
62153
|
-
COMMON_CONFIG_FLAG
|
|
62154
|
-
],
|
|
62683
|
+
flags: [{ name: "against", type: "string", description: "\u5907\u4EFD id \u6216\u8DEF\u5F84" }, COMMON_CONFIG_FLAG],
|
|
62155
62684
|
supportsJson: true,
|
|
62156
62685
|
handler: forward(["diff"])
|
|
62157
62686
|
});
|
|
@@ -62265,6 +62794,26 @@ defineCommand({
|
|
|
62265
62794
|
supportsJson: true,
|
|
62266
62795
|
handler: forward(["provider", "add"])
|
|
62267
62796
|
});
|
|
62797
|
+
defineCommand({
|
|
62798
|
+
name: "config provider add-lan",
|
|
62799
|
+
summary: "\u4ECE\u5C40\u57DF\u7F51\u5185\u5176\u4ED6 local-router \u55C5\u63A2\u5E76\u65B0\u589E provider",
|
|
62800
|
+
positionals: [{ name: "ip", required: true, description: "\u5BF9\u7AEF IP" }],
|
|
62801
|
+
flags: [
|
|
62802
|
+
{
|
|
62803
|
+
name: "type",
|
|
62804
|
+
type: "enum",
|
|
62805
|
+
enum: [...PROVIDER_TYPE_ENUM],
|
|
62806
|
+
required: true,
|
|
62807
|
+
description: "\u534F\u8BAE\u7C7B\u578B"
|
|
62808
|
+
},
|
|
62809
|
+
{ name: "port", type: "string", description: "\u5BF9\u7AEF\u7AEF\u53E3\uFF08\u9ED8\u8BA4 4099\uFF09" },
|
|
62810
|
+
DRY_RUN_FLAG,
|
|
62811
|
+
COMMON_CONFIG_FLAG
|
|
62812
|
+
],
|
|
62813
|
+
mutates: true,
|
|
62814
|
+
supportsJson: true,
|
|
62815
|
+
handler: forward(["provider", "add-lan"])
|
|
62816
|
+
});
|
|
62268
62817
|
defineCommand({
|
|
62269
62818
|
name: "config provider set",
|
|
62270
62819
|
summary: "\u4FEE\u6539 provider \u5B57\u6BB5",
|
|
@@ -62350,10 +62899,7 @@ defineCommand({
|
|
|
62350
62899
|
defineCommand({
|
|
62351
62900
|
name: "config route list",
|
|
62352
62901
|
summary: "\u5217\u51FA\u6240\u6709\u8DEF\u7531",
|
|
62353
|
-
flags: [
|
|
62354
|
-
{ name: "entry", type: "string", description: "\u53EA\u770B\u67D0\u5165\u53E3" },
|
|
62355
|
-
COMMON_CONFIG_FLAG
|
|
62356
|
-
],
|
|
62902
|
+
flags: [{ name: "entry", type: "string", description: "\u53EA\u770B\u67D0\u5165\u53E3" }, COMMON_CONFIG_FLAG],
|
|
62357
62903
|
supportsJson: true,
|
|
62358
62904
|
handler: forward(["route", "list"])
|
|
62359
62905
|
});
|
|
@@ -64676,7 +65222,7 @@ defineSchemaCommand({
|
|
|
64676
65222
|
{
|
|
64677
65223
|
name: "window",
|
|
64678
65224
|
type: "enum",
|
|
64679
|
-
enum: ["1h", "6h", "24h"],
|
|
65225
|
+
enum: ["1h", "6h", "24h", "7d", "1mo", "1y"],
|
|
64680
65226
|
default: "24h",
|
|
64681
65227
|
description: "\u65F6\u95F4\u7A97\u53E3"
|
|
64682
65228
|
},
|
|
@@ -64809,7 +65355,7 @@ defineSchemaCommand({
|
|
|
64809
65355
|
{
|
|
64810
65356
|
name: "window",
|
|
64811
65357
|
type: "enum",
|
|
64812
|
-
enum: ["1h", "6h", "24h"],
|
|
65358
|
+
enum: ["1h", "6h", "24h", "7d", "1mo", "1y"],
|
|
64813
65359
|
default: "24h",
|
|
64814
65360
|
description: "\u65F6\u95F4\u7A97\u53E3"
|
|
64815
65361
|
}
|
|
@@ -64933,7 +65479,7 @@ defineSchemaCommand({
|
|
|
64933
65479
|
{
|
|
64934
65480
|
name: "window",
|
|
64935
65481
|
type: "enum",
|
|
64936
|
-
enum: ["1h", "6h", "24h"],
|
|
65482
|
+
enum: ["1h", "6h", "24h", "7d", "1mo", "1y"],
|
|
64937
65483
|
default: "24h",
|
|
64938
65484
|
description: "\u65F6\u95F4\u7A97\u53E3"
|
|
64939
65485
|
},
|
|
@@ -65020,7 +65566,7 @@ defineSchemaCommand({
|
|
|
65020
65566
|
{
|
|
65021
65567
|
name: "window",
|
|
65022
65568
|
type: "enum",
|
|
65023
|
-
enum: ["1h", "6h", "24h"],
|
|
65569
|
+
enum: ["1h", "6h", "24h", "7d", "1mo", "1y"],
|
|
65024
65570
|
default: "24h",
|
|
65025
65571
|
description: "\u65F6\u95F4\u7A97\u53E3"
|
|
65026
65572
|
},
|
|
@@ -65146,7 +65692,7 @@ defineSchemaCommand({
|
|
|
65146
65692
|
{
|
|
65147
65693
|
name: "window",
|
|
65148
65694
|
type: "enum",
|
|
65149
|
-
enum: ["1h", "6h", "24h"],
|
|
65695
|
+
enum: ["1h", "6h", "24h", "7d", "1mo", "1y"],
|
|
65150
65696
|
default: "24h",
|
|
65151
65697
|
description: "\u65F6\u95F4\u7A97\u53E3"
|
|
65152
65698
|
}
|
|
@@ -65206,7 +65752,7 @@ defineSchemaCommand({
|
|
|
65206
65752
|
{
|
|
65207
65753
|
name: "window",
|
|
65208
65754
|
type: "enum",
|
|
65209
|
-
enum: ["1h", "6h", "24h"],
|
|
65755
|
+
enum: ["1h", "6h", "24h", "7d", "1mo", "1y"],
|
|
65210
65756
|
default: "24h",
|
|
65211
65757
|
description: "\u65F6\u95F4\u7A97\u53E3"
|
|
65212
65758
|
},
|