openzoo 0.51.20 → 0.51.22

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.
@@ -1,3 +1,3 @@
1
1
  <!doctype html><html><head><meta charset="utf-8"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; script-src 'self'"><title>OpenZoo savings</title><style>
2
2
  *{box-sizing:border-box}body{max-height:100vh;overflow-y:auto;margin:0;padding:8px;background:transparent;font:13px system-ui;color:#fff}.pill{border-radius:20px;background:#18181bf5;border:1px solid #ffffff25;overflow:hidden;box-shadow:0 4px 14px #0004}header{background:#e85d1c;padding:12px 16px;font-weight:650;-webkit-app-region:drag;display:flex;justify-content:space-between;align-items:center}button{-webkit-app-region:no-drag;border:0;background:none;color:inherit;font:18px system-ui;cursor:pointer;padding:0 5px}main{padding:12px 16px}dl{display:grid;grid-template-columns:1fr auto;margin:0;gap:7px}dd{margin:0;font-variant-numeric:tabular-nums}small{color:#bbb;display:block;margin-top:12px;font-size:11px}#state{color:#d8ff76}.actions{display:flex;align-items:center;gap:8px}#deposit,.fund-button{font-size:12px;border:1px solid #ffffff60;border-radius:7px;padding:5px 10px}.fund-button{display:block;width:100%;text-align:left;margin:9px 0;overflow-wrap:anywhere;line-height:1.5}.fund-button span{display:block;font-size:11px;color:#ccc;user-select:text}[hidden]{display:none!important}#welcome p{font-size:12px;line-height:1.5;color:#ccc}#funding{border-top:1px solid #ffffff25;margin-top:12px}#funding p{font-size:12px;color:#ccc}
3
- </style></head><body><div class="pill"><header><span>OpenZoo · costs & savings</span><div class="actions"><button id="deposit">Deposit</button><button id="collapse" aria-label="Collapse savings" aria-expanded="true" title="Collapse">−</button><button id="close" aria-label="Close savings pill">×</button></div></header><main><section id="welcome" hidden><h3>Welcome to OpenZoo</h3><p>Pay per request from your OpenZoo wallet. Add funds before your first chat.</p><p>1. Choose card or crypto below.<br>2. Add funds to this wallet.<br>3. Once your balance appears, start chatting.</p></section><div id="totals"><dl><dt>Wallet balance</dt><dd id="wallet">—</dd><dt>Prepaid credit</dt><dd id="credit">—</dd><dt>Charged · verified calls</dt><dd id="spent">—</dd><dt>Direct cost · verified calls</dt><dd id="direct">—</dd><dt id="saving-label">Saved</dt><dd id="saved">—</dd></dl><small id="state" role="status">Checking your balance…</small><small>Savings cover matching verified calls only. Drag the orange bar to move.</small></div><section id="funding" hidden><h3>Add funds</h3><p id="fund-status" role="status">Loading your wallet…</p><button class="fund-button" id="copy-solana" disabled>Solana · USDC / KISS / LEOS<span id="solana-address"></span><span>Click to copy address</span></button><button class="fund-button" id="copy-evm" disabled>Base · USDC<span id="evm-address"></span><span>Click to copy address</span></button><button class="fund-button" id="card">Pay by card · Whop ↗</button><p>At checkout, paste your Solana address to link the purchase to this wallet. Your balance updates automatically after confirmation.</p><button class="fund-button" id="back">Back to savings</button><button class="fund-button" id="later" hidden>Set up later</button></section></main></div><script src="savings-renderer.js"></script></body></html>
3
+ </style></head><body><div class="pill"><header><span>OpenZoo · costs & savings</span><div class="actions"><button id="deposit">Deposit</button><button id="collapse" aria-label="Collapse savings" aria-expanded="true" title="Collapse">−</button><button id="close" aria-label="Close savings pill">×</button></div></header><main><section id="welcome" hidden><h3>Welcome to OpenZoo</h3><p>Pay per request from your OpenZoo wallet. Add funds before your first chat.</p><p>1. Choose card or crypto below.<br>2. Add funds to this wallet.<br>3. Once your balance appears, start chatting.</p></section><div id="totals"><dl><dt>Wallet balance</dt><dd id="wallet">—</dd><dt>Prepaid credit</dt><dd id="credit">—</dd><dt>Charged · verified calls</dt><dd id="spent">—</dd><dt>Direct cost · verified calls</dt><dd id="direct">—</dd><dt id="saving-label">Saved</dt><dd id="saved">—</dd></dl><small id="state" role="status">Checking your balance…</small><small>Savings cover matching verified calls only. Drag the orange bar to move.</small></div><section id="funding" hidden><h3>Add funds</h3><p id="fund-status" role="status">Loading your wallet…</p><button class="fund-button" id="copy-solana" disabled>Solana · USDC / KISS / LEOS / TOKEN<span id="solana-address"></span><span>Click to copy address</span></button><button class="fund-button" id="copy-evm" disabled>Base · USDC<span id="evm-address"></span><span>Click to copy address</span></button><button class="fund-button" id="card">Pay by card · Whop ↗</button><p>At checkout, paste your Solana address to link the purchase to this wallet. Your balance updates automatically after confirmation.</p><button class="fund-button" id="back">Back to savings</button><button class="fund-button" id="later" hidden>Set up later</button></section></main></div><script src="savings-renderer.js"></script></body></html>
package/lib/config.js CHANGED
@@ -32,7 +32,7 @@ export const config = {
32
32
  };
33
33
 
34
34
  /**
35
- * Assets a user can fund the burner wallet with. All three are first-class and
35
+ * Assets a user can fund the burner wallet with. All are first-class and
36
36
  * these are the EXACT mints the 402 quotes — fund one, spend it, no conversion
37
37
  * step. Never mention one of these without the others.
38
38
  */
@@ -43,10 +43,11 @@ export const FUNDING_ASSETS = [
43
43
  // balance reads must not assume either, so nothing here hardcodes them;
44
44
  // decimals come off the mint on chain.
45
45
  { symbol: 'LEOS', mint: '5xgsnby6P9zqGK71J7H4yJLxzqPvNbC7rDZxNzjHmj7e' },
46
+ { symbol: 'TOKEN', mint: 'EVULoNF4DeMBN4dGiZiDfpiiTfNZgoCvXWWgaV3epump' },
46
47
  ];
47
48
 
48
49
  export const USDC_MINT = FUNDING_ASSETS[0].mint;
49
- export const TOKEN_MINT = FUNDING_ASSETS[1].mint;
50
+ export const TOKEN_MINT = FUNDING_ASSETS.find(a => a.symbol === 'KISS').mint;
50
51
  export const LEOS_MINT = FUNDING_ASSETS[2].mint;
51
52
 
52
53
  /**
@@ -144,7 +145,7 @@ export function fundingLine(address) {
144
145
  * along with the twins, and the two are now the same asset on every rail.
145
146
  */
146
147
  export const RAIL_FUNDING = {
147
- solana: { label: 'Solana', assets: ['USDC', 'KISS', 'LEOS'] },
148
+ solana: { label: 'Solana', assets: ['USDC', 'KISS', 'LEOS', 'TOKEN'] },
148
149
  base: { label: 'Base', assets: ['USDC'] },
149
150
  robinhood: { label: 'Robinhood Chain', assets: ['USDG'] },
150
151
  arbitrum: { label: 'Arbitrum', assets: ['USDC'] },
package/lib/proxy.js CHANGED
@@ -111,10 +111,10 @@ print('\\n'.join(str(p) for p in pids if p != os.getpid()))
111
111
  return [...seen];
112
112
  }
113
113
 
114
- /** This package.json version. Same one /v1/info and /v1/session publish. */
115
- export function packageVersion() {
116
- return JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
117
- }
114
+ // Capture the loaded code version once. An npm update must not make an old
115
+ // running proxy advertise the newly installed version and evade restart.
116
+ const loadedVersion = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
117
+ export function packageVersion() { return loadedVersion; }
118
118
 
119
119
  /** True when the listener on this port is THIS openzoo version or newer.
120
120
  * Missing / unparseable version is stale (0.49.x answered with no version).
@@ -139,7 +139,7 @@ export async function oursOn(port = config.port) {
139
139
  const r = await fetch(`http://127.0.0.1:${Number(port)}${path}`, { signal: AbortSignal.timeout(1500) });
140
140
  if (!r.ok) continue;
141
141
  const j = await r.json().catch(() => ({}));
142
- if (attachable(j.version)) return true;
142
+ if (attachable(j.runtimeVersion)) return true;
143
143
  } catch { /* try next */ }
144
144
  }
145
145
  return false;
@@ -259,12 +259,14 @@ function jsonErr(res, status, message, extraFields = {}) {
259
259
  */
260
260
  async function snapshotBalances(client) {
261
261
  const out = [];
262
- try {
263
- const bals = await Promise.all(
264
- FUNDING_ASSETS.map((a) => tokenBalance(client.connection, client.keypair.publicKey, a.mint)),
265
- );
266
- FUNDING_ASSETS.forEach((a, i) => out.push({ symbol: a.symbol, ui: Number(bals[i].ui ?? 0), chain: 'solana' }));
267
- } catch { /* Solana RPC hiccup — EVM entries still report */ }
262
+ const bals = await Promise.allSettled(
263
+ FUNDING_ASSETS.map((a) => tokenBalance(client.connection, client.keypair.publicKey, a.mint)),
264
+ );
265
+ FUNDING_ASSETS.forEach((a, i) => {
266
+ if (bals[i].status === 'fulfilled') {
267
+ out.push({ symbol: a.symbol, ui: Number(bals[i].value.ui ?? 0), chain: 'solana' });
268
+ }
269
+ });
268
270
  const owner = client.evmAddress;
269
271
  if (owner) {
270
272
  await Promise.all(Object.entries(EVM_FUNDING_ASSETS).flatMap(([rail, assets]) => assets.map(async (a) => {
@@ -568,11 +570,9 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
568
570
  refreshPrices();
569
571
  const money = walletMoney();
570
572
  res.writeHead(200, { 'content-type': 'application/json' });
571
- const { version } = JSON.parse(
572
- readFileSync(new URL('../package.json', import.meta.url), 'utf8'),
573
- );
573
+ const version = packageVersion();
574
574
  res.end(JSON.stringify({
575
- version,
575
+ version, runtimeVersion: version,
576
576
  spentUsd: sessionSpent, cogsUsd: sessionCogs, directUsd: sessionDirect, paidCalls,
577
577
  creditUsd, chainUsd: money.chainUsd, lastQuoteUsd,
578
578
  }));
@@ -669,12 +669,11 @@ export async function startProxy({ silent = false, requireToken = null, sessionM
669
669
  'content-type': 'application/json',
670
670
  'access-control-allow-origin': '*',
671
671
  });
672
- const { version: ozVersion } = JSON.parse(
673
- readFileSync(new URL('../package.json', import.meta.url), 'utf8'),
674
- );
672
+ const ozVersion = packageVersion();
675
673
  res.end(JSON.stringify({
676
674
  youAreTalkingTo: 'openzoo proxy',
677
675
  version: ozVersion,
676
+ runtimeVersion: ozVersion,
678
677
  solana: client.address,
679
678
  evm: client.evmAddress,
680
679
  yourEndpoint: self,
@@ -101,8 +101,8 @@ export function whopFundBlurb(solana, evm) {
101
101
  'Funding options:',
102
102
  `Card: ${url}`,
103
103
  `At checkout, use this Solana wallet address to link your purchase: ${addr}`,
104
- `Solana deposit wallet (USDC / LEOS / KISS): ${addr}`,
105
- ...FUNDING_ASSETS.filter(a => ['LEOS', 'KISS'].includes(a.symbol)).map(a => `${a.symbol} mint (CA): ${a.mint}`),
104
+ `Solana deposit wallet (USDC / LEOS / KISS / TOKEN): ${addr}`,
105
+ ...FUNDING_ASSETS.filter(a => ['LEOS', 'KISS', 'TOKEN'].includes(a.symbol)).map(a => `${a.symbol} mint (CA): ${a.mint}`),
106
106
  'Send funds to your deposit wallet, not the mint address.',
107
107
  ...(base ? [`Base (USDC): ${base}`] : []),
108
108
  'Your balance refreshes automatically once the payment is confirmed.',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openzoo",
3
- "version": "0.51.20",
3
+ "version": "0.51.22",
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",