@lakphy/local-router 0.3.3 → 0.4.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config.schema.json +26 -0
- package/dist/cli.js +470 -57
- package/dist/entry.js +455 -42
- package/dist/web/assets/index-DuaLtWlv.js +191 -0
- package/dist/web/assets/index-RuflkSNT.css +2 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-CbUvycUp.css +0 -2
- package/dist/web/assets/index-Dz4pO265.js +0 -191
package/dist/cli.js
CHANGED
|
@@ -4935,7 +4935,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
4935
4935
|
const schOrFunc = root2.refs[ref];
|
|
4936
4936
|
if (schOrFunc)
|
|
4937
4937
|
return schOrFunc;
|
|
4938
|
-
let _sch =
|
|
4938
|
+
let _sch = resolve6.call(this, root2, ref);
|
|
4939
4939
|
if (_sch === undefined) {
|
|
4940
4940
|
const schema = (_a21 = root2.localRefs) === null || _a21 === undefined ? undefined : _a21[ref];
|
|
4941
4941
|
const { schemaId } = this.opts;
|
|
@@ -4962,7 +4962,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
4962
4962
|
function sameSchemaEnv(s1, s2) {
|
|
4963
4963
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
4964
4964
|
}
|
|
4965
|
-
function
|
|
4965
|
+
function resolve6(root2, ref) {
|
|
4966
4966
|
let sch;
|
|
4967
4967
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
4968
4968
|
ref = sch;
|
|
@@ -5492,7 +5492,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
5492
5492
|
}
|
|
5493
5493
|
return uri;
|
|
5494
5494
|
}
|
|
5495
|
-
function
|
|
5495
|
+
function resolve6(baseURI, relativeURI, options) {
|
|
5496
5496
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
5497
5497
|
const resolved = resolveComponent(parse7(baseURI, schemelessOptions), parse7(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
5498
5498
|
schemelessOptions.skipEscape = true;
|
|
@@ -5720,7 +5720,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
5720
5720
|
var fastUri = {
|
|
5721
5721
|
SCHEMES,
|
|
5722
5722
|
normalize,
|
|
5723
|
-
resolve:
|
|
5723
|
+
resolve: resolve6,
|
|
5724
5724
|
resolveComponent,
|
|
5725
5725
|
equal,
|
|
5726
5726
|
serialize,
|
|
@@ -10518,6 +10518,7 @@ import { parseArgs } from "util";
|
|
|
10518
10518
|
|
|
10519
10519
|
// src/index.ts
|
|
10520
10520
|
import { readFileSync as readFileSync4 } from "fs";
|
|
10521
|
+
import { dirname as dirname2, resolve as resolve6 } from "path";
|
|
10521
10522
|
|
|
10522
10523
|
// node_modules/.bun/@ai-sdk+provider@3.0.8/node_modules/@ai-sdk/provider/dist/index.mjs
|
|
10523
10524
|
var marker = "vercel.ai.error";
|
|
@@ -52118,6 +52119,14 @@ async function buildLogEventDetail(id, parsed, location, context2) {
|
|
|
52118
52119
|
const responseBodyAvailable = event.response_body !== undefined;
|
|
52119
52120
|
const streamCaptured = Boolean(event.stream_file);
|
|
52120
52121
|
const { content: streamContent, warning: streamWarning } = readStreamContent(resolveLogBaseDir(context2.logConfig), event.stream_file);
|
|
52122
|
+
const hasPluginData = event.plugins_request || event.plugins_response || event.request_body_after_plugins !== undefined || event.request_url_after_plugins !== undefined || event.response_body_after_plugins !== undefined;
|
|
52123
|
+
const pluginsSection = hasPluginData ? {
|
|
52124
|
+
request: event.plugins_request,
|
|
52125
|
+
response: event.plugins_response,
|
|
52126
|
+
requestBodyAfterPlugins: event.request_body_after_plugins,
|
|
52127
|
+
requestUrlAfterPlugins: event.request_url_after_plugins,
|
|
52128
|
+
responseBodyAfterPlugins: event.response_body_after_plugins
|
|
52129
|
+
} : undefined;
|
|
52121
52130
|
return {
|
|
52122
52131
|
id,
|
|
52123
52132
|
summary: {
|
|
@@ -52169,6 +52178,7 @@ async function buildLogEventDetail(id, parsed, location, context2) {
|
|
|
52169
52178
|
...streamWarning ? [streamWarning] : []
|
|
52170
52179
|
]
|
|
52171
52180
|
},
|
|
52181
|
+
...pluginsSection && { plugins: pluginsSection },
|
|
52172
52182
|
rawEvent: event,
|
|
52173
52183
|
location
|
|
52174
52184
|
};
|
|
@@ -54081,10 +54091,301 @@ var openAPISpec = {
|
|
|
54081
54091
|
}
|
|
54082
54092
|
};
|
|
54083
54093
|
|
|
54094
|
+
// src/plugin-loader.ts
|
|
54095
|
+
import { resolve as resolve5, join as join8 } from "path";
|
|
54096
|
+
import { tmpdir } from "os";
|
|
54097
|
+
import { mkdtemp, writeFile, rm } from "fs/promises";
|
|
54098
|
+
function isLocalPath(pkg) {
|
|
54099
|
+
return pkg.startsWith("./") || pkg.startsWith("../") || pkg.startsWith("/") || /^[A-Za-z]:[\\/]/.test(pkg);
|
|
54100
|
+
}
|
|
54101
|
+
function isRemoteUrl(pkg) {
|
|
54102
|
+
return pkg.startsWith("http://") || pkg.startsWith("https://");
|
|
54103
|
+
}
|
|
54104
|
+
function inferExtension(url2, contentType) {
|
|
54105
|
+
const pathname = new URL(url2).pathname;
|
|
54106
|
+
if (pathname.endsWith(".ts") || pathname.endsWith(".tsx"))
|
|
54107
|
+
return ".ts";
|
|
54108
|
+
if (pathname.endsWith(".mjs"))
|
|
54109
|
+
return ".mjs";
|
|
54110
|
+
if (pathname.endsWith(".cjs"))
|
|
54111
|
+
return ".cjs";
|
|
54112
|
+
if (contentType?.includes("typescript"))
|
|
54113
|
+
return ".ts";
|
|
54114
|
+
return ".js";
|
|
54115
|
+
}
|
|
54116
|
+
var remoteTmpDir = null;
|
|
54117
|
+
var remoteTmpFiles = [];
|
|
54118
|
+
async function ensureRemoteTmpDir() {
|
|
54119
|
+
if (!remoteTmpDir) {
|
|
54120
|
+
remoteTmpDir = await mkdtemp(join8(tmpdir(), "local-router-plugins-"));
|
|
54121
|
+
}
|
|
54122
|
+
return remoteTmpDir;
|
|
54123
|
+
}
|
|
54124
|
+
async function fetchRemotePlugin(url2) {
|
|
54125
|
+
const response = await fetch(url2);
|
|
54126
|
+
if (!response.ok) {
|
|
54127
|
+
throw new Error(`\u4E0B\u8F7D\u8FDC\u7A0B\u63D2\u4EF6\u5931\u8D25: HTTP ${response.status} ${response.statusText} (${url2})`);
|
|
54128
|
+
}
|
|
54129
|
+
const content = await response.text();
|
|
54130
|
+
const ext = inferExtension(url2, response.headers.get("content-type"));
|
|
54131
|
+
const dir = await ensureRemoteTmpDir();
|
|
54132
|
+
const fileName = `plugin_${Date.now()}_${Math.random().toString(36).slice(2, 8)}${ext}`;
|
|
54133
|
+
const filePath = join8(dir, fileName);
|
|
54134
|
+
await writeFile(filePath, content, "utf-8");
|
|
54135
|
+
remoteTmpFiles.push(filePath);
|
|
54136
|
+
return filePath;
|
|
54137
|
+
}
|
|
54138
|
+
async function cleanupRemoteTmpFiles() {
|
|
54139
|
+
if (remoteTmpDir) {
|
|
54140
|
+
try {
|
|
54141
|
+
await rm(remoteTmpDir, { recursive: true, force: true });
|
|
54142
|
+
} catch {}
|
|
54143
|
+
remoteTmpDir = null;
|
|
54144
|
+
remoteTmpFiles.length = 0;
|
|
54145
|
+
}
|
|
54146
|
+
}
|
|
54147
|
+
async function importPlugin(pkg, configDir) {
|
|
54148
|
+
let modulePath;
|
|
54149
|
+
if (isRemoteUrl(pkg)) {
|
|
54150
|
+
const localPath = await fetchRemotePlugin(pkg);
|
|
54151
|
+
modulePath = `${localPath}?t=${Date.now()}`;
|
|
54152
|
+
} else if (isLocalPath(pkg)) {
|
|
54153
|
+
const absolutePath = resolve5(configDir, pkg);
|
|
54154
|
+
modulePath = `${absolutePath}?t=${Date.now()}`;
|
|
54155
|
+
} else {
|
|
54156
|
+
modulePath = pkg;
|
|
54157
|
+
}
|
|
54158
|
+
const mod = await import(modulePath);
|
|
54159
|
+
const definition = mod.default ?? mod;
|
|
54160
|
+
if (!definition || typeof definition.name !== "string" || typeof definition.create !== "function") {
|
|
54161
|
+
throw new Error(`\u63D2\u4EF6 "${pkg}" \u5BFC\u51FA\u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u9700\u5BFC\u51FA\u5305\u542B name \u548C create \u7684 PluginDefinition`);
|
|
54162
|
+
}
|
|
54163
|
+
return definition;
|
|
54164
|
+
}
|
|
54165
|
+
|
|
54166
|
+
class PluginManager {
|
|
54167
|
+
plugins = new Map;
|
|
54168
|
+
configDir;
|
|
54169
|
+
constructor(configDir) {
|
|
54170
|
+
this.configDir = configDir;
|
|
54171
|
+
}
|
|
54172
|
+
async loadPluginsForProvider(providerName, pluginConfigs) {
|
|
54173
|
+
const loaded = [];
|
|
54174
|
+
const failures = [];
|
|
54175
|
+
for (const config2 of pluginConfigs) {
|
|
54176
|
+
try {
|
|
54177
|
+
const definition = await importPlugin(config2.package, this.configDir);
|
|
54178
|
+
const instance2 = await definition.create(config2.params ?? {});
|
|
54179
|
+
loaded.push({ config: config2, definition, instance: instance2 });
|
|
54180
|
+
} catch (err) {
|
|
54181
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
54182
|
+
console.error(`[plugin] \u52A0\u8F7D\u63D2\u4EF6 "${config2.package}" \u5931\u8D25 (provider: ${providerName}):`, errorMsg);
|
|
54183
|
+
failures.push({ provider: providerName, package: config2.package, error: errorMsg });
|
|
54184
|
+
}
|
|
54185
|
+
}
|
|
54186
|
+
return { loaded, failures };
|
|
54187
|
+
}
|
|
54188
|
+
async reloadAll(providers) {
|
|
54189
|
+
const newPlugins = new Map;
|
|
54190
|
+
const allFailures = [];
|
|
54191
|
+
const oldPluginsToDispose = [];
|
|
54192
|
+
for (const [providerName, providerConfig] of Object.entries(providers)) {
|
|
54193
|
+
if (providerConfig.plugins && providerConfig.plugins.length > 0) {
|
|
54194
|
+
const { loaded, failures } = await this.loadPluginsForProvider(providerName, providerConfig.plugins);
|
|
54195
|
+
allFailures.push(...failures);
|
|
54196
|
+
if (failures.length > 0) {
|
|
54197
|
+
console.warn(`[plugin] provider "${providerName}" \u6709\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25\uFF0C\u4FDD\u7559\u65E7\u63D2\u4EF6\u94FE`);
|
|
54198
|
+
const oldLoaded = this.plugins.get(providerName);
|
|
54199
|
+
if (oldLoaded) {
|
|
54200
|
+
newPlugins.set(providerName, oldLoaded);
|
|
54201
|
+
}
|
|
54202
|
+
for (const { instance: instance2, config: config2 } of loaded) {
|
|
54203
|
+
try {
|
|
54204
|
+
await instance2.dispose?.();
|
|
54205
|
+
} catch (err) {
|
|
54206
|
+
console.error(`[plugin] \u56DE\u6EDA\u9500\u6BC1\u63D2\u4EF6 "${config2.package}" \u5931\u8D25:`, err instanceof Error ? err.message : err);
|
|
54207
|
+
}
|
|
54208
|
+
}
|
|
54209
|
+
} else {
|
|
54210
|
+
newPlugins.set(providerName, loaded);
|
|
54211
|
+
const oldLoaded = this.plugins.get(providerName);
|
|
54212
|
+
if (oldLoaded) {
|
|
54213
|
+
oldPluginsToDispose.push(...oldLoaded);
|
|
54214
|
+
}
|
|
54215
|
+
}
|
|
54216
|
+
}
|
|
54217
|
+
}
|
|
54218
|
+
for (const [providerName, oldLoaded] of this.plugins) {
|
|
54219
|
+
if (!newPlugins.has(providerName)) {
|
|
54220
|
+
oldPluginsToDispose.push(...oldLoaded);
|
|
54221
|
+
}
|
|
54222
|
+
}
|
|
54223
|
+
this.plugins = newPlugins;
|
|
54224
|
+
if (oldPluginsToDispose.length > 0) {
|
|
54225
|
+
setTimeout(() => {
|
|
54226
|
+
this.disposePluginList(oldPluginsToDispose).catch((err) => {
|
|
54227
|
+
console.error("[plugin] \u65E7\u63D2\u4EF6\u9500\u6BC1\u5931\u8D25:", err);
|
|
54228
|
+
});
|
|
54229
|
+
}, 5000);
|
|
54230
|
+
}
|
|
54231
|
+
if (allFailures.length > 0) {
|
|
54232
|
+
console.warn(`[plugin] \u70ED\u91CD\u8F7D\u5B8C\u6210\uFF0C\u4F46\u6709 ${allFailures.length} \u4E2A\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25:`, allFailures.map((f) => `${f.provider}/${f.package}`).join(", "));
|
|
54233
|
+
}
|
|
54234
|
+
return { ok: allFailures.length === 0, failures: allFailures };
|
|
54235
|
+
}
|
|
54236
|
+
getPlugins(providerName) {
|
|
54237
|
+
const loaded = this.plugins.get(providerName);
|
|
54238
|
+
if (!loaded)
|
|
54239
|
+
return [];
|
|
54240
|
+
return loaded.map((l) => l.instance);
|
|
54241
|
+
}
|
|
54242
|
+
getLoadedPlugins(providerName) {
|
|
54243
|
+
return this.plugins.get(providerName) ?? [];
|
|
54244
|
+
}
|
|
54245
|
+
async disposeAll() {
|
|
54246
|
+
const allPlugins = [];
|
|
54247
|
+
for (const [, loadedPlugins] of this.plugins) {
|
|
54248
|
+
allPlugins.push(...loadedPlugins);
|
|
54249
|
+
}
|
|
54250
|
+
this.plugins.clear();
|
|
54251
|
+
await this.disposePluginList(allPlugins);
|
|
54252
|
+
await cleanupRemoteTmpFiles();
|
|
54253
|
+
}
|
|
54254
|
+
async disposePluginList(plugins) {
|
|
54255
|
+
for (const { instance: instance2, config: config2 } of plugins) {
|
|
54256
|
+
try {
|
|
54257
|
+
await instance2.dispose?.();
|
|
54258
|
+
} catch (err) {
|
|
54259
|
+
console.error(`[plugin] \u9500\u6BC1\u63D2\u4EF6 "${config2.package}" \u5931\u8D25:`, err instanceof Error ? err.message : err);
|
|
54260
|
+
}
|
|
54261
|
+
}
|
|
54262
|
+
}
|
|
54263
|
+
async disposePluginMap(pluginMap) {
|
|
54264
|
+
const allPlugins = [];
|
|
54265
|
+
for (const [, loadedPlugins] of pluginMap) {
|
|
54266
|
+
allPlugins.push(...loadedPlugins);
|
|
54267
|
+
}
|
|
54268
|
+
await this.disposePluginList(allPlugins);
|
|
54269
|
+
}
|
|
54270
|
+
}
|
|
54271
|
+
|
|
54084
54272
|
// src/proxy.ts
|
|
54085
54273
|
import { appendFile, readFile, unlink } from "fs/promises";
|
|
54086
|
-
import { join as
|
|
54087
|
-
import { tmpdir } from "os";
|
|
54274
|
+
import { join as join9 } from "path";
|
|
54275
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
54276
|
+
|
|
54277
|
+
// src/plugin-engine.ts
|
|
54278
|
+
async function executeRequestPlugins(plugins, ctx, url2, headers, body) {
|
|
54279
|
+
let currentUrl = url2;
|
|
54280
|
+
let currentHeaders = headers;
|
|
54281
|
+
let currentBody = body;
|
|
54282
|
+
for (const plugin of plugins) {
|
|
54283
|
+
if (!plugin.onRequest)
|
|
54284
|
+
continue;
|
|
54285
|
+
try {
|
|
54286
|
+
const result = await plugin.onRequest({
|
|
54287
|
+
ctx,
|
|
54288
|
+
url: currentUrl,
|
|
54289
|
+
headers: currentHeaders,
|
|
54290
|
+
body: currentBody
|
|
54291
|
+
});
|
|
54292
|
+
if (result) {
|
|
54293
|
+
if (result.url !== undefined)
|
|
54294
|
+
currentUrl = result.url;
|
|
54295
|
+
if (result.headers !== undefined)
|
|
54296
|
+
currentHeaders = result.headers;
|
|
54297
|
+
if (result.body !== undefined)
|
|
54298
|
+
currentBody = result.body;
|
|
54299
|
+
}
|
|
54300
|
+
} catch (err) {
|
|
54301
|
+
const error48 = err instanceof Error ? err : new Error(String(err));
|
|
54302
|
+
try {
|
|
54303
|
+
await plugin.onError?.({ ctx, phase: "request", error: error48 });
|
|
54304
|
+
} catch {}
|
|
54305
|
+
}
|
|
54306
|
+
}
|
|
54307
|
+
return { url: currentUrl, headers: currentHeaders, body: currentBody };
|
|
54308
|
+
}
|
|
54309
|
+
async function executeJsonResponsePlugins(plugins, ctx, status, headers, body) {
|
|
54310
|
+
let currentStatus = status;
|
|
54311
|
+
let currentHeaders = headers;
|
|
54312
|
+
let currentBody = body;
|
|
54313
|
+
for (let i = plugins.length - 1;i >= 0; i--) {
|
|
54314
|
+
const plugin = plugins[i];
|
|
54315
|
+
if (!plugin.onResponse)
|
|
54316
|
+
continue;
|
|
54317
|
+
try {
|
|
54318
|
+
const result = await plugin.onResponse({
|
|
54319
|
+
ctx,
|
|
54320
|
+
status: currentStatus,
|
|
54321
|
+
headers: currentHeaders,
|
|
54322
|
+
body: currentBody
|
|
54323
|
+
});
|
|
54324
|
+
if (result) {
|
|
54325
|
+
if (result.status !== undefined)
|
|
54326
|
+
currentStatus = result.status;
|
|
54327
|
+
if (result.headers !== undefined)
|
|
54328
|
+
currentHeaders = result.headers;
|
|
54329
|
+
if (result.body !== undefined)
|
|
54330
|
+
currentBody = result.body;
|
|
54331
|
+
}
|
|
54332
|
+
} catch (err) {
|
|
54333
|
+
const error48 = err instanceof Error ? err : new Error(String(err));
|
|
54334
|
+
try {
|
|
54335
|
+
await plugin.onError?.({ ctx, phase: "response", error: error48 });
|
|
54336
|
+
} catch {}
|
|
54337
|
+
}
|
|
54338
|
+
}
|
|
54339
|
+
return { status: currentStatus, headers: currentHeaders, body: currentBody };
|
|
54340
|
+
}
|
|
54341
|
+
async function createSSEPluginTransform(plugins, ctx, status, headers) {
|
|
54342
|
+
let currentStatus = status;
|
|
54343
|
+
let currentHeaders = headers;
|
|
54344
|
+
const transforms = [];
|
|
54345
|
+
for (let i = plugins.length - 1;i >= 0; i--) {
|
|
54346
|
+
const plugin = plugins[i];
|
|
54347
|
+
if (!plugin.onSSEResponse)
|
|
54348
|
+
continue;
|
|
54349
|
+
try {
|
|
54350
|
+
const result = await plugin.onSSEResponse({
|
|
54351
|
+
ctx,
|
|
54352
|
+
status: currentStatus,
|
|
54353
|
+
headers: currentHeaders
|
|
54354
|
+
});
|
|
54355
|
+
if (result) {
|
|
54356
|
+
if (result.status !== undefined)
|
|
54357
|
+
currentStatus = result.status;
|
|
54358
|
+
if (result.headers !== undefined)
|
|
54359
|
+
currentHeaders = result.headers;
|
|
54360
|
+
if (result.transform)
|
|
54361
|
+
transforms.push(result.transform);
|
|
54362
|
+
}
|
|
54363
|
+
} catch (err) {
|
|
54364
|
+
const error48 = err instanceof Error ? err : new Error(String(err));
|
|
54365
|
+
try {
|
|
54366
|
+
await plugin.onError?.({ ctx, phase: "response", error: error48 });
|
|
54367
|
+
} catch {}
|
|
54368
|
+
}
|
|
54369
|
+
}
|
|
54370
|
+
if (transforms.length === 0) {
|
|
54371
|
+
return { status: currentStatus, headers: currentHeaders, transform: null };
|
|
54372
|
+
}
|
|
54373
|
+
if (transforms.length === 1) {
|
|
54374
|
+
return { status: currentStatus, headers: currentHeaders, transform: transforms[0] };
|
|
54375
|
+
}
|
|
54376
|
+
const entry = new TransformStream;
|
|
54377
|
+
let stream = entry.readable;
|
|
54378
|
+
for (const t of transforms) {
|
|
54379
|
+
stream = stream.pipeThrough(t);
|
|
54380
|
+
}
|
|
54381
|
+
return {
|
|
54382
|
+
status: currentStatus,
|
|
54383
|
+
headers: currentHeaders,
|
|
54384
|
+
transform: { writable: entry.writable, readable: stream }
|
|
54385
|
+
};
|
|
54386
|
+
}
|
|
54387
|
+
|
|
54388
|
+
// src/proxy.ts
|
|
54088
54389
|
var HOP_BY_HOP_HEADERS = new Set([
|
|
54089
54390
|
"connection",
|
|
54090
54391
|
"keep-alive",
|
|
@@ -54163,7 +54464,7 @@ function buildLogEvent(logMeta, targetUrl, proxyUrl, tsEnd, overrides) {
|
|
|
54163
54464
|
};
|
|
54164
54465
|
}
|
|
54165
54466
|
function createTempStreamCapturePath(requestId) {
|
|
54166
|
-
return
|
|
54467
|
+
return join9(tmpdir2(), `local-router-stream-${requestId}-${Date.now()}.sse.raw`);
|
|
54167
54468
|
}
|
|
54168
54469
|
async function appendTempStreamCapture(filePath, chunk) {
|
|
54169
54470
|
await appendFile(filePath, chunk);
|
|
@@ -54185,33 +54486,63 @@ async function flushTempCaptureToLogger(tempPath, requestId, dateStr, logger) {
|
|
|
54185
54486
|
}
|
|
54186
54487
|
}
|
|
54187
54488
|
async function proxyRequest(c2, options) {
|
|
54188
|
-
const { logMeta } = options;
|
|
54489
|
+
const { logMeta, plugins, pluginConfigs } = options;
|
|
54189
54490
|
const logger = getLogger();
|
|
54190
54491
|
const shouldLog = logger?.enabled ?? false;
|
|
54191
|
-
const
|
|
54492
|
+
const hasPlugins = plugins && plugins.length > 0;
|
|
54493
|
+
let targetUrl = options.targetUrl;
|
|
54494
|
+
let headers = buildUpstreamHeaders(c2.req.raw.headers, options.apiKey, options.authType);
|
|
54495
|
+
let bodyStr = options.body;
|
|
54496
|
+
const pluginLogOverrides = {};
|
|
54497
|
+
if (hasPlugins) {
|
|
54498
|
+
const bodyObj = JSON.parse(bodyStr);
|
|
54499
|
+
const ctx = {
|
|
54500
|
+
requestId: logMeta.requestId,
|
|
54501
|
+
provider: logMeta.provider,
|
|
54502
|
+
modelIn: logMeta.modelIn,
|
|
54503
|
+
modelOut: logMeta.modelOut,
|
|
54504
|
+
routeType: logMeta.routeType,
|
|
54505
|
+
isStream: logMeta.isStream
|
|
54506
|
+
};
|
|
54507
|
+
const result = await executeRequestPlugins(plugins, ctx, targetUrl, headers, bodyObj);
|
|
54508
|
+
if (pluginConfigs) {
|
|
54509
|
+
pluginLogOverrides.plugins_request = pluginConfigs;
|
|
54510
|
+
}
|
|
54511
|
+
if (result.url !== targetUrl) {
|
|
54512
|
+
targetUrl = result.url;
|
|
54513
|
+
pluginLogOverrides.request_url_after_plugins = targetUrl;
|
|
54514
|
+
}
|
|
54515
|
+
headers = result.headers;
|
|
54516
|
+
const newBodyStr = JSON.stringify(result.body);
|
|
54517
|
+
if (newBodyStr !== bodyStr) {
|
|
54518
|
+
bodyStr = newBodyStr;
|
|
54519
|
+
pluginLogOverrides.request_body_after_plugins = result.body;
|
|
54520
|
+
}
|
|
54521
|
+
}
|
|
54192
54522
|
const requestBody = shouldLog && logger?.bodyPolicy !== "off" ? JSON.parse(options.body) : undefined;
|
|
54193
54523
|
const proxy = options.proxy?.trim() ? options.proxy.trim() : undefined;
|
|
54194
54524
|
let upstreamRes;
|
|
54195
54525
|
try {
|
|
54196
|
-
upstreamRes = await fetch(
|
|
54526
|
+
upstreamRes = await fetch(targetUrl, {
|
|
54197
54527
|
method: c2.req.method,
|
|
54198
54528
|
headers,
|
|
54199
|
-
body:
|
|
54529
|
+
body: bodyStr,
|
|
54200
54530
|
...proxy ? { proxy } : {},
|
|
54201
54531
|
decompress: true
|
|
54202
54532
|
});
|
|
54203
54533
|
} catch (err) {
|
|
54204
54534
|
if (shouldLog) {
|
|
54205
|
-
logger?.writeEvent(buildLogEvent(logMeta,
|
|
54535
|
+
logger?.writeEvent(buildLogEvent(logMeta, targetUrl, proxy, Date.now(), {
|
|
54206
54536
|
error_type: err instanceof Error ? err.constructor.name : "UnknownError",
|
|
54207
54537
|
error_message: err instanceof Error ? err.message : String(err),
|
|
54208
|
-
...requestBody !== undefined && { request_body: requestBody }
|
|
54538
|
+
...requestBody !== undefined && { request_body: requestBody },
|
|
54539
|
+
...pluginLogOverrides
|
|
54209
54540
|
}));
|
|
54210
54541
|
}
|
|
54211
54542
|
throw err;
|
|
54212
54543
|
}
|
|
54213
54544
|
const responseHeaders = buildResponseHeaders(upstreamRes.headers);
|
|
54214
|
-
if (!shouldLog) {
|
|
54545
|
+
if (!shouldLog && !hasPlugins) {
|
|
54215
54546
|
return new Response(upstreamRes.body, {
|
|
54216
54547
|
status: upstreamRes.status,
|
|
54217
54548
|
headers: responseHeaders
|
|
@@ -54221,6 +54552,33 @@ async function proxyRequest(c2, options) {
|
|
|
54221
54552
|
const providerRequestId = extractProviderRequestId(upstreamRes.headers);
|
|
54222
54553
|
const dateStr = new Date(logMeta.tsStart).toISOString().slice(0, 10);
|
|
54223
54554
|
if (logMeta.isStream && upstreamRes.body) {
|
|
54555
|
+
let sseStatus = upstreamRes.status;
|
|
54556
|
+
let sseHeaders = responseHeaders;
|
|
54557
|
+
let sseTransform = null;
|
|
54558
|
+
if (hasPlugins) {
|
|
54559
|
+
const ctx = {
|
|
54560
|
+
requestId: logMeta.requestId,
|
|
54561
|
+
provider: logMeta.provider,
|
|
54562
|
+
modelIn: logMeta.modelIn,
|
|
54563
|
+
modelOut: logMeta.modelOut,
|
|
54564
|
+
routeType: logMeta.routeType,
|
|
54565
|
+
isStream: logMeta.isStream
|
|
54566
|
+
};
|
|
54567
|
+
const sseResult = await createSSEPluginTransform(plugins, ctx, upstreamRes.status, responseHeaders);
|
|
54568
|
+
sseStatus = sseResult.status;
|
|
54569
|
+
sseHeaders = sseResult.headers;
|
|
54570
|
+
sseTransform = sseResult.transform;
|
|
54571
|
+
if (pluginConfigs) {
|
|
54572
|
+
pluginLogOverrides.plugins_response = pluginConfigs;
|
|
54573
|
+
}
|
|
54574
|
+
}
|
|
54575
|
+
if (!shouldLog) {
|
|
54576
|
+
const outputBody2 = sseTransform ? upstreamRes.body.pipeThrough(sseTransform) : upstreamRes.body;
|
|
54577
|
+
return new Response(outputBody2, {
|
|
54578
|
+
status: sseStatus,
|
|
54579
|
+
headers: sseHeaders
|
|
54580
|
+
});
|
|
54581
|
+
}
|
|
54224
54582
|
const [clientStream, logStream] = upstreamRes.body.tee();
|
|
54225
54583
|
(async () => {
|
|
54226
54584
|
const tempPath = createTempStreamCapturePath(logMeta.requestId);
|
|
@@ -54242,30 +54600,61 @@ async function proxyRequest(c2, options) {
|
|
|
54242
54600
|
});
|
|
54243
54601
|
console.error("[logger] \u6D41\u5F0F\u65E5\u5FD7\u5904\u7406\u5931\u8D25:", err);
|
|
54244
54602
|
} finally {
|
|
54245
|
-
logger?.writeEvent(buildLogEvent(logMeta,
|
|
54246
|
-
upstream_status:
|
|
54603
|
+
logger?.writeEvent(buildLogEvent(logMeta, targetUrl, proxy, Date.now(), {
|
|
54604
|
+
upstream_status: sseStatus,
|
|
54247
54605
|
content_type_res: contentTypeRes,
|
|
54248
|
-
response_headers:
|
|
54606
|
+
response_headers: sseHeaders,
|
|
54249
54607
|
stream_bytes: streamBytes,
|
|
54250
54608
|
provider_request_id: providerRequestId,
|
|
54251
54609
|
...streamFile != null && { stream_file: streamFile },
|
|
54252
|
-
...requestBody !== undefined && { request_body: requestBody }
|
|
54610
|
+
...requestBody !== undefined && { request_body: requestBody },
|
|
54611
|
+
...pluginLogOverrides
|
|
54253
54612
|
}));
|
|
54254
54613
|
}
|
|
54255
54614
|
})();
|
|
54256
|
-
|
|
54257
|
-
|
|
54258
|
-
|
|
54615
|
+
const outputBody = sseTransform ? clientStream.pipeThrough(sseTransform) : clientStream;
|
|
54616
|
+
return new Response(outputBody, {
|
|
54617
|
+
status: sseStatus,
|
|
54618
|
+
headers: sseHeaders
|
|
54619
|
+
});
|
|
54620
|
+
}
|
|
54621
|
+
let responseText = await upstreamRes.text();
|
|
54622
|
+
let responseStatus = upstreamRes.status;
|
|
54623
|
+
let finalResponseHeaders = responseHeaders;
|
|
54624
|
+
if (hasPlugins) {
|
|
54625
|
+
const ctx = {
|
|
54626
|
+
requestId: logMeta.requestId,
|
|
54627
|
+
provider: logMeta.provider,
|
|
54628
|
+
modelIn: logMeta.modelIn,
|
|
54629
|
+
modelOut: logMeta.modelOut,
|
|
54630
|
+
routeType: logMeta.routeType,
|
|
54631
|
+
isStream: logMeta.isStream
|
|
54632
|
+
};
|
|
54633
|
+
const result = await executeJsonResponsePlugins(plugins, ctx, upstreamRes.status, responseHeaders, responseText);
|
|
54634
|
+
if (pluginConfigs) {
|
|
54635
|
+
pluginLogOverrides.plugins_response = pluginConfigs;
|
|
54636
|
+
}
|
|
54637
|
+
if (result.body !== responseText) {
|
|
54638
|
+
pluginLogOverrides.response_body_after_plugins = result.body;
|
|
54639
|
+
}
|
|
54640
|
+
responseStatus = result.status;
|
|
54641
|
+
finalResponseHeaders = result.headers;
|
|
54642
|
+
responseText = result.body;
|
|
54643
|
+
}
|
|
54644
|
+
if (!shouldLog) {
|
|
54645
|
+
return new Response(responseText, {
|
|
54646
|
+
status: responseStatus,
|
|
54647
|
+
headers: finalResponseHeaders
|
|
54259
54648
|
});
|
|
54260
54649
|
}
|
|
54261
|
-
const responseText = await upstreamRes.text();
|
|
54262
54650
|
const responseBytes = Buffer.byteLength(responseText, "utf-8");
|
|
54263
54651
|
const eventOverrides = {
|
|
54264
54652
|
upstream_status: upstreamRes.status,
|
|
54265
54653
|
content_type_res: contentTypeRes,
|
|
54266
|
-
response_headers:
|
|
54654
|
+
response_headers: finalResponseHeaders,
|
|
54267
54655
|
response_bytes: responseBytes,
|
|
54268
|
-
provider_request_id: providerRequestId
|
|
54656
|
+
provider_request_id: providerRequestId,
|
|
54657
|
+
...pluginLogOverrides
|
|
54269
54658
|
};
|
|
54270
54659
|
if (requestBody !== undefined) {
|
|
54271
54660
|
eventOverrides.request_body = requestBody;
|
|
@@ -54273,10 +54662,10 @@ async function proxyRequest(c2, options) {
|
|
|
54273
54662
|
if (logger?.bodyPolicy !== "off") {
|
|
54274
54663
|
eventOverrides.response_body = responseText;
|
|
54275
54664
|
}
|
|
54276
|
-
logger?.writeEvent(buildLogEvent(logMeta,
|
|
54665
|
+
logger?.writeEvent(buildLogEvent(logMeta, targetUrl, proxy, Date.now(), eventOverrides));
|
|
54277
54666
|
return new Response(responseText, {
|
|
54278
|
-
status:
|
|
54279
|
-
headers:
|
|
54667
|
+
status: responseStatus,
|
|
54668
|
+
headers: finalResponseHeaders
|
|
54280
54669
|
});
|
|
54281
54670
|
}
|
|
54282
54671
|
|
|
@@ -54291,7 +54680,7 @@ function resolveRoute(modelMap, incomingModel) {
|
|
|
54291
54680
|
return;
|
|
54292
54681
|
}
|
|
54293
54682
|
function createModelRoutingHandler(options) {
|
|
54294
|
-
const { routeType, store, authType, buildTargetUrl } = options;
|
|
54683
|
+
const { routeType, store, authType, buildTargetUrl, pluginManager } = options;
|
|
54295
54684
|
return async (c2) => {
|
|
54296
54685
|
const config2 = store.get();
|
|
54297
54686
|
const modelMap = config2.routes[routeType];
|
|
@@ -54333,49 +54722,60 @@ function createModelRoutingHandler(options) {
|
|
|
54333
54722
|
requestBytes: Buffer.byteLength(body, "utf-8"),
|
|
54334
54723
|
requestHeaders: collectHeaders(c2.req.raw.headers)
|
|
54335
54724
|
};
|
|
54725
|
+
const plugins = pluginManager?.getPlugins(target.provider) ?? [];
|
|
54726
|
+
const pluginConfigs = pluginManager?.getLoadedPlugins(target.provider) ?? [];
|
|
54336
54727
|
return proxyRequest(c2, {
|
|
54337
54728
|
targetUrl,
|
|
54338
54729
|
apiKey: provider.apiKey,
|
|
54339
54730
|
proxy: provider.proxy,
|
|
54340
54731
|
authType,
|
|
54341
54732
|
body,
|
|
54342
|
-
logMeta
|
|
54733
|
+
logMeta,
|
|
54734
|
+
plugins: plugins.length > 0 ? plugins : undefined,
|
|
54735
|
+
pluginConfigs: pluginConfigs.length > 0 ? pluginConfigs.map((lp) => ({
|
|
54736
|
+
name: lp.definition.name,
|
|
54737
|
+
package: lp.config.package,
|
|
54738
|
+
params: lp.config.params ?? {}
|
|
54739
|
+
})) : undefined
|
|
54343
54740
|
});
|
|
54344
54741
|
};
|
|
54345
54742
|
}
|
|
54346
54743
|
|
|
54347
54744
|
// src/routes/anthropic-messages.ts
|
|
54348
|
-
function createAnthropicMessagesRoutes(routeType, store) {
|
|
54745
|
+
function createAnthropicMessagesRoutes(routeType, store, pluginManager) {
|
|
54349
54746
|
const routes = new Hono2;
|
|
54350
54747
|
routes.post("/v1/messages", createModelRoutingHandler({
|
|
54351
54748
|
routeType,
|
|
54352
54749
|
store,
|
|
54353
54750
|
authType: "x-api-key",
|
|
54354
|
-
buildTargetUrl: (base) => `${base}/v1/messages
|
|
54751
|
+
buildTargetUrl: (base) => `${base}/v1/messages`,
|
|
54752
|
+
pluginManager
|
|
54355
54753
|
}));
|
|
54356
54754
|
return routes;
|
|
54357
54755
|
}
|
|
54358
54756
|
|
|
54359
54757
|
// src/routes/openai-completions.ts
|
|
54360
|
-
function createOpenaiCompletionsRoutes(routeType, store) {
|
|
54758
|
+
function createOpenaiCompletionsRoutes(routeType, store, pluginManager) {
|
|
54361
54759
|
const routes = new Hono2;
|
|
54362
54760
|
routes.post("/v1/chat/completions", createModelRoutingHandler({
|
|
54363
54761
|
routeType,
|
|
54364
54762
|
store,
|
|
54365
54763
|
authType: "bearer",
|
|
54366
|
-
buildTargetUrl: (base) => `${base}/v1/chat/completions
|
|
54764
|
+
buildTargetUrl: (base) => `${base}/v1/chat/completions`,
|
|
54765
|
+
pluginManager
|
|
54367
54766
|
}));
|
|
54368
54767
|
return routes;
|
|
54369
54768
|
}
|
|
54370
54769
|
|
|
54371
54770
|
// src/routes/openai-responses.ts
|
|
54372
|
-
function createOpenaiResponsesRoutes(routeType, store) {
|
|
54771
|
+
function createOpenaiResponsesRoutes(routeType, store, pluginManager) {
|
|
54373
54772
|
const routes = new Hono2;
|
|
54374
54773
|
routes.post("/v1/responses", createModelRoutingHandler({
|
|
54375
54774
|
routeType,
|
|
54376
54775
|
store,
|
|
54377
54776
|
authType: "bearer",
|
|
54378
|
-
buildTargetUrl: (base) => `${base}/v1/responses
|
|
54777
|
+
buildTargetUrl: (base) => `${base}/v1/responses`,
|
|
54778
|
+
pluginManager
|
|
54379
54779
|
}));
|
|
54380
54780
|
return routes;
|
|
54381
54781
|
}
|
|
@@ -54536,7 +54936,7 @@ function createChatProxyModel(providerName, providerConfig, model) {
|
|
|
54536
54936
|
throw new Error(`\u6682\u4E0D\u652F\u6301\u7684 provider \u7C7B\u578B: ${providerConfig.type}`);
|
|
54537
54937
|
}
|
|
54538
54938
|
}
|
|
54539
|
-
function createAdminApiRoutes(store, registerCleanup) {
|
|
54939
|
+
function createAdminApiRoutes(store, pluginManager, registerCleanup) {
|
|
54540
54940
|
const api2 = new Hono2;
|
|
54541
54941
|
const cryptoSessions = new Map;
|
|
54542
54942
|
const CRYPTO_SESSION_TTL_MS = 2 * 60 * 1000;
|
|
@@ -54647,18 +55047,22 @@ function createAdminApiRoutes(store, registerCleanup) {
|
|
|
54647
55047
|
session.dispose();
|
|
54648
55048
|
}
|
|
54649
55049
|
});
|
|
54650
|
-
api2.post("/config/apply", (_c) => {
|
|
55050
|
+
api2.post("/config/apply", async (_c) => {
|
|
54651
55051
|
try {
|
|
54652
55052
|
const config2 = store.reload();
|
|
54653
55053
|
if (config2.log) {
|
|
54654
55054
|
const logBaseDir = resolveLogBaseDir(config2.log);
|
|
54655
55055
|
initLogger(logBaseDir, config2.log);
|
|
54656
55056
|
}
|
|
55057
|
+
const pluginResult = await pluginManager.reloadAll(config2.providers);
|
|
54657
55058
|
return _c.json({
|
|
54658
55059
|
ok: true,
|
|
54659
55060
|
summary: {
|
|
54660
55061
|
providers: Object.keys(config2.providers).length,
|
|
54661
55062
|
routes: Object.keys(config2.routes).length
|
|
55063
|
+
},
|
|
55064
|
+
...pluginResult.failures.length > 0 && {
|
|
55065
|
+
pluginWarnings: pluginResult.failures
|
|
54662
55066
|
}
|
|
54663
55067
|
});
|
|
54664
55068
|
} catch (err) {
|
|
@@ -55083,7 +55487,7 @@ async function proxyAdminToDevServer(c2, origin) {
|
|
|
55083
55487
|
headers: buildProxyResponseHeaders(upstreamRes.headers)
|
|
55084
55488
|
});
|
|
55085
55489
|
}
|
|
55086
|
-
function createApp(store, options) {
|
|
55490
|
+
async function createApp(store, options) {
|
|
55087
55491
|
const config2 = store.get();
|
|
55088
55492
|
console.log(`\u5DF2\u52A0\u8F7D\u914D\u7F6E: ${store.getPath()}`);
|
|
55089
55493
|
if (config2.log) {
|
|
@@ -55094,15 +55498,24 @@ function createApp(store, options) {
|
|
|
55094
55498
|
}
|
|
55095
55499
|
const stopLogStorageTask = startLogStorageBackgroundTask(config2.log);
|
|
55096
55500
|
options?.registerCleanup?.(stopLogStorageTask);
|
|
55501
|
+
const configDir = dirname2(resolve6(store.getPath()));
|
|
55502
|
+
const pluginManager = new PluginManager(configDir);
|
|
55503
|
+
const reloadResult = await pluginManager.reloadAll(config2.providers);
|
|
55504
|
+
if (!reloadResult.ok) {
|
|
55505
|
+
console.warn(`[plugin] \u63D2\u4EF6\u521D\u59CB\u5316\u5B8C\u6210\uFF0C\u4F46\u6709 ${reloadResult.failures.length} \u4E2A\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25`);
|
|
55506
|
+
}
|
|
55507
|
+
options?.registerCleanup?.(() => {
|
|
55508
|
+
pluginManager.disposeAll().catch(() => {});
|
|
55509
|
+
});
|
|
55097
55510
|
printIntegrationGuide(config2);
|
|
55098
55511
|
const app = new Hono2;
|
|
55099
55512
|
app.get("/", (c2) => c2.text("local-router is running"));
|
|
55100
55513
|
for (const [routeType, entry] of Object.entries(ROUTE_REGISTRY)) {
|
|
55101
|
-
const subApp = entry.create(routeType, store);
|
|
55514
|
+
const subApp = entry.create(routeType, store, pluginManager);
|
|
55102
55515
|
app.route(entry.mountPrefix, subApp);
|
|
55103
55516
|
console.log(`\u5DF2\u6CE8\u518C\u8DEF\u7531: ${routeType} -> ${entry.mountPrefix}`);
|
|
55104
55517
|
}
|
|
55105
|
-
app.route("/api", createAdminApiRoutes(store, options?.registerCleanup));
|
|
55518
|
+
app.route("/api", createAdminApiRoutes(store, pluginManager, options?.registerCleanup));
|
|
55106
55519
|
console.log("\u5DF2\u6CE8\u518C\u7BA1\u7406 API: /api");
|
|
55107
55520
|
app.get("/api/docs", middleware({ url: "/api/openapi.json" }));
|
|
55108
55521
|
app.get("/api/openapi.json", (c2) => c2.json(openAPISpec));
|
|
@@ -55131,10 +55544,10 @@ function createApp(store, options) {
|
|
|
55131
55544
|
}
|
|
55132
55545
|
return app;
|
|
55133
55546
|
}
|
|
55134
|
-
function createAppRuntimeFromConfigPath(configPath) {
|
|
55547
|
+
async function createAppRuntimeFromConfigPath(configPath) {
|
|
55135
55548
|
const store = new ConfigStore(configPath);
|
|
55136
55549
|
const cleanups = [];
|
|
55137
|
-
const app = createApp(store, {
|
|
55550
|
+
const app = await createApp(store, {
|
|
55138
55551
|
registerCleanup: (cleanup) => {
|
|
55139
55552
|
cleanups.push(cleanup);
|
|
55140
55553
|
}
|
|
@@ -55152,7 +55565,7 @@ function createAppRuntimeFromConfigPath(configPath) {
|
|
|
55152
55565
|
}
|
|
55153
55566
|
|
|
55154
55567
|
// src/server.ts
|
|
55155
|
-
var DEFAULT_IDLE_TIMEOUT_SECONDS =
|
|
55568
|
+
var DEFAULT_IDLE_TIMEOUT_SECONDS = 0;
|
|
55156
55569
|
function resolveIdleTimeoutSeconds(explicit) {
|
|
55157
55570
|
if (typeof explicit === "number" && Number.isFinite(explicit) && explicit >= 0) {
|
|
55158
55571
|
return explicit;
|
|
@@ -55167,8 +55580,8 @@ function resolveIdleTimeoutSeconds(explicit) {
|
|
|
55167
55580
|
}
|
|
55168
55581
|
return DEFAULT_IDLE_TIMEOUT_SECONDS;
|
|
55169
55582
|
}
|
|
55170
|
-
function startServer(options) {
|
|
55171
|
-
const runtime = createAppRuntimeFromConfigPath(options.configPath);
|
|
55583
|
+
async function startServer(options) {
|
|
55584
|
+
const runtime = await createAppRuntimeFromConfigPath(options.configPath);
|
|
55172
55585
|
const idleTimeout = resolveIdleTimeoutSeconds(options.idleTimeoutSeconds);
|
|
55173
55586
|
const server = Bun.serve({
|
|
55174
55587
|
fetch: runtime.app.fetch,
|
|
@@ -55193,21 +55606,21 @@ function startServer(options) {
|
|
|
55193
55606
|
// src/cli/runtime.ts
|
|
55194
55607
|
import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync4 } from "fs";
|
|
55195
55608
|
import { homedir as homedir2 } from "os";
|
|
55196
|
-
import { join as
|
|
55609
|
+
import { join as join10, resolve as resolve7 } from "path";
|
|
55197
55610
|
function getRuntimeDirs() {
|
|
55198
|
-
const root2 =
|
|
55611
|
+
const root2 = join10(homedir2(), ".local-router");
|
|
55199
55612
|
return {
|
|
55200
55613
|
root: root2,
|
|
55201
|
-
run:
|
|
55202
|
-
logs:
|
|
55614
|
+
run: join10(root2, "run"),
|
|
55615
|
+
logs: join10(root2, "logs")
|
|
55203
55616
|
};
|
|
55204
55617
|
}
|
|
55205
55618
|
function getRuntimeFiles() {
|
|
55206
55619
|
const dirs = getRuntimeDirs();
|
|
55207
55620
|
return {
|
|
55208
|
-
pid:
|
|
55209
|
-
state:
|
|
55210
|
-
daemonLog:
|
|
55621
|
+
pid: join10(dirs.run, "local-router.pid"),
|
|
55622
|
+
state: join10(dirs.run, "status.json"),
|
|
55623
|
+
daemonLog: join10(dirs.logs, "daemon.log")
|
|
55211
55624
|
};
|
|
55212
55625
|
}
|
|
55213
55626
|
function ensureRuntimeDirs() {
|
|
@@ -55240,7 +55653,7 @@ function clearRuntimeFiles() {
|
|
|
55240
55653
|
rmSync(files.state, { force: true });
|
|
55241
55654
|
}
|
|
55242
55655
|
function resolveConfigArgPath(pathValue) {
|
|
55243
|
-
return
|
|
55656
|
+
return resolve7(pathValue);
|
|
55244
55657
|
}
|
|
55245
55658
|
|
|
55246
55659
|
// src/cli/process.ts
|
|
@@ -55319,7 +55732,7 @@ async function runServerProcess(opts) {
|
|
|
55319
55732
|
const idleTimeoutSeconds = opts.idleTimeoutSeconds ?? Number.parseInt(process.env.LOCAL_ROUTER_IDLE_TIMEOUT ?? "", 10);
|
|
55320
55733
|
let running;
|
|
55321
55734
|
try {
|
|
55322
|
-
running = startServer({
|
|
55735
|
+
running = await startServer({
|
|
55323
55736
|
configPath: ensured.path,
|
|
55324
55737
|
host,
|
|
55325
55738
|
port,
|
|
@@ -55471,7 +55884,7 @@ function readLogDelta(filePath, offset) {
|
|
|
55471
55884
|
// src/cli/config-command.ts
|
|
55472
55885
|
import { createInterface as createInterface4 } from "readline/promises";
|
|
55473
55886
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
55474
|
-
import { dirname as
|
|
55887
|
+
import { dirname as dirname3, join as join11 } from "path";
|
|
55475
55888
|
import { parseArgs as parseArgs2 } from "util";
|
|
55476
55889
|
function readConfig(configArg) {
|
|
55477
55890
|
const path = resolveConfigPath(configArg);
|
|
@@ -55479,9 +55892,9 @@ function readConfig(configArg) {
|
|
|
55479
55892
|
}
|
|
55480
55893
|
function saveConfig(path, config2) {
|
|
55481
55894
|
validateConfigOrThrow(config2);
|
|
55482
|
-
const backupDir =
|
|
55895
|
+
const backupDir = join11(dirname3(path), ".backups");
|
|
55483
55896
|
mkdirSync4(backupDir, { recursive: true });
|
|
55484
|
-
const backupPath =
|
|
55897
|
+
const backupPath = join11(backupDir, `config-${Date.now()}.json5`);
|
|
55485
55898
|
writeFileSync5(backupPath, readFileSync7(path, "utf-8"), "utf-8");
|
|
55486
55899
|
const content = dist_default.stringify(config2, { space: 2, quote: '"' });
|
|
55487
55900
|
writeFileSync5(path, content, "utf-8");
|