@tempoxyz/patron 0.0.26 → 0.0.27

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
@@ -6,13 +6,13 @@ Your AI agents pay every website they read: $0.001 a page, in OUSD on Tempo, pri
6
6
  npx @tempoxyz/patron
7
7
  ```
8
8
 
9
- First run signs you in with Tempo Wallet, asks for a monthly budget (default $5), buys
10
- seals and adds a hook to every supported agent it finds. After that, every page an agent
11
- reads pays its site one seal. Nothing stays running: the hook hands each read to a one-shot
12
- background payment and exits at once, so the agent never waits, and when seals run low it
9
+ First run signs you in with Tempo Wallet, asks for a monthly budget (default $5), adds
10
+ funds to your Patron balance and adds a hook to every supported agent it finds. After that, every page an agent
11
+ reads pays its site $0.001. Nothing stays running: the hook hands each read to a one-shot
12
+ background payment and exits at once, so the agent never waits, and when your balance runs low it
13
13
  starts a one-shot purchase that exits when done.
14
14
 
15
- Run `npx @tempoxyz/patron` again for status (seals left, pages paid, budget used, rank) and to pause,
15
+ Run `npx @tempoxyz/patron` again for status (balance, pages paid, tips, budget used, rank) and to pause,
16
16
  change the budget or uninstall.
17
17
 
18
18
  ## Commands
@@ -20,7 +20,7 @@ change the budget or uninstall.
20
20
  | Command | What it does |
21
21
  | :- | :- |
22
22
  | `patron` | Set up, or show status and options |
23
- | `patron status` | Seals left, pages paid this month, budget used, leaderboard rank |
23
+ | `patron status` | Balance, pages paid and tips this month, budget used, leaderboard rank |
24
24
  | `patron pause` / `patron resume` | Stop or restart paying |
25
25
  | `patron budget <usd>` | Change the monthly budget |
26
26
  | `patron tip <url> [usd]` | Tip a site, $0.10 by default |
@@ -34,7 +34,7 @@ change the budget or uninstall.
34
34
  - A fetched page pays its site only when it loads (a 2xx status). Error pages, blocks and
35
35
  redirect notices pay nothing.
36
36
  - A search pays each site in its results, up to 10 sites per search.
37
- - Each site's seals are redeemed at once, in separate relayed requests, never batched: the
37
+ - Each site's payments are redeemed at once, in separate relayed requests, never batched: the
38
38
  gateway cannot tell which sites one reader read together.
39
39
  - Sites are paid per registrable domain: `docs.python.org` pays `python.org`. Authors on shared
40
40
  hosts are paid as their own site: `alice.github.io`, `app.vercel.app`, `alice.substack.com`.
@@ -44,19 +44,19 @@ change the budget or uninstall.
44
44
 
45
45
  ## Privacy
46
46
 
47
- Seals are Privacy Pass blind tokens (RFC 9578). The gateway knows your address bought a
48
- number of seals, but cannot link a seal to you when it is spent. Each read sends one seal
47
+ Payments are Privacy Pass blind tokens (RFC 9578). The gateway knows how much your address
48
+ added to its balance, but cannot link a payment to you when it is spent. Each read sends one payment
49
49
  and the site's domain through an Oblivious HTTP relay (RFC 9458): the relay sees your IP but
50
50
  not the content; the gateway sees the content but not your IP.
51
51
 
52
- Local state lives in `~/.patron`: settings, seals encrypted with AES-256-GCM under a key
52
+ Local state lives in `~/.patron`: settings, your balance's blind tokens encrypted with AES-256-GCM under a key
53
53
  file readable only by you, this month's per-site counts, which never leave the machine, and
54
54
  a copy of the CLI in `~/.patron/cli` that agent hooks start with node, so a read never waits
55
55
  on npx. Running `npx @tempoxyz/patron` updates the copy.
56
56
 
57
57
  ## Budget
58
58
 
59
- The budget caps purchases: Patron never buys more than the monthly budget's worth of seals
59
+ The budget caps purchases: Patron never buys more than the monthly budget
60
60
  in a calendar month. With Tempo Wallet, the access key Patron holds also has a spending
61
61
  limit equal to the budget, renewed every 30 days.
62
62
 
package/dist/bin.js CHANGED
@@ -4,14 +4,14 @@ 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-ZPEWRFL2.js");
7
+ const { runHookProcess } = await import("./chunks/hook-process-QQPBFRY6.js");
8
8
  await runHookProcess().catch(() => void 0);
9
9
  process.exit(0);
10
10
  } else if (process.argv[2] === "pay") {
11
- const { runPayProcess } = await import("./chunks/hook-process-ZPEWRFL2.js");
11
+ const { runPayProcess } = await import("./chunks/hook-process-QQPBFRY6.js");
12
12
  await runPayProcess().catch(() => void 0);
13
13
  process.exit(0);
14
14
  } else {
15
- const { run } = await import("./chunks/-WOZ4DM2Y.js");
15
+ const { run } = await import("./chunks/-PBBSDRMM.js");
16
16
  process.exitCode = await run(process.argv.slice(2));
17
17
  }
@@ -29,7 +29,7 @@ import {
29
29
  withPatronStatus,
30
30
  withoutPatronHandlers,
31
31
  writeJsonObject
32
- } from "./chunk-NQ6RRPM6.js";
32
+ } from "./chunk-F5CY5O7O.js";
33
33
  import {
34
34
  startRefill
35
35
  } from "./chunk-TV5VLFTD.js";
@@ -56,7 +56,7 @@ import {
56
56
  updateUsage,
57
57
  writeConfig,
58
58
  writePrivateFile
59
- } from "./chunk-SGQ525FB.js";
59
+ } from "./chunk-MZJEM2SE.js";
60
60
  import {
61
61
  tryLock,
62
62
  withLock
@@ -700,10 +700,10 @@ async function linkRefillFailedAt(home) {
700
700
  var REFILL_LOCK_STALE_MS = 5 * 60 * 1e3;
701
701
  var defaultOpenWallet = async (settings, config, issuer, maxUnits) => {
702
702
  if (config.wallet === "link") {
703
- const { openLinkWallet } = await import("./wallet-IDSQUCB5.js");
703
+ const { openLinkWallet } = await import("./wallet-OJP2JREM.js");
704
704
  return openLinkWallet(config, maxUnits);
705
705
  }
706
- const { openWallet } = await import("./wallet-IDSQUCB5.js");
706
+ const { openWallet } = await import("./wallet-OJP2JREM.js");
707
707
  return openWallet(settings, config.wallet, issuer, maxUnits);
708
708
  };
709
709
  async function buyWithinBudget(settings, config, wanted, openWallet = defaultOpenWallet) {
@@ -778,17 +778,14 @@ function formatStatus(view, color) {
778
778
  const top = Object.entries(usage.domains).sort(([, left], [, right]) => right - left).slice(0, 3).map(([domain, count]) => `${domain} ${count}`);
779
779
  const lines = [
780
780
  `${styleText("Patron", "bold", color)} ${state}${network}`,
781
- row(
782
- "Seals left",
783
- `${tokensLeft.toLocaleString("en-US")} (${tokensUsd(tokensLeft)})`,
784
- color
785
- ),
781
+ row("Balance", `${tokensUsd(tokensLeft)} left`, color),
786
782
  row(
787
783
  "Per page",
788
784
  `$${(clampTokensPerPage(config.tokensPerPage) / 1e3).toFixed(3)}`,
789
785
  color
790
786
  ),
791
787
  row("Pages paid", `${usage.paidPages.toLocaleString("en-US")} this month`, color),
788
+ row("Tipped", `${tokensUsd(usage.tippedTokens)} this month`, color),
792
789
  row(
793
790
  "Budget used",
794
791
  `${bought} of ${budget} this month (${budgetTokens(config.monthlyBudgetUsd) > 0 ? Math.min(100, Math.round(usage.boughtTokens / budgetTokens(config.monthlyBudgetUsd) * 100)) : 0}%)`,
@@ -796,7 +793,7 @@ function formatStatus(view, color) {
796
793
  ),
797
794
  row(
798
795
  "Rank",
799
- standing?.rank ? `#${standing.rank} \xB7 ${standing.tokens.toLocaleString("en-US")} seals bought` : styleText("not ranked yet", "dim", color),
796
+ standing?.rank ? `#${standing.rank} \xB7 ${tokensUsd(standing.tokens)} added` : styleText("not ranked yet", "dim", color),
800
797
  color
801
798
  ),
802
799
  row(
@@ -835,7 +832,7 @@ var HELP = `patron@${VERSION} \u2014 pay the websites your agents read, privatel
835
832
  Usage: patron [command]
836
833
 
837
834
  (none) Set up, or show status and options
838
- status Seals left, pages paid, budget and rank
835
+ status Balance, pages paid, tips, budget and rank
839
836
  pause | resume Stop or restart paying
840
837
  budget <usd> Change the monthly budget
841
838
  per-page <usd> What each site gets per page read, $0.001 to $0.01
@@ -1022,9 +1019,9 @@ async function setup(deps) {
1022
1019
  await writeConfig(settings.home, config);
1023
1020
  const starter = config.wallet === "link" ? PACK_SIZE : STARTER_TOKENS;
1024
1021
  const first = purchasableTokens(config, await readUsage(settings.home), starter);
1025
- step(deps, `Buying ${first.toLocaleString("en-US")} seals (${tokensUsd(first)})`);
1022
+ step(deps, `Adding ${tokensUsd(first)} to your balance`);
1026
1023
  const bought = await buyWithinBudget(settings, config, starter, deps.openWallet);
1027
- done(deps, `${bought.toLocaleString("en-US")} seals ready`);
1024
+ done(deps, `${tokensUsd(bought)} ready to pay sites`);
1028
1025
  deps.startRefill();
1029
1026
  await installStableCli(settings.home).catch(() => void 0);
1030
1027
  const agents = await detectAgents(deps.agents);
@@ -1072,7 +1069,7 @@ async function tempoSignIn(deps, budgetUnits, issuer) {
1072
1069
  deps,
1073
1070
  deps.settings.privateKey ? "Using PATRON_PRIVATE_KEY" : "Signing in with Tempo Wallet"
1074
1071
  );
1075
- const { signIn } = await import("./wallet-IDSQUCB5.js");
1072
+ const { signIn } = await import("./wallet-OJP2JREM.js");
1076
1073
  const account = await signIn(deps.settings, {
1077
1074
  budgetUnits,
1078
1075
  issuer,
@@ -1083,7 +1080,7 @@ async function tempoSignIn(deps, budgetUnits, issuer) {
1083
1080
  }
1084
1081
  async function linkSignIn(deps) {
1085
1082
  step(deps, "Checking your Link wallet (link-cli)");
1086
- const { linkBalance, linkCli, linkPaymentMethods } = await import("./link-OU7W7IT6.js");
1083
+ const { linkBalance, linkCli, linkPaymentMethods } = await import("./link-VK7VCE2R.js");
1087
1084
  const cli = deps.linkCli ?? linkCli();
1088
1085
  const methods = await linkPaymentMethods(cli).catch((error) => {
1089
1086
  throw new Error(
@@ -1186,7 +1183,7 @@ async function changeBudget(deps, input) {
1186
1183
  } else budget = await askBudget(deps, config.monthlyBudgetUsd);
1187
1184
  if (config.wallet === "tempo" && budget > config.monthlyBudgetUsd) {
1188
1185
  step(deps, "Approve the new spending limit in Tempo Wallet");
1189
- const { authorizeBudget } = await import("./wallet-IDSQUCB5.js");
1186
+ const { authorizeBudget } = await import("./wallet-OJP2JREM.js");
1190
1187
  const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
1191
1188
  fetch: deps.fetch
1192
1189
  });
@@ -1240,7 +1237,7 @@ async function tip(deps, url, amount = "0.10") {
1240
1237
  throw new Error(
1241
1238
  `This tip needs ${tokensUsd(missing)} more than this month's budget allows. Raise it with patron budget <usd>.`
1242
1239
  );
1243
- step(deps, `Buying ${missing.toLocaleString("en-US")} seals (${tokensUsd(missing)})`);
1240
+ step(deps, `Adding ${tokensUsd(missing)} to your balance`);
1244
1241
  await buyWithinBudget(settings, config, missing, deps.openWallet);
1245
1242
  }
1246
1243
  const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
@@ -1275,16 +1272,17 @@ async function tip(deps, url, amount = "0.10") {
1275
1272
  if (paid > 0)
1276
1273
  await updateUsage(settings.home, (usage) => {
1277
1274
  usage.domains[domain] = (usage.domains[domain] ?? 0) + paid;
1275
+ usage.tippedTokens += paid;
1278
1276
  });
1279
1277
  if (paid === 0)
1280
1278
  throw new Error(
1281
- rejection ? `Patron rejected the tip to ${domain}: ${rejection}.` : `Could not reach Patron to tip ${domain}; your seals were kept.`
1279
+ rejection ? `Patron rejected the tip to ${domain}: ${rejection}.` : `Could not reach Patron to tip ${domain}; your balance was kept.`
1282
1280
  );
1283
1281
  if (paid < count)
1284
1282
  say(
1285
1283
  deps,
1286
1284
  styleText(
1287
- ` ${count - paid} of ${count} seals did not go through.`,
1285
+ ` ${tokensUsd(count - paid)} of ${tokensUsd(count)} did not go through.`,
1288
1286
  "yellow",
1289
1287
  deps.color
1290
1288
  )
@@ -1302,7 +1300,7 @@ async function setName(deps, name) {
1302
1300
  const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
1303
1301
  fetch: deps.fetch
1304
1302
  });
1305
- const open = deps.openWallet ?? (async (s, c, i, max) => (await import("./wallet-IDSQUCB5.js")).openWallet(s, c.wallet, i, max));
1303
+ const open = deps.openWallet ?? (async (s, c, i, max) => (await import("./wallet-OJP2JREM.js")).openWallet(s, c.wallet, i, max));
1306
1304
  const wallet = await open(settings, config, issuer, 0n);
1307
1305
  await setProfile(settings.gatewayUrl, wallet, name, deps.fetch);
1308
1306
  await writeConfig(settings.home, { ...config, name });
@@ -1325,7 +1323,7 @@ async function uninstall(deps) {
1325
1323
  const prompter = deps.prompter();
1326
1324
  try {
1327
1325
  purge = await prompter.confirm(
1328
- `Also delete ${deps.settings.home}${tokensLeft > 0 ? ` and ${tokensLeft} unspent seals (${tokensUsd(tokensLeft)})` : ""}?`,
1326
+ `Also delete ${deps.settings.home}${tokensLeft > 0 ? ` and your unspent balance of ${tokensUsd(tokensLeft)}` : ""}?`,
1329
1327
  false
1330
1328
  );
1331
1329
  } finally {
@@ -14,7 +14,7 @@ import {
14
14
  readJson,
15
15
  statePaths,
16
16
  writePrivateFile
17
- } from "./chunk-SGQ525FB.js";
17
+ } from "./chunk-MZJEM2SE.js";
18
18
  import {
19
19
  withLock
20
20
  } from "./chunk-O64T22EK.js";
@@ -110,7 +110,7 @@ async function writeConfig(home, config) {
110
110
  );
111
111
  }
112
112
  function emptyUsage(month) {
113
- return { boughtTokens: 0, domains: {}, month, paidPages: 0 };
113
+ return { boughtTokens: 0, domains: {}, month, paidPages: 0, tippedTokens: 0 };
114
114
  }
115
115
  async function readUsage(home, now = /* @__PURE__ */ new Date()) {
116
116
  const month = monthOf(now);
@@ -125,7 +125,8 @@ async function readUsage(home, now = /* @__PURE__ */ new Date()) {
125
125
  boughtTokens: value.boughtTokens,
126
126
  domains: value.domains && typeof value.domains === "object" ? { ...value.domains } : {},
127
127
  month,
128
- paidPages: Number(value.paidPages ?? 0)
128
+ paidPages: Number(value.paidPages ?? 0),
129
+ tippedTokens: Number(value.tippedTokens ?? 0)
129
130
  };
130
131
  }
131
132
  function isUsageRecord(value) {
@@ -135,7 +136,7 @@ function isUsageRecord(value) {
135
136
  }
136
137
  function unreadableUsage(path) {
137
138
  return new Error(
138
- `${path} is unreadable, so Patron stops buying seals. Delete it to restart this month's budget count.`
139
+ `${path} is unreadable, so Patron stops adding to your balance. Delete it to restart this month's budget count.`
139
140
  );
140
141
  }
141
142
  async function updateUsage(home, update, now = /* @__PURE__ */ new Date()) {
@@ -16,7 +16,7 @@ import {
16
16
  needsRefill,
17
17
  redeem,
18
18
  refillSize
19
- } from "./chunk-NQ6RRPM6.js";
19
+ } from "./chunk-F5CY5O7O.js";
20
20
  import {
21
21
  clampTokensPerPage,
22
22
  settingsFor
@@ -26,7 +26,7 @@ import {
26
26
  readUsage,
27
27
  updateUsage,
28
28
  writePrivateFile
29
- } from "./chunk-SGQ525FB.js";
29
+ } from "./chunk-MZJEM2SE.js";
30
30
  import {
31
31
  withLock
32
32
  } from "./chunk-O64T22EK.js";
@@ -202,7 +202,7 @@ async function runPayProcess() {
202
202
  }
203
203
  async function payEvent(event, settings, refill, timeoutMs) {
204
204
  if (timeoutMs <= 0) return;
205
- const { runHook } = await import("./hook-OZRD6I6F.js");
205
+ const { runHook } = await import("./hook-3CYJEB2M.js");
206
206
  await runHook(
207
207
  {
208
208
  readInput: async () => event.raw,
@@ -86,7 +86,7 @@ async function createLinkSpt(options) {
86
86
  "--currency",
87
87
  "usd",
88
88
  "--context",
89
- `Patron: buying $${usd} of seals (1,000 per dollar) that pay the websites your AI agents and browser read, $0.001 per page, privately. Started by npx @tempoxyz/patron on this computer.`,
89
+ `Patron: adding $${usd} to the balance that pays the websites your AI agents and browser read, $0.001 per page, privately. Started by npx @tempoxyz/patron on this computer.`,
90
90
  "--idempotency-key",
91
91
  options.idempotencyKey,
92
92
  "--request-approval",
@@ -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-SGQ525FB.js";
5
+ } from "./chunk-MZJEM2SE.js";
6
6
  import "./chunk-O64T22EK.js";
7
7
  import "./chunk-GTMLTZRN.js";
8
8
 
@@ -121,7 +121,7 @@ async function openWallet(settings, wallet, issuer, maxUnits, output = process.s
121
121
  }
122
122
  var UNITS_PER_CENT = 10000n;
123
123
  async function openLinkWallet(config, maxUnits, output = process.stderr) {
124
- const { linkCli, linkFetch } = await import("./link-OU7W7IT6.js");
124
+ const { linkCli, linkFetch } = await import("./link-VK7VCE2R.js");
125
125
  return {
126
126
  address: "0x0000000000000000000000000000000000000000",
127
127
  fetch: linkFetch({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tempoxyz/patron",
3
- "version": "0.0.26",
3
+ "version": "0.0.27",
4
4
  "description": "Pay the websites your AI agents read, privately",
5
5
  "type": "module",
6
6
  "bin": {