x402-perpcheck / tree / src/free-tier-do.js ยท raw (this view has old GitHub links rewritten for the mirror; raw is byte-exact)
// SQLite Durable Object for the free MCP tier (see free-tier.js). One instance ("free-tier") per Worker.
// Table u(day, k, n): k = sha256(day|client) prefix, '*' = the tool-wide total. Days before today are pruned.
// take() is synchronous SQL inside one DO, so concurrent calls can't overshoot either cap.
import { DurableObject } from 'cloudflare:workers';

export class FreeTierCounter extends DurableObject {
  constructor(ctx, env) {
    super(ctx, env);
    this.sql = ctx.storage.sql;
    this.sql.exec('CREATE TABLE IF NOT EXISTS u (day TEXT NOT NULL, k TEXT NOT NULL, n INTEGER NOT NULL DEFAULT 0, PRIMARY KEY (day, k))');
    this.day = null;
  }
  n(day, k) { const r = this.sql.exec('SELECT n FROM u WHERE day = ? AND k = ?', day, k).toArray(); return r.length ? Number(r[0].n) : 0; }
  take(day, k, perClient, globalDaily) {
    if (!/^\d{4}-\d{2}-\d{2}$/.test(day) || !/^[0-9a-f]{8,64}$/.test(k)) return { ok: false, reason: 'client', used: 0, global_used: 0 };
    if (day !== this.day) { this.sql.exec('DELETE FROM u WHERE day < ?', day); this.day = day; }
    const n = this.n(day, k); const g = this.n(day, '*');
    if (n >= perClient) return { ok: false, reason: 'client', used: n, global_used: g };
    if (g >= globalDaily) return { ok: false, reason: 'global', used: n, global_used: g };
    const up = 'INSERT INTO u (day, k, n) VALUES (?, ?, 1) ON CONFLICT (day, k) DO UPDATE SET n = n + 1';
    this.sql.exec(up, day, k); this.sql.exec(up, day, '*');
    return { ok: true, used: n + 1, global_used: g + 1 };
  }
  refund(day, k) {
    if (!/^[0-9a-f]{8,64}$/.test(k)) return false;
    this.sql.exec('UPDATE u SET n = n - 1 WHERE day = ? AND k IN (?, ?) AND n > 0', day, k, '*');
    return true;
  }
}

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