openzoo 0.34.5 → 0.34.6

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.
@@ -31,5 +31,19 @@ let models = [];
31
31
  try { models = JSON.parse(fs.readFileSync(modelsPath, 'utf8')); }
32
32
  catch (e) { log(`cursor-backend: could not read models (${e.message})`); process.exit(1); }
33
33
 
34
+ // NEVER LET ONE BAD REQUEST KILL THE SERVER. The h2 header bug threw out of an
35
+ // async handler, which is an unhandled rejection / uncaught throw at process
36
+ // level — node tore the whole backend down mid-request, so :443 went dead and
37
+ // every later attempt logged ECONNRESET with no listener behind it. This is a
38
+ // static impersonation server; staying up while logging the fault is always
39
+ // better than exiting and blackholing the host the app depends on.
40
+ process.on('uncaughtException', (e) => {
41
+ log(`cursor-backend: UNCAUGHT ${e && e.code ? e.code + ' ' : ''}${e && e.message}`);
42
+ if (e && e.stack) log(String(e.stack).split('\n').slice(1, 4).join('\n'));
43
+ });
44
+ process.on('unhandledRejection', (e) => {
45
+ log(`cursor-backend: UNHANDLED REJECTION ${e && e.message ? e.message : e}`);
46
+ });
47
+
34
48
  startCursorBackend({ port, models, log });
35
49
  log(`cursor-backend: standalone up on :${port} (${models.length} models)`);
@@ -305,7 +305,21 @@ export function startCursorBackend({ port = 8443, models, log = () => {} } = {})
305
305
  });
306
306
  const buf = Buffer.from(await up.arrayBuffer());
307
307
  const h = { ...CORS };
308
- up.headers.forEach((v, k) => { if (!['content-encoding', 'transfer-encoding', 'connection'].includes(k)) h[k] = v; });
308
+ // STRIP EVERY CONNECTION-SPECIFIC HEADER, NOT JUST `connection`.
309
+ // RFC 7540 §8.1.2.2 bans all of these on HTTP/2, and Node enforces it
310
+ // by THROWING ERR_HTTP2_INVALID_CONNECTION_HEADERS out of writeHead.
311
+ // The local proxy answers with `keep-alive`, which sailed past a
312
+ // denylist that only knew about `connection` — so the very first
313
+ // desktop request killed the whole backend process (uncaught, since
314
+ // this is inside the async handler), and every later attempt got
315
+ // ECONNRESET with nothing listening. Content-length goes too: the
316
+ // body was re-buffered, so let Node recompute it.
317
+ const HOP_BY_HOP = new Set([
318
+ 'connection', 'keep-alive', 'upgrade', 'proxy-connection',
319
+ 'transfer-encoding', 'te', 'trailer', 'proxy-authenticate',
320
+ 'proxy-authorization', 'content-encoding', 'content-length',
321
+ ]);
322
+ up.headers.forEach((v, k) => { if (!HOP_BY_HOP.has(k.toLowerCase())) h[k] = v; });
309
323
  res.writeHead(up.status, h);
310
324
  res.end(buf);
311
325
  log(`cursor-backend: #${conns} ${req.method} ${full} ANTHROPIC -> proxy (${up.status}, ${buf.length}b)`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openzoo",
3
- "version": "0.34.5",
3
+ "version": "0.34.6",
4
4
  "description": "Local x402-paying proxy + MCP server for openzoo.fun — point any OpenAI-compatible harness (Cursor, Claude Code, aider, SDKs) at localhost and it pays per call from a local burner wallet. Solana and Base rails live; Robinhood experimental.",
5
5
  "license": "MIT",
6
6
  "type": "module",