@chatpanel/gateway 0.6.39 → 0.6.40

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatpanel/gateway",
3
- "version": "0.6.39",
3
+ "version": "0.6.40",
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": {
@@ -178,6 +178,15 @@ export class HistoryStore {
178
178
  return this.records.size;
179
179
  }
180
180
 
181
+ // Wipe every record — the user purging the on-disk warm copy. Returns how many were dropped.
182
+ clear() {
183
+ const n = this.records.size;
184
+ this.records.clear();
185
+ this.index = new SearchIndex();
186
+ this.schedulePersist();
187
+ return n;
188
+ }
189
+
181
190
  search(query, opts) {
182
191
  return this.index.search(query, opts);
183
192
  }
package/src/server.js CHANGED
@@ -46,7 +46,7 @@ import * as openai from './openai.js';
46
46
  import * as responses from './responses.js';
47
47
  import * as anthropic from './anthropic.js';
48
48
 
49
- export const VERSION = '0.6.39';
49
+ export const VERSION = '0.6.40';
50
50
 
51
51
  // WARM search tier — SQLite + FTS5 record store (falls back to an encrypted-JSON
52
52
  // store if SQLite can't load), fed by the extension's ingest sync + backup-ingest.
@@ -534,8 +534,8 @@ export function createGateway(cfg = loadConfig()) {
534
534
  // WRITES are not: a drive-by localhost page or a random local process must not be
535
535
  // able to inject records the model then trusts as the user's real history. Ingest
536
536
  // requires the extension Origin (which its POST always carries) or the gateway token.
537
- if (pathname === '/v1/history/ingest' && req.method === 'POST' && !isAdminAuthorized(req)) {
538
- return sendJson(res, 403, { error: { message: 'history ingest is a write — extension origin or gateway token required', type: 'forbidden' } });
537
+ if ((pathname === '/v1/history/ingest' || pathname === '/v1/history/clear') && req.method === 'POST' && !isAdminAuthorized(req)) {
538
+ return sendJson(res, 403, { error: { message: 'history write — extension origin or gateway token required', type: 'forbidden' } });
539
539
  }
540
540
  // The access log is who-read-what — sensitive, and writable only by the local MCP
541
541
  // process (which sends the gateway token). Extension Origin or token for both the
@@ -596,6 +596,10 @@ export function createGateway(cfg = loadConfig()) {
596
596
  return sendJson(res, 400, { error: { message: `ingest failed: ${e.message}`, type: 'ingest_error' } });
597
597
  }
598
598
  }
599
+ if (pathname === '/v1/history/clear' && req.method === 'POST') {
600
+ const dropped = historyStore.clear();
601
+ return sendJson(res, 200, { ok: true, dropped, size: historyStore.size });
602
+ }
599
603
  if (pathname === '/v1/history/search' && req.method === 'POST') {
600
604
  try {
601
605
  const body = JSON.parse((await readBody(req, cfg.maxBodyBytes)).toString('utf8')) || {};
@@ -153,6 +153,14 @@ export class SqliteHistoryStore {
153
153
  const body = this.db.get('SELECT text FROM fts WHERE id = ?', [id]);
154
154
  return { ...meta, text: body?.text || '' };
155
155
  }
156
+
157
+ // Wipe every record — the user purging the on-disk warm copy. Returns how many were dropped.
158
+ clear() {
159
+ const n = this.size;
160
+ this.db.exec('DELETE FROM records');
161
+ this.db.exec('DELETE FROM fts');
162
+ return n;
163
+ }
156
164
  }
157
165
 
158
166
  // Pick the best available warm engine. SQLite when it loads; otherwise the