@chatpanel/gateway 0.6.45 → 0.6.46
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/package.json +1 -1
- package/src/server.js +20 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chatpanel/gateway",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.46",
|
|
4
4
|
"description": "Local privacy gateway \u2014 redacts PII out of OpenAI/Anthropic API traffic before it reaches a model, then restores it in the reply. Point opencode, codex, aider, Claude Code, etc. at it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/server.js
CHANGED
|
@@ -49,7 +49,7 @@ import * as openai from './openai.js';
|
|
|
49
49
|
import * as responses from './responses.js';
|
|
50
50
|
import * as anthropic from './anthropic.js';
|
|
51
51
|
|
|
52
|
-
export const VERSION = '0.6.
|
|
52
|
+
export const VERSION = '0.6.46';
|
|
53
53
|
|
|
54
54
|
// WARM search tier — SQLite + FTS5 record store (falls back to an encrypted-JSON
|
|
55
55
|
// store if SQLite can't load), fed by the extension's ingest sync + backup-ingest.
|
|
@@ -429,6 +429,24 @@ async function handleBridge(req, res, { kind, adapter, redactable, pathname, age
|
|
|
429
429
|
|
|
430
430
|
// ---- backend: api ----------------------------------------------------------
|
|
431
431
|
|
|
432
|
+
// Join a destination's base URL to the incoming path WITHOUT doubling the API version.
|
|
433
|
+
//
|
|
434
|
+
// Every OpenAI-compatible provider tells you to paste a base that already ends at the version
|
|
435
|
+
// — https://integrate.api.nvidia.com/v1, https://openrouter.ai/api/v1, https://router.hugging
|
|
436
|
+
// face.co/v1 — and the request arriving here carries the version too (/v1/chat/completions).
|
|
437
|
+
// Concatenating them produced /v1/v1/chat/completions, and what came back was the provider's
|
|
438
|
+
// own "404 page not found". That reads like a broken gateway, or a wrong model, or a dead
|
|
439
|
+
// channel — anything except the mis-joined URL it actually was.
|
|
440
|
+
//
|
|
441
|
+
// Matching on the leading segment rather than hardcoding "v1" so a provider on /v2 or a beta
|
|
442
|
+
// path is joined correctly too.
|
|
443
|
+
export function joinUpstream(base, pathname, search = '') {
|
|
444
|
+
const b = String(base || '').replace(/\/+$/, '');
|
|
445
|
+
const seg = String(pathname || '').split('/')[1];
|
|
446
|
+
if (seg && b.endsWith(`/${seg}`)) return b.slice(0, -(seg.length + 1)) + pathname + search;
|
|
447
|
+
return b + pathname + search;
|
|
448
|
+
}
|
|
449
|
+
|
|
432
450
|
async function handleApi(req, res, { adapter, kind, pathname, search, base, destKey, destProtocol, harness, trace }, outBody, vault) {
|
|
433
451
|
let upstream;
|
|
434
452
|
const up0 = trace ? trace.clock() : 0;
|
|
@@ -443,7 +461,7 @@ async function handleApi(req, res, { adapter, kind, pathname, search, base, dest
|
|
|
443
461
|
// SSRF guard on the config-supplied upstream: block cloud-metadata + non-http(s)
|
|
444
462
|
// BEFORE the fetch. Loopback/LAN stay allowed (Ollama/LM Studio/homelab are the
|
|
445
463
|
// point of a BYO gateway); only the credential-theft pivot is refused.
|
|
446
|
-
const upstreamUrl = assertEndpointUrl(base
|
|
464
|
+
const upstreamUrl = assertEndpointUrl(joinUpstream(base, pathname, search)).toString();
|
|
447
465
|
upstream = await fetch(upstreamUrl, {
|
|
448
466
|
method: req.method,
|
|
449
467
|
headers,
|