@chatpanel/gateway 0.2.2 → 0.2.3

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/server.js +17 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatpanel/gateway",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Local privacy gateway — 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
@@ -32,7 +32,7 @@ import * as openai from './openai.js';
32
32
  import * as responses from './responses.js';
33
33
  import * as anthropic from './anthropic.js';
34
34
 
35
- export const VERSION = '0.2.2';
35
+ export const VERSION = '0.2.3';
36
36
 
37
37
  const KNOWN_AGENTS = new Set(['codex', 'claude', 'opencode', 'pi', 'kiro', 'antigravity']);
38
38
 
@@ -67,6 +67,14 @@ function setCors(res, origin) {
67
67
 
68
68
  const STARTED_AT = Date.now();
69
69
 
70
+ // In-memory ring of recent request SUMMARIES for the extension's monitoring view.
71
+ // Counts only — never any prompt/response text or values.
72
+ const recentRequests = [];
73
+ function recordRequest(entry) {
74
+ recentRequests.push(entry);
75
+ if (recentRequests.length > 50) recentRequests.shift();
76
+ }
77
+
70
78
  // Classify a request: which protocol kind + adapter, whether it's a redactable
71
79
  // chat endpoint, and (api backend) which upstream base URL.
72
80
  function route(pathname, headers, cfg) {
@@ -237,6 +245,9 @@ export function createGateway(cfg = loadConfig()) {
237
245
  uptimeSeconds: Math.floor((Date.now() - STARTED_AT) / 1000),
238
246
  });
239
247
  }
248
+ if (pathname === '/logs' && req.method === 'GET') {
249
+ return sendJson(res, 200, { entries: [...recentRequests].reverse() }); // newest first; counts only
250
+ }
240
251
  if (pathname === '/config' && req.method === 'GET') {
241
252
  const proUnlocked = await resolvePro(cfg.pro?.entitlementToken);
242
253
  return sendJson(res, 200, publicConfig(cfg, { proUnlocked }));
@@ -270,6 +281,7 @@ export function createGateway(cfg = loadConfig()) {
270
281
  let vault = null;
271
282
  let body = null;
272
283
  let outBody = raw;
284
+ let redactedCount = 0;
273
285
  if (r.redactable && req.method === 'POST' && raw.length) {
274
286
  try { body = JSON.parse(raw.toString('utf8')); } catch { body = null; }
275
287
  if (body) {
@@ -287,6 +299,7 @@ export function createGateway(cfg = loadConfig()) {
287
299
  req.on('close', () => ac.abort());
288
300
  const { vault: v, count } = await redactSegments(segs, cfg.redaction, { signal: ac.signal, isPro });
289
301
  vault = v;
302
+ redactedCount = count;
290
303
  outBody = Buffer.from(JSON.stringify(body), 'utf8');
291
304
  }
292
305
  }
@@ -294,8 +307,9 @@ export function createGateway(cfg = loadConfig()) {
294
307
  // Route by the requested model → a destination (agent via the bridge, or an
295
308
  // API we forward to). Falls back to the legacy backend when none configured.
296
309
  const dest = resolveDestination(body?.model, cfg, r.kind);
297
- if (cfg.logRequests) {
298
- console.log(`[gateway] ${req.method} ${pathname} · model=${body?.model || '-'} ${dest ? `${dest.id}(${dest.type})` : 'none'}`);
310
+ if (cfg.logRequests && r.redactable) {
311
+ recordRequest({ t: Date.now(), model: body?.model || null, dest: dest ? dest.id : null, type: dest ? dest.type : null, redacted: redactedCount });
312
+ console.log(`[gateway] ${req.method} ${pathname} · model=${body?.model || '-'} → ${dest ? `${dest.id}(${dest.type})` : 'none'} · redacted ${redactedCount}`);
299
313
  }
300
314
  if (dest && dest.type === 'api') {
301
315
  if (!dest.baseUrl) return sendJson(res, 502, { error: `destination "${dest.id}" has no baseUrl` });