openzoo 0.9.5 → 0.9.7
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/lib/models.js +18 -3
- package/lib/proxy.js +30 -5
- package/package.json +1 -1
package/lib/models.js
CHANGED
|
@@ -137,12 +137,27 @@ export const ALIAS_IDS = [
|
|
|
137
137
|
'deepseek-chat', 'deepseek-reasoner', 'qwen-max', 'llama-3.3-70b',
|
|
138
138
|
];
|
|
139
139
|
|
|
140
|
-
/**
|
|
140
|
+
/**
|
|
141
|
+
* Merge alias rows into a /v1/models payload without duplicating real ids.
|
|
142
|
+
* Each alias inherits context_length and pricing from the model it RESOLVES
|
|
143
|
+
* to — a harness sizing its corpus off "gpt-4o" gets the real ceiling of the
|
|
144
|
+
* model that will actually serve it, not a blank.
|
|
145
|
+
*/
|
|
141
146
|
export function augmentModelList(payload) {
|
|
142
147
|
const data = Array.isArray(payload?.data) ? payload.data : [];
|
|
143
148
|
const have = new Set(data.map((m) => m.id));
|
|
144
|
-
const
|
|
145
|
-
|
|
149
|
+
const ids = data.map((m) => m.id);
|
|
150
|
+
const aliases = ALIAS_IDS.filter((id) => !have.has(id)).map((id) => {
|
|
151
|
+
const target = data.find((m) => m.id === resolveModel(id, ids));
|
|
152
|
+
return {
|
|
153
|
+
id,
|
|
154
|
+
object: 'model',
|
|
155
|
+
owned_by: 'openzoo-alias',
|
|
156
|
+
...(target?.context_length ? { context_length: target.context_length, context_window: target.context_window ?? target.context_length } : {}),
|
|
157
|
+
...(target?.pricing ? { pricing: target.pricing } : {}),
|
|
158
|
+
...(target ? { served_by: target.id } : {}),
|
|
159
|
+
};
|
|
160
|
+
});
|
|
146
161
|
return { ...payload, object: payload?.object || 'list', data: [...data, ...aliases] };
|
|
147
162
|
}
|
|
148
163
|
|
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
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzoo",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.7",
|
|
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",
|