@ldgr/cli 0.2.2 → 0.4.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
@@ -1,6 +1,6 @@
1
1
  # @ldgr/cli
2
2
 
3
- LDGR's self-custody terminal wallet. Version 0.2.0 creates or imports local wallets, lets you select between them, shows addresses and balances, sends native LDGR or a token, and persistently switches the selected wallet between mainnet and testnet.
3
+ LDGR's self-custody terminal wallet. Version 0.4.0 creates or imports local wallets, lets you select between them, shows addresses and balances, sends native Ledra or a token, and persistently switches the selected wallet between mainnet and testnet.
4
4
 
5
5
  ```bash
6
6
  npm install -g @ldgr/cli
@@ -13,7 +13,8 @@ ldgr address
13
13
  ldgr balance
14
14
  ldgr send ldgr1… 2.5
15
15
  ldgr send-token t1abcdef01234567 ldgr1… 10
16
+ ldgr network show
16
17
  ldgr network set testnet
17
18
  ```
18
19
 
19
- The default owner-only wallet store lives at `~/.ldgr/wallet.json`. On first use, an existing `~/.config/ldgr/wallet.json` store is validated, copied to the new owner-only location, and removed from its former location. At creation/import you can choose passphrase protection or an **unprotected** wallet, which follows the extension model and relies only on the local file's permissions. `wallet list` shows one-based indexes and marks the active wallet; `wallet select <index>` changes it without exposing a secret. `wallet export <path>` writes a `0600` `ldgr-recovery-key.txt` file containing the raw recovery-key value accepted by the extension; `wallet import <path>` reads the same file. Testnet prints a warning on every wallet command and only uses `https://tst.ldgr.ltd`.
20
+ The default owner-only wallet store lives at `~/.ldgr/wallet.json`. Pass `--wallet <path>` to any command to use a different store. On first use, an existing `~/.config/ldgr/wallet.json` store is validated, copied to the new owner-only location, and removed from its former location; an explicit `--wallet` path is never moved. On Windows, the CLI uses the native `USERPROFILE`/`APPDATA` locations and path separators, and relies on the file's native ACLs instead of POSIX mode bits. At creation/import you can choose passphrase protection or an **unprotected** wallet, which follows the extension model and relies only on the local file's permissions. `wallet list` shows one-based indexes and marks the active wallet; `wallet select <index>` changes it without exposing a secret. `wallet export <path>` writes an owner-only `ldgr-recovery-key.txt` file containing the raw recovery-key value accepted by the extension; `wallet import <path>` reads the same file. `--testnet` is available only when creating or importing a wallet; use `network set testnet` for an existing wallet. Testnet prints a warning on every wallet command and only uses `https://tst.ldgr.ltd`.
package/dist/cli.js CHANGED
@@ -11,48 +11,14 @@ import {
11
11
  import { readFile as readFile2 } from "node:fs/promises";
12
12
 
13
13
  // src/transfer.ts
14
- import {
15
- canonicalizeLedgerAddress,
16
- formatAtomicAmount,
17
- parseDecimalAmount
18
- } from "@ldgr/protocol";
19
- async function buildTransferSubmission(input) {
20
- const recipient = canonicalizeLedgerAddress(input.to, input.wallet.ledgerId);
21
- const amount = parseDecimalAmount(input.amount.trim(), input.assetDefinition);
22
- if (amount <= 0n)
23
- throw new RangeError("Amount must be greater than zero");
24
- if (!/^(0|[1-9][0-9]*)$/.test(input.nextNonce))
25
- throw new TypeError("Ledger returned an invalid next nonce");
26
- const payload = {
27
- version: 1,
28
- action: "transfer",
29
- chain: "ldgr-v1",
30
- ledgerId: input.wallet.ledgerId,
31
- asset: input.asset,
32
- from: input.wallet.address,
33
- to: recipient,
34
- amount,
35
- nonce: BigInt(input.nextNonce),
36
- timestamp: BigInt((input.now ?? Date.now)()),
37
- publicKey: input.wallet.publicKey
38
- };
39
- const signature = await input.wallet.sign(payload);
40
- return {
41
- payload: {
42
- ...payload,
43
- amount: formatAtomicAmount(amount, input.assetDefinition),
44
- nonce: payload.nonce.toString(),
45
- timestamp: payload.timestamp.toString()
46
- },
47
- signature
48
- };
49
- }
14
+ import { buildTransferSubmission } from "@ldgr/wallet-core";
50
15
 
51
16
  // src/wallet-file.ts
52
17
  import { generateLocalWallet, loadLocalWallet } from "@ldgr/client";
53
- import { canonicalizeLedgerAddress as canonicalizeLedgerAddress2, decodeEd25519RecoveryKey } from "@ldgr/protocol";
18
+ import { canonicalizeLedgerAddress, decodeEd25519RecoveryKey } from "@ldgr/protocol";
54
19
  import { lstat, mkdir, open, readFile, rename, unlink } from "node:fs/promises";
55
- import { dirname, join } from "node:path";
20
+ import { dirname, join, win32 } from "node:path";
21
+ import { homedir } from "node:os";
56
22
  var KDF_ITERATIONS = 310000;
57
23
  var AES_GCM = "AES-GCM";
58
24
  function arrayBuffer(bytes) {
@@ -87,7 +53,7 @@ function parseWalletEntry(value) {
87
53
  throw new TypeError("Unsupported wallet file format");
88
54
  if (file.network !== networkForLedger(file.ledgerId))
89
55
  throw new TypeError("Wallet file network does not match ledgerId");
90
- canonicalizeLedgerAddress2(file.address, file.ledgerId);
56
+ canonicalizeLedgerAddress(file.address, file.ledgerId);
91
57
  if (file.protection === "none") {
92
58
  if (typeof file.recoveryKey !== "string")
93
59
  throw new TypeError("Unsupported wallet file format");
@@ -125,18 +91,31 @@ function serializeWalletStore(store) {
125
91
  return `${JSON.stringify(store, null, 2)}
126
92
  `;
127
93
  }
94
+ function pathJoiner(platform) {
95
+ return platform === "win32" ? win32.join : join;
96
+ }
97
+ function homeDirectory(input, platform) {
98
+ if (input.home !== undefined)
99
+ return input.home;
100
+ if (platform === "win32")
101
+ return process.env.USERPROFILE?.trim() || process.env.HOME?.trim() || homedir();
102
+ return process.env.HOME?.trim() || homedir();
103
+ }
128
104
  function defaultWalletPath(input = {}) {
129
- const home = input.home ?? process.env.HOME;
105
+ const platform = input.platform ?? process.platform;
106
+ const home = homeDirectory(input, platform);
130
107
  if (!home)
131
108
  throw new Error("Could not determine your home directory; use --wallet <path>");
132
- return join(home, ".ldgr", "wallet.json");
109
+ return pathJoiner(platform)(home, ".ldgr", "wallet.json");
133
110
  }
134
111
  function legacyDefaultWalletPath(input = {}) {
135
- const home = input.home ?? process.env.HOME;
112
+ const platform = input.platform ?? process.platform;
113
+ const joinPath = pathJoiner(platform);
114
+ const home = homeDirectory(input, platform);
136
115
  if (!home)
137
116
  throw new Error("Could not determine your home directory; use --wallet <path>");
138
- const configHome = input.configHome ?? (process.env.XDG_CONFIG_HOME?.trim() || join(home, ".config"));
139
- return join(configHome, "ldgr", "wallet.json");
117
+ const configHome = input.configHome ?? (platform === "win32" ? process.env.APPDATA?.trim() || joinPath(home, "AppData", "Roaming") : process.env.XDG_CONFIG_HOME?.trim() || joinPath(home, ".config"));
118
+ return joinPath(configHome, "ldgr", "wallet.json");
140
119
  }
141
120
  async function createEncryptedWalletFile(input) {
142
121
  const wallet = await generateLocalWallet({ ledgerId: input.ledgerId });
@@ -204,7 +183,7 @@ async function readWalletStore(path) {
204
183
  });
205
184
  if (!details.isFile() || details.isSymbolicLink() || details.nlink !== 1)
206
185
  throw new Error("Wallet file must be a regular file with no links");
207
- if ((details.mode & 63) !== 0)
186
+ if (process.platform !== "win32" && (details.mode & 63) !== 0)
208
187
  throw new Error("Wallet file must be owner-only (chmod 600)");
209
188
  let parsed;
210
189
  try {
@@ -362,7 +341,7 @@ async function walletFileMetadata(path) {
362
341
 
363
342
  // src/cli.ts
364
343
  var HELP = `
365
- LDGR CLI 0.2.2 — self-custody wallet
344
+ LDGR CLI 0.4.0 — self-custody wallet
366
345
 
367
346
  Usage:
368
347
  ldgr wallet create [--testnet] [--wallet <path>]
@@ -1,14 +1 @@
1
- import type { LdgrSigner } from "@ldgr/client";
2
- import { type AssetDefinition } from "@ldgr/protocol";
3
- export declare function buildTransferSubmission(input: {
4
- readonly wallet: LdgrSigner;
5
- readonly asset: string;
6
- readonly assetDefinition: AssetDefinition;
7
- readonly amount: string;
8
- readonly to: string;
9
- readonly nextNonce: string;
10
- readonly now?: () => number;
11
- }): Promise<{
12
- readonly payload: Record<string, unknown>;
13
- readonly signature: string;
14
- }>;
1
+ export { buildTransferSubmission } from "@ldgr/wallet-core";
@@ -40,8 +40,10 @@ export type WalletFileMetadata = LocalWalletFile & {
40
40
  };
41
41
  export type DefaultWalletPathInput = {
42
42
  readonly home?: string | undefined;
43
- /** Test seam for the former XDG default; production reads XDG_CONFIG_HOME. */
43
+ /** Test seam for the former platform-specific config default. */
44
44
  readonly configHome?: string | undefined;
45
+ /** Test seam for Windows path and environment behavior. */
46
+ readonly platform?: NodeJS.Platform | undefined;
45
47
  };
46
48
  export type CreatedEncryptedWallet = {
47
49
  readonly file: LocalWalletFile;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ldgr/cli",
3
- "version": "0.2.2",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "ldgr": "dist/cli.js"
@@ -16,12 +16,13 @@
16
16
  "node": ">=20.19.0"
17
17
  },
18
18
  "dependencies": {
19
- "@ldgr/client": "^0.2.1",
20
- "@ldgr/protocol": "^0.2.1",
19
+ "@ldgr/client": "^0.4.0",
20
+ "@ldgr/protocol": "^0.4.0",
21
+ "@ldgr/wallet-core": "^0.2.0",
21
22
  "@clack/prompts": "^0.11.0"
22
23
  },
23
24
  "scripts": {
24
- "build": "rm -rf dist && bun build src/cli.ts --outdir dist --target node --format esm --packages external && tsc -p tsconfig.build.json",
25
+ "build": "bun scripts/build.mjs",
25
26
  "prepack": "bun run build",
26
27
  "start": "bun src/cli.ts",
27
28
  "test": "bun test",
@@ -29,6 +30,6 @@
29
30
  },
30
31
  "devDependencies": {
31
32
  "@types/node": "^22.20.1",
32
- "typescript": "^5.9.3"
33
+ "typescript": "^7.0.2"
33
34
  }
34
35
  }