From 02afe4e65f9e66c83f5daea0dfba42a87aad2ba3 Mon Sep 17 00:00:00 2001 From: panditdhamdhere Date: Thu, 23 Jul 2026 15:09:48 +0530 Subject: [PATCH] fix: honor TEMPO_MAX_SPEND when --max-spend is omitted --- .changelog/tempo-max-spend.md | 5 +++++ src/commands/request.ts | 8 ++++++++ src/request-cli.ts | 7 +++++-- test/request.test.ts | 30 ++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 .changelog/tempo-max-spend.md diff --git a/.changelog/tempo-max-spend.md b/.changelog/tempo-max-spend.md new file mode 100644 index 0000000..f3fbc2b --- /dev/null +++ b/.changelog/tempo-max-spend.md @@ -0,0 +1,5 @@ +--- +wallet-cli: patch +--- + +Honor `TEMPO_MAX_SPEND` when `tempo request --max-spend` is not set. diff --git a/src/commands/request.ts b/src/commands/request.ts index 6f67df6..330e654 100644 --- a/src/commands/request.ts +++ b/src/commands/request.ts @@ -318,7 +318,15 @@ export function parseRequestArgs(argv: readonly string[]): RequestOptions { return { ...options, url }; } +export function applyMaxSpendEnv(options: RequestOptions): RequestOptions { + if (options.maxSpend !== undefined) return options; + const fromEnv = process.env.TEMPO_MAX_SPEND?.trim(); + if (!fromEnv) return options; + return { ...options, maxSpend: fromEnv }; +} + export async function executeRequest(options: RequestOptions, io: RequestRunOptions = {}) { + options = applyMaxSpendEnv(options); const stdout = io.stdout ?? process.stdout; const started = Date.now(); const request = await buildFetchRequest(options); diff --git a/src/request-cli.ts b/src/request-cli.ts index a07d870..992db88 100644 --- a/src/request-cli.ts +++ b/src/request-cli.ts @@ -10,7 +10,10 @@ const args = z.object({ const options = z.object({ "dry-run": z.boolean().optional().describe("Show payment challenge without paying"), - "max-spend": z.string().optional().describe("Hard cap for cumulative payment spend"), + "max-spend": z + .string() + .optional() + .describe("Hard cap for cumulative payment spend (or TEMPO_MAX_SPEND)"), "private-key": z.string().optional().describe("Sign payments with an ephemeral private key"), network: z .string() @@ -216,7 +219,7 @@ function describeRequestCli() { name: "max_spend", long: "--max-spend", value_name: "AMOUNT", - help: "Hard cap for cumulative payment spend", + help: "Hard cap for cumulative payment spend (or TEMPO_MAX_SPEND)", }, { name: "private_key", diff --git a/test/request.test.ts b/test/request.test.ts index e532992..906879b 100644 --- a/test/request.test.ts +++ b/test/request.test.ts @@ -10,6 +10,7 @@ import { Abis as TempoAbis, Channel as TempoChannel, KeyAuthorizationManager } f import { afterEach, describe, expect, it } from "vitest"; import { + applyMaxSpendEnv, buildTopUpTransactionRequest, isSessionInvalidationResponse, parseRequestArgs, @@ -354,6 +355,35 @@ describe("request command", () => { }); }); + it("applies TEMPO_MAX_SPEND when --max-spend is omitted", () => { + const previous = process.env.TEMPO_MAX_SPEND; + process.env.TEMPO_MAX_SPEND = " 2.50 "; + try { + expect(applyMaxSpendEnv(parseRequestArgs(["https://example.com"]))).toMatchObject({ + maxSpend: "2.50", + url: "https://example.com", + }); + } finally { + if (previous === undefined) delete process.env.TEMPO_MAX_SPEND; + else process.env.TEMPO_MAX_SPEND = previous; + } + }); + + it("prefers --max-spend over TEMPO_MAX_SPEND", () => { + const previous = process.env.TEMPO_MAX_SPEND; + process.env.TEMPO_MAX_SPEND = "9.00"; + try { + expect( + applyMaxSpendEnv(parseRequestArgs(["--max-spend", "1.00", "https://example.com"])), + ).toMatchObject({ + maxSpend: "1.00", + }); + } finally { + if (previous === undefined) delete process.env.TEMPO_MAX_SPEND; + else process.env.TEMPO_MAX_SPEND = previous; + } + }); + it("recovers stale session locks left behind by killed request processes", async () => { const home = await useTempHome(); const lockDir = join(home, ".tempo", "wallet", "session-locks");