openzoo 0.44.1 → 0.45.0
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 +11 -0
- package/lib/info.js +54 -0
- package/lib/proxy.js +28 -0
- package/package.json +1 -1
package/bin/openzoo.js
CHANGED
|
@@ -192,6 +192,17 @@ async function main() {
|
|
|
192
192
|
case 'balance':
|
|
193
193
|
await (await import('../lib/info.js')).printBalance();
|
|
194
194
|
break;
|
|
195
|
+
case 'topup':
|
|
196
|
+
case 'prepay':
|
|
197
|
+
await (await import('../lib/info.js')).topUp(process.argv[3]);
|
|
198
|
+
break;
|
|
199
|
+
case 'credit':
|
|
200
|
+
case 'credits': {
|
|
201
|
+
const bal = await (await import('../lib/info.js')).creditBalance();
|
|
202
|
+
console.log(`prepaid credit: $${bal.toFixed(6)}`);
|
|
203
|
+
if (bal <= 0) console.log('buy some with: npx openzoo topup 10');
|
|
204
|
+
break;
|
|
205
|
+
}
|
|
195
206
|
case 'address':
|
|
196
207
|
(await import('../lib/info.js')).printAddress();
|
|
197
208
|
break;
|
package/lib/info.js
CHANGED
|
@@ -73,3 +73,57 @@ export async function printBalance() {
|
|
|
73
73
|
console.log(` or USDC on Base to ${evmAddress}`);
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* PREPAY. Buys gateway credit in ONE settlement so later calls skip the
|
|
79
|
+
* per-call payment round trip entirely.
|
|
80
|
+
*
|
|
81
|
+
* That round trip is where the latency lives, not the model: MEASURED against
|
|
82
|
+
* the live gateway, a 402 challenge comes back in 0.12s while a full paid call
|
|
83
|
+
* takes 9-37s end to end. The gateway already applies credit automatically
|
|
84
|
+
* whenever a balance covers the quote — nothing could BUY it until now.
|
|
85
|
+
*
|
|
86
|
+
* Credit is keyed by the signed namespace, so it belongs to this wallet and
|
|
87
|
+
* cannot be spent by anyone else.
|
|
88
|
+
*/
|
|
89
|
+
export async function topUp(usdArg) {
|
|
90
|
+
const usd = Number(usdArg);
|
|
91
|
+
if (!Number.isFinite(usd) || usd < 1 || usd > 500) {
|
|
92
|
+
throw new Error('usage: openzoo topup <usd> (1-500)');
|
|
93
|
+
}
|
|
94
|
+
const { PayClient } = await import('./pay.js');
|
|
95
|
+
const client = new PayClient();
|
|
96
|
+
const url = `${config.apiBase}/v1/credits/topup`;
|
|
97
|
+
|
|
98
|
+
const before = await creditBalance();
|
|
99
|
+
console.log(`credit before: $${before.toFixed(6)}`);
|
|
100
|
+
console.log(`buying $${usd.toFixed(2)} of credit — one on-chain settlement...`);
|
|
101
|
+
|
|
102
|
+
const { response, paid } = await client.fetch(url, {
|
|
103
|
+
method: 'POST',
|
|
104
|
+
headers: { 'content-type': 'application/json' },
|
|
105
|
+
body: JSON.stringify({ usd }),
|
|
106
|
+
});
|
|
107
|
+
const body = await response.json().catch(() => ({}));
|
|
108
|
+
if (!response.ok) {
|
|
109
|
+
throw new Error(`topup failed (HTTP ${response.status}): ${body.error || body.detail || 'unknown'}`);
|
|
110
|
+
}
|
|
111
|
+
console.log('');
|
|
112
|
+
console.log(`credited: $${Number(body.creditedUsd ?? usd).toFixed(2)}${paid ? '' : ' (from existing credit)'}`);
|
|
113
|
+
console.log(`balance: $${Number(body.balanceUsd ?? 0).toFixed(6)}`);
|
|
114
|
+
if (body.tx) console.log(`tx: ${body.tx}`);
|
|
115
|
+
console.log('');
|
|
116
|
+
console.log('calls now settle against this balance instead of paying on-chain each time.');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** Current prepaid credit for this wallet's namespace. */
|
|
120
|
+
export async function creditBalance() {
|
|
121
|
+
const { withNamespace } = await import('./namespace.js');
|
|
122
|
+
try {
|
|
123
|
+
const r = await fetch(`${config.apiBase}/v1/credits`, { headers: withNamespace({}) });
|
|
124
|
+
const j = await r.json();
|
|
125
|
+
return Number(j.balanceUsd) || 0;
|
|
126
|
+
} catch {
|
|
127
|
+
return 0;
|
|
128
|
+
}
|
|
129
|
+
}
|
package/lib/proxy.js
CHANGED
|
@@ -779,6 +779,34 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
|
|
|
779
779
|
server.listen(config.port, bindHost, resolve);
|
|
780
780
|
});
|
|
781
781
|
|
|
782
|
+
// AUTO-PREPAY. Paying on-chain per call is where the latency lives: the
|
|
783
|
+
// gateway answers its 402 challenge in ~0.12s while a full settled call
|
|
784
|
+
// MEASURED 9-37s end to end. Credit is applied automatically server-side
|
|
785
|
+
// whenever a balance covers the quote, so buying it once makes every later
|
|
786
|
+
// call skip verify+settle entirely.
|
|
787
|
+
//
|
|
788
|
+
// Runs in the background — never block the listener on a payment — and only
|
|
789
|
+
// when this wallet actually has funds, so a fresh/empty wallet is untouched.
|
|
790
|
+
// Opt out with OPENZOO_NO_AUTOTOPUP=1; size it with OPENZOO_AUTOTOPUP_USD.
|
|
791
|
+
if (!process.env.OPENZOO_NO_AUTOTOPUP) {
|
|
792
|
+
(async () => {
|
|
793
|
+
try {
|
|
794
|
+
const { creditBalance, topUp } = await import('./info.js');
|
|
795
|
+
const have = await creditBalance();
|
|
796
|
+
const want = Number(process.env.OPENZOO_AUTOTOPUP_USD || 5);
|
|
797
|
+
// Only top up when nearly dry, so restarting the proxy does not keep
|
|
798
|
+
// buying credit on top of a healthy balance.
|
|
799
|
+
if (have >= Math.min(1, want)) return;
|
|
800
|
+
say(`prepaid credit $${have.toFixed(4)} — topping up $${want} so calls stop settling on-chain each time...`);
|
|
801
|
+
await topUp(want);
|
|
802
|
+
} catch (e) {
|
|
803
|
+
// A wallet with no funds, or a gateway that refuses, must never stop
|
|
804
|
+
// the proxy from serving: calls just fall back to paying per call.
|
|
805
|
+
say(`auto top-up skipped: ${String(e.message || e).slice(0, 120)}`);
|
|
806
|
+
}
|
|
807
|
+
})();
|
|
808
|
+
}
|
|
809
|
+
|
|
782
810
|
if (!silent) {
|
|
783
811
|
// VERSION IN THE BANNER, deliberately. `npx openzoo` can serve a STALE
|
|
784
812
|
// cached copy — npx reuses a cache entry that matches the bare spec, so a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openzoo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.45.0",
|
|
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",
|