codecrypto-cli 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +64 -7
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/deploy-sc.d.ts.map +1 -1
- package/dist/commands/deploy-sc.js +162 -0
- package/dist/commands/deploy-sc.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +556 -18
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +518 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/docker-build/Dockerfile +18 -0
- package/docker-build/standalone/.next/BUILD_ID +1 -0
- package/docker-build/standalone/.next/app-path-routes-manifest.json +6 -0
- package/docker-build/standalone/.next/build-manifest.json +19 -0
- package/docker-build/standalone/.next/package.json +1 -0
- package/docker-build/standalone/.next/prerender-manifest.json +114 -0
- package/docker-build/standalone/.next/required-server-files.json +164 -0
- package/docker-build/standalone/.next/routes-manifest.json +68 -0
- package/docker-build/standalone/.next/server/app/_global-error/page/app-paths-manifest.json +3 -0
- package/docker-build/standalone/.next/server/app/_global-error/page/build-manifest.json +16 -0
- package/docker-build/standalone/.next/server/app/_global-error/page/next-font-manifest.json +6 -0
- package/docker-build/standalone/.next/server/app/_global-error/page/react-loadable-manifest.json +1 -0
- package/docker-build/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +4 -0
- package/docker-build/standalone/.next/server/app/_global-error/page.js +11 -0
- package/docker-build/standalone/.next/server/app/_global-error/page.js.map +5 -0
- package/docker-build/standalone/.next/server/app/_global-error/page.js.nft.json +1 -0
- package/docker-build/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +2 -0
- package/docker-build/standalone/.next/server/app/_global-error.html +2 -0
- package/docker-build/standalone/.next/server/app/_global-error.meta +15 -0
- package/docker-build/standalone/.next/server/app/_global-error.rsc +13 -0
- package/docker-build/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +5 -0
- package/docker-build/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +13 -0
- package/docker-build/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +6 -0
- package/docker-build/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +4 -0
- package/docker-build/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
- package/docker-build/standalone/.next/server/app/_not-found/page/app-paths-manifest.json +3 -0
- package/docker-build/standalone/.next/server/app/_not-found/page/build-manifest.json +16 -0
- package/docker-build/standalone/.next/server/app/_not-found/page/next-font-manifest.json +11 -0
- package/docker-build/standalone/.next/server/app/_not-found/page/react-loadable-manifest.json +1 -0
- package/docker-build/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +4 -0
- package/docker-build/standalone/.next/server/app/_not-found/page.js +14 -0
- package/docker-build/standalone/.next/server/app/_not-found/page.js.map +5 -0
- package/docker-build/standalone/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/docker-build/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +2 -0
- package/docker-build/standalone/.next/server/app/_not-found.html +1 -0
- package/docker-build/standalone/.next/server/app/_not-found.meta +16 -0
- package/docker-build/standalone/.next/server/app/_not-found.rsc +14 -0
- package/docker-build/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -0
- package/docker-build/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +6 -0
- package/docker-build/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +5 -0
- package/docker-build/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -0
- package/docker-build/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +4 -0
- package/docker-build/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -0
- package/docker-build/standalone/.next/server/app/favicon.ico/route/app-paths-manifest.json +3 -0
- package/docker-build/standalone/.next/server/app/favicon.ico/route/build-manifest.json +11 -0
- package/docker-build/standalone/.next/server/app/favicon.ico/route.js +6 -0
- package/docker-build/standalone/.next/server/app/favicon.ico/route.js.map +5 -0
- package/docker-build/standalone/.next/server/app/favicon.ico/route.js.nft.json +1 -0
- package/docker-build/standalone/.next/server/app/favicon.ico.body +0 -0
- package/docker-build/standalone/.next/server/app/favicon.ico.meta +1 -0
- package/docker-build/standalone/.next/server/app/index.html +1 -0
- package/docker-build/standalone/.next/server/app/index.meta +14 -0
- package/docker-build/standalone/.next/server/app/index.rsc +16 -0
- package/docker-build/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +5 -0
- package/docker-build/standalone/.next/server/app/index.segments/_full.segment.rsc +16 -0
- package/docker-build/standalone/.next/server/app/index.segments/_head.segment.rsc +6 -0
- package/docker-build/standalone/.next/server/app/index.segments/_index.segment.rsc +5 -0
- package/docker-build/standalone/.next/server/app/index.segments/_tree.segment.rsc +4 -0
- package/docker-build/standalone/.next/server/app/page/app-paths-manifest.json +3 -0
- package/docker-build/standalone/.next/server/app/page/build-manifest.json +16 -0
- package/docker-build/standalone/.next/server/app/page/next-font-manifest.json +11 -0
- package/docker-build/standalone/.next/server/app/page/react-loadable-manifest.json +1 -0
- package/docker-build/standalone/.next/server/app/page/server-reference-manifest.json +4 -0
- package/docker-build/standalone/.next/server/app/page.js +16 -0
- package/docker-build/standalone/.next/server/app/page.js.map +5 -0
- package/docker-build/standalone/.next/server/app/page.js.nft.json +1 -0
- package/docker-build/standalone/.next/server/app/page_client-reference-manifest.js +2 -0
- package/docker-build/standalone/.next/server/app-paths-manifest.json +6 -0
- package/docker-build/standalone/.next/server/chunks/66d90_example-navidad__next-internal_server_app_favicon_ico_route_actions_a30dceae.js +3 -0
- package/docker-build/standalone/.next/server/chunks/[externals]_next_dist_03fe02e0._.js +3 -0
- package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__4b49000d._.js +21 -0
- package/docker-build/standalone/.next/server/chunks/[turbopack]_runtime.js +795 -0
- package/docker-build/standalone/.next/server/chunks/ssr/10072_infra_example-navidad__next-internal_server_app_page_actions_a387aef9.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_example-navidad_377109b0._.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_example-navidad_90799f30._.js +4 -0
- package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_example-navidad_app_b9057478._.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/66d90_example-navidad__next-internal_server_app__global-error_page_actions_a079475f.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/66d90_example-navidad__next-internal_server_app__not-found_page_actions_ac88cec2.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_51be1544._.js +4 -0
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_8dba0557._.js +6 -0
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_client_components_41330064._.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_client_components_builtin_forbidden_ff3a0457.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_client_components_builtin_global-error_e0d57e6e.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_client_components_builtin_unauthorized_f1c47e13.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_d332f292._.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/77a20_next_dist_esm_build_templates_app-page_cf6afba1.js +4 -0
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__02f3f427._.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__2f460610._.js +4 -0
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__4722e53c._.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__53b749fa._.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__61942f2d._.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__7707ad1b._.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__864cadbf._.js +10 -0
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__9939e281._.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__b4b0aa8a._.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__d2b7072b._.js +3 -0
- package/docker-build/standalone/.next/server/chunks/ssr/[turbopack]_runtime.js +795 -0
- package/docker-build/standalone/.next/server/functions-config-manifest.json +4 -0
- package/docker-build/standalone/.next/server/middleware-build-manifest.js +20 -0
- package/docker-build/standalone/.next/server/middleware-manifest.json +6 -0
- package/docker-build/standalone/.next/server/next-font-manifest.js +1 -0
- package/docker-build/standalone/.next/server/next-font-manifest.json +15 -0
- package/docker-build/standalone/.next/server/pages/404.html +1 -0
- package/docker-build/standalone/.next/server/pages/500.html +2 -0
- package/docker-build/standalone/.next/server/pages-manifest.json +4 -0
- package/docker-build/standalone/.next/server/server-reference-manifest.js +1 -0
- package/docker-build/standalone/.next/server/server-reference-manifest.json +5 -0
- package/docker-build/standalone/.next/static/_NbfI2TKfapiyxsQgIG3h/_buildManifest.js +11 -0
- package/docker-build/standalone/.next/static/_NbfI2TKfapiyxsQgIG3h/_clientMiddlewareManifest.json +1 -0
- package/docker-build/standalone/.next/static/_NbfI2TKfapiyxsQgIG3h/_ssgManifest.js +1 -0
- package/docker-build/standalone/.next/static/chunks/57d1af92f5dc15fa.js +1 -0
- package/docker-build/standalone/.next/static/chunks/6ae71d5e8ea4d1eb.js +1 -0
- package/docker-build/standalone/.next/static/chunks/70977d70c9306213.js +1 -0
- package/docker-build/standalone/.next/static/chunks/777dac7104fe2a30.js +5 -0
- package/docker-build/standalone/.next/static/chunks/a6dad97d9634a72d.js +1 -0
- package/docker-build/standalone/.next/static/chunks/a6dad97d9634a72d.js.map +1 -0
- package/docker-build/standalone/.next/static/chunks/d6aec49b013224a2.css +3 -0
- package/docker-build/standalone/.next/static/chunks/turbopack-0ce517fb6224c1f0.js +4 -0
- package/docker-build/standalone/.next/static/media/4fa387ec64143e14-s.c1fdd6c2.woff2 +0 -0
- package/docker-build/standalone/.next/static/media/7178b3e590c64307-s.b97b3418.woff2 +0 -0
- package/docker-build/standalone/.next/static/media/797e433ab948586e-s.p.dbea232f.woff2 +0 -0
- package/docker-build/standalone/.next/static/media/8a480f0b521d4e75-s.8e0177b5.woff2 +0 -0
- package/docker-build/standalone/.next/static/media/bbc41e54d2fcbd21-s.799d8ef8.woff2 +0 -0
- package/docker-build/standalone/.next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2 +0 -0
- package/docker-build/standalone/.next/static/media/favicon.0b3bf435.ico +0 -0
- package/docker-build/standalone/package.json +26 -0
- package/docker-build/standalone/public/file.svg +1 -0
- package/docker-build/standalone/public/globe.svg +1 -0
- package/docker-build/standalone/public/next.svg +1 -0
- package/docker-build/standalone/public/vercel.svg +1 -0
- package/docker-build/standalone/public/window.svg +1 -0
- package/docker-build/standalone/server.js +38 -0
- package/package.json +1 -1
- package/src/commands/auth.ts +71 -8
- package/src/commands/deploy-sc.ts +182 -0
- package/src/commands/deploy.ts +592 -21
- package/src/commands/doctor.ts +498 -0
- package/src/index.ts +2 -0
- package/token.json +69 -0
package/src/commands/auth.ts
CHANGED
|
@@ -34,6 +34,7 @@ export const authCommand = new Command('auth')
|
|
|
34
34
|
.option('--server-url <url>', 'Server URL', API_BASE_URL)
|
|
35
35
|
.option('--poll-interval <seconds>', 'Polling interval in seconds', '3')
|
|
36
36
|
.option('--debug', 'Show debug information', false)
|
|
37
|
+
.option('--force', 'Force creation of new token even if one exists', false)
|
|
37
38
|
.action(async (options) => {
|
|
38
39
|
console.log(chalk.blue('\n🔐 CodeCrypto Authentication\n'));
|
|
39
40
|
|
|
@@ -41,6 +42,40 @@ export const authCommand = new Command('auth')
|
|
|
41
42
|
const pollInterval = parseInt(options.pollInterval || '3', 10) * 1000;
|
|
42
43
|
|
|
43
44
|
try {
|
|
45
|
+
// Verificar si ya existe un token guardado
|
|
46
|
+
const homeDir = os.homedir();
|
|
47
|
+
const codecryptoDir = path.join(homeDir, '.codecrypto');
|
|
48
|
+
const tokenFile = path.join(codecryptoDir, 'token.json');
|
|
49
|
+
|
|
50
|
+
// Verificar si ya existe un token y si se debe crear uno nuevo
|
|
51
|
+
if (!options.force && fs.existsSync(tokenFile)) {
|
|
52
|
+
try {
|
|
53
|
+
const existingTokenData = JSON.parse(fs.readFileSync(tokenFile, 'utf-8'));
|
|
54
|
+
if (existingTokenData.token && existingTokenData.email) {
|
|
55
|
+
console.log(chalk.yellow('⚠️ Found existing authentication token'));
|
|
56
|
+
console.log(chalk.gray(` Email: ${chalk.cyan(existingTokenData.email)}`));
|
|
57
|
+
console.log(chalk.gray(` Created: ${chalk.cyan(existingTokenData.createdAt || 'unknown')}`));
|
|
58
|
+
console.log(chalk.yellow('\n💡 You already have a valid token. Creating a new one will generate a new token in the database.'));
|
|
59
|
+
console.log(chalk.yellow(' To use the existing token, you can skip this authentication.'));
|
|
60
|
+
console.log(chalk.yellow(' To create a new token, use: codecrypto auth --force\n'));
|
|
61
|
+
|
|
62
|
+
// Por defecto, no crear un nuevo token si ya existe uno
|
|
63
|
+
console.log(chalk.green('✅ Using existing token. No new token will be created.'));
|
|
64
|
+
console.log(chalk.gray(` Token location: ${chalk.cyan(tokenFile)}\n`));
|
|
65
|
+
process.exit(0);
|
|
66
|
+
}
|
|
67
|
+
} catch (error) {
|
|
68
|
+
// Si hay error leyendo el token existente, continuar con la creación
|
|
69
|
+
if (options.debug) {
|
|
70
|
+
console.log(chalk.yellow(`[DEBUG] Could not read existing token: ${error}`));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (options.force && fs.existsSync(tokenFile)) {
|
|
76
|
+
console.log(chalk.yellow('⚠️ Force flag detected. Creating new token (this will not invalidate the previous one).\n'));
|
|
77
|
+
}
|
|
78
|
+
|
|
44
79
|
// Paso 1: Solicitar código de autenticación
|
|
45
80
|
const requestSpinner = ora('Requesting authentication code...').start();
|
|
46
81
|
|
|
@@ -59,6 +94,12 @@ export const authCommand = new Command('auth')
|
|
|
59
94
|
|
|
60
95
|
const jsonData = await response.json();
|
|
61
96
|
|
|
97
|
+
// Mostrar respuesta raw
|
|
98
|
+
console.log(chalk.gray('\n[RAW RESPONSE] POST /api/tokens:'));
|
|
99
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
100
|
+
console.log(JSON.stringify(jsonData, null, 2));
|
|
101
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
102
|
+
|
|
62
103
|
if (options.debug) {
|
|
63
104
|
console.log(chalk.gray(`\n[DEBUG] POST Response: ${JSON.stringify(jsonData, null, 2)}`));
|
|
64
105
|
}
|
|
@@ -122,7 +163,7 @@ export const authCommand = new Command('auth')
|
|
|
122
163
|
process.exit(1);
|
|
123
164
|
}
|
|
124
165
|
|
|
125
|
-
const tokenUrl = `${serverUrl}/token`;
|
|
166
|
+
const tokenUrl = `${serverUrl}/login?token=${tokenId}`;
|
|
126
167
|
|
|
127
168
|
// Mostrar información al usuario con el ID REAL obtenido
|
|
128
169
|
console.log(chalk.green('\n✅ Authentication code generated!'));
|
|
@@ -139,6 +180,7 @@ export const authCommand = new Command('auth')
|
|
|
139
180
|
|
|
140
181
|
let verifiedToken: string | null = null;
|
|
141
182
|
let tokenEmail: string | null = null;
|
|
183
|
+
let verificationData: any = null; // Guardar toda la respuesta de verificación
|
|
142
184
|
let attempts = 0;
|
|
143
185
|
|
|
144
186
|
// Función helper para extraer el token JWT y el email de la respuesta
|
|
@@ -233,15 +275,24 @@ export const authCommand = new Command('auth')
|
|
|
233
275
|
if (verifyResponse.ok) {
|
|
234
276
|
const verifyData = await verifyResponse.json();
|
|
235
277
|
|
|
278
|
+
// Mostrar respuesta raw solo en el primer intento exitoso o si hay token
|
|
279
|
+
const extracted = extractToken(verifyData);
|
|
280
|
+
if (extracted.token && !verifiedToken) {
|
|
281
|
+
console.log(chalk.gray('\n[RAW RESPONSE] GET /api/tokens/{id}:'));
|
|
282
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
283
|
+
//console.log(JSON.stringify(verifyData, null, 2));
|
|
284
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
285
|
+
}
|
|
286
|
+
|
|
236
287
|
if (options.debug) {
|
|
237
288
|
console.log(chalk.gray(`\n[DEBUG] Attempt ${attempts + 1} - Response: ${JSON.stringify(verifyData, null, 2)}`));
|
|
238
289
|
}
|
|
239
290
|
|
|
240
291
|
// Intentar extraer el token
|
|
241
|
-
const extracted = extractToken(verifyData);
|
|
242
292
|
if (extracted.token) {
|
|
243
293
|
verifiedToken = extracted.token;
|
|
244
294
|
tokenEmail = extracted.email;
|
|
295
|
+
verificationData = verifyData; // Guardar toda la respuesta
|
|
245
296
|
break;
|
|
246
297
|
}
|
|
247
298
|
} else {
|
|
@@ -275,9 +326,7 @@ export const authCommand = new Command('auth')
|
|
|
275
326
|
pollSpinner.succeed('Token verified successfully');
|
|
276
327
|
|
|
277
328
|
// Paso 3: Guardar token en ~/.codecrypto
|
|
278
|
-
|
|
279
|
-
const codecryptoDir = path.join(homeDir, '.codecrypto');
|
|
280
|
-
const tokenFile = path.join(codecryptoDir, 'token.json');
|
|
329
|
+
// Reutilizar las variables ya declaradas arriba
|
|
281
330
|
|
|
282
331
|
const saveSpinner = ora('Saving authentication token...').start();
|
|
283
332
|
|
|
@@ -287,14 +336,27 @@ export const authCommand = new Command('auth')
|
|
|
287
336
|
fs.mkdirSync(codecryptoDir, { recursive: true });
|
|
288
337
|
}
|
|
289
338
|
|
|
290
|
-
// Guardar
|
|
291
|
-
const tokenContent = {
|
|
339
|
+
// Guardar datos básicos y extraer globals de la respuesta
|
|
340
|
+
const tokenContent: any = {
|
|
341
|
+
// Datos básicos extraídos
|
|
292
342
|
token: verifiedToken,
|
|
293
343
|
email: tokenEmail,
|
|
344
|
+
tokenId: tokenId,
|
|
345
|
+
code: code,
|
|
294
346
|
serverUrl: serverUrl,
|
|
295
|
-
|
|
347
|
+
verifiedAt: new Date().toISOString(),
|
|
296
348
|
};
|
|
297
349
|
|
|
350
|
+
// Extraer studentGlobalsAll y adminGlobals de verificationResponse.globals
|
|
351
|
+
if (verificationData && verificationData.globals) {
|
|
352
|
+
if (verificationData.globals.studentGlobalsAll) {
|
|
353
|
+
tokenContent.studentGlobalsAll = verificationData.globals.studentGlobalsAll;
|
|
354
|
+
}
|
|
355
|
+
if (verificationData.globals.adminGlobals) {
|
|
356
|
+
tokenContent.adminGlobals = verificationData.globals.adminGlobals;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
298
360
|
fs.writeFileSync(tokenFile, JSON.stringify(tokenContent, null, 2), 'utf-8');
|
|
299
361
|
saveSpinner.succeed('Token saved successfully');
|
|
300
362
|
} catch (error: any) {
|
|
@@ -308,6 +370,7 @@ export const authCommand = new Command('auth')
|
|
|
308
370
|
if (tokenEmail) {
|
|
309
371
|
console.log(chalk.gray(` Email: ${chalk.cyan(tokenEmail)}`));
|
|
310
372
|
}
|
|
373
|
+
console.log(chalk.gray(` Token ID: ${chalk.cyan(tokenId)}`));
|
|
311
374
|
console.log('');
|
|
312
375
|
|
|
313
376
|
} catch (error: any) {
|
|
@@ -4,6 +4,7 @@ import ora from 'ora';
|
|
|
4
4
|
import { execSync } from 'child_process';
|
|
5
5
|
import * as fs from 'fs';
|
|
6
6
|
import * as path from 'path';
|
|
7
|
+
import * as os from 'os';
|
|
7
8
|
|
|
8
9
|
export const deployScCommand = new Command('deploy-sc')
|
|
9
10
|
.description('Deploy smart contract using Foundry')
|
|
@@ -15,6 +16,7 @@ export const deployScCommand = new Command('deploy-sc')
|
|
|
15
16
|
.option('--verify', 'Verify contract on block explorer', false)
|
|
16
17
|
.option('--broadcast', 'Broadcast the transaction', true)
|
|
17
18
|
.option('--slow', 'Use slow mode for deployment', false)
|
|
19
|
+
.option('--debug', 'Show debug information', false)
|
|
18
20
|
.action(async (scriptPath: string, options) => {
|
|
19
21
|
console.log(chalk.blue('\n🔷 CodeCrypto Smart Contract Deployment\n'));
|
|
20
22
|
|
|
@@ -168,6 +170,29 @@ export const deployScCommand = new Command('deploy-sc')
|
|
|
168
170
|
|
|
169
171
|
deploySpinner.succeed('Smart contract desplegado exitosamente');
|
|
170
172
|
|
|
173
|
+
// Buscar y leer el archivo de transacciones generado por Foundry (solo si se hizo broadcast)
|
|
174
|
+
if (options.broadcast) {
|
|
175
|
+
const uploadSpinner = ora('Uploading deployment results to database...').start();
|
|
176
|
+
try {
|
|
177
|
+
await uploadDeploymentResults({
|
|
178
|
+
scriptPath: scriptRelativePath,
|
|
179
|
+
foundryProjectDir,
|
|
180
|
+
rpcUrl: options.url,
|
|
181
|
+
privateKey: privateKey || (options.account !== undefined ? `account-${options.account}` : null),
|
|
182
|
+
debug: options.debug || false,
|
|
183
|
+
});
|
|
184
|
+
uploadSpinner.succeed('Deployment results uploaded successfully');
|
|
185
|
+
} catch (uploadError: any) {
|
|
186
|
+
uploadSpinner.warn(`Failed to upload deployment results: ${uploadError.message}`);
|
|
187
|
+
console.log(chalk.yellow(' Deployment was successful, but results were not saved to database'));
|
|
188
|
+
if (uploadError.message.includes('run-latest.json')) {
|
|
189
|
+
console.log(chalk.yellow(' Note: Make sure --broadcast flag is used to generate transaction files'));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
} else {
|
|
193
|
+
console.log(chalk.gray('\n💡 Deployment results not uploaded (--broadcast was not used)'));
|
|
194
|
+
}
|
|
195
|
+
|
|
171
196
|
console.log(chalk.green('\n✅ Deployment completed successfully!'));
|
|
172
197
|
console.log(chalk.gray('Contract details:'));
|
|
173
198
|
console.log(chalk.white(` Script: ${chalk.cyan(scriptRelativePath)}`));
|
|
@@ -198,3 +223,160 @@ export const deployScCommand = new Command('deploy-sc')
|
|
|
198
223
|
}
|
|
199
224
|
});
|
|
200
225
|
|
|
226
|
+
// Función para subir los resultados del despliegue a la base de datos
|
|
227
|
+
async function uploadDeploymentResults(config: {
|
|
228
|
+
scriptPath: string;
|
|
229
|
+
foundryProjectDir: string;
|
|
230
|
+
rpcUrl: string;
|
|
231
|
+
privateKey: string | null;
|
|
232
|
+
debug?: boolean;
|
|
233
|
+
}) {
|
|
234
|
+
// 1. Leer token.json para obtener email y serverUrl
|
|
235
|
+
const tokenFilePath = path.join(os.homedir(), '.codecrypto', 'token.json');
|
|
236
|
+
if (!fs.existsSync(tokenFilePath)) {
|
|
237
|
+
throw new Error('Token file not found. Please run "codecrypto auth" first.');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
let tokenData: any;
|
|
241
|
+
try {
|
|
242
|
+
tokenData = JSON.parse(fs.readFileSync(tokenFilePath, 'utf-8'));
|
|
243
|
+
} catch (error: any) {
|
|
244
|
+
throw new Error(`Failed to read token file: ${error.message}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const email = tokenData.email;
|
|
248
|
+
const serverUrl = tokenData.serverUrl || 'http://localhost:3000';
|
|
249
|
+
const token = tokenData.token;
|
|
250
|
+
|
|
251
|
+
if (!email) {
|
|
252
|
+
throw new Error('Email not found in token.json');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (!token) {
|
|
256
|
+
throw new Error('Token not found in token.json');
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// 2. Encontrar el archivo JSON de transacciones
|
|
260
|
+
// Foundry guarda los resultados en: broadcast/{ScriptName}/{chainId}/run-latest.json
|
|
261
|
+
const scriptName = path.basename(config.scriptPath, '.s.sol');
|
|
262
|
+
const broadcastDir = path.join(config.foundryProjectDir, 'broadcast', `${scriptName}.s.sol`);
|
|
263
|
+
|
|
264
|
+
if (!fs.existsSync(broadcastDir)) {
|
|
265
|
+
throw new Error(`Broadcast directory not found: ${broadcastDir}`);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Buscar el archivo run-latest.json en cualquier subdirectorio de chainId
|
|
269
|
+
let transactionsJsonPath: string | null = null;
|
|
270
|
+
const chainDirs = fs.readdirSync(broadcastDir, { withFileTypes: true })
|
|
271
|
+
.filter(dirent => dirent.isDirectory())
|
|
272
|
+
.map(dirent => dirent.name);
|
|
273
|
+
|
|
274
|
+
for (const chainDir of chainDirs) {
|
|
275
|
+
const runLatestPath = path.join(broadcastDir, chainDir, 'run-latest.json');
|
|
276
|
+
if (fs.existsSync(runLatestPath)) {
|
|
277
|
+
transactionsJsonPath = runLatestPath;
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (!transactionsJsonPath) {
|
|
283
|
+
throw new Error(`No run-latest.json found in ${broadcastDir}`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// 3. Leer el JSON de transacciones
|
|
287
|
+
let transactionsData: any;
|
|
288
|
+
try {
|
|
289
|
+
transactionsData = JSON.parse(fs.readFileSync(transactionsJsonPath, 'utf-8'));
|
|
290
|
+
} catch (error: any) {
|
|
291
|
+
throw new Error(`Failed to read transactions file: ${error.message}`);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// 4. Obtener el folder (directorio del proyecto)
|
|
295
|
+
const folder = config.foundryProjectDir;
|
|
296
|
+
|
|
297
|
+
// 5. Preparar los datos para enviar
|
|
298
|
+
// Asegurarse de que transactionsData incluye tanto transactions como receipts
|
|
299
|
+
const uploadData = {
|
|
300
|
+
email,
|
|
301
|
+
folder,
|
|
302
|
+
transactions: transactionsData, // Incluye transactions, receipts, y todo lo demás
|
|
303
|
+
rpcUrl: config.rpcUrl,
|
|
304
|
+
privateKey: config.privateKey,
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
// Verificar que tenemos transacciones
|
|
308
|
+
if (!transactionsData.transactions || !Array.isArray(transactionsData.transactions)) {
|
|
309
|
+
throw new Error('No transactions found in run-latest.json');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// 6. Hacer la llamada POST al endpoint
|
|
313
|
+
const apiUrl = `${serverUrl}/api/uploadSmartContract`;
|
|
314
|
+
|
|
315
|
+
// Log de la petición (solo si debug está activado)
|
|
316
|
+
if (config.debug) {
|
|
317
|
+
console.log(chalk.gray('\n[UPLOAD REQUEST] POST /api/uploadSmartContract:'));
|
|
318
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
319
|
+
console.log(chalk.gray(`URL: ${chalk.cyan(apiUrl)}`));
|
|
320
|
+
console.log(chalk.gray(`Method: ${chalk.cyan('POST')}`));
|
|
321
|
+
console.log(chalk.gray('Headers:'));
|
|
322
|
+
console.log(chalk.gray(` Content-Type: ${chalk.cyan('application/json')}`));
|
|
323
|
+
console.log(chalk.gray(` Authorization: ${chalk.cyan('Bearer ' + token.substring(0, 20) + '...')}`));
|
|
324
|
+
console.log(chalk.gray('Body summary:'));
|
|
325
|
+
console.log(chalk.gray(` email: ${chalk.cyan(email)}`));
|
|
326
|
+
console.log(chalk.gray(` folder: ${chalk.cyan(folder)}`));
|
|
327
|
+
console.log(chalk.gray(` rpcUrl: ${chalk.cyan(config.rpcUrl)}`));
|
|
328
|
+
console.log(chalk.gray(` privateKey: ${chalk.cyan(config.privateKey ? `${config.privateKey.substring(0, 10)}...` : 'null')}`));
|
|
329
|
+
console.log(chalk.gray(` transactions.transactions: ${chalk.cyan(transactionsData.transactions.length)} transaction(s)`));
|
|
330
|
+
console.log(chalk.gray(` transactions.receipts: ${chalk.cyan(transactionsData.receipts ? transactionsData.receipts.length : 0)} receipt(s)`));
|
|
331
|
+
console.log(chalk.gray(` transactions.chain: ${chalk.cyan(transactionsData.chain || 'N/A')}`));
|
|
332
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
333
|
+
console.log(chalk.gray(chalk.yellow('⚠️ Sending full transactions data (not just receipts)...')));
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
try {
|
|
337
|
+
const response = await fetch(apiUrl, {
|
|
338
|
+
method: 'POST',
|
|
339
|
+
headers: {
|
|
340
|
+
'Content-Type': 'application/json',
|
|
341
|
+
'Authorization': `Bearer ${token}`,
|
|
342
|
+
},
|
|
343
|
+
body: JSON.stringify(uploadData),
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// Log de la respuesta (solo si debug está activado)
|
|
347
|
+
const responseText = await response.text();
|
|
348
|
+
if (config.debug) {
|
|
349
|
+
console.log(chalk.gray('\n[UPLOAD RESPONSE] POST /api/uploadSmartContract:'));
|
|
350
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
351
|
+
console.log(chalk.gray(`Status: ${response.ok ? chalk.green(response.status) : chalk.red(response.status)}`));
|
|
352
|
+
console.log(chalk.gray('Response:'));
|
|
353
|
+
try {
|
|
354
|
+
const responseJson = JSON.parse(responseText);
|
|
355
|
+
console.log(JSON.stringify(responseJson, null, 2));
|
|
356
|
+
} catch {
|
|
357
|
+
console.log(responseText);
|
|
358
|
+
}
|
|
359
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (!response.ok) {
|
|
363
|
+
let errorMessage: string;
|
|
364
|
+
try {
|
|
365
|
+
const errorJson = JSON.parse(responseText);
|
|
366
|
+
errorMessage = errorJson.error || errorJson.message || responseText;
|
|
367
|
+
} catch {
|
|
368
|
+
errorMessage = responseText || `HTTP error! status: ${response.status}`;
|
|
369
|
+
}
|
|
370
|
+
throw new Error(errorMessage);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const result = JSON.parse(responseText);
|
|
374
|
+
return result;
|
|
375
|
+
} catch (error: any) {
|
|
376
|
+
if (error.message) {
|
|
377
|
+
throw error;
|
|
378
|
+
}
|
|
379
|
+
throw new Error(`Failed to upload deployment results: ${error.message || String(error)}`);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|