@tempoxyz/patron 0.0.26 → 0.0.28
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 +11 -11
- package/dist/bin.js +3 -3
- package/dist/chunks/{-WOZ4DM2Y.js → -5Q7V7W7W.js} +52 -38
- package/dist/chunks/{chunk-WZRGCKEK.js → chunk-EISHX7Q3.js} +54 -32
- package/dist/chunks/chunk-EKFENOVR.js +15456 -0
- package/dist/chunks/{chunk-NQ6RRPM6.js → chunk-EV7OA6GK.js} +19226 -34511
- package/dist/chunks/{chunk-HVTTV2A5.js → chunk-HQ2ZLUTT.js} +1 -1
- package/dist/chunks/chunk-OQXACACU.js +37 -0
- package/dist/chunks/{hook-OZRD6I6F.js → hook-N2SVXVUR.js} +6 -6
- package/dist/chunks/{hook-process-ZPEWRFL2.js → hook-process-IMQMGXBT.js} +4 -4
- package/dist/chunks/{link-OU7W7IT6.js → link-VK7VCE2R.js} +1 -1
- package/dist/chunks/{wallet-IDSQUCB5.js → wallet-6TDMXRWW.js} +6 -4
- package/package.json +1 -1
- package/dist/chunks/chunk-O64T22EK.js +0 -54
- package/dist/chunks/chunk-SGQ525FB.js +0 -162
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),
|
|
10
|
-
|
|
11
|
-
reads pays its site
|
|
12
|
-
background payment and exits at once, so the agent never waits, and when
|
|
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 (
|
|
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` |
|
|
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
|
|
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
|
-
|
|
48
|
-
|
|
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,
|
|
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
|
|
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-
|
|
7
|
+
const { runHookProcess } = await import("./chunks/hook-process-IMQMGXBT.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-
|
|
11
|
+
const { runPayProcess } = await import("./chunks/hook-process-IMQMGXBT.js");
|
|
12
12
|
await runPayProcess().catch(() => void 0);
|
|
13
13
|
process.exit(0);
|
|
14
14
|
} else {
|
|
15
|
-
const { run } = await import("./chunks/-
|
|
15
|
+
const { run } = await import("./chunks/-5Q7V7W7W.js");
|
|
16
16
|
process.exitCode = await run(process.argv.slice(2));
|
|
17
17
|
}
|
|
@@ -3,8 +3,6 @@ const require = __patronCreateRequire(import.meta.url)
|
|
|
3
3
|
import {
|
|
4
4
|
FileTokenStore,
|
|
5
5
|
LINK_TOKEN_STEP,
|
|
6
|
-
LeaderboardResponse,
|
|
7
|
-
PatronInfo,
|
|
8
6
|
STARTER_TOKENS,
|
|
9
7
|
budgetTokens,
|
|
10
8
|
buyTokens,
|
|
@@ -17,7 +15,6 @@ import {
|
|
|
17
15
|
loadIssuer,
|
|
18
16
|
needsRefill,
|
|
19
17
|
parseUsd,
|
|
20
|
-
profileMessage,
|
|
21
18
|
purchasableTokens,
|
|
22
19
|
readJsonObject,
|
|
23
20
|
redeem,
|
|
@@ -29,26 +26,20 @@ import {
|
|
|
29
26
|
withPatronStatus,
|
|
30
27
|
withoutPatronHandlers,
|
|
31
28
|
writeJsonObject
|
|
32
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-EKFENOVR.js";
|
|
33
30
|
import {
|
|
34
31
|
startRefill
|
|
35
32
|
} from "./chunk-TV5VLFTD.js";
|
|
36
33
|
import {
|
|
37
|
-
DEFAULT_MONTHLY_BUDGET_USD,
|
|
38
|
-
MAX_TOKENS_PER_PAGE,
|
|
39
|
-
MIN_TOKENS_PER_PAGE,
|
|
40
|
-
PACK_SIZE,
|
|
41
|
-
TOKEN_PRICE_UNITS,
|
|
42
|
-
clampTokensPerPage,
|
|
43
|
-
formatUsd,
|
|
44
|
-
normalizePayee,
|
|
45
34
|
resolveSettings,
|
|
46
|
-
settingsFor
|
|
47
|
-
|
|
48
|
-
} from "./chunk-WZRGCKEK.js";
|
|
35
|
+
settingsFor
|
|
36
|
+
} from "./chunk-OQXACACU.js";
|
|
49
37
|
import {
|
|
50
38
|
AGENT_IDS,
|
|
39
|
+
LeaderboardResponse,
|
|
40
|
+
PatronInfo,
|
|
51
41
|
ensureHome,
|
|
42
|
+
profileMessage,
|
|
52
43
|
readConfig,
|
|
53
44
|
readJson,
|
|
54
45
|
readUsage,
|
|
@@ -56,11 +47,20 @@ import {
|
|
|
56
47
|
updateUsage,
|
|
57
48
|
writeConfig,
|
|
58
49
|
writePrivateFile
|
|
59
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-EV7OA6GK.js";
|
|
60
51
|
import {
|
|
52
|
+
DEFAULT_MONTHLY_BUDGET_USD,
|
|
53
|
+
MAX_TOKENS_PER_PAGE,
|
|
54
|
+
MIN_TOKENS_PER_PAGE,
|
|
55
|
+
PACK_SIZE,
|
|
56
|
+
TOKEN_PRICE_UNITS,
|
|
57
|
+
clampTokensPerPage,
|
|
58
|
+
formatUsd,
|
|
59
|
+
normalizePayee,
|
|
60
|
+
tokensToUnits,
|
|
61
61
|
tryLock,
|
|
62
62
|
withLock
|
|
63
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-EISHX7Q3.js";
|
|
64
64
|
import "./chunk-GTMLTZRN.js";
|
|
65
65
|
|
|
66
66
|
// src/index.ts
|
|
@@ -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-
|
|
703
|
+
const { openLinkWallet } = await import("./wallet-6TDMXRWW.js");
|
|
704
704
|
return openLinkWallet(config, maxUnits);
|
|
705
705
|
}
|
|
706
|
-
const { openWallet } = await import("./wallet-
|
|
706
|
+
const { openWallet } = await import("./wallet-6TDMXRWW.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
|
|
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
|
|
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
|
|
@@ -864,6 +861,19 @@ function defaults() {
|
|
|
864
861
|
stdout: process.stdout
|
|
865
862
|
};
|
|
866
863
|
}
|
|
864
|
+
var REFRESHES_STABLE_COPY = /* @__PURE__ */ new Set([
|
|
865
|
+
"status",
|
|
866
|
+
"pause",
|
|
867
|
+
"resume",
|
|
868
|
+
"budget",
|
|
869
|
+
"per-page",
|
|
870
|
+
"tip",
|
|
871
|
+
"name"
|
|
872
|
+
]);
|
|
873
|
+
async function refreshStableCli(deps) {
|
|
874
|
+
const config = await readConfig(deps.settings.home).catch(() => void 0);
|
|
875
|
+
if (config) await installStableCli(deps.settings.home).catch(() => void 0);
|
|
876
|
+
}
|
|
867
877
|
async function run(argv, overrides = {}) {
|
|
868
878
|
const base = { ...defaults(), ...overrides };
|
|
869
879
|
let shared;
|
|
@@ -876,6 +886,8 @@ async function run(argv, overrides = {}) {
|
|
|
876
886
|
};
|
|
877
887
|
const [command, ...args] = argv;
|
|
878
888
|
try {
|
|
889
|
+
if (command !== void 0 && REFRESHES_STABLE_COPY.has(command))
|
|
890
|
+
await refreshStableCli(deps);
|
|
879
891
|
switch (command) {
|
|
880
892
|
case void 0:
|
|
881
893
|
await main(deps);
|
|
@@ -1022,9 +1034,9 @@ async function setup(deps) {
|
|
|
1022
1034
|
await writeConfig(settings.home, config);
|
|
1023
1035
|
const starter = config.wallet === "link" ? PACK_SIZE : STARTER_TOKENS;
|
|
1024
1036
|
const first = purchasableTokens(config, await readUsage(settings.home), starter);
|
|
1025
|
-
step(deps, `
|
|
1037
|
+
step(deps, `Adding ${tokensUsd(first)} to your balance`);
|
|
1026
1038
|
const bought = await buyWithinBudget(settings, config, starter, deps.openWallet);
|
|
1027
|
-
done(deps, `${bought
|
|
1039
|
+
done(deps, `${tokensUsd(bought)} ready to pay sites`);
|
|
1028
1040
|
deps.startRefill();
|
|
1029
1041
|
await installStableCli(settings.home).catch(() => void 0);
|
|
1030
1042
|
const agents = await detectAgents(deps.agents);
|
|
@@ -1072,7 +1084,7 @@ async function tempoSignIn(deps, budgetUnits, issuer) {
|
|
|
1072
1084
|
deps,
|
|
1073
1085
|
deps.settings.privateKey ? "Using PATRON_PRIVATE_KEY" : "Signing in with Tempo Wallet"
|
|
1074
1086
|
);
|
|
1075
|
-
const { signIn } = await import("./wallet-
|
|
1087
|
+
const { signIn } = await import("./wallet-6TDMXRWW.js");
|
|
1076
1088
|
const account = await signIn(deps.settings, {
|
|
1077
1089
|
budgetUnits,
|
|
1078
1090
|
issuer,
|
|
@@ -1083,7 +1095,7 @@ async function tempoSignIn(deps, budgetUnits, issuer) {
|
|
|
1083
1095
|
}
|
|
1084
1096
|
async function linkSignIn(deps) {
|
|
1085
1097
|
step(deps, "Checking your Link wallet (link-cli)");
|
|
1086
|
-
const { linkBalance, linkCli, linkPaymentMethods } = await import("./link-
|
|
1098
|
+
const { linkBalance, linkCli, linkPaymentMethods } = await import("./link-VK7VCE2R.js");
|
|
1087
1099
|
const cli = deps.linkCli ?? linkCli();
|
|
1088
1100
|
const methods = await linkPaymentMethods(cli).catch((error) => {
|
|
1089
1101
|
throw new Error(
|
|
@@ -1184,9 +1196,9 @@ async function changeBudget(deps, input) {
|
|
|
1184
1196
|
if (budget === void 0 || budget < 1e-3)
|
|
1185
1197
|
throw new UsageError("Usage: patron budget <usd>, such as patron budget 10");
|
|
1186
1198
|
} else budget = await askBudget(deps, config.monthlyBudgetUsd);
|
|
1187
|
-
if (config.wallet === "tempo" && budget
|
|
1199
|
+
if (config.wallet === "tempo" && budget >= config.monthlyBudgetUsd) {
|
|
1188
1200
|
step(deps, "Approve the new spending limit in Tempo Wallet");
|
|
1189
|
-
const { authorizeBudget } = await import("./wallet-
|
|
1201
|
+
const { authorizeBudget } = await import("./wallet-6TDMXRWW.js");
|
|
1190
1202
|
const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
|
|
1191
1203
|
fetch: deps.fetch
|
|
1192
1204
|
});
|
|
@@ -1240,8 +1252,9 @@ async function tip(deps, url, amount = "0.10") {
|
|
|
1240
1252
|
throw new Error(
|
|
1241
1253
|
`This tip needs ${tokensUsd(missing)} more than this month's budget allows. Raise it with patron budget <usd>.`
|
|
1242
1254
|
);
|
|
1243
|
-
|
|
1244
|
-
|
|
1255
|
+
const amount2 = Math.max(missing, purchasableTokens(config, usage, PACK_SIZE));
|
|
1256
|
+
step(deps, `Adding ${tokensUsd(amount2)} to your balance`);
|
|
1257
|
+
await buyWithinBudget(settings, config, amount2, deps.openWallet);
|
|
1245
1258
|
}
|
|
1246
1259
|
const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
|
|
1247
1260
|
fetch: deps.fetch
|
|
@@ -1275,16 +1288,17 @@ async function tip(deps, url, amount = "0.10") {
|
|
|
1275
1288
|
if (paid > 0)
|
|
1276
1289
|
await updateUsage(settings.home, (usage) => {
|
|
1277
1290
|
usage.domains[domain] = (usage.domains[domain] ?? 0) + paid;
|
|
1291
|
+
usage.tippedTokens += paid;
|
|
1278
1292
|
});
|
|
1279
1293
|
if (paid === 0)
|
|
1280
1294
|
throw new Error(
|
|
1281
|
-
rejection ? `Patron rejected the tip to ${domain}: ${rejection}.` : `Could not reach Patron to tip ${domain}; your
|
|
1295
|
+
rejection ? `Patron rejected the tip to ${domain}: ${rejection}.` : `Could not reach Patron to tip ${domain}; your balance was kept.`
|
|
1282
1296
|
);
|
|
1283
1297
|
if (paid < count)
|
|
1284
1298
|
say(
|
|
1285
1299
|
deps,
|
|
1286
1300
|
styleText(
|
|
1287
|
-
` ${count - paid} of ${count}
|
|
1301
|
+
` ${tokensUsd(count - paid)} of ${tokensUsd(count)} did not go through.`,
|
|
1288
1302
|
"yellow",
|
|
1289
1303
|
deps.color
|
|
1290
1304
|
)
|
|
@@ -1302,7 +1316,7 @@ async function setName(deps, name) {
|
|
|
1302
1316
|
const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
|
|
1303
1317
|
fetch: deps.fetch
|
|
1304
1318
|
});
|
|
1305
|
-
const open = deps.openWallet ?? (async (s, c, i, max) => (await import("./wallet-
|
|
1319
|
+
const open = deps.openWallet ?? (async (s, c, i, max) => (await import("./wallet-6TDMXRWW.js")).openWallet(s, c.wallet, i, max));
|
|
1306
1320
|
const wallet = await open(settings, config, issuer, 0n);
|
|
1307
1321
|
await setProfile(settings.gatewayUrl, wallet, name, deps.fetch);
|
|
1308
1322
|
await writeConfig(settings.home, { ...config, name });
|
|
@@ -1325,7 +1339,7 @@ async function uninstall(deps) {
|
|
|
1325
1339
|
const prompter = deps.prompter();
|
|
1326
1340
|
try {
|
|
1327
1341
|
purge = await prompter.confirm(
|
|
1328
|
-
`Also delete ${deps.settings.home}${tokensLeft > 0 ? ` and
|
|
1342
|
+
`Also delete ${deps.settings.home}${tokensLeft > 0 ? ` and your unspent balance of ${tokensUsd(tokensLeft)}` : ""}?`,
|
|
1329
1343
|
false
|
|
1330
1344
|
);
|
|
1331
1345
|
} finally {
|
|
@@ -797,6 +797,10 @@ var TOKEN_PRICE_UNITS = 1000n;
|
|
|
797
797
|
var PACK_SIZE = 1e3;
|
|
798
798
|
var MAX_TOKENS_PER_PURCHASE = 5e3;
|
|
799
799
|
var DEFAULT_MONTHLY_BUDGET_USD = 5;
|
|
800
|
+
function accessKeyLimitUnits(budgetUnits) {
|
|
801
|
+
if (budgetUnits <= 0n) return 0n;
|
|
802
|
+
return budgetUnits + 50000n + budgetUnits / 100n;
|
|
803
|
+
}
|
|
800
804
|
var MIN_TOKENS_PER_PAGE = 1;
|
|
801
805
|
var MAX_TOKENS_PER_PAGE = 10;
|
|
802
806
|
var DEFAULT_TOKENS_PER_PAGE = 1;
|
|
@@ -956,36 +960,6 @@ function normalizePayee(input) {
|
|
|
956
960
|
return normalizeDomain(trimmed);
|
|
957
961
|
}
|
|
958
962
|
|
|
959
|
-
// src/settings.ts
|
|
960
|
-
import { homedir } from "node:os";
|
|
961
|
-
import { join } from "node:path";
|
|
962
|
-
var DEFAULT_GATEWAY_URL = "https://patron-gateway.tempo-dev.workers.dev";
|
|
963
|
-
var DEFAULT_RELAY_URL = "https://patron-relay.tempo-dev.workers.dev";
|
|
964
|
-
function resolveSettings(env = process.env) {
|
|
965
|
-
const key = env.PATRON_PRIVATE_KEY?.trim();
|
|
966
|
-
const privateKey = key && /^0x[0-9a-fA-F]{64}$/.test(key) ? key : void 0;
|
|
967
|
-
return {
|
|
968
|
-
gatewayUrl: env.PATRON_GATEWAY_URL || DEFAULT_GATEWAY_URL,
|
|
969
|
-
home: env.PATRON_HOME || join(homedir(), ".patron"),
|
|
970
|
-
network: env.PATRON_NETWORK === "testnet" ? "testnet" : "mainnet",
|
|
971
|
-
overridden: {
|
|
972
|
-
gatewayUrl: Boolean(env.PATRON_GATEWAY_URL),
|
|
973
|
-
network: Boolean(env.PATRON_NETWORK),
|
|
974
|
-
relayUrl: Boolean(env.PATRON_RELAY_URL)
|
|
975
|
-
},
|
|
976
|
-
relayUrl: env.PATRON_RELAY_URL || DEFAULT_RELAY_URL,
|
|
977
|
-
...privateKey ? { privateKey } : {}
|
|
978
|
-
};
|
|
979
|
-
}
|
|
980
|
-
function settingsFor(settings, saved) {
|
|
981
|
-
return {
|
|
982
|
-
...settings,
|
|
983
|
-
gatewayUrl: settings.overridden.gatewayUrl || !saved.gatewayUrl ? settings.gatewayUrl : saved.gatewayUrl,
|
|
984
|
-
network: settings.overridden.network ? settings.network : saved.network,
|
|
985
|
-
relayUrl: settings.overridden.relayUrl || !saved.relayUrl ? settings.relayUrl : saved.relayUrl
|
|
986
|
-
};
|
|
987
|
-
}
|
|
988
|
-
|
|
989
963
|
// ../protocol/src/encoding.ts
|
|
990
964
|
function toBase64Url(bytes) {
|
|
991
965
|
let binary = "";
|
|
@@ -1190,11 +1164,59 @@ function tokensToUnits(tokens) {
|
|
|
1190
1164
|
return BigInt(tokens) * TOKEN_PRICE_UNITS;
|
|
1191
1165
|
}
|
|
1192
1166
|
|
|
1167
|
+
// src/lock.ts
|
|
1168
|
+
import { open, rm, stat } from "node:fs/promises";
|
|
1169
|
+
async function withLock(path, fn, options = {}) {
|
|
1170
|
+
const deadline = Date.now() + (options.timeoutMs ?? 3e3);
|
|
1171
|
+
const staleMs = options.staleMs ?? 1e4;
|
|
1172
|
+
for (; ; ) {
|
|
1173
|
+
try {
|
|
1174
|
+
const handle = await open(path, "wx", 384);
|
|
1175
|
+
await handle.close();
|
|
1176
|
+
break;
|
|
1177
|
+
} catch (error) {
|
|
1178
|
+
if (error.code !== "EEXIST") throw error;
|
|
1179
|
+
const age = await stat(path).then(
|
|
1180
|
+
(stats) => Date.now() - stats.mtimeMs,
|
|
1181
|
+
() => 0
|
|
1182
|
+
);
|
|
1183
|
+
if (age > staleMs) {
|
|
1184
|
+
await rm(path, { force: true });
|
|
1185
|
+
continue;
|
|
1186
|
+
}
|
|
1187
|
+
if (Date.now() > deadline) throw new Error(`Patron state is busy: ${path}`);
|
|
1188
|
+
await new Promise((resolve) => setTimeout(resolve, 10 + Math.random() * 20));
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
try {
|
|
1192
|
+
return await fn();
|
|
1193
|
+
} finally {
|
|
1194
|
+
await rm(path, { force: true });
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
async function tryLock(path, staleMs) {
|
|
1198
|
+
try {
|
|
1199
|
+
const handle = await open(path, "wx", 384);
|
|
1200
|
+
await handle.close();
|
|
1201
|
+
} catch (error) {
|
|
1202
|
+
if (error.code !== "EEXIST") throw error;
|
|
1203
|
+
const age = await stat(path).then(
|
|
1204
|
+
(stats) => Date.now() - stats.mtimeMs,
|
|
1205
|
+
() => 0
|
|
1206
|
+
);
|
|
1207
|
+
if (age <= staleMs) return void 0;
|
|
1208
|
+
await rm(path, { force: true });
|
|
1209
|
+
return tryLock(path, staleMs);
|
|
1210
|
+
}
|
|
1211
|
+
return () => rm(path, { force: true });
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1193
1214
|
export {
|
|
1194
1215
|
TOKEN_PRICE_UNITS,
|
|
1195
1216
|
PACK_SIZE,
|
|
1196
1217
|
MAX_TOKENS_PER_PURCHASE,
|
|
1197
1218
|
DEFAULT_MONTHLY_BUDGET_USD,
|
|
1219
|
+
accessKeyLimitUnits,
|
|
1198
1220
|
MIN_TOKENS_PER_PAGE,
|
|
1199
1221
|
MAX_TOKENS_PER_PAGE,
|
|
1200
1222
|
clampTokensPerPage,
|
|
@@ -1206,6 +1228,6 @@ export {
|
|
|
1206
1228
|
isExcludedByDefault,
|
|
1207
1229
|
formatUsd,
|
|
1208
1230
|
tokensToUnits,
|
|
1209
|
-
|
|
1210
|
-
|
|
1231
|
+
withLock,
|
|
1232
|
+
tryLock
|
|
1211
1233
|
};
|