@lakphy/local-router 0.3.3 → 0.4.0-beta.1
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 +407 -46
- package/dist/entry.js +400 -39
- 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/entry.js
CHANGED
|
@@ -4934,7 +4934,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
4934
4934
|
const schOrFunc = root2.refs[ref];
|
|
4935
4935
|
if (schOrFunc)
|
|
4936
4936
|
return schOrFunc;
|
|
4937
|
-
let _sch =
|
|
4937
|
+
let _sch = resolve6.call(this, root2, ref);
|
|
4938
4938
|
if (_sch === undefined) {
|
|
4939
4939
|
const schema = (_a21 = root2.localRefs) === null || _a21 === undefined ? undefined : _a21[ref];
|
|
4940
4940
|
const { schemaId } = this.opts;
|
|
@@ -4961,7 +4961,7 @@ var require_compile = __commonJS((exports) => {
|
|
|
4961
4961
|
function sameSchemaEnv(s1, s2) {
|
|
4962
4962
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
4963
4963
|
}
|
|
4964
|
-
function
|
|
4964
|
+
function resolve6(root2, ref) {
|
|
4965
4965
|
let sch;
|
|
4966
4966
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
4967
4967
|
ref = sch;
|
|
@@ -5491,7 +5491,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
5491
5491
|
}
|
|
5492
5492
|
return uri;
|
|
5493
5493
|
}
|
|
5494
|
-
function
|
|
5494
|
+
function resolve6(baseURI, relativeURI, options) {
|
|
5495
5495
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
5496
5496
|
const resolved = resolveComponent(parse7(baseURI, schemelessOptions), parse7(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
5497
5497
|
schemelessOptions.skipEscape = true;
|
|
@@ -5719,7 +5719,7 @@ var require_fast_uri = __commonJS((exports, module) => {
|
|
|
5719
5719
|
var fastUri = {
|
|
5720
5720
|
SCHEMES,
|
|
5721
5721
|
normalize,
|
|
5722
|
-
resolve:
|
|
5722
|
+
resolve: resolve6,
|
|
5723
5723
|
resolveComponent,
|
|
5724
5724
|
equal,
|
|
5725
5725
|
serialize,
|
|
@@ -9285,6 +9285,7 @@ var require_dist2 = __commonJS((exports, module) => {
|
|
|
9285
9285
|
|
|
9286
9286
|
// src/index.ts
|
|
9287
9287
|
import { readFileSync as readFileSync4 } from "fs";
|
|
9288
|
+
import { dirname as dirname3, resolve as resolve6 } from "path";
|
|
9288
9289
|
|
|
9289
9290
|
// node_modules/.bun/@ai-sdk+provider@3.0.8/node_modules/@ai-sdk/provider/dist/index.mjs
|
|
9290
9291
|
var marker = "vercel.ai.error";
|
|
@@ -52102,6 +52103,14 @@ async function buildLogEventDetail(id, parsed, location, context2) {
|
|
|
52102
52103
|
const responseBodyAvailable = event.response_body !== undefined;
|
|
52103
52104
|
const streamCaptured = Boolean(event.stream_file);
|
|
52104
52105
|
const { content: streamContent, warning: streamWarning } = readStreamContent(resolveLogBaseDir(context2.logConfig), event.stream_file);
|
|
52106
|
+
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;
|
|
52107
|
+
const pluginsSection = hasPluginData ? {
|
|
52108
|
+
request: event.plugins_request,
|
|
52109
|
+
response: event.plugins_response,
|
|
52110
|
+
requestBodyAfterPlugins: event.request_body_after_plugins,
|
|
52111
|
+
requestUrlAfterPlugins: event.request_url_after_plugins,
|
|
52112
|
+
responseBodyAfterPlugins: event.response_body_after_plugins
|
|
52113
|
+
} : undefined;
|
|
52105
52114
|
return {
|
|
52106
52115
|
id,
|
|
52107
52116
|
summary: {
|
|
@@ -52153,6 +52162,7 @@ async function buildLogEventDetail(id, parsed, location, context2) {
|
|
|
52153
52162
|
...streamWarning ? [streamWarning] : []
|
|
52154
52163
|
]
|
|
52155
52164
|
},
|
|
52165
|
+
...pluginsSection && { plugins: pluginsSection },
|
|
52156
52166
|
rawEvent: event,
|
|
52157
52167
|
location
|
|
52158
52168
|
};
|
|
@@ -54065,10 +54075,249 @@ var openAPISpec = {
|
|
|
54065
54075
|
}
|
|
54066
54076
|
};
|
|
54067
54077
|
|
|
54078
|
+
// src/plugin-loader.ts
|
|
54079
|
+
import { resolve as resolve5 } from "path";
|
|
54080
|
+
function isLocalPath(pkg) {
|
|
54081
|
+
return pkg.startsWith("./") || pkg.startsWith("../") || pkg.startsWith("/") || /^[A-Za-z]:[\\/]/.test(pkg);
|
|
54082
|
+
}
|
|
54083
|
+
async function importPlugin(pkg, configDir) {
|
|
54084
|
+
let modulePath;
|
|
54085
|
+
if (isLocalPath(pkg)) {
|
|
54086
|
+
const absolutePath = resolve5(configDir, pkg);
|
|
54087
|
+
modulePath = `${absolutePath}?t=${Date.now()}`;
|
|
54088
|
+
} else {
|
|
54089
|
+
modulePath = pkg;
|
|
54090
|
+
}
|
|
54091
|
+
const mod = await import(modulePath);
|
|
54092
|
+
const definition = mod.default ?? mod;
|
|
54093
|
+
if (!definition || typeof definition.name !== "string" || typeof definition.create !== "function") {
|
|
54094
|
+
throw new Error(`\u63D2\u4EF6 "${pkg}" \u5BFC\u51FA\u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u9700\u5BFC\u51FA\u5305\u542B name \u548C create \u7684 PluginDefinition`);
|
|
54095
|
+
}
|
|
54096
|
+
return definition;
|
|
54097
|
+
}
|
|
54098
|
+
|
|
54099
|
+
class PluginManager {
|
|
54100
|
+
plugins = new Map;
|
|
54101
|
+
configDir;
|
|
54102
|
+
constructor(configDir) {
|
|
54103
|
+
this.configDir = configDir;
|
|
54104
|
+
}
|
|
54105
|
+
async loadPluginsForProvider(providerName, pluginConfigs) {
|
|
54106
|
+
const loaded = [];
|
|
54107
|
+
const failures = [];
|
|
54108
|
+
for (const config2 of pluginConfigs) {
|
|
54109
|
+
try {
|
|
54110
|
+
const definition = await importPlugin(config2.package, this.configDir);
|
|
54111
|
+
const instance2 = await definition.create(config2.params ?? {});
|
|
54112
|
+
loaded.push({ config: config2, definition, instance: instance2 });
|
|
54113
|
+
} catch (err) {
|
|
54114
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
54115
|
+
console.error(`[plugin] \u52A0\u8F7D\u63D2\u4EF6 "${config2.package}" \u5931\u8D25 (provider: ${providerName}):`, errorMsg);
|
|
54116
|
+
failures.push({ provider: providerName, package: config2.package, error: errorMsg });
|
|
54117
|
+
}
|
|
54118
|
+
}
|
|
54119
|
+
return { loaded, failures };
|
|
54120
|
+
}
|
|
54121
|
+
async reloadAll(providers) {
|
|
54122
|
+
const newPlugins = new Map;
|
|
54123
|
+
const allFailures = [];
|
|
54124
|
+
const oldPluginsToDispose = [];
|
|
54125
|
+
for (const [providerName, providerConfig] of Object.entries(providers)) {
|
|
54126
|
+
if (providerConfig.plugins && providerConfig.plugins.length > 0) {
|
|
54127
|
+
const { loaded, failures } = await this.loadPluginsForProvider(providerName, providerConfig.plugins);
|
|
54128
|
+
allFailures.push(...failures);
|
|
54129
|
+
if (failures.length > 0) {
|
|
54130
|
+
console.warn(`[plugin] provider "${providerName}" \u6709\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25\uFF0C\u4FDD\u7559\u65E7\u63D2\u4EF6\u94FE`);
|
|
54131
|
+
const oldLoaded = this.plugins.get(providerName);
|
|
54132
|
+
if (oldLoaded) {
|
|
54133
|
+
newPlugins.set(providerName, oldLoaded);
|
|
54134
|
+
}
|
|
54135
|
+
for (const { instance: instance2, config: config2 } of loaded) {
|
|
54136
|
+
try {
|
|
54137
|
+
await instance2.dispose?.();
|
|
54138
|
+
} catch (err) {
|
|
54139
|
+
console.error(`[plugin] \u56DE\u6EDA\u9500\u6BC1\u63D2\u4EF6 "${config2.package}" \u5931\u8D25:`, err instanceof Error ? err.message : err);
|
|
54140
|
+
}
|
|
54141
|
+
}
|
|
54142
|
+
} else {
|
|
54143
|
+
newPlugins.set(providerName, loaded);
|
|
54144
|
+
const oldLoaded = this.plugins.get(providerName);
|
|
54145
|
+
if (oldLoaded) {
|
|
54146
|
+
oldPluginsToDispose.push(...oldLoaded);
|
|
54147
|
+
}
|
|
54148
|
+
}
|
|
54149
|
+
}
|
|
54150
|
+
}
|
|
54151
|
+
for (const [providerName, oldLoaded] of this.plugins) {
|
|
54152
|
+
if (!newPlugins.has(providerName)) {
|
|
54153
|
+
oldPluginsToDispose.push(...oldLoaded);
|
|
54154
|
+
}
|
|
54155
|
+
}
|
|
54156
|
+
this.plugins = newPlugins;
|
|
54157
|
+
if (oldPluginsToDispose.length > 0) {
|
|
54158
|
+
setTimeout(() => {
|
|
54159
|
+
this.disposePluginList(oldPluginsToDispose).catch((err) => {
|
|
54160
|
+
console.error("[plugin] \u65E7\u63D2\u4EF6\u9500\u6BC1\u5931\u8D25:", err);
|
|
54161
|
+
});
|
|
54162
|
+
}, 5000);
|
|
54163
|
+
}
|
|
54164
|
+
if (allFailures.length > 0) {
|
|
54165
|
+
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(", "));
|
|
54166
|
+
}
|
|
54167
|
+
return { ok: allFailures.length === 0, failures: allFailures };
|
|
54168
|
+
}
|
|
54169
|
+
getPlugins(providerName) {
|
|
54170
|
+
const loaded = this.plugins.get(providerName);
|
|
54171
|
+
if (!loaded)
|
|
54172
|
+
return [];
|
|
54173
|
+
return loaded.map((l) => l.instance);
|
|
54174
|
+
}
|
|
54175
|
+
getLoadedPlugins(providerName) {
|
|
54176
|
+
return this.plugins.get(providerName) ?? [];
|
|
54177
|
+
}
|
|
54178
|
+
async disposeAll() {
|
|
54179
|
+
const allPlugins = [];
|
|
54180
|
+
for (const [, loadedPlugins] of this.plugins) {
|
|
54181
|
+
allPlugins.push(...loadedPlugins);
|
|
54182
|
+
}
|
|
54183
|
+
this.plugins.clear();
|
|
54184
|
+
await this.disposePluginList(allPlugins);
|
|
54185
|
+
}
|
|
54186
|
+
async disposePluginList(plugins) {
|
|
54187
|
+
for (const { instance: instance2, config: config2 } of plugins) {
|
|
54188
|
+
try {
|
|
54189
|
+
await instance2.dispose?.();
|
|
54190
|
+
} catch (err) {
|
|
54191
|
+
console.error(`[plugin] \u9500\u6BC1\u63D2\u4EF6 "${config2.package}" \u5931\u8D25:`, err instanceof Error ? err.message : err);
|
|
54192
|
+
}
|
|
54193
|
+
}
|
|
54194
|
+
}
|
|
54195
|
+
async disposePluginMap(pluginMap) {
|
|
54196
|
+
const allPlugins = [];
|
|
54197
|
+
for (const [, loadedPlugins] of pluginMap) {
|
|
54198
|
+
allPlugins.push(...loadedPlugins);
|
|
54199
|
+
}
|
|
54200
|
+
await this.disposePluginList(allPlugins);
|
|
54201
|
+
}
|
|
54202
|
+
}
|
|
54203
|
+
|
|
54068
54204
|
// src/proxy.ts
|
|
54069
54205
|
import { appendFile, readFile, unlink } from "fs/promises";
|
|
54070
54206
|
import { join as join8 } from "path";
|
|
54071
54207
|
import { tmpdir } from "os";
|
|
54208
|
+
|
|
54209
|
+
// src/plugin-engine.ts
|
|
54210
|
+
async function executeRequestPlugins(plugins, ctx, url2, headers, body) {
|
|
54211
|
+
let currentUrl = url2;
|
|
54212
|
+
let currentHeaders = headers;
|
|
54213
|
+
let currentBody = body;
|
|
54214
|
+
for (const plugin of plugins) {
|
|
54215
|
+
if (!plugin.onRequest)
|
|
54216
|
+
continue;
|
|
54217
|
+
try {
|
|
54218
|
+
const result = await plugin.onRequest({
|
|
54219
|
+
ctx,
|
|
54220
|
+
url: currentUrl,
|
|
54221
|
+
headers: currentHeaders,
|
|
54222
|
+
body: currentBody
|
|
54223
|
+
});
|
|
54224
|
+
if (result) {
|
|
54225
|
+
if (result.url !== undefined)
|
|
54226
|
+
currentUrl = result.url;
|
|
54227
|
+
if (result.headers !== undefined)
|
|
54228
|
+
currentHeaders = result.headers;
|
|
54229
|
+
if (result.body !== undefined)
|
|
54230
|
+
currentBody = result.body;
|
|
54231
|
+
}
|
|
54232
|
+
} catch (err) {
|
|
54233
|
+
const error48 = err instanceof Error ? err : new Error(String(err));
|
|
54234
|
+
try {
|
|
54235
|
+
await plugin.onError?.({ ctx, phase: "request", error: error48 });
|
|
54236
|
+
} catch {}
|
|
54237
|
+
}
|
|
54238
|
+
}
|
|
54239
|
+
return { url: currentUrl, headers: currentHeaders, body: currentBody };
|
|
54240
|
+
}
|
|
54241
|
+
async function executeJsonResponsePlugins(plugins, ctx, status, headers, body) {
|
|
54242
|
+
let currentStatus = status;
|
|
54243
|
+
let currentHeaders = headers;
|
|
54244
|
+
let currentBody = body;
|
|
54245
|
+
for (let i = plugins.length - 1;i >= 0; i--) {
|
|
54246
|
+
const plugin = plugins[i];
|
|
54247
|
+
if (!plugin.onResponse)
|
|
54248
|
+
continue;
|
|
54249
|
+
try {
|
|
54250
|
+
const result = await plugin.onResponse({
|
|
54251
|
+
ctx,
|
|
54252
|
+
status: currentStatus,
|
|
54253
|
+
headers: currentHeaders,
|
|
54254
|
+
body: currentBody
|
|
54255
|
+
});
|
|
54256
|
+
if (result) {
|
|
54257
|
+
if (result.status !== undefined)
|
|
54258
|
+
currentStatus = result.status;
|
|
54259
|
+
if (result.headers !== undefined)
|
|
54260
|
+
currentHeaders = result.headers;
|
|
54261
|
+
if (result.body !== undefined)
|
|
54262
|
+
currentBody = result.body;
|
|
54263
|
+
}
|
|
54264
|
+
} catch (err) {
|
|
54265
|
+
const error48 = err instanceof Error ? err : new Error(String(err));
|
|
54266
|
+
try {
|
|
54267
|
+
await plugin.onError?.({ ctx, phase: "response", error: error48 });
|
|
54268
|
+
} catch {}
|
|
54269
|
+
}
|
|
54270
|
+
}
|
|
54271
|
+
return { status: currentStatus, headers: currentHeaders, body: currentBody };
|
|
54272
|
+
}
|
|
54273
|
+
async function createSSEPluginTransform(plugins, ctx, status, headers) {
|
|
54274
|
+
let currentStatus = status;
|
|
54275
|
+
let currentHeaders = headers;
|
|
54276
|
+
const transforms = [];
|
|
54277
|
+
for (let i = plugins.length - 1;i >= 0; i--) {
|
|
54278
|
+
const plugin = plugins[i];
|
|
54279
|
+
if (!plugin.onSSEResponse)
|
|
54280
|
+
continue;
|
|
54281
|
+
try {
|
|
54282
|
+
const result = await plugin.onSSEResponse({
|
|
54283
|
+
ctx,
|
|
54284
|
+
status: currentStatus,
|
|
54285
|
+
headers: currentHeaders
|
|
54286
|
+
});
|
|
54287
|
+
if (result) {
|
|
54288
|
+
if (result.status !== undefined)
|
|
54289
|
+
currentStatus = result.status;
|
|
54290
|
+
if (result.headers !== undefined)
|
|
54291
|
+
currentHeaders = result.headers;
|
|
54292
|
+
if (result.transform)
|
|
54293
|
+
transforms.push(result.transform);
|
|
54294
|
+
}
|
|
54295
|
+
} catch (err) {
|
|
54296
|
+
const error48 = err instanceof Error ? err : new Error(String(err));
|
|
54297
|
+
try {
|
|
54298
|
+
await plugin.onError?.({ ctx, phase: "response", error: error48 });
|
|
54299
|
+
} catch {}
|
|
54300
|
+
}
|
|
54301
|
+
}
|
|
54302
|
+
if (transforms.length === 0) {
|
|
54303
|
+
return { status: currentStatus, headers: currentHeaders, transform: null };
|
|
54304
|
+
}
|
|
54305
|
+
if (transforms.length === 1) {
|
|
54306
|
+
return { status: currentStatus, headers: currentHeaders, transform: transforms[0] };
|
|
54307
|
+
}
|
|
54308
|
+
const entry = new TransformStream;
|
|
54309
|
+
let stream = entry.readable;
|
|
54310
|
+
for (const t of transforms) {
|
|
54311
|
+
stream = stream.pipeThrough(t);
|
|
54312
|
+
}
|
|
54313
|
+
return {
|
|
54314
|
+
status: currentStatus,
|
|
54315
|
+
headers: currentHeaders,
|
|
54316
|
+
transform: { writable: entry.writable, readable: stream }
|
|
54317
|
+
};
|
|
54318
|
+
}
|
|
54319
|
+
|
|
54320
|
+
// src/proxy.ts
|
|
54072
54321
|
var HOP_BY_HOP_HEADERS = new Set([
|
|
54073
54322
|
"connection",
|
|
54074
54323
|
"keep-alive",
|
|
@@ -54169,33 +54418,63 @@ async function flushTempCaptureToLogger(tempPath, requestId, dateStr, logger) {
|
|
|
54169
54418
|
}
|
|
54170
54419
|
}
|
|
54171
54420
|
async function proxyRequest(c2, options) {
|
|
54172
|
-
const { logMeta } = options;
|
|
54421
|
+
const { logMeta, plugins, pluginConfigs } = options;
|
|
54173
54422
|
const logger = getLogger();
|
|
54174
54423
|
const shouldLog = logger?.enabled ?? false;
|
|
54175
|
-
const
|
|
54424
|
+
const hasPlugins = plugins && plugins.length > 0;
|
|
54425
|
+
let targetUrl = options.targetUrl;
|
|
54426
|
+
let headers = buildUpstreamHeaders(c2.req.raw.headers, options.apiKey, options.authType);
|
|
54427
|
+
let bodyStr = options.body;
|
|
54428
|
+
const pluginLogOverrides = {};
|
|
54429
|
+
if (hasPlugins) {
|
|
54430
|
+
const bodyObj = JSON.parse(bodyStr);
|
|
54431
|
+
const ctx = {
|
|
54432
|
+
requestId: logMeta.requestId,
|
|
54433
|
+
provider: logMeta.provider,
|
|
54434
|
+
modelIn: logMeta.modelIn,
|
|
54435
|
+
modelOut: logMeta.modelOut,
|
|
54436
|
+
routeType: logMeta.routeType,
|
|
54437
|
+
isStream: logMeta.isStream
|
|
54438
|
+
};
|
|
54439
|
+
const result = await executeRequestPlugins(plugins, ctx, targetUrl, headers, bodyObj);
|
|
54440
|
+
if (pluginConfigs) {
|
|
54441
|
+
pluginLogOverrides.plugins_request = pluginConfigs;
|
|
54442
|
+
}
|
|
54443
|
+
if (result.url !== targetUrl) {
|
|
54444
|
+
targetUrl = result.url;
|
|
54445
|
+
pluginLogOverrides.request_url_after_plugins = targetUrl;
|
|
54446
|
+
}
|
|
54447
|
+
headers = result.headers;
|
|
54448
|
+
const newBodyStr = JSON.stringify(result.body);
|
|
54449
|
+
if (newBodyStr !== bodyStr) {
|
|
54450
|
+
bodyStr = newBodyStr;
|
|
54451
|
+
pluginLogOverrides.request_body_after_plugins = result.body;
|
|
54452
|
+
}
|
|
54453
|
+
}
|
|
54176
54454
|
const requestBody = shouldLog && logger?.bodyPolicy !== "off" ? JSON.parse(options.body) : undefined;
|
|
54177
54455
|
const proxy = options.proxy?.trim() ? options.proxy.trim() : undefined;
|
|
54178
54456
|
let upstreamRes;
|
|
54179
54457
|
try {
|
|
54180
|
-
upstreamRes = await fetch(
|
|
54458
|
+
upstreamRes = await fetch(targetUrl, {
|
|
54181
54459
|
method: c2.req.method,
|
|
54182
54460
|
headers,
|
|
54183
|
-
body:
|
|
54461
|
+
body: bodyStr,
|
|
54184
54462
|
...proxy ? { proxy } : {},
|
|
54185
54463
|
decompress: true
|
|
54186
54464
|
});
|
|
54187
54465
|
} catch (err) {
|
|
54188
54466
|
if (shouldLog) {
|
|
54189
|
-
logger?.writeEvent(buildLogEvent(logMeta,
|
|
54467
|
+
logger?.writeEvent(buildLogEvent(logMeta, targetUrl, proxy, Date.now(), {
|
|
54190
54468
|
error_type: err instanceof Error ? err.constructor.name : "UnknownError",
|
|
54191
54469
|
error_message: err instanceof Error ? err.message : String(err),
|
|
54192
|
-
...requestBody !== undefined && { request_body: requestBody }
|
|
54470
|
+
...requestBody !== undefined && { request_body: requestBody },
|
|
54471
|
+
...pluginLogOverrides
|
|
54193
54472
|
}));
|
|
54194
54473
|
}
|
|
54195
54474
|
throw err;
|
|
54196
54475
|
}
|
|
54197
54476
|
const responseHeaders = buildResponseHeaders(upstreamRes.headers);
|
|
54198
|
-
if (!shouldLog) {
|
|
54477
|
+
if (!shouldLog && !hasPlugins) {
|
|
54199
54478
|
return new Response(upstreamRes.body, {
|
|
54200
54479
|
status: upstreamRes.status,
|
|
54201
54480
|
headers: responseHeaders
|
|
@@ -54205,6 +54484,33 @@ async function proxyRequest(c2, options) {
|
|
|
54205
54484
|
const providerRequestId = extractProviderRequestId(upstreamRes.headers);
|
|
54206
54485
|
const dateStr = new Date(logMeta.tsStart).toISOString().slice(0, 10);
|
|
54207
54486
|
if (logMeta.isStream && upstreamRes.body) {
|
|
54487
|
+
let sseStatus = upstreamRes.status;
|
|
54488
|
+
let sseHeaders = responseHeaders;
|
|
54489
|
+
let sseTransform = null;
|
|
54490
|
+
if (hasPlugins) {
|
|
54491
|
+
const ctx = {
|
|
54492
|
+
requestId: logMeta.requestId,
|
|
54493
|
+
provider: logMeta.provider,
|
|
54494
|
+
modelIn: logMeta.modelIn,
|
|
54495
|
+
modelOut: logMeta.modelOut,
|
|
54496
|
+
routeType: logMeta.routeType,
|
|
54497
|
+
isStream: logMeta.isStream
|
|
54498
|
+
};
|
|
54499
|
+
const sseResult = await createSSEPluginTransform(plugins, ctx, upstreamRes.status, responseHeaders);
|
|
54500
|
+
sseStatus = sseResult.status;
|
|
54501
|
+
sseHeaders = sseResult.headers;
|
|
54502
|
+
sseTransform = sseResult.transform;
|
|
54503
|
+
if (pluginConfigs) {
|
|
54504
|
+
pluginLogOverrides.plugins_response = pluginConfigs;
|
|
54505
|
+
}
|
|
54506
|
+
}
|
|
54507
|
+
if (!shouldLog) {
|
|
54508
|
+
const outputBody2 = sseTransform ? upstreamRes.body.pipeThrough(sseTransform) : upstreamRes.body;
|
|
54509
|
+
return new Response(outputBody2, {
|
|
54510
|
+
status: sseStatus,
|
|
54511
|
+
headers: sseHeaders
|
|
54512
|
+
});
|
|
54513
|
+
}
|
|
54208
54514
|
const [clientStream, logStream] = upstreamRes.body.tee();
|
|
54209
54515
|
(async () => {
|
|
54210
54516
|
const tempPath = createTempStreamCapturePath(logMeta.requestId);
|
|
@@ -54226,30 +54532,61 @@ async function proxyRequest(c2, options) {
|
|
|
54226
54532
|
});
|
|
54227
54533
|
console.error("[logger] \u6D41\u5F0F\u65E5\u5FD7\u5904\u7406\u5931\u8D25:", err);
|
|
54228
54534
|
} finally {
|
|
54229
|
-
logger?.writeEvent(buildLogEvent(logMeta,
|
|
54230
|
-
upstream_status:
|
|
54535
|
+
logger?.writeEvent(buildLogEvent(logMeta, targetUrl, proxy, Date.now(), {
|
|
54536
|
+
upstream_status: sseStatus,
|
|
54231
54537
|
content_type_res: contentTypeRes,
|
|
54232
|
-
response_headers:
|
|
54538
|
+
response_headers: sseHeaders,
|
|
54233
54539
|
stream_bytes: streamBytes,
|
|
54234
54540
|
provider_request_id: providerRequestId,
|
|
54235
54541
|
...streamFile != null && { stream_file: streamFile },
|
|
54236
|
-
...requestBody !== undefined && { request_body: requestBody }
|
|
54542
|
+
...requestBody !== undefined && { request_body: requestBody },
|
|
54543
|
+
...pluginLogOverrides
|
|
54237
54544
|
}));
|
|
54238
54545
|
}
|
|
54239
54546
|
})();
|
|
54240
|
-
|
|
54241
|
-
|
|
54242
|
-
|
|
54547
|
+
const outputBody = sseTransform ? clientStream.pipeThrough(sseTransform) : clientStream;
|
|
54548
|
+
return new Response(outputBody, {
|
|
54549
|
+
status: sseStatus,
|
|
54550
|
+
headers: sseHeaders
|
|
54551
|
+
});
|
|
54552
|
+
}
|
|
54553
|
+
let responseText = await upstreamRes.text();
|
|
54554
|
+
let responseStatus = upstreamRes.status;
|
|
54555
|
+
let finalResponseHeaders = responseHeaders;
|
|
54556
|
+
if (hasPlugins) {
|
|
54557
|
+
const ctx = {
|
|
54558
|
+
requestId: logMeta.requestId,
|
|
54559
|
+
provider: logMeta.provider,
|
|
54560
|
+
modelIn: logMeta.modelIn,
|
|
54561
|
+
modelOut: logMeta.modelOut,
|
|
54562
|
+
routeType: logMeta.routeType,
|
|
54563
|
+
isStream: logMeta.isStream
|
|
54564
|
+
};
|
|
54565
|
+
const result = await executeJsonResponsePlugins(plugins, ctx, upstreamRes.status, responseHeaders, responseText);
|
|
54566
|
+
if (pluginConfigs) {
|
|
54567
|
+
pluginLogOverrides.plugins_response = pluginConfigs;
|
|
54568
|
+
}
|
|
54569
|
+
if (result.body !== responseText) {
|
|
54570
|
+
pluginLogOverrides.response_body_after_plugins = result.body;
|
|
54571
|
+
}
|
|
54572
|
+
responseStatus = result.status;
|
|
54573
|
+
finalResponseHeaders = result.headers;
|
|
54574
|
+
responseText = result.body;
|
|
54575
|
+
}
|
|
54576
|
+
if (!shouldLog) {
|
|
54577
|
+
return new Response(responseText, {
|
|
54578
|
+
status: responseStatus,
|
|
54579
|
+
headers: finalResponseHeaders
|
|
54243
54580
|
});
|
|
54244
54581
|
}
|
|
54245
|
-
const responseText = await upstreamRes.text();
|
|
54246
54582
|
const responseBytes = Buffer.byteLength(responseText, "utf-8");
|
|
54247
54583
|
const eventOverrides = {
|
|
54248
54584
|
upstream_status: upstreamRes.status,
|
|
54249
54585
|
content_type_res: contentTypeRes,
|
|
54250
|
-
response_headers:
|
|
54586
|
+
response_headers: finalResponseHeaders,
|
|
54251
54587
|
response_bytes: responseBytes,
|
|
54252
|
-
provider_request_id: providerRequestId
|
|
54588
|
+
provider_request_id: providerRequestId,
|
|
54589
|
+
...pluginLogOverrides
|
|
54253
54590
|
};
|
|
54254
54591
|
if (requestBody !== undefined) {
|
|
54255
54592
|
eventOverrides.request_body = requestBody;
|
|
@@ -54257,10 +54594,10 @@ async function proxyRequest(c2, options) {
|
|
|
54257
54594
|
if (logger?.bodyPolicy !== "off") {
|
|
54258
54595
|
eventOverrides.response_body = responseText;
|
|
54259
54596
|
}
|
|
54260
|
-
logger?.writeEvent(buildLogEvent(logMeta,
|
|
54597
|
+
logger?.writeEvent(buildLogEvent(logMeta, targetUrl, proxy, Date.now(), eventOverrides));
|
|
54261
54598
|
return new Response(responseText, {
|
|
54262
|
-
status:
|
|
54263
|
-
headers:
|
|
54599
|
+
status: responseStatus,
|
|
54600
|
+
headers: finalResponseHeaders
|
|
54264
54601
|
});
|
|
54265
54602
|
}
|
|
54266
54603
|
|
|
@@ -54275,7 +54612,7 @@ function resolveRoute(modelMap, incomingModel) {
|
|
|
54275
54612
|
return;
|
|
54276
54613
|
}
|
|
54277
54614
|
function createModelRoutingHandler(options) {
|
|
54278
|
-
const { routeType, store, authType, buildTargetUrl } = options;
|
|
54615
|
+
const { routeType, store, authType, buildTargetUrl, pluginManager } = options;
|
|
54279
54616
|
return async (c2) => {
|
|
54280
54617
|
const config2 = store.get();
|
|
54281
54618
|
const modelMap = config2.routes[routeType];
|
|
@@ -54317,49 +54654,60 @@ function createModelRoutingHandler(options) {
|
|
|
54317
54654
|
requestBytes: Buffer.byteLength(body, "utf-8"),
|
|
54318
54655
|
requestHeaders: collectHeaders(c2.req.raw.headers)
|
|
54319
54656
|
};
|
|
54657
|
+
const plugins = pluginManager?.getPlugins(target.provider) ?? [];
|
|
54658
|
+
const pluginConfigs = pluginManager?.getLoadedPlugins(target.provider) ?? [];
|
|
54320
54659
|
return proxyRequest(c2, {
|
|
54321
54660
|
targetUrl,
|
|
54322
54661
|
apiKey: provider.apiKey,
|
|
54323
54662
|
proxy: provider.proxy,
|
|
54324
54663
|
authType,
|
|
54325
54664
|
body,
|
|
54326
|
-
logMeta
|
|
54665
|
+
logMeta,
|
|
54666
|
+
plugins: plugins.length > 0 ? plugins : undefined,
|
|
54667
|
+
pluginConfigs: pluginConfigs.length > 0 ? pluginConfigs.map((lp) => ({
|
|
54668
|
+
name: lp.definition.name,
|
|
54669
|
+
package: lp.config.package,
|
|
54670
|
+
params: lp.config.params ?? {}
|
|
54671
|
+
})) : undefined
|
|
54327
54672
|
});
|
|
54328
54673
|
};
|
|
54329
54674
|
}
|
|
54330
54675
|
|
|
54331
54676
|
// src/routes/anthropic-messages.ts
|
|
54332
|
-
function createAnthropicMessagesRoutes(routeType, store) {
|
|
54677
|
+
function createAnthropicMessagesRoutes(routeType, store, pluginManager) {
|
|
54333
54678
|
const routes = new Hono2;
|
|
54334
54679
|
routes.post("/v1/messages", createModelRoutingHandler({
|
|
54335
54680
|
routeType,
|
|
54336
54681
|
store,
|
|
54337
54682
|
authType: "x-api-key",
|
|
54338
|
-
buildTargetUrl: (base) => `${base}/v1/messages
|
|
54683
|
+
buildTargetUrl: (base) => `${base}/v1/messages`,
|
|
54684
|
+
pluginManager
|
|
54339
54685
|
}));
|
|
54340
54686
|
return routes;
|
|
54341
54687
|
}
|
|
54342
54688
|
|
|
54343
54689
|
// src/routes/openai-completions.ts
|
|
54344
|
-
function createOpenaiCompletionsRoutes(routeType, store) {
|
|
54690
|
+
function createOpenaiCompletionsRoutes(routeType, store, pluginManager) {
|
|
54345
54691
|
const routes = new Hono2;
|
|
54346
54692
|
routes.post("/v1/chat/completions", createModelRoutingHandler({
|
|
54347
54693
|
routeType,
|
|
54348
54694
|
store,
|
|
54349
54695
|
authType: "bearer",
|
|
54350
|
-
buildTargetUrl: (base) => `${base}/v1/chat/completions
|
|
54696
|
+
buildTargetUrl: (base) => `${base}/v1/chat/completions`,
|
|
54697
|
+
pluginManager
|
|
54351
54698
|
}));
|
|
54352
54699
|
return routes;
|
|
54353
54700
|
}
|
|
54354
54701
|
|
|
54355
54702
|
// src/routes/openai-responses.ts
|
|
54356
|
-
function createOpenaiResponsesRoutes(routeType, store) {
|
|
54703
|
+
function createOpenaiResponsesRoutes(routeType, store, pluginManager) {
|
|
54357
54704
|
const routes = new Hono2;
|
|
54358
54705
|
routes.post("/v1/responses", createModelRoutingHandler({
|
|
54359
54706
|
routeType,
|
|
54360
54707
|
store,
|
|
54361
54708
|
authType: "bearer",
|
|
54362
|
-
buildTargetUrl: (base) => `${base}/v1/responses
|
|
54709
|
+
buildTargetUrl: (base) => `${base}/v1/responses`,
|
|
54710
|
+
pluginManager
|
|
54363
54711
|
}));
|
|
54364
54712
|
return routes;
|
|
54365
54713
|
}
|
|
@@ -54520,7 +54868,7 @@ function createChatProxyModel(providerName, providerConfig, model) {
|
|
|
54520
54868
|
throw new Error(`\u6682\u4E0D\u652F\u6301\u7684 provider \u7C7B\u578B: ${providerConfig.type}`);
|
|
54521
54869
|
}
|
|
54522
54870
|
}
|
|
54523
|
-
function createAdminApiRoutes(store, registerCleanup) {
|
|
54871
|
+
function createAdminApiRoutes(store, pluginManager, registerCleanup) {
|
|
54524
54872
|
const api2 = new Hono2;
|
|
54525
54873
|
const cryptoSessions = new Map;
|
|
54526
54874
|
const CRYPTO_SESSION_TTL_MS = 2 * 60 * 1000;
|
|
@@ -54631,18 +54979,22 @@ function createAdminApiRoutes(store, registerCleanup) {
|
|
|
54631
54979
|
session.dispose();
|
|
54632
54980
|
}
|
|
54633
54981
|
});
|
|
54634
|
-
api2.post("/config/apply", (_c) => {
|
|
54982
|
+
api2.post("/config/apply", async (_c) => {
|
|
54635
54983
|
try {
|
|
54636
54984
|
const config2 = store.reload();
|
|
54637
54985
|
if (config2.log) {
|
|
54638
54986
|
const logBaseDir = resolveLogBaseDir(config2.log);
|
|
54639
54987
|
initLogger(logBaseDir, config2.log);
|
|
54640
54988
|
}
|
|
54989
|
+
const pluginResult = await pluginManager.reloadAll(config2.providers);
|
|
54641
54990
|
return _c.json({
|
|
54642
54991
|
ok: true,
|
|
54643
54992
|
summary: {
|
|
54644
54993
|
providers: Object.keys(config2.providers).length,
|
|
54645
54994
|
routes: Object.keys(config2.routes).length
|
|
54995
|
+
},
|
|
54996
|
+
...pluginResult.failures.length > 0 && {
|
|
54997
|
+
pluginWarnings: pluginResult.failures
|
|
54646
54998
|
}
|
|
54647
54999
|
});
|
|
54648
55000
|
} catch (err) {
|
|
@@ -55067,7 +55419,7 @@ async function proxyAdminToDevServer(c2, origin) {
|
|
|
55067
55419
|
headers: buildProxyResponseHeaders(upstreamRes.headers)
|
|
55068
55420
|
});
|
|
55069
55421
|
}
|
|
55070
|
-
function createApp(store, options) {
|
|
55422
|
+
async function createApp(store, options) {
|
|
55071
55423
|
const config2 = store.get();
|
|
55072
55424
|
console.log(`\u5DF2\u52A0\u8F7D\u914D\u7F6E: ${store.getPath()}`);
|
|
55073
55425
|
if (config2.log) {
|
|
@@ -55078,15 +55430,24 @@ function createApp(store, options) {
|
|
|
55078
55430
|
}
|
|
55079
55431
|
const stopLogStorageTask = startLogStorageBackgroundTask(config2.log);
|
|
55080
55432
|
options?.registerCleanup?.(stopLogStorageTask);
|
|
55433
|
+
const configDir = dirname3(resolve6(store.getPath()));
|
|
55434
|
+
const pluginManager = new PluginManager(configDir);
|
|
55435
|
+
const reloadResult = await pluginManager.reloadAll(config2.providers);
|
|
55436
|
+
if (!reloadResult.ok) {
|
|
55437
|
+
console.warn(`[plugin] \u63D2\u4EF6\u521D\u59CB\u5316\u5B8C\u6210\uFF0C\u4F46\u6709 ${reloadResult.failures.length} \u4E2A\u63D2\u4EF6\u52A0\u8F7D\u5931\u8D25`);
|
|
55438
|
+
}
|
|
55439
|
+
options?.registerCleanup?.(() => {
|
|
55440
|
+
pluginManager.disposeAll().catch(() => {});
|
|
55441
|
+
});
|
|
55081
55442
|
printIntegrationGuide(config2);
|
|
55082
55443
|
const app = new Hono2;
|
|
55083
55444
|
app.get("/", (c2) => c2.text("local-router is running"));
|
|
55084
55445
|
for (const [routeType, entry] of Object.entries(ROUTE_REGISTRY)) {
|
|
55085
|
-
const subApp = entry.create(routeType, store);
|
|
55446
|
+
const subApp = entry.create(routeType, store, pluginManager);
|
|
55086
55447
|
app.route(entry.mountPrefix, subApp);
|
|
55087
55448
|
console.log(`\u5DF2\u6CE8\u518C\u8DEF\u7531: ${routeType} -> ${entry.mountPrefix}`);
|
|
55088
55449
|
}
|
|
55089
|
-
app.route("/api", createAdminApiRoutes(store, options?.registerCleanup));
|
|
55450
|
+
app.route("/api", createAdminApiRoutes(store, pluginManager, options?.registerCleanup));
|
|
55090
55451
|
console.log("\u5DF2\u6CE8\u518C\u7BA1\u7406 API: /api");
|
|
55091
55452
|
app.get("/api/docs", middleware({ url: "/api/openapi.json" }));
|
|
55092
55453
|
app.get("/api/openapi.json", (c2) => c2.json(openAPISpec));
|
|
@@ -55115,14 +55476,14 @@ function createApp(store, options) {
|
|
|
55115
55476
|
}
|
|
55116
55477
|
return app;
|
|
55117
55478
|
}
|
|
55118
|
-
function createDefaultAppFromProcessArgs() {
|
|
55479
|
+
async function createDefaultAppFromProcessArgs() {
|
|
55119
55480
|
const configPath = parseConfigPath();
|
|
55120
55481
|
const store = new ConfigStore(configPath);
|
|
55121
55482
|
return createApp(store);
|
|
55122
55483
|
}
|
|
55123
55484
|
|
|
55124
55485
|
// src/entry.ts
|
|
55125
|
-
var app = createDefaultAppFromProcessArgs();
|
|
55486
|
+
var app = await createDefaultAppFromProcessArgs();
|
|
55126
55487
|
var entry_default = app;
|
|
55127
55488
|
export {
|
|
55128
55489
|
entry_default as default
|