openzoo 0.9.4 → 0.9.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.
package/bin/openzoo.js CHANGED
@@ -30,12 +30,12 @@ env:
30
30
  OPENZOO_RPC (mainnet-beta) OPENZOO_TOKEN (402 rail preference) OPENZOO_WALLET (~/.openzoo/wallet.json)
31
31
  OPENZOO_RAIL (unset — force a rail: solana | base | robinhood)
32
32
  OPENZOO_BASE_RPC (https://mainnet.base.org) OPENZOO_RH_RPC (rpc.mainnet.chain.robinhood.com)
33
- OPENZOO_MAX_USD_PER_CALL (0.5) OPENZOO_DEMO_MAX_USD (0.01)
33
+ OPENZOO_MAX_USD_PER_CALL (unset — NO per-call ceiling; set to add one) OPENZOO_DEMO_MAX_USD (0.01)
34
34
  OPENZOO_CONTEXT_MIN_CHARS (16384 — bodies bigger than this bind once + reuse)
35
35
  OPENZOO_NO_CONTEXT_CACHE (0 — set 1 to always ship the full body)
36
36
  OPENZOO_ENABLE_RH (0 — let DEFAULT selection fall through to the Robinhood rail;
37
37
  OPENZOO_RAIL=robinhood forces it without this)
38
- OPENZOO_TUNNEL_MAX_USD (1.00 — public-url session ceiling) OPENZOO_TUNNEL_TOKEN (pin the api key)
38
+ OPENZOO_TUNNEL_MAX_USD (unsetNO public-url session ceiling; set to add one) OPENZOO_TUNNEL_TOKEN (pin the api key)
39
39
  OPENZOO_NO_TUNNEL (0 — set 1 for localhost-only, no public url)`;
40
40
 
41
41
  async function main() {
package/lib/config.js CHANGED
@@ -15,7 +15,9 @@ export const config = {
15
15
  rhRpcUrl: process.env.OPENZOO_RH_RPC || 'https://rpc.mainnet.chain.robinhood.com',
16
16
  walletPath: process.env.OPENZOO_WALLET || path.join(os.homedir(), '.openzoo', 'wallet.json'),
17
17
  // Refuse to auto-pay any single 402 quote above this many USD (extra.billedUsd).
18
- maxUsdPerCall: Number(process.env.OPENZOO_MAX_USD_PER_CALL || 0.5),
18
+ // UNCAPPED by default (user directive: no maximums — a giant bound-corpus
19
+ // call is a legitimate call). Set OPENZOO_MAX_USD_PER_CALL to add a ceiling.
20
+ maxUsdPerCall: process.env.OPENZOO_MAX_USD_PER_CALL ? Number(process.env.OPENZOO_MAX_USD_PER_CALL) : Infinity,
19
21
  // Demo will only actually pay if the quote is at or below this.
20
22
  demoMaxUsd: Number(process.env.OPENZOO_DEMO_MAX_USD || 0.01),
21
23
  };
package/lib/proxy.js CHANGED
@@ -271,12 +271,37 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
271
271
  }
272
272
  if (viaTunnel) {
273
273
  const got = (req.headers.authorization || '').replace(/^Bearer\s+/i, '').trim();
274
- if (got !== tunnelGate.token) {
275
- log(`public url: 401 ${req.method} ${req.url}`);
276
- jsonErr(res, 401, 'unauthorized: this openzoo public URL requires the api key printed at startup');
277
- return;
274
+ const authed = got === tunnelGate.token;
275
+ const p = (req.url || '').split('?')[0];
276
+ // DISCOVERY IS FREE. An agent probing this URL cold should be able to
277
+ // work out what it is and what to ask its operator for — a bare 401 on
278
+ // every path just sends it spelunking through the operator's machine.
279
+ // Reads that cost nothing and leak nothing (the catalog is public on
280
+ // the zoo anyway) go through without the key; money paths stay gated.
281
+ if (!authed) {
282
+ if (req.method === 'GET' && (p === '/' || p === '/v1' || p === '/v1/info')) {
283
+ res.writeHead(200, { 'content-type': 'application/json' });
284
+ res.end(JSON.stringify({
285
+ name: 'openzoo proxy (public tunnel)',
286
+ what: 'OpenAI-compatible pay-per-call proxy — the operator\'s wallet pays per request via x402; no account, no signup.',
287
+ authentication: 'All POST endpoints require `Authorization: Bearer <api key>`. The key is printed in the operator\'s terminal at proxy startup — ask them for it. It is NOT guessable.',
288
+ endpoints: {
289
+ 'GET /v1/models': 'model catalog with pricing + context_length — no key needed',
290
+ 'GET /v1/models/{id}': 'single-model probe — no key needed',
291
+ 'POST /v1/chat/completions': 'chat (streaming supported, any model id — unknown ids are matched to the nearest served model) — key required',
292
+ },
293
+ docs: 'https://openzoo.fun · https://www.npmjs.com/package/openzoo',
294
+ }, null, 2));
295
+ return;
296
+ }
297
+ const freeRead = req.method === 'GET' && (p === '/v1/models' || p.startsWith('/v1/models/'));
298
+ if (!freeRead) {
299
+ log(`public url: 401 ${req.method} ${req.url}`);
300
+ jsonErr(res, 401, 'unauthorized: this openzoo public URL requires the api key printed at the operator\'s proxy startup — GET / for discovery, GET /v1/models is open');
301
+ return;
302
+ }
278
303
  }
279
- if (tunnelSpent >= tunnelGate.sessionMaxUsd) {
304
+ if (authed && tunnelSpent >= tunnelGate.sessionMaxUsd) {
280
305
  jsonErr(res, 402, `openzoo public-URL session cap reached ($${tunnelGate.sessionMaxUsd}) — restart the proxy or raise OPENZOO_TUNNEL_MAX_USD`);
281
306
  return;
282
307
  }
@@ -515,7 +540,7 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
515
540
  try {
516
541
  const { ensureCloudflared, startCloudflared, mintToken } = await import('./tunnel.js');
517
542
  const token = mintToken();
518
- const cap = Number(process.env.OPENZOO_TUNNEL_MAX_USD || 1);
543
+ const cap = process.env.OPENZOO_TUNNEL_MAX_USD ? Number(process.env.OPENZOO_TUNNEL_MAX_USD) : Infinity;
519
544
  const bin = await ensureCloudflared((m) => log(m));
520
545
  const { url, proc } = await startCloudflared(bin, config.port, log);
521
546
  tunnelGate = { token, sessionMaxUsd: cap };
@@ -527,8 +552,8 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
527
552
  log('cloud IDE / remote harness? use the public URL (they cannot reach localhost):');
528
553
  log(` base_url = ${url}/v1`);
529
554
  log(` api_key = ${token}`);
530
- log(` (key REQUIRED on the public URL — it spends this wallet; capped at $${cap.toFixed(2)}/session,`);
531
- log(' OPENZOO_TUNNEL_MAX_USD to change, OPENZOO_NO_TUNNEL=1 for localhost-only)');
555
+ log(` (key REQUIRED on the public URL — it spends this wallet; ${Number.isFinite(cap) ? `capped at $${cap.toFixed(2)}/session` : 'NO session cap — OPENZOO_TUNNEL_MAX_USD adds one'},`);
556
+ log(' OPENZOO_NO_TUNNEL=1 for localhost-only)');
532
557
  } catch (err) {
533
558
  log(`public URL unavailable (${err.message}) — localhost still works; OPENZOO_NO_TUNNEL=1 hides this line`);
534
559
  }
package/lib/tunnel.js CHANGED
@@ -16,8 +16,8 @@
16
16
  * front of your money, so tunnel mode is the ONE mode where the api key is real:
17
17
  * - a random bearer token is minted per session and REQUIRED (401 otherwise),
18
18
  * checked before anything is forwarded, quoted, or paid;
19
- * - the per-call cap (OPENZOO_MAX_USD_PER_CALL) still applies, and a session
20
- * ceiling (OPENZOO_TUNNEL_MAX_USD, default $1) stops paying when reached;
19
+ * - caps are OPT-IN (user directive: no maximums by default) — set
20
+ * OPENZOO_MAX_USD_PER_CALL and/or OPENZOO_TUNNEL_MAX_USD to add them;
21
21
  * - every tunnel-served request is logged with its running spend.
22
22
  */
23
23
  import { spawn } from 'node:child_process';
@@ -119,7 +119,8 @@ export async function runTunnel() {
119
119
  const { config } = await import('./config.js');
120
120
 
121
121
  const token = mintToken();
122
- const sessionCap = Number(process.env.OPENZOO_TUNNEL_MAX_USD || 1);
122
+ // Uncapped unless the user sets a ceiling — the required token is the gate.
123
+ const sessionCap = process.env.OPENZOO_TUNNEL_MAX_USD ? Number(process.env.OPENZOO_TUNNEL_MAX_USD) : null;
123
124
 
124
125
  // The proxy enforces the gate itself: nothing is forwarded, quoted or paid
125
126
  // without the bearer token, and the session ceiling stops spend cold.
@@ -136,7 +137,9 @@ export async function runTunnel() {
136
137
  console.log(' ┌─────────────────────────────────────────────────────────────');
137
138
  console.log(' │ THIS URL SPENDS REAL MONEY FROM YOUR WALLET.');
138
139
  console.log(' │ The token below is the only thing protecting it.');
139
- console.log(` │ Session ceiling: $${sessionCap.toFixed(2)} then it stops paying.`);
140
+ console.log(sessionCap != null
141
+ ? ` │ Session ceiling: $${sessionCap.toFixed(2)} — then it stops paying.`
142
+ : ' │ NO session ceiling — OPENZOO_TUNNEL_MAX_USD adds one.');
140
143
  console.log(' │ Ctrl-C when you are done; the URL dies with this process.');
141
144
  console.log(' └─────────────────────────────────────────────────────────────');
142
145
  console.log('');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openzoo",
3
- "version": "0.9.4",
3
+ "version": "0.9.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",