@1sat/cli 0.0.108 → 0.0.110
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 +17 -0
- package/dist/cli.js +125 -26
- package/package.json +1 -1
- package/src/commands/authfetch-request.ts +152 -0
- package/src/commands/authfetch.ts +28 -35
- package/src/help.ts +1 -1
package/README.md
CHANGED
|
@@ -331,3 +331,20 @@ The CLI is pure Bun with no framework. Arg parsing is manual (`src/args.ts`). Bu
|
|
|
331
331
|
## License
|
|
332
332
|
|
|
333
333
|
MIT
|
|
334
|
+
|
|
335
|
+
### Authenticated HTTP requests
|
|
336
|
+
|
|
337
|
+
`1sat authfetch <method> <url> [--body <json|@file>] [--header 'K: V']`
|
|
338
|
+
uses the SDK's BRC-104 AuthFetch with CLI wallet keys. If the SDK reports
|
|
339
|
+
missing response authentication headers, only GET and HEAD may retry using
|
|
340
|
+
plain fetch for public reads. Other methods fail with an unknown-outcome
|
|
341
|
+
warning: verify activity before retrying, since the server may already have
|
|
342
|
+
executed the request.
|
|
343
|
+
|
|
344
|
+
A 402 response requires interactive payment confirmation or explicit `--yes`.
|
|
345
|
+
Without `--yes` and a terminal on both stdin and stdout, the command returns
|
|
346
|
+
`approval_required` with exit status 1 and makes no payment retry. Use `--json`
|
|
347
|
+
for structured output; `satoshis` is included only when the public payment
|
|
348
|
+
header is a nonnegative safe integer of at most 16 decimal digits. Review the
|
|
349
|
+
payment before rerunning with `--yes`; this authorizes the existing SDK payment
|
|
350
|
+
flow. It does not impose a spending cap. `--quiet` suppresses output as usual.
|
package/dist/cli.js
CHANGED
|
@@ -1378,7 +1378,7 @@ var init_help = __esm(() => {
|
|
|
1378
1378
|
{
|
|
1379
1379
|
group: "Advanced",
|
|
1380
1380
|
name: "authfetch",
|
|
1381
|
-
description: "HTTP request with BRC-104 AuthFetch using CLI wallet keys. On 402,
|
|
1381
|
+
description: "HTTP request with BRC-104 AuthFetch using CLI wallet keys. Only GET/HEAD retry public routes without auth. On 402, requires --yes or interactive confirmation; noninteractive calls return approval_required and exit nonzero.",
|
|
1382
1382
|
positional: "<method> <url>",
|
|
1383
1383
|
args: [
|
|
1384
1384
|
{
|
|
@@ -1423,9 +1423,114 @@ var init_help = __esm(() => {
|
|
|
1423
1423
|
];
|
|
1424
1424
|
});
|
|
1425
1425
|
|
|
1426
|
+
// src/commands/authfetch-request.ts
|
|
1427
|
+
import { AuthFetch } from "@bsv/sdk";
|
|
1428
|
+
function createApprovalAuth(wallet) {
|
|
1429
|
+
let approved = false;
|
|
1430
|
+
let submitted = false;
|
|
1431
|
+
let currentRequest;
|
|
1432
|
+
const guarded = new Proxy(wallet, {
|
|
1433
|
+
get(target, property) {
|
|
1434
|
+
if (property === "createAction")
|
|
1435
|
+
return async (...args) => {
|
|
1436
|
+
const satoshis = args[0].outputs?.reduce((sum, output2) => sum + output2.satoshis, 0) ?? 0;
|
|
1437
|
+
if (!Number.isSafeInteger(satoshis) || satoshis <= 0)
|
|
1438
|
+
throw new Error("Invalid HTTP payment amount");
|
|
1439
|
+
if (approved === false)
|
|
1440
|
+
throw new PaymentRequired(satoshis);
|
|
1441
|
+
if (typeof approved === "number" && satoshis !== approved)
|
|
1442
|
+
throw new Error("Payment amount changed; review the new quote before retrying");
|
|
1443
|
+
if (submitted)
|
|
1444
|
+
throw new Error("Payment already submitted; reconcile wallet activity before retrying");
|
|
1445
|
+
submitted = true;
|
|
1446
|
+
const result = await target.createAction(...args);
|
|
1447
|
+
if (currentRequest?.retryCounter === 0)
|
|
1448
|
+
currentRequest.retryCounter = 1;
|
|
1449
|
+
return result;
|
|
1450
|
+
};
|
|
1451
|
+
if (property === "signAction")
|
|
1452
|
+
return async () => {
|
|
1453
|
+
throw new Error("Unexpected HTTP payment signing request");
|
|
1454
|
+
};
|
|
1455
|
+
const value = Reflect.get(target, property, target);
|
|
1456
|
+
return typeof value === "function" ? value.bind(target) : value;
|
|
1457
|
+
}
|
|
1458
|
+
});
|
|
1459
|
+
return {
|
|
1460
|
+
auth: new AuthFetch(guarded),
|
|
1461
|
+
prepareRequest: (config) => {
|
|
1462
|
+
currentRequest = config;
|
|
1463
|
+
},
|
|
1464
|
+
authorizePayment: (satoshis) => {
|
|
1465
|
+
approved = satoshis ?? true;
|
|
1466
|
+
}
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
async function requestWithApproval(url, init, options, dependencies) {
|
|
1470
|
+
const send = () => {
|
|
1471
|
+
const config = {
|
|
1472
|
+
...init,
|
|
1473
|
+
paymentRetryAttempts: 1,
|
|
1474
|
+
...init.method === "GET" || init.method === "HEAD" ? {} : { retryCounter: 1 }
|
|
1475
|
+
};
|
|
1476
|
+
dependencies.prepareRequest?.(config);
|
|
1477
|
+
return dependencies.auth.fetch(url, config);
|
|
1478
|
+
};
|
|
1479
|
+
let res;
|
|
1480
|
+
try {
|
|
1481
|
+
res = await send();
|
|
1482
|
+
} catch (error) {
|
|
1483
|
+
if (error instanceof PaymentRequired) {
|
|
1484
|
+
res = new Response(null, {
|
|
1485
|
+
status: 402,
|
|
1486
|
+
headers: { "x-bsv-payment-satoshis-required": String(error.satoshis) }
|
|
1487
|
+
});
|
|
1488
|
+
} else {
|
|
1489
|
+
const missingAuthentication = error instanceof Error && /^Received HTTP \d{3}(?: [^\n]*)? from /.test(error.message) && (error.message.includes(` from ${url} without valid BSV authentication (missing headers: `) || error.message.includes(` from ${url} without valid BSV authentication (response lacked required BSV auth headers)`));
|
|
1490
|
+
if (!missingAuthentication)
|
|
1491
|
+
throw error;
|
|
1492
|
+
if (init.method !== "GET" && init.method !== "HEAD") {
|
|
1493
|
+
throw new Error("Authentication could not be verified. The request outcome may be unknown; verify activity before retrying.", { cause: error });
|
|
1494
|
+
}
|
|
1495
|
+
res = await dependencies.plainFetch(url, init);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
if (res.status !== 402)
|
|
1499
|
+
return res;
|
|
1500
|
+
const amount = res.headers.get("x-bsv-payment-satoshis-required");
|
|
1501
|
+
const value = amount !== null && /^\d{1,16}$/.test(amount) ? Number(amount) : Number.NaN;
|
|
1502
|
+
const satoshis = Number.isSafeInteger(value) ? value : undefined;
|
|
1503
|
+
const message = satoshis !== undefined ? `Pay ${satoshis} sats for ${init.method} ${url}?` : `Server requires payment (402) for ${init.method} ${url}. Continue?`;
|
|
1504
|
+
if (!options.yes) {
|
|
1505
|
+
if (!options.interactive) {
|
|
1506
|
+
return {
|
|
1507
|
+
error: "approval_required",
|
|
1508
|
+
status: 402,
|
|
1509
|
+
ok: false,
|
|
1510
|
+
message: "Payment requires approval. Review the payment and rerun with --yes to authorize it, or run in an interactive terminal.",
|
|
1511
|
+
...satoshis !== undefined ? { satoshis } : {}
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
if (!await dependencies.confirmPayment(message)) {
|
|
1515
|
+
throw new Error("Payment cancelled.");
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
dependencies.authorizePayment?.(satoshis);
|
|
1519
|
+
return send();
|
|
1520
|
+
}
|
|
1521
|
+
var PaymentRequired;
|
|
1522
|
+
var init_authfetch_request = __esm(() => {
|
|
1523
|
+
PaymentRequired = class PaymentRequired extends Error {
|
|
1524
|
+
satoshis;
|
|
1525
|
+
constructor(satoshis) {
|
|
1526
|
+
super("Payment requires approval");
|
|
1527
|
+
this.satoshis = satoshis;
|
|
1528
|
+
}
|
|
1529
|
+
};
|
|
1530
|
+
});
|
|
1531
|
+
|
|
1426
1532
|
// src/commands/authfetch.ts
|
|
1427
1533
|
import { readFileSync as readFileSync5 } from "node:fs";
|
|
1428
|
-
import { AuthFetch } from "@bsv/sdk";
|
|
1429
1534
|
import { confirm, isCancel as isCancel2 } from "@clack/prompts";
|
|
1430
1535
|
async function handleAuthfetchCommand(args, opts) {
|
|
1431
1536
|
if (!args[0] || args[0] === "help" || args.includes("--help") || args.includes("-h")) {
|
|
@@ -1494,36 +1599,29 @@ Unknown or missing method: ${method ?? ""}`);
|
|
|
1494
1599
|
chain: opts.chain
|
|
1495
1600
|
});
|
|
1496
1601
|
try {
|
|
1497
|
-
const auth =
|
|
1602
|
+
const { auth, authorizePayment, prepareRequest } = createApprovalAuth(walletResult.wallet);
|
|
1498
1603
|
const init = {
|
|
1499
1604
|
method,
|
|
1500
1605
|
headers,
|
|
1501
1606
|
...body !== undefined ? { body } : {}
|
|
1502
1607
|
};
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
throw err;
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
if (res.status === 402) {
|
|
1518
|
-
const satsHeader = res.headers.get("x-bsv-payment-satoshis-required");
|
|
1519
|
-
const sats = satsHeader ? Number(satsHeader) : undefined;
|
|
1520
|
-
const payMsg = sats != null && Number.isFinite(sats) ? `Pay ${sats} sats for ${method} ${url}?` : `Server requires payment (402) for ${method} ${url}. Continue?`;
|
|
1521
|
-
if (!opts.yes) {
|
|
1522
|
-
const ok = await confirm({ message: payMsg });
|
|
1523
|
-
if (isCancel2(ok) || !ok)
|
|
1524
|
-
fatal("Payment cancelled.");
|
|
1608
|
+
const res = await requestWithApproval(url, init, {
|
|
1609
|
+
yes: opts.yes,
|
|
1610
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY)
|
|
1611
|
+
}, {
|
|
1612
|
+
auth,
|
|
1613
|
+
authorizePayment,
|
|
1614
|
+
prepareRequest,
|
|
1615
|
+
plainFetch: fetch,
|
|
1616
|
+
confirmPayment: async (message) => {
|
|
1617
|
+
const ok = await confirm({ message });
|
|
1618
|
+
return !isCancel2(ok) && ok === true;
|
|
1525
1619
|
}
|
|
1526
|
-
|
|
1620
|
+
});
|
|
1621
|
+
if ("error" in res) {
|
|
1622
|
+
output(res, opts);
|
|
1623
|
+
process.exitCode = 1;
|
|
1624
|
+
return;
|
|
1527
1625
|
}
|
|
1528
1626
|
const text = await res.text();
|
|
1529
1627
|
let parsed = text;
|
|
@@ -1562,6 +1660,7 @@ var init_authfetch = __esm(() => {
|
|
|
1562
1660
|
init_help();
|
|
1563
1661
|
init_keys();
|
|
1564
1662
|
init_output();
|
|
1663
|
+
init_authfetch_request();
|
|
1565
1664
|
METHODS = new Set([
|
|
1566
1665
|
"GET",
|
|
1567
1666
|
"POST",
|
package/package.json
CHANGED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { AuthFetch, type WalletInterface } from '@bsv/sdk'
|
|
2
|
+
|
|
3
|
+
class PaymentRequired extends Error {
|
|
4
|
+
constructor(readonly satoshis: number) {
|
|
5
|
+
super('Payment requires approval')
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Enforce approval at the wallet boundary; SDK retry=0 does not disable payment. */
|
|
10
|
+
export function createApprovalAuth(wallet: WalletInterface) {
|
|
11
|
+
let approved: false | number | true = false
|
|
12
|
+
let submitted = false
|
|
13
|
+
let currentRequest: { retryCounter?: number } | undefined
|
|
14
|
+
const guarded = new Proxy(wallet, {
|
|
15
|
+
get(target, property) {
|
|
16
|
+
if (property === 'createAction')
|
|
17
|
+
return async (...args: Parameters<WalletInterface['createAction']>) => {
|
|
18
|
+
const satoshis =
|
|
19
|
+
args[0].outputs?.reduce(
|
|
20
|
+
(sum, output) => sum + output.satoshis,
|
|
21
|
+
0,
|
|
22
|
+
) ?? 0
|
|
23
|
+
if (!Number.isSafeInteger(satoshis) || satoshis <= 0)
|
|
24
|
+
throw new Error('Invalid HTTP payment amount')
|
|
25
|
+
if (approved === false) throw new PaymentRequired(satoshis)
|
|
26
|
+
if (typeof approved === 'number' && satoshis !== approved)
|
|
27
|
+
throw new Error(
|
|
28
|
+
'Payment amount changed; review the new quote before retrying',
|
|
29
|
+
)
|
|
30
|
+
if (submitted)
|
|
31
|
+
throw new Error(
|
|
32
|
+
'Payment already submitted; reconcile wallet activity before retrying',
|
|
33
|
+
)
|
|
34
|
+
submitted = true
|
|
35
|
+
const result = await target.createAction(...args)
|
|
36
|
+
// A verified 402 reached the approved wallet boundary. Permit its
|
|
37
|
+
// one paid send, but not stale-session replay of that send.
|
|
38
|
+
if (currentRequest?.retryCounter === 0)
|
|
39
|
+
currentRequest.retryCounter = 1
|
|
40
|
+
return result
|
|
41
|
+
}
|
|
42
|
+
if (property === 'signAction')
|
|
43
|
+
return async () => {
|
|
44
|
+
throw new Error('Unexpected HTTP payment signing request')
|
|
45
|
+
}
|
|
46
|
+
const value = Reflect.get(target, property, target)
|
|
47
|
+
return typeof value === 'function' ? value.bind(target) : value
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
return {
|
|
51
|
+
auth: new AuthFetch(guarded),
|
|
52
|
+
prepareRequest: (config: { retryCounter?: number }) => {
|
|
53
|
+
currentRequest = config
|
|
54
|
+
},
|
|
55
|
+
authorizePayment: (satoshis?: number) => {
|
|
56
|
+
approved = satoshis ?? true
|
|
57
|
+
},
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface PaymentApprovalRequired {
|
|
62
|
+
error: 'approval_required'
|
|
63
|
+
status: 402
|
|
64
|
+
ok: false
|
|
65
|
+
message: string
|
|
66
|
+
satoshis?: number
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Keep request replay and payment decisions separate from wallet setup/output. */
|
|
70
|
+
export async function requestWithApproval(
|
|
71
|
+
url: string,
|
|
72
|
+
init: RequestInit & { method: string },
|
|
73
|
+
options: { yes?: boolean; interactive: boolean },
|
|
74
|
+
dependencies: {
|
|
75
|
+
auth: Pick<AuthFetch, 'fetch'>
|
|
76
|
+
plainFetch: typeof fetch
|
|
77
|
+
confirmPayment: (message: string) => Promise<boolean>
|
|
78
|
+
authorizePayment?: (satoshis?: number) => void
|
|
79
|
+
prepareRequest?: (config: { retryCounter?: number }) => void
|
|
80
|
+
},
|
|
81
|
+
): Promise<Response | PaymentApprovalRequired> {
|
|
82
|
+
const send = () => {
|
|
83
|
+
const config = {
|
|
84
|
+
...init,
|
|
85
|
+
paymentRetryAttempts: 1,
|
|
86
|
+
...(init.method === 'GET' || init.method === 'HEAD'
|
|
87
|
+
? {}
|
|
88
|
+
: { retryCounter: 1 }),
|
|
89
|
+
}
|
|
90
|
+
dependencies.prepareRequest?.(config)
|
|
91
|
+
return dependencies.auth.fetch(url, config)
|
|
92
|
+
}
|
|
93
|
+
let res: Response
|
|
94
|
+
try {
|
|
95
|
+
res = await send()
|
|
96
|
+
} catch (error) {
|
|
97
|
+
if (error instanceof PaymentRequired) {
|
|
98
|
+
res = new Response(null, {
|
|
99
|
+
status: 402,
|
|
100
|
+
headers: { 'x-bsv-payment-satoshis-required': String(error.satoshis) },
|
|
101
|
+
})
|
|
102
|
+
} else {
|
|
103
|
+
// Match only the SDK's known unauthenticated-response error, not
|
|
104
|
+
// transport, signature verification, or other authentication failures.
|
|
105
|
+
const missingAuthentication =
|
|
106
|
+
error instanceof Error &&
|
|
107
|
+
/^Received HTTP \d{3}(?: [^\n]*)? from /.test(error.message) &&
|
|
108
|
+
(error.message.includes(
|
|
109
|
+
` from ${url} without valid BSV authentication (missing headers: `,
|
|
110
|
+
) ||
|
|
111
|
+
error.message.includes(
|
|
112
|
+
` from ${url} without valid BSV authentication (response lacked required BSV auth headers)`,
|
|
113
|
+
))
|
|
114
|
+
if (!missingAuthentication) throw error
|
|
115
|
+
if (init.method !== 'GET' && init.method !== 'HEAD') {
|
|
116
|
+
throw new Error(
|
|
117
|
+
'Authentication could not be verified. The request outcome may be unknown; verify activity before retrying.',
|
|
118
|
+
{ cause: error },
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
res = await dependencies.plainFetch(url, init)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (res.status !== 402) return res
|
|
126
|
+
|
|
127
|
+
const amount = res.headers.get('x-bsv-payment-satoshis-required')
|
|
128
|
+
const value =
|
|
129
|
+
amount !== null && /^\d{1,16}$/.test(amount) ? Number(amount) : Number.NaN
|
|
130
|
+
const satoshis = Number.isSafeInteger(value) ? value : undefined
|
|
131
|
+
const message =
|
|
132
|
+
satoshis !== undefined
|
|
133
|
+
? `Pay ${satoshis} sats for ${init.method} ${url}?`
|
|
134
|
+
: `Server requires payment (402) for ${init.method} ${url}. Continue?`
|
|
135
|
+
if (!options.yes) {
|
|
136
|
+
if (!options.interactive) {
|
|
137
|
+
return {
|
|
138
|
+
error: 'approval_required',
|
|
139
|
+
status: 402,
|
|
140
|
+
ok: false,
|
|
141
|
+
message:
|
|
142
|
+
'Payment requires approval. Review the payment and rerun with --yes to authorize it, or run in an interactive terminal.',
|
|
143
|
+
...(satoshis !== undefined ? { satoshis } : {}),
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (!(await dependencies.confirmPayment(message))) {
|
|
147
|
+
throw new Error('Payment cancelled.')
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
dependencies.authorizePayment?.(satoshis)
|
|
151
|
+
return send()
|
|
152
|
+
}
|
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 1sat authfetch <method> <url> [--body <json|@file>] [--header 'K: V']...
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Authenticates first; only GET/HEAD may retry public routes without auth.
|
|
7
|
+
* Payment requires --yes or interactive confirmation.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { readFileSync } from 'node:fs'
|
|
11
|
-
import { AuthFetch } from '@bsv/sdk'
|
|
12
11
|
import { confirm, isCancel } from '@clack/prompts'
|
|
13
12
|
import type { GlobalFlags } from '../args.js'
|
|
14
13
|
import { loadContext } from '../context.js'
|
|
15
14
|
import { printCommandHelp } from '../help.js'
|
|
16
15
|
import { loadKey } from '../keys.js'
|
|
17
16
|
import { fatal, output } from '../output.js'
|
|
17
|
+
import { createApprovalAuth, requestWithApproval } from './authfetch-request.js'
|
|
18
18
|
|
|
19
19
|
const METHODS = new Set([
|
|
20
20
|
'GET',
|
|
@@ -107,44 +107,37 @@ export async function handleAuthfetchCommand(
|
|
|
107
107
|
})
|
|
108
108
|
|
|
109
109
|
try {
|
|
110
|
-
const auth =
|
|
110
|
+
const { auth, authorizePayment, prepareRequest } = createApprovalAuth(
|
|
111
|
+
walletResult.wallet,
|
|
112
|
+
)
|
|
111
113
|
const init = {
|
|
112
114
|
method,
|
|
113
115
|
headers,
|
|
114
116
|
...(body !== undefined ? { body } : {}),
|
|
115
117
|
}
|
|
116
118
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
? `Pay ${sats} sats for ${method} ${url}?`
|
|
140
|
-
: `Server requires payment (402) for ${method} ${url}. Continue?`
|
|
141
|
-
|
|
142
|
-
if (!opts.yes) {
|
|
143
|
-
const ok = await confirm({ message: payMsg })
|
|
144
|
-
if (isCancel(ok) || !ok) fatal('Payment cancelled.')
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
res = await auth.fetch(url, init)
|
|
119
|
+
const res = await requestWithApproval(
|
|
120
|
+
url,
|
|
121
|
+
init,
|
|
122
|
+
{
|
|
123
|
+
yes: opts.yes,
|
|
124
|
+
interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
auth,
|
|
128
|
+
authorizePayment,
|
|
129
|
+
prepareRequest,
|
|
130
|
+
plainFetch: fetch,
|
|
131
|
+
confirmPayment: async (message) => {
|
|
132
|
+
const ok = await confirm({ message })
|
|
133
|
+
return !isCancel(ok) && ok === true
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
)
|
|
137
|
+
if ('error' in res) {
|
|
138
|
+
output(res, opts)
|
|
139
|
+
process.exitCode = 1
|
|
140
|
+
return
|
|
148
141
|
}
|
|
149
142
|
|
|
150
143
|
const text = await res.text()
|
package/src/help.ts
CHANGED
|
@@ -763,7 +763,7 @@ export const COMMANDS: CommandSpec[] = [
|
|
|
763
763
|
group: 'Advanced',
|
|
764
764
|
name: 'authfetch',
|
|
765
765
|
description:
|
|
766
|
-
'HTTP request with BRC-104 AuthFetch using CLI wallet keys. On 402,
|
|
766
|
+
'HTTP request with BRC-104 AuthFetch using CLI wallet keys. Only GET/HEAD retry public routes without auth. On 402, requires --yes or interactive confirmation; noninteractive calls return approval_required and exit nonzero.',
|
|
767
767
|
positional: '<method> <url>',
|
|
768
768
|
args: [
|
|
769
769
|
{
|