@alchemy/cli 0.11.0 → 0.12.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
@@ -118,8 +118,8 @@ Use `alchemy help` or `alchemy help <command>` for generated command help.
118
118
 
119
119
  | Command | What it does | Example |
120
120
  |---|---|---|
121
- | `wallet connect` | Interactive: choose a session wallet (recommended) or a local wallet. For scripts, pass `--mode <session\|local>`. | `alchemy wallet connect` |
122
- | `wallet connect --mode local --chain evm` | Create a new local EVM key (non-interactive). `--chain` accepts `evm`, `solana`, or `both`. | `alchemy wallet connect --mode local --chain both` |
121
+ | `wallet connect` | Connects a session wallet by default. Pass `--mode local` only when you explicitly need local keys. | `alchemy wallet connect` |
122
+ | `wallet connect --mode local` | Create new local EVM and Solana keys. | `alchemy wallet connect --mode local` |
123
123
  | `wallet connect --mode local --import <path>` | Import an existing EVM private key from a file. | `alchemy wallet connect --mode local --import ./key.txt` |
124
124
  | `wallet connect --mode session --instance-name <name>` | Connect a named session wallet instance. | `alchemy wallet connect --mode session --instance-name laptop` |
125
125
  | `wallet status [--verify]` | Reports session, local EVM, local Solana, and the active signer. `--verify` reconciles the session with the backend. | `alchemy wallet status --verify` |
@@ -3,10 +3,10 @@ if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
3
3
  import {
4
4
  registerAuth,
5
5
  selectAppAfterAuth
6
- } from "./chunk-XZS6KZHN.js";
6
+ } from "./chunk-ILPOKA4Y.js";
7
7
  import "./chunk-I6YQX7PF.js";
8
8
  import "./chunk-RPSHRYCZ.js";
9
- import "./chunk-B5KVL3ZR.js";
9
+ import "./chunk-OL5MEN62.js";
10
10
  import "./chunk-DXQAGBW6.js";
11
11
  import "./chunk-LANOFNO6.js";
12
12
  import "./chunk-5BEJA752.js";
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  resolveAuthToken,
8
8
  resolveWalletSession
9
- } from "./chunk-B5KVL3ZR.js";
9
+ } from "./chunk-OL5MEN62.js";
10
10
 
11
11
  // src/lib/onboarding.ts
12
12
  var SETUP_CAPABILITY_ORDER = [
@@ -69,10 +69,7 @@ function getSetupCapabilities(cfg) {
69
69
  complete: hasLocalWallet || hasSessionWallet,
70
70
  satisfiedBy: hasSessionWallet ? "wallet_session" : hasLocalWallet ? "local_wallet" : null,
71
71
  missing: hasLocalWallet || hasSessionWallet ? [] : ["wallet signer"],
72
- nextCommands: hasLocalWallet || hasSessionWallet ? [] : [
73
- "alchemy wallet connect",
74
- "alchemy wallet connect --mode local"
75
- ]
72
+ nextCommands: hasLocalWallet || hasSessionWallet ? [] : ["alchemy wallet connect"]
76
73
  }),
77
74
  x402: capabilityStatus({
78
75
  complete: x402Ready,
@@ -53,7 +53,7 @@ function semverLT(a, b) {
53
53
  return false;
54
54
  }
55
55
  function currentVersion() {
56
- return true ? "0.11.0" : "0.0.0";
56
+ return true ? "0.12.0" : "0.0.0";
57
57
  }
58
58
  function toUpdateStatus(latestVersion, checkedAt) {
59
59
  const current = currentVersion();
@@ -3,7 +3,7 @@ if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
3
3
  import {
4
4
  gasManagerClientFromFlags,
5
5
  toAdminNetworkId
6
- } from "./chunk-B5KVL3ZR.js";
6
+ } from "./chunk-OL5MEN62.js";
7
7
  import {
8
8
  dim,
9
9
  green,
@@ -11,7 +11,7 @@ import {
11
11
  import {
12
12
  AdminClient,
13
13
  resolveAuthToken
14
- } from "./chunk-B5KVL3ZR.js";
14
+ } from "./chunk-OL5MEN62.js";
15
15
  import {
16
16
  bold,
17
17
  brand,
@@ -624,6 +624,11 @@ var Client = class _Client {
624
624
  if (networkNotEnabled) return networkNotEnabled;
625
625
  return errInvalidAPIKey(detail || void 0);
626
626
  }
627
+ isWrappedNetworkFailure(err) {
628
+ return err.status === void 0 && err.code === -32e3 && /\b(fetch failed|failed to fetch|network error|econnrefused|enotfound|etimedout|eai_again|socket hang up)\b/i.test(
629
+ err.message
630
+ );
631
+ }
627
632
  tryParseRPCError(text) {
628
633
  try {
629
634
  const parsed = JSON.parse(text);
@@ -673,7 +678,7 @@ var Client = class _Client {
673
678
  if (err.status !== void 0) {
674
679
  throw errNetwork(`HTTP ${err.status}: ${err.message}`);
675
680
  }
676
- if (this.isFetchFailureError(err)) {
681
+ if (this.isWrappedNetworkFailure(err)) {
677
682
  throw errNetwork(err.message);
678
683
  }
679
684
  throw errRPC(err.code, err.message);
package/dist/index.js CHANGED
@@ -5,10 +5,10 @@ import {
5
5
  errNotLoggedInForPolicyLookup,
6
6
  errSponsorshipNeedsPolicy,
7
7
  selectOrCreatePolicy
8
- } from "./chunk-KIYIW6SX.js";
8
+ } from "./chunk-CJDHJYLM.js";
9
9
  import {
10
10
  registerAuth
11
- } from "./chunk-XZS6KZHN.js";
11
+ } from "./chunk-ILPOKA4Y.js";
12
12
  import {
13
13
  openBrowser
14
14
  } from "./chunk-I6YQX7PF.js";
@@ -18,7 +18,7 @@ import {
18
18
  getSetupStatus,
19
19
  isSetupComplete,
20
20
  shouldRunOnboarding
21
- } from "./chunk-CSBYGYG6.js";
21
+ } from "./chunk-2VVJKVRL.js";
22
22
  import {
23
23
  isInteractiveAllowed
24
24
  } from "./chunk-RPSHRYCZ.js";
@@ -63,12 +63,12 @@ import {
63
63
  updateSession,
64
64
  validateNetwork,
65
65
  walletNetworkToChain
66
- } from "./chunk-B5KVL3ZR.js";
66
+ } from "./chunk-OL5MEN62.js";
67
67
  import {
68
68
  getAvailableUpdate,
69
69
  getUpdateStatus,
70
70
  printUpdateNotice
71
- } from "./chunk-4QSVWWSK.js";
71
+ } from "./chunk-BFOZ2KM7.js";
72
72
  import {
73
73
  bold,
74
74
  brand,
@@ -133,11 +133,13 @@ import {
133
133
  isJSONMode,
134
134
  isLocalhost,
135
135
  isReplMode,
136
+ isRevealMode,
136
137
  noColor,
137
138
  parseBaseURLOverride,
138
139
  printHuman,
139
140
  printJSON,
140
141
  quiet,
142
+ redactSensitiveText,
141
143
  setFlags,
142
144
  setNoColor,
143
145
  timeout,
@@ -579,8 +581,8 @@ function registerConfig(program2) {
579
581
  "Interactive policy selection requires an interactive terminal. Pass an ID: `alchemy config set evm-gas-policy-id <id>`."
580
582
  );
581
583
  }
582
- const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-3EVE7DW3.js");
583
- const { resolveNetwork: resolveNetwork2 } = await import("./resolve-FRMIY357.js");
584
+ const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-YU6L2VJZ.js");
585
+ const { resolveNetwork: resolveNetwork2 } = await import("./resolve-WXXPXPCU.js");
584
586
  const network = resolveNetwork2(program2);
585
587
  await selectOrCreatePolicy2({
586
588
  flavor: "sponsorship",
@@ -634,8 +636,8 @@ function registerConfig(program2) {
634
636
  "Interactive policy selection requires an interactive terminal. Pass an ID: `alchemy config set solana-fee-policy-id <id>`."
635
637
  );
636
638
  }
637
- const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-3EVE7DW3.js");
638
- const { resolveSolanaNetwork: resolveSolanaNetwork2 } = await import("./resolve-FRMIY357.js");
639
+ const { selectOrCreatePolicy: selectOrCreatePolicy2 } = await import("./policy-prompt-YU6L2VJZ.js");
640
+ const { resolveSolanaNetwork: resolveSolanaNetwork2 } = await import("./resolve-WXXPXPCU.js");
639
641
  const network = resolveSolanaNetwork2(program2);
640
642
  await selectOrCreatePolicy2({
641
643
  flavor: "solana",
@@ -692,7 +694,7 @@ function registerConfig(program2) {
692
694
  printJSON(toMap(cfg));
693
695
  return;
694
696
  }
695
- const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-FRMIY357.js");
697
+ const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-WXXPXPCU.js");
696
698
  const validToken = resolveAuthToken2(cfg);
697
699
  const authStatus = cfg.auth_token ? validToken ? `${green("\u2713")} authenticated${cfg.auth_token_expires_at ? ` ${dim(`(expires ${cfg.auth_token_expires_at})`)}` : ""}` : `${yellow("\u25C6")} expired${cfg.auth_token_expires_at ? ` ${dim(`(${cfg.auth_token_expires_at})`)}` : ""}` : dim("(not set) \u2014 run 'alchemy auth' to log in");
698
700
  const pairs = [
@@ -827,12 +829,24 @@ function registerVersion(program2) {
827
829
  }
828
830
 
829
831
  // src/commands/apps.ts
832
+ function redactAppUrl(value) {
833
+ return isRevealMode() ? value : redactSensitiveText(value);
834
+ }
830
835
  function maskAppSecrets(app) {
831
- return {
836
+ const masked = {
832
837
  ...app,
833
838
  ...app.apiKey !== void 0 && { apiKey: maskIf(app.apiKey) },
834
839
  ...app.webhookApiKey !== void 0 && { webhookApiKey: maskIf(app.webhookApiKey) }
835
840
  };
841
+ if (app.chainNetworks !== void 0) {
842
+ masked.chainNetworks = app.chainNetworks.map((network) => ({
843
+ ...network,
844
+ ...network.rpcUrl !== void 0 && { rpcUrl: redactAppUrl(network.rpcUrl) },
845
+ ...network.wsUrl !== void 0 && { wsUrl: redactAppUrl(network.wsUrl) },
846
+ ...network.grpcUrl !== void 0 && { grpcUrl: redactAppUrl(network.grpcUrl) }
847
+ }));
848
+ }
849
+ return masked;
836
850
  }
837
851
  function printFetchSummary(appsCount, pagesCount, opts) {
838
852
  const suffix = opts?.suffix ? ` ${opts.suffix}` : "";
@@ -2580,28 +2594,11 @@ async function runConnectFlow(program2, opts) {
2580
2594
  }
2581
2595
  mode = "session";
2582
2596
  }
2583
- if (importPath) {
2584
- if (mode === "session") {
2585
- throw errInvalidArgs("`--import` is only valid with `--mode local`.");
2586
- }
2587
- mode = "local";
2597
+ if (importPath && mode !== "local") {
2598
+ throw errInvalidArgs("`--import` is only valid with `--mode local`.");
2588
2599
  }
2589
2600
  if (!mode) {
2590
- if (!isInteractiveAllowed(program2)) {
2591
- mode = "session";
2592
- } else {
2593
- const choice = await promptSelect({
2594
- message: "Choose a wallet to connect",
2595
- options: [
2596
- { value: "session", label: "Session wallet", hint: "Recommended \u2014 Alchemy-managed, more secure" },
2597
- { value: "local", label: "Local wallet", hint: "Private key stored on this machine" }
2598
- ],
2599
- initialValue: "session",
2600
- cancelMessage: "Wallet connect cancelled."
2601
- });
2602
- if (choice === null) throw new WalletConnectInterruptedError();
2603
- mode = choice;
2604
- }
2601
+ mode = "session";
2605
2602
  }
2606
2603
  if (mode === "session") {
2607
2604
  await runSessionConnect({
@@ -2743,7 +2740,7 @@ async function buildSessionSnapshot(program2, verify) {
2743
2740
  }
2744
2741
  function registerWallets(program2) {
2745
2742
  const cmd = program2.command("wallet").description("Manage wallets");
2746
- cmd.command("connect").description("Connect a wallet for onchain actions (session or local)").option("--mode <mode>", "session | local").option("--import <path>", "For --mode local: import an EVM key from file instead of creating both wallets").option("--instance-name <name>", "For --mode session: name this CLI instance").option("--force", "Replace the existing signer").action(async (opts) => {
2743
+ cmd.command("connect").description("Connect a session wallet for onchain actions").option("--mode <mode>", "session | local (default: session; local must be explicit)").option("--import <path>", "For --mode local: import an EVM key from file instead of creating both wallets").option("--instance-name <name>", "For --mode session: name this CLI instance").option("--force", "Replace the existing signer").action(async (opts) => {
2747
2744
  try {
2748
2745
  await runConnectFlow(program2, opts);
2749
2746
  } catch (err) {
@@ -3164,6 +3161,24 @@ function resolveWebhookApiKey(opts) {
3164
3161
  const cfg = load();
3165
3162
  return opts?.webhookApiKey || opts?.notifyToken || process.env.ALCHEMY_WEBHOOK_API_KEY || process.env.ALCHEMY_NOTIFY_AUTH_TOKEN || cfg.webhook_api_key || cfg.app?.webhookApiKey;
3166
3163
  }
3164
+ function isWebhookSigningKey(key) {
3165
+ const normalized = key.replace(/[^a-z0-9]/gi, "").toLowerCase();
3166
+ return (normalized.includes("signing") || normalized.includes("hmac")) && (normalized.includes("key") || normalized.includes("secret"));
3167
+ }
3168
+ function maskWebhookSecrets(value) {
3169
+ if (Array.isArray(value)) {
3170
+ return value.map(maskWebhookSecrets);
3171
+ }
3172
+ if (value && typeof value === "object") {
3173
+ return Object.fromEntries(
3174
+ Object.entries(value).map(([key, nested]) => [
3175
+ key,
3176
+ isWebhookSigningKey(key) && typeof nested === "string" ? maskIf(nested) : maskWebhookSecrets(nested)
3177
+ ])
3178
+ );
3179
+ }
3180
+ return value;
3181
+ }
3167
3182
  function registerWebhooks(program2) {
3168
3183
  const cmd = program2.command("webhook").description("Notify API wrappers");
3169
3184
  cmd.option("--webhook-api-key <key>", "Webhook API key").option("--notify-token <token>", "Deprecated alias for webhook API key");
@@ -3175,8 +3190,9 @@ function registerWebhooks(program2) {
3175
3190
  "Webhooks fetched",
3176
3191
  () => callNotify(token, "/team-webhooks")
3177
3192
  );
3178
- if (isJSONMode()) printJSON(result);
3179
- else printSyntaxJSON(result);
3193
+ const output = maskWebhookSecrets(result);
3194
+ if (isJSONMode()) printJSON(output);
3195
+ else printSyntaxJSON(output);
3180
3196
  } catch (err) {
3181
3197
  exitWithError(err);
3182
3198
  }
@@ -6401,7 +6417,7 @@ function buildAgentPrompt(program2) {
6401
6417
  "evm approve",
6402
6418
  "xchain bridge"
6403
6419
  ],
6404
- notes: "`--signer local` only selects the local signer. You still need a local EVM key via env, flag, or saved config."
6420
+ notes: "Use only when you explicitly need a local private key. `--signer local` selects the local signer but still requires a local EVM key via env, flag, or saved config."
6405
6421
  }
6406
6422
  ],
6407
6423
  commands,
@@ -8360,13 +8376,7 @@ Examples:
8360
8376
  return;
8361
8377
  }
8362
8378
  const client = clientFromFlags(program2);
8363
- const parsed = params.map((p) => {
8364
- try {
8365
- return JSON.parse(p);
8366
- } catch {
8367
- return p;
8368
- }
8369
- });
8379
+ const parsed = parseRPCParams(params);
8370
8380
  debug(`rpc ${method} %o`, parsed);
8371
8381
  const result = await withSpinner(
8372
8382
  `Calling ${method}\u2026`,
@@ -8380,6 +8390,13 @@ Examples:
8380
8390
  });
8381
8391
  registerEvmRpcSurfaceCommands(program2, cmd);
8382
8392
  }
8393
+ function parseRPCParams(params) {
8394
+ const parsed = parseCLIParams(params);
8395
+ if (parsed.length === 1 && Array.isArray(parsed[0])) {
8396
+ return parsed[0];
8397
+ }
8398
+ return parsed;
8399
+ }
8383
8400
  function outputRpcHelp(cmd, method, params) {
8384
8401
  if (method !== "help") {
8385
8402
  return false;
@@ -10356,7 +10373,7 @@ async function flushProcessOutput() {
10356
10373
  }
10357
10374
  program.name("alchemy").description(
10358
10375
  "The Alchemy CLI lets you query blockchain data, call JSON-RPC methods, and manage your Alchemy configuration."
10359
- ).version("0.11.0", "-v, --version", "display CLI version").option("--api-key <key>", "Alchemy API key (env: ALCHEMY_API_KEY)").option(
10376
+ ).version("0.12.0", "-v, --version", "display CLI version").option("--api-key <key>", "Alchemy API key (env: ALCHEMY_API_KEY)").option(
10360
10377
  "-n, --network <network>",
10361
10378
  "Target network for networked commands"
10362
10379
  ).option("--x402", "Use x402 wallet-based gateway auth").option(
@@ -10543,11 +10560,11 @@ ${styledLine}`;
10543
10560
  "wallet"
10544
10561
  ];
10545
10562
  if (!skipAppPrompt.includes(cmdName) && isInteractiveAllowed(program) && !opts.apiKey && !process.env.ALCHEMY_API_KEY) {
10546
- const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-FRMIY357.js");
10563
+ const { resolveAuthToken: resolveAuthToken2 } = await import("./resolve-WXXPXPCU.js");
10547
10564
  const authToken = resolveAuthToken2(cfg);
10548
10565
  const hasApiKey = Boolean(cfg.api_key?.trim() || cfg.app?.apiKey);
10549
10566
  if (authToken && !hasApiKey) {
10550
- const { selectAppAfterAuth } = await import("./auth-6X2DBBYQ.js");
10567
+ const { selectAppAfterAuth } = await import("./auth-AU7LPEQL.js");
10551
10568
  console.log("");
10552
10569
  console.log(` No app selected. Please select an app to continue.`);
10553
10570
  await selectAppAfterAuth(authToken);
@@ -10582,7 +10599,7 @@ ${styledLine}`;
10582
10599
  if (isInteractiveAllowed(program)) {
10583
10600
  let latestForInteractiveStartup = null;
10584
10601
  if (shouldRunOnboarding(program, cfg)) {
10585
- const { runOnboarding } = await import("./onboarding-2FLKQYLY.js");
10602
+ const { runOnboarding } = await import("./onboarding-RXNSVGSW.js");
10586
10603
  const latest = getAvailableUpdateOnce();
10587
10604
  const completed = await runOnboarding(program, latest);
10588
10605
  updateShownDuringInteractiveStartup = Boolean(latest);
@@ -10596,7 +10613,7 @@ ${styledLine}`;
10596
10613
  latestForInteractiveStartup
10597
10614
  );
10598
10615
  }
10599
- const { startREPL } = await import("./interactive-EXQM6HWQ.js");
10616
+ const { startREPL } = await import("./interactive-6L2HNSOS.js");
10600
10617
  program.exitOverride();
10601
10618
  program.configureOutput({
10602
10619
  writeErr: () => {
@@ -2,14 +2,14 @@
2
2
  if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
3
3
  import {
4
4
  getSetupMethod
5
- } from "./chunk-CSBYGYG6.js";
5
+ } from "./chunk-2VVJKVRL.js";
6
6
  import "./chunk-RPSHRYCZ.js";
7
7
  import {
8
8
  getRPCNetworkIds
9
- } from "./chunk-B5KVL3ZR.js";
9
+ } from "./chunk-OL5MEN62.js";
10
10
  import {
11
11
  getUpdateNoticeLines
12
- } from "./chunk-4QSVWWSK.js";
12
+ } from "./chunk-BFOZ2KM7.js";
13
13
  import {
14
14
  bold,
15
15
  brand,
@@ -2,7 +2,7 @@
2
2
  if(process.argv.includes("--no-color"))process.env.NO_COLOR="1";
3
3
  import {
4
4
  getUpdateNoticeLines
5
- } from "./chunk-4QSVWWSK.js";
5
+ } from "./chunk-BFOZ2KM7.js";
6
6
  import {
7
7
  bold,
8
8
  brand,
@@ -51,7 +51,7 @@ async function runOnboarding(_program, latestUpdate = null) {
51
51
  auth_token_expires_at: result.expiresAt
52
52
  });
53
53
  console.log(` ${green("\u2713")} Logged in successfully`);
54
- const { selectAppAfterAuth } = await import("./auth-6X2DBBYQ.js");
54
+ const { selectAppAfterAuth } = await import("./auth-AU7LPEQL.js");
55
55
  await selectAppAfterAuth(result.token);
56
56
  return true;
57
57
  } catch (err) {
@@ -5,8 +5,8 @@ import {
5
5
  errNotLoggedInForPolicyLookup,
6
6
  errSponsorshipNeedsPolicy,
7
7
  selectOrCreatePolicy
8
- } from "./chunk-KIYIW6SX.js";
9
- import "./chunk-B5KVL3ZR.js";
8
+ } from "./chunk-CJDHJYLM.js";
9
+ import "./chunk-OL5MEN62.js";
10
10
  import "./chunk-DXQAGBW6.js";
11
11
  import "./chunk-LANOFNO6.js";
12
12
  import "./chunk-5BEJA752.js";
@@ -26,7 +26,7 @@ import {
26
26
  resolveWalletSession,
27
27
  resolveX402,
28
28
  resolveX402Client
29
- } from "./chunk-B5KVL3ZR.js";
29
+ } from "./chunk-OL5MEN62.js";
30
30
  import "./chunk-LANOFNO6.js";
31
31
  import "./chunk-5BEJA752.js";
32
32
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alchemy/cli",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "Alchemy CLI — interact with blockchain data",
5
5
  "type": "module",
6
6
  "bin": {