@getalby/cli 0.0.0 → 0.1.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.
package/README.md CHANGED
@@ -5,10 +5,14 @@ CLI for Nostr Wallet Connect (NIP-47) with lightning tools.
5
5
  ## Usage
6
6
 
7
7
  ```bash
8
- npx @getalby/cli --connection-secret <NWC_CONNECTION_STRING> <command> [options]
8
+ # Pass a file path to a connection secret (preferred)
9
+ npx @getalby/cli -c /path/to/secret.txt <command> [options]
10
+
11
+ # Or pass connection string directly
12
+ npx @getalby/cli -c "nostr+walletconnect://..." <command> [options]
9
13
  ```
10
14
 
11
- The `--connection-secret` (or `-c`) option is required for wallet operations. You can get a connection string from your NWC-compatible wallet (e.g., [Alby](https://getalby.com)).
15
+ The `-c` option auto-detects whether you're passing a connection string or a file path. You can get a connection string from your NWC-compatible wallet (e.g., [Alby](https://getalby.com)).
12
16
 
13
17
  ## Testing Wallet
14
18
 
@@ -48,14 +52,41 @@ npx @getalby/cli -c "nostr+walletconnect://..." make-invoice --amount 1000 --des
48
52
  # Pay an invoice
49
53
  npx @getalby/cli -c "nostr+walletconnect://..." pay-invoice --invoice "lnbc..."
50
54
 
55
+ # Send a keysend payment
56
+ npx @getalby/cli -c "nostr+walletconnect://..." pay-keysend --pubkey "02abc..." --amount 100
57
+
51
58
  # Look up an invoice by payment hash
52
59
  npx @getalby/cli -c "nostr+walletconnect://..." lookup-invoice --payment-hash "abc123..."
53
60
 
54
61
  # List transactions
55
62
  npx @getalby/cli -c "nostr+walletconnect://..." list-transactions --limit 10
56
63
 
64
+ # Get wallet budget
65
+ npx @getalby/cli -c "nostr+walletconnect://..." get-budget
66
+
67
+ # Sign a message
68
+ npx @getalby/cli -c "nostr+walletconnect://..." sign-message --message "Hello, World!"
69
+
57
70
  # Fetch L402-protected resource
58
71
  npx @getalby/cli -c "nostr+walletconnect://..." fetch-l402 --url "https://example.com/api"
72
+
73
+ # Wait for a payment notification
74
+ npx @getalby/cli -c "nostr+walletconnect://..." wait-for-payment --payment-hash "abc123..."
75
+ ```
76
+
77
+ ### HOLD Invoices
78
+
79
+ HOLD invoices allow you to accept payments conditionally - the payment is held until you settle or cancel it.
80
+
81
+ ```bash
82
+ # Create a HOLD invoice (you provide the payment hash)
83
+ npx @getalby/cli -c "nostr+walletconnect://..." make-hold-invoice --amount 1000 --payment-hash "abc123..."
84
+
85
+ # Settle a HOLD invoice (claim the payment)
86
+ npx @getalby/cli -c "nostr+walletconnect://..." settle-hold-invoice --preimage "def456..."
87
+
88
+ # Cancel a HOLD invoice (reject the payment)
89
+ npx @getalby/cli -c "nostr+walletconnect://..." cancel-hold-invoice --payment-hash "abc123..."
59
90
  ```
60
91
 
61
92
  ### Lightning Tools
@@ -66,28 +97,61 @@ These commands don't require a wallet connection:
66
97
  # Convert USD to sats
67
98
  npx @getalby/cli fiat-to-sats --currency USD --amount 10
68
99
 
100
+ # Convert sats to USD
101
+ npx @getalby/cli sats-to-fiat --amount 1000 --currency USD
102
+
69
103
  # Parse a BOLT-11 invoice
70
104
  npx @getalby/cli parse-invoice --invoice "lnbc..."
71
105
 
106
+ # Verify a preimage against an invoice
107
+ npx @getalby/cli verify-preimage --invoice "lnbc..." --preimage "abc123..."
108
+
72
109
  # Request invoice from lightning address
73
- npx @getalby/cli request-invoice --address "hello@getalby.com" --amount 1000
110
+ npx @getalby/cli request-invoice-from-lightning-address --address "hello@getalby.com" --amount 1000
74
111
  ```
75
112
 
76
113
  ## Command Reference
77
114
 
78
- | Command | Description | Required Options |
79
- |---------|-------------|------------------|
80
- | `get-balance` | Get wallet balance | - |
81
- | `get-info` | Get wallet info | - |
82
- | `get-wallet-service-info` | Get wallet capabilities | - |
83
- | `make-invoice` | Create a lightning invoice | `--amount` |
84
- | `pay-invoice` | Pay a lightning invoice | `--invoice` |
85
- | `lookup-invoice` | Look up an invoice | `--payment-hash` or `--invoice` |
86
- | `list-transactions` | List transactions | - |
87
- | `fiat-to-sats` | Convert fiat to sats | `--currency`, `--amount` |
88
- | `parse-invoice` | Parse a BOLT-11 invoice | `--invoice` |
89
- | `request-invoice` | Request invoice from lightning address | `--address`, `--amount` |
90
- | `fetch-l402` | Fetch L402-protected resource | `--url` |
115
+ ### Wallet Commands
116
+
117
+ These require `-c` or `--connection-secret`:
118
+
119
+ | Command | Description | Required Options |
120
+ | ------------------------- | ------------------------------ | ------------------------------- |
121
+ | `get-balance` | Get wallet balance | - |
122
+ | `get-info` | Get wallet info | - |
123
+ | `get-wallet-service-info` | Get wallet capabilities | - |
124
+ | `get-budget` | Get wallet budget | - |
125
+ | `make-invoice` | Create a lightning invoice | `--amount` |
126
+ | `pay-invoice` | Pay a lightning invoice | `--invoice` |
127
+ | `pay-keysend` | Send a keysend payment | `--pubkey`, `--amount` |
128
+ | `lookup-invoice` | Look up an invoice | `--payment-hash` or `--invoice` |
129
+ | `list-transactions` | List transactions | - |
130
+ | `sign-message` | Sign a message with wallet key | `--message` |
131
+ | `wait-for-payment` | Wait for payment notification | `--payment-hash` |
132
+ | `fetch-l402` | Fetch L402-protected resource | `--url` |
133
+
134
+ ### HOLD Invoice Commands
135
+
136
+ These require `-c` or `--connection-secret`:
137
+
138
+ | Command | Description | Required Options |
139
+ | --------------------- | --------------------- | ---------------------------- |
140
+ | `make-hold-invoice` | Create a HOLD invoice | `--amount`, `--payment-hash` |
141
+ | `settle-hold-invoice` | Settle a HOLD invoice | `--preimage` |
142
+ | `cancel-hold-invoice` | Cancel a HOLD invoice | `--payment-hash` |
143
+
144
+ ### Lightning Tools
145
+
146
+ These don't require a wallet connection:
147
+
148
+ | Command | Description | Required Options |
149
+ | ---------------------------------------- | -------------------------------------- | ------------------------- |
150
+ | `fiat-to-sats` | Convert fiat to sats | `--currency`, `--amount` |
151
+ | `sats-to-fiat` | Convert sats to fiat | `--amount`, `--currency` |
152
+ | `parse-invoice` | Parse a BOLT-11 invoice | `--invoice` |
153
+ | `verify-preimage` | Verify preimage against invoice | `--invoice`, `--preimage` |
154
+ | `request-invoice-from-lightning-address` | Request invoice from lightning address | `--address`, `--amount` |
91
155
 
92
156
  ## Output
93
157
 
@@ -1,15 +1,15 @@
1
- import { requestInvoice } from "../tools/lightning/request_invoice.js";
1
+ import { requestInvoiceFromLightningAddress } from "../tools/lightning/request_invoice_from_lightning_address.js";
2
2
  import { handleError, output } from "../utils.js";
3
- export function registerRequestInvoiceCommand(program) {
3
+ export function registerRequestInvoiceFromLightningAddressCommand(program) {
4
4
  program
5
- .command("request-invoice")
6
- .description("Request invoice from lightning address")
5
+ .command("request-invoice-from-lightning-address")
6
+ .description("Request an invoice from a lightning address")
7
7
  .requiredOption("-a, --address <ln-address>", "Lightning address")
8
8
  .requiredOption("-s, --amount <sats>", "Amount in sats", parseInt)
9
9
  .option("--comment <text>", "Optional comment")
10
10
  .action(async (options) => {
11
11
  await handleError(async () => {
12
- const result = await requestInvoice({
12
+ const result = await requestInvoiceFromLightningAddress({
13
13
  lightning_address: options.address,
14
14
  amount_in_sats: options.amount,
15
15
  comment: options.comment,
package/build/index.js CHANGED
@@ -18,14 +18,14 @@ import { registerFiatToSatsCommand } from "./commands/fiat-to-sats.js";
18
18
  import { registerSatsToFiatCommand } from "./commands/sats-to-fiat.js";
19
19
  import { registerParseInvoiceCommand } from "./commands/parse-invoice.js";
20
20
  import { registerVerifyPreimageCommand } from "./commands/verify-preimage.js";
21
- import { registerRequestInvoiceCommand } from "./commands/request-invoice.js";
21
+ import { registerRequestInvoiceFromLightningAddressCommand } from "./commands/request-invoice-from-lightning-address.js";
22
22
  import { registerFetchL402Command } from "./commands/fetch-l402.js";
23
23
  const program = new Command();
24
24
  program
25
25
  .name("alby-cli")
26
26
  .description("CLI for Nostr Wallet Connect (NIP-47) with lightning tools")
27
- .version("0.0.0")
28
- .option("-c, --connection-secret <string>", "NWC connection secret (nostr+walletconnect://...)");
27
+ .version("0.1.0")
28
+ .option("-c, --connection-secret <string>", "NWC connection secret (nostr+walletconnect://...) or path to file containing it (preferred)");
29
29
  // Register all commands
30
30
  registerGetBalanceCommand(program);
31
31
  registerGetBudgetCommand(program);
@@ -45,6 +45,6 @@ registerFiatToSatsCommand(program);
45
45
  registerSatsToFiatCommand(program);
46
46
  registerParseInvoiceCommand(program);
47
47
  registerVerifyPreimageCommand(program);
48
- registerRequestInvoiceCommand(program);
48
+ registerRequestInvoiceFromLightningAddressCommand(program);
49
49
  registerFetchL402Command(program);
50
50
  program.parse();
@@ -0,0 +1,57 @@
1
+ import { describe, test, expect, beforeAll, afterAll } from "vitest";
2
+ import { createTestWallet, runCli } from "./helpers.js";
3
+ import { writeFileSync, unlinkSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ describe("Connection Secret Handling", () => {
7
+ let wallet;
8
+ let secretFilePath;
9
+ let badSecretFilePath;
10
+ beforeAll(async () => {
11
+ wallet = await createTestWallet();
12
+ // Create temp file with valid connection secret
13
+ secretFilePath = join(tmpdir(), `nwc-test-secret-${Date.now()}.txt`);
14
+ writeFileSync(secretFilePath, wallet.nwcUrl);
15
+ // Create temp file with invalid/truncated content
16
+ badSecretFilePath = join(tmpdir(), `nwc-test-bad-secret-${Date.now()}.txt`);
17
+ writeFileSync(badSecretFilePath, "nostr+wallet");
18
+ }, 60000);
19
+ afterAll(() => {
20
+ try {
21
+ unlinkSync(secretFilePath);
22
+ }
23
+ catch { }
24
+ try {
25
+ unlinkSync(badSecretFilePath);
26
+ }
27
+ catch { }
28
+ });
29
+ test("accepts connection string directly", () => {
30
+ const result = runCli(`-c "${wallet.nwcUrl}" get-balance`);
31
+ expect(result.success).toBe(true);
32
+ });
33
+ test("reads connection secret from file", () => {
34
+ const result = runCli(`-c "${secretFilePath}" get-balance`);
35
+ expect(result.success).toBe(true);
36
+ });
37
+ test("errors when file does not exist", () => {
38
+ const result = runCli(`-c "/tmp/nonexistent-file-${Date.now()}" get-balance`);
39
+ expect(result.success).toBe(false);
40
+ expect(result.output.error).toContain("Failed to read connection secret file");
41
+ });
42
+ test("errors when file contains invalid connection string", () => {
43
+ const result = runCli(`-c "${badSecretFilePath}" get-balance`);
44
+ expect(result.success).toBe(false);
45
+ expect(result.output.error).toContain("Invalid connection secret");
46
+ });
47
+ test("errors when no connection secret provided", () => {
48
+ const result = runCli("get-balance");
49
+ expect(result.success).toBe(false);
50
+ expect(result.output.error).toContain("--connection-secret is required");
51
+ });
52
+ test("errors when connection string is malformed", () => {
53
+ const result = runCli(`-c "nostr+walletconnect://asdf" get-balance`);
54
+ expect(result.success).toBe(false);
55
+ expect(result.output.error).toContain("Invalid connection secret");
56
+ });
57
+ });
@@ -28,8 +28,8 @@ describe("Lightning Tools (no wallet required)", () => {
28
28
  expect(result.success).toBe(true);
29
29
  expect(result.output.valid).toBe(false);
30
30
  });
31
- test("request-invoice requests invoice from lightning address", async () => {
32
- const result = runCli(`request-invoice -a "${exampleLightningAddress}" -s 100`);
31
+ test("request-invoice-from-lightning-address requests invoice from lightning address", async () => {
32
+ const result = runCli(`request-invoice-from-lightning-address -a "${exampleLightningAddress}" -s 100`);
33
33
  expect(result.success).toBe(true);
34
34
  expect(result.output.paymentRequest.toLowerCase()).toMatch(/^lnbc/);
35
35
  });
@@ -1,5 +1,5 @@
1
1
  import { LightningAddress } from "@getalby/lightning-tools";
2
- export async function requestInvoice(params) {
2
+ export async function requestInvoiceFromLightningAddress(params) {
3
3
  const ln = new LightningAddress(params.lightning_address);
4
4
  await ln.fetch();
5
5
  const { satoshi, ...invoice } = await ln.requestInvoice({
package/build/utils.js CHANGED
@@ -1,12 +1,47 @@
1
1
  import { NWCClient } from "@getalby/sdk";
2
+ import { readFileSync } from "node:fs";
2
3
  export function getClient(program) {
3
4
  const opts = program.opts();
4
- const connectionSecret = opts.connectionSecret;
5
+ let connectionSecret = opts.connectionSecret;
5
6
  if (!connectionSecret) {
6
7
  console.error("Error: --connection-secret is required for this command");
7
8
  process.exit(1);
8
9
  }
9
- return new NWCClient({ nostrWalletConnectUrl: connectionSecret });
10
+ // Auto-detect: if it doesn't start with the protocol, treat as file path
11
+ if (!connectionSecret.startsWith("nostr+walletconnect://")) {
12
+ try {
13
+ connectionSecret = readFileSync(connectionSecret, "utf-8").trim();
14
+ }
15
+ catch (error) {
16
+ console.error(`Error: Failed to read connection secret file "${opts.connectionSecret}": ${error instanceof Error ? error.message : String(error)}`);
17
+ process.exit(1);
18
+ }
19
+ }
20
+ // Validate the connection string format
21
+ if (!connectionSecret.startsWith("nostr+walletconnect://")) {
22
+ console.error(`Error: Invalid connection secret. Expected format: nostr+walletconnect://...\n` +
23
+ `Got: "${connectionSecret.substring(0, 50)}${connectionSecret.length > 50 ? "..." : ""}"\n` +
24
+ `Hint: Make sure the connection string is complete and not truncated.`);
25
+ process.exit(1);
26
+ }
27
+ const client = new NWCClient({ nostrWalletConnectUrl: connectionSecret });
28
+ // Validate client properties
29
+ if (!client.secret || !/^[0-9a-f]{64}$/i.test(client.secret)) {
30
+ console.error(`Error: Invalid connection secret. Missing or invalid secret key.\n` +
31
+ `Hint: Make sure the connection string is complete and not truncated.`);
32
+ process.exit(1);
33
+ }
34
+ if (!client.walletPubkey || !/^[0-9a-f]{64}$/i.test(client.walletPubkey)) {
35
+ console.error(`Error: Invalid connection secret. Missing or invalid wallet pubkey.\n` +
36
+ `Hint: Make sure the connection string is complete and not truncated.`);
37
+ process.exit(1);
38
+ }
39
+ if (!client.relayUrls) {
40
+ console.error(`Error: Invalid connection secret. Missing relay URL.\n` +
41
+ `Hint: Make sure the connection string is complete and not truncated.`);
42
+ process.exit(1);
43
+ }
44
+ return client;
10
45
  }
11
46
  export function output(data) {
12
47
  console.log(JSON.stringify(data, null, 2));
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.0.0",
5
+ "version": "0.1.0",
6
6
  "type": "module",
7
7
  "main": "build/index.js",
8
8
  "bin": {