@tempoxyz/patron 0.0.29 → 0.0.31

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/dist/bin.js CHANGED
@@ -1,17 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire as __patronCreateRequire } from 'node:module'
3
3
  const require = __patronCreateRequire(import.meta.url)
4
+ import {
5
+ inferHome
6
+ } from "./chunks/chunk-NDBTADXZ.js";
7
+ import "./chunks/chunk-GTMLTZRN.js";
4
8
 
5
9
  // src/bin.ts
10
+ if (!process.env.PATRON_HOME) {
11
+ const home = inferHome(process.argv[1]);
12
+ if (home) process.env.PATRON_HOME = home;
13
+ }
6
14
  if (process.argv[2] === "hook") {
7
- const { runHookProcess } = await import("./chunks/hook-process-6WSLYXC7.js");
15
+ const { runHookProcess } = await import("./chunks/hook-process-W3ZK5FT3.js");
8
16
  await runHookProcess().catch(() => void 0);
9
17
  process.exit(0);
10
18
  } else if (process.argv[2] === "pay") {
11
- const { runPayProcess } = await import("./chunks/hook-process-6WSLYXC7.js");
19
+ const { runPayProcess } = await import("./chunks/hook-process-W3ZK5FT3.js");
12
20
  await runPayProcess().catch(() => void 0);
13
21
  process.exit(0);
14
22
  } else {
15
- const { run } = await import("./chunks/-OLVAZG3H.js");
23
+ const { run } = await import("./chunks/-K6MPD575.js");
16
24
  process.exitCode = await run(process.argv.slice(2));
17
25
  }
@@ -21,7 +21,9 @@ import {
21
21
  purchasableTokens,
22
22
  readJsonObject,
23
23
  redeem,
24
+ refillSize,
24
25
  removeCodex,
26
+ storedIssuer,
25
27
  tipTokens,
26
28
  upgradeCodex,
27
29
  withHooksKey,
@@ -29,41 +31,44 @@ import {
29
31
  withPatronStatus,
30
32
  withoutPatronHandlers,
31
33
  writeJsonObject
32
- } from "./chunk-SAEZ54SS.js";
34
+ } from "./chunk-AN64RW3X.js";
33
35
  import {
36
+ awaitRedemptions,
37
+ gatewayTurn,
34
38
  startRefill
35
- } from "./chunk-3CYJJJR3.js";
39
+ } from "./chunk-IIB6TI3U.js";
36
40
  import {
41
+ inferHome,
37
42
  resolveSettings,
38
43
  settingsFor
39
- } from "./chunk-OQXACACU.js";
44
+ } from "./chunk-NDBTADXZ.js";
40
45
  import {
41
- AGENT_IDS,
42
46
  LeaderboardResponse,
43
47
  PatronInfo,
44
- ensureHome,
45
- profileMessage,
46
- readConfig,
47
- readJson,
48
- readUsage,
49
- statePaths,
50
- updateUsage,
51
- writeConfig,
52
- writePrivateFile
53
- } from "./chunk-ZOQJ4CZE.js";
48
+ profileMessage
49
+ } from "./chunk-GBZCXMDZ.js";
54
50
  import {
51
+ AGENT_IDS,
55
52
  DEFAULT_MONTHLY_BUDGET_USD,
56
53
  MAX_TOKENS_PER_PAGE,
57
54
  MIN_TOKENS_PER_PAGE,
58
55
  PACK_SIZE,
59
56
  TOKEN_PRICE_UNITS,
60
57
  clampTokensPerPage,
58
+ ensureHome,
61
59
  formatUsd,
62
60
  normalizePayee,
61
+ readConfig,
62
+ readJson,
63
+ readUsage,
64
+ statePaths,
63
65
  tokensToUnits,
64
66
  tryLock,
65
- withLock
66
- } from "./chunk-EISHX7Q3.js";
67
+ updateUsage,
68
+ withLock,
69
+ writeConfig,
70
+ writePrivateFile
71
+ } from "./chunk-JTPFWITF.js";
67
72
  import "./chunk-GTMLTZRN.js";
68
73
 
69
74
  // src/index.ts
@@ -356,15 +361,16 @@ import {
356
361
  realpath,
357
362
  rename,
358
363
  rm as rm3,
359
- symlink
364
+ symlink,
365
+ writeFile as writeFile2
360
366
  } from "node:fs/promises";
361
367
  import { basename, dirname as dirname3, join as join4 } from "node:path";
362
368
  function stableBin(home) {
363
369
  return join4(home, "cli", "current", "dist", "bin.js");
364
370
  }
365
- async function installStableCli(home, script = process.argv[1]) {
371
+ async function installStableCli(home, script = process.argv[1], anySource = process.platform === "win32" && Boolean(process.env.PATRON_HOME)) {
366
372
  const resolved = script ? await realpath(script).catch(() => void 0) : void 0;
367
- if (!resolved || !/[/\\]_npx[/\\]/.test(resolved) || basename(resolved) !== "bin.js")
373
+ if (!resolved || !anySource && !/[/\\]_npx[/\\]/.test(resolved) || basename(resolved) !== "bin.js")
368
374
  return void 0;
369
375
  const packageDir = dirname3(dirname3(resolved));
370
376
  const { version } = JSON.parse(await readFile3(join4(packageDir, "package.json"), "utf8"));
@@ -377,6 +383,7 @@ async function installStableCli(home, script = process.argv[1]) {
377
383
  await rm3(staging, { force: true, recursive: true });
378
384
  await cp(join4(packageDir, "dist"), join4(staging, "dist"), { recursive: true });
379
385
  await cp(join4(packageDir, "package.json"), join4(staging, "package.json"));
386
+ await writeFile2(join4(staging, "origin.json"), JSON.stringify({ bin: resolved }));
380
387
  await rm3(target, { force: true, recursive: true });
381
388
  await rename(staging, target);
382
389
  }
@@ -549,23 +556,45 @@ function failure(agent, error) {
549
556
  state: "failed"
550
557
  };
551
558
  }
552
- async function hookCommand(env = process.env, script = process.argv[1], node = process.execPath, patronHome = env.PATRON_HOME || join5(homedir(), ".patron")) {
559
+ async function hookCommand(env = process.env, script = process.argv[1], node = process.execPath, patronHome = env.PATRON_HOME || join5(homedir(), ".patron"), platform = process.platform) {
553
560
  if (env.PATRON_HOOK_COMMAND) return env.PATRON_HOOK_COMMAND;
554
- return withPatronHome(await runCommand(script, node, patronHome), env.PATRON_HOME);
555
- }
556
- async function runCommand(script, node, patronHome) {
561
+ const windows = platform === "win32";
562
+ const run2 = await runCommand(
563
+ script,
564
+ node,
565
+ patronHome,
566
+ windows && Boolean(env.PATRON_HOME),
567
+ platform
568
+ );
569
+ if (!env.PATRON_HOME || windows || await runsFromHome(run2.bin, patronHome))
570
+ return run2.command;
571
+ return withPatronHome(run2.command, env.PATRON_HOME);
572
+ }
573
+ async function runCommand(script, node, patronHome, preferCopy, platform) {
574
+ const run2 = (bin) => ({
575
+ bin,
576
+ command: `${quote(node, platform)} ${quote(bin, platform)} hook`
577
+ });
578
+ const stable = stableBin(patronHome);
579
+ if (preferCopy && await exists(stable)) return run2(stable);
557
580
  const resolved = script ? await realpath2(script).catch(() => void 0) : void 0;
558
581
  if (resolved && /[/\\]bin\.js$/.test(resolved) && !/[/\\]_npx[/\\]/.test(resolved))
559
- return `${quote(node)} ${quote(resolved)} hook`;
560
- if (await exists(stableBin(patronHome)))
561
- return `${quote(node)} ${quote(stableBin(patronHome))} hook`;
562
- return "npx -y @tempoxyz/patron hook";
582
+ return run2(resolved);
583
+ if (await exists(stable)) return run2(stable);
584
+ return { command: "npx -y @tempoxyz/patron hook" };
585
+ }
586
+ async function runsFromHome(bin, patronHome) {
587
+ const inferred = inferHome(bin);
588
+ if (!inferred) return false;
589
+ const real = (path) => realpath2(path).catch(() => resolve(path));
590
+ return await real(inferred) === await real(patronHome);
563
591
  }
564
592
  function withPatronHome(command, patronHome) {
565
593
  return patronHome ? `PATRON_HOME=${quote(resolve(patronHome))} ${command}` : command;
566
594
  }
567
- function quote(value) {
568
- return /^[\w./:@-]+$/.test(value) ? value : `'${value.replaceAll("'", "'\\''")}'`;
595
+ function quote(value, platform = process.platform) {
596
+ if (/^[\w./:@-]+$/.test(value)) return value;
597
+ return platform === "win32" ? `"${value}"` : `'${value.replaceAll("'", "'\\''")}'`;
569
598
  }
570
599
  async function exists(path) {
571
600
  return access2(path).then(
@@ -751,10 +780,10 @@ async function linkRefillFailedAt(home) {
751
780
  }
752
781
  var defaultOpenWallet = async (settings, config, issuer, maxUnits) => {
753
782
  if (config.wallet === "link") {
754
- const { openLinkWallet } = await import("./wallet-LOLL66ID.js");
783
+ const { openLinkWallet } = await import("./wallet-WR6EBMN6.js");
755
784
  return openLinkWallet(config, maxUnits);
756
785
  }
757
- const { openWallet } = await import("./wallet-LOLL66ID.js");
786
+ const { openWallet } = await import("./wallet-WR6EBMN6.js");
758
787
  return openWallet(settings, config.wallet, issuer, maxUnits);
759
788
  };
760
789
  var REFILL_LOCK_STALE_MS = 5 * 60 * 1e3;
@@ -794,23 +823,43 @@ async function delayedRefill(base, openWallet = defaultOpenWallet, sleep = (ms)
794
823
  if (!await readConfig(base.home)) return 0;
795
824
  const release = await tryLock(
796
825
  statePaths(base.home).refillWait,
797
- REFILL_DELAY_MS.max + REFILL_LOCK_STALE_MS
826
+ REFILL_DELAY_MS.max + REFILL_GATEWAY_WAIT_MS + REFILL_LOCK_STALE_MS
798
827
  );
799
828
  if (!release) return 0;
800
829
  try {
801
830
  await sleep(
802
831
  REFILL_DELAY_MS.min + random() * (REFILL_DELAY_MS.max - REFILL_DELAY_MS.min)
803
832
  );
833
+ return await refill(base, openWallet, Date.now, sleep);
804
834
  } finally {
805
835
  await release();
806
836
  }
807
- return refill(base, openWallet);
808
837
  }
809
- async function refill(base, openWallet = defaultOpenWallet, now = Date.now) {
838
+ var REFILL_GATEWAY_WAIT_MS = 15 * 60 * 1e3;
839
+ async function refill(base, openWallet = defaultOpenWallet, now = Date.now, sleep) {
810
840
  const config = await readConfig(base.home);
811
841
  if (!config || config.paused) return 0;
812
842
  const settings = settingsFor(base, config);
813
- await loadIssuer(settings.home, settings.gatewayUrl).catch(() => void 0);
843
+ const stale = (await storedIssuer(settings.home, settings.gatewayUrl))?.stale ?? true;
844
+ const low = needsRefill(await new FileTokenStore(settings.home).count()) && await linkBackedOff(settings.home, config, now()) === false && await readUsage(settings.home).then(
845
+ (usage) => refillSize(config, usage) > 0,
846
+ () => true
847
+ );
848
+ if (!stale && !low) return 0;
849
+ const bought = await gatewayTurn(
850
+ settings.home,
851
+ async () => {
852
+ const current = await readConfig(base.home);
853
+ if (!current || current.paused) return 0;
854
+ const latest = settingsFor(base, current);
855
+ if (stale) await loadIssuer(latest.home, latest.gatewayUrl).catch(() => void 0);
856
+ return low ? refillLocked(latest, current, openWallet, now) : 0;
857
+ },
858
+ { maxWaitMs: REFILL_GATEWAY_WAIT_MS, ...sleep ? { sleep } : {} }
859
+ );
860
+ return bought ?? 0;
861
+ }
862
+ async function refillLocked(settings, config, openWallet, now) {
814
863
  const release = await tryLock(
815
864
  statePaths(settings.home).refillLock,
816
865
  REFILL_LOCK_STALE_MS
@@ -820,8 +869,7 @@ async function refill(base, openWallet = defaultOpenWallet, now = Date.now) {
820
869
  if (!needsRefill(await new FileTokenStore(settings.home).count())) return 0;
821
870
  if (config.wallet !== "link")
822
871
  return await buyWithinBudget(settings, config, PACK_SIZE, openWallet);
823
- const failedAt = await linkRefillFailedAt(settings.home);
824
- if (failedAt !== void 0 && now() - failedAt < LINK_REFILL_BACKOFF_MS) return 0;
872
+ if (await linkBackedOff(settings.home, config, now())) return 0;
825
873
  const path = statePaths(settings.home).linkRefill;
826
874
  try {
827
875
  const bought = await buyWithinBudget(settings, config, PACK_SIZE, openWallet);
@@ -835,6 +883,11 @@ async function refill(base, openWallet = defaultOpenWallet, now = Date.now) {
835
883
  await release();
836
884
  }
837
885
  }
886
+ async function linkBackedOff(home, config, now) {
887
+ if (config.wallet !== "link") return false;
888
+ const failedAt = await linkRefillFailedAt(home);
889
+ return failedAt !== void 0 && now - failedAt < LINK_REFILL_BACKOFF_MS;
890
+ }
838
891
 
839
892
  // src/render.ts
840
893
  function tokensUsd(tokens) {
@@ -871,9 +924,20 @@ function formatStatus(view, color) {
871
924
  ),
872
925
  row(
873
926
  "Rank",
874
- standing?.rank ? `#${standing.rank} \xB7 ${tokensUsd(standing.tokens)} added` : styleText("not ranked yet", "dim", color),
927
+ standing?.rank ? `#${standing.rank} \xB7 ${tokensUsd(standing.tokens)} added${view.standingSkipped ? styleText(" (last check)", "dim", color) : ""}` : view.standingSkipped ? styleText("not checked right now", "dim", color) : styleText("not ranked yet", "dim", color),
875
928
  color
876
929
  ),
930
+ ...view.standingSkipped ? [
931
+ row(
932
+ "",
933
+ styleText(
934
+ "Checked once your agents' payments go quiet, so the two can't be linked.",
935
+ "dim",
936
+ color
937
+ ),
938
+ color
939
+ )
940
+ ] : [],
877
941
  row(
878
942
  "Agents",
879
943
  config.agents.length > 0 ? config.agents.map((agent) => AGENT_LABELS[agent]).join(", ") : styleText("none", "dim", color),
@@ -925,6 +989,76 @@ PATRON_WALLET=link (pay with Link through link-cli), PATRON_LINK_CLI (its path).
925
989
  var UsageError = class extends Error {
926
990
  };
927
991
  var TIP_BATCH = 8;
992
+ var TIP_REDEEM_TIMEOUT_MS = 3e4;
993
+ var TIP_BATCH_LEASE_MS = 6e4;
994
+ async function inGatewayTurn(deps, fn) {
995
+ const result = await gatewayTurn(
996
+ deps.settings.home,
997
+ async () => ({ value: await fn() }),
998
+ gatewayWaiting(deps)
999
+ );
1000
+ return result.value;
1001
+ }
1002
+ function gatewayWaiting(deps) {
1003
+ return {
1004
+ ...waiting(deps),
1005
+ onWait: (ms) => say(
1006
+ deps,
1007
+ styleText(
1008
+ ` Waiting ${minutes(ms)} after the last payment, so Patron can't link the two.`,
1009
+ "dim",
1010
+ deps.color
1011
+ )
1012
+ )
1013
+ };
1014
+ }
1015
+ async function currentIssuer(deps, settings) {
1016
+ const stored = await storedIssuer(settings.home, settings.gatewayUrl);
1017
+ if (stored && !stored.stale) return stored.issuer;
1018
+ return inGatewayTurn(
1019
+ deps,
1020
+ () => loadIssuer(settings.home, settings.gatewayUrl, { fetch: deps.fetch, fresh: true })
1021
+ );
1022
+ }
1023
+ async function standingFor(deps, settings, config) {
1024
+ const address = config.address.toLowerCase();
1025
+ if (!address) return {};
1026
+ const path = statePaths(settings.home).standing;
1027
+ const fetched = await gatewayTurn(
1028
+ settings.home,
1029
+ async () => ({
1030
+ standing: await fetchStanding(
1031
+ settings.gatewayUrl,
1032
+ address,
1033
+ config.name,
1034
+ deps.fetch
1035
+ ).catch(() => void 0)
1036
+ }),
1037
+ { maxWaitMs: 0, want: false }
1038
+ ).catch(() => void 0);
1039
+ if (fetched) {
1040
+ if (fetched.standing)
1041
+ await writePrivateFile(
1042
+ path,
1043
+ JSON.stringify({
1044
+ address,
1045
+ gatewayUrl: settings.gatewayUrl,
1046
+ standing: fetched.standing
1047
+ })
1048
+ ).catch(() => void 0);
1049
+ return { standing: fetched.standing };
1050
+ }
1051
+ const cached = await readJson(path).catch(() => void 0);
1052
+ const last = cached?.address === address && cached.gatewayUrl === settings.gatewayUrl ? cached.standing : void 0;
1053
+ return { skipped: true, standing: last };
1054
+ }
1055
+ function waiting(deps) {
1056
+ return deps.sleep ? { sleep: deps.sleep } : {};
1057
+ }
1058
+ function minutes(ms) {
1059
+ const count = Math.max(1, Math.ceil(ms / 6e4));
1060
+ return count === 1 ? "about a minute" : `about ${count} minutes`;
1061
+ }
928
1062
  function defaults() {
929
1063
  const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
930
1064
  const color = supportsColor(process.stdout);
@@ -936,7 +1070,7 @@ function defaults() {
936
1070
  prompter: () => createPrompter(process.stdout, color),
937
1071
  settings: resolveSettings(),
938
1072
  stderr: process.stderr,
939
- startRefill: () => startRefill(),
1073
+ startRefill: (options) => startRefill(options),
940
1074
  stdout: process.stdout
941
1075
  };
942
1076
  }
@@ -1086,10 +1220,13 @@ async function setup(deps) {
1086
1220
  const settings = deps.settings;
1087
1221
  say(deps, scrollBanner(VERSION, deps.color));
1088
1222
  say(deps);
1089
- const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
1090
- fetch: deps.fetch,
1091
- fresh: true
1092
- }).catch((error) => {
1223
+ const issuer = await inGatewayTurn(
1224
+ deps,
1225
+ () => loadIssuer(settings.home, settings.gatewayUrl, {
1226
+ fetch: deps.fetch,
1227
+ fresh: true
1228
+ })
1229
+ ).catch((error) => {
1093
1230
  throw new Error(`Cannot reach Patron at ${settings.gatewayUrl}: ${error.message}`);
1094
1231
  });
1095
1232
  const budget = await askBudget(deps, DEFAULT_MONTHLY_BUDGET_USD);
@@ -1114,7 +1251,10 @@ async function setup(deps) {
1114
1251
  const starter = config.wallet === "link" ? PACK_SIZE : STARTER_TOKENS;
1115
1252
  const first = purchasableTokens(config, await readUsage(settings.home), starter);
1116
1253
  step(deps, `Adding ${tokensUsd(first)} to your balance`);
1117
- const bought = await buyWithinBudget(settings, config, starter, deps.openWallet);
1254
+ const bought = await inGatewayTurn(
1255
+ deps,
1256
+ () => buyWithinBudget(settings, config, starter, deps.openWallet)
1257
+ );
1118
1258
  done(deps, `${tokensUsd(bought)} ready to pay sites`);
1119
1259
  deps.startRefill();
1120
1260
  await installStableCli(settings.home).catch(() => void 0);
@@ -1163,7 +1303,7 @@ async function tempoSignIn(deps, budgetUnits, issuer) {
1163
1303
  deps,
1164
1304
  deps.settings.privateKey ? "Using PATRON_PRIVATE_KEY" : "Signing in with Tempo Wallet"
1165
1305
  );
1166
- const { signIn } = await import("./wallet-LOLL66ID.js");
1306
+ const { signIn } = await import("./wallet-WR6EBMN6.js");
1167
1307
  const account = await signIn(deps.settings, {
1168
1308
  budgetUnits,
1169
1309
  issuer,
@@ -1221,18 +1361,23 @@ async function askBudget(deps, fallback) {
1221
1361
  }
1222
1362
  async function status(deps, menu) {
1223
1363
  const { config, settings } = await loadSetup(deps);
1224
- const [tokensLeft, usage, standing, refillFailedAt] = await Promise.all([
1364
+ const [tokensLeft, usage, rank, refillFailedAt] = await Promise.all([
1225
1365
  new FileTokenStore(settings.home).count(),
1226
1366
  readUsage(settings.home),
1227
- config.address ? fetchStanding(settings.gatewayUrl, config.address, config.name, deps.fetch).catch(
1228
- () => void 0
1229
- ) : void 0,
1367
+ standingFor(deps, settings, config),
1230
1368
  config.wallet === "link" ? linkRefillFailedAt(settings.home) : void 0
1231
1369
  ]);
1232
1370
  say(
1233
1371
  deps,
1234
1372
  formatStatus(
1235
- { config, linkRefillFailedAt: refillFailedAt, standing, tokensLeft, usage },
1373
+ {
1374
+ config,
1375
+ linkRefillFailedAt: refillFailedAt,
1376
+ standing: rank.standing,
1377
+ ...rank.skipped ? { standingSkipped: true } : {},
1378
+ tokensLeft,
1379
+ usage
1380
+ },
1236
1381
  deps.color
1237
1382
  )
1238
1383
  );
@@ -1277,10 +1422,8 @@ async function changeBudget(deps, input) {
1277
1422
  } else budget = await askBudget(deps, config.monthlyBudgetUsd);
1278
1423
  if (config.wallet === "tempo" && budget >= config.monthlyBudgetUsd) {
1279
1424
  step(deps, "Approve the new spending limit in Tempo Wallet");
1280
- const { authorizeBudget } = await import("./wallet-LOLL66ID.js");
1281
- const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
1282
- fetch: deps.fetch
1283
- });
1425
+ const { authorizeBudget } = await import("./wallet-WR6EBMN6.js");
1426
+ const issuer = await currentIssuer(deps, settings);
1284
1427
  await authorizeBudget(settings, {
1285
1428
  budgetUnits: BigInt(budgetTokens(budget)) * TOKEN_PRICE_UNITS,
1286
1429
  issuer,
@@ -1333,11 +1476,37 @@ async function tip(deps, url, amount = "0.10") {
1333
1476
  );
1334
1477
  const amount2 = Math.max(missing, purchasableTokens(config, usage, PACK_SIZE));
1335
1478
  step(deps, `Adding ${tokensUsd(amount2)} to your balance`);
1336
- await buyWithinBudget(settings, config, amount2, deps.openWallet);
1479
+ await inGatewayTurn(
1480
+ deps,
1481
+ () => buyWithinBudget(settings, config, amount2, deps.openWallet)
1482
+ );
1337
1483
  }
1338
- const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
1339
- fetch: deps.fetch
1484
+ const stored = await storedIssuer(settings.home, settings.gatewayUrl);
1485
+ let issuer = stored?.issuer ?? await inGatewayTurn(
1486
+ deps,
1487
+ () => loadIssuer(settings.home, settings.gatewayUrl, { fetch: deps.fetch, fresh: true })
1488
+ );
1489
+ let stale = stored?.stale ?? false;
1490
+ let refreshed = false;
1491
+ const redeemFetch = (input, init) => deps.fetch(input, { ...init, signal: AbortSignal.timeout(TIP_REDEEM_TIMEOUT_MS) });
1492
+ let told = false;
1493
+ const claimBatch = (cancelled) => awaitRedemptions(settings.home, TIP_BATCH_LEASE_MS, {
1494
+ ...waiting(deps),
1495
+ ...cancelled ? { cancelled } : {},
1496
+ onWait: (ms) => {
1497
+ if (told) return;
1498
+ told = true;
1499
+ say(
1500
+ deps,
1501
+ styleText(
1502
+ ` Waiting ${minutes(ms)} after a recent purchase, so Patron can't link it to this tip. Ctrl-C keeps your balance.`,
1503
+ "dim",
1504
+ deps.color
1505
+ )
1506
+ );
1507
+ }
1340
1508
  });
1509
+ await claimBatch();
1341
1510
  let stopped = false;
1342
1511
  const stop = () => {
1343
1512
  stopped = true;
@@ -1349,8 +1518,11 @@ async function tip(deps, url, amount = "0.10") {
1349
1518
  let paid = 0;
1350
1519
  let sent = 0;
1351
1520
  let rejection;
1521
+ let claimed = true;
1352
1522
  try {
1353
1523
  while (sent < count && !stopped) {
1524
+ if (!claimed && !await claimBatch(() => stopped)) break;
1525
+ claimed = false;
1354
1526
  const batch = await store.takeMany(Math.min(TIP_BATCH, count - sent));
1355
1527
  if (batch.length === 0) break;
1356
1528
  sent += batch.length;
@@ -1360,7 +1532,7 @@ async function tip(deps, url, amount = "0.10") {
1360
1532
  batch.map(
1361
1533
  (token) => redeem({
1362
1534
  domain,
1363
- fetch: deps.fetch,
1535
+ fetch: redeemFetch,
1364
1536
  issuer,
1365
1537
  relayUrl: settings.relayUrl,
1366
1538
  token
@@ -1393,12 +1565,31 @@ async function tip(deps, url, amount = "0.10") {
1393
1565
  deps.color
1394
1566
  )
1395
1567
  );
1396
- if (ok === 0 && (rejected > 0 || unsent.length > 0)) break;
1568
+ if (ok === 0 && (rejected > 0 || unsent.length > 0)) {
1569
+ if (rejected === 0 && stale && !refreshed) {
1570
+ refreshed = true;
1571
+ const fresh = await gatewayTurn(
1572
+ settings.home,
1573
+ () => loadIssuer(settings.home, settings.gatewayUrl, {
1574
+ fetch: deps.fetch,
1575
+ fresh: true
1576
+ }),
1577
+ { ...gatewayWaiting(deps), cancelled: () => stopped }
1578
+ ).catch(() => void 0);
1579
+ if (fresh) {
1580
+ issuer = fresh;
1581
+ stale = false;
1582
+ continue;
1583
+ }
1584
+ }
1585
+ break;
1586
+ }
1397
1587
  }
1398
1588
  } finally {
1399
1589
  process.off("SIGINT", stop);
1400
1590
  process.off("SIGTERM", stop);
1401
1591
  }
1592
+ if (stale) deps.startRefill({ delayed: true });
1402
1593
  if (stopped && sent < count)
1403
1594
  throw new Error(
1404
1595
  `Tip stopped: tipped ${domain} ${tokensUsd(paid)} of ${tokensUsd(count)}; the rest stays in your balance.`
@@ -1426,12 +1617,13 @@ async function setName(deps, name) {
1426
1617
  throw new UsageError(
1427
1618
  "Leaderboard names belong to Tempo addresses; Link purchases are not ranked."
1428
1619
  );
1429
- const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
1430
- fetch: deps.fetch
1431
- });
1432
- const open = deps.openWallet ?? (async (s, c, i, max) => (await import("./wallet-LOLL66ID.js")).openWallet(s, c.wallet, i, max));
1620
+ const issuer = await currentIssuer(deps, settings);
1621
+ const open = deps.openWallet ?? (async (s, c, i, max) => (await import("./wallet-WR6EBMN6.js")).openWallet(s, c.wallet, i, max));
1433
1622
  const wallet = await open(settings, config, issuer, 0n);
1434
- await setProfile(settings.gatewayUrl, wallet, name, deps.fetch);
1623
+ await inGatewayTurn(
1624
+ deps,
1625
+ () => setProfile(settings.gatewayUrl, wallet, name, deps.fetch)
1626
+ );
1435
1627
  await writeConfig(settings.home, { ...config, name });
1436
1628
  done(deps, `Leaderboard name set to ${name}.`);
1437
1629
  }
@@ -3,7 +3,7 @@ const require = __patronCreateRequire(import.meta.url)
3
3
  import {
4
4
  isExcludedByDefault,
5
5
  normalizePayee
6
- } from "./chunk-EISHX7Q3.js";
6
+ } from "./chunk-JTPFWITF.js";
7
7
 
8
8
  // src/hook-input.ts
9
9
  var HOOK_TIMEOUT_MS = 2e3;
@@ -3,22 +3,22 @@ const require = __patronCreateRequire(import.meta.url)
3
3
  import {
4
4
  IssueResponse,
5
5
  IssuerInfo,
6
- RedeemResponse,
7
- ensureHome,
8
- readJson,
9
- statePaths,
10
- writePrivateFile
11
- } from "./chunk-ZOQJ4CZE.js";
6
+ RedeemResponse
7
+ } from "./chunk-GBZCXMDZ.js";
12
8
  import {
13
9
  ISSUER_NAME,
14
10
  MAX_TOKENS_PER_PURCHASE,
15
11
  PACK_SIZE,
16
12
  TOKEN_PRICE_UNITS,
17
13
  TOKEN_TYPE,
14
+ ensureHome,
18
15
  fromBase64Url,
16
+ readJson,
17
+ statePaths,
19
18
  toBase64Url,
20
- withLock
21
- } from "./chunk-EISHX7Q3.js";
19
+ withLock,
20
+ writePrivateFile
21
+ } from "./chunk-JTPFWITF.js";
22
22
  import {
23
23
  __commonJS,
24
24
  __export,