@getalby/cli 0.8.0 → 0.9.0

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.
@@ -23,6 +23,29 @@ function parseMaxAmountSats(value) {
23
23
  }
24
24
  return sats;
25
25
  }
26
+ /**
27
+ * Parse and validate the `--credentials` JSON. It must be an object with string
28
+ * `header` and `value` fields, matching the reusable credential emitted in a
29
+ * previous fetch's `payment.credentials`. Rejects anything else so a malformed
30
+ * credential fails loudly instead of being silently ignored by the fetch helper.
31
+ */
32
+ function parseCredentials(value) {
33
+ let parsed;
34
+ try {
35
+ parsed = JSON.parse(value);
36
+ }
37
+ catch {
38
+ throw new InvalidArgumentError("--credentials must be valid JSON (e.g. '{\"header\":\"Authorization\",\"value\":\"L402 ...\"}')");
39
+ }
40
+ if (typeof parsed !== "object" ||
41
+ parsed === null ||
42
+ typeof parsed.header !== "string" ||
43
+ typeof parsed.value !== "string") {
44
+ throw new InvalidArgumentError('--credentials must be a JSON object with string "header" and "value" fields');
45
+ }
46
+ const { header, value: headerValue } = parsed;
47
+ return { header, value: headerValue };
48
+ }
26
49
  export function registerFetch402Command(program) {
27
50
  program
28
51
  .command("fetch")
@@ -36,8 +59,15 @@ export function registerFetch402Command(program) {
36
59
  .option("--currency <code>", "Denomination of --max-amount — currently must be BTC")
37
60
  .option("--unit <sats|BTC>", "Sub-unit of --max-amount — currently must be sats")
38
61
  .option("--network <name>", "Rail for --max-amount — currently must be lightning")
62
+ .option("--credentials <json>", "Reusable payment credential from a previous fetch " +
63
+ '(JSON: {"header":"...","value":"..."}). When set, the request is ' +
64
+ "authorized with it and never pays again — use it to authorize " +
65
+ "follow-up requests (e.g. polling) without re-paying.")
39
66
  .addHelpText("after", "\nExample:\n" +
40
- ' $ npx @getalby/cli fetch "https://example.com/api" --max-amount 1000 --currency BTC --unit sats --network lightning\n')
67
+ ' $ npx @getalby/cli fetch "https://example.com/api" --max-amount 1000 --currency BTC --unit sats --network lightning\n' +
68
+ "\nA successful response includes a `payment` object with the fees paid and a\n" +
69
+ "reusable `credentials` value. Reuse it to avoid paying again:\n" +
70
+ ' $ npx @getalby/cli fetch "https://example.com/api" --credentials \'{"header":"Authorization","value":"L402 ..."}\'\n')
41
71
  .action(async (url, options) => {
42
72
  await handleError(async () => {
43
73
  // A cap must state its denomination, like every other amount. For now
@@ -67,6 +97,9 @@ export function registerFetch402Command(program) {
67
97
  // --unit is restricted to sats above, so --max-amount is already the
68
98
  // sats cap. When omitted, the tool applies its default.
69
99
  maxAmountSats: options.maxAmount,
100
+ credentials: options.credentials
101
+ ? parseCredentials(options.credentials)
102
+ : undefined,
70
103
  });
71
104
  output(result);
72
105
  });
package/build/index.js CHANGED
@@ -40,7 +40,7 @@ program
40
40
  " $ npx @getalby/cli pay alice@getalby.com --amount 100 --currency BTC --unit sats --network lightning\n" +
41
41
  " $ npx @getalby/cli pay alice@getalby.com --amount 5 --currency USD --network lightning\n" +
42
42
  ' $ npx @getalby/cli receive --amount 2100 --currency BTC --unit sats --network lightning --description "Coffee"')
43
- .version("0.8.0")
43
+ .version("0.9.0")
44
44
  .configureHelp({ showGlobalOptions: true })
45
45
  .option("-w, --wallet-name <name>", "Use a named wallet's connection secret (~/.alby-cli/connection-secret-<name>.key)")
46
46
  .option("-c, --connection-secret <string>", "NWC connection secret (nostr+walletconnect://...) or path to file containing it (preferred)")
@@ -1,4 +1,4 @@
1
- import { fetch402 as fetch402Lib } from "@getalby/lightning-tools/402";
1
+ import { fetch402 as fetch402Lib, } from "@getalby/lightning-tools/402";
2
2
  const DEFAULT_MAX_AMOUNT_SATS = 5000;
3
3
  export async function fetch402(client, params) {
4
4
  const method = params.method?.toUpperCase();
@@ -7,10 +7,15 @@ export async function fetch402(client, params) {
7
7
  };
8
8
  if (method && method !== "GET" && method !== "HEAD") {
9
9
  requestOptions.body = params.body;
10
- requestOptions.headers = {
11
- "Content-Type": "application/json",
12
- ...params.headers,
13
- };
10
+ // A body is always passed as JSON, so default the Content-Type. The agent
11
+ // isn't required to set the header itself but might do so anyway, so only
12
+ // add our default when it's absent to avoid a duplicate Content-Type.
13
+ const headers = { ...params.headers };
14
+ const hasContentType = Object.keys(headers).some((key) => key.toLowerCase() === "content-type");
15
+ if (!hasContentType) {
16
+ headers["Content-Type"] = "application/json";
17
+ }
18
+ requestOptions.headers = headers;
14
19
  }
15
20
  else if (params.headers) {
16
21
  requestOptions.headers = params.headers;
@@ -19,6 +24,7 @@ export async function fetch402(client, params) {
19
24
  const result = await fetch402Lib(params.url, requestOptions, {
20
25
  wallet: client,
21
26
  maxAmount: maxAmountSats,
27
+ credentials: params.credentials,
22
28
  });
23
29
  const responseContent = await result.text();
24
30
  if (!result.ok) {
@@ -26,5 +32,11 @@ export async function fetch402(client, params) {
26
32
  }
27
33
  return {
28
34
  content: responseContent,
35
+ // Payment metadata attached by the 402 helper: whether a payment was made,
36
+ // the amount, routing fees (feesPaid, in millisatoshis), and the reusable
37
+ // credential. Pass `credentials` back via --credentials on a follow-up
38
+ // request to authorize it without paying again. Absent when no 402 payment
39
+ // was involved (e.g. an already-open resource).
40
+ payment: result.payment,
29
41
  };
30
42
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@getalby/cli",
3
3
  "description": "CLI for Nostr Wallet Connect (NIP-47) with a few additional useful lightning tools",
4
4
  "repository": "https://github.com/getAlby/cli.git",
5
- "version": "0.8.0",
5
+ "version": "0.9.0",
6
6
  "type": "module",
7
7
  "main": "build/index.js",
8
8
  "bin": {
@@ -36,8 +36,8 @@
36
36
  "node": ">=20"
37
37
  },
38
38
  "dependencies": {
39
- "@getalby/lightning-tools": "^8.1.1",
40
- "@getalby/sdk": "^8.0.1",
39
+ "@getalby/lightning-tools": "^8.2.0",
40
+ "@getalby/sdk": "^8.0.3",
41
41
  "@lendasat/lendaswap-sdk-pure": "^0.2.38",
42
42
  "@noble/hashes": "^2.0.1",
43
43
  "commander": "^14.0.3",