@genkaku/protocol 0.1.18 → 0.1.21
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/dist/bridge.d.ts +6 -9
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +47 -63
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/keys.d.ts +2 -0
- package/dist/keys.d.ts.map +1 -1
- package/dist/keys.js +11 -0
- package/dist/p2pNode.d.ts.map +1 -1
- package/dist/p2pNode.js +1 -0
- package/dist/paywall.d.ts +6 -0
- package/dist/paywall.d.ts.map +1 -1
- package/dist/paywall.js +6 -3
- package/dist/status.d.ts +21 -1
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +25 -2
- package/dist/walletControl.d.ts +17 -0
- package/dist/walletControl.d.ts.map +1 -0
- package/dist/walletControl.js +63 -0
- package/package.json +1 -1
package/dist/bridge.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Libp2p } from 'libp2p';
|
|
2
|
+
import { type WalletControl } from './walletControl.ts';
|
|
2
3
|
import type { Hex } from 'viem';
|
|
3
4
|
import type { ModeManager, RoleMode } from './modeManager.ts';
|
|
4
5
|
import type { NetEnvironment } from './netconfig.ts';
|
|
@@ -38,16 +39,12 @@ export type BridgeOptions = {
|
|
|
38
39
|
workers?: string[];
|
|
39
40
|
settle?: boolean;
|
|
40
41
|
}) => void | Promise<void>;
|
|
42
|
+
/** Re-run discovery. The worker set is read at startup, so the host restarts
|
|
43
|
+
* its half; this callback returns before that happens (the reply must land). */
|
|
44
|
+
onRefresh?: () => void | Promise<void>;
|
|
41
45
|
/** Wallet operations the panel drives. Key material only ever leaves over
|
|
42
|
-
*
|
|
43
|
-
wallet?:
|
|
44
|
-
address: () => string;
|
|
45
|
-
exportKey: () => string;
|
|
46
|
-
importKey: (privateKey: string) => void;
|
|
47
|
-
rotate: () => void;
|
|
48
|
-
/** testnet only; mints MockUSDC to the current user wallet */
|
|
49
|
-
mint?: (amount: bigint) => Promise<string>;
|
|
50
|
-
};
|
|
46
|
+
* the panel CORS gate, and only after an explicit confirmation flag. */
|
|
47
|
+
wallet?: WalletControl;
|
|
51
48
|
/** P4.9h: derived credit per worker wallet (escrow events, not self-report).
|
|
52
49
|
* Absent = offers keep whatever the worker claimed. */
|
|
53
50
|
credit?: (wallets: string[]) => Map<string, {
|
package/dist/bridge.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAGpC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAc/B,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,EAAgB,MAAM,EAAc,MAAM,YAAY,CAAA;AAI7D,uEAAuE;AACvE,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAA;KAAE,CAAC,CAAA;IACjE,GAAG,EAAE,MAAM,CAAA;IACX,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAA;CAChD,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,cAAc,CAAA;IACnB,WAAW,EAAE,WAAW,CAAA;IACxB,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;IAC9B,OAAO,EAAE,MAAM,GAAG,CAAA;IAClB,yEAAyE;IACzE,MAAM,EAAE,OAAO,CAAA;IACf,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3B,wFAAwF;IACxF,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACnC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAC3F,wDAAwD;IACxD,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjD;gFAC4E;IAC5E,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACtF;
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAGpC,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAc/B,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,EAAgB,MAAM,EAAc,MAAM,YAAY,CAAA;AAI7D,uEAAuE;AACvE,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,UAAU,CAAC,OAAO,MAAM,CAAC,CAAA;KAAE,CAAC,CAAA;IACjE,GAAG,EAAE,MAAM,CAAA;IACX,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAA;CAChD,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,EAAE,cAAc,CAAA;IACnB,WAAW,EAAE,WAAW,CAAA;IACxB,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;IAC9B,OAAO,EAAE,MAAM,GAAG,CAAA;IAClB,yEAAyE;IACzE,MAAM,EAAE,OAAO,CAAA;IACf,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3B,wFAAwF;IACxF,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACnC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAC3F,wDAAwD;IACxD,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjD;gFAC4E;IAC5E,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACtF;qFACiF;IACjF,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACtC;6EACyE;IACzE,MAAM,CAAC,EAAE,aAAa,CAAA;IACtB;4DACwD;IACxD,MAAM,CAAC,EAAE,CACP,OAAO,EAAE,MAAM,EAAE,KACd,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;CAClH,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B,CAAA;AAuJD,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAsmBlF"}
|
package/dist/bridge.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { appendFileSync } from 'node:fs';
|
|
6
6
|
import { createServer } from 'node:http';
|
|
7
7
|
import { applyPanelCors } from "./cors.js";
|
|
8
|
+
import { runWalletAction } from "./walletControl.js";
|
|
8
9
|
import { openEscrow, publicClientFor, readWorker, refundSession, settleSession, signReceiptPayload, walletAddress, walletClientFor, } from "./chain.js";
|
|
9
10
|
import { dialWorkerAny, fetchOffers, requestSettleCosign } from "./dial.js";
|
|
10
11
|
import { dedupeOffers, toWire } from "./offer.js";
|
|
@@ -153,14 +154,31 @@ export async function startOpenAiBridge(opts) {
|
|
|
153
154
|
return offers;
|
|
154
155
|
}
|
|
155
156
|
async function board() {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
157
|
+
// One dial per PEER, not per address. The chain directory and the seed can
|
|
158
|
+
// both list the same worker (a LAN address plus a relay circuit), and
|
|
159
|
+
// dialing those in parallel makes libp2p race itself — both attempts then
|
|
160
|
+
// time out. Try the peer's addresses in order, direct first, and stop at
|
|
161
|
+
// the first board that answers.
|
|
162
|
+
const peers = new Map();
|
|
163
|
+
for (const addr of opts.workers) {
|
|
164
|
+
const key = peerIdOf(addr) ?? addr;
|
|
165
|
+
const list = peers.get(key);
|
|
166
|
+
if (list == null)
|
|
167
|
+
peers.set(key, [addr]);
|
|
168
|
+
else if (!list.includes(addr))
|
|
169
|
+
list.push(addr);
|
|
170
|
+
}
|
|
171
|
+
const rows = await Promise.all([...peers.values()].map(async (addrs) => {
|
|
172
|
+
const ordered = [...addrs].sort((a, b) => Number(a.includes('/p2p-circuit')) - Number(b.includes('/p2p-circuit')));
|
|
173
|
+
for (const addr of ordered) {
|
|
174
|
+
try {
|
|
175
|
+
return (await offersOf(addr)).map(offer => ({ addr, offer }));
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
opts.log(`offers: ${addr} unreachable (${error instanceof Error ? error.message : String(error)})`);
|
|
179
|
+
}
|
|
163
180
|
}
|
|
181
|
+
return [];
|
|
164
182
|
}));
|
|
165
183
|
return dedupeOffers(rows.flat());
|
|
166
184
|
}
|
|
@@ -339,7 +357,13 @@ export async function startOpenAiBridge(opts) {
|
|
|
339
357
|
: 1024, MAX_COMPLETION_TOKENS);
|
|
340
358
|
let escrowId = '0';
|
|
341
359
|
let walletC = null;
|
|
342
|
-
|
|
360
|
+
// A zero quote is free by the operator's own listing. Opening an escrow of
|
|
361
|
+
// 0 reverts on-chain, and the worker's paywall accepts an unpriced session
|
|
362
|
+
// for exactly these models, so skip the chain entirely.
|
|
363
|
+
if (picked.offer.pricePerHour === 0n) {
|
|
364
|
+
opts.log(`session ${jobId}: ${picked.offer.model} is free — no escrow`);
|
|
365
|
+
}
|
|
366
|
+
else if (opts.settle && picked.offer.workerWallet?.startsWith('0x')) {
|
|
343
367
|
walletC = walletClientFor(opts.env, opts.userKey());
|
|
344
368
|
const opened = await openEscrow(publicClientFor(opts.env), walletC, opts.env, picked.offer.workerWallet, picked.offer.pricePerHour);
|
|
345
369
|
escrowId = opened.escrowId.toString();
|
|
@@ -579,60 +603,10 @@ export async function startOpenAiBridge(opts) {
|
|
|
579
603
|
failure(res, 400, 'invalid JSON body');
|
|
580
604
|
return;
|
|
581
605
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
// stray click (or a scripted call without intent) cannot read it.
|
|
585
|
-
if (body.confirm !== true) {
|
|
586
|
-
failure(res, 400, 'export requires confirm: true');
|
|
587
|
-
return;
|
|
588
|
-
}
|
|
606
|
+
const reply = await runWalletAction(action, body, opts.wallet);
|
|
607
|
+
if (reply.status === 200 && action === 'export')
|
|
589
608
|
res.setHeader('cache-control', 'no-store');
|
|
590
|
-
|
|
591
|
-
return;
|
|
592
|
-
}
|
|
593
|
-
if (action === 'import') {
|
|
594
|
-
const key = typeof body.privateKey === 'string' ? body.privateKey.trim() : '';
|
|
595
|
-
if (key === '') {
|
|
596
|
-
failure(res, 400, 'privateKey is required');
|
|
597
|
-
return;
|
|
598
|
-
}
|
|
599
|
-
try {
|
|
600
|
-
opts.wallet.importKey(key);
|
|
601
|
-
}
|
|
602
|
-
catch (error) {
|
|
603
|
-
failure(res, 400, error instanceof Error ? error.message : String(error));
|
|
604
|
-
return;
|
|
605
|
-
}
|
|
606
|
-
json(res, 200, { ok: true, address: opts.wallet.address(), restarting: true });
|
|
607
|
-
return;
|
|
608
|
-
}
|
|
609
|
-
if (action === 'new') {
|
|
610
|
-
opts.wallet.rotate();
|
|
611
|
-
json(res, 200, { ok: true, address: opts.wallet.address(), restarting: true });
|
|
612
|
-
return;
|
|
613
|
-
}
|
|
614
|
-
if (action === 'mint') {
|
|
615
|
-
if (opts.wallet.mint == null) {
|
|
616
|
-
failure(res, 400, 'test USDC mint is only available on base-sepolia');
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
const raw = body.amountUsdc === undefined ? '100' : String(body.amountUsdc);
|
|
620
|
-
const amount = Math.round(Number(raw) * 1e6);
|
|
621
|
-
if (!Number.isFinite(amount) || amount <= 0 || amount > 10_000e6) {
|
|
622
|
-
failure(res, 400, 'amountUsdc must be between 0 and 10000');
|
|
623
|
-
return;
|
|
624
|
-
}
|
|
625
|
-
try {
|
|
626
|
-
const tx = await opts.wallet.mint(BigInt(amount));
|
|
627
|
-
json(res, 200, { ok: true, tx, amountUsdc: Number(raw) });
|
|
628
|
-
}
|
|
629
|
-
catch (error) {
|
|
630
|
-
failure(res, 500, error instanceof Error ? error.message : String(error));
|
|
631
|
-
}
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
failure(res, 404, 'unknown wallet action');
|
|
635
|
-
return;
|
|
609
|
+
json(res, reply.status, reply.doc);
|
|
636
610
|
}
|
|
637
611
|
if (req.method === 'POST' && (path === '/genkaku/settings' || path === '/genkaku/settings/')) {
|
|
638
612
|
let body;
|
|
@@ -644,9 +618,19 @@ export async function startOpenAiBridge(opts) {
|
|
|
644
618
|
return;
|
|
645
619
|
}
|
|
646
620
|
if (body.refresh === true) {
|
|
647
|
-
// Drop the 10s offer cache
|
|
648
|
-
//
|
|
621
|
+
// Drop the 10s offer cache, then ask the host to re-read the chain
|
|
622
|
+
// directory and the seed. Clearing the cache alone only re-dialed
|
|
623
|
+
// the workers we already knew about.
|
|
649
624
|
cache.clear();
|
|
625
|
+
transports.clear();
|
|
626
|
+
if (opts.onRefresh != null) {
|
|
627
|
+
try {
|
|
628
|
+
await opts.onRefresh();
|
|
629
|
+
}
|
|
630
|
+
catch (error) {
|
|
631
|
+
opts.log(`refresh: restart refused (${error instanceof Error ? error.message : String(error)})`);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
650
634
|
}
|
|
651
635
|
const patch = {};
|
|
652
636
|
if (body.workers !== undefined) {
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,SAAS,CAAA;AACvB,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,aAAa,CAAA;AAC3B,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,YAAY,CAAA;AAC1B,cAAc,WAAW,CAAA;AACzB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,SAAS,CAAA;AACvB,cAAc,kBAAkB,CAAA;AAChC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,YAAY,CAAA;AAC1B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,eAAe,CAAA;AAC7B,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA"}
|
package/dist/index.js
CHANGED
package/dist/keys.d.ts
CHANGED
|
@@ -14,6 +14,8 @@ export type KeyVault = {
|
|
|
14
14
|
workerKey(): PrivKey;
|
|
15
15
|
/** replace the user key (import / rotate); refuses while an env key wins */
|
|
16
16
|
setUserKey(key: PrivKey): void;
|
|
17
|
+
/** replace the worker identity key (import / rotate); same env guard */
|
|
18
|
+
setWorkerKey(key: PrivKey): void;
|
|
17
19
|
/** derived addresses only (renderer-safe mirror of the keys) */
|
|
18
20
|
addresses(): {
|
|
19
21
|
user: EthAddress;
|
package/dist/keys.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAG/B,MAAM,MAAM,OAAO,GAAG,GAAG,CAAA;AACzB,MAAM,MAAM,UAAU,GAAG,KAAK,MAAM,EAAE,CAAA;AAEtC;gFACgF;AAChF,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAC9B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;CAC9B,CAAA;AASD,MAAM,MAAM,QAAQ,GAAG;IACrB,2DAA2D;IAC3D,OAAO,IAAI,OAAO,CAAA;IAClB,6DAA6D;IAC7D,SAAS,IAAI,OAAO,CAAA;IACpB,4EAA4E;IAC5E,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAA;IAC9B,gEAAgE;IAChE,SAAS,IAAI;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,CAAA;IACrD,qEAAqE;IACrE,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAA;CACpC,CAAA;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,0EAA0E;IAC1E,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,QAAQ,CAAA;CACjB,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAG/B,MAAM,MAAM,OAAO,GAAG,GAAG,CAAA;AACzB,MAAM,MAAM,UAAU,GAAG,KAAK,MAAM,EAAE,CAAA;AAEtC;gFACgF;AAChF,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IAC9B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;CAC9B,CAAA;AASD,MAAM,MAAM,QAAQ,GAAG;IACrB,2DAA2D;IAC3D,OAAO,IAAI,OAAO,CAAA;IAClB,6DAA6D;IAC7D,SAAS,IAAI,OAAO,CAAA;IACpB,4EAA4E;IAC5E,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAA;IAC9B,wEAAwE;IACxE,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAA;IAChC,gEAAgE;IAChE,SAAS,IAAI;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,CAAA;IACrD,qEAAqE;IACrE,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAA;CACpC,CAAA;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE;IACnC,0EAA0E;IAC1E,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,QAAQ,CAAA;CACjB,GAAG,QAAQ,CAmIX;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAQnD"}
|
package/dist/keys.js
CHANGED
|
@@ -108,6 +108,17 @@ export function createKeyVault(opts) {
|
|
|
108
108
|
vault.userKeyEnc = codec.encrypt(next).toString('base64');
|
|
109
109
|
persist();
|
|
110
110
|
},
|
|
111
|
+
setWorkerKey(key) {
|
|
112
|
+
// Same reasoning as setUserKey: an env key is process-scoped, so claiming
|
|
113
|
+
// a successful replacement while the old identity stays live would lie.
|
|
114
|
+
if (envWorker != null) {
|
|
115
|
+
throw new Error('the worker key comes from GENKAKU_WORKER_KEY; unset it before importing or rotating');
|
|
116
|
+
}
|
|
117
|
+
const next = normalizeKey(key);
|
|
118
|
+
workerKey = next;
|
|
119
|
+
vault.workerKeyEnc = codec.encrypt(next).toString('base64');
|
|
120
|
+
persist();
|
|
121
|
+
},
|
|
111
122
|
get usingEnvOverrides() {
|
|
112
123
|
return envUser != null || envWorker != null;
|
|
113
124
|
},
|
package/dist/p2pNode.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"p2pNode.d.ts","sourceRoot":"","sources":["../src/p2pNode.ts"],"names":[],"mappings":"AAcA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAA;AAClD,OAAO,EAAE,KAAK,GAAG,EAAW,MAAM,MAAM,CAAA;AAIxC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAE5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAGnD,OAAO,EAAoB,KAAK,KAAK,EAAU,MAAM,YAAY,CAAA;AAajE,OAAO,KAAK,EAAgB,YAAY,EAAiB,MAAM,oBAAoB,CAAA;AAGnF,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACzD,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC,eAAO,MAAM,iBAAiB,2JAQpB,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG;IAC3B,WAAW,EAAE,WAAW,CAAA;IACxB,MAAM,EAAE,qBAAqB,CAAA;IAC7B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,2EAA2E;IAC3E,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,+EAA+E;IAC/E,OAAO,EAAE,KAAK,EAAE,CAAA;IAChB,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,CAAA;IACzC,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;kFAC8E;IAC9E,SAAS,CAAC,EAAE,GAAG,CAAA;IACf;6EACyE;IACzE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,0DAA0D;IAC1D,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7B,CAAA;AAED;0EAC0E,CAAA,MAAM,MAAM,aAAa,GAAG;IACpG,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAA;IAChB,kEAAkE;IAClE,SAAS,EAAE,KAAK,MAAM,EAAE,CAAA;IACxB,UAAU,EAAE,KAAK,MAAM,EAAE,CAAA;CAC1B,CAAA;AAkBD,+EAA+E;AAC/E,wBAAsB,cAAc,CAAC,MAAM,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAY3E;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,MAAM,EAAE,CAAA;IACzB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACrB,cAAc,EAAE,MAAM,MAAM,CAAA;IAC5B,+DAA+D;IAC/D,SAAS,EAAE,MAAM,MAAM,CAAA;IACvB,qEAAqE;IACrE,UAAU,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,CAAA;CACtC,CAAA;AAOD,wBAAsB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,
|
|
1
|
+
{"version":3,"file":"p2pNode.d.ts","sourceRoot":"","sources":["../src/p2pNode.ts"],"names":[],"mappings":"AAcA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAA;AAClD,OAAO,EAAE,KAAK,GAAG,EAAW,MAAM,MAAM,CAAA;AAIxC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAE5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAGnD,OAAO,EAAoB,KAAK,KAAK,EAAU,MAAM,YAAY,CAAA;AAajE,OAAO,KAAK,EAAgB,YAAY,EAAiB,MAAM,oBAAoB,CAAA;AAGnF,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AACzD,YAAY,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC,eAAO,MAAM,iBAAiB,2JAQpB,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG;IAC3B,WAAW,EAAE,WAAW,CAAA;IACxB,MAAM,EAAE,qBAAqB,CAAA;IAC7B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,eAAe,CAAA;IAC5B,2EAA2E;IAC3E,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,+EAA+E;IAC/E,OAAO,EAAE,KAAK,EAAE,CAAA;IAChB,aAAa,CAAC,EAAE,CAAC,CAAC,EAAE,YAAY,KAAK,IAAI,CAAA;IACzC,gFAAgF;IAChF,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB;kFAC8E;IAC9E,SAAS,CAAC,EAAE,GAAG,CAAA;IACf;6EACyE;IACzE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB,0DAA0D;IAC1D,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7B,CAAA;AAED;0EAC0E,CAAA,MAAM,MAAM,aAAa,GAAG;IACpG,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAA;IAChB,kEAAkE;IAClE,SAAS,EAAE,KAAK,MAAM,EAAE,CAAA;IACxB,UAAU,EAAE,KAAK,MAAM,EAAE,CAAA;CAC1B,CAAA;AAkBD,+EAA+E;AAC/E,wBAAsB,cAAc,CAAC,MAAM,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAY3E;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,MAAM,EAAE,CAAA;IACzB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACrB,cAAc,EAAE,MAAM,MAAM,CAAA;IAC5B,+DAA+D;IAC/D,SAAS,EAAE,MAAM,MAAM,CAAA;IACvB,qEAAqE;IACrE,UAAU,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,CAAA;CACtC,CAAA;AAOD,wBAAsB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CA+gBjF"}
|
package/dist/p2pNode.js
CHANGED
|
@@ -167,6 +167,7 @@ export async function createSidecar(opts) {
|
|
|
167
167
|
jobId: env.jobId,
|
|
168
168
|
escrowId: env.escrowId || '0',
|
|
169
169
|
clientPeer: env.clientPeer ?? '',
|
|
170
|
+
model: env.model,
|
|
170
171
|
}).catch(() => ({ ok: false, code: 'paywall-error', reason: 'paywall check failed' }));
|
|
171
172
|
if (!verdict.ok) {
|
|
172
173
|
opts.sessionEvents?.({
|
package/dist/paywall.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export type PaywallRequest = {
|
|
|
4
4
|
jobId: string;
|
|
5
5
|
escrowId: string;
|
|
6
6
|
clientPeer: string;
|
|
7
|
+
/** the model in the OPEN envelope; decides whether "unpriced" is free */
|
|
8
|
+
model: string;
|
|
7
9
|
};
|
|
8
10
|
export type PaywallVerdict = {
|
|
9
11
|
ok: true; /** the escrow's payer — receipts must be signed by this wallet */
|
|
@@ -21,6 +23,10 @@ export type PaywallOptions = {
|
|
|
21
23
|
worker: `0x${string}`;
|
|
22
24
|
/** dev escape hatch: allow `escrowId: "0"` (unpriced) sessions */
|
|
23
25
|
allowUnpriced?: boolean;
|
|
26
|
+
/** the operator's current quote per model (micro-USDC/hour). An unpriced
|
|
27
|
+
* session is authorized only for a model quoted at exactly zero — a priced
|
|
28
|
+
* model must still present real escrow, so naming "0" cannot skip payment. */
|
|
29
|
+
prices?: (model: string) => bigint | undefined;
|
|
24
30
|
now?: () => number;
|
|
25
31
|
log?: {
|
|
26
32
|
warn: (msg: string, ...args: unknown[]) => void;
|
package/dist/paywall.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paywall.d.ts","sourceRoot":"","sources":["../src/paywall.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAqB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"paywall.d.ts","sourceRoot":"","sources":["../src/paywall.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAqB,KAAK,aAAa,EAAE,MAAM,YAAY,CAAA;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC,CAAC,kEAAkE;IAAC,KAAK,EAAE,KAAK,MAAM,EAAE,CAAA;CAAE,GACrG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAE/C,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,cAAc,CAAC,CAAA;AAK1E,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,aAAa,CAAA;IACtB,GAAG,EAAE,cAAc,CAAA;IACnB,iDAAiD;IACjD,MAAM,EAAE,KAAK,MAAM,EAAE,CAAA;IACrB,kEAAkE;IAClE,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;mFAE+E;IAC/E,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAA;IAC9C,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAClB,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAA;CAC1D,CAAA;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAgD3D"}
|
package/dist/paywall.js
CHANGED
|
@@ -28,9 +28,12 @@ export function createPaywall(opts) {
|
|
|
28
28
|
return async (request) => {
|
|
29
29
|
const raw = (request.escrowId ?? '').trim();
|
|
30
30
|
if (raw === '' || raw === '0') {
|
|
31
|
-
// Unpriced sessions have no payer to certify
|
|
32
|
-
//
|
|
33
|
-
|
|
31
|
+
// Unpriced sessions have no payer to certify. Two ways in: the operator
|
|
32
|
+
// disabled the paywall outright (dev), or this model's own quote is 0 —
|
|
33
|
+
// a free listing cannot open a 0-value escrow because the contract
|
|
34
|
+
// reverts, so free has to mean "no escrow".
|
|
35
|
+
const price = request.model === '' ? undefined : opts.prices?.(request.model);
|
|
36
|
+
return opts.allowUnpriced === true || price === 0n
|
|
34
37
|
? { ok: true, payer: ZERO }
|
|
35
38
|
: { ok: false, code: 'payment-required', reason: 'unpriced session rejected: open an escrow first' };
|
|
36
39
|
}
|
package/dist/status.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type WalletControl } from './walletControl.ts';
|
|
1
2
|
import type { RoleMode } from './modeManager.ts';
|
|
2
3
|
import type { OfferWire } from './offer.ts';
|
|
3
4
|
/** One offer row rendered by the dashboard. */
|
|
@@ -26,6 +27,11 @@ export type StatusSnapshot = {
|
|
|
26
27
|
transport?: 'direct' | 'relay' | 'lan';
|
|
27
28
|
/** Relay hops this worker reserved (seed VM), for the panel to explain relay mode. */
|
|
28
29
|
relayHints?: string[];
|
|
30
|
+
/** Live wallet figures, base units as decimal strings (wei / 6-dec USDC). */
|
|
31
|
+
balances?: {
|
|
32
|
+
eth: string;
|
|
33
|
+
usdc: string;
|
|
34
|
+
};
|
|
29
35
|
};
|
|
30
36
|
export type StatusHandle = {
|
|
31
37
|
url: string;
|
|
@@ -60,5 +66,19 @@ export type OllamaControl = {
|
|
|
60
66
|
remove: (model: string) => Promise<void>;
|
|
61
67
|
};
|
|
62
68
|
/** Serve the dashboard and live status JSON on 127.0.0.1. */
|
|
63
|
-
|
|
69
|
+
/** Everything the worker dashboard can drive. Named fields rather than a long
|
|
70
|
+
* positional list: the wallet joined five other callbacks, and a positional
|
|
71
|
+
* boolean trade at the end is how panels end up wiring the wrong handler. */
|
|
72
|
+
export type StatusServerOptions = {
|
|
73
|
+
port: number;
|
|
74
|
+
snapshot: () => StatusSnapshot | Promise<StatusSnapshot>;
|
|
75
|
+
onCatalog?: CatalogUpdateHandler;
|
|
76
|
+
onMode?: ModeUpdateHandler;
|
|
77
|
+
ollama?: OllamaControl;
|
|
78
|
+
onPublish?: PublishUpdateHandler;
|
|
79
|
+
/** Worker identity wallet: export/import/rotate. No mint — a worker earns
|
|
80
|
+
* USDC and only ever needs gas, which it cannot buy from a faucet button. */
|
|
81
|
+
wallet?: WalletControl;
|
|
82
|
+
};
|
|
83
|
+
export declare function startStatusServer(opts: StatusServerOptions): Promise<StatusHandle>;
|
|
64
84
|
//# sourceMappingURL=status.d.ts.map
|
package/dist/status.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C,+CAA+C;AAC/C,MAAM,MAAM,WAAW,GAAG;IACxB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,SAAS,CAAA;CACjB,CAAA;AAED,0EAA0E;AAC1E,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,4EAA4E;IAC5E,SAAS,EAAE,OAAO,CAAA;IAClB,2EAA2E;IAC3E,cAAc,EAAE,OAAO,CAAA;IACvB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,oFAAoF;IACpF,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,iFAAiF;IACjF,SAAS,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,KAAK,CAAA;IACtC,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"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"}
|
package/dist/status.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// the JSON always reflect the live sidecar, never a boot-time copy.
|
|
4
4
|
import { createServer } from 'node:http';
|
|
5
5
|
import { applyPanelCors } from "./cors.js";
|
|
6
|
+
import { runWalletAction } from "./walletControl.js";
|
|
6
7
|
/** Self-contained dashboard; mirrors the user bridge style and polls the JSON. */
|
|
7
8
|
const DASHBOARD_HTML = `<!doctype html>
|
|
8
9
|
<html lang="en">
|
|
@@ -165,8 +166,8 @@ function parseCatalog(body) {
|
|
|
165
166
|
}
|
|
166
167
|
return { ok: true, catalog };
|
|
167
168
|
}
|
|
168
|
-
|
|
169
|
-
|
|
169
|
+
export async function startStatusServer(opts) {
|
|
170
|
+
const { port, snapshot, onCatalog, onMode, ollama, onPublish, wallet } = opts;
|
|
170
171
|
const server = createServer((req, res) => {
|
|
171
172
|
void (async () => {
|
|
172
173
|
try {
|
|
@@ -246,6 +247,28 @@ export async function startStatusServer(port, snapshot, onCatalog, onMode, ollam
|
|
|
246
247
|
json(res, { ok: true });
|
|
247
248
|
return;
|
|
248
249
|
}
|
|
250
|
+
if (req.method === 'POST' && path.startsWith('/genkaku/wallet/')) {
|
|
251
|
+
const action = path.slice('/genkaku/wallet/'.length).replace(/\/$/, '');
|
|
252
|
+
if (wallet == null) {
|
|
253
|
+
failure(res, 501, 'wallet operations are not enabled in this role');
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
let body = {};
|
|
257
|
+
try {
|
|
258
|
+
body = await readJson(req);
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
failure(res, 400, 'invalid JSON body');
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const reply = await runWalletAction(action, body, wallet);
|
|
265
|
+
res.writeHead(reply.status, {
|
|
266
|
+
'content-type': 'application/json',
|
|
267
|
+
...(action === 'export' ? { 'cache-control': 'no-store' } : {}),
|
|
268
|
+
});
|
|
269
|
+
res.end(JSON.stringify(reply.doc));
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
249
272
|
if (path === '/genkaku/ollama' || path === '/genkaku/ollama/') {
|
|
250
273
|
if (ollama == null) {
|
|
251
274
|
failure(res, 501, 'ollama onboarding is not enabled in this role');
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Wallet operations a control plane may offer. */
|
|
2
|
+
export type WalletControl = {
|
|
3
|
+
address: () => string;
|
|
4
|
+
exportKey: () => string;
|
|
5
|
+
importKey: (privateKey: string) => void | Promise<void>;
|
|
6
|
+
rotate: () => void | Promise<void>;
|
|
7
|
+
/** base-sepolia only; mints MockUSDC to the panel's own address */
|
|
8
|
+
mint?: (amount: bigint) => Promise<string>;
|
|
9
|
+
};
|
|
10
|
+
/** One action's HTTP answer: status code plus JSON body. */
|
|
11
|
+
export type WalletActionReply = {
|
|
12
|
+
status: number;
|
|
13
|
+
doc: Record<string, unknown>;
|
|
14
|
+
};
|
|
15
|
+
/** Validate and run one `/genkaku/wallet/<action>` call. */
|
|
16
|
+
export declare function runWalletAction(action: string, body: Record<string, unknown>, wallet: WalletControl): Promise<WalletActionReply>;
|
|
17
|
+
//# sourceMappingURL=walletControl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walletControl.d.ts","sourceRoot":"","sources":["../src/walletControl.ts"],"names":[],"mappings":"AAYA,mDAAmD;AACnD,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,EAAE,MAAM,MAAM,CAAA;IACrB,SAAS,EAAE,MAAM,MAAM,CAAA;IACvB,SAAS,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACvD,MAAM,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAClC,mEAAmE;IACnE,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CAC3C,CAAA;AAED,4DAA4D;AAC5D,MAAM,MAAM,iBAAiB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAA;AAEhF,4DAA4D;AAC5D,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAwD5B"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// GENKAKU: wallet operations shared by both control planes.
|
|
2
|
+
//
|
|
3
|
+
// The user bridge and the worker status server expose the same four actions —
|
|
4
|
+
// export, import, new, mint — against different keys: the buyer's key signs
|
|
5
|
+
// escrows, the worker's key signs receipts and binds the directory entry. The
|
|
6
|
+
// HTTP shape and the safeguards are identical, so they live here instead of
|
|
7
|
+
// being copied into two request handlers that can drift apart.
|
|
8
|
+
//
|
|
9
|
+
// Key material only ever leaves over the panel CORS gate (see cors.ts), and
|
|
10
|
+
// export additionally requires `confirm: true` so a stray click — or a script
|
|
11
|
+
// that reached the port without intent — cannot read it.
|
|
12
|
+
/** Validate and run one `/genkaku/wallet/<action>` call. */
|
|
13
|
+
export async function runWalletAction(action, body, wallet) {
|
|
14
|
+
if (action === 'export') {
|
|
15
|
+
// The key IS the wallet: require an explicit acknowledgement.
|
|
16
|
+
if (body.confirm !== true)
|
|
17
|
+
return { status: 400, doc: { error: { message: 'export requires confirm: true' } } };
|
|
18
|
+
return {
|
|
19
|
+
status: 200,
|
|
20
|
+
doc: { ok: true, address: wallet.address(), privateKey: wallet.exportKey() },
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
if (action === 'import') {
|
|
24
|
+
const key = typeof body.privateKey === 'string' ? body.privateKey.trim() : '';
|
|
25
|
+
if (key === '')
|
|
26
|
+
return { status: 400, doc: { error: { message: 'privateKey is required' } } };
|
|
27
|
+
try {
|
|
28
|
+
await wallet.importKey(key);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
return { status: 400, doc: { error: { message: error instanceof Error ? error.message : String(error) } } };
|
|
32
|
+
}
|
|
33
|
+
return { status: 200, doc: { ok: true, address: wallet.address(), restarting: true } };
|
|
34
|
+
}
|
|
35
|
+
if (action === 'new') {
|
|
36
|
+
try {
|
|
37
|
+
await wallet.rotate();
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
return { status: 500, doc: { error: { message: error instanceof Error ? error.message : String(error) } } };
|
|
41
|
+
}
|
|
42
|
+
return { status: 200, doc: { ok: true, address: wallet.address(), restarting: true } };
|
|
43
|
+
}
|
|
44
|
+
if (action === 'mint') {
|
|
45
|
+
if (wallet.mint == null) {
|
|
46
|
+
return { status: 400, doc: { error: { message: 'test USDC mint is only available on base-sepolia' } } };
|
|
47
|
+
}
|
|
48
|
+
const raw = body.amountUsdc === undefined ? '100' : String(body.amountUsdc);
|
|
49
|
+
const amount = Math.round(Number(raw) * 1e6);
|
|
50
|
+
if (!Number.isFinite(amount) || amount <= 0 || amount > 10_000e6) {
|
|
51
|
+
return { status: 400, doc: { error: { message: 'amountUsdc must be between 0 and 10000' } } };
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const tx = await wallet.mint(BigInt(amount));
|
|
55
|
+
return { status: 200, doc: { ok: true, tx, amountUsdc: Number(raw) } };
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
return { status: 500, doc: { error: { message: error instanceof Error ? error.message : String(error) } } };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { status: 404, doc: { error: { message: 'unknown wallet action' } } };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=walletControl.js.map
|
package/package.json
CHANGED