@tempoxyz/patron 0.0.1 → 0.0.11

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/README.md CHANGED
@@ -7,11 +7,11 @@ npx @tempoxyz/patron
7
7
  ```
8
8
 
9
9
  First run signs you in with Tempo Wallet, asks for a monthly budget (default $5), buys
10
- tokens and adds a hook to Claude Code. After that, every page Claude Code fetches pays its
11
- site one token. Nothing stays running: the hook runs once per read and exits, and when
12
- tokens run low it starts a one-shot purchase that exits when done.
10
+ seals and adds a hook to Claude Code. After that, every page Claude Code fetches pays its
11
+ site one seal. Nothing stays running: the hook runs once per read and exits, and when
12
+ seals run low it starts a one-shot purchase that exits when done.
13
13
 
14
- Run `npx @tempoxyz/patron` again for status (tokens left, pages paid, budget used, rank) and to pause,
14
+ Run `npx @tempoxyz/patron` again for status (seals left, pages paid, budget used, rank) and to pause,
15
15
  change the budget or uninstall.
16
16
 
17
17
  ## Commands
@@ -19,7 +19,7 @@ change the budget or uninstall.
19
19
  | Command | What it does |
20
20
  | :- | :- |
21
21
  | `patron` | Set up, or show status and options |
22
- | `patron status` | Tokens left, pages paid this month, budget used, leaderboard rank |
22
+ | `patron status` | Seals left, pages paid this month, budget used, leaderboard rank |
23
23
  | `patron pause` / `patron resume` | Stop or restart paying |
24
24
  | `patron budget <usd>` | Change the monthly budget |
25
25
  | `patron tip <url> [usd]` | Tip a site, $0.10 by default |
@@ -29,17 +29,17 @@ change the budget or uninstall.
29
29
 
30
30
  ## Privacy
31
31
 
32
- Tokens are Privacy Pass blind tokens (RFC 9578). The gateway knows your address bought a
33
- number of tokens, but cannot link a token to you when it is spent. Each read sends one token
32
+ Seals are Privacy Pass blind tokens (RFC 9578). The gateway knows your address bought a
33
+ number of seals, but cannot link a seal to you when it is spent. Each read sends one seal
34
34
  and the site's domain through an Oblivious HTTP relay (RFC 9458): the relay sees your IP but
35
35
  not the content; the gateway sees the content but not your IP.
36
36
 
37
- Local state lives in `~/.patron`: settings, tokens encrypted with AES-256-GCM under a key
37
+ Local state lives in `~/.patron`: settings, seals encrypted with AES-256-GCM under a key
38
38
  file readable only by you, and this month's per-site counts, which never leave the machine.
39
39
 
40
40
  ## Budget
41
41
 
42
- The budget caps purchases: Patron never buys more than the monthly budget's worth of tokens
42
+ The budget caps purchases: Patron never buys more than the monthly budget's worth of seals
43
43
  in a calendar month. With Tempo Wallet, the access key Patron holds also has a spending
44
44
  limit equal to the budget, renewed every 30 days.
45
45
 
package/dist/bin.js CHANGED
@@ -4,10 +4,10 @@ const require = __patronCreateRequire(import.meta.url)
4
4
 
5
5
  // src/bin.ts
6
6
  if (process.argv[2] === "hook") {
7
- const { runHookProcess } = await import("./chunks/hook-process-QQ34YQIA.js");
7
+ const { runHookProcess } = await import("./chunks/hook-process-SIOU4SZZ.js");
8
8
  await runHookProcess().catch(() => void 0);
9
9
  process.exit(0);
10
10
  } else {
11
- const { run } = await import("./chunks/-MVQH5G3L.js");
11
+ const { run } = await import("./chunks/-E6NINF53.js");
12
12
  process.exitCode = await run(process.argv.slice(2));
13
13
  }
@@ -22,7 +22,7 @@ import {
22
22
  isPatronHandler,
23
23
  loadIssuer,
24
24
  needsRefill,
25
- normalizeDomain,
25
+ normalizePayee,
26
26
  parseUsd,
27
27
  profileMessage,
28
28
  purchasableTokens,
@@ -38,7 +38,7 @@ import {
38
38
  withPatronGroup,
39
39
  withoutPatronHandlers,
40
40
  writeJsonObject
41
- } from "./chunk-6Q7AFS33.js";
41
+ } from "./chunk-G2PONYHX.js";
42
42
  import {
43
43
  AGENT_IDS,
44
44
  ensureHome,
@@ -51,7 +51,7 @@ import {
51
51
  withLock,
52
52
  writeConfig,
53
53
  writePrivateFile
54
- } from "./chunk-NLCZ2IHE.js";
54
+ } from "./chunk-6TTNL3HT.js";
55
55
 
56
56
  // src/index.ts
57
57
  import { readFileSync } from "node:fs";
@@ -415,6 +415,45 @@ async function onPath(commands, path) {
415
415
  return false;
416
416
  }
417
417
 
418
+ // src/terminal-style.ts
419
+ var RESET = "\x1B[0m";
420
+ var ANSI = {
421
+ bold: "\x1B[1m",
422
+ cyan: "\x1B[36m",
423
+ dim: "\x1B[2m",
424
+ green: "\x1B[32m",
425
+ purple: "\x1B[35m",
426
+ red: "\x1B[31m",
427
+ yellow: "\x1B[33m"
428
+ };
429
+ function supportsColor(output, requested = true) {
430
+ return requested && process.env.NO_COLOR === void 0 && process.env.TERM !== "dumb" && Boolean(output.isTTY);
431
+ }
432
+ function styleText(value, style, enabled) {
433
+ return enabled ? `${ANSI[style]}${value}${RESET}` : value;
434
+ }
435
+
436
+ // src/banner.ts
437
+ function scrollBanner(version, color) {
438
+ const dim = (text) => styleText(text, "dim", color);
439
+ const bold = (text) => styleText(text, "bold", color);
440
+ const width = 30;
441
+ const line = (text, style = (value) => value) => ` ${dim("|")} ${style(text.padEnd(width - 2))} ${dim("|")}`;
442
+ return [
443
+ dim(` ${"_".repeat(width)}`),
444
+ dim(` /\\${" ".repeat(width)}\\`),
445
+ ` ${dim("( )")} ${bold("P A T R O N")}${" ".repeat(width - 14)}${dim(")")}`,
446
+ dim(` \\/${"_".repeat(width - 1)}/`),
447
+ line("pay every page you read"),
448
+ line("$0.001+ a page, privately"),
449
+ line(`v${version}`, dim),
450
+ dim(` |${"_".repeat(width)}|`),
451
+ dim(` /\\${" ".repeat(width)}\\`),
452
+ dim(` ( )${"_".repeat(width)})`),
453
+ dim(" \\/")
454
+ ].join("\n");
455
+ }
456
+
418
457
  // src/gateway.ts
419
458
  var STANDING_TIMEOUT_MS = 3e3;
420
459
  function shortAddress(address) {
@@ -477,24 +516,6 @@ function openPromptInput() {
477
516
  }
478
517
  }
479
518
 
480
- // src/terminal-style.ts
481
- var RESET = "\x1B[0m";
482
- var ANSI = {
483
- bold: "\x1B[1m",
484
- cyan: "\x1B[36m",
485
- dim: "\x1B[2m",
486
- green: "\x1B[32m",
487
- purple: "\x1B[35m",
488
- red: "\x1B[31m",
489
- yellow: "\x1B[33m"
490
- };
491
- function supportsColor(output, requested = true) {
492
- return requested && process.env.NO_COLOR === void 0 && process.env.TERM !== "dumb" && Boolean(output.isTTY);
493
- }
494
- function styleText(value, style, enabled) {
495
- return enabled ? `${ANSI[style]}${value}${RESET}` : value;
496
- }
497
-
498
519
  // src/prompts.ts
499
520
  function createPrompter(output = process.stdout, color = false, input) {
500
521
  const promptInput = input ? { close: () => void 0, input } : openPromptInput();
@@ -552,7 +573,7 @@ ${styleText(title, "bold", color)}
552
573
  // src/purchase.ts
553
574
  var REFILL_LOCK_STALE_MS = 5 * 60 * 1e3;
554
575
  var defaultOpenWallet = async (settings, config, issuer, maxUnits) => {
555
- const { openWallet } = await import("./wallet-3AFTEAOI.js");
576
+ const { openWallet } = await import("./wallet-MEBNL43A.js");
556
577
  return openWallet(settings, config.wallet, issuer, maxUnits);
557
578
  };
558
579
  async function buyWithinBudget(settings, config, wanted, openWallet = defaultOpenWallet) {
@@ -616,7 +637,7 @@ function formatStatus(view, color) {
616
637
  const lines = [
617
638
  `${styleText("Patron", "bold", color)} ${state}${network}`,
618
639
  row(
619
- "Tokens left",
640
+ "Seals left",
620
641
  `${tokensLeft.toLocaleString("en-US")} (${tokensUsd(tokensLeft)})`,
621
642
  color
622
643
  ),
@@ -633,7 +654,7 @@ function formatStatus(view, color) {
633
654
  ),
634
655
  row(
635
656
  "Rank",
636
- standing?.rank ? `#${standing.rank} \xB7 ${standing.tokens.toLocaleString("en-US")} tokens bought` : styleText("not ranked yet", "dim", color),
657
+ standing?.rank ? `#${standing.rank} \xB7 ${standing.tokens.toLocaleString("en-US")} seals bought` : styleText("not ranked yet", "dim", color),
637
658
  color
638
659
  ),
639
660
  row(
@@ -660,11 +681,11 @@ var HELP = `patron@${VERSION} \u2014 pay the websites your agents read, privatel
660
681
  Usage: patron [command]
661
682
 
662
683
  (none) Set up, or show status and options
663
- status Tokens left, pages paid, budget and rank
684
+ status Seals left, pages paid, budget and rank
664
685
  pause | resume Stop or restart paying
665
686
  budget <usd> Change the monthly budget
666
687
  per-page <usd> What each site gets per page read, $0.001 to $0.01
667
- tip <url> [usd] Tip a site (default $0.10)
688
+ tip <url> [usd] Tip a site or @handle on X (default $0.10)
668
689
  name <handle> Set your public leaderboard name
669
690
  uninstall Remove agent hooks
670
691
  hook Run by agents after each web read (reads the event JSON)
@@ -797,15 +818,7 @@ async function syncAgents(deps, config) {
797
818
  }
798
819
  async function setup(deps) {
799
820
  const settings = deps.settings;
800
- say(deps, styleText(`Patron v${VERSION}`, "bold", deps.color));
801
- say(
802
- deps,
803
- styleText(
804
- "Pay every site your agents read, $0.001 a page, privately.",
805
- "dim",
806
- deps.color
807
- )
808
- );
821
+ say(deps, scrollBanner(VERSION, deps.color));
809
822
  say(deps);
810
823
  const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
811
824
  fetch: deps.fetch,
@@ -819,7 +832,7 @@ async function setup(deps) {
819
832
  deps,
820
833
  settings.privateKey ? "Using PATRON_PRIVATE_KEY" : "Signing in with Tempo Wallet"
821
834
  );
822
- const { signIn } = await import("./wallet-3AFTEAOI.js");
835
+ const { signIn } = await import("./wallet-MEBNL43A.js");
823
836
  const account = await signIn(settings, { budgetUnits, issuer, output: deps.stdout });
824
837
  done(deps, `Signed in as ${account.address}`);
825
838
  const config = {
@@ -835,9 +848,9 @@ async function setup(deps) {
835
848
  };
836
849
  await writeConfig(settings.home, config);
837
850
  const first = purchasableTokens(config, await readUsage(settings.home), STARTER_TOKENS);
838
- step(deps, `Buying ${first.toLocaleString("en-US")} tokens (${tokensUsd(first)})`);
851
+ step(deps, `Buying ${first.toLocaleString("en-US")} seals (${tokensUsd(first)})`);
839
852
  const bought = await buyWithinBudget(settings, config, STARTER_TOKENS, deps.openWallet);
840
- done(deps, `${bought.toLocaleString("en-US")} tokens ready`);
853
+ done(deps, `${bought.toLocaleString("en-US")} seals ready`);
841
854
  deps.startRefill();
842
855
  const agents = await detectAgents(deps.agents);
843
856
  if (agents.length === 0) {
@@ -933,7 +946,7 @@ async function changeBudget(deps, input) {
933
946
  } else budget = await askBudget(deps, config.monthlyBudgetUsd);
934
947
  if (config.wallet === "tempo" && budget > config.monthlyBudgetUsd) {
935
948
  step(deps, "Approve the new spending limit in Tempo Wallet");
936
- const { authorizeBudget } = await import("./wallet-3AFTEAOI.js");
949
+ const { authorizeBudget } = await import("./wallet-MEBNL43A.js");
937
950
  const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
938
951
  fetch: deps.fetch
939
952
  });
@@ -972,9 +985,10 @@ async function changePerPage(deps, input) {
972
985
  done(deps, `Each site now gets $${(tokens / 1e3).toFixed(3)} per page.`);
973
986
  }
974
987
  async function tip(deps, url, amount = "0.10") {
975
- const domain = url ? normalizeDomain(url) : null;
988
+ const domain = url ? normalizePayee(url) : null;
976
989
  const usd = parseUsd(amount);
977
- if (!domain || usd === void 0) throw new UsageError("Usage: patron tip <url> [usd]");
990
+ if (!domain || usd === void 0)
991
+ throw new UsageError("Usage: patron tip <url or @handle> [usd]");
978
992
  const count = tipTokens(usd);
979
993
  if (count < 1) throw new UsageError("The smallest tip is $0.001.");
980
994
  const { config, settings } = await loadSetup(deps);
@@ -986,7 +1000,7 @@ async function tip(deps, url, amount = "0.10") {
986
1000
  throw new Error(
987
1001
  `This tip needs ${tokensUsd(missing)} more than this month's budget allows. Raise it with patron budget <usd>.`
988
1002
  );
989
- step(deps, `Buying ${missing.toLocaleString("en-US")} tokens (${tokensUsd(missing)})`);
1003
+ step(deps, `Buying ${missing.toLocaleString("en-US")} seals (${tokensUsd(missing)})`);
990
1004
  await buyWithinBudget(settings, config, missing, deps.openWallet);
991
1005
  }
992
1006
  const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
@@ -1024,13 +1038,13 @@ async function tip(deps, url, amount = "0.10") {
1024
1038
  });
1025
1039
  if (paid === 0)
1026
1040
  throw new Error(
1027
- rejection ? `Patron rejected the tip to ${domain}: ${rejection}.` : `Could not reach Patron to tip ${domain}; your tokens were kept.`
1041
+ rejection ? `Patron rejected the tip to ${domain}: ${rejection}.` : `Could not reach Patron to tip ${domain}; your seals were kept.`
1028
1042
  );
1029
1043
  if (paid < count)
1030
1044
  say(
1031
1045
  deps,
1032
1046
  styleText(
1033
- ` ${count - paid} of ${count} tokens did not go through.`,
1047
+ ` ${count - paid} of ${count} seals did not go through.`,
1034
1048
  "yellow",
1035
1049
  deps.color
1036
1050
  )
@@ -1044,7 +1058,7 @@ async function setName(deps, name) {
1044
1058
  const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
1045
1059
  fetch: deps.fetch
1046
1060
  });
1047
- const open = deps.openWallet ?? (async (s, c, i, max) => (await import("./wallet-3AFTEAOI.js")).openWallet(s, c.wallet, i, max));
1061
+ const open = deps.openWallet ?? (async (s, c, i, max) => (await import("./wallet-MEBNL43A.js")).openWallet(s, c.wallet, i, max));
1048
1062
  const wallet = await open(settings, config, issuer, 0n);
1049
1063
  await setProfile(settings.gatewayUrl, wallet, name, deps.fetch);
1050
1064
  await writeConfig(settings.home, { ...config, name });
@@ -1067,7 +1081,7 @@ async function uninstall(deps) {
1067
1081
  const prompter = deps.prompter();
1068
1082
  try {
1069
1083
  purge = await prompter.confirm(
1070
- `Also delete ${deps.settings.home}${tokensLeft > 0 ? ` and ${tokensLeft} unspent tokens (${tokensUsd(tokensLeft)})` : ""}?`,
1084
+ `Also delete ${deps.settings.home}${tokensLeft > 0 ? ` and ${tokensLeft} unspent seals (${tokensUsd(tokensLeft)})` : ""}?`,
1071
1085
  false
1072
1086
  );
1073
1087
  } finally {
@@ -143,7 +143,8 @@ async function readConfig(home) {
143
143
  relayUrl: String(config.relayUrl ?? ""),
144
144
  version: 1,
145
145
  wallet: config.wallet === "key" ? "key" : "tempo",
146
- ...typeof config.name === "string" ? { name: config.name } : {}
146
+ ...typeof config.name === "string" ? { name: config.name } : {},
147
+ ...typeof config.tokensPerPage === "number" ? { tokensPerPage: config.tokensPerPage } : {}
147
148
  };
148
149
  }
149
150
  async function writeConfig(home, config) {
@@ -180,7 +181,7 @@ function isUsageRecord(value) {
180
181
  }
181
182
  function unreadableUsage(path) {
182
183
  return new Error(
183
- `${path} is unreadable, so Patron stops buying tokens. Delete it to restart this month's budget count.`
184
+ `${path} is unreadable, so Patron stops buying seals. Delete it to restart this month's budget count.`
184
185
  );
185
186
  }
186
187
  async function updateUsage(home, update, now = /* @__PURE__ */ new Date()) {
@@ -10,7 +10,7 @@ import {
10
10
  statePaths,
11
11
  withLock,
12
12
  writePrivateFile
13
- } from "./chunk-NLCZ2IHE.js";
13
+ } from "./chunk-6TTNL3HT.js";
14
14
 
15
15
  // ../../node_modules/.pnpm/tldts@7.4.19/node_modules/tldts/dist/cjs/index.js
16
16
  var require_cjs = __commonJS({
@@ -8608,6 +8608,76 @@ function normalizeDomain(input2) {
8608
8608
  return parsed.domain;
8609
8609
  }
8610
8610
 
8611
+ // ../protocol/src/payee.ts
8612
+ var X_PAYEE_PREFIX = "x.com/";
8613
+ var X_HOSTS = /* @__PURE__ */ new Set([
8614
+ "x.com",
8615
+ "www.x.com",
8616
+ "mobile.x.com",
8617
+ "twitter.com",
8618
+ "www.twitter.com",
8619
+ "mobile.twitter.com"
8620
+ ]);
8621
+ var X_RESERVED = /* @__PURE__ */ new Set([
8622
+ "about",
8623
+ "account",
8624
+ "bookmarks",
8625
+ "communities",
8626
+ "compose",
8627
+ "download",
8628
+ "explore",
8629
+ "grok",
8630
+ "hashtag",
8631
+ "home",
8632
+ "i",
8633
+ "intent",
8634
+ "jobs",
8635
+ "lists",
8636
+ "login",
8637
+ "logout",
8638
+ "messages",
8639
+ "notifications",
8640
+ "premium",
8641
+ "privacy",
8642
+ "search",
8643
+ "settings",
8644
+ "share",
8645
+ "signup",
8646
+ "tos"
8647
+ ]);
8648
+ var X_HANDLE = /^[a-z0-9_]{1,15}$/;
8649
+ function xPayee(handle) {
8650
+ const lower = handle.replace(/^@/, "").toLowerCase();
8651
+ return X_HANDLE.test(lower) && !X_RESERVED.has(lower) ? `${X_PAYEE_PREFIX}${lower}` : null;
8652
+ }
8653
+ function normalizePayee(input2) {
8654
+ const trimmed = input2.trim();
8655
+ if (!trimmed) return null;
8656
+ if (trimmed.startsWith("@")) return xPayee(trimmed);
8657
+ let url2;
8658
+ try {
8659
+ url2 = new URL(
8660
+ /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`
8661
+ );
8662
+ } catch {
8663
+ return null;
8664
+ }
8665
+ const host = url2.hostname.toLowerCase().replace(/\.$/, "");
8666
+ const bareHost = !/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) && !trimmed.includes("/");
8667
+ if (X_HOSTS.has(host) && !bareHost && (url2.protocol === "https:" || url2.protocol === "http:")) {
8668
+ const [first, second] = url2.pathname.split("/").filter(Boolean);
8669
+ if (!first) return null;
8670
+ if (/^[a-z]{2}(-[a-z]{2})?$/i.test(first) && second && X_RESERVED.has(second.toLowerCase()))
8671
+ return null;
8672
+ try {
8673
+ return xPayee(decodeURIComponent(first));
8674
+ } catch {
8675
+ return null;
8676
+ }
8677
+ }
8678
+ return normalizeDomain(trimmed);
8679
+ }
8680
+
8611
8681
  // ../protocol/src/encoding.ts
8612
8682
  function toBase64Url(bytes) {
8613
8683
  let binary = "";
@@ -28410,12 +28480,27 @@ var LeaderboardResponse = external_exports.object({
28410
28480
  sites: external_exports.array(
28411
28481
  external_exports.object({ domain: external_exports.string(), earnedUsd: usd, visits: external_exports.number().int() })
28412
28482
  ),
28483
+ /** Claimed X profiles, by earnings: their own leaderboard. */
28484
+ creators: external_exports.array(external_exports.object({ handle: external_exports.string(), earnedUsd: usd, visits: external_exports.number().int() })).default([]),
28413
28485
  totals: external_exports.object({ tokens: external_exports.number().int(), sites: external_exports.number().int(), usd })
28414
28486
  });
28415
28487
  var ClaimRequest = external_exports.object({
28488
+ /** A registrable domain, or an X profile as "x.com/<handle>". */
28416
28489
  domain: external_exports.string().min(1).max(253),
28490
+ address,
28491
+ /** For an X profile: the URL of a post by that profile containing claimRecordValue(address). */
28492
+ proofUrl: external_exports.string().url().max(512).optional(),
28493
+ /** For an X profile, instead of proofUrl: the proof Sign in with X returned to the claim page. */
28494
+ xProof: external_exports.string().max(1024).optional()
28495
+ });
28496
+ var XSignInRequest = external_exports.object({
28497
+ /** The X handle to sign in as, with or without @. */
28498
+ handle: external_exports.string().min(1).max(16),
28499
+ /** The address the proof will claim for. */
28417
28500
  address
28418
28501
  });
28502
+ var XSignInResponse = external_exports.object({ authorizationUrl: external_exports.string().url() });
28503
+ var XConfig = external_exports.object({ signIn: external_exports.boolean() });
28419
28504
  var ClaimResponse = external_exports.object({
28420
28505
  ok: external_exports.boolean(),
28421
28506
  domain: external_exports.string(),
@@ -35702,8 +35787,18 @@ function codexPaths(env, home) {
35702
35787
  function withCodexStopHook(settings, command) {
35703
35788
  return withPatronGroup(settings, EVENT, stopGroup(command));
35704
35789
  }
35790
+ var CODEX_HOOK_STATUS = "Patron: pay the sites this turn read";
35705
35791
  function stopGroup(command) {
35706
- return { hooks: [{ command, timeout: HOOK_TIMEOUT_SECONDS, type: "command" }] };
35792
+ return {
35793
+ hooks: [
35794
+ {
35795
+ command,
35796
+ statusMessage: CODEX_HOOK_STATUS,
35797
+ timeout: HOOK_TIMEOUT_SECONDS,
35798
+ type: "command"
35799
+ }
35800
+ ]
35801
+ };
35707
35802
  }
35708
35803
  function hasStopGroup(settings, command) {
35709
35804
  const groups = isObject2(settings.hooks) ? settings.hooks[EVENT] : void 0;
@@ -35795,9 +35890,9 @@ export {
35795
35890
  MIN_TOKENS_PER_PAGE,
35796
35891
  MAX_TOKENS_PER_PAGE,
35797
35892
  clampTokensPerPage,
35798
- normalizeDomain,
35799
35893
  formatUsd,
35800
35894
  tokensToUnits,
35895
+ normalizePayee,
35801
35896
  LeaderboardResponse,
35802
35897
  PatronInfo,
35803
35898
  profileMessage,
@@ -6,20 +6,20 @@ import {
6
6
  codexHome,
7
7
  loadIssuer,
8
8
  needsRefill,
9
- normalizeDomain,
9
+ normalizePayee,
10
10
  refillSize,
11
11
  resolveSettings,
12
12
  settingsFor,
13
13
  spend,
14
14
  startRefill
15
- } from "./chunk-6Q7AFS33.js";
15
+ } from "./chunk-G2PONYHX.js";
16
16
  import {
17
17
  readConfig,
18
18
  readUsage,
19
19
  updateUsage,
20
20
  withLock,
21
21
  writePrivateFile
22
- } from "./chunk-NLCZ2IHE.js";
22
+ } from "./chunk-6TTNL3HT.js";
23
23
 
24
24
  // src/hook.ts
25
25
  import { homedir } from "node:os";
@@ -50,7 +50,7 @@ function hookUrls(payload) {
50
50
  function hookDomains(payload) {
51
51
  const domains = [];
52
52
  for (const url of hookUrls(payload)) {
53
- const domain = normalizeDomain(url);
53
+ const domain = normalizePayee(url);
54
54
  if (domain && !domains.includes(domain)) domains.push(domain);
55
55
  if (domains.length >= MAX_DOMAINS_PER_HOOK) break;
56
56
  }
@@ -179,7 +179,7 @@ async function takeTranscriptDomains(home, transcriptPath2, options) {
179
179
  const known = /* @__PURE__ */ new Set([...state.paid, ...state.pending]);
180
180
  const pending = [...state.pending];
181
181
  for (const url of codexRolloutUrls(lines)) {
182
- const domain = normalizeDomain(url);
182
+ const domain = normalizePayee(url);
183
183
  if (domain && !known.has(domain)) {
184
184
  known.add(domain);
185
185
  pending.push(domain);
@@ -336,9 +336,11 @@ async function payReads(dependencies, deadline) {
336
336
  const paid = [];
337
337
  let empty = false;
338
338
  const perPage = clampTokensPerPage(config.tokensPerPage);
339
- reads: for (const domain of domains) {
340
- for (let token = 0; token < perPage; token++) {
341
- if (Date.now() >= deadline) break reads;
339
+ let pending = domains.slice();
340
+ rounds: for (let round = 0; round < perPage && pending.length > 0; round++) {
341
+ const next = [];
342
+ for (const domain of pending) {
343
+ if (Date.now() >= deadline) break rounds;
342
344
  const result = await spend({
343
345
  domain,
344
346
  fetch: boundedFetch,
@@ -348,11 +350,13 @@ async function payReads(dependencies, deadline) {
348
350
  }).catch(() => null);
349
351
  if (result === void 0) {
350
352
  empty = true;
351
- break reads;
353
+ break rounds;
352
354
  }
353
- if (token === 0 && result?.ok) paid.push(result.domain || domain);
354
- if (!result?.ok) break;
355
+ if (!result?.ok) continue;
356
+ if (round === 0) paid.push(result.domain || domain);
357
+ next.push(domain);
355
358
  }
359
+ pending = next;
356
360
  }
357
361
  const now = dependencies.now?.() ?? /* @__PURE__ */ new Date();
358
362
  if (paid.length > 0)
@@ -2,7 +2,7 @@ import { createRequire as __patronCreateRequire } from 'node:module'
2
2
  const require = __patronCreateRequire(import.meta.url)
3
3
  import {
4
4
  statePaths
5
- } from "./chunk-NLCZ2IHE.js";
5
+ } from "./chunk-6TTNL3HT.js";
6
6
 
7
7
  // src/wallet.ts
8
8
  import { Store } from "accounts";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tempoxyz/patron",
3
- "version": "0.0.1",
3
+ "version": "0.0.11",
4
4
  "description": "Pay the websites your AI agents read, privately",
5
5
  "type": "module",
6
6
  "bin": {
@@ -41,7 +41,7 @@
41
41
  "vitest": "4.1.12"
42
42
  },
43
43
  "dependencies": {
44
- "accounts": "0.21.0",
44
+ "accounts": "0.21.1",
45
45
  "mppx": "0.15.0",
46
46
  "viem": "2.57.12"
47
47
  }