@tempoxyz/patron 0.0.1 → 0.0.10
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 +9 -9
- package/dist/bin.js +2 -2
- package/dist/chunks/{-MVQH5G3L.js → -SRYAMUCC.js} +60 -46
- package/dist/chunks/{chunk-NLCZ2IHE.js → chunk-6TTNL3HT.js} +3 -2
- package/dist/chunks/{chunk-6Q7AFS33.js → chunk-DEUBVELW.js} +87 -2
- package/dist/chunks/{hook-process-QQ34YQIA.js → hook-process-ZBZ3WF5I.js} +15 -11
- package/dist/chunks/{wallet-3AFTEAOI.js → wallet-MEBNL43A.js} +1 -1
- package/package.json +2 -2
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
|
-
|
|
11
|
-
site one
|
|
12
|
-
|
|
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 (
|
|
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` |
|
|
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
|
-
|
|
33
|
-
number of
|
|
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,
|
|
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
|
|
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-
|
|
7
|
+
const { runHookProcess } = await import("./chunks/hook-process-ZBZ3WF5I.js");
|
|
8
8
|
await runHookProcess().catch(() => void 0);
|
|
9
9
|
process.exit(0);
|
|
10
10
|
} else {
|
|
11
|
-
const { run } = await import("./chunks/-
|
|
11
|
+
const { run } = await import("./chunks/-SRYAMUCC.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
|
-
|
|
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-
|
|
41
|
+
} from "./chunk-DEUBVELW.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-
|
|
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-
|
|
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
|
-
"
|
|
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")}
|
|
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
|
|
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,
|
|
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-
|
|
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")}
|
|
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")}
|
|
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-
|
|
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 ?
|
|
988
|
+
const domain = url ? normalizePayee(url) : null;
|
|
976
989
|
const usd = parseUsd(amount);
|
|
977
|
-
if (!domain || usd === void 0)
|
|
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")}
|
|
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
|
|
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}
|
|
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-
|
|
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
|
|
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
|
|
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-
|
|
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(),
|
|
@@ -35795,9 +35880,9 @@ export {
|
|
|
35795
35880
|
MIN_TOKENS_PER_PAGE,
|
|
35796
35881
|
MAX_TOKENS_PER_PAGE,
|
|
35797
35882
|
clampTokensPerPage,
|
|
35798
|
-
normalizeDomain,
|
|
35799
35883
|
formatUsd,
|
|
35800
35884
|
tokensToUnits,
|
|
35885
|
+
normalizePayee,
|
|
35801
35886
|
LeaderboardResponse,
|
|
35802
35887
|
PatronInfo,
|
|
35803
35888
|
profileMessage,
|
|
@@ -6,20 +6,20 @@ import {
|
|
|
6
6
|
codexHome,
|
|
7
7
|
loadIssuer,
|
|
8
8
|
needsRefill,
|
|
9
|
-
|
|
9
|
+
normalizePayee,
|
|
10
10
|
refillSize,
|
|
11
11
|
resolveSettings,
|
|
12
12
|
settingsFor,
|
|
13
13
|
spend,
|
|
14
14
|
startRefill
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-DEUBVELW.js";
|
|
16
16
|
import {
|
|
17
17
|
readConfig,
|
|
18
18
|
readUsage,
|
|
19
19
|
updateUsage,
|
|
20
20
|
withLock,
|
|
21
21
|
writePrivateFile
|
|
22
|
-
} from "./chunk-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
340
|
-
|
|
341
|
-
|
|
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
|
|
353
|
+
break rounds;
|
|
352
354
|
}
|
|
353
|
-
if (
|
|
354
|
-
if (
|
|
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-
|
|
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.
|
|
3
|
+
"version": "0.0.10",
|
|
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.
|
|
44
|
+
"accounts": "0.21.1",
|
|
45
45
|
"mppx": "0.15.0",
|
|
46
46
|
"viem": "2.57.12"
|
|
47
47
|
}
|