@genkaku/protocol 0.1.19 → 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 CHANGED
@@ -39,6 +39,9 @@ export type BridgeOptions = {
39
39
  workers?: string[];
40
40
  settle?: boolean;
41
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>;
42
45
  /** Wallet operations the panel drives. Key material only ever leaves over
43
46
  * the panel CORS gate, and only after an explicit confirmation flag. */
44
47
  wallet?: WalletControl;
@@ -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,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;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,CAskBlF"}
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
@@ -154,14 +154,31 @@ export async function startOpenAiBridge(opts) {
154
154
  return offers;
155
155
  }
156
156
  async function board() {
157
- const rows = await Promise.all(opts.workers.map(async (addr) => {
158
- try {
159
- return (await offersOf(addr)).map(offer => ({ addr, offer }));
160
- }
161
- catch (error) {
162
- opts.log(`offers: ${addr} unreachable (${error instanceof Error ? error.message : String(error)})`);
163
- return [];
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
+ }
164
180
  }
181
+ return [];
165
182
  }));
166
183
  return dedupeOffers(rows.flat());
167
184
  }
@@ -340,7 +357,13 @@ export async function startOpenAiBridge(opts) {
340
357
  : 1024, MAX_COMPLETION_TOKENS);
341
358
  let escrowId = '0';
342
359
  let walletC = null;
343
- if (opts.settle && picked.offer.workerWallet?.startsWith('0x')) {
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')) {
344
367
  walletC = walletClientFor(opts.env, opts.userKey());
345
368
  const opened = await openEscrow(publicClientFor(opts.env), walletC, opts.env, picked.offer.workerWallet, picked.offer.pricePerHour);
346
369
  escrowId = opened.escrowId.toString();
@@ -595,9 +618,19 @@ export async function startOpenAiBridge(opts) {
595
618
  return;
596
619
  }
597
620
  if (body.refresh === true) {
598
- // Drop the 10s offer cache so the next status/model read re-dials
599
- // every discovered worker right now.
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.
600
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
+ }
601
634
  }
602
635
  const patch = {};
603
636
  if (body.workers !== undefined) {
@@ -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,CA8gBjF"}
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;
@@ -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;CACnB,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,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,CA4C3D"}
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; the dev escape hatch keeps
32
- // them working for an explicit opt-out only.
33
- return opts.allowUnpriced === true
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genkaku/protocol",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "description": "GenKaKu protocol core: on-chain worker directory, USDC escrow billing, libp2p transport, Ollama lifecycle",
5
5
  "license": "MIT",
6
6
  "type": "module",