codecrypto-cli 1.0.4 → 1.0.6

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.
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const authCommand: Command;
3
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+BpC,eAAO,MAAM,WAAW,SA6RpB,CAAC"}
@@ -0,0 +1,298 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.authCommand = void 0;
40
+ const commander_1 = require("commander");
41
+ const chalk_1 = __importDefault(require("chalk"));
42
+ const ora_1 = __importDefault(require("ora"));
43
+ const fs = __importStar(require("fs"));
44
+ const path = __importStar(require("path"));
45
+ const os = __importStar(require("os"));
46
+ const jose_1 = require("jose");
47
+ const API_BASE_URL = 'http://localhost:3000';
48
+ const POLL_INTERVAL = 3000; // 3 segundos
49
+ const MAX_POLL_ATTEMPTS = 100; // Máximo 5 minutos (100 * 3 segundos)
50
+ exports.authCommand = new commander_1.Command('auth')
51
+ .description('Authenticate with CodeCrypto platform')
52
+ .option('--server-url <url>', 'Server URL', API_BASE_URL)
53
+ .option('--poll-interval <seconds>', 'Polling interval in seconds', '3')
54
+ .option('--debug', 'Show debug information', false)
55
+ .action(async (options) => {
56
+ console.log(chalk_1.default.blue('\n🔐 CodeCrypto Authentication\n'));
57
+ const serverUrl = options.serverUrl || API_BASE_URL;
58
+ const pollInterval = parseInt(options.pollInterval || '3', 10) * 1000;
59
+ try {
60
+ // Paso 1: Solicitar código de autenticación
61
+ const requestSpinner = (0, ora_1.default)('Requesting authentication code...').start();
62
+ let tokenData;
63
+ try {
64
+ const response = await fetch(`${serverUrl}/api/tokens`, {
65
+ method: 'POST',
66
+ headers: {
67
+ 'Content-Type': 'application/json',
68
+ },
69
+ });
70
+ if (!response.ok) {
71
+ throw new Error(`HTTP error! status: ${response.status}`);
72
+ }
73
+ const jsonData = await response.json();
74
+ if (options.debug) {
75
+ console.log(chalk_1.default.gray(`\n[DEBUG] POST Response: ${JSON.stringify(jsonData, null, 2)}`));
76
+ }
77
+ tokenData = jsonData;
78
+ // Validar estructura de respuesta
79
+ if (!tokenData || typeof tokenData !== 'object') {
80
+ throw new Error('Invalid response format from server');
81
+ }
82
+ if (!tokenData.success) {
83
+ throw new Error(`Server returned error: ${tokenData.error || 'Unknown error'}`);
84
+ }
85
+ if (!tokenData.data || typeof tokenData.data !== 'object') {
86
+ throw new Error('Response data is missing or invalid');
87
+ }
88
+ // Extraer y validar _id y code de la respuesta
89
+ const responseId = tokenData.data._id;
90
+ const responseCode = tokenData.data.code;
91
+ if (!responseId || typeof responseId !== 'string' || responseId.trim() === '') {
92
+ console.error(chalk_1.default.red(`❌ Error: Invalid or missing _id in response`));
93
+ if (options.debug) {
94
+ console.log(chalk_1.default.gray(`\n[DEBUG] Full response: ${JSON.stringify(tokenData, null, 2)}`));
95
+ }
96
+ throw new Error('Invalid token ID received from server');
97
+ }
98
+ if (!responseCode || typeof responseCode !== 'string' || responseCode.trim() === '') {
99
+ console.error(chalk_1.default.red(`❌ Error: Invalid or missing code in response`));
100
+ if (options.debug) {
101
+ console.log(chalk_1.default.gray(`\n[DEBUG] Full response: ${JSON.stringify(tokenData, null, 2)}`));
102
+ }
103
+ throw new Error('Invalid code received from server');
104
+ }
105
+ requestSpinner.succeed('Authentication code received');
106
+ }
107
+ catch (error) {
108
+ requestSpinner.fail('Failed to request authentication code');
109
+ console.error(chalk_1.default.red(`❌ Error: ${error.message}`));
110
+ if (options.debug && error.stack) {
111
+ console.error(chalk_1.default.gray(`\n[DEBUG] Stack: ${error.stack}`));
112
+ }
113
+ process.exit(1);
114
+ }
115
+ // EXTRAER DIRECTAMENTE DE LA RESPUESTA - NUNCA HARDCODEADO
116
+ // Obtener el _id y code directamente de la respuesta del POST
117
+ const tokenId = String(tokenData.data._id).trim();
118
+ const code = String(tokenData.data.code).trim();
119
+ // Verificación final (no debería fallar si llegamos aquí, pero por seguridad)
120
+ if (!tokenId || tokenId === '' || !code || code === '') {
121
+ console.error(chalk_1.default.red(`❌ Error: Missing tokenId or code after extraction`));
122
+ console.error(chalk_1.default.red(` tokenId: "${tokenId}"`));
123
+ console.error(chalk_1.default.red(` code: "${code}"`));
124
+ console.error(chalk_1.default.red(` Full response data: ${JSON.stringify(tokenData.data, null, 2)}`));
125
+ process.exit(1);
126
+ }
127
+ const tokenUrl = `${serverUrl}/token`;
128
+ // Mostrar información al usuario con el ID REAL obtenido
129
+ console.log(chalk_1.default.green('\n✅ Authentication code generated!'));
130
+ console.log(chalk_1.default.white(`\n Code: ${chalk_1.default.cyan(code)}`));
131
+ console.log(chalk_1.default.white(` Token ID: ${chalk_1.default.gray(tokenId)}`));
132
+ console.log(chalk_1.default.white(`\n Please visit: ${chalk_1.default.cyan.underline(tokenUrl)}`));
133
+ console.log(chalk_1.default.gray(' Enter the code above to complete authentication.\n'));
134
+ // Log explícito del ID que se va a usar
135
+ console.log(chalk_1.default.gray(`[INFO] Will poll using token ID: ${chalk_1.default.yellow(tokenId)}\n`));
136
+ // Paso 2: Polling para verificar el token
137
+ const pollSpinner = (0, ora_1.default)('Waiting for token verification...').start();
138
+ let verifiedToken = null;
139
+ let tokenEmail = null;
140
+ let attempts = 0;
141
+ // Función helper para extraer el token JWT y el email de la respuesta
142
+ const extractToken = (data) => {
143
+ if (!data)
144
+ return { token: null, email: null };
145
+ let jwtToken = null;
146
+ let email = null;
147
+ // Estructura real: data.success && data.data.jwt (el JWT está en data.jwt)
148
+ if (data.success && data.data) {
149
+ // El JWT puede estar en data.jwt o data.token
150
+ jwtToken = data.data.jwt || data.data.token || null;
151
+ // El email está directamente en data.email
152
+ email = data.data.email || null;
153
+ }
154
+ // Estructura alternativa: data.jwt directamente
155
+ else if (data.jwt && typeof data.jwt === 'string') {
156
+ jwtToken = data.jwt;
157
+ email = data.email || null;
158
+ }
159
+ // Estructura alternativa: data.token
160
+ else if (data.token && typeof data.token === 'string') {
161
+ jwtToken = data.token;
162
+ email = data.email || null;
163
+ }
164
+ if (!jwtToken) {
165
+ return { token: null, email: null };
166
+ }
167
+ // Si no tenemos email de la respuesta, intentar extraerlo del JWT
168
+ if (!email) {
169
+ try {
170
+ const decoded = (0, jose_1.decodeJwt)(jwtToken);
171
+ // El email puede estar en diferentes campos del payload
172
+ email = decoded.email ||
173
+ decoded.sub ||
174
+ decoded.user?.email ||
175
+ null;
176
+ if (options.debug) {
177
+ console.log(chalk_1.default.gray(`[DEBUG] JWT decoded payload: ${JSON.stringify(decoded, null, 2)}`));
178
+ console.log(chalk_1.default.gray(`[DEBUG] Email extracted from JWT: ${email}`));
179
+ }
180
+ }
181
+ catch (error) {
182
+ if (options.debug) {
183
+ console.log(chalk_1.default.yellow(`[DEBUG] Could not decode JWT: ${error.message}`));
184
+ }
185
+ }
186
+ }
187
+ else {
188
+ if (options.debug) {
189
+ console.log(chalk_1.default.gray(`[DEBUG] Email from response data: ${email}`));
190
+ }
191
+ }
192
+ return { token: jwtToken, email };
193
+ };
194
+ while (!verifiedToken && attempts < MAX_POLL_ATTEMPTS) {
195
+ try {
196
+ // Esperar antes de cada intento excepto el primero
197
+ if (attempts > 0) {
198
+ await new Promise(resolve => setTimeout(resolve, pollInterval));
199
+ }
200
+ // CONSTRUIR URL CON EL TOKEN ID OBTENIDO DEL POST - NUNCA HARDCODEADO
201
+ // Asegurarse de que tokenId es el valor real de la respuesta
202
+ const currentTokenId = tokenId; // Variable local para asegurar que usamos el valor correcto
203
+ const verifyUrl = `${serverUrl}/api/tokens/${currentTokenId}`;
204
+ // SIEMPRE mostrar el ID que se está usando (no solo en debug)
205
+ if (attempts === 0) {
206
+ console.log(chalk_1.default.yellow(`\n[POLLING] Using Token ID: ${chalk_1.default.cyan(currentTokenId)}`));
207
+ console.log(chalk_1.default.yellow(`[POLLING] URL: ${chalk_1.default.cyan(verifyUrl)}\n`));
208
+ }
209
+ if (options.debug) {
210
+ console.log(chalk_1.default.gray(`[DEBUG] Attempt ${attempts + 1}`));
211
+ console.log(chalk_1.default.gray(`[DEBUG] Token ID from POST response: ${currentTokenId}`));
212
+ console.log(chalk_1.default.gray(`[DEBUG] Code from POST response: ${code}`));
213
+ console.log(chalk_1.default.gray(`[DEBUG] Full verification URL: ${verifyUrl}`));
214
+ }
215
+ const verifyResponse = await fetch(verifyUrl, {
216
+ method: 'GET',
217
+ headers: {
218
+ 'Content-Type': 'application/json',
219
+ },
220
+ });
221
+ if (verifyResponse.ok) {
222
+ const verifyData = await verifyResponse.json();
223
+ if (options.debug) {
224
+ console.log(chalk_1.default.gray(`\n[DEBUG] Attempt ${attempts + 1} - Response: ${JSON.stringify(verifyData, null, 2)}`));
225
+ }
226
+ // Intentar extraer el token
227
+ const extracted = extractToken(verifyData);
228
+ if (extracted.token) {
229
+ verifiedToken = extracted.token;
230
+ tokenEmail = extracted.email;
231
+ break;
232
+ }
233
+ }
234
+ else {
235
+ // Si la respuesta no es OK, mostrar el status para debug
236
+ if (options.debug) {
237
+ const errorText = await verifyResponse.text();
238
+ console.log(chalk_1.default.yellow(`[DEBUG] HTTP Status: ${verifyResponse.status}, Response: ${errorText}`));
239
+ }
240
+ }
241
+ attempts++;
242
+ pollSpinner.text = `Waiting for token verification... (attempt ${attempts}/${MAX_POLL_ATTEMPTS})`;
243
+ }
244
+ catch (error) {
245
+ // Continuar intentando en caso de error de red
246
+ if (options.debug) {
247
+ console.log(chalk_1.default.yellow(`[DEBUG] Error: ${error.message}`));
248
+ }
249
+ attempts++;
250
+ pollSpinner.text = `Waiting for token verification... (attempt ${attempts}/${MAX_POLL_ATTEMPTS})`;
251
+ }
252
+ }
253
+ if (!verifiedToken) {
254
+ pollSpinner.fail('Token verification timeout');
255
+ console.error(chalk_1.default.red('\n❌ Authentication timeout. Please try again.'));
256
+ console.error(chalk_1.default.yellow('\n💡 Tip: Use --debug flag to see detailed response information'));
257
+ console.error(chalk_1.default.yellow(` Example: codecrypto auth --debug\n`));
258
+ process.exit(1);
259
+ }
260
+ pollSpinner.succeed('Token verified successfully');
261
+ // Paso 3: Guardar token en ~/.codecrypto
262
+ const homeDir = os.homedir();
263
+ const codecryptoDir = path.join(homeDir, '.codecrypto');
264
+ const tokenFile = path.join(codecryptoDir, 'token.json');
265
+ const saveSpinner = (0, ora_1.default)('Saving authentication token...').start();
266
+ try {
267
+ // Crear directorio si no existe
268
+ if (!fs.existsSync(codecryptoDir)) {
269
+ fs.mkdirSync(codecryptoDir, { recursive: true });
270
+ }
271
+ // Guardar token
272
+ const tokenContent = {
273
+ token: verifiedToken,
274
+ email: tokenEmail,
275
+ serverUrl: serverUrl,
276
+ createdAt: new Date().toISOString(),
277
+ };
278
+ fs.writeFileSync(tokenFile, JSON.stringify(tokenContent, null, 2), 'utf-8');
279
+ saveSpinner.succeed('Token saved successfully');
280
+ }
281
+ catch (error) {
282
+ saveSpinner.fail('Failed to save token');
283
+ console.error(chalk_1.default.red(`❌ Error: ${error.message}`));
284
+ process.exit(1);
285
+ }
286
+ console.log(chalk_1.default.green('\n✅ Authentication completed successfully!'));
287
+ console.log(chalk_1.default.gray(` Token saved to: ${chalk_1.default.cyan(tokenFile)}`));
288
+ if (tokenEmail) {
289
+ console.log(chalk_1.default.gray(` Email: ${chalk_1.default.cyan(tokenEmail)}`));
290
+ }
291
+ console.log('');
292
+ }
293
+ catch (error) {
294
+ console.error(chalk_1.default.red(`\n❌ Error: ${error.message}`));
295
+ process.exit(1);
296
+ }
297
+ });
298
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -4,9 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const commander_1 = require("commander");
5
5
  const deploy_1 = require("./commands/deploy");
6
6
  const deploy_sc_1 = require("./commands/deploy-sc");
7
- const user_1 = require("./commands/user");
8
- const config_1 = require("./commands/config");
9
- const database_1 = require("./commands/database");
7
+ const auth_1 = require("./commands/auth");
10
8
  const program = new commander_1.Command();
11
9
  program
12
10
  .name('codecrypto')
@@ -15,8 +13,6 @@ program
15
13
  // Registrar comandos
16
14
  program.addCommand(deploy_1.deployCommand);
17
15
  program.addCommand(deploy_sc_1.deployScCommand);
18
- program.addCommand(user_1.userCommand);
19
- program.addCommand(config_1.configCommand);
20
- program.addCommand(database_1.dbCommand);
16
+ program.addCommand(auth_1.authCommand);
21
17
  program.parse(process.argv);
22
18
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,8CAAkD;AAClD,oDAAuD;AACvD,0CAA8C;AAC9C,8CAAkD;AAClD,kDAAgD;AAEhD,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,oCAAoC,CAAC;KACjD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,qBAAqB;AACrB,OAAO,CAAC,UAAU,CAAC,sBAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,2BAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,kBAAW,CAAC,CAAC;AAChC,OAAO,CAAC,UAAU,CAAC,sBAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,oBAAS,CAAC,CAAC;AAE9B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,yCAAoC;AACpC,8CAAkD;AAClD,oDAAuD;AACvD,0CAA8C;AAE9C,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,oCAAoC,CAAC;KACjD,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,qBAAqB;AACrB,OAAO,CAAC,UAAU,CAAC,sBAAa,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,2BAAe,CAAC,CAAC;AACpC,OAAO,CAAC,UAAU,CAAC,kBAAW,CAAC,CAAC;AAEhC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codecrypto-cli",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "CLI tool for CodeCrypto operations",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -20,16 +20,17 @@
20
20
  "author": "",
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
- "commander": "^12.0.0",
24
23
  "chalk": "^4.1.2",
25
- "ora": "^5.4.1",
26
- "inquirer": "^8.2.5"
24
+ "commander": "^12.0.0",
25
+ "inquirer": "^8.2.5",
26
+ "jose": "^6.1.3",
27
+ "ora": "^5.4.1"
27
28
  },
28
29
  "devDependencies": {
29
- "@types/node": "^20.10.0",
30
30
  "@types/inquirer": "^9.0.7",
31
- "typescript": "^5.3.0",
32
- "tsx": "^4.7.0"
31
+ "@types/node": "^20.10.0",
32
+ "tsx": "^4.7.0",
33
+ "typescript": "^5.3.0"
33
34
  },
34
35
  "engines": {
35
36
  "node": ">=16.0.0"
@@ -0,0 +1,318 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import * as fs from 'fs';
5
+ import * as path from 'path';
6
+ import * as os from 'os';
7
+ import { decodeJwt } from 'jose';
8
+
9
+ interface TokenResponse {
10
+ success: boolean;
11
+ data: {
12
+ _id: string;
13
+ code: string;
14
+ createdAt: string;
15
+ };
16
+ }
17
+
18
+ interface TokenVerificationResponse {
19
+ success: boolean;
20
+ data?: {
21
+ token?: string;
22
+ email?: string;
23
+ [key: string]: any;
24
+ };
25
+ error?: string;
26
+ }
27
+
28
+ const API_BASE_URL = 'http://localhost:3000';
29
+ const POLL_INTERVAL = 3000; // 3 segundos
30
+ const MAX_POLL_ATTEMPTS = 100; // Máximo 5 minutos (100 * 3 segundos)
31
+
32
+ export const authCommand = new Command('auth')
33
+ .description('Authenticate with CodeCrypto platform')
34
+ .option('--server-url <url>', 'Server URL', API_BASE_URL)
35
+ .option('--poll-interval <seconds>', 'Polling interval in seconds', '3')
36
+ .option('--debug', 'Show debug information', false)
37
+ .action(async (options) => {
38
+ console.log(chalk.blue('\n🔐 CodeCrypto Authentication\n'));
39
+
40
+ const serverUrl = options.serverUrl || API_BASE_URL;
41
+ const pollInterval = parseInt(options.pollInterval || '3', 10) * 1000;
42
+
43
+ try {
44
+ // Paso 1: Solicitar código de autenticación
45
+ const requestSpinner = ora('Requesting authentication code...').start();
46
+
47
+ let tokenData: TokenResponse;
48
+ try {
49
+ const response = await fetch(`${serverUrl}/api/tokens`, {
50
+ method: 'POST',
51
+ headers: {
52
+ 'Content-Type': 'application/json',
53
+ },
54
+ });
55
+
56
+ if (!response.ok) {
57
+ throw new Error(`HTTP error! status: ${response.status}`);
58
+ }
59
+
60
+ const jsonData = await response.json();
61
+
62
+ if (options.debug) {
63
+ console.log(chalk.gray(`\n[DEBUG] POST Response: ${JSON.stringify(jsonData, null, 2)}`));
64
+ }
65
+
66
+ tokenData = jsonData as TokenResponse;
67
+
68
+ // Validar estructura de respuesta
69
+ if (!tokenData || typeof tokenData !== 'object') {
70
+ throw new Error('Invalid response format from server');
71
+ }
72
+
73
+ if (!tokenData.success) {
74
+ throw new Error(`Server returned error: ${(tokenData as any).error || 'Unknown error'}`);
75
+ }
76
+
77
+ if (!tokenData.data || typeof tokenData.data !== 'object') {
78
+ throw new Error('Response data is missing or invalid');
79
+ }
80
+
81
+ // Extraer y validar _id y code de la respuesta
82
+ const responseId = tokenData.data._id;
83
+ const responseCode = tokenData.data.code;
84
+
85
+ if (!responseId || typeof responseId !== 'string' || responseId.trim() === '') {
86
+ console.error(chalk.red(`❌ Error: Invalid or missing _id in response`));
87
+ if (options.debug) {
88
+ console.log(chalk.gray(`\n[DEBUG] Full response: ${JSON.stringify(tokenData, null, 2)}`));
89
+ }
90
+ throw new Error('Invalid token ID received from server');
91
+ }
92
+
93
+ if (!responseCode || typeof responseCode !== 'string' || responseCode.trim() === '') {
94
+ console.error(chalk.red(`❌ Error: Invalid or missing code in response`));
95
+ if (options.debug) {
96
+ console.log(chalk.gray(`\n[DEBUG] Full response: ${JSON.stringify(tokenData, null, 2)}`));
97
+ }
98
+ throw new Error('Invalid code received from server');
99
+ }
100
+
101
+ requestSpinner.succeed('Authentication code received');
102
+ } catch (error: any) {
103
+ requestSpinner.fail('Failed to request authentication code');
104
+ console.error(chalk.red(`❌ Error: ${error.message}`));
105
+ if (options.debug && error.stack) {
106
+ console.error(chalk.gray(`\n[DEBUG] Stack: ${error.stack}`));
107
+ }
108
+ process.exit(1);
109
+ }
110
+
111
+ // EXTRAER DIRECTAMENTE DE LA RESPUESTA - NUNCA HARDCODEADO
112
+ // Obtener el _id y code directamente de la respuesta del POST
113
+ const tokenId = String(tokenData.data._id).trim();
114
+ const code = String(tokenData.data.code).trim();
115
+
116
+ // Verificación final (no debería fallar si llegamos aquí, pero por seguridad)
117
+ if (!tokenId || tokenId === '' || !code || code === '') {
118
+ console.error(chalk.red(`❌ Error: Missing tokenId or code after extraction`));
119
+ console.error(chalk.red(` tokenId: "${tokenId}"`));
120
+ console.error(chalk.red(` code: "${code}"`));
121
+ console.error(chalk.red(` Full response data: ${JSON.stringify(tokenData.data, null, 2)}`));
122
+ process.exit(1);
123
+ }
124
+
125
+ const tokenUrl = `${serverUrl}/token`;
126
+
127
+ // Mostrar información al usuario con el ID REAL obtenido
128
+ console.log(chalk.green('\n✅ Authentication code generated!'));
129
+ console.log(chalk.white(`\n Code: ${chalk.cyan(code)}`));
130
+ console.log(chalk.white(` Token ID: ${chalk.gray(tokenId)}`));
131
+ console.log(chalk.white(`\n Please visit: ${chalk.cyan.underline(tokenUrl)}`));
132
+ console.log(chalk.gray(' Enter the code above to complete authentication.\n'));
133
+
134
+ // Log explícito del ID que se va a usar
135
+ console.log(chalk.gray(`[INFO] Will poll using token ID: ${chalk.yellow(tokenId)}\n`));
136
+
137
+ // Paso 2: Polling para verificar el token
138
+ const pollSpinner = ora('Waiting for token verification...').start();
139
+
140
+ let verifiedToken: string | null = null;
141
+ let tokenEmail: string | null = null;
142
+ let attempts = 0;
143
+
144
+ // Función helper para extraer el token JWT y el email de la respuesta
145
+ const extractToken = (data: any): { token: string | null; email: string | null } => {
146
+ if (!data) return { token: null, email: null };
147
+
148
+ let jwtToken: string | null = null;
149
+ let email: string | null = null;
150
+
151
+ // Estructura real: data.success && data.data.jwt (el JWT está en data.jwt)
152
+ if (data.success && data.data) {
153
+ // El JWT puede estar en data.jwt o data.token
154
+ jwtToken = data.data.jwt || data.data.token || null;
155
+ // El email está directamente en data.email
156
+ email = data.data.email || null;
157
+ }
158
+ // Estructura alternativa: data.jwt directamente
159
+ else if (data.jwt && typeof data.jwt === 'string') {
160
+ jwtToken = data.jwt;
161
+ email = data.email || null;
162
+ }
163
+ // Estructura alternativa: data.token
164
+ else if (data.token && typeof data.token === 'string') {
165
+ jwtToken = data.token;
166
+ email = data.email || null;
167
+ }
168
+
169
+ if (!jwtToken) {
170
+ return { token: null, email: null };
171
+ }
172
+
173
+ // Si no tenemos email de la respuesta, intentar extraerlo del JWT
174
+ if (!email) {
175
+ try {
176
+ const decoded = decodeJwt(jwtToken) as any;
177
+ // El email puede estar en diferentes campos del payload
178
+ email = decoded.email ||
179
+ decoded.sub ||
180
+ decoded.user?.email ||
181
+ null;
182
+
183
+ if (options.debug) {
184
+ console.log(chalk.gray(`[DEBUG] JWT decoded payload: ${JSON.stringify(decoded, null, 2)}`));
185
+ console.log(chalk.gray(`[DEBUG] Email extracted from JWT: ${email}`));
186
+ }
187
+ } catch (error: any) {
188
+ if (options.debug) {
189
+ console.log(chalk.yellow(`[DEBUG] Could not decode JWT: ${error.message}`));
190
+ }
191
+ }
192
+ } else {
193
+ if (options.debug) {
194
+ console.log(chalk.gray(`[DEBUG] Email from response data: ${email}`));
195
+ }
196
+ }
197
+
198
+ return { token: jwtToken, email };
199
+ };
200
+
201
+ while (!verifiedToken && attempts < MAX_POLL_ATTEMPTS) {
202
+ try {
203
+ // Esperar antes de cada intento excepto el primero
204
+ if (attempts > 0) {
205
+ await new Promise(resolve => setTimeout(resolve, pollInterval));
206
+ }
207
+
208
+ // CONSTRUIR URL CON EL TOKEN ID OBTENIDO DEL POST - NUNCA HARDCODEADO
209
+ // Asegurarse de que tokenId es el valor real de la respuesta
210
+ const currentTokenId = tokenId; // Variable local para asegurar que usamos el valor correcto
211
+ const verifyUrl = `${serverUrl}/api/tokens/${currentTokenId}`;
212
+
213
+ // SIEMPRE mostrar el ID que se está usando (no solo en debug)
214
+ if (attempts === 0) {
215
+ console.log(chalk.yellow(`\n[POLLING] Using Token ID: ${chalk.cyan(currentTokenId)}`));
216
+ console.log(chalk.yellow(`[POLLING] URL: ${chalk.cyan(verifyUrl)}\n`));
217
+ }
218
+
219
+ if (options.debug) {
220
+ console.log(chalk.gray(`[DEBUG] Attempt ${attempts + 1}`));
221
+ console.log(chalk.gray(`[DEBUG] Token ID from POST response: ${currentTokenId}`));
222
+ console.log(chalk.gray(`[DEBUG] Code from POST response: ${code}`));
223
+ console.log(chalk.gray(`[DEBUG] Full verification URL: ${verifyUrl}`));
224
+ }
225
+
226
+ const verifyResponse = await fetch(verifyUrl, {
227
+ method: 'GET',
228
+ headers: {
229
+ 'Content-Type': 'application/json',
230
+ },
231
+ });
232
+
233
+ if (verifyResponse.ok) {
234
+ const verifyData = await verifyResponse.json();
235
+
236
+ if (options.debug) {
237
+ console.log(chalk.gray(`\n[DEBUG] Attempt ${attempts + 1} - Response: ${JSON.stringify(verifyData, null, 2)}`));
238
+ }
239
+
240
+ // Intentar extraer el token
241
+ const extracted = extractToken(verifyData);
242
+ if (extracted.token) {
243
+ verifiedToken = extracted.token;
244
+ tokenEmail = extracted.email;
245
+ break;
246
+ }
247
+ } else {
248
+ // Si la respuesta no es OK, mostrar el status para debug
249
+ if (options.debug) {
250
+ const errorText = await verifyResponse.text();
251
+ console.log(chalk.yellow(`[DEBUG] HTTP Status: ${verifyResponse.status}, Response: ${errorText}`));
252
+ }
253
+ }
254
+
255
+ attempts++;
256
+ pollSpinner.text = `Waiting for token verification... (attempt ${attempts}/${MAX_POLL_ATTEMPTS})`;
257
+ } catch (error: any) {
258
+ // Continuar intentando en caso de error de red
259
+ if (options.debug) {
260
+ console.log(chalk.yellow(`[DEBUG] Error: ${error.message}`));
261
+ }
262
+ attempts++;
263
+ pollSpinner.text = `Waiting for token verification... (attempt ${attempts}/${MAX_POLL_ATTEMPTS})`;
264
+ }
265
+ }
266
+
267
+ if (!verifiedToken) {
268
+ pollSpinner.fail('Token verification timeout');
269
+ console.error(chalk.red('\n❌ Authentication timeout. Please try again.'));
270
+ console.error(chalk.yellow('\n💡 Tip: Use --debug flag to see detailed response information'));
271
+ console.error(chalk.yellow(` Example: codecrypto auth --debug\n`));
272
+ process.exit(1);
273
+ }
274
+
275
+ pollSpinner.succeed('Token verified successfully');
276
+
277
+ // Paso 3: Guardar token en ~/.codecrypto
278
+ const homeDir = os.homedir();
279
+ const codecryptoDir = path.join(homeDir, '.codecrypto');
280
+ const tokenFile = path.join(codecryptoDir, 'token.json');
281
+
282
+ const saveSpinner = ora('Saving authentication token...').start();
283
+
284
+ try {
285
+ // Crear directorio si no existe
286
+ if (!fs.existsSync(codecryptoDir)) {
287
+ fs.mkdirSync(codecryptoDir, { recursive: true });
288
+ }
289
+
290
+ // Guardar token
291
+ const tokenContent = {
292
+ token: verifiedToken,
293
+ email: tokenEmail,
294
+ serverUrl: serverUrl,
295
+ createdAt: new Date().toISOString(),
296
+ };
297
+
298
+ fs.writeFileSync(tokenFile, JSON.stringify(tokenContent, null, 2), 'utf-8');
299
+ saveSpinner.succeed('Token saved successfully');
300
+ } catch (error: any) {
301
+ saveSpinner.fail('Failed to save token');
302
+ console.error(chalk.red(`❌ Error: ${error.message}`));
303
+ process.exit(1);
304
+ }
305
+
306
+ console.log(chalk.green('\n✅ Authentication completed successfully!'));
307
+ console.log(chalk.gray(` Token saved to: ${chalk.cyan(tokenFile)}`));
308
+ if (tokenEmail) {
309
+ console.log(chalk.gray(` Email: ${chalk.cyan(tokenEmail)}`));
310
+ }
311
+ console.log('');
312
+
313
+ } catch (error: any) {
314
+ console.error(chalk.red(`\n❌ Error: ${error.message}`));
315
+ process.exit(1);
316
+ }
317
+ });
318
+
package/src/index.ts CHANGED
@@ -3,9 +3,7 @@
3
3
  import { Command } from 'commander';
4
4
  import { deployCommand } from './commands/deploy';
5
5
  import { deployScCommand } from './commands/deploy-sc';
6
- import { userCommand } from './commands/user';
7
- import { configCommand } from './commands/config';
8
- import { dbCommand } from './commands/database';
6
+ import { authCommand } from './commands/auth';
9
7
 
10
8
  const program = new Command();
11
9
 
@@ -17,8 +15,6 @@ program
17
15
  // Registrar comandos
18
16
  program.addCommand(deployCommand);
19
17
  program.addCommand(deployScCommand);
20
- program.addCommand(userCommand);
21
- program.addCommand(configCommand);
22
- program.addCommand(dbCommand);
18
+ program.addCommand(authCommand);
23
19
 
24
20
  program.parse(process.argv);
@@ -1,55 +0,0 @@
1
- import { Command } from 'commander';
2
- import chalk from 'chalk';
3
-
4
- export const configCommand = new Command('config')
5
- .description('Manage CLI configuration');
6
-
7
- // Subcomando: set
8
- configCommand
9
- .command('set <key> <value>')
10
- .description('Set a configuration value')
11
- .option('-g, --global', 'Set global configuration', false)
12
- .action((key, value, options) => {
13
- const scope = options.global ? 'global' : 'local';
14
- console.log(chalk.blue('\n⚙️ Configuration\n'));
15
- console.log(chalk.green(`✅ Set ${chalk.cyan(key)} = ${chalk.yellow(value)} (${scope})\n`));
16
- });
17
-
18
- // Subcomando: get
19
- configCommand
20
- .command('get <key>')
21
- .description('Get a configuration value')
22
- .action((key) => {
23
- console.log(chalk.blue('\n⚙️ Configuration\n'));
24
- // Simular obtener valor
25
- const mockValues: Record<string, string> = {
26
- 'api.url': 'https://api.codecrypto.com',
27
- 'api.token': '*********************',
28
- 'default.region': 'us-east-1'
29
- };
30
-
31
- const value = mockValues[key] || 'not set';
32
- console.log(chalk.white(`${chalk.cyan(key)}: ${chalk.yellow(value)}\n`));
33
- });
34
-
35
- // Subcomando: list
36
- configCommand
37
- .command('list')
38
- .description('List all configuration values')
39
- .option('-g, --global', 'Show global configuration', false)
40
- .action((options) => {
41
- const scope = options.global ? 'global' : 'local';
42
- console.log(chalk.blue(`\n⚙️ Configuration (${scope})\n`));
43
-
44
- const configs = {
45
- 'api.url': 'https://api.codecrypto.com',
46
- 'api.token': '*********************',
47
- 'default.region': 'us-east-1',
48
- 'default.env': 'dev'
49
- };
50
-
51
- Object.entries(configs).forEach(([key, value]) => {
52
- console.log(chalk.white(` ${chalk.cyan(key)}: ${chalk.yellow(value)}`));
53
- });
54
- console.log();
55
- });
@@ -1,105 +0,0 @@
1
- import { Command } from 'commander';
2
- import chalk from 'chalk';
3
- import ora from 'ora';
4
-
5
- export const dbCommand = new Command('db')
6
- .description('Database operations');
7
-
8
- // Subcomando: migrate
9
- dbCommand
10
- .command('migrate')
11
- .description('Run database migrations')
12
- .option('-e, --env <environment>', 'Target environment', 'dev')
13
- .option('--rollback', 'Rollback last migration', false)
14
- .option('--steps <number>', 'Number of migrations to run/rollback', 'all')
15
- .action(async (options) => {
16
- console.log(chalk.blue('\n💾 Database Migration\n'));
17
-
18
- const action = options.rollback ? 'Rolling back' : 'Running';
19
- const spinner = ora(`${action} migrations...`).start();
20
-
21
- await sleep(1500);
22
-
23
- if (options.rollback) {
24
- spinner.succeed(chalk.green('✅ Migrations rolled back successfully!'));
25
- } else {
26
- spinner.succeed(chalk.green('✅ Migrations completed successfully!'));
27
- }
28
-
29
- console.log(chalk.gray(`Environment: ${chalk.cyan(options.env)}`));
30
- console.log(chalk.gray(`Steps: ${chalk.cyan(options.steps)}\n`));
31
- });
32
-
33
- // Subcomando: seed
34
- dbCommand
35
- .command('seed')
36
- .description('Seed the database with sample data')
37
- .option('-e, --env <environment>', 'Target environment', 'dev')
38
- .option('-f, --file <file>', 'Seed file to run')
39
- .option('--clear', 'Clear existing data before seeding', false)
40
- .action(async (options) => {
41
- console.log(chalk.blue('\n🌱 Database Seeding\n'));
42
-
43
- if (options.clear) {
44
- console.log(chalk.yellow('⚠️ Clearing existing data...'));
45
- await sleep(1000);
46
- }
47
-
48
- const spinner = ora('Seeding database...').start();
49
- await sleep(2000);
50
-
51
- spinner.succeed(chalk.green('✅ Database seeded successfully!'));
52
- console.log(chalk.gray(`Environment: ${chalk.cyan(options.env)}`));
53
- if (options.file) {
54
- console.log(chalk.gray(`Seed file: ${chalk.cyan(options.file)}`));
55
- }
56
- console.log();
57
- });
58
-
59
- // Subcomando: backup
60
- dbCommand
61
- .command('backup')
62
- .description('Create a database backup')
63
- .argument('<name>', 'Backup name')
64
- .option('-e, --env <environment>', 'Source environment', 'prod')
65
- .option('-o, --output <path>', 'Output directory', './backups')
66
- .option('--compress', 'Compress backup file', true)
67
- .action(async (name, options) => {
68
- console.log(chalk.blue('\n💼 Database Backup\n'));
69
-
70
- const spinner = ora('Creating backup...').start();
71
- await sleep(2500);
72
-
73
- spinner.succeed(chalk.green('✅ Backup created successfully!'));
74
-
75
- const fileName = `${name}_${new Date().toISOString().split('T')[0]}.sql${options.compress ? '.gz' : ''}`;
76
- console.log(chalk.gray(`Environment: ${chalk.cyan(options.env)}`));
77
- console.log(chalk.gray(`Output: ${chalk.cyan(options.output)}/${chalk.cyan(fileName)}`));
78
- console.log(chalk.gray(`Compressed: ${options.compress ? chalk.green('Yes') : chalk.yellow('No')}\n`));
79
- });
80
-
81
- // Subcomando: restore
82
- dbCommand
83
- .command('restore <backupFile>')
84
- .description('Restore database from backup')
85
- .option('-e, --env <environment>', 'Target environment', 'dev')
86
- .option('--force', 'Skip confirmation', false)
87
- .action(async (backupFile, options) => {
88
- console.log(chalk.blue('\n♻️ Database Restore\n'));
89
-
90
- if (options.env === 'prod' && !options.force) {
91
- console.log(chalk.red('❌ Cannot restore to production without --force flag\n'));
92
- return;
93
- }
94
-
95
- const spinner = ora('Restoring database...').start();
96
- await sleep(3000);
97
-
98
- spinner.succeed(chalk.green('✅ Database restored successfully!'));
99
- console.log(chalk.gray(`Environment: ${chalk.cyan(options.env)}`));
100
- console.log(chalk.gray(`Backup file: ${chalk.cyan(backupFile)}\n`));
101
- });
102
-
103
- function sleep(ms: number): Promise<void> {
104
- return new Promise(resolve => setTimeout(resolve, ms));
105
- }
@@ -1,122 +0,0 @@
1
- import { Command } from 'commander';
2
- import chalk from 'chalk';
3
- import inquirer from 'inquirer';
4
-
5
- export const userCommand = new Command('user')
6
- .description('Manage users in the system');
7
-
8
- // Subcomando: crear usuario
9
- userCommand
10
- .command('create')
11
- .description('Create a new user')
12
- .option('-u, --username <username>', 'Username')
13
- .option('-e, --email <email>', 'Email address')
14
- .option('-r, --role <role>', 'User role (admin, user, guest)', 'user')
15
- .option('--interactive', 'Interactive mode', false)
16
- .action(async (options) => {
17
- console.log(chalk.blue('\n👤 Create New User\n'));
18
-
19
- let userData = {
20
- username: options.username,
21
- email: options.email,
22
- role: options.role
23
- };
24
-
25
- // Modo interactivo
26
- if (options.interactive || !options.username || !options.email) {
27
- const answers = await inquirer.prompt([
28
- {
29
- type: 'input',
30
- name: 'username',
31
- message: 'Enter username:',
32
- default: options.username,
33
- validate: (input) => input.length > 0 || 'Username is required'
34
- },
35
- {
36
- type: 'input',
37
- name: 'email',
38
- message: 'Enter email:',
39
- default: options.email,
40
- validate: (input) => {
41
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
42
- return emailRegex.test(input) || 'Invalid email format';
43
- }
44
- },
45
- {
46
- type: 'list',
47
- name: 'role',
48
- message: 'Select role:',
49
- choices: ['admin', 'user', 'guest'],
50
- default: options.role
51
- }
52
- ]);
53
-
54
- userData = { ...userData, ...answers };
55
- }
56
-
57
- console.log(chalk.green('\n✅ User created successfully!'));
58
- console.log(chalk.gray('User details:'));
59
- console.log(chalk.white(` Username: ${chalk.cyan(userData.username)}`));
60
- console.log(chalk.white(` Email: ${chalk.cyan(userData.email)}`));
61
- console.log(chalk.white(` Role: ${chalk.cyan(userData.role)}`));
62
- });
63
-
64
- // Subcomando: listar usuarios
65
- userCommand
66
- .command('list')
67
- .description('List all users')
68
- .option('-r, --role <role>', 'Filter by role')
69
- .option('-l, --limit <number>', 'Limit number of results', '10')
70
- .action((options) => {
71
- console.log(chalk.blue('\n📋 User List\n'));
72
-
73
- if (options.role) {
74
- console.log(chalk.gray(`Filtering by role: ${chalk.cyan(options.role)}`));
75
- }
76
-
77
- // Datos de ejemplo
78
- const users = [
79
- { id: 1, username: 'john_doe', email: 'john@example.com', role: 'admin' },
80
- { id: 2, username: 'jane_smith', email: 'jane@example.com', role: 'user' },
81
- { id: 3, username: 'bob_wilson', email: 'bob@example.com', role: 'user' }
82
- ];
83
-
84
- const filteredUsers = options.role
85
- ? users.filter(u => u.role === options.role)
86
- : users;
87
-
88
- const limitedUsers = filteredUsers.slice(0, parseInt(options.limit));
89
-
90
- limitedUsers.forEach(user => {
91
- console.log(chalk.white(` ${user.id}. ${chalk.cyan(user.username)} (${user.email}) - ${chalk.yellow(user.role)}`));
92
- });
93
-
94
- console.log(chalk.gray(`\nTotal: ${limitedUsers.length} users\n`));
95
- });
96
-
97
- // Subcomando: eliminar usuario
98
- userCommand
99
- .command('delete <userId>')
100
- .description('Delete a user by ID')
101
- .option('-f, --force', 'Skip confirmation', false)
102
- .action(async (userId, options) => {
103
- console.log(chalk.blue('\n🗑️ Delete User\n'));
104
-
105
- if (!options.force) {
106
- const { confirm } = await inquirer.prompt([
107
- {
108
- type: 'confirm',
109
- name: 'confirm',
110
- message: `Are you sure you want to delete user ${userId}?`,
111
- default: false
112
- }
113
- ]);
114
-
115
- if (!confirm) {
116
- console.log(chalk.yellow('❌ Operation cancelled\n'));
117
- return;
118
- }
119
- }
120
-
121
- console.log(chalk.green(`✅ User ${userId} deleted successfully!\n`));
122
- });