agentgate / tree / service/src/facilitator.js ยท raw (this view has old GitHub links rewritten for the mirror; raw is byte-exact)
// A facilitator client that can't hang the Worker. On Workers, staticSupported=true answers /supported from a
// static list (matching PayAI's) with no I/O: @x402/hono starts its init when the app is built, i.e. inside the
// first request, and if that request finishes first its fetch and timers are orphaned, so every later paid request
// would wait forever on that promise. Otherwise /supported gets a short timeout and the same static fallback.
// verify and settle run inside the paying request and get their own timeouts.
// createAuthHeaders (CDP facilitator) is passed through to HTTPFacilitatorClient; it runs inside verify/settle, so the
// same deadlines cover it. EXTENSION-RESPONSES (e.g. CDP's bazaar indexing status) is logged after verify/settle.
import { HTTPFacilitatorClient } from '@x402/core/server';
import { withDeadline as withTimeout, BUDGET } from './deadline.js';

export class ResilientFacilitatorClient extends HTTPFacilitatorClient {
  constructor({ url, network, createAuthHeaders, name, supportedTimeoutMs = BUDGET.supportedMs, verifyTimeoutMs = BUDGET.verifyMs, settleTimeoutMs = BUDGET.settleMs, staticSupported = false }) {
    super(createAuthHeaders ? { url, createAuthHeaders } : { url });
    this.name = name || 'payai';
    this.network = network;
    this.supportedTimeoutMs = supportedTimeoutMs;
    this.verifyTimeoutMs = verifyTimeoutMs;
    this.settleTimeoutMs = settleTimeoutMs;
    this.staticSupported = staticSupported;
  }
  staticKinds() {
    return { kinds: [{ x402Version: 2, scheme: 'exact', network: this.network }], extensions: ['bazaar'], signers: {} };
  }
  async getSupported() {
    if (this.staticSupported) return this.staticKinds();
    try { return await withTimeout(super.getSupported(), this.supportedTimeoutMs, 'facilitator /supported'); }
    catch (e) {
      console.warn(`x402: ${e.message}; using static supported kinds`);
      return this.staticKinds();
    }
  }
  verify(payload, requirements) { return withTimeout(super.verify(payload, requirements), this.verifyTimeoutMs, 'facilitator /verify').then((r) => logExtensionResponses(this.name, 'verify', r)); }
  settle(payload, requirements) { return withTimeout(super.settle(payload, requirements), this.settleTimeoutMs, 'facilitator /settle').then((r) => logExtensionResponses(this.name, 'settle', r)); }
}

/** Log the facilitator's decoded EXTENSION-RESPONSES header (HTTPFacilitatorClient puts it on result.extensionResponses). */
export function logExtensionResponses(facilitator, op, result, log = console.log) {
  try { if (result?.extensionResponses) log(`x402 EXTENSION-RESPONSES ${facilitator} ${op}: ${JSON.stringify(result.extensionResponses)}`); } catch { /* logging never breaks a payment */ }
  return result;
}

agentgate-source: code mirror on Cloudflare Pages. All repos