@lakphy/local-router 0.5.6 → 0.5.8
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 +1095 -436
- package/dist/entry.js +436 -238
- package/dist/web/assets/{index-0-b0NcMV.js → index-B-4HJAZa.js} +69 -69
- 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-_8dgANhJ.css +0 -2
package/dist/entry.js
CHANGED
|
@@ -9287,216 +9287,6 @@ var require_dist2 = __commonJS((exports, module) => {
|
|
|
9287
9287
|
import { readFileSync as readFileSync6 } from "fs";
|
|
9288
9288
|
import { dirname as dirname3, resolve as resolve8 } from "path";
|
|
9289
9289
|
|
|
9290
|
-
// src/cli/autostart.ts
|
|
9291
|
-
import { execSync } from "child_process";
|
|
9292
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
9293
|
-
import { homedir as homedir2, platform } from "os";
|
|
9294
|
-
import { dirname, join as join2 } from "path";
|
|
9295
|
-
|
|
9296
|
-
// src/cli/runtime.ts
|
|
9297
|
-
import { homedir } from "os";
|
|
9298
|
-
import { join, resolve } from "path";
|
|
9299
|
-
function getRuntimeDirs() {
|
|
9300
|
-
const override = process.env.LOCAL_ROUTER_RUNTIME_DIR;
|
|
9301
|
-
const root = override?.trim() ? override.trim() : join(homedir(), ".local-router");
|
|
9302
|
-
return {
|
|
9303
|
-
root,
|
|
9304
|
-
run: join(root, "run"),
|
|
9305
|
-
logs: join(root, "logs")
|
|
9306
|
-
};
|
|
9307
|
-
}
|
|
9308
|
-
|
|
9309
|
-
// src/cli/autostart.ts
|
|
9310
|
-
var LABEL = "com.lakphy.local-router";
|
|
9311
|
-
function getDaemonLogPath() {
|
|
9312
|
-
return getRuntimeDirs().logs + "/daemon.log";
|
|
9313
|
-
}
|
|
9314
|
-
function getLaunchAgentPath() {
|
|
9315
|
-
return join2(homedir2(), "Library", "LaunchAgents", `${LABEL}.plist`);
|
|
9316
|
-
}
|
|
9317
|
-
function buildPlist(opts) {
|
|
9318
|
-
const logPath = getDaemonLogPath();
|
|
9319
|
-
const args = [opts.execPath, ...opts.args].map((a) => ` <string>${escapeXml(a)}</string>`).join(`
|
|
9320
|
-
`);
|
|
9321
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
9322
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
9323
|
-
<plist version="1.0">
|
|
9324
|
-
<dict>
|
|
9325
|
-
<key>Label</key>
|
|
9326
|
-
<string>${escapeXml(opts.label)}</string>
|
|
9327
|
-
<key>ProgramArguments</key>
|
|
9328
|
-
<array>
|
|
9329
|
-
${args}
|
|
9330
|
-
</array>
|
|
9331
|
-
<key>RunAtLoad</key>
|
|
9332
|
-
<true/>
|
|
9333
|
-
<key>KeepAlive</key>
|
|
9334
|
-
<false/>
|
|
9335
|
-
<key>StandardOutPath</key>
|
|
9336
|
-
<string>${escapeXml(logPath)}</string>
|
|
9337
|
-
<key>StandardErrorPath</key>
|
|
9338
|
-
<string>${escapeXml(logPath)}</string>
|
|
9339
|
-
</dict>
|
|
9340
|
-
</plist>
|
|
9341
|
-
`;
|
|
9342
|
-
}
|
|
9343
|
-
function escapeXml(s) {
|
|
9344
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
9345
|
-
}
|
|
9346
|
-
function createMacosManager() {
|
|
9347
|
-
const plistPath = getLaunchAgentPath();
|
|
9348
|
-
return {
|
|
9349
|
-
platform: "macos",
|
|
9350
|
-
async isInstalled() {
|
|
9351
|
-
return existsSync(plistPath);
|
|
9352
|
-
},
|
|
9353
|
-
async install(opts) {
|
|
9354
|
-
const dir = dirname(plistPath);
|
|
9355
|
-
if (!existsSync(dir))
|
|
9356
|
-
mkdirSync(dir, { recursive: true });
|
|
9357
|
-
writeFileSync(plistPath, buildPlist(opts), "utf-8");
|
|
9358
|
-
try {
|
|
9359
|
-
execSync(`launchctl bootout gui/$(id -u) ${plistPath} 2>/dev/null`, { stdio: "ignore" });
|
|
9360
|
-
} catch {}
|
|
9361
|
-
execSync(`launchctl bootstrap gui/$(id -u) ${plistPath}`, { stdio: "ignore" });
|
|
9362
|
-
},
|
|
9363
|
-
async uninstall() {
|
|
9364
|
-
if (!existsSync(plistPath))
|
|
9365
|
-
return;
|
|
9366
|
-
try {
|
|
9367
|
-
execSync(`launchctl bootout gui/$(id -u) ${plistPath}`, { stdio: "ignore" });
|
|
9368
|
-
} catch {}
|
|
9369
|
-
rmSync(plistPath, { force: true });
|
|
9370
|
-
},
|
|
9371
|
-
getServicePath() {
|
|
9372
|
-
return plistPath;
|
|
9373
|
-
}
|
|
9374
|
-
};
|
|
9375
|
-
}
|
|
9376
|
-
function getSystemdUnitPath() {
|
|
9377
|
-
return join2(homedir2(), ".config", "systemd", "user", "local-router.service");
|
|
9378
|
-
}
|
|
9379
|
-
function buildUnit(opts) {
|
|
9380
|
-
const logPath = getDaemonLogPath();
|
|
9381
|
-
const execStart = [opts.execPath, ...opts.args].join(" ");
|
|
9382
|
-
return `[Unit]
|
|
9383
|
-
Description=Local Router API Gateway
|
|
9384
|
-
After=network-online.target
|
|
9385
|
-
|
|
9386
|
-
[Service]
|
|
9387
|
-
Type=simple
|
|
9388
|
-
ExecStart=${execStart}
|
|
9389
|
-
Restart=on-failure
|
|
9390
|
-
RestartSec=5
|
|
9391
|
-
StandardOutput=append:${logPath}
|
|
9392
|
-
StandardError=append:${logPath}
|
|
9393
|
-
|
|
9394
|
-
[Install]
|
|
9395
|
-
WantedBy=default.target
|
|
9396
|
-
`;
|
|
9397
|
-
}
|
|
9398
|
-
function createLinuxManager() {
|
|
9399
|
-
const unitPath = getSystemdUnitPath();
|
|
9400
|
-
return {
|
|
9401
|
-
platform: "linux",
|
|
9402
|
-
async isInstalled() {
|
|
9403
|
-
if (!existsSync(unitPath))
|
|
9404
|
-
return false;
|
|
9405
|
-
try {
|
|
9406
|
-
const out = execSync("systemctl --user is-enabled local-router 2>/dev/null", {
|
|
9407
|
-
encoding: "utf-8"
|
|
9408
|
-
}).trim();
|
|
9409
|
-
return out === "enabled";
|
|
9410
|
-
} catch {
|
|
9411
|
-
return false;
|
|
9412
|
-
}
|
|
9413
|
-
},
|
|
9414
|
-
async install(opts) {
|
|
9415
|
-
const dir = dirname(unitPath);
|
|
9416
|
-
if (!existsSync(dir))
|
|
9417
|
-
mkdirSync(dir, { recursive: true });
|
|
9418
|
-
writeFileSync(unitPath, buildUnit(opts), "utf-8");
|
|
9419
|
-
execSync("systemctl --user daemon-reload", { stdio: "ignore" });
|
|
9420
|
-
execSync("systemctl --user enable local-router", { stdio: "ignore" });
|
|
9421
|
-
},
|
|
9422
|
-
async uninstall() {
|
|
9423
|
-
try {
|
|
9424
|
-
execSync("systemctl --user disable local-router", { stdio: "ignore" });
|
|
9425
|
-
} catch {}
|
|
9426
|
-
rmSync(unitPath, { force: true });
|
|
9427
|
-
try {
|
|
9428
|
-
execSync("systemctl --user daemon-reload", { stdio: "ignore" });
|
|
9429
|
-
} catch {}
|
|
9430
|
-
},
|
|
9431
|
-
getServicePath() {
|
|
9432
|
-
return unitPath;
|
|
9433
|
-
}
|
|
9434
|
-
};
|
|
9435
|
-
}
|
|
9436
|
-
var WIN_REG_KEY = "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";
|
|
9437
|
-
var WIN_REG_VALUE = "LocalRouter";
|
|
9438
|
-
function createWindowsManager() {
|
|
9439
|
-
return {
|
|
9440
|
-
platform: "windows",
|
|
9441
|
-
async isInstalled() {
|
|
9442
|
-
try {
|
|
9443
|
-
execSync(`reg query "${WIN_REG_KEY}" /v ${WIN_REG_VALUE}`, { stdio: "ignore" });
|
|
9444
|
-
return true;
|
|
9445
|
-
} catch {
|
|
9446
|
-
return false;
|
|
9447
|
-
}
|
|
9448
|
-
},
|
|
9449
|
-
async install(opts) {
|
|
9450
|
-
const cmd = [opts.execPath, ...opts.args].map((a) => `"${a}"`).join(" ");
|
|
9451
|
-
execSync(`reg add "${WIN_REG_KEY}" /v ${WIN_REG_VALUE} /t REG_SZ /d "${cmd}" /f`, {
|
|
9452
|
-
stdio: "ignore"
|
|
9453
|
-
});
|
|
9454
|
-
},
|
|
9455
|
-
async uninstall() {
|
|
9456
|
-
try {
|
|
9457
|
-
execSync(`reg delete "${WIN_REG_KEY}" /v ${WIN_REG_VALUE} /f`, { stdio: "ignore" });
|
|
9458
|
-
} catch {}
|
|
9459
|
-
},
|
|
9460
|
-
getServicePath() {
|
|
9461
|
-
return `${WIN_REG_KEY}\\${WIN_REG_VALUE}`;
|
|
9462
|
-
}
|
|
9463
|
-
};
|
|
9464
|
-
}
|
|
9465
|
-
function createUnsupportedManager() {
|
|
9466
|
-
return {
|
|
9467
|
-
platform: "unsupported",
|
|
9468
|
-
async isInstalled() {
|
|
9469
|
-
return false;
|
|
9470
|
-
},
|
|
9471
|
-
async install() {
|
|
9472
|
-
throw new Error("\u5F53\u524D\u5E73\u53F0\u4E0D\u652F\u6301\u81EA\u542F\u52A8");
|
|
9473
|
-
},
|
|
9474
|
-
async uninstall() {
|
|
9475
|
-
throw new Error("\u5F53\u524D\u5E73\u53F0\u4E0D\u652F\u6301\u81EA\u542F\u52A8");
|
|
9476
|
-
},
|
|
9477
|
-
getServicePath() {
|
|
9478
|
-
return "";
|
|
9479
|
-
}
|
|
9480
|
-
};
|
|
9481
|
-
}
|
|
9482
|
-
function createAutostartManager() {
|
|
9483
|
-
const p = platform();
|
|
9484
|
-
if (p === "darwin")
|
|
9485
|
-
return createMacosManager();
|
|
9486
|
-
if (p === "linux")
|
|
9487
|
-
return createLinuxManager();
|
|
9488
|
-
if (p === "win32")
|
|
9489
|
-
return createWindowsManager();
|
|
9490
|
-
return createUnsupportedManager();
|
|
9491
|
-
}
|
|
9492
|
-
function getAutostartExecArgs() {
|
|
9493
|
-
const script = process.argv[1] ?? "dist/cli.js";
|
|
9494
|
-
return {
|
|
9495
|
-
execPath: process.execPath,
|
|
9496
|
-
args: [script, "__run-server", "--mode", "daemon"]
|
|
9497
|
-
};
|
|
9498
|
-
}
|
|
9499
|
-
|
|
9500
9290
|
// node_modules/.bun/@ai-sdk+provider@3.0.8/node_modules/@ai-sdk/provider/dist/index.mjs
|
|
9501
9291
|
var marker = "vercel.ai.error";
|
|
9502
9292
|
var symbol = Symbol.for(marker);
|
|
@@ -29343,7 +29133,7 @@ function createProviderToolFactoryWithOutputSchema({
|
|
|
29343
29133
|
supportsDeferredResults
|
|
29344
29134
|
});
|
|
29345
29135
|
}
|
|
29346
|
-
async function
|
|
29136
|
+
async function resolve(value) {
|
|
29347
29137
|
if (typeof value === "function") {
|
|
29348
29138
|
value = value();
|
|
29349
29139
|
}
|
|
@@ -32288,11 +32078,11 @@ var AnthropicMessagesLanguageModel = class {
|
|
|
32288
32078
|
betas,
|
|
32289
32079
|
headers
|
|
32290
32080
|
}) {
|
|
32291
|
-
return combineHeaders(await
|
|
32081
|
+
return combineHeaders(await resolve(this.config.headers), headers, betas.size > 0 ? { "anthropic-beta": Array.from(betas).join(",") } : {});
|
|
32292
32082
|
}
|
|
32293
32083
|
async getBetasFromHeaders(requestHeaders) {
|
|
32294
32084
|
var _a16, _b16;
|
|
32295
|
-
const configHeaders = await
|
|
32085
|
+
const configHeaders = await resolve(this.config.headers);
|
|
32296
32086
|
const configBetaHeader = (_a16 = configHeaders["anthropic-beta"]) != null ? _a16 : "";
|
|
32297
32087
|
const requestBetaHeader = (_b16 = requestHeaders == null ? undefined : requestHeaders["anthropic-beta"]) != null ? _b16 : "";
|
|
32298
32088
|
return new Set([
|
|
@@ -41477,7 +41267,7 @@ var GatewayFetchMetadata = class {
|
|
|
41477
41267
|
try {
|
|
41478
41268
|
const { value } = await getFromApi({
|
|
41479
41269
|
url: `${this.config.baseURL}/config`,
|
|
41480
|
-
headers: await
|
|
41270
|
+
headers: await resolve(this.config.headers()),
|
|
41481
41271
|
successfulResponseHandler: createJsonResponseHandler(gatewayAvailableModelsResponseSchema),
|
|
41482
41272
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
41483
41273
|
errorSchema: exports_external.any(),
|
|
@@ -41495,7 +41285,7 @@ var GatewayFetchMetadata = class {
|
|
|
41495
41285
|
const baseUrl = new URL(this.config.baseURL);
|
|
41496
41286
|
const { value } = await getFromApi({
|
|
41497
41287
|
url: `${baseUrl.origin}/v1/credits`,
|
|
41498
|
-
headers: await
|
|
41288
|
+
headers: await resolve(this.config.headers()),
|
|
41499
41289
|
successfulResponseHandler: createJsonResponseHandler(gatewayCreditsResponseSchema),
|
|
41500
41290
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
41501
41291
|
errorSchema: exports_external.any(),
|
|
@@ -41560,7 +41350,7 @@ var GatewayLanguageModel = class {
|
|
|
41560
41350
|
async doGenerate(options) {
|
|
41561
41351
|
const { args, warnings } = await this.getArgs(options);
|
|
41562
41352
|
const { abortSignal } = options;
|
|
41563
|
-
const resolvedHeaders = await
|
|
41353
|
+
const resolvedHeaders = await resolve(this.config.headers());
|
|
41564
41354
|
try {
|
|
41565
41355
|
const {
|
|
41566
41356
|
responseHeaders,
|
|
@@ -41568,7 +41358,7 @@ var GatewayLanguageModel = class {
|
|
|
41568
41358
|
rawValue: rawResponse
|
|
41569
41359
|
} = await postJsonToApi({
|
|
41570
41360
|
url: this.getUrl(),
|
|
41571
|
-
headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, false), await
|
|
41361
|
+
headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, false), await resolve(this.config.o11yHeaders)),
|
|
41572
41362
|
body: args,
|
|
41573
41363
|
successfulResponseHandler: createJsonResponseHandler(exports_external.any()),
|
|
41574
41364
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
@@ -41591,11 +41381,11 @@ var GatewayLanguageModel = class {
|
|
|
41591
41381
|
async doStream(options) {
|
|
41592
41382
|
const { args, warnings } = await this.getArgs(options);
|
|
41593
41383
|
const { abortSignal } = options;
|
|
41594
|
-
const resolvedHeaders = await
|
|
41384
|
+
const resolvedHeaders = await resolve(this.config.headers());
|
|
41595
41385
|
try {
|
|
41596
41386
|
const { value: response, responseHeaders } = await postJsonToApi({
|
|
41597
41387
|
url: this.getUrl(),
|
|
41598
|
-
headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, true), await
|
|
41388
|
+
headers: combineHeaders(resolvedHeaders, options.headers, this.getModelConfigHeaders(this.modelId, true), await resolve(this.config.o11yHeaders)),
|
|
41599
41389
|
body: args,
|
|
41600
41390
|
successfulResponseHandler: createEventSourceResponseHandler(exports_external.any()),
|
|
41601
41391
|
failedResponseHandler: createJsonErrorResponseHandler({
|
|
@@ -41681,7 +41471,7 @@ var GatewayEmbeddingModel = class {
|
|
|
41681
41471
|
providerOptions
|
|
41682
41472
|
}) {
|
|
41683
41473
|
var _a92;
|
|
41684
|
-
const resolvedHeaders = await
|
|
41474
|
+
const resolvedHeaders = await resolve(this.config.headers());
|
|
41685
41475
|
try {
|
|
41686
41476
|
const {
|
|
41687
41477
|
responseHeaders,
|
|
@@ -41689,7 +41479,7 @@ var GatewayEmbeddingModel = class {
|
|
|
41689
41479
|
rawValue
|
|
41690
41480
|
} = await postJsonToApi({
|
|
41691
41481
|
url: this.getUrl(),
|
|
41692
|
-
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await
|
|
41482
|
+
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve(this.config.o11yHeaders)),
|
|
41693
41483
|
body: {
|
|
41694
41484
|
values,
|
|
41695
41485
|
...providerOptions ? { providerOptions } : {}
|
|
@@ -41751,7 +41541,7 @@ var GatewayImageModel = class {
|
|
|
41751
41541
|
abortSignal
|
|
41752
41542
|
}) {
|
|
41753
41543
|
var _a92, _b92, _c, _d;
|
|
41754
|
-
const resolvedHeaders = await
|
|
41544
|
+
const resolvedHeaders = await resolve(this.config.headers());
|
|
41755
41545
|
try {
|
|
41756
41546
|
const {
|
|
41757
41547
|
responseHeaders,
|
|
@@ -41759,7 +41549,7 @@ var GatewayImageModel = class {
|
|
|
41759
41549
|
rawValue
|
|
41760
41550
|
} = await postJsonToApi({
|
|
41761
41551
|
url: this.getUrl(),
|
|
41762
|
-
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await
|
|
41552
|
+
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve(this.config.o11yHeaders)),
|
|
41763
41553
|
body: {
|
|
41764
41554
|
prompt,
|
|
41765
41555
|
n,
|
|
@@ -41874,11 +41664,11 @@ var GatewayVideoModel = class {
|
|
|
41874
41664
|
abortSignal
|
|
41875
41665
|
}) {
|
|
41876
41666
|
var _a92;
|
|
41877
|
-
const resolvedHeaders = await
|
|
41667
|
+
const resolvedHeaders = await resolve(this.config.headers());
|
|
41878
41668
|
try {
|
|
41879
41669
|
const { responseHeaders, value: responseBody } = await postJsonToApi({
|
|
41880
41670
|
url: this.getUrl(),
|
|
41881
|
-
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await
|
|
41671
|
+
headers: combineHeaders(resolvedHeaders, headers != null ? headers : {}, this.getModelConfigHeaders(), await resolve(this.config.o11yHeaders), { accept: "text/event-stream" }),
|
|
41882
41672
|
body: {
|
|
41883
41673
|
prompt,
|
|
41884
41674
|
n,
|
|
@@ -44749,7 +44539,7 @@ var object2 = ({
|
|
|
44749
44539
|
const schema = asSchema(inputSchema);
|
|
44750
44540
|
return {
|
|
44751
44541
|
name: "object",
|
|
44752
|
-
responseFormat:
|
|
44542
|
+
responseFormat: resolve(schema.jsonSchema).then((jsonSchema2) => ({
|
|
44753
44543
|
type: "json",
|
|
44754
44544
|
schema: jsonSchema2,
|
|
44755
44545
|
...name21 != null && { name: name21 },
|
|
@@ -44811,7 +44601,7 @@ var array2 = ({
|
|
|
44811
44601
|
const elementSchema = asSchema(inputElementSchema);
|
|
44812
44602
|
return {
|
|
44813
44603
|
name: "array",
|
|
44814
|
-
responseFormat:
|
|
44604
|
+
responseFormat: resolve(elementSchema.jsonSchema).then((jsonSchema2) => {
|
|
44815
44605
|
const { $schema, ...itemSchema } = jsonSchema2;
|
|
44816
44606
|
return {
|
|
44817
44607
|
type: "json",
|
|
@@ -50070,7 +49860,7 @@ var Hono2 = class extends Hono {
|
|
|
50070
49860
|
|
|
50071
49861
|
// node_modules/.bun/hono@4.12.5/node_modules/hono/dist/adapter/bun/serve-static.js
|
|
50072
49862
|
import { stat } from "fs/promises";
|
|
50073
|
-
import { join
|
|
49863
|
+
import { join } from "path";
|
|
50074
49864
|
|
|
50075
49865
|
// node_modules/.bun/hono@4.12.5/node_modules/hono/dist/utils/compress.js
|
|
50076
49866
|
var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/(?!event-stream(?:[;\s]|$))[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i;
|
|
@@ -50175,7 +49965,7 @@ var DEFAULT_DOCUMENT = "index.html";
|
|
|
50175
49965
|
var serveStatic = (options) => {
|
|
50176
49966
|
const root = options.root ?? "./";
|
|
50177
49967
|
const optionPath = options.path;
|
|
50178
|
-
const
|
|
49968
|
+
const join = options.join ?? defaultJoin;
|
|
50179
49969
|
return async (c, next) => {
|
|
50180
49970
|
if (c.finalized) {
|
|
50181
49971
|
return next();
|
|
@@ -50194,9 +49984,9 @@ var serveStatic = (options) => {
|
|
|
50194
49984
|
return next();
|
|
50195
49985
|
}
|
|
50196
49986
|
}
|
|
50197
|
-
let path =
|
|
49987
|
+
let path = join(root, !optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename) : filename);
|
|
50198
49988
|
if (options.isDir && await options.isDir(path)) {
|
|
50199
|
-
path =
|
|
49989
|
+
path = join(path, DEFAULT_DOCUMENT);
|
|
50200
49990
|
}
|
|
50201
49991
|
const getContent = options.getContent;
|
|
50202
49992
|
let content = await getContent(path, c);
|
|
@@ -50248,7 +50038,7 @@ var serveStatic2 = (options) => {
|
|
|
50248
50038
|
return serveStatic({
|
|
50249
50039
|
...options,
|
|
50250
50040
|
getContent,
|
|
50251
|
-
join
|
|
50041
|
+
join,
|
|
50252
50042
|
isDir
|
|
50253
50043
|
})(c, next);
|
|
50254
50044
|
};
|
|
@@ -50339,6 +50129,242 @@ var upgradeWebSocket = defineWebSocketHelper((c, events) => {
|
|
|
50339
50129
|
return;
|
|
50340
50130
|
});
|
|
50341
50131
|
|
|
50132
|
+
// src/cli/asset-paths.ts
|
|
50133
|
+
async function findExisting(...candidates) {
|
|
50134
|
+
for (const url2 of candidates) {
|
|
50135
|
+
try {
|
|
50136
|
+
const exists = await Bun.file(url2).exists();
|
|
50137
|
+
if (exists)
|
|
50138
|
+
return url2;
|
|
50139
|
+
} catch {}
|
|
50140
|
+
}
|
|
50141
|
+
return null;
|
|
50142
|
+
}
|
|
50143
|
+
async function readPackageJson() {
|
|
50144
|
+
const url2 = await findExisting(new URL("../../package.json", import.meta.url), new URL("../package.json", import.meta.url), new URL("../../../package.json", import.meta.url));
|
|
50145
|
+
if (!url2)
|
|
50146
|
+
return null;
|
|
50147
|
+
try {
|
|
50148
|
+
return await Bun.file(url2).json();
|
|
50149
|
+
} catch {
|
|
50150
|
+
return null;
|
|
50151
|
+
}
|
|
50152
|
+
}
|
|
50153
|
+
async function readVersionString() {
|
|
50154
|
+
const pkg = await readPackageJson();
|
|
50155
|
+
return typeof pkg?.version === "string" ? pkg.version : "unknown";
|
|
50156
|
+
}
|
|
50157
|
+
|
|
50158
|
+
// src/cli/autostart.ts
|
|
50159
|
+
import { execSync } from "child_process";
|
|
50160
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
50161
|
+
import { homedir as homedir2, platform } from "os";
|
|
50162
|
+
import { dirname as dirname2, join as join3 } from "path";
|
|
50163
|
+
|
|
50164
|
+
// src/cli/runtime.ts
|
|
50165
|
+
import { homedir } from "os";
|
|
50166
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
50167
|
+
function getRuntimeDirs() {
|
|
50168
|
+
const override = process.env.LOCAL_ROUTER_RUNTIME_DIR;
|
|
50169
|
+
const root = override?.trim() ? override.trim() : join2(homedir(), ".local-router");
|
|
50170
|
+
return {
|
|
50171
|
+
root,
|
|
50172
|
+
run: join2(root, "run"),
|
|
50173
|
+
logs: join2(root, "logs")
|
|
50174
|
+
};
|
|
50175
|
+
}
|
|
50176
|
+
|
|
50177
|
+
// src/cli/autostart.ts
|
|
50178
|
+
var LABEL = "com.lakphy.local-router";
|
|
50179
|
+
function getDaemonLogPath() {
|
|
50180
|
+
return getRuntimeDirs().logs + "/daemon.log";
|
|
50181
|
+
}
|
|
50182
|
+
function getLaunchAgentPath() {
|
|
50183
|
+
return join3(homedir2(), "Library", "LaunchAgents", `${LABEL}.plist`);
|
|
50184
|
+
}
|
|
50185
|
+
function buildPlist(opts) {
|
|
50186
|
+
const logPath = getDaemonLogPath();
|
|
50187
|
+
const args = [opts.execPath, ...opts.args].map((a) => ` <string>${escapeXml(a)}</string>`).join(`
|
|
50188
|
+
`);
|
|
50189
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
50190
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
50191
|
+
<plist version="1.0">
|
|
50192
|
+
<dict>
|
|
50193
|
+
<key>Label</key>
|
|
50194
|
+
<string>${escapeXml(opts.label)}</string>
|
|
50195
|
+
<key>ProgramArguments</key>
|
|
50196
|
+
<array>
|
|
50197
|
+
${args}
|
|
50198
|
+
</array>
|
|
50199
|
+
<key>RunAtLoad</key>
|
|
50200
|
+
<true/>
|
|
50201
|
+
<key>KeepAlive</key>
|
|
50202
|
+
<false/>
|
|
50203
|
+
<key>StandardOutPath</key>
|
|
50204
|
+
<string>${escapeXml(logPath)}</string>
|
|
50205
|
+
<key>StandardErrorPath</key>
|
|
50206
|
+
<string>${escapeXml(logPath)}</string>
|
|
50207
|
+
</dict>
|
|
50208
|
+
</plist>
|
|
50209
|
+
`;
|
|
50210
|
+
}
|
|
50211
|
+
function escapeXml(s) {
|
|
50212
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
50213
|
+
}
|
|
50214
|
+
function createMacosManager() {
|
|
50215
|
+
const plistPath = getLaunchAgentPath();
|
|
50216
|
+
return {
|
|
50217
|
+
platform: "macos",
|
|
50218
|
+
async isInstalled() {
|
|
50219
|
+
return existsSync(plistPath);
|
|
50220
|
+
},
|
|
50221
|
+
async install(opts) {
|
|
50222
|
+
const dir = dirname2(plistPath);
|
|
50223
|
+
if (!existsSync(dir))
|
|
50224
|
+
mkdirSync(dir, { recursive: true });
|
|
50225
|
+
writeFileSync(plistPath, buildPlist(opts), "utf-8");
|
|
50226
|
+
try {
|
|
50227
|
+
execSync(`launchctl bootout gui/$(id -u) ${plistPath} 2>/dev/null`, { stdio: "ignore" });
|
|
50228
|
+
} catch {}
|
|
50229
|
+
execSync(`launchctl bootstrap gui/$(id -u) ${plistPath}`, { stdio: "ignore" });
|
|
50230
|
+
},
|
|
50231
|
+
async uninstall() {
|
|
50232
|
+
if (!existsSync(plistPath))
|
|
50233
|
+
return;
|
|
50234
|
+
try {
|
|
50235
|
+
execSync(`launchctl bootout gui/$(id -u) ${plistPath}`, { stdio: "ignore" });
|
|
50236
|
+
} catch {}
|
|
50237
|
+
rmSync(plistPath, { force: true });
|
|
50238
|
+
},
|
|
50239
|
+
getServicePath() {
|
|
50240
|
+
return plistPath;
|
|
50241
|
+
}
|
|
50242
|
+
};
|
|
50243
|
+
}
|
|
50244
|
+
function getSystemdUnitPath() {
|
|
50245
|
+
return join3(homedir2(), ".config", "systemd", "user", "local-router.service");
|
|
50246
|
+
}
|
|
50247
|
+
function buildUnit(opts) {
|
|
50248
|
+
const logPath = getDaemonLogPath();
|
|
50249
|
+
const execStart = [opts.execPath, ...opts.args].join(" ");
|
|
50250
|
+
return `[Unit]
|
|
50251
|
+
Description=Local Router API Gateway
|
|
50252
|
+
After=network-online.target
|
|
50253
|
+
|
|
50254
|
+
[Service]
|
|
50255
|
+
Type=simple
|
|
50256
|
+
ExecStart=${execStart}
|
|
50257
|
+
Restart=on-failure
|
|
50258
|
+
RestartSec=5
|
|
50259
|
+
StandardOutput=append:${logPath}
|
|
50260
|
+
StandardError=append:${logPath}
|
|
50261
|
+
|
|
50262
|
+
[Install]
|
|
50263
|
+
WantedBy=default.target
|
|
50264
|
+
`;
|
|
50265
|
+
}
|
|
50266
|
+
function createLinuxManager() {
|
|
50267
|
+
const unitPath = getSystemdUnitPath();
|
|
50268
|
+
return {
|
|
50269
|
+
platform: "linux",
|
|
50270
|
+
async isInstalled() {
|
|
50271
|
+
if (!existsSync(unitPath))
|
|
50272
|
+
return false;
|
|
50273
|
+
try {
|
|
50274
|
+
const out = execSync("systemctl --user is-enabled local-router 2>/dev/null", {
|
|
50275
|
+
encoding: "utf-8"
|
|
50276
|
+
}).trim();
|
|
50277
|
+
return out === "enabled";
|
|
50278
|
+
} catch {
|
|
50279
|
+
return false;
|
|
50280
|
+
}
|
|
50281
|
+
},
|
|
50282
|
+
async install(opts) {
|
|
50283
|
+
const dir = dirname2(unitPath);
|
|
50284
|
+
if (!existsSync(dir))
|
|
50285
|
+
mkdirSync(dir, { recursive: true });
|
|
50286
|
+
writeFileSync(unitPath, buildUnit(opts), "utf-8");
|
|
50287
|
+
execSync("systemctl --user daemon-reload", { stdio: "ignore" });
|
|
50288
|
+
execSync("systemctl --user enable local-router", { stdio: "ignore" });
|
|
50289
|
+
},
|
|
50290
|
+
async uninstall() {
|
|
50291
|
+
try {
|
|
50292
|
+
execSync("systemctl --user disable local-router", { stdio: "ignore" });
|
|
50293
|
+
} catch {}
|
|
50294
|
+
rmSync(unitPath, { force: true });
|
|
50295
|
+
try {
|
|
50296
|
+
execSync("systemctl --user daemon-reload", { stdio: "ignore" });
|
|
50297
|
+
} catch {}
|
|
50298
|
+
},
|
|
50299
|
+
getServicePath() {
|
|
50300
|
+
return unitPath;
|
|
50301
|
+
}
|
|
50302
|
+
};
|
|
50303
|
+
}
|
|
50304
|
+
var WIN_REG_KEY = "HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run";
|
|
50305
|
+
var WIN_REG_VALUE = "LocalRouter";
|
|
50306
|
+
function createWindowsManager() {
|
|
50307
|
+
return {
|
|
50308
|
+
platform: "windows",
|
|
50309
|
+
async isInstalled() {
|
|
50310
|
+
try {
|
|
50311
|
+
execSync(`reg query "${WIN_REG_KEY}" /v ${WIN_REG_VALUE}`, { stdio: "ignore" });
|
|
50312
|
+
return true;
|
|
50313
|
+
} catch {
|
|
50314
|
+
return false;
|
|
50315
|
+
}
|
|
50316
|
+
},
|
|
50317
|
+
async install(opts) {
|
|
50318
|
+
const cmd = [opts.execPath, ...opts.args].map((a) => `"${a}"`).join(" ");
|
|
50319
|
+
execSync(`reg add "${WIN_REG_KEY}" /v ${WIN_REG_VALUE} /t REG_SZ /d "${cmd}" /f`, {
|
|
50320
|
+
stdio: "ignore"
|
|
50321
|
+
});
|
|
50322
|
+
},
|
|
50323
|
+
async uninstall() {
|
|
50324
|
+
try {
|
|
50325
|
+
execSync(`reg delete "${WIN_REG_KEY}" /v ${WIN_REG_VALUE} /f`, { stdio: "ignore" });
|
|
50326
|
+
} catch {}
|
|
50327
|
+
},
|
|
50328
|
+
getServicePath() {
|
|
50329
|
+
return `${WIN_REG_KEY}\\${WIN_REG_VALUE}`;
|
|
50330
|
+
}
|
|
50331
|
+
};
|
|
50332
|
+
}
|
|
50333
|
+
function createUnsupportedManager() {
|
|
50334
|
+
return {
|
|
50335
|
+
platform: "unsupported",
|
|
50336
|
+
async isInstalled() {
|
|
50337
|
+
return false;
|
|
50338
|
+
},
|
|
50339
|
+
async install() {
|
|
50340
|
+
throw new Error("\u5F53\u524D\u5E73\u53F0\u4E0D\u652F\u6301\u81EA\u542F\u52A8");
|
|
50341
|
+
},
|
|
50342
|
+
async uninstall() {
|
|
50343
|
+
throw new Error("\u5F53\u524D\u5E73\u53F0\u4E0D\u652F\u6301\u81EA\u542F\u52A8");
|
|
50344
|
+
},
|
|
50345
|
+
getServicePath() {
|
|
50346
|
+
return "";
|
|
50347
|
+
}
|
|
50348
|
+
};
|
|
50349
|
+
}
|
|
50350
|
+
function createAutostartManager() {
|
|
50351
|
+
const p = platform();
|
|
50352
|
+
if (p === "darwin")
|
|
50353
|
+
return createMacosManager();
|
|
50354
|
+
if (p === "linux")
|
|
50355
|
+
return createLinuxManager();
|
|
50356
|
+
if (p === "win32")
|
|
50357
|
+
return createWindowsManager();
|
|
50358
|
+
return createUnsupportedManager();
|
|
50359
|
+
}
|
|
50360
|
+
function getAutostartExecArgs() {
|
|
50361
|
+
const script = process.argv[1] ?? "dist/cli.js";
|
|
50362
|
+
return {
|
|
50363
|
+
execPath: process.execPath,
|
|
50364
|
+
args: [script, "__run-server", "--mode", "daemon"]
|
|
50365
|
+
};
|
|
50366
|
+
}
|
|
50367
|
+
|
|
50342
50368
|
// src/config.ts
|
|
50343
50369
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
50344
50370
|
import { homedir as homedir3 } from "os";
|
|
@@ -56217,6 +56243,97 @@ var openAPISpec = {
|
|
|
56217
56243
|
}
|
|
56218
56244
|
}
|
|
56219
56245
|
},
|
|
56246
|
+
"/api/models": {
|
|
56247
|
+
get: {
|
|
56248
|
+
tags: ["Health"],
|
|
56249
|
+
summary: "\u55C5\u63A2\u53EF\u7528\u6A21\u578B\u8DEF\u7531",
|
|
56250
|
+
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",
|
|
56251
|
+
parameters: [
|
|
56252
|
+
{
|
|
56253
|
+
name: "protocol",
|
|
56254
|
+
in: "query",
|
|
56255
|
+
required: true,
|
|
56256
|
+
schema: {
|
|
56257
|
+
type: "string",
|
|
56258
|
+
enum: ["openai-completions", "openai-responses", "anthropic-messages"]
|
|
56259
|
+
},
|
|
56260
|
+
description: "\u534F\u8BAE\u7C7B\u578B"
|
|
56261
|
+
}
|
|
56262
|
+
],
|
|
56263
|
+
responses: {
|
|
56264
|
+
"200": {
|
|
56265
|
+
description: "\u53EF\u7528\u6A21\u578B\u8DEF\u7531\u5217\u8868",
|
|
56266
|
+
content: {
|
|
56267
|
+
"application/json": {
|
|
56268
|
+
schema: {
|
|
56269
|
+
type: "object",
|
|
56270
|
+
properties: {
|
|
56271
|
+
protocol: { type: "string", example: "anthropic-messages" },
|
|
56272
|
+
models: {
|
|
56273
|
+
type: "array",
|
|
56274
|
+
items: { type: "string" },
|
|
56275
|
+
example: ["claude-3-5-sonnet", "claude-3-opus"]
|
|
56276
|
+
}
|
|
56277
|
+
}
|
|
56278
|
+
}
|
|
56279
|
+
}
|
|
56280
|
+
}
|
|
56281
|
+
},
|
|
56282
|
+
"400": { description: "\u534F\u8BAE\u53C2\u6570\u7F3A\u5931\u6216\u65E0\u6548" }
|
|
56283
|
+
}
|
|
56284
|
+
}
|
|
56285
|
+
},
|
|
56286
|
+
"/api/providers/discover": {
|
|
56287
|
+
get: {
|
|
56288
|
+
tags: ["Health"],
|
|
56289
|
+
summary: "\u53D1\u73B0\u5C40\u57DF\u7F51 local-router \u7684\u6A21\u578B",
|
|
56290
|
+
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",
|
|
56291
|
+
parameters: [
|
|
56292
|
+
{
|
|
56293
|
+
name: "ip",
|
|
56294
|
+
in: "query",
|
|
56295
|
+
required: true,
|
|
56296
|
+
schema: { type: "string" },
|
|
56297
|
+
description: "\u5BF9\u7AEF IP"
|
|
56298
|
+
},
|
|
56299
|
+
{
|
|
56300
|
+
name: "port",
|
|
56301
|
+
in: "query",
|
|
56302
|
+
required: false,
|
|
56303
|
+
schema: { type: "string", default: "4099" },
|
|
56304
|
+
description: "\u5BF9\u7AEF\u7AEF\u53E3\uFF0C\u9ED8\u8BA4 4099"
|
|
56305
|
+
},
|
|
56306
|
+
{
|
|
56307
|
+
name: "protocol",
|
|
56308
|
+
in: "query",
|
|
56309
|
+
required: true,
|
|
56310
|
+
schema: {
|
|
56311
|
+
type: "string",
|
|
56312
|
+
enum: ["openai-completions", "openai-responses", "anthropic-messages"]
|
|
56313
|
+
},
|
|
56314
|
+
description: "\u534F\u8BAE\u7C7B\u578B"
|
|
56315
|
+
}
|
|
56316
|
+
],
|
|
56317
|
+
responses: {
|
|
56318
|
+
"200": {
|
|
56319
|
+
description: "\u5BF9\u7AEF\u53EF\u7528\u6A21\u578B\u8DEF\u7531\u5217\u8868",
|
|
56320
|
+
content: {
|
|
56321
|
+
"application/json": {
|
|
56322
|
+
schema: {
|
|
56323
|
+
type: "object",
|
|
56324
|
+
properties: {
|
|
56325
|
+
protocol: { type: "string", example: "anthropic-messages" },
|
|
56326
|
+
models: { type: "array", items: { type: "string" } }
|
|
56327
|
+
}
|
|
56328
|
+
}
|
|
56329
|
+
}
|
|
56330
|
+
}
|
|
56331
|
+
},
|
|
56332
|
+
"400": { description: "\u53C2\u6570\u7F3A\u5931" },
|
|
56333
|
+
"502": { description: "\u65E0\u6CD5\u8FDE\u63A5\u5BF9\u7AEF\u6216\u5BF9\u7AEF\u8FD4\u56DE\u9519\u8BEF" }
|
|
56334
|
+
}
|
|
56335
|
+
}
|
|
56336
|
+
},
|
|
56220
56337
|
"/api/metrics/logs": {
|
|
56221
56338
|
get: {
|
|
56222
56339
|
tags: ["Health"],
|
|
@@ -57970,6 +58087,13 @@ function createServerAddressInfo(listenHost, port) {
|
|
|
57970
58087
|
}
|
|
57971
58088
|
|
|
57972
58089
|
// src/index.ts
|
|
58090
|
+
function readRestartCriticalServerFields(config2) {
|
|
58091
|
+
return {
|
|
58092
|
+
host: config2.server?.host ?? "0.0.0.0",
|
|
58093
|
+
port: config2.server?.port ?? 4099,
|
|
58094
|
+
idleTimeout: config2.server?.idleTimeout ?? 0
|
|
58095
|
+
};
|
|
58096
|
+
}
|
|
57973
58097
|
var ROUTE_REGISTRY = {
|
|
57974
58098
|
"openai-completions": {
|
|
57975
58099
|
mountPrefix: "/openai-completions",
|
|
@@ -58087,7 +58211,7 @@ function createChatProxyModel(providerName, providerConfig, model) {
|
|
|
58087
58211
|
throw new Error(`\u6682\u4E0D\u652F\u6301\u7684 provider \u7C7B\u578B: ${providerConfig.type}`);
|
|
58088
58212
|
}
|
|
58089
58213
|
}
|
|
58090
|
-
function createAdminApiRoutes(store, pluginManager, registerCleanup) {
|
|
58214
|
+
function createAdminApiRoutes(store, pluginManager, registerCleanup, serverControl, restartLogStorageTask, serviceVersion) {
|
|
58091
58215
|
const api2 = new Hono2;
|
|
58092
58216
|
const cryptoSessions = new Map;
|
|
58093
58217
|
const CRYPTO_SESSION_TTL_MS = 2 * 60 * 1000;
|
|
@@ -58127,7 +58251,16 @@ function createAdminApiRoutes(store, pluginManager, registerCleanup) {
|
|
|
58127
58251
|
}
|
|
58128
58252
|
cryptoSessions.clear();
|
|
58129
58253
|
});
|
|
58130
|
-
api2.get("/health", (c2) =>
|
|
58254
|
+
api2.get("/health", (c2) => {
|
|
58255
|
+
const addr = serverControl?.current ?? readRestartCriticalServerFields(store.get());
|
|
58256
|
+
return c2.json({
|
|
58257
|
+
status: "ok",
|
|
58258
|
+
service: "local-router",
|
|
58259
|
+
version: serviceVersion ?? "unknown",
|
|
58260
|
+
host: addr.host,
|
|
58261
|
+
port: addr.port
|
|
58262
|
+
});
|
|
58263
|
+
});
|
|
58131
58264
|
api2.post("/crypto/handshake", async (c2) => {
|
|
58132
58265
|
pruneExpiredCryptoSessions();
|
|
58133
58266
|
if (cryptoSessions.size >= CRYPTO_SESSION_MAX) {
|
|
@@ -58200,18 +58333,30 @@ function createAdminApiRoutes(store, pluginManager, registerCleanup) {
|
|
|
58200
58333
|
});
|
|
58201
58334
|
api2.post("/config/apply", async (_c) => {
|
|
58202
58335
|
try {
|
|
58336
|
+
const fallbackBefore = readRestartCriticalServerFields(store.get());
|
|
58337
|
+
const before = serverControl?.current ?? fallbackBefore;
|
|
58203
58338
|
const config2 = store.reload();
|
|
58339
|
+
const after = readRestartCriticalServerFields(config2);
|
|
58204
58340
|
if (config2.log) {
|
|
58205
58341
|
const logBaseDir = resolveLogBaseDir(config2.log);
|
|
58206
58342
|
initLogger(logBaseDir, config2.log);
|
|
58343
|
+
} else {
|
|
58344
|
+
resetLogger();
|
|
58207
58345
|
}
|
|
58346
|
+
restartLogStorageTask?.(config2.log);
|
|
58208
58347
|
const pluginResult = await pluginManager.reloadAll(config2.providers);
|
|
58348
|
+
const restartRequired = before.host !== after.host || before.port !== after.port || before.idleTimeout !== after.idleTimeout;
|
|
58209
58349
|
return _c.json({
|
|
58210
58350
|
ok: true,
|
|
58211
58351
|
summary: {
|
|
58212
58352
|
providers: Object.keys(config2.providers).length,
|
|
58213
58353
|
routes: Object.keys(config2.routes).length
|
|
58214
58354
|
},
|
|
58355
|
+
restartRequired,
|
|
58356
|
+
...restartRequired && {
|
|
58357
|
+
listen: { host: after.host, port: after.port },
|
|
58358
|
+
canRestart: Boolean(serverControl)
|
|
58359
|
+
},
|
|
58215
58360
|
...pluginResult.failures.length > 0 && {
|
|
58216
58361
|
pluginWarnings: pluginResult.failures
|
|
58217
58362
|
}
|
|
@@ -58220,12 +58365,57 @@ function createAdminApiRoutes(store, pluginManager, registerCleanup) {
|
|
|
58220
58365
|
return _c.json({ error: `\u5E94\u7528\u914D\u7F6E\u5931\u8D25: ${err instanceof Error ? err.message : err}` }, 500);
|
|
58221
58366
|
}
|
|
58222
58367
|
});
|
|
58368
|
+
api2.post("/restart", (c2) => {
|
|
58369
|
+
if (!serverControl) {
|
|
58370
|
+
return c2.json({ error: "\u5F53\u524D\u8FD0\u884C\u65B9\u5F0F\u4E0D\u652F\u6301\u81EA\u52A8\u91CD\u542F\uFF0C\u8BF7\u624B\u52A8\u6267\u884C local-router restart" }, 501);
|
|
58371
|
+
}
|
|
58372
|
+
const { host, port } = readRestartCriticalServerFields(store.get());
|
|
58373
|
+
serverControl.requestRestart();
|
|
58374
|
+
return c2.json({ ok: true, listen: { host, port } });
|
|
58375
|
+
});
|
|
58223
58376
|
api2.get("/config/meta", (c2) => {
|
|
58224
58377
|
return c2.json({
|
|
58225
58378
|
configPath: store.getPath(),
|
|
58226
58379
|
routeTypes: Object.keys(ROUTE_REGISTRY)
|
|
58227
58380
|
});
|
|
58228
58381
|
});
|
|
58382
|
+
api2.get("/models", (c2) => {
|
|
58383
|
+
const protocol = c2.req.query("protocol");
|
|
58384
|
+
const routeTypes = Object.keys(ROUTE_REGISTRY);
|
|
58385
|
+
if (!protocol || !routeTypes.includes(protocol)) {
|
|
58386
|
+
return c2.json({ error: "invalid or missing protocol", routeTypes }, 400);
|
|
58387
|
+
}
|
|
58388
|
+
const routes = store.get().routes[protocol] ?? {};
|
|
58389
|
+
const models = Object.keys(routes).filter((k) => k !== "*");
|
|
58390
|
+
return c2.json({ protocol, models });
|
|
58391
|
+
});
|
|
58392
|
+
api2.get("/providers/discover", async (c2) => {
|
|
58393
|
+
const ip = c2.req.query("ip");
|
|
58394
|
+
const portStr = c2.req.query("port") ?? "4099";
|
|
58395
|
+
const protocol = c2.req.query("protocol");
|
|
58396
|
+
if (!ip || !protocol) {
|
|
58397
|
+
return c2.json({ error: "ip and protocol are required" }, 400);
|
|
58398
|
+
}
|
|
58399
|
+
const port = Number(portStr);
|
|
58400
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
58401
|
+
return c2.json({ error: "\u7AEF\u53E3\u65E0\u6548\uFF0C\u5FC5\u987B\u662F 1-65535 \u7684\u6574\u6570" }, 400);
|
|
58402
|
+
}
|
|
58403
|
+
if (!isLoopbackAddress(ip) && !isLanAddress(ip)) {
|
|
58404
|
+
return c2.json({ error: "\u4EC5\u652F\u6301\u5C40\u57DF\u7F51\u6216\u672C\u673A IP \u5730\u5740" }, 400);
|
|
58405
|
+
}
|
|
58406
|
+
const url2 = `http://${ip}:${port}/api/models?protocol=${encodeURIComponent(protocol)}`;
|
|
58407
|
+
try {
|
|
58408
|
+
const res = await fetch(url2, { signal: AbortSignal.timeout(5000) });
|
|
58409
|
+
if (!res.ok) {
|
|
58410
|
+
const body = await res.json().catch(() => ({}));
|
|
58411
|
+
return c2.json({ error: body.error ?? `remote returned ${res.status}` }, 502);
|
|
58412
|
+
}
|
|
58413
|
+
const data = await res.json();
|
|
58414
|
+
return c2.json(data);
|
|
58415
|
+
} catch (err) {
|
|
58416
|
+
return c2.json({ error: `\u65E0\u6CD5\u8FDE\u63A5\u5BF9\u7AEF local-router: ${err instanceof Error ? err.message : err}` }, 502);
|
|
58417
|
+
}
|
|
58418
|
+
});
|
|
58229
58419
|
api2.get("/config/schema", (c2) => {
|
|
58230
58420
|
try {
|
|
58231
58421
|
return c2.json(schemaJson);
|
|
@@ -58728,6 +58918,7 @@ async function proxyAdminToDevServer(c2, origin) {
|
|
|
58728
58918
|
}
|
|
58729
58919
|
async function createApp(store, options) {
|
|
58730
58920
|
const config2 = store.get();
|
|
58921
|
+
const serviceVersion = await readVersionString();
|
|
58731
58922
|
console.log(`\u5DF2\u52A0\u8F7D\u914D\u7F6E: ${store.getPath()}`);
|
|
58732
58923
|
if (config2.log) {
|
|
58733
58924
|
const logBaseDir = resolveLogBaseDir(config2.log);
|
|
@@ -58735,8 +58926,14 @@ async function createApp(store, options) {
|
|
|
58735
58926
|
} else {
|
|
58736
58927
|
resetLogger();
|
|
58737
58928
|
}
|
|
58738
|
-
|
|
58739
|
-
|
|
58929
|
+
let stopLogStorageTask = startLogStorageBackgroundTask(config2.log);
|
|
58930
|
+
const restartLogStorageTask = (logConfig) => {
|
|
58931
|
+
try {
|
|
58932
|
+
stopLogStorageTask();
|
|
58933
|
+
} catch {}
|
|
58934
|
+
stopLogStorageTask = startLogStorageBackgroundTask(logConfig);
|
|
58935
|
+
};
|
|
58936
|
+
options?.registerCleanup?.(() => stopLogStorageTask());
|
|
58740
58937
|
const configDir = dirname3(resolve8(store.getPath()));
|
|
58741
58938
|
const pluginManager = new PluginManager(configDir);
|
|
58742
58939
|
const reloadResult = await pluginManager.reloadAll(config2.providers);
|
|
@@ -58755,7 +58952,7 @@ async function createApp(store, options) {
|
|
|
58755
58952
|
app.route(entry.mountPrefix, subApp);
|
|
58756
58953
|
console.log(`\u5DF2\u6CE8\u518C\u8DEF\u7531: ${routeType} -> ${entry.mountPrefix}`);
|
|
58757
58954
|
}
|
|
58758
|
-
app.route("/api", createAdminApiRoutes(store, pluginManager, options?.registerCleanup));
|
|
58955
|
+
app.route("/api", createAdminApiRoutes(store, pluginManager, options?.registerCleanup, options?.serverControl, restartLogStorageTask, serviceVersion));
|
|
58759
58956
|
console.log("\u5DF2\u6CE8\u518C\u7BA1\u7406 API: /api");
|
|
58760
58957
|
app.get("/api/docs", middleware({ url: "/api/openapi.json" }));
|
|
58761
58958
|
app.get("/api/openapi.json", (c2) => c2.json(openAPISpec));
|
|
@@ -58784,11 +58981,12 @@ async function createApp(store, options) {
|
|
|
58784
58981
|
}
|
|
58785
58982
|
return app;
|
|
58786
58983
|
}
|
|
58787
|
-
async function createAppRuntimeFromConfigPath(configPath, listen) {
|
|
58984
|
+
async function createAppRuntimeFromConfigPath(configPath, listen, serverControl) {
|
|
58788
58985
|
const store = new ConfigStore(configPath);
|
|
58789
58986
|
const cleanups = [];
|
|
58790
58987
|
const app = await createApp(store, {
|
|
58791
58988
|
listen,
|
|
58989
|
+
serverControl,
|
|
58792
58990
|
registerCleanup: (cleanup) => {
|
|
58793
58991
|
cleanups.push(cleanup);
|
|
58794
58992
|
}
|