@layr-labs/ecloud-cli 0.0.1-dev → 0.0.1-rfc.1

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.
Files changed (75) hide show
  1. package/README.md +2 -6
  2. package/dist/commands/app/create.js +29 -0
  3. package/dist/commands/app/create.js.map +1 -0
  4. package/dist/commands/app/deploy.js +142 -0
  5. package/dist/commands/app/deploy.js.map +1 -0
  6. package/dist/commands/app/logs.js +108 -0
  7. package/dist/commands/app/logs.js.map +1 -0
  8. package/dist/commands/app/start.js +121 -0
  9. package/dist/commands/app/start.js.map +1 -0
  10. package/dist/commands/app/stop.js +121 -0
  11. package/dist/commands/app/stop.js.map +1 -0
  12. package/dist/commands/app/terminate.js +128 -0
  13. package/dist/commands/app/terminate.js.map +1 -0
  14. package/dist/commands/app/upgrade.js +142 -0
  15. package/dist/commands/app/upgrade.js.map +1 -0
  16. package/dist/commands/auth/generate.js +10 -116
  17. package/dist/commands/auth/generate.js.map +1 -1
  18. package/dist/commands/auth/login.js +35 -37
  19. package/dist/commands/auth/login.js.map +1 -1
  20. package/dist/commands/auth/logout.js +8 -2
  21. package/dist/commands/auth/logout.js.map +1 -1
  22. package/dist/commands/auth/migrate.js +37 -32
  23. package/dist/commands/auth/migrate.js.map +1 -1
  24. package/dist/commands/auth/whoami.js +21 -53
  25. package/dist/commands/auth/whoami.js.map +1 -1
  26. package/dist/commands/billing/cancel.js +22 -83
  27. package/dist/commands/billing/cancel.js.map +1 -1
  28. package/dist/commands/billing/status.js +29 -92
  29. package/dist/commands/billing/status.js.map +1 -1
  30. package/dist/commands/billing/subscribe.js +31 -86
  31. package/dist/commands/billing/subscribe.js.map +1 -1
  32. package/dist/keys/mainnet-alpha/prod/kms-encryption-public-key.pem +14 -0
  33. package/dist/keys/mainnet-alpha/prod/kms-signing-public-key.pem +4 -0
  34. package/dist/keys/sepolia/dev/kms-encryption-public-key.pem +14 -0
  35. package/dist/keys/sepolia/dev/kms-signing-public-key.pem +4 -0
  36. package/dist/keys/sepolia/prod/kms-encryption-public-key.pem +14 -0
  37. package/dist/keys/sepolia/prod/kms-signing-public-key.pem +4 -0
  38. package/dist/templates/Dockerfile.layered.tmpl +58 -0
  39. package/dist/templates/compute-source-env.sh.tmpl +110 -0
  40. package/package.json +4 -29
  41. package/VERSION +0 -2
  42. package/dist/commands/compute/app/configure/tls.js +0 -150
  43. package/dist/commands/compute/app/configure/tls.js.map +0 -1
  44. package/dist/commands/compute/app/create.js +0 -134
  45. package/dist/commands/compute/app/create.js.map +0 -1
  46. package/dist/commands/compute/app/deploy.js +0 -1081
  47. package/dist/commands/compute/app/deploy.js.map +0 -1
  48. package/dist/commands/compute/app/info.js +0 -809
  49. package/dist/commands/compute/app/info.js.map +0 -1
  50. package/dist/commands/compute/app/list.js +0 -570
  51. package/dist/commands/compute/app/list.js.map +0 -1
  52. package/dist/commands/compute/app/logs.js +0 -629
  53. package/dist/commands/compute/app/logs.js.map +0 -1
  54. package/dist/commands/compute/app/profile/set.js +0 -1072
  55. package/dist/commands/compute/app/profile/set.js.map +0 -1
  56. package/dist/commands/compute/app/start.js +0 -665
  57. package/dist/commands/compute/app/start.js.map +0 -1
  58. package/dist/commands/compute/app/stop.js +0 -665
  59. package/dist/commands/compute/app/stop.js.map +0 -1
  60. package/dist/commands/compute/app/terminate.js +0 -671
  61. package/dist/commands/compute/app/terminate.js.map +0 -1
  62. package/dist/commands/compute/app/upgrade.js +0 -1063
  63. package/dist/commands/compute/app/upgrade.js.map +0 -1
  64. package/dist/commands/compute/environment/list.js +0 -89
  65. package/dist/commands/compute/environment/list.js.map +0 -1
  66. package/dist/commands/compute/environment/set.js +0 -215
  67. package/dist/commands/compute/environment/set.js.map +0 -1
  68. package/dist/commands/compute/environment/show.js +0 -96
  69. package/dist/commands/compute/environment/show.js.map +0 -1
  70. package/dist/commands/compute/undelegate.js +0 -250
  71. package/dist/commands/compute/undelegate.js.map +0 -1
  72. package/dist/commands/upgrade.js +0 -91
  73. package/dist/commands/upgrade.js.map +0 -1
  74. package/dist/commands/version.js +0 -65
  75. package/dist/commands/version.js.map +0 -1
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/app/terminate.ts
4
+ import { Command, Args, Flags as Flags2 } from "@oclif/core";
5
+
6
+ // src/client.ts
7
+ import {
8
+ createAppModule,
9
+ createBillingModule,
10
+ getPrivateKeyInteractive as getPrivateKeyInteractive2,
11
+ getEnvironmentConfig,
12
+ requirePrivateKey,
13
+ getPrivateKeyWithSource
14
+ } from "@layr-labs/ecloud-sdk";
15
+
16
+ // src/flags.ts
17
+ import {
18
+ getEnvironmentInteractive,
19
+ getPrivateKeyInteractive,
20
+ getAvailableEnvironments
21
+ } from "@layr-labs/ecloud-sdk";
22
+ import { Flags } from "@oclif/core";
23
+ var getEnvironmentOptions = () => {
24
+ try {
25
+ return getAvailableEnvironments();
26
+ } catch {
27
+ return ["sepolia", "sepolia-dev", "mainnet-alpha"];
28
+ }
29
+ };
30
+ var commonFlags = {
31
+ environment: Flags.string({
32
+ required: false,
33
+ description: "Deployment environment to use",
34
+ options: getEnvironmentOptions(),
35
+ env: "ECLOUD_ENV"
36
+ }),
37
+ "private-key": Flags.string({
38
+ required: false,
39
+ description: "Private key for signing transactions",
40
+ env: "ECLOUD_PRIVATE_KEY"
41
+ }),
42
+ "rpc-url": Flags.string({
43
+ required: false,
44
+ description: "RPC URL to connect to blockchain",
45
+ env: "ECLOUD_RPC_URL"
46
+ }),
47
+ verbose: Flags.boolean({
48
+ required: false,
49
+ description: "Enable verbose logging (default: false)",
50
+ default: false
51
+ })
52
+ };
53
+ async function validateCommonFlags(flags) {
54
+ flags["environment"] = await getEnvironmentInteractive(flags["environment"]);
55
+ flags["private-key"] = await getPrivateKeyInteractive(flags["private-key"]);
56
+ return flags;
57
+ }
58
+
59
+ // src/client.ts
60
+ async function createAppClient(flags) {
61
+ flags = await validateCommonFlags(flags);
62
+ const environment = flags.environment;
63
+ const environmentConfig = getEnvironmentConfig(environment);
64
+ const rpcUrl = flags["rpc-url"] || environmentConfig.defaultRPCURL;
65
+ const { key: privateKey, source } = await requirePrivateKey({
66
+ privateKey: flags["private-key"]
67
+ });
68
+ if (flags.verbose) {
69
+ console.log(`Using private key from: ${source}`);
70
+ }
71
+ return createAppModule({
72
+ verbose: flags.verbose,
73
+ privateKey,
74
+ rpcUrl,
75
+ environment
76
+ });
77
+ }
78
+
79
+ // src/commands/app/terminate.ts
80
+ import { getEnvironmentConfig as getEnvironmentConfig2, getOrPromptAppID } from "@layr-labs/ecloud-sdk";
81
+ import chalk from "chalk";
82
+ var AppLifecycleTerminate = class _AppLifecycleTerminate extends Command {
83
+ static description = "Terminate app (terminate GCP instance) permanently";
84
+ static args = {
85
+ "app-id": Args.string({
86
+ description: "App ID or name to terminate",
87
+ required: false
88
+ })
89
+ };
90
+ static flags = {
91
+ ...commonFlags,
92
+ force: Flags2.boolean({
93
+ required: false,
94
+ description: "Force termination without confirmation",
95
+ default: false
96
+ })
97
+ };
98
+ async run() {
99
+ const { args, flags } = await this.parse(_AppLifecycleTerminate);
100
+ const app = await createAppClient(flags);
101
+ const environment = flags.environment || "sepolia";
102
+ const environmentConfig = getEnvironmentConfig2(environment);
103
+ const rpcUrl = flags.rpcUrl || environmentConfig.defaultRPCURL;
104
+ const appId = await getOrPromptAppID(
105
+ {
106
+ appID: args["app-id"],
107
+ environment: flags["environment"],
108
+ privateKey: flags["private-key"],
109
+ rpcUrl,
110
+ action: "terminate"
111
+ }
112
+ );
113
+ const res = await app.terminate(appId, {
114
+ force: flags.force
115
+ });
116
+ if (!res.tx) {
117
+ this.log(`
118
+ ${chalk.gray(`Termination aborted`)}`);
119
+ } else {
120
+ this.log(`
121
+ \u2705 ${chalk.green(`App terminated successfully`)}`);
122
+ }
123
+ }
124
+ };
125
+ export {
126
+ AppLifecycleTerminate as default
127
+ };
128
+ //# sourceMappingURL=terminate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/commands/app/terminate.ts","../../../src/client.ts","../../../src/flags.ts"],"sourcesContent":["import { Command, Args, Flags } from \"@oclif/core\";\nimport { createAppClient } from \"../../client\";\nimport { commonFlags } from \"../../flags\";\nimport { getEnvironmentConfig, getOrPromptAppID } from \"@layr-labs/ecloud-sdk\";\nimport chalk from \"chalk\";\n\nexport default class AppLifecycleTerminate extends Command {\n static description =\n \"Terminate app (terminate GCP instance) permanently\";\n\n static args = {\n \"app-id\": Args.string({\n description: \"App ID or name to terminate\",\n required: false,\n }),\n };\n\n static flags = {\n ...commonFlags,\n force: Flags.boolean({\n required: false,\n description: \"Force termination without confirmation\",\n default: false,\n }),\n };\n\n async run() {\n const { args, flags } = await this.parse(AppLifecycleTerminate);\n const app = await createAppClient(flags);\n\n // Get environment config\n const environment = flags.environment || \"sepolia\";\n const environmentConfig = getEnvironmentConfig(environment);\n \n // Get RPC URL (needed for contract queries and authentication)\n const rpcUrl = flags.rpcUrl || environmentConfig.defaultRPCURL;\n \n // Resolve app ID (prompt if not provided)\n const appId = await getOrPromptAppID(\n {\n appID: args[\"app-id\"],\n environment: flags[\"environment\"]!,\n privateKey: flags[\"private-key\"],\n rpcUrl,\n action: \"terminate\",\n }\n );\n\n const res = await app.terminate(appId, {\n force: flags.force,\n });\n\n if (!res.tx) {\n this.log(`\\n${chalk.gray(`Termination aborted`)}`);\n } else {\n this.log(`\\n✅ ${chalk.green(`App terminated successfully`)}`);\n }\n }\n}\n\n","import {\n createAppModule,\n createBillingModule,\n getPrivateKeyInteractive,\n getEnvironmentConfig,\n requirePrivateKey,\n getPrivateKeyWithSource,\n} from \"@layr-labs/ecloud-sdk\";\nimport { CommonFlags, validateCommonFlags } from \"./flags\";\nimport { Hex } from \"viem\";\n\nexport async function createAppClient(flags: CommonFlags) {\n flags = await validateCommonFlags(flags);\n\n const environment = flags.environment!;\n const environmentConfig = getEnvironmentConfig(environment);\n const rpcUrl = flags[\"rpc-url\"] || environmentConfig.defaultRPCURL;\n const { key: privateKey, source } = await requirePrivateKey({\n privateKey: flags[\"private-key\"],\n });\n\n if (flags.verbose) {\n console.log(`Using private key from: ${source}`);\n }\n\n return createAppModule({\n verbose: flags.verbose,\n privateKey,\n rpcUrl,\n environment,\n });\n}\n\nexport async function createBillingClient(flags: {\n \"private-key\"?: string;\n verbose?: boolean;\n}) {\n const result = await getPrivateKeyWithSource({\n privateKey: flags[\"private-key\"],\n });\n const privateKey = await getPrivateKeyInteractive(result?.key);\n\n return createBillingModule({\n verbose: flags.verbose ?? false,\n privateKey: privateKey as Hex,\n });\n}\n","import {\n getEnvironmentInteractive,\n getPrivateKeyInteractive,\n getAvailableEnvironments,\n} from \"@layr-labs/ecloud-sdk\";\nimport { Flags } from \"@oclif/core\";\n\nexport type CommonFlags = {\n verbose: boolean;\n environment?: string;\n \"private-key\"?: string;\n \"rpc-url\"?: string;\n};\n\n// Get available environments dynamically from SDK based on build type\nconst getEnvironmentOptions = (): string[] => {\n try {\n return getAvailableEnvironments();\n } catch {\n // Fallback to all environments if SDK not available\n return [\"sepolia\", \"sepolia-dev\", \"mainnet-alpha\"];\n }\n};\n\nexport const commonFlags = {\n environment: Flags.string({\n required: false,\n description: \"Deployment environment to use\",\n options: getEnvironmentOptions(),\n env: \"ECLOUD_ENV\",\n }),\n \"private-key\": Flags.string({\n required: false,\n description: \"Private key for signing transactions\",\n env: \"ECLOUD_PRIVATE_KEY\",\n }),\n \"rpc-url\": Flags.string({\n required: false,\n description: \"RPC URL to connect to blockchain\",\n env: \"ECLOUD_RPC_URL\",\n }),\n verbose: Flags.boolean({\n required: false,\n description: \"Enable verbose logging (default: false)\",\n default: false,\n }),\n};\n\n// Validate or prompt for required common flags\nexport async function validateCommonFlags(flags: CommonFlags) {\n flags[\"environment\"] = await getEnvironmentInteractive(flags[\"environment\"]);\n flags[\"private-key\"] = await getPrivateKeyInteractive(flags[\"private-key\"]);\n\n return flags;\n}\n"],"mappings":"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","names":["Flags","getPrivateKeyInteractive","getEnvironmentConfig","Flags"]}
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/app/upgrade.ts
4
+ import { Command, Args, Flags as Flags2 } from "@oclif/core";
5
+
6
+ // src/client.ts
7
+ import {
8
+ createAppModule,
9
+ createBillingModule,
10
+ getPrivateKeyInteractive as getPrivateKeyInteractive2,
11
+ getEnvironmentConfig,
12
+ requirePrivateKey,
13
+ getPrivateKeyWithSource
14
+ } from "@layr-labs/ecloud-sdk";
15
+
16
+ // src/flags.ts
17
+ import {
18
+ getEnvironmentInteractive,
19
+ getPrivateKeyInteractive,
20
+ getAvailableEnvironments
21
+ } from "@layr-labs/ecloud-sdk";
22
+ import { Flags } from "@oclif/core";
23
+ var getEnvironmentOptions = () => {
24
+ try {
25
+ return getAvailableEnvironments();
26
+ } catch {
27
+ return ["sepolia", "sepolia-dev", "mainnet-alpha"];
28
+ }
29
+ };
30
+ var commonFlags = {
31
+ environment: Flags.string({
32
+ required: false,
33
+ description: "Deployment environment to use",
34
+ options: getEnvironmentOptions(),
35
+ env: "ECLOUD_ENV"
36
+ }),
37
+ "private-key": Flags.string({
38
+ required: false,
39
+ description: "Private key for signing transactions",
40
+ env: "ECLOUD_PRIVATE_KEY"
41
+ }),
42
+ "rpc-url": Flags.string({
43
+ required: false,
44
+ description: "RPC URL to connect to blockchain",
45
+ env: "ECLOUD_RPC_URL"
46
+ }),
47
+ verbose: Flags.boolean({
48
+ required: false,
49
+ description: "Enable verbose logging (default: false)",
50
+ default: false
51
+ })
52
+ };
53
+ async function validateCommonFlags(flags) {
54
+ flags["environment"] = await getEnvironmentInteractive(flags["environment"]);
55
+ flags["private-key"] = await getPrivateKeyInteractive(flags["private-key"]);
56
+ return flags;
57
+ }
58
+
59
+ // src/client.ts
60
+ async function createAppClient(flags) {
61
+ flags = await validateCommonFlags(flags);
62
+ const environment = flags.environment;
63
+ const environmentConfig = getEnvironmentConfig(environment);
64
+ const rpcUrl = flags["rpc-url"] || environmentConfig.defaultRPCURL;
65
+ const { key: privateKey, source } = await requirePrivateKey({
66
+ privateKey: flags["private-key"]
67
+ });
68
+ if (flags.verbose) {
69
+ console.log(`Using private key from: ${source}`);
70
+ }
71
+ return createAppModule({
72
+ verbose: flags.verbose,
73
+ privateKey,
74
+ rpcUrl,
75
+ environment
76
+ });
77
+ }
78
+
79
+ // src/commands/app/upgrade.ts
80
+ import chalk from "chalk";
81
+ var AppUpgrade = class _AppUpgrade extends Command {
82
+ static description = "Upgrade existing deployment";
83
+ static args = {
84
+ "app-id": Args.string({
85
+ description: "App ID or name to upgrade",
86
+ required: false
87
+ })
88
+ };
89
+ static flags = {
90
+ ...commonFlags,
91
+ dockerfile: Flags2.string({
92
+ required: false,
93
+ description: "Path to Dockerfile",
94
+ env: "ECLOUD_DOCKERFILE_PATH"
95
+ }),
96
+ "image-ref": Flags2.string({
97
+ required: false,
98
+ description: "Image reference pointing to registry",
99
+ env: "ECLOUD_IMAGE_REF"
100
+ }),
101
+ "env-file": Flags2.string({
102
+ required: false,
103
+ description: 'Environment file to use (default: ".env")',
104
+ default: ".env",
105
+ env: "ECLOUD_ENVFILE_PATH"
106
+ }),
107
+ "log-visibility": Flags2.string({
108
+ required: false,
109
+ description: "Log visibility setting: public, private, or off",
110
+ options: ["public", "private", "off"],
111
+ env: "ECLOUD_LOG_VISIBILITY"
112
+ }),
113
+ "instance-type": Flags2.string({
114
+ required: false,
115
+ description: "Machine instance type to use e.g. g1-standard-4t, g1-standard-8t",
116
+ env: "ECLOUD_INSTANCE_TYPE"
117
+ })
118
+ };
119
+ async run() {
120
+ const { args, flags } = await this.parse(_AppUpgrade);
121
+ const app = await createAppClient(flags);
122
+ const res = await app.upgrade(args["app-id"], {
123
+ dockerfile: flags.dockerfile,
124
+ envFile: flags["env-file"],
125
+ imageRef: flags["image-ref"],
126
+ logVisibility: flags["log-visibility"],
127
+ instanceType: flags["instance-type"]
128
+ });
129
+ if (!res.tx) {
130
+ this.log(`
131
+ ${chalk.gray(`Upgrade failed`)}`);
132
+ } else {
133
+ this.log(`
134
+ \u2705 ${chalk.green(`App upgraded successfully ${chalk.bold(`(id: ${res.appID}, image: ${res.imageRef})`)}`)}`);
135
+ }
136
+ this.log(JSON.stringify(res, null, 2));
137
+ }
138
+ };
139
+ export {
140
+ AppUpgrade as default
141
+ };
142
+ //# sourceMappingURL=upgrade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/commands/app/upgrade.ts","../../../src/client.ts","../../../src/flags.ts"],"sourcesContent":["import { Command, Args, Flags } from \"@oclif/core\";\nimport { logVisibility } from \"@layr-labs/ecloud-sdk\";\nimport { createAppClient } from \"../../client\";\nimport { commonFlags } from \"../../flags\";\nimport chalk from \"chalk\";\n\nexport default class AppUpgrade extends Command {\n static description = \"Upgrade existing deployment\";\n\n static args = {\n \"app-id\": Args.string({\n description: \"App ID or name to upgrade\",\n required: false,\n }),\n };\n\n static flags = {\n ...commonFlags,\n dockerfile: Flags.string({\n required: false,\n description: \"Path to Dockerfile\",\n env: \"ECLOUD_DOCKERFILE_PATH\",\n }),\n \"image-ref\": Flags.string({\n required: false,\n description: \"Image reference pointing to registry\",\n env: \"ECLOUD_IMAGE_REF\",\n }),\n \"env-file\": Flags.string({\n required: false,\n description: 'Environment file to use (default: \".env\")',\n default: \".env\",\n env: \"ECLOUD_ENVFILE_PATH\",\n }),\n \"log-visibility\": Flags.string({\n required: false,\n description: \"Log visibility setting: public, private, or off\",\n options: [\"public\", \"private\", \"off\"],\n env: \"ECLOUD_LOG_VISIBILITY\",\n }),\n \"instance-type\": Flags.string({\n required: false,\n description:\n \"Machine instance type to use e.g. g1-standard-4t, g1-standard-8t\",\n env: \"ECLOUD_INSTANCE_TYPE\",\n }),\n };\n\n async run() {\n const { args, flags } = await this.parse(AppUpgrade);\n const app = await createAppClient(flags);\n\n const res = await app.upgrade(args[\"app-id\"] as any, {\n dockerfile: flags.dockerfile,\n envFile: flags[\"env-file\"],\n imageRef: flags[\"image-ref\"],\n logVisibility: flags[\"log-visibility\"] as logVisibility,\n instanceType: flags[\"instance-type\"],\n });\n\n if (!res.tx) {\n this.log(`\\n${chalk.gray(`Upgrade failed`)}`);\n } else {\n this.log(`\\n✅ ${chalk.green(`App upgraded successfully ${chalk.bold(`(id: ${res.appID}, image: ${res.imageRef})`)}`)}`);\n }\n this.log(JSON.stringify(res, null, 2));\n }\n}\n\n","import {\n createAppModule,\n createBillingModule,\n getPrivateKeyInteractive,\n getEnvironmentConfig,\n requirePrivateKey,\n getPrivateKeyWithSource,\n} from \"@layr-labs/ecloud-sdk\";\nimport { CommonFlags, validateCommonFlags } from \"./flags\";\nimport { Hex } from \"viem\";\n\nexport async function createAppClient(flags: CommonFlags) {\n flags = await validateCommonFlags(flags);\n\n const environment = flags.environment!;\n const environmentConfig = getEnvironmentConfig(environment);\n const rpcUrl = flags[\"rpc-url\"] || environmentConfig.defaultRPCURL;\n const { key: privateKey, source } = await requirePrivateKey({\n privateKey: flags[\"private-key\"],\n });\n\n if (flags.verbose) {\n console.log(`Using private key from: ${source}`);\n }\n\n return createAppModule({\n verbose: flags.verbose,\n privateKey,\n rpcUrl,\n environment,\n });\n}\n\nexport async function createBillingClient(flags: {\n \"private-key\"?: string;\n verbose?: boolean;\n}) {\n const result = await getPrivateKeyWithSource({\n privateKey: flags[\"private-key\"],\n });\n const privateKey = await getPrivateKeyInteractive(result?.key);\n\n return createBillingModule({\n verbose: flags.verbose ?? false,\n privateKey: privateKey as Hex,\n });\n}\n","import {\n getEnvironmentInteractive,\n getPrivateKeyInteractive,\n getAvailableEnvironments,\n} from \"@layr-labs/ecloud-sdk\";\nimport { Flags } from \"@oclif/core\";\n\nexport type CommonFlags = {\n verbose: boolean;\n environment?: string;\n \"private-key\"?: string;\n \"rpc-url\"?: string;\n};\n\n// Get available environments dynamically from SDK based on build type\nconst getEnvironmentOptions = (): string[] => {\n try {\n return getAvailableEnvironments();\n } catch {\n // Fallback to all environments if SDK not available\n return [\"sepolia\", \"sepolia-dev\", \"mainnet-alpha\"];\n }\n};\n\nexport const commonFlags = {\n environment: Flags.string({\n required: false,\n description: \"Deployment environment to use\",\n options: getEnvironmentOptions(),\n env: \"ECLOUD_ENV\",\n }),\n \"private-key\": Flags.string({\n required: false,\n description: \"Private key for signing transactions\",\n env: \"ECLOUD_PRIVATE_KEY\",\n }),\n \"rpc-url\": Flags.string({\n required: false,\n description: \"RPC URL to connect to blockchain\",\n env: \"ECLOUD_RPC_URL\",\n }),\n verbose: Flags.boolean({\n required: false,\n description: \"Enable verbose logging (default: false)\",\n default: false,\n }),\n};\n\n// Validate or prompt for required common flags\nexport async function validateCommonFlags(flags: CommonFlags) {\n flags[\"environment\"] = await getEnvironmentInteractive(flags[\"environment\"]);\n flags[\"private-key\"] = await getPrivateKeyInteractive(flags[\"private-key\"]);\n\n return flags;\n}\n"],"mappings":"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","names":["Flags","getPrivateKeyInteractive","Flags"]}
@@ -3,121 +3,13 @@
3
3
  // src/commands/auth/generate.ts
4
4
  import { Command, Flags } from "@oclif/core";
5
5
  import { confirm } from "@inquirer/prompts";
6
- import { generateNewPrivateKey, storePrivateKey, keyExists } from "@layr-labs/ecloud-sdk";
7
-
8
- // src/utils/security.ts
9
- import { spawn, execSync } from "child_process";
10
- import { platform } from "os";
11
- import { select, password } from "@inquirer/prompts";
12
- async function showPrivateKey(content) {
13
- const pager = detectPager();
14
- if (pager) {
15
- try {
16
- await runPager(pager, content);
17
- return true;
18
- } catch (err) {
19
- console.error(`Failed to run pager: ${err}`);
20
- }
21
- }
22
- console.log("\nNo pager (less/more) found on PATH.");
23
- console.log("For security, avoid printing private keys to the terminal.");
24
- console.log("");
25
- const choice = await select({
26
- message: "Choose an option:",
27
- choices: [
28
- { name: "Abort (recommended)", value: "abort" },
29
- { name: "Print and clear screen", value: "print" }
30
- ]
31
- });
32
- if (choice === "print") {
33
- console.log(content);
34
- console.log("");
35
- console.log("Press Enter after you have securely saved the key.");
36
- console.log("The screen will be cleared...");
37
- await password({
38
- message: "",
39
- mask: ""
40
- });
41
- clearTerminal();
42
- return true;
43
- }
44
- return false;
45
- }
46
- function detectPager() {
47
- if (process.env.PAGER) {
48
- const pagerEnv = process.env.PAGER.trim();
49
- if (/^[a-zA-Z0-9_-]+$/.test(pagerEnv)) {
50
- return pagerEnv;
51
- }
52
- }
53
- const pagers = ["less", "more"];
54
- for (const pagerCmd of pagers) {
55
- if (commandExists(pagerCmd)) {
56
- return pagerCmd;
57
- }
58
- }
59
- return null;
60
- }
61
- function runPager(pager, content) {
62
- return new Promise((resolve, reject) => {
63
- const child = spawn(pager, [], {
64
- stdio: ["pipe", "inherit", "inherit"]
65
- });
66
- child.on("error", reject);
67
- child.on("exit", (code) => {
68
- if (code === 0) {
69
- resolve();
70
- } else {
71
- reject(new Error(`Pager exited with code ${code}`));
72
- }
73
- });
74
- try {
75
- const written = child.stdin.write(content);
76
- if (!written) {
77
- child.stdin.once("drain", () => {
78
- try {
79
- child.stdin.end();
80
- } catch (err) {
81
- reject(err);
82
- }
83
- });
84
- } else {
85
- child.stdin.end();
86
- }
87
- } catch (err) {
88
- reject(err);
89
- }
90
- });
91
- }
92
- function commandExists(command) {
93
- try {
94
- const cmd = platform() === "win32" ? `where ${command}` : `which ${command}`;
95
- execSync(cmd, { stdio: "ignore" });
96
- return true;
97
- } catch {
98
- return false;
99
- }
100
- }
101
- function clearTerminal() {
102
- if (platform() === "win32") {
103
- process.stdout.write("\x1Bc");
104
- } else {
105
- process.stdout.write("\x1B[2J\x1B[3J\x1B[H");
106
- }
107
- }
108
- function displayWarning(lines) {
109
- const width = lines.length > 0 ? Math.max(...lines.map((l) => l.length)) + 4 : 4;
110
- const border = "\u26A0".repeat(width);
111
- console.log("");
112
- console.log(border);
113
- for (const line of lines) {
114
- console.log(`\u26A0 ${line}`);
115
- }
116
- console.log(border);
117
- console.log("");
118
- }
119
-
120
- // src/commands/auth/generate.ts
6
+ import {
7
+ generateNewPrivateKey,
8
+ storePrivateKey,
9
+ keyExists,
10
+ showPrivateKey,
11
+ displayWarning
12
+ } from "@layr-labs/ecloud-sdk";
121
13
  var AuthGenerate = class _AuthGenerate extends Command {
122
14
  static description = "Generate a new private key";
123
15
  static aliases = ["auth:gen", "auth:new"];
@@ -191,7 +83,9 @@ Press 'q' to exit and continue...
191
83
  this.log(`
192
84
  \u2713 Private key stored in OS keyring`);
193
85
  this.log(`\u2713 Address: ${address}`);
194
- this.log("\nYou can now use ecloud commands without --private-key flag.");
86
+ this.log(
87
+ "\nYou can now use ecloud commands without --private-key flag."
88
+ );
195
89
  } catch (err) {
196
90
  this.error(`Failed to store key: ${err.message}`);
197
91
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/auth/generate.ts","../../../src/utils/security.ts"],"sourcesContent":["/**\n * Auth Generate Command\n *\n * Generate a new private key and optionally store it in OS keyring\n */\n\nimport { Command, Flags } from \"@oclif/core\";\nimport { confirm } from \"@inquirer/prompts\";\nimport { generateNewPrivateKey, storePrivateKey, keyExists } from \"@layr-labs/ecloud-sdk\";\nimport { showPrivateKey, displayWarning } from \"../../utils/security\";\n\nexport default class AuthGenerate extends Command {\n static description = \"Generate a new private key\";\n\n static aliases = [\"auth:gen\", \"auth:new\"];\n\n static examples = [\n \"<%= config.bin %> <%= command.id %>\",\n \"<%= config.bin %> <%= command.id %> --store\",\n ];\n\n static flags = {\n store: Flags.boolean({\n description: \"Automatically store in OS keyring\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(AuthGenerate);\n\n // Generate new key\n this.log(\"Generating new private key...\\n\");\n const { privateKey, address } = generateNewPrivateKey();\n\n // Display key securely\n const content = `\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\nA new private key was generated for you.\n\nIMPORTANT: You MUST backup this key now.\n It will never be shown again.\n\nAddress: ${address}\nPrivate key: ${privateKey}\n\n⚠️ SECURITY WARNING:\n • Anyone with this key can control your account\n • Never share it or commit it to version control\n • Store it in a secure password manager\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\nPress 'q' to exit and continue...\n`;\n\n const displayed = await showPrivateKey(content);\n\n if (!displayed) {\n this.log(\"Key generation cancelled.\");\n return;\n }\n\n // Ask about storing\n let shouldStore = flags.store;\n\n if (!shouldStore && displayed) {\n shouldStore = await confirm({\n message: \"Store this key in your OS keyring?\",\n default: true,\n });\n }\n\n if (shouldStore) {\n // Check if key already exists\n const exists = await keyExists();\n\n if (exists) {\n displayWarning([\n `WARNING: A private key for ecloud already exists!`,\n \"If you continue, the existing key will be PERMANENTLY REPLACED.\",\n \"This cannot be undone!\",\n \"\",\n \"The previous key will be lost forever if you haven't backed it up.\",\n ]);\n\n const confirmReplace = await confirm({\n message: `Replace existing key for ecloud?`,\n default: false,\n });\n\n if (!confirmReplace) {\n this.log(\n \"\\nKey not stored. If you did not save your new key when it was displayed, it is now lost and cannot be recovered.\",\n );\n return;\n }\n }\n\n // Store the key\n try {\n await storePrivateKey(privateKey);\n this.log(`\\n✓ Private key stored in OS keyring`);\n this.log(`✓ Address: ${address}`);\n this.log(\"\\nYou can now use ecloud commands without --private-key flag.\");\n } catch (err: any) {\n this.error(`Failed to store key: ${err.message}`);\n }\n } else {\n this.log(\"\\nKey not stored in keyring.\");\n this.log(\"Remember to save the key shown above in a secure location.\");\n }\n }\n}\n","/**\n * Security utilities for CLI\n *\n * Functions for securely displaying and handling sensitive content\n * like private keys.\n */\n\nimport { spawn, execSync } from \"child_process\";\nimport { platform } from \"os\";\nimport { select, password } from \"@inquirer/prompts\";\n\n/**\n * Display sensitive content using system pager (less/more)\n * Returns true if content was displayed, false if user aborted\n */\nexport async function showPrivateKey(content: string): Promise<boolean> {\n // Try to use system pager\n const pager = detectPager();\n\n if (pager) {\n try {\n await runPager(pager, content);\n return true;\n } catch (err) {\n console.error(`Failed to run pager: ${err}`);\n // Fall through to fallback\n }\n }\n\n // No pager available - give user a choice\n console.log(\"\\nNo pager (less/more) found on PATH.\");\n console.log(\"For security, avoid printing private keys to the terminal.\");\n console.log(\"\");\n\n const choice = await select({\n message: \"Choose an option:\",\n choices: [\n { name: \"Abort (recommended)\", value: \"abort\" },\n { name: \"Print and clear screen\", value: \"print\" },\n ],\n });\n\n if (choice === \"print\") {\n console.log(content);\n console.log(\"\");\n console.log(\"Press Enter after you have securely saved the key.\");\n console.log(\"The screen will be cleared...\");\n\n // Wait for Enter\n await password({\n message: \"\",\n mask: \"\",\n });\n\n clearTerminal();\n return true;\n }\n\n return false; // User aborted\n}\n\n/**\n * Detect system pager (less or more)\n */\nfunction detectPager(): string | null {\n // Check PAGER env var first\n if (process.env.PAGER) {\n const pagerEnv = process.env.PAGER.trim();\n // Only allow simple command names without arguments or special characters\n if (/^[a-zA-Z0-9_-]+$/.test(pagerEnv)) {\n return pagerEnv;\n }\n }\n\n // Try common pagers\n const pagers = [\"less\", \"more\"];\n\n for (const pagerCmd of pagers) {\n if (commandExists(pagerCmd)) {\n return pagerCmd;\n }\n }\n\n return null;\n}\n\n/**\n * Run pager with content\n */\nfunction runPager(pager: string, content: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(pager, [], {\n stdio: [\"pipe\", \"inherit\", \"inherit\"],\n });\n\n child.on(\"error\", reject);\n child.on(\"exit\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Pager exited with code ${code}`));\n }\n });\n\n try {\n const written = child.stdin!.write(content);\n if (!written) {\n child.stdin!.once(\"drain\", () => {\n try {\n child.stdin!.end();\n } catch (err) {\n reject(err);\n }\n });\n } else {\n child.stdin!.end();\n }\n } catch (err) {\n reject(err);\n }\n });\n}\n\n/**\n * Check if command exists\n */\nfunction commandExists(command: string): boolean {\n try {\n const cmd = platform() === \"win32\" ? `where ${command}` : `which ${command}`;\n execSync(cmd, { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Clear terminal screen\n */\nexport function clearTerminal(): void {\n if (platform() === \"win32\") {\n process.stdout.write(\"\\x1Bc\");\n } else {\n process.stdout.write(\"\\x1B[2J\\x1B[3J\\x1B[H\");\n }\n}\n\n/**\n * Get hidden input (password-style)\n */\nexport async function getHiddenInput(message: string): Promise<string> {\n return await password({\n message,\n mask: \"*\",\n });\n}\n\n/**\n * Display multi-line warning for destructive operations\n */\nexport function displayWarning(lines: string[]): void {\n const width = lines.length > 0 ? Math.max(...lines.map((l) => l.length)) + 4 : 4;\n const border = \"⚠\".repeat(width);\n\n console.log(\"\");\n console.log(border);\n for (const line of lines) {\n console.log(`⚠ ${line}`);\n }\n console.log(border);\n console.log(\"\");\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/commands/auth/generate.ts"],"sourcesContent":["/**\n * Auth Generate Command\n *\n * Generate a new private key and optionally store it in OS keyring\n */\n\nimport { Command, Flags } from \"@oclif/core\";\nimport { confirm } from \"@inquirer/prompts\";\nimport {\n generateNewPrivateKey,\n storePrivateKey,\n keyExists,\n showPrivateKey,\n displayWarning,\n} from \"@layr-labs/ecloud-sdk\";\n\nexport default class AuthGenerate extends Command {\n static description = \"Generate a new private key\";\n\n static aliases = [\"auth:gen\", \"auth:new\"];\n\n static examples = [\n \"<%= config.bin %> <%= command.id %>\",\n \"<%= config.bin %> <%= command.id %> --store\",\n ];\n\n static flags = {\n store: Flags.boolean({\n description: \"Automatically store in OS keyring\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(AuthGenerate);\n\n // Generate new key\n this.log(\"Generating new private key...\\n\");\n const { privateKey, address } = generateNewPrivateKey();\n\n // Display key securely\n const content = `\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\nA new private key was generated for you.\n\nIMPORTANT: You MUST backup this key now.\n It will never be shown again.\n\nAddress: ${address}\nPrivate key: ${privateKey}\n\n⚠️ SECURITY WARNING:\n • Anyone with this key can control your account\n • Never share it or commit it to version control\n • Store it in a secure password manager\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\nPress 'q' to exit and continue...\n`;\n\n const displayed = await showPrivateKey(content);\n\n if (!displayed) {\n this.log(\"Key generation cancelled.\");\n return;\n }\n\n // Ask about storing\n let shouldStore = flags.store;\n\n if (!shouldStore && displayed) {\n shouldStore = await confirm({\n message: \"Store this key in your OS keyring?\",\n default: true,\n });\n }\n\n if (shouldStore) {\n // Check if key already exists\n const exists = await keyExists();\n\n if (exists) {\n displayWarning([\n `WARNING: A private key for ecloud already exists!`,\n \"If you continue, the existing key will be PERMANENTLY REPLACED.\",\n \"This cannot be undone!\",\n \"\",\n \"The previous key will be lost forever if you haven't backed it up.\",\n ]);\n\n const confirmReplace = await confirm({\n message: `Replace existing key for ecloud?`,\n default: false,\n });\n\n if (!confirmReplace) {\n this.log(\n \"\\nKey not stored. If you did not save your new key when it was displayed, it is now lost and cannot be recovered.\"\n );\n return;\n }\n }\n\n // Store the key\n try {\n await storePrivateKey(privateKey);\n this.log(`\\n✓ Private key stored in OS keyring`);\n this.log(`✓ Address: ${address}`);\n this.log(\n \"\\nYou can now use ecloud commands without --private-key flag.\"\n );\n } catch (err: any) {\n this.error(`Failed to store key: ${err.message}`);\n }\n } else {\n this.log(\"\\nKey not stored in keyring.\");\n this.log(\"Remember to save the key shown above in a secure location.\");\n }\n }\n}\n"],"mappings":";;;AAMA,SAAS,SAAS,aAAa;AAC/B,SAAS,eAAe;AACxB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,IAAqB,eAArB,MAAqB,sBAAqB,QAAQ;AAAA,EAChD,OAAO,cAAc;AAAA,EAErB,OAAO,UAAU,CAAC,YAAY,UAAU;AAAA,EAExC,OAAO,WAAW;AAAA,IAChB;AAAA,IACA;AAAA,EACF;AAAA,EAEA,OAAO,QAAQ;AAAA,IACb,OAAO,MAAM,QAAQ;AAAA,MACnB,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,MAAM,aAAY;AAG/C,SAAK,IAAI,iCAAiC;AAC1C,UAAM,EAAE,YAAY,QAAQ,IAAI,sBAAsB;AAGtD,UAAM,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAOL,OAAO;AAAA,eACP,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWrB,UAAM,YAAY,MAAM,eAAe,OAAO;AAE9C,QAAI,CAAC,WAAW;AACd,WAAK,IAAI,2BAA2B;AACpC;AAAA,IACF;AAGA,QAAI,cAAc,MAAM;AAExB,QAAI,CAAC,eAAe,WAAW;AAC7B,oBAAc,MAAM,QAAQ;AAAA,QAC1B,SAAS;AAAA,QACT,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAEA,QAAI,aAAa;AAEf,YAAM,SAAS,MAAM,UAAU;AAE/B,UAAI,QAAQ;AACV,uBAAe;AAAA,UACb;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAED,cAAM,iBAAiB,MAAM,QAAQ;AAAA,UACnC,SAAS;AAAA,UACT,SAAS;AAAA,QACX,CAAC;AAED,YAAI,CAAC,gBAAgB;AACnB,eAAK;AAAA,YACH;AAAA,UACF;AACA;AAAA,QACF;AAAA,MACF;AAGA,UAAI;AACF,cAAM,gBAAgB,UAAU;AAChC,aAAK,IAAI;AAAA,wCAAsC;AAC/C,aAAK,IAAI,mBAAc,OAAO,EAAE;AAChC,aAAK;AAAA,UACH;AAAA,QACF;AAAA,MACF,SAAS,KAAU;AACjB,aAAK,MAAM,wBAAwB,IAAI,OAAO,EAAE;AAAA,MAClD;AAAA,IACF,OAAO;AACL,WAAK,IAAI,8BAA8B;AACvC,WAAK,IAAI,4DAA4D;AAAA,IACvE;AAAA,EACF;AACF;","names":[]}
@@ -2,40 +2,18 @@
2
2
 
3
3
  // src/commands/auth/login.ts
4
4
  import { Command } from "@oclif/core";
5
- import { confirm, select as select2 } from "@inquirer/prompts";
5
+ import { confirm, select } from "@inquirer/prompts";
6
6
  import {
7
7
  storePrivateKey,
8
8
  keyExists,
9
+ getHiddenInput,
9
10
  validatePrivateKey,
10
11
  getAddressFromPrivateKey,
12
+ displayWarning,
11
13
  getLegacyKeys,
12
14
  getLegacyPrivateKey,
13
15
  deleteLegacyPrivateKey
14
16
  } from "@layr-labs/ecloud-sdk";
15
-
16
- // src/utils/security.ts
17
- import { spawn, execSync } from "child_process";
18
- import { platform } from "os";
19
- import { select, password } from "@inquirer/prompts";
20
- async function getHiddenInput(message) {
21
- return await password({
22
- message,
23
- mask: "*"
24
- });
25
- }
26
- function displayWarning(lines) {
27
- const width = lines.length > 0 ? Math.max(...lines.map((l) => l.length)) + 4 : 4;
28
- const border = "\u26A0".repeat(width);
29
- console.log("");
30
- console.log(border);
31
- for (const line of lines) {
32
- console.log(`\u26A0 ${line}`);
33
- }
34
- console.log(border);
35
- console.log("");
36
- }
37
-
38
- // src/commands/auth/login.ts
39
17
  var AuthLogin = class extends Command {
40
18
  static description = "Store your private key in OS keyring";
41
19
  static examples = ["<%= config.bin %> <%= command.id %>"];
@@ -77,16 +55,23 @@ var AuthLogin = class extends Command {
77
55
  name: `${key.address} (${key.environment} - ${key.source})`,
78
56
  value: key
79
57
  }));
80
- selectedKey = await select2({
58
+ selectedKey = await select({
81
59
  message: "Select a key to import:",
82
60
  choices
83
61
  });
84
- privateKey = await getLegacyPrivateKey(selectedKey.environment, selectedKey.source);
62
+ privateKey = await getLegacyPrivateKey(
63
+ selectedKey.environment,
64
+ selectedKey.source
65
+ );
85
66
  if (!privateKey) {
86
- this.error(`Failed to retrieve legacy key for ${selectedKey.environment}`);
67
+ this.error(
68
+ `Failed to retrieve legacy key for ${selectedKey.environment}`
69
+ );
87
70
  }
88
- this.log(`
89
- Importing key from ${selectedKey.source}:${selectedKey.environment}`);
71
+ this.log(
72
+ `
73
+ Importing key from ${selectedKey.source}:${selectedKey.environment}`
74
+ );
90
75
  }
91
76
  }
92
77
  if (!privateKey) {
@@ -111,7 +96,9 @@ Address: ${address}`);
111
96
  await storePrivateKey(privateKey);
112
97
  this.log("\n\u2713 Private key stored in OS keyring");
113
98
  this.log(`\u2713 Address: ${address}`);
114
- this.log("\nNote: This key will be used for all environments (mainnet, sepolia, etc.)");
99
+ this.log(
100
+ "\nNote: This key will be used for all environments (mainnet, sepolia, etc.)"
101
+ );
115
102
  this.log("You can now use ecloud commands without --private-key flag.");
116
103
  if (selectedKey) {
117
104
  this.log("");
@@ -120,14 +107,21 @@ Address: ${address}`);
120
107
  default: false
121
108
  });
122
109
  if (confirmDelete) {
123
- const deleted = await deleteLegacyPrivateKey(selectedKey.environment, selectedKey.source);
110
+ const deleted = await deleteLegacyPrivateKey(
111
+ selectedKey.environment,
112
+ selectedKey.source
113
+ );
124
114
  if (deleted) {
125
115
  this.log(
126
116
  `
127
117
  \u2713 Legacy key deleted from ${selectedKey.source}:${selectedKey.environment}`
128
118
  );
129
- this.log("\nNote: The key is now only stored in ecloud. You can still use it with");
130
- this.log("eigenx-cli by providing --private-key flag or EIGENX_PRIVATE_KEY env var.");
119
+ this.log(
120
+ "\nNote: The key is now only stored in ecloud. You can still use it with"
121
+ );
122
+ this.log(
123
+ "eigenx-cli by providing --private-key flag or EIGENX_PRIVATE_KEY env var."
124
+ );
131
125
  } else {
132
126
  this.log(
133
127
  `
@@ -136,9 +130,13 @@ Address: ${address}`);
136
130
  this.log("The key may have already been removed.");
137
131
  }
138
132
  } else {
139
- this.log(`
140
- Legacy key kept in ${selectedKey.source}:${selectedKey.environment}`);
141
- this.log("You can delete it later using 'eigenx auth logout' if needed.");
133
+ this.log(
134
+ `
135
+ Legacy key kept in ${selectedKey.source}:${selectedKey.environment}`
136
+ );
137
+ this.log(
138
+ "You can delete it later using 'eigenx auth logout' if needed."
139
+ );
142
140
  }
143
141
  }
144
142
  } catch (err) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/auth/login.ts","../../../src/utils/security.ts"],"sourcesContent":["/**\n * Auth Login Command\n *\n * Store an existing private key in OS keyring\n */\n\nimport { Command } from \"@oclif/core\";\nimport { confirm, select } from \"@inquirer/prompts\";\nimport {\n storePrivateKey,\n keyExists,\n validatePrivateKey,\n getAddressFromPrivateKey,\n getLegacyKeys,\n getLegacyPrivateKey,\n deleteLegacyPrivateKey,\n type LegacyKey,\n} from \"@layr-labs/ecloud-sdk\";\nimport { getHiddenInput, displayWarning } from \"../../utils/security\";\n\nexport default class AuthLogin extends Command {\n static description = \"Store your private key in OS keyring\";\n\n static examples = [\"<%= config.bin %> <%= command.id %>\"];\n\n async run(): Promise<void> {\n // Check if key already exists\n const exists = await keyExists();\n\n if (exists) {\n displayWarning([\n \"WARNING: A private key for ecloud already exists!\",\n \"Replacing it will cause PERMANENT DATA LOSS if not backed up.\",\n \"The previous key will be lost forever.\",\n ]);\n\n const confirmReplace = await confirm({\n message: \"Replace existing key?\",\n default: false,\n });\n\n if (!confirmReplace) {\n this.log(\"\\nLogin cancelled.\");\n return;\n }\n }\n\n // Check for legacy keys from eigenx-cli\n const legacyKeys = await getLegacyKeys();\n let privateKey: string | null = null;\n let selectedKey: LegacyKey | null = null;\n\n if (legacyKeys.length > 0) {\n this.log(\"\\nFound legacy keys from eigenx-cli:\");\n this.log(\"\");\n\n // Display legacy keys\n for (const key of legacyKeys) {\n this.log(` Address: ${key.address}`);\n this.log(` Environment: ${key.environment}`);\n this.log(` Source: ${key.source}`);\n this.log(\"\");\n }\n\n const importLegacy = await confirm({\n message: \"Would you like to import one of these legacy keys?\",\n default: false,\n });\n\n if (importLegacy) {\n // Create choices for selection\n const choices = legacyKeys.map((key) => ({\n name: `${key.address} (${key.environment} - ${key.source})`,\n value: key,\n }));\n\n selectedKey = await select<LegacyKey>({\n message: \"Select a key to import:\",\n choices,\n });\n\n // Retrieve the actual private key\n privateKey = await getLegacyPrivateKey(selectedKey.environment, selectedKey.source);\n\n if (!privateKey) {\n this.error(`Failed to retrieve legacy key for ${selectedKey.environment}`);\n }\n\n this.log(`\\nImporting key from ${selectedKey.source}:${selectedKey.environment}`);\n }\n }\n\n // If no legacy key was selected, prompt for private key input\n if (!privateKey) {\n privateKey = await getHiddenInput(\"Enter your private key:\");\n\n privateKey = privateKey.trim();\n }\n\n if (!validatePrivateKey(privateKey)) {\n this.error(\"Invalid private key format. Please check and try again.\");\n }\n\n // Derive address for confirmation\n const address = getAddressFromPrivateKey(privateKey);\n\n this.log(`\\nAddress: ${address}`);\n\n const confirmStore = await confirm({\n message: \"Store this key in OS keyring?\",\n default: true,\n });\n\n if (!confirmStore) {\n this.log(\"\\nLogin cancelled.\");\n return;\n }\n\n // Store in keyring\n try {\n await storePrivateKey(privateKey);\n this.log(\"\\n✓ Private key stored in OS keyring\");\n this.log(`✓ Address: ${address}`);\n this.log(\"\\nNote: This key will be used for all environments (mainnet, sepolia, etc.)\");\n this.log(\"You can now use ecloud commands without --private-key flag.\");\n\n // Ask if user wants to delete the legacy key (only if save was successful)\n if (selectedKey) {\n this.log(\"\");\n const confirmDelete = await confirm({\n message: `Delete the legacy key from ${selectedKey.source}:${selectedKey.environment}?`,\n default: false,\n });\n\n if (confirmDelete) {\n const deleted = await deleteLegacyPrivateKey(selectedKey.environment, selectedKey.source);\n\n if (deleted) {\n this.log(\n `\\n✓ Legacy key deleted from ${selectedKey.source}:${selectedKey.environment}`,\n );\n this.log(\"\\nNote: The key is now only stored in ecloud. You can still use it with\");\n this.log(\"eigenx-cli by providing --private-key flag or EIGENX_PRIVATE_KEY env var.\");\n } else {\n this.log(\n `\\n⚠️ Failed to delete legacy key from ${selectedKey.source}:${selectedKey.environment}`,\n );\n this.log(\"The key may have already been removed.\");\n }\n } else {\n this.log(`\\nLegacy key kept in ${selectedKey.source}:${selectedKey.environment}`);\n this.log(\"You can delete it later using 'eigenx auth logout' if needed.\");\n }\n }\n } catch (err: any) {\n this.error(`Failed to store key: ${err.message}`);\n }\n }\n}\n","/**\n * Security utilities for CLI\n *\n * Functions for securely displaying and handling sensitive content\n * like private keys.\n */\n\nimport { spawn, execSync } from \"child_process\";\nimport { platform } from \"os\";\nimport { select, password } from \"@inquirer/prompts\";\n\n/**\n * Display sensitive content using system pager (less/more)\n * Returns true if content was displayed, false if user aborted\n */\nexport async function showPrivateKey(content: string): Promise<boolean> {\n // Try to use system pager\n const pager = detectPager();\n\n if (pager) {\n try {\n await runPager(pager, content);\n return true;\n } catch (err) {\n console.error(`Failed to run pager: ${err}`);\n // Fall through to fallback\n }\n }\n\n // No pager available - give user a choice\n console.log(\"\\nNo pager (less/more) found on PATH.\");\n console.log(\"For security, avoid printing private keys to the terminal.\");\n console.log(\"\");\n\n const choice = await select({\n message: \"Choose an option:\",\n choices: [\n { name: \"Abort (recommended)\", value: \"abort\" },\n { name: \"Print and clear screen\", value: \"print\" },\n ],\n });\n\n if (choice === \"print\") {\n console.log(content);\n console.log(\"\");\n console.log(\"Press Enter after you have securely saved the key.\");\n console.log(\"The screen will be cleared...\");\n\n // Wait for Enter\n await password({\n message: \"\",\n mask: \"\",\n });\n\n clearTerminal();\n return true;\n }\n\n return false; // User aborted\n}\n\n/**\n * Detect system pager (less or more)\n */\nfunction detectPager(): string | null {\n // Check PAGER env var first\n if (process.env.PAGER) {\n const pagerEnv = process.env.PAGER.trim();\n // Only allow simple command names without arguments or special characters\n if (/^[a-zA-Z0-9_-]+$/.test(pagerEnv)) {\n return pagerEnv;\n }\n }\n\n // Try common pagers\n const pagers = [\"less\", \"more\"];\n\n for (const pagerCmd of pagers) {\n if (commandExists(pagerCmd)) {\n return pagerCmd;\n }\n }\n\n return null;\n}\n\n/**\n * Run pager with content\n */\nfunction runPager(pager: string, content: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(pager, [], {\n stdio: [\"pipe\", \"inherit\", \"inherit\"],\n });\n\n child.on(\"error\", reject);\n child.on(\"exit\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Pager exited with code ${code}`));\n }\n });\n\n try {\n const written = child.stdin!.write(content);\n if (!written) {\n child.stdin!.once(\"drain\", () => {\n try {\n child.stdin!.end();\n } catch (err) {\n reject(err);\n }\n });\n } else {\n child.stdin!.end();\n }\n } catch (err) {\n reject(err);\n }\n });\n}\n\n/**\n * Check if command exists\n */\nfunction commandExists(command: string): boolean {\n try {\n const cmd = platform() === \"win32\" ? `where ${command}` : `which ${command}`;\n execSync(cmd, { stdio: \"ignore\" });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Clear terminal screen\n */\nexport function clearTerminal(): void {\n if (platform() === \"win32\") {\n process.stdout.write(\"\\x1Bc\");\n } else {\n process.stdout.write(\"\\x1B[2J\\x1B[3J\\x1B[H\");\n }\n}\n\n/**\n * Get hidden input (password-style)\n */\nexport async function getHiddenInput(message: string): Promise<string> {\n return await password({\n message,\n mask: \"*\",\n });\n}\n\n/**\n * Display multi-line warning for destructive operations\n */\nexport function displayWarning(lines: string[]): void {\n const width = lines.length > 0 ? Math.max(...lines.map((l) => l.length)) + 4 : 4;\n const border = \"⚠\".repeat(width);\n\n console.log(\"\");\n console.log(border);\n for (const line of lines) {\n console.log(`⚠ ${line}`);\n }\n console.log(border);\n console.log(\"\");\n}\n"],"mappings":";;;AAMA,SAAS,eAAe;AACxB,SAAS,SAAS,UAAAA,eAAc;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;;;ACVP,SAAS,OAAO,gBAAgB;AAChC,SAAS,gBAAgB;AACzB,SAAS,QAAQ,gBAAgB;AA6IjC,eAAsB,eAAe,SAAkC;AACrE,SAAO,MAAM,SAAS;AAAA,IACpB;AAAA,IACA,MAAM;AAAA,EACR,CAAC;AACH;AAKO,SAAS,eAAe,OAAuB;AACpD,QAAM,QAAQ,MAAM,SAAS,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,IAAI;AAC/E,QAAM,SAAS,SAAI,OAAO,KAAK;AAE/B,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,MAAM;AAClB,aAAW,QAAQ,OAAO;AACxB,YAAQ,IAAI,WAAM,IAAI,EAAE;AAAA,EAC1B;AACA,UAAQ,IAAI,MAAM;AAClB,UAAQ,IAAI,EAAE;AAChB;;;ADvJA,IAAqB,YAArB,cAAuC,QAAQ;AAAA,EAC7C,OAAO,cAAc;AAAA,EAErB,OAAO,WAAW,CAAC,qCAAqC;AAAA,EAExD,MAAM,MAAqB;AAEzB,UAAM,SAAS,MAAM,UAAU;AAE/B,QAAI,QAAQ;AACV,qBAAe;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAED,YAAM,iBAAiB,MAAM,QAAQ;AAAA,QACnC,SAAS;AAAA,QACT,SAAS;AAAA,MACX,CAAC;AAED,UAAI,CAAC,gBAAgB;AACnB,aAAK,IAAI,oBAAoB;AAC7B;AAAA,MACF;AAAA,IACF;AAGA,UAAM,aAAa,MAAM,cAAc;AACvC,QAAI,aAA4B;AAChC,QAAI,cAAgC;AAEpC,QAAI,WAAW,SAAS,GAAG;AACzB,WAAK,IAAI,sCAAsC;AAC/C,WAAK,IAAI,EAAE;AAGX,iBAAW,OAAO,YAAY;AAC5B,aAAK,IAAI,cAAc,IAAI,OAAO,EAAE;AACpC,aAAK,IAAI,kBAAkB,IAAI,WAAW,EAAE;AAC5C,aAAK,IAAI,aAAa,IAAI,MAAM,EAAE;AAClC,aAAK,IAAI,EAAE;AAAA,MACb;AAEA,YAAM,eAAe,MAAM,QAAQ;AAAA,QACjC,SAAS;AAAA,QACT,SAAS;AAAA,MACX,CAAC;AAED,UAAI,cAAc;AAEhB,cAAM,UAAU,WAAW,IAAI,CAAC,SAAS;AAAA,UACvC,MAAM,GAAG,IAAI,OAAO,KAAK,IAAI,WAAW,MAAM,IAAI,MAAM;AAAA,UACxD,OAAO;AAAA,QACT,EAAE;AAEF,sBAAc,MAAMC,QAAkB;AAAA,UACpC,SAAS;AAAA,UACT;AAAA,QACF,CAAC;AAGD,qBAAa,MAAM,oBAAoB,YAAY,aAAa,YAAY,MAAM;AAElF,YAAI,CAAC,YAAY;AACf,eAAK,MAAM,qCAAqC,YAAY,WAAW,EAAE;AAAA,QAC3E;AAEA,aAAK,IAAI;AAAA,qBAAwB,YAAY,MAAM,IAAI,YAAY,WAAW,EAAE;AAAA,MAClF;AAAA,IACF;AAGA,QAAI,CAAC,YAAY;AACf,mBAAa,MAAM,eAAe,yBAAyB;AAE3D,mBAAa,WAAW,KAAK;AAAA,IAC/B;AAEA,QAAI,CAAC,mBAAmB,UAAU,GAAG;AACnC,WAAK,MAAM,yDAAyD;AAAA,IACtE;AAGA,UAAM,UAAU,yBAAyB,UAAU;AAEnD,SAAK,IAAI;AAAA,WAAc,OAAO,EAAE;AAEhC,UAAM,eAAe,MAAM,QAAQ;AAAA,MACjC,SAAS;AAAA,MACT,SAAS;AAAA,IACX,CAAC;AAED,QAAI,CAAC,cAAc;AACjB,WAAK,IAAI,oBAAoB;AAC7B;AAAA,IACF;AAGA,QAAI;AACF,YAAM,gBAAgB,UAAU;AAChC,WAAK,IAAI,2CAAsC;AAC/C,WAAK,IAAI,mBAAc,OAAO,EAAE;AAChC,WAAK,IAAI,6EAA6E;AACtF,WAAK,IAAI,6DAA6D;AAGtE,UAAI,aAAa;AACf,aAAK,IAAI,EAAE;AACX,cAAM,gBAAgB,MAAM,QAAQ;AAAA,UAClC,SAAS,8BAA8B,YAAY,MAAM,IAAI,YAAY,WAAW;AAAA,UACpF,SAAS;AAAA,QACX,CAAC;AAED,YAAI,eAAe;AACjB,gBAAM,UAAU,MAAM,uBAAuB,YAAY,aAAa,YAAY,MAAM;AAExF,cAAI,SAAS;AACX,iBAAK;AAAA,cACH;AAAA,iCAA+B,YAAY,MAAM,IAAI,YAAY,WAAW;AAAA,YAC9E;AACA,iBAAK,IAAI,yEAAyE;AAClF,iBAAK,IAAI,2EAA2E;AAAA,UACtF,OAAO;AACL,iBAAK;AAAA,cACH;AAAA,iDAA0C,YAAY,MAAM,IAAI,YAAY,WAAW;AAAA,YACzF;AACA,iBAAK,IAAI,wCAAwC;AAAA,UACnD;AAAA,QACF,OAAO;AACL,eAAK,IAAI;AAAA,qBAAwB,YAAY,MAAM,IAAI,YAAY,WAAW,EAAE;AAChF,eAAK,IAAI,+DAA+D;AAAA,QAC1E;AAAA,MACF;AAAA,IACF,SAAS,KAAU;AACjB,WAAK,MAAM,wBAAwB,IAAI,OAAO,EAAE;AAAA,IAClD;AAAA,EACF;AACF;","names":["select","select"]}
1
+ {"version":3,"sources":["../../../src/commands/auth/login.ts"],"sourcesContent":["/**\n * Auth Login Command\n *\n * Store an existing private key in OS keyring\n */\n\nimport { Command } from \"@oclif/core\";\nimport { confirm, select } from \"@inquirer/prompts\";\nimport {\n storePrivateKey,\n keyExists,\n getHiddenInput,\n validatePrivateKey,\n getAddressFromPrivateKey,\n displayWarning,\n getLegacyKeys,\n getLegacyPrivateKey,\n deleteLegacyPrivateKey,\n type LegacyKey,\n} from \"@layr-labs/ecloud-sdk\";\n\nexport default class AuthLogin extends Command {\n static description = \"Store your private key in OS keyring\";\n\n static examples = [\"<%= config.bin %> <%= command.id %>\"];\n\n async run(): Promise<void> {\n // Check if key already exists\n const exists = await keyExists();\n\n if (exists) {\n displayWarning([\n \"WARNING: A private key for ecloud already exists!\",\n \"Replacing it will cause PERMANENT DATA LOSS if not backed up.\",\n \"The previous key will be lost forever.\",\n ]);\n\n const confirmReplace = await confirm({\n message: \"Replace existing key?\",\n default: false,\n });\n\n if (!confirmReplace) {\n this.log(\"\\nLogin cancelled.\");\n return;\n }\n }\n\n // Check for legacy keys from eigenx-cli\n const legacyKeys = await getLegacyKeys();\n let privateKey: string | null = null;\n let selectedKey: LegacyKey | null = null;\n\n if (legacyKeys.length > 0) {\n this.log(\"\\nFound legacy keys from eigenx-cli:\");\n this.log(\"\");\n\n // Display legacy keys\n for (const key of legacyKeys) {\n this.log(` Address: ${key.address}`);\n this.log(` Environment: ${key.environment}`);\n this.log(` Source: ${key.source}`);\n this.log(\"\");\n }\n\n const importLegacy = await confirm({\n message: \"Would you like to import one of these legacy keys?\",\n default: false,\n });\n\n if (importLegacy) {\n // Create choices for selection\n const choices = legacyKeys.map((key) => ({\n name: `${key.address} (${key.environment} - ${key.source})`,\n value: key,\n }));\n\n selectedKey = await select<LegacyKey>({\n message: \"Select a key to import:\",\n choices,\n });\n\n // Retrieve the actual private key\n privateKey = await getLegacyPrivateKey(\n selectedKey.environment,\n selectedKey.source\n );\n\n if (!privateKey) {\n this.error(\n `Failed to retrieve legacy key for ${selectedKey.environment}`\n );\n }\n\n this.log(\n `\\nImporting key from ${selectedKey.source}:${selectedKey.environment}`\n );\n }\n }\n\n // If no legacy key was selected, prompt for private key input\n if (!privateKey) {\n privateKey = await getHiddenInput(\"Enter your private key:\");\n\n privateKey = privateKey.trim();\n }\n\n if (!validatePrivateKey(privateKey)) {\n this.error(\"Invalid private key format. Please check and try again.\");\n }\n\n // Derive address for confirmation\n const address = getAddressFromPrivateKey(privateKey);\n\n this.log(`\\nAddress: ${address}`);\n\n const confirmStore = await confirm({\n message: \"Store this key in OS keyring?\",\n default: true,\n });\n\n if (!confirmStore) {\n this.log(\"\\nLogin cancelled.\");\n return;\n }\n\n // Store in keyring\n try {\n await storePrivateKey(privateKey);\n this.log(\"\\n✓ Private key stored in OS keyring\");\n this.log(`✓ Address: ${address}`);\n this.log(\n \"\\nNote: This key will be used for all environments (mainnet, sepolia, etc.)\"\n );\n this.log(\"You can now use ecloud commands without --private-key flag.\");\n\n // Ask if user wants to delete the legacy key (only if save was successful)\n if (selectedKey) {\n this.log(\"\");\n const confirmDelete = await confirm({\n message: `Delete the legacy key from ${selectedKey.source}:${selectedKey.environment}?`,\n default: false,\n });\n\n if (confirmDelete) {\n const deleted = await deleteLegacyPrivateKey(\n selectedKey.environment,\n selectedKey.source\n );\n\n if (deleted) {\n this.log(\n `\\n✓ Legacy key deleted from ${selectedKey.source}:${selectedKey.environment}`\n );\n this.log(\n \"\\nNote: The key is now only stored in ecloud. You can still use it with\"\n );\n this.log(\n \"eigenx-cli by providing --private-key flag or EIGENX_PRIVATE_KEY env var.\"\n );\n } else {\n this.log(\n `\\n⚠️ Failed to delete legacy key from ${selectedKey.source}:${selectedKey.environment}`\n );\n this.log(\"The key may have already been removed.\");\n }\n } else {\n this.log(\n `\\nLegacy key kept in ${selectedKey.source}:${selectedKey.environment}`\n );\n this.log(\n \"You can delete it later using 'eigenx auth logout' if needed.\"\n );\n }\n }\n } catch (err: any) {\n this.error(`Failed to store key: ${err.message}`);\n }\n }\n}\n"],"mappings":"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","names":[]}