codecrypto-cli 1.0.8 → 1.0.10

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 (272) hide show
  1. package/dist/commands/auth.d.ts.map +1 -1
  2. package/dist/commands/auth.js +64 -7
  3. package/dist/commands/auth.js.map +1 -1
  4. package/dist/commands/deploy-sc.d.ts.map +1 -1
  5. package/dist/commands/deploy-sc.js +162 -0
  6. package/dist/commands/deploy-sc.js.map +1 -1
  7. package/dist/commands/deploy.d.ts.map +1 -1
  8. package/dist/commands/deploy.js +644 -136
  9. package/dist/commands/deploy.js.map +1 -1
  10. package/dist/commands/doctor.d.ts +3 -0
  11. package/dist/commands/doctor.d.ts.map +1 -0
  12. package/dist/commands/doctor.js +518 -0
  13. package/dist/commands/doctor.js.map +1 -0
  14. package/dist/index.js +2 -0
  15. package/dist/index.js.map +1 -1
  16. package/package.json +1 -1
  17. package/src/commands/auth.ts +71 -8
  18. package/src/commands/deploy-sc.ts +182 -0
  19. package/src/commands/deploy.ts +688 -150
  20. package/src/commands/doctor.ts +498 -0
  21. package/src/index.ts +2 -0
  22. package/token.json +69 -0
  23. package/docker-build/Dockerfile +0 -14
  24. package/docker-build/standalone/.next/BUILD_ID +0 -1
  25. package/docker-build/standalone/.next/app-path-routes-manifest.json +0 -13
  26. package/docker-build/standalone/.next/build-manifest.json +0 -20
  27. package/docker-build/standalone/.next/package.json +0 -1
  28. package/docker-build/standalone/.next/prerender-manifest.json +0 -186
  29. package/docker-build/standalone/.next/required-server-files.json +0 -164
  30. package/docker-build/standalone/.next/routes-manifest.json +0 -110
  31. package/docker-build/standalone/.next/server/app/_global-error/page/app-paths-manifest.json +0 -3
  32. package/docker-build/standalone/.next/server/app/_global-error/page/build-manifest.json +0 -17
  33. package/docker-build/standalone/.next/server/app/_global-error/page/next-font-manifest.json +0 -6
  34. package/docker-build/standalone/.next/server/app/_global-error/page/react-loadable-manifest.json +0 -1
  35. package/docker-build/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +0 -4
  36. package/docker-build/standalone/.next/server/app/_global-error/page.js +0 -11
  37. package/docker-build/standalone/.next/server/app/_global-error/page.js.map +0 -5
  38. package/docker-build/standalone/.next/server/app/_global-error/page.js.nft.json +0 -1
  39. package/docker-build/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +0 -2
  40. package/docker-build/standalone/.next/server/app/_global-error.html +0 -2
  41. package/docker-build/standalone/.next/server/app/_global-error.meta +0 -15
  42. package/docker-build/standalone/.next/server/app/_global-error.rsc +0 -13
  43. package/docker-build/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +0 -5
  44. package/docker-build/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +0 -13
  45. package/docker-build/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +0 -6
  46. package/docker-build/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +0 -4
  47. package/docker-build/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +0 -1
  48. package/docker-build/standalone/.next/server/app/_not-found/page/app-paths-manifest.json +0 -3
  49. package/docker-build/standalone/.next/server/app/_not-found/page/build-manifest.json +0 -17
  50. package/docker-build/standalone/.next/server/app/_not-found/page/next-font-manifest.json +0 -11
  51. package/docker-build/standalone/.next/server/app/_not-found/page/react-loadable-manifest.json +0 -1
  52. package/docker-build/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +0 -4
  53. package/docker-build/standalone/.next/server/app/_not-found/page.js +0 -14
  54. package/docker-build/standalone/.next/server/app/_not-found/page.js.map +0 -5
  55. package/docker-build/standalone/.next/server/app/_not-found/page.js.nft.json +0 -1
  56. package/docker-build/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +0 -2
  57. package/docker-build/standalone/.next/server/app/_not-found.html +0 -1
  58. package/docker-build/standalone/.next/server/app/_not-found.meta +0 -16
  59. package/docker-build/standalone/.next/server/app/_not-found.rsc +0 -14
  60. package/docker-build/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +0 -14
  61. package/docker-build/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +0 -6
  62. package/docker-build/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +0 -5
  63. package/docker-build/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +0 -5
  64. package/docker-build/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +0 -4
  65. package/docker-build/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +0 -2
  66. package/docker-build/standalone/.next/server/app/api/deploy/route/app-paths-manifest.json +0 -3
  67. package/docker-build/standalone/.next/server/app/api/deploy/route/build-manifest.json +0 -11
  68. package/docker-build/standalone/.next/server/app/api/deploy/route/server-reference-manifest.json +0 -4
  69. package/docker-build/standalone/.next/server/app/api/deploy/route.js +0 -7
  70. package/docker-build/standalone/.next/server/app/api/deploy/route.js.map +0 -5
  71. package/docker-build/standalone/.next/server/app/api/deploy/route.js.nft.json +0 -1
  72. package/docker-build/standalone/.next/server/app/api/deploy/route_client-reference-manifest.js +0 -2
  73. package/docker-build/standalone/.next/server/app/api/deploy-image/route/app-paths-manifest.json +0 -3
  74. package/docker-build/standalone/.next/server/app/api/deploy-image/route/build-manifest.json +0 -11
  75. package/docker-build/standalone/.next/server/app/api/deploy-image/route/server-reference-manifest.json +0 -4
  76. package/docker-build/standalone/.next/server/app/api/deploy-image/route.js +0 -6
  77. package/docker-build/standalone/.next/server/app/api/deploy-image/route.js.map +0 -5
  78. package/docker-build/standalone/.next/server/app/api/deploy-image/route.js.nft.json +0 -1
  79. package/docker-build/standalone/.next/server/app/api/deploy-image/route_client-reference-manifest.js +0 -2
  80. package/docker-build/standalone/.next/server/app/api/docker-images/route/app-paths-manifest.json +0 -3
  81. package/docker-build/standalone/.next/server/app/api/docker-images/route/build-manifest.json +0 -11
  82. package/docker-build/standalone/.next/server/app/api/docker-images/route/server-reference-manifest.json +0 -4
  83. package/docker-build/standalone/.next/server/app/api/docker-images/route.js +0 -6
  84. package/docker-build/standalone/.next/server/app/api/docker-images/route.js.map +0 -5
  85. package/docker-build/standalone/.next/server/app/api/docker-images/route.js.nft.json +0 -1
  86. package/docker-build/standalone/.next/server/app/api/docker-images/route_client-reference-manifest.js +0 -2
  87. package/docker-build/standalone/.next/server/app/api/faucet/route/app-paths-manifest.json +0 -3
  88. package/docker-build/standalone/.next/server/app/api/faucet/route/build-manifest.json +0 -11
  89. package/docker-build/standalone/.next/server/app/api/faucet/route/server-reference-manifest.json +0 -4
  90. package/docker-build/standalone/.next/server/app/api/faucet/route.js +0 -9
  91. package/docker-build/standalone/.next/server/app/api/faucet/route.js.map +0 -5
  92. package/docker-build/standalone/.next/server/app/api/faucet/route.js.nft.json +0 -1
  93. package/docker-build/standalone/.next/server/app/api/faucet/route_client-reference-manifest.js +0 -2
  94. package/docker-build/standalone/.next/server/app/deploy/page/app-paths-manifest.json +0 -3
  95. package/docker-build/standalone/.next/server/app/deploy/page/build-manifest.json +0 -17
  96. package/docker-build/standalone/.next/server/app/deploy/page/next-font-manifest.json +0 -11
  97. package/docker-build/standalone/.next/server/app/deploy/page/react-loadable-manifest.json +0 -1
  98. package/docker-build/standalone/.next/server/app/deploy/page/server-reference-manifest.json +0 -4
  99. package/docker-build/standalone/.next/server/app/deploy/page.js +0 -16
  100. package/docker-build/standalone/.next/server/app/deploy/page.js.map +0 -5
  101. package/docker-build/standalone/.next/server/app/deploy/page.js.nft.json +0 -1
  102. package/docker-build/standalone/.next/server/app/deploy/page_client-reference-manifest.js +0 -2
  103. package/docker-build/standalone/.next/server/app/deploy.html +0 -1
  104. package/docker-build/standalone/.next/server/app/deploy.meta +0 -15
  105. package/docker-build/standalone/.next/server/app/deploy.rsc +0 -20
  106. package/docker-build/standalone/.next/server/app/deploy.segments/_full.segment.rsc +0 -20
  107. package/docker-build/standalone/.next/server/app/deploy.segments/_head.segment.rsc +0 -6
  108. package/docker-build/standalone/.next/server/app/deploy.segments/_index.segment.rsc +0 -5
  109. package/docker-build/standalone/.next/server/app/deploy.segments/_tree.segment.rsc +0 -4
  110. package/docker-build/standalone/.next/server/app/deploy.segments/deploy/__PAGE__.segment.rsc +0 -9
  111. package/docker-build/standalone/.next/server/app/deploy.segments/deploy.segment.rsc +0 -4
  112. package/docker-build/standalone/.next/server/app/faucet/page/app-paths-manifest.json +0 -3
  113. package/docker-build/standalone/.next/server/app/faucet/page/build-manifest.json +0 -17
  114. package/docker-build/standalone/.next/server/app/faucet/page/next-font-manifest.json +0 -11
  115. package/docker-build/standalone/.next/server/app/faucet/page/react-loadable-manifest.json +0 -1
  116. package/docker-build/standalone/.next/server/app/faucet/page/server-reference-manifest.json +0 -4
  117. package/docker-build/standalone/.next/server/app/faucet/page.js +0 -16
  118. package/docker-build/standalone/.next/server/app/faucet/page.js.map +0 -5
  119. package/docker-build/standalone/.next/server/app/faucet/page.js.nft.json +0 -1
  120. package/docker-build/standalone/.next/server/app/faucet/page_client-reference-manifest.js +0 -2
  121. package/docker-build/standalone/.next/server/app/faucet.html +0 -1
  122. package/docker-build/standalone/.next/server/app/faucet.meta +0 -15
  123. package/docker-build/standalone/.next/server/app/faucet.rsc +0 -20
  124. package/docker-build/standalone/.next/server/app/faucet.segments/_full.segment.rsc +0 -20
  125. package/docker-build/standalone/.next/server/app/faucet.segments/_head.segment.rsc +0 -6
  126. package/docker-build/standalone/.next/server/app/faucet.segments/_index.segment.rsc +0 -5
  127. package/docker-build/standalone/.next/server/app/faucet.segments/_tree.segment.rsc +0 -4
  128. package/docker-build/standalone/.next/server/app/faucet.segments/faucet/__PAGE__.segment.rsc +0 -9
  129. package/docker-build/standalone/.next/server/app/faucet.segments/faucet.segment.rsc +0 -4
  130. package/docker-build/standalone/.next/server/app/favicon.ico/route/app-paths-manifest.json +0 -3
  131. package/docker-build/standalone/.next/server/app/favicon.ico/route/build-manifest.json +0 -11
  132. package/docker-build/standalone/.next/server/app/favicon.ico/route.js +0 -7
  133. package/docker-build/standalone/.next/server/app/favicon.ico/route.js.map +0 -5
  134. package/docker-build/standalone/.next/server/app/favicon.ico/route.js.nft.json +0 -1
  135. package/docker-build/standalone/.next/server/app/favicon.ico.body +0 -0
  136. package/docker-build/standalone/.next/server/app/favicon.ico.meta +0 -1
  137. package/docker-build/standalone/.next/server/app/images/page/app-paths-manifest.json +0 -3
  138. package/docker-build/standalone/.next/server/app/images/page/build-manifest.json +0 -17
  139. package/docker-build/standalone/.next/server/app/images/page/next-font-manifest.json +0 -11
  140. package/docker-build/standalone/.next/server/app/images/page/react-loadable-manifest.json +0 -1
  141. package/docker-build/standalone/.next/server/app/images/page/server-reference-manifest.json +0 -4
  142. package/docker-build/standalone/.next/server/app/images/page.js +0 -16
  143. package/docker-build/standalone/.next/server/app/images/page.js.map +0 -5
  144. package/docker-build/standalone/.next/server/app/images/page.js.nft.json +0 -1
  145. package/docker-build/standalone/.next/server/app/images/page_client-reference-manifest.js +0 -2
  146. package/docker-build/standalone/.next/server/app/images.html +0 -1
  147. package/docker-build/standalone/.next/server/app/images.meta +0 -15
  148. package/docker-build/standalone/.next/server/app/images.rsc +0 -20
  149. package/docker-build/standalone/.next/server/app/images.segments/_full.segment.rsc +0 -20
  150. package/docker-build/standalone/.next/server/app/images.segments/_head.segment.rsc +0 -6
  151. package/docker-build/standalone/.next/server/app/images.segments/_index.segment.rsc +0 -5
  152. package/docker-build/standalone/.next/server/app/images.segments/_tree.segment.rsc +0 -4
  153. package/docker-build/standalone/.next/server/app/images.segments/images/__PAGE__.segment.rsc +0 -9
  154. package/docker-build/standalone/.next/server/app/images.segments/images.segment.rsc +0 -4
  155. package/docker-build/standalone/.next/server/app/index.html +0 -1
  156. package/docker-build/standalone/.next/server/app/index.meta +0 -14
  157. package/docker-build/standalone/.next/server/app/index.rsc +0 -25
  158. package/docker-build/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +0 -8
  159. package/docker-build/standalone/.next/server/app/index.segments/_full.segment.rsc +0 -25
  160. package/docker-build/standalone/.next/server/app/index.segments/_head.segment.rsc +0 -6
  161. package/docker-build/standalone/.next/server/app/index.segments/_index.segment.rsc +0 -5
  162. package/docker-build/standalone/.next/server/app/index.segments/_tree.segment.rsc +0 -4
  163. package/docker-build/standalone/.next/server/app/page/app-paths-manifest.json +0 -3
  164. package/docker-build/standalone/.next/server/app/page/build-manifest.json +0 -17
  165. package/docker-build/standalone/.next/server/app/page/next-font-manifest.json +0 -11
  166. package/docker-build/standalone/.next/server/app/page/react-loadable-manifest.json +0 -1
  167. package/docker-build/standalone/.next/server/app/page/server-reference-manifest.json +0 -4
  168. package/docker-build/standalone/.next/server/app/page.js +0 -16
  169. package/docker-build/standalone/.next/server/app/page.js.map +0 -5
  170. package/docker-build/standalone/.next/server/app/page.js.nft.json +0 -1
  171. package/docker-build/standalone/.next/server/app/page_client-reference-manifest.js +0 -2
  172. package/docker-build/standalone/.next/server/app-paths-manifest.json +0 -13
  173. package/docker-build/standalone/.next/server/chunks/10072_infra_server-cc__next-internal_server_app_api_deploy_route_actions_6cdc6432.js +0 -3
  174. package/docker-build/standalone/.next/server/chunks/10072_infra_server-cc__next-internal_server_app_api_faucet_route_actions_f54ec975.js +0 -3
  175. package/docker-build/standalone/.next/server/chunks/10072_infra_server-cc__next-internal_server_app_favicon_ico_route_actions_d73715d1.js +0 -3
  176. package/docker-build/standalone/.next/server/chunks/66d90_server-cc__next-internal_server_app_api_deploy-image_route_actions_b340a7f4.js +0 -3
  177. package/docker-build/standalone/.next/server/chunks/66d90_server-cc__next-internal_server_app_api_docker-images_route_actions_4adcb030.js +0 -3
  178. package/docker-build/standalone/.next/server/chunks/6f6aa_4d460f49._.js +0 -30
  179. package/docker-build/standalone/.next/server/chunks/6f6aa_@noble_curves_esm_secp256k1_c7f9b58b.js +0 -3
  180. package/docker-build/standalone/.next/server/chunks/6f6aa_next_dist_esm_build_templates_app-route_1a9ee783.js +0 -6
  181. package/docker-build/standalone/.next/server/chunks/6f6aa_next_dist_esm_build_templates_app-route_8d132e6a.js +0 -3
  182. package/docker-build/standalone/.next/server/chunks/6f6aa_viem__esm_utils_ccip_bb7bf310.js +0 -3
  183. package/docker-build/standalone/.next/server/chunks/[externals]_next_dist_b01ab6e1._.js +0 -3
  184. package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__0928cca7._.js +0 -3
  185. package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__0c6b3bd9._.js +0 -3
  186. package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__1846bb23._.js +0 -3
  187. package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__8f8a2ff9._.js +0 -3
  188. package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__90ea784b._.js +0 -21
  189. package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__f6379956._.js +0 -39
  190. package/docker-build/standalone/.next/server/chunks/[turbopack]_runtime.js +0 -795
  191. package/docker-build/standalone/.next/server/chunks/ssr/10072_infra_server-cc__next-internal_server_app__global-error_page_actions_bdbde336.js +0 -3
  192. package/docker-build/standalone/.next/server/chunks/ssr/10072_infra_server-cc__next-internal_server_app__not-found_page_actions_41269af3.js +0 -3
  193. package/docker-build/standalone/.next/server/chunks/ssr/10072_infra_server-cc__next-internal_server_app_deploy_page_actions_3988cfb8.js +0 -3
  194. package/docker-build/standalone/.next/server/chunks/ssr/10072_infra_server-cc__next-internal_server_app_faucet_page_actions_e5e8dd8a.js +0 -3
  195. package/docker-build/standalone/.next/server/chunks/ssr/10072_infra_server-cc__next-internal_server_app_images_page_actions_bcdfd86b.js +0 -3
  196. package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_293382c4._.js +0 -4
  197. package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_55723634._.js +0 -4
  198. package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_821445df._.js +0 -3
  199. package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_8545ebc7._.js +0 -4
  200. package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_acad38a1._.js +0 -6
  201. package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_app_b373a582._.js +0 -3
  202. package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_d03dcb7a._.js +0 -4
  203. package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_7c51ed4c._.js +0 -3
  204. package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_05cd73d5._.js +0 -3
  205. package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_3e60adb5._.js +0 -6
  206. package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_5002976b._.js +0 -4
  207. package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_client_components_a432b2d3._.js +0 -3
  208. package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_client_components_builtin_forbidden_b4e63d3a.js +0 -3
  209. package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_client_components_builtin_global-error_edcabd66.js +0 -3
  210. package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_client_components_builtin_unauthorized_f08488ad.js +0 -3
  211. package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_esm_build_templates_app-page_c7a8656a.js +0 -4
  212. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e0d983d._.js +0 -3
  213. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__0f25bf3b._.js +0 -3
  214. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__10dae68a._.js +0 -3
  215. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ebd727b._.js +0 -3
  216. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__30996048._.js +0 -3
  217. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__587c95dd._.js +0 -3
  218. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__5ecc39a2._.js +0 -3
  219. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__6382fff8._.js +0 -3
  220. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__8ed1042a._.js +0 -3
  221. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__91644c56._.js +0 -3
  222. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__a2833bcd._.js +0 -10
  223. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__acf31a1c._.js +0 -3
  224. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__ae009f46._.js +0 -3
  225. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__daca67ae._.js +0 -3
  226. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__f2372d3f._.js +0 -4
  227. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__f2ed834a._.js +0 -3
  228. package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__ff0dddf3._.js +0 -3
  229. package/docker-build/standalone/.next/server/chunks/ssr/[turbopack]_runtime.js +0 -795
  230. package/docker-build/standalone/.next/server/chunks/ssr/e6d68_cc_CODECRYPTO_infra_server-cc__next-internal_server_app_page_actions_12ae3ff1.js +0 -3
  231. package/docker-build/standalone/.next/server/functions-config-manifest.json +0 -4
  232. package/docker-build/standalone/.next/server/middleware-build-manifest.js +0 -21
  233. package/docker-build/standalone/.next/server/middleware-manifest.json +0 -6
  234. package/docker-build/standalone/.next/server/next-font-manifest.js +0 -1
  235. package/docker-build/standalone/.next/server/next-font-manifest.json +0 -27
  236. package/docker-build/standalone/.next/server/pages/404.html +0 -1
  237. package/docker-build/standalone/.next/server/pages/500.html +0 -2
  238. package/docker-build/standalone/.next/server/pages-manifest.json +0 -4
  239. package/docker-build/standalone/.next/server/server-reference-manifest.js +0 -1
  240. package/docker-build/standalone/.next/server/server-reference-manifest.json +0 -5
  241. package/docker-build/standalone/.next/static/ZrQJjBH5oznRmy8xN4NKX/_buildManifest.js +0 -11
  242. package/docker-build/standalone/.next/static/ZrQJjBH5oznRmy8xN4NKX/_clientMiddlewareManifest.json +0 -1
  243. package/docker-build/standalone/.next/static/ZrQJjBH5oznRmy8xN4NKX/_ssgManifest.js +0 -1
  244. package/docker-build/standalone/.next/static/chunks/0c03a563297c48f4.js +0 -1
  245. package/docker-build/standalone/.next/static/chunks/3142ddfdb448fd24.js +0 -1
  246. package/docker-build/standalone/.next/static/chunks/35b2ae0057b43b20.js +0 -1
  247. package/docker-build/standalone/.next/static/chunks/5a1aef391fd12242.js +0 -1
  248. package/docker-build/standalone/.next/static/chunks/66401b6fc62891de.js +0 -4
  249. package/docker-build/standalone/.next/static/chunks/782a67ca986fb1bd.js +0 -1
  250. package/docker-build/standalone/.next/static/chunks/8b27abf6cb0fca62.js +0 -2
  251. package/docker-build/standalone/.next/static/chunks/8dba80aa68873762.css +0 -3
  252. package/docker-build/standalone/.next/static/chunks/902797f337bf356c.js +0 -1
  253. package/docker-build/standalone/.next/static/chunks/9706b17cfd50df01.js +0 -1
  254. package/docker-build/standalone/.next/static/chunks/a6dad97d9634a72d.js +0 -1
  255. package/docker-build/standalone/.next/static/chunks/a6dad97d9634a72d.js.map +0 -1
  256. package/docker-build/standalone/.next/static/chunks/df3b8eb181fde7c2.js +0 -1
  257. package/docker-build/standalone/.next/static/chunks/turbopack-237950634fd3a365.js +0 -4
  258. package/docker-build/standalone/.next/static/media/4fa387ec64143e14-s.c1fdd6c2.woff2 +0 -0
  259. package/docker-build/standalone/.next/static/media/7178b3e590c64307-s.b97b3418.woff2 +0 -0
  260. package/docker-build/standalone/.next/static/media/797e433ab948586e-s.p.dbea232f.woff2 +0 -0
  261. package/docker-build/standalone/.next/static/media/8a480f0b521d4e75-s.8e0177b5.woff2 +0 -0
  262. package/docker-build/standalone/.next/static/media/bbc41e54d2fcbd21-s.799d8ef8.woff2 +0 -0
  263. package/docker-build/standalone/.next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2 +0 -0
  264. package/docker-build/standalone/.next/static/media/favicon.0b3bf435.ico +0 -0
  265. package/docker-build/standalone/package.json +0 -35
  266. package/docker-build/standalone/public/deploy-test.html +0 -276
  267. package/docker-build/standalone/public/file.svg +0 -1
  268. package/docker-build/standalone/public/globe.svg +0 -1
  269. package/docker-build/standalone/public/next.svg +0 -1
  270. package/docker-build/standalone/public/vercel.svg +0 -1
  271. package/docker-build/standalone/public/window.svg +0 -1
  272. package/docker-build/standalone/server.js +0 -38
@@ -7,8 +7,8 @@ import * as path from 'path';
7
7
  import * as os from 'os';
8
8
 
9
9
  export const deployCommand = new Command('deploy')
10
- .description('Build and deploy Docker image for Next.js standalone application')
11
- .argument('<project-path>', 'Path to the Next.js project directory')
10
+ .description('Build and deploy Docker image for Next.js or Express application')
11
+ .argument('<project-path>', 'Path to the project directory')
12
12
  .argument('[dest-folder]', 'Destination folder for Docker build context', './docker-build')
13
13
  .option('--skip-build', 'Skip npm run build (assume already built)', false)
14
14
  .option('--no-push', 'Build image but do not push to registry')
@@ -17,6 +17,8 @@ export const deployCommand = new Command('deploy')
17
17
  .option('--env-file <path>', 'Path to .env file with environment variables')
18
18
  .option('--port <port>', 'Application port', '3000')
19
19
  .option('--domain-base <domain>', 'Domain base for deployment', 'proyectos.codecrypto.academy')
20
+ .option('--image-version <version>', 'Image version/tag to deploy (overrides package.json version)')
21
+ .option('--skip-git-check', 'Skip Git repository status check', false)
20
22
  .action(async (projectPath: string, destFolder: string, options) => {
21
23
  console.log(chalk.blue('\n🐳 CodeCrypto Docker Deployment\n'));
22
24
 
@@ -35,9 +37,81 @@ export const deployCommand = new Command('deploy')
35
37
  process.exit(1);
36
38
  }
37
39
 
38
- // Leer versión del package.json
40
+ // Validar que no hay archivos pendientes de commit (a menos que se omita)
41
+ if (!options.skipGitCheck) {
42
+ const gitCheckSpinner = ora('Checking Git status...').start();
43
+ try {
44
+ // Verificar si es un repositorio git usando git rev-parse
45
+ // Esto es más robusto que solo verificar .git ya que funciona con submodules y worktrees
46
+ let isGitRepo = false;
47
+ try {
48
+ execSync('git rev-parse --git-dir', {
49
+ cwd: resolvedProjectPath,
50
+ encoding: 'utf-8',
51
+ stdio: 'pipe',
52
+ });
53
+ isGitRepo = true;
54
+ } catch {
55
+ // No es un repositorio git o git no está disponible
56
+ isGitRepo = false;
57
+ }
58
+
59
+ if (isGitRepo) {
60
+ // Verificar si hay cambios sin commitear
61
+ try {
62
+ const gitStatus = execSync('git status --porcelain', {
63
+ cwd: resolvedProjectPath,
64
+ encoding: 'utf-8',
65
+ stdio: 'pipe',
66
+ }).trim();
67
+
68
+ if (gitStatus) {
69
+ gitCheckSpinner.fail('Uncommitted changes detected');
70
+ console.error(chalk.red('\n❌ Error: Hay archivos pendientes de commit en el repositorio'));
71
+ console.error(chalk.yellow('\n📋 Archivos modificados/sin commitear:'));
72
+ console.log(chalk.gray('─'.repeat(60)));
73
+
74
+ // Mostrar los archivos pendientes
75
+ const files = gitStatus.split('\n').filter(line => line.trim());
76
+ files.forEach(file => {
77
+ const status = file.substring(0, 2);
78
+ const fileName = file.substring(3);
79
+ let statusColor = chalk.yellow;
80
+ if (status.includes('A')) statusColor = chalk.green;
81
+ else if (status.includes('D')) statusColor = chalk.red;
82
+ else if (status.includes('M')) statusColor = chalk.yellow;
83
+ console.log(chalk.gray(` ${statusColor(status)} ${chalk.white(fileName)}`));
84
+ });
85
+
86
+ console.log(chalk.gray('─'.repeat(60)));
87
+ console.error(chalk.yellow('\n💡 Por favor, haz commit de tus cambios antes de desplegar:'));
88
+ console.error(chalk.cyan(' git add .'));
89
+ console.error(chalk.cyan(' git commit -m "your message"'));
90
+ console.error(chalk.yellow('\n O usa --skip-git-check para omitir esta validación (no recomendado)'));
91
+ process.exit(1);
92
+ } else {
93
+ gitCheckSpinner.succeed('Git repository is clean');
94
+ }
95
+ } catch (error: any) {
96
+ // Si git status falla, puede ser que haya algún problema
97
+ gitCheckSpinner.warn('Could not check Git status, continuing...');
98
+ if (error.message) {
99
+ console.log(chalk.yellow(` Warning: ${error.message}`));
100
+ }
101
+ }
102
+ } else {
103
+ gitCheckSpinner.succeed('Not a Git repository (skipping check)');
104
+ }
105
+ } catch (error: any) {
106
+ gitCheckSpinner.warn('Git check failed, continuing...');
107
+ }
108
+ } else {
109
+ console.log(chalk.yellow('⚠️ Git status check skipped (--skip-git-check)'));
110
+ }
111
+
112
+ // Leer versión del package.json o usar la versión especificada
39
113
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
40
- const version = packageJson.version || 'latest';
114
+ const version = options.imageVersion || packageJson.version || 'latest';
41
115
  const projectName = path.basename(resolvedProjectPath);
42
116
  const imageBase = `jviejo/${projectName}`;
43
117
  const imageName = `${imageBase}:${version}`;
@@ -49,128 +123,164 @@ export const deployCommand = new Command('deploy')
49
123
  // - Con --no-push: options.push = false (no hace push)
50
124
  const shouldPush = options.push !== false;
51
125
 
126
+ // Detectar automáticamente el tipo de proyecto analizando package.json
127
+ const allDependencies = {
128
+ ...(packageJson.dependencies || {}),
129
+ ...(packageJson.devDependencies || {}),
130
+ };
131
+
132
+ let projectType: 'nextjs' | 'express' | null = null;
133
+
134
+ if (allDependencies.next || allDependencies['nextjs']) {
135
+ projectType = 'nextjs';
136
+ } else if (allDependencies.express) {
137
+ projectType = 'express';
138
+ }
139
+
140
+ if (!projectType) {
141
+ console.error(chalk.red(`❌ Error: No se pudo detectar el tipo de proyecto`));
142
+ console.error(chalk.yellow(' El proyecto debe tener "next" o "express" en las dependencias del package.json'));
143
+ console.error(chalk.yellow(' Dependencias encontradas:'));
144
+ const depKeys = Object.keys(allDependencies).slice(0, 10);
145
+ depKeys.forEach(dep => {
146
+ console.error(chalk.gray(` - ${dep}`));
147
+ });
148
+ if (Object.keys(allDependencies).length > 10) {
149
+ console.error(chalk.gray(` ... y ${Object.keys(allDependencies).length - 10} más`));
150
+ }
151
+ process.exit(1);
152
+ }
153
+
52
154
  console.log(chalk.gray('Deployment Configuration:'));
53
155
  console.log(chalk.white(` Project: ${chalk.green(projectName)}`));
156
+ console.log(chalk.white(` Type: ${chalk.green(projectType)}`));
54
157
  console.log(chalk.white(` Version: ${chalk.green(version)}`));
55
158
  console.log(chalk.white(` Image: ${chalk.green(imageName)}`));
56
159
  console.log(chalk.white(` Latest: ${chalk.green(imageLatest)}`));
57
160
  console.log(chalk.white(` Push to Registry: ${shouldPush ? chalk.green('Yes') : chalk.yellow('No')}\n`));
58
161
 
59
- // Paso 1: Build del proyecto si es necesario
60
- if (!options.skipBuild) {
61
- const buildSpinner = ora('Building Next.js application...').start();
62
- try {
63
- execSync('npm run build', {
64
- cwd: resolvedProjectPath,
65
- stdio: 'pipe'
66
- });
67
- buildSpinner.succeed('Build completed successfully');
68
- } catch (error) {
69
- buildSpinner.fail('Build failed');
70
- console.error(chalk.red('Error during build. Make sure you have "output: standalone" in next.config.ts'));
71
- process.exit(1);
72
- }
73
- }
74
-
75
- // Verificar que existe .next/standalone
76
- const standalonePath = path.join(resolvedProjectPath, '.next', 'standalone');
77
- if (!fs.existsSync(standalonePath)) {
78
- console.error(chalk.red(`❌ Error: No se encontró .next/standalone`));
79
- console.error(chalk.yellow('Asegúrate de tener "output: standalone" en next.config.ts y ejecutar "npm run build"'));
80
- process.exit(1);
81
- }
82
-
83
- // Paso 2: Preparar directorio destino
162
+ // Preparar directorio destino
84
163
  const resolvedDestFolder = path.resolve(destFolder);
85
- const standaloneDest = path.join(resolvedDestFolder, 'standalone');
86
-
87
- const copySpinner = ora('Copying standalone files...').start();
88
164
  if (fs.existsSync(resolvedDestFolder)) {
89
165
  fs.rmSync(resolvedDestFolder, { recursive: true, force: true });
90
166
  }
91
- fs.mkdirSync(standaloneDest, { recursive: true });
92
-
93
- // Copiar contenido de standalone
94
- const nextDir = findDirectory(standalonePath, '.next');
95
- if (nextDir) {
96
- const parentDir = path.dirname(nextDir);
97
- copyDirectory(parentDir, standaloneDest);
98
- } else {
99
- copyDirectory(standalonePath, standaloneDest);
100
- }
101
-
102
- // Copiar .next/static
103
- const staticPath = path.join(resolvedProjectPath, '.next', 'static');
104
- if (fs.existsSync(staticPath)) {
105
- const staticDest = path.join(standaloneDest, '.next', 'static');
106
- fs.mkdirSync(staticDest, { recursive: true });
107
- copyDirectory(staticPath, staticDest);
108
- }
109
-
110
- // Copiar public
111
- const publicPath = path.join(resolvedProjectPath, 'public');
112
- if (fs.existsSync(publicPath)) {
113
- const publicDest = path.join(standaloneDest, 'public');
114
- fs.mkdirSync(publicDest, { recursive: true });
115
- copyDirectory(publicPath, publicDest);
116
- }
167
+ fs.mkdirSync(resolvedDestFolder, { recursive: true });
117
168
 
118
- // Verificar server.js
119
- const serverJsPath = path.join(standaloneDest, 'server.js');
120
- if (!fs.existsSync(serverJsPath)) {
121
- copySpinner.fail('server.js not found in standalone');
122
- process.exit(1);
123
- }
124
-
125
- copySpinner.succeed('Files copied successfully');
126
-
127
- // Leer y procesar archivo .env si existe
128
- let nextPublicEnvVars: string[] = [];
129
169
  let runtimeEnvVars: string[] = [];
170
+ let nextPublicEnvVars: string[] = [];
171
+ let dockerfileContent: string;
172
+
173
+ // Determinar ruta del archivo .env (común para ambos tipos de proyecto)
130
174
  const envFilePath = options.envFile
131
175
  ? path.resolve(options.envFile)
132
176
  : path.join(resolvedProjectPath, '.env');
133
-
134
- if (fs.existsSync(envFilePath)) {
135
- const envContent = fs.readFileSync(envFilePath, 'utf-8');
136
- const envLines = envContent.split('\n');
177
+
178
+ if (projectType === 'nextjs') {
179
+ // ========== LÓGICA PARA NEXT.JS ==========
137
180
 
138
- for (const line of envLines) {
139
- const trimmed = line.trim();
140
- // Ignorar comentarios y líneas vacías
141
- if (!trimmed || trimmed.startsWith('#')) continue;
142
-
143
- const equalIndex = trimmed.indexOf('=');
144
- if (equalIndex === -1) continue;
145
-
146
- const key = trimmed.substring(0, equalIndex).trim();
147
- const value = trimmed.substring(equalIndex + 1).trim();
181
+ // Paso 1: Build del proyecto si es necesario
182
+ if (!options.skipBuild) {
183
+ const buildSpinner = ora('Building Next.js application...').start();
184
+ try {
185
+ execSync('npm run build', {
186
+ cwd: resolvedProjectPath,
187
+ stdio: 'pipe'
188
+ });
189
+ buildSpinner.succeed('Build completed successfully');
190
+ } catch (error) {
191
+ buildSpinner.fail('Build failed');
192
+ console.error(chalk.red('Error during build. Make sure you have "output: standalone" in next.config.ts'));
193
+ process.exit(1);
194
+ }
195
+ }
196
+
197
+ // Verificar que existe .next/standalone
198
+ const standalonePath = path.join(resolvedProjectPath, '.next', 'standalone');
199
+ if (!fs.existsSync(standalonePath)) {
200
+ console.error(chalk.red(`❌ Error: No se encontró .next/standalone`));
201
+ console.error(chalk.yellow('Asegúrate de tener "output: standalone" en next.config.ts y ejecutar "npm run build"'));
202
+ process.exit(1);
203
+ }
204
+
205
+ // Paso 2: Preparar directorio destino
206
+ const standaloneDest = path.join(resolvedDestFolder, 'standalone');
207
+
208
+ const copySpinner = ora('Copying standalone files...').start();
209
+ fs.mkdirSync(standaloneDest, { recursive: true });
210
+
211
+ // Copiar contenido de standalone
212
+ const nextDir = findDirectory(standalonePath, '.next');
213
+ if (nextDir) {
214
+ const parentDir = path.dirname(nextDir);
215
+ copyDirectory(parentDir, standaloneDest);
216
+ } else {
217
+ copyDirectory(standalonePath, standaloneDest);
218
+ }
219
+
220
+ // Copiar .next/static
221
+ const staticPath = path.join(resolvedProjectPath, '.next', 'static');
222
+ if (fs.existsSync(staticPath)) {
223
+ const staticDest = path.join(standaloneDest, '.next', 'static');
224
+ fs.mkdirSync(staticDest, { recursive: true });
225
+ copyDirectory(staticPath, staticDest);
226
+ }
227
+
228
+ // Copiar public
229
+ const publicPath = path.join(resolvedProjectPath, 'public');
230
+ if (fs.existsSync(publicPath)) {
231
+ const publicDest = path.join(standaloneDest, 'public');
232
+ fs.mkdirSync(publicDest, { recursive: true });
233
+ copyDirectory(publicPath, publicDest);
234
+ }
235
+
236
+ // Verificar server.js
237
+ const serverJsPath = path.join(standaloneDest, 'server.js');
238
+ if (!fs.existsSync(serverJsPath)) {
239
+ copySpinner.fail('server.js not found in standalone');
240
+ process.exit(1);
241
+ }
242
+
243
+ copySpinner.succeed('Files copied successfully');
244
+
245
+ // Leer y procesar archivo .env si existe
246
+ // (envFilePath ya está definido arriba)
247
+ if (fs.existsSync(envFilePath)) {
248
+ const envContent = fs.readFileSync(envFilePath, 'utf-8');
249
+ const envLines = envContent.split('\n');
148
250
 
149
- if (key.startsWith('NEXT_PUBLIC_')) {
150
- nextPublicEnvVars.push(`${key}=${value}`);
151
- } else {
152
- runtimeEnvVars.push(`${key}=${value}`);
251
+ for (const line of envLines) {
252
+ const trimmed = line.trim();
253
+ // Ignorar comentarios y líneas vacías
254
+ if (!trimmed || trimmed.startsWith('#')) continue;
255
+
256
+ const equalIndex = trimmed.indexOf('=');
257
+ if (equalIndex === -1) continue;
258
+
259
+ const key = trimmed.substring(0, equalIndex).trim();
260
+ const value = trimmed.substring(equalIndex + 1).trim();
261
+
262
+ if (key.startsWith('NEXT_PUBLIC_')) {
263
+ nextPublicEnvVars.push(`${key}=${value}`);
264
+ } else {
265
+ runtimeEnvVars.push(`${key}=${value}`);
266
+ }
153
267
  }
154
268
  }
155
- }
156
269
 
157
- // Paso 3: Crear Dockerfile con variables NEXT_PUBLIC_*
158
- const dockerfilePath = path.join(resolvedDestFolder, 'Dockerfile');
159
-
160
- // Construir ARG y ENV para NEXT_PUBLIC_*
161
- const buildArgs = nextPublicEnvVars.map(env => {
162
- const [key, ...valueParts] = env.split('=');
163
- const value = valueParts.join('=');
164
- return `ARG ${key}=${value}`;
165
- }).join('\n');
166
-
167
- const buildEnvs = nextPublicEnvVars.map(env => {
168
- const [key, ...valueParts] = env.split('=');
169
- const value = valueParts.join('=');
170
- return `ENV ${key}=${value}`;
171
- }).join('\n');
172
-
173
- const dockerfileContent = `FROM node:20-alpine
270
+ // Construir ARG y ENV para NEXT_PUBLIC_*
271
+ const buildArgs = nextPublicEnvVars.map(env => {
272
+ const [key, ...valueParts] = env.split('=');
273
+ const value = valueParts.join('=');
274
+ return `ARG ${key}=${value}`;
275
+ }).join('\n');
276
+
277
+ const buildEnvs = nextPublicEnvVars.map(env => {
278
+ const [key, ...valueParts] = env.split('=');
279
+ const value = valueParts.join('=');
280
+ return `ENV ${key}=${value}`;
281
+ }).join('\n');
282
+
283
+ dockerfileContent = `FROM node:20-alpine
174
284
  WORKDIR /app
175
285
 
176
286
  ENV NODE_ENV=production
@@ -189,22 +299,257 @@ EXPOSE 3000
189
299
  # Arrancamos directamente con Node
190
300
  CMD ["node", "server.js"]
191
301
  `;
302
+
303
+ } else {
304
+ // ========== LÓGICA PARA EXPRESS ==========
305
+
306
+ // Paso 1: Instalar dependencias de producción si es necesario
307
+ if (!options.skipBuild) {
308
+ const installSpinner = ora('Installing production dependencies...').start();
309
+ try {
310
+ // Verificar si node_modules existe
311
+ const nodeModulesPath = path.join(resolvedProjectPath, 'node_modules');
312
+ if (!fs.existsSync(nodeModulesPath)) {
313
+ execSync('npm install --production', {
314
+ cwd: resolvedProjectPath,
315
+ stdio: 'pipe'
316
+ });
317
+ }
318
+ installSpinner.succeed('Dependencies ready');
319
+ } catch (error) {
320
+ installSpinner.fail('Failed to install dependencies');
321
+ console.error(chalk.red('Error installing dependencies'));
322
+ process.exit(1);
323
+ }
324
+ }
325
+
326
+ // Paso 2: Copiar archivos del proyecto (sin node_modules, Docker lo instalará)
327
+ const copySpinner = ora('Copying project files...').start();
328
+
329
+ // Copiar todos los archivos excepto los que están en .dockerignore
330
+ const ignorePatterns = [
331
+ 'node_modules',
332
+ '.git',
333
+ '.next',
334
+ 'dist',
335
+ 'build',
336
+ '.env',
337
+ '.env.local',
338
+ '.env.*.local',
339
+ 'npm-debug.log*',
340
+ 'yarn-debug.log*',
341
+ 'yarn-error.log*',
342
+ '.DS_Store',
343
+ 'coverage',
344
+ '.nyc_output',
345
+ ];
346
+
347
+ function shouldIgnore(filePath: string, basePath: string): boolean {
348
+ const relativePath = path.relative(basePath, filePath);
349
+ return ignorePatterns.some(pattern => {
350
+ if (relativePath.includes(pattern)) return true;
351
+ // Verificar si es un archivo que empieza con el patrón
352
+ const parts = relativePath.split(path.sep);
353
+ return parts.some(part => part === pattern || part.startsWith(pattern));
354
+ });
355
+ }
356
+
357
+ function copyProjectFiles(src: string, dest: string): void {
358
+ if (!fs.existsSync(dest)) {
359
+ fs.mkdirSync(dest, { recursive: true });
360
+ }
361
+
362
+ const entries = fs.readdirSync(src, { withFileTypes: true });
363
+ for (const entry of entries) {
364
+ const srcPath = path.join(src, entry.name);
365
+ const destPath = path.join(dest, entry.name);
366
+
367
+ // Ignorar archivos y directorios según los patrones
368
+ if (shouldIgnore(srcPath, resolvedProjectPath)) {
369
+ continue;
370
+ }
371
+
372
+ try {
373
+ const stats = fs.lstatSync(srcPath);
374
+
375
+ if (stats.isDirectory()) {
376
+ copyProjectFiles(srcPath, destPath);
377
+ } else if (stats.isFile()) {
378
+ fs.copyFileSync(srcPath, destPath);
379
+ }
380
+ } catch (error: any) {
381
+ // Ignorar errores al copiar archivos especiales
382
+ if (error.code === 'ENOTSUP' || error.code === 'EINVAL' || error.code === 'EOPNOTSUPP') {
383
+ continue;
384
+ }
385
+ throw error;
386
+ }
387
+ }
388
+ }
389
+
390
+ // Copiar archivos del proyecto
391
+ copyProjectFiles(resolvedProjectPath, resolvedDestFolder);
392
+
393
+ // Verificar que existe package.json en el destino
394
+ const destPackageJson = path.join(resolvedDestFolder, 'package.json');
395
+ if (!fs.existsSync(destPackageJson)) {
396
+ copySpinner.fail('package.json not found');
397
+ console.error(chalk.red('❌ Error: package.json is required for Express application'));
398
+ process.exit(1);
399
+ }
400
+
401
+ // Verificar que existe un archivo principal
402
+ const packageJson = JSON.parse(fs.readFileSync(destPackageJson, 'utf-8'));
403
+ const mainFile = packageJson.main || 'index.js';
404
+ const mainFilePath = path.join(resolvedDestFolder, mainFile);
405
+
406
+ if (!fs.existsSync(mainFilePath)) {
407
+ // Buscar otros archivos comunes
408
+ const commonFiles = ['index.js', 'server.js', 'app.js', 'main.js'];
409
+ let found = false;
410
+ for (const file of commonFiles) {
411
+ if (fs.existsSync(path.join(resolvedDestFolder, file))) {
412
+ found = true;
413
+ break;
414
+ }
415
+ }
416
+ if (!found) {
417
+ copySpinner.fail(`Main entry file not found: ${mainFile}`);
418
+ console.error(chalk.red(`❌ Error: Could not find main entry file (${mainFile}) for Express application`));
419
+ process.exit(1);
420
+ }
421
+ }
422
+
423
+ copySpinner.succeed('Files copied successfully');
424
+
425
+ // Leer y procesar archivo .env si existe
426
+ // (envFilePath ya está definido arriba)
427
+ if (fs.existsSync(envFilePath)) {
428
+ const envContent = fs.readFileSync(envFilePath, 'utf-8');
429
+ const envLines = envContent.split('\n');
430
+
431
+ for (const line of envLines) {
432
+ const trimmed = line.trim();
433
+ // Ignorar comentarios y líneas vacías
434
+ if (!trimmed || trimmed.startsWith('#')) continue;
435
+
436
+ const equalIndex = trimmed.indexOf('=');
437
+ if (equalIndex === -1) continue;
438
+
439
+ const key = trimmed.substring(0, equalIndex).trim();
440
+ const value = trimmed.substring(equalIndex + 1).trim();
441
+
442
+ runtimeEnvVars.push(`${key}=${value}`);
443
+ }
444
+ }
445
+
446
+ // Crear Dockerfile optimizado para Express
447
+ // (destPackageJson, packageJson y mainFile ya están declaradas arriba)
448
+ const startScript = packageJson.scripts?.start;
449
+
450
+ // Determinar el comando de inicio
451
+ let startCmd: string[];
452
+ if (startScript) {
453
+ // Si hay un script start, usarlo
454
+ startCmd = startScript.split(' ');
455
+ } else {
456
+ // Si no, usar node con el archivo principal
457
+ startCmd = ['node', mainFile];
458
+ }
459
+
460
+ dockerfileContent = `FROM node:20-alpine
461
+
462
+ WORKDIR /app
463
+
464
+ ENV NODE_ENV=production
465
+ ENV PORT=3000
466
+
467
+ # Copiar package files primero para aprovechar cache de Docker
468
+ COPY package*.json ./
469
+
470
+ # Instalar solo dependencias de producción
471
+ RUN npm ci --only=production && npm cache clean --force
472
+
473
+ # Copiar código fuente
474
+ COPY . .
475
+
476
+ # Exponemos el puerto
477
+ EXPOSE 3000
478
+
479
+ # Comando de inicio
480
+ CMD ${JSON.stringify(startCmd)}
481
+ `;
482
+ }
483
+
484
+ // Paso 3: Crear Dockerfile
485
+ const dockerfileSpinner = ora('Creating Dockerfile...').start();
486
+ const dockerfilePath = path.join(resolvedDestFolder, 'Dockerfile');
192
487
  fs.writeFileSync(dockerfilePath, dockerfileContent);
488
+
489
+ dockerfileSpinner.succeed('Dockerfile created');
490
+
491
+ // Mostrar contenido del Dockerfile
492
+ if (projectType === 'nextjs' && nextPublicEnvVars.length > 0) {
493
+ console.log(chalk.gray('\n📄 Dockerfile content:'));
494
+ console.log(chalk.gray('─'.repeat(60)));
495
+ console.log(chalk.white(dockerfileContent));
496
+ console.log(chalk.gray('─'.repeat(60)));
497
+ console.log(chalk.gray(`\n NEXT_PUBLIC_* variables: ${chalk.cyan(nextPublicEnvVars.length)}`));
498
+ nextPublicEnvVars.forEach(env => {
499
+ const [key] = env.split('=');
500
+ console.log(chalk.gray(` - ${chalk.cyan(key)}`));
501
+ });
502
+ } else {
503
+ console.log(chalk.gray(`\n📄 Dockerfile created for ${projectType} application`));
504
+ }
193
505
 
194
506
  // Paso 4: Verificar/crear builder multi-plataforma
195
507
  const builderSpinner = ora('Setting up multi-platform builder...').start();
196
508
  try {
197
- const builders = execSync('docker buildx ls', { encoding: 'utf-8' });
509
+ // Listar builders disponibles, ignorando errores de builders con problemas
510
+ let buildersOutput = '';
511
+ try {
512
+ // Redirigir stderr a /dev/null para ignorar errores de builders problemáticos
513
+ buildersOutput = execSync('docker buildx ls 2>/dev/null', {
514
+ encoding: 'utf-8',
515
+ stdio: 'pipe',
516
+ shell: '/bin/sh',
517
+ });
518
+ } catch (error) {
519
+ // Si hay errores al listar builders (por ejemplo, builder "cc" con problemas SSH),
520
+ // intentar continuar de todas formas
521
+ console.log(chalk.yellow('⚠️ Warning: Some builders have connection issues, continuing...'));
522
+ }
523
+
198
524
  const builderName = 'multiarch-builder';
199
- if (!builders.includes(builderName)) {
200
- execSync(`docker buildx create --name ${builderName} --use --bootstrap`, { stdio: 'pipe' });
525
+ if (!buildersOutput.includes(builderName)) {
526
+ builderSpinner.text = 'Creating multi-platform builder...';
527
+ execSync(`docker buildx create --name ${builderName} --use --bootstrap`, {
528
+ stdio: 'pipe',
529
+ // No heredar stderr para evitar errores de otros builders
530
+ });
201
531
  } else {
202
- execSync(`docker buildx use ${builderName}`, { stdio: 'pipe' });
203
- }
532
+ builderSpinner.text = 'Using existing multi-platform builder...';
533
+ try {
534
+ execSync(`docker buildx use ${builderName}`, { stdio: 'pipe' });
535
+ } catch (error) {
536
+ // Si falla, intentar crearlo de nuevo
537
+ builderSpinner.text = 'Recreating multi-platform builder...';
538
+ try {
539
+ execSync(`docker buildx rm ${builderName}`, { stdio: 'pipe' });
540
+ } catch {
541
+ // Ignorar si no existe
542
+ }
543
+ execSync(`docker buildx create --name ${builderName} --use --bootstrap`, { stdio: 'pipe' });
544
+ }
545
+ }
204
546
  builderSpinner.succeed('Builder ready');
205
- } catch (error) {
547
+ } catch (error: any) {
206
548
  builderSpinner.fail('Failed to setup builder');
207
549
  console.error(chalk.red('Error setting up Docker buildx builder'));
550
+ console.error(chalk.yellow('💡 Tip: If you have problematic builders configured, you can remove them with:'));
551
+ console.error(chalk.cyan(' docker buildx rm <builder-name>'));
552
+ console.error(chalk.yellow(' Or inspect them with: docker buildx inspect <builder-name>'));
208
553
  process.exit(1);
209
554
  }
210
555
 
@@ -243,6 +588,14 @@ CMD ["node", "server.js"]
243
588
  --progress=plain \
244
589
  .`;
245
590
 
591
+ console.log(chalk.gray('\n🔨 Build command:'));
592
+ console.log(chalk.gray('─'.repeat(60)));
593
+ console.log(chalk.cyan(buildCommand));
594
+ console.log(chalk.gray('─'.repeat(60)));
595
+ console.log(chalk.gray(`\n Working directory: ${chalk.cyan(resolvedDestFolder)}`));
596
+ console.log(chalk.gray(` Platforms: ${chalk.cyan('linux/amd64, linux/arm64')}`));
597
+ console.log(chalk.gray(` Push to registry: ${shouldPush ? chalk.green('Yes') : chalk.yellow('No')}\n`));
598
+
246
599
  execSync(buildCommand, {
247
600
  cwd: resolvedDestFolder,
248
601
  stdio: 'inherit'
@@ -250,8 +603,9 @@ CMD ["node", "server.js"]
250
603
 
251
604
  buildDockerSpinner.succeed('Docker image built successfully');
252
605
 
253
- console.log(chalk.green('\n✅ Deployment completed successfully!'));
254
- console.log(chalk.gray('Image details:'));
606
+ console.log(chalk.green('\n✅ Image build and push completed successfully!'));
607
+ console.log(chalk.gray('📦 Image details:'));
608
+ console.log(chalk.gray('─'.repeat(60)));
255
609
  console.log(chalk.white(` Platforms: ${chalk.cyan('linux/amd64, linux/arm64')}`));
256
610
  console.log(chalk.white(` Version: ${chalk.cyan(version)}`));
257
611
  console.log(chalk.white(` Tags:`));
@@ -260,6 +614,11 @@ CMD ["node", "server.js"]
260
614
  if (shouldPush) {
261
615
  console.log(chalk.white(` Registry: ${chalk.cyan('Docker Hub')}`));
262
616
  console.log(chalk.white(` URL: ${chalk.cyan(`https://hub.docker.com/r/${imageBase}`)}`));
617
+ console.log(chalk.gray('─'.repeat(60)));
618
+ console.log(chalk.green(`\n✅ Image pushed to Docker Hub successfully!`));
619
+ } else {
620
+ console.log(chalk.gray('─'.repeat(60)));
621
+ console.log(chalk.yellow(`\n⚠️ Image built locally (not pushed to registry)`));
263
622
  }
264
623
  } catch (error) {
265
624
  buildDockerSpinner.fail('Docker build failed');
@@ -272,8 +631,13 @@ CMD ["node", "server.js"]
272
631
 
273
632
  // Paso 6: Desplegar en servidor remoto si se solicita
274
633
  if (options.deploy) {
634
+ // Para despliegue, usar la versión especificada o la del package.json
635
+ const deployImageName = options.imageVersion
636
+ ? `${imageBase}:${options.imageVersion}`
637
+ : (shouldPush ? imageName : imageLatest);
638
+
275
639
  await deployToRemoteServer({
276
- imageName: shouldPush ? imageName : imageLatest,
640
+ imageName: deployImageName,
277
641
  serviceName: options.serviceName || projectName,
278
642
  domainBase: options.domainBase,
279
643
  port: options.port,
@@ -288,6 +652,115 @@ CMD ["node", "server.js"]
288
652
  }
289
653
  });
290
654
 
655
+ // Función para leer certificados Docker desde token.json
656
+ function loadDockerCertificatesFromToken(): { caPem: string; certPem: string; keyPem: string; certPath: string } {
657
+ const tokenFilePath = path.join(os.homedir(), '.codecrypto', 'token.json');
658
+
659
+ if (!fs.existsSync(tokenFilePath)) {
660
+ throw new Error(`Token file not found at ${tokenFilePath}. Please run 'codecrypto auth' first.`);
661
+ }
662
+
663
+ let tokenData: any;
664
+ try {
665
+ tokenData = JSON.parse(fs.readFileSync(tokenFilePath, 'utf-8'));
666
+ } catch (error: any) {
667
+ throw new Error(`Failed to read token file: ${error.message}`);
668
+ }
669
+
670
+ if (!tokenData.adminGlobals || !Array.isArray(tokenData.adminGlobals)) {
671
+ throw new Error('adminGlobals not found in token.json. Please run "codecrypto auth --force" to refresh your token.');
672
+ }
673
+
674
+ // Buscar los certificados Docker en el array adminGlobals
675
+ // Las keys que buscamos son:
676
+ // - docker-client/ca-pem
677
+ // - docker-client/cert.pem
678
+ // - docker-client/key.pem
679
+ const certKeys = {
680
+ ca: 'docker-client/ca-pem',
681
+ cert: 'docker-client/cert.pem',
682
+ key: 'docker-client/key.pem'
683
+ };
684
+
685
+ const certificates: { ca?: string; cert?: string; key?: string } = {};
686
+
687
+ // Lista de keys encontradas para debugging
688
+ const foundKeys: string[] = [];
689
+
690
+ // Iterar sobre adminGlobals para encontrar los certificados
691
+ for (const global of tokenData.adminGlobals) {
692
+ if (global && global.key) {
693
+ foundKeys.push(global.key);
694
+ // Buscar cada certificado por su key exacta
695
+ if (global.key === certKeys.ca) {
696
+ certificates.ca = global.value;
697
+ } else if (global.key === certKeys.cert) {
698
+ certificates.cert = global.value;
699
+ } else if (global.key === certKeys.key) {
700
+ certificates.key = global.value;
701
+ }
702
+ }
703
+ }
704
+
705
+ // Verificar que todos los certificados estén presentes
706
+ if (!certificates.ca) {
707
+ const availableKeys = foundKeys.filter(k => k.includes('docker-client')).join(', ') || 'none';
708
+ throw new Error(
709
+ `Certificate not found: ${certKeys.ca} in adminGlobals.\n` +
710
+ ` Available docker-client keys: ${availableKeys || 'none'}\n` +
711
+ ` Total adminGlobals entries: ${tokenData.adminGlobals.length}\n` +
712
+ ` Please run "codecrypto auth --force" to refresh your token.`
713
+ );
714
+ }
715
+ if (!certificates.cert) {
716
+ const availableKeys = foundKeys.filter(k => k.includes('docker-client')).join(', ') || 'none';
717
+ throw new Error(
718
+ `Certificate not found: ${certKeys.cert} in adminGlobals.\n` +
719
+ ` Available docker-client keys: ${availableKeys || 'none'}\n` +
720
+ ` Total adminGlobals entries: ${tokenData.adminGlobals.length}\n` +
721
+ ` Please run "codecrypto auth --force" to refresh your token.`
722
+ );
723
+ }
724
+ if (!certificates.key) {
725
+ const availableKeys = foundKeys.filter(k => k.includes('docker-client')).join(', ') || 'none';
726
+ throw new Error(
727
+ `Certificate not found: ${certKeys.key} in adminGlobals.\n` +
728
+ ` Available docker-client keys: ${availableKeys || 'none'}\n` +
729
+ ` Total adminGlobals entries: ${tokenData.adminGlobals.length}\n` +
730
+ ` Please run "codecrypto auth --force" to refresh your token.`
731
+ );
732
+ }
733
+
734
+ // Crear directorio para certificados si no existe
735
+ const dockerCertPath = path.join(os.homedir(), '.codecrypto', 'docker-client');
736
+ if (!fs.existsSync(dockerCertPath)) {
737
+ fs.mkdirSync(dockerCertPath, { recursive: true });
738
+ }
739
+
740
+ // Escribir certificados a archivos
741
+ const caPemPath = path.join(dockerCertPath, 'ca.pem');
742
+ const certPemPath = path.join(dockerCertPath, 'cert.pem');
743
+ const keyPemPath = path.join(dockerCertPath, 'key.pem');
744
+
745
+ fs.writeFileSync(caPemPath, certificates.ca, 'utf-8');
746
+ fs.writeFileSync(certPemPath, certificates.cert, 'utf-8');
747
+ fs.writeFileSync(keyPemPath, certificates.key, 'utf-8');
748
+
749
+ // Establecer permisos correctos para la clave privada (solo lectura para el propietario)
750
+ try {
751
+ fs.chmodSync(keyPemPath, 0o600);
752
+ } catch (error) {
753
+ // Ignorar errores de chmod en Windows
754
+ }
755
+
756
+ return {
757
+ caPem: certificates.ca,
758
+ certPem: certificates.cert,
759
+ keyPem: certificates.key,
760
+ certPath: dockerCertPath
761
+ };
762
+ }
763
+
291
764
  // Función para desplegar en servidor remoto
292
765
  async function deployToRemoteServer(config: {
293
766
  imageName: string;
@@ -300,13 +773,19 @@ async function deployToRemoteServer(config: {
300
773
  const deploySpinner = ora('Configuring remote Docker connection...').start();
301
774
 
302
775
  try {
303
- // Configurar variables de entorno para Docker remoto
304
- const dockerCertPath = path.join(os.homedir(), '.codecrypto', 'docker-client');
305
-
306
- if (!fs.existsSync(dockerCertPath)) {
307
- deploySpinner.fail('Docker certificates not found');
308
- console.error(chalk.red(`❌ Error: Docker certificates not found at ${dockerCertPath}`));
309
- console.error(chalk.yellow(' Make sure you have the certificates in ~/.codecrypto/docker-client'));
776
+ // Cargar certificados desde token.json
777
+ let dockerCertPath: string;
778
+ try {
779
+ const certs = loadDockerCertificatesFromToken();
780
+ dockerCertPath = certs.certPath;
781
+ deploySpinner.succeed('Docker certificates loaded from token.json');
782
+ } catch (error: any) {
783
+ deploySpinner.fail('Failed to load Docker certificates');
784
+ console.error(chalk.red(`❌ Error: ${error.message}`));
785
+ console.error(chalk.yellow('\n💡 To fix this issue:'));
786
+ console.error(chalk.yellow(' 1. Run: codecrypto auth --force'));
787
+ console.error(chalk.yellow(' 2. This will refresh your token with the latest adminGlobals'));
788
+ console.error(chalk.yellow(' 3. Then try the deploy command again\n'));
310
789
  process.exit(1);
311
790
  }
312
791
 
@@ -321,44 +800,79 @@ async function deployToRemoteServer(config: {
321
800
  }
322
801
  }
323
802
 
324
- // Configurar variables de entorno para Docker
325
- const dockerEnv: Record<string, string> = {
326
- ...process.env,
327
- DOCKER_HOST: 'https://server.codecrypto.academy:2376',
328
- DOCKER_TLS_VERIFY: '1',
329
- DOCKER_CERT_PATH: dockerCertPath,
330
- };
331
-
332
- deploySpinner.succeed('Docker connection configured');
803
+ // Construir prefijo de comando Docker con parámetros TLS
804
+ const dockerHost = 'tcp://server.codecrypto.academy:2376';
805
+ const dockerTlsPrefix = `docker -H ${dockerHost} \\
806
+ --tlsverify \\
807
+ --tlscacert="${path.join(dockerCertPath, 'ca.pem')}" \\
808
+ --tlscert="${path.join(dockerCertPath, 'cert.pem')}" \\
809
+ --tlskey="${path.join(dockerCertPath, 'key.pem')}"`;
810
+
811
+ console.log(chalk.gray('\n🔌 Remote Docker configuration:'));
812
+ console.log(chalk.gray('─'.repeat(60)));
813
+ console.log(chalk.white(` Docker Host: ${chalk.cyan(dockerHost)}`));
814
+ console.log(chalk.white(` TLS Verify: ${chalk.cyan('enabled')}`));
815
+ console.log(chalk.white(` Certificates Source: ${chalk.cyan('token.json (adminGlobals)')}`));
816
+ console.log(chalk.white(` Certificates Path: ${chalk.cyan(dockerCertPath)}`));
817
+ console.log(chalk.gray(' Certificates loaded:'));
818
+ requiredCerts.forEach(cert => {
819
+ const certPath = path.join(dockerCertPath, cert);
820
+ const exists = fs.existsSync(certPath);
821
+ console.log(chalk.gray(` ${exists ? '✓' : '✗'} ${chalk.cyan(cert)}`));
822
+ });
823
+ console.log(chalk.gray('─'.repeat(60)));
824
+ console.log(chalk.yellow('\n💡 All docker commands will use TLS parameters directly\n'));
333
825
 
334
826
  // Construir nombre completo del dominio
335
827
  const fullDomain = `${config.serviceName}.${config.domainBase}`;
336
828
  const serviceName = config.serviceName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
337
829
 
338
830
  // Detener y eliminar contenedor existente si existe
339
- const stopSpinner = ora('Checking for existing container...').start();
831
+ const stopSpinner = ora('Checking and removing existing container...').start();
340
832
  try {
341
- execSync(`docker ps -a --filter name=^${fullDomain}$ --format "{{.Names}}"`, {
342
- env: dockerEnv,
833
+ // Verificar si el contenedor existe
834
+ const checkCmd = `${dockerTlsPrefix} ps -a --filter name=^${fullDomain}$ --format "{{.Names}}"`;
835
+ const existingContainer = execSync(checkCmd, {
343
836
  stdio: 'pipe',
344
837
  encoding: 'utf-8',
345
- });
838
+ shell: '/bin/sh',
839
+ }).trim();
346
840
 
347
- // Si existe, detenerlo y eliminarlo
348
- try {
349
- execSync(`docker stop ${fullDomain}`, { env: dockerEnv, stdio: 'pipe' });
350
- } catch {
351
- // Container might not be running
841
+ if (existingContainer === fullDomain) {
842
+ // Contenedor existe, detenerlo primero (si está corriendo)
843
+ try {
844
+ const stopCmd = `${dockerTlsPrefix} stop ${fullDomain}`;
845
+ execSync(stopCmd, { stdio: 'pipe', shell: '/bin/sh' });
846
+ console.log(chalk.gray(` ✓ Container ${fullDomain} stopped`));
847
+ } catch (error: any) {
848
+ // Container might not be running, that's okay
849
+ console.log(chalk.gray(` ℹ Container ${fullDomain} was not running`));
850
+ }
851
+
852
+ // Eliminar el contenedor
853
+ try {
854
+ const rmCmd = `${dockerTlsPrefix} rm -f ${fullDomain}`;
855
+ execSync(rmCmd, { stdio: 'pipe', shell: '/bin/sh' });
856
+ stopSpinner.succeed(`Existing container ${fullDomain} removed`);
857
+ } catch (error: any) {
858
+ stopSpinner.fail(`Failed to remove container ${fullDomain}`);
859
+ console.error(chalk.red(` Error: ${error.message}`));
860
+ process.exit(1);
861
+ }
862
+ } else {
863
+ stopSpinner.succeed('No existing container found');
352
864
  }
353
-
865
+ } catch (error: any) {
866
+ // Si el comando falla, puede ser que el contenedor no exista
867
+ // Intentar eliminarlo de todas formas con -f para forzar
354
868
  try {
355
- execSync(`docker rm ${fullDomain}`, { env: dockerEnv, stdio: 'pipe' });
356
- stopSpinner.succeed('Existing container removed');
869
+ const forceRmCmd = `${dockerTlsPrefix} rm -f ${fullDomain}`;
870
+ execSync(forceRmCmd, { stdio: 'pipe', shell: '/bin/sh' });
871
+ stopSpinner.succeed('Existing container removed (forced)');
357
872
  } catch {
358
- stopSpinner.warn('No existing container found');
873
+ // Si falla, asumir que no existe y continuar
874
+ stopSpinner.succeed('No existing container found');
359
875
  }
360
- } catch (error) {
361
- stopSpinner.warn('Could not check for existing container');
362
876
  }
363
877
 
364
878
  // Preparar opciones de entorno
@@ -376,12 +890,12 @@ async function deployToRemoteServer(config: {
376
890
  });
377
891
  }
378
892
 
379
- // Construir comando docker run
380
- const dockerRunCmd = `docker run -d \\
893
+ // Construir comando docker run con parámetros TLS
894
+ const dockerRunCmd = `${dockerTlsPrefix} run -d \\
381
895
  --name ${fullDomain} \\
382
896
  --network academy-network \\
383
897
  --restart unless-stopped \\
384
- ${envOpts.join(' \\\n ')} \\
898
+ ${envOpts.length > 0 ? envOpts.join(' \\\n ') + ' \\' : ''}
385
899
  -l traefik.enable=true \\
386
900
  -l "traefik.http.routers.${serviceName}-router.rule=Host(\\\`${fullDomain}\\\`)" \\
387
901
  -l traefik.http.routers.${serviceName}-router.entrypoints=websecure \\
@@ -389,11 +903,30 @@ async function deployToRemoteServer(config: {
389
903
  -l traefik.http.services.${serviceName}-service.loadbalancer.server.port=${config.port} \\
390
904
  ${config.imageName}`;
391
905
 
906
+ console.log(chalk.gray('\n🚀 Deployment command (executing on remote Docker):'));
907
+ console.log(chalk.gray('─'.repeat(60)));
908
+ console.log(chalk.cyan(dockerRunCmd));
909
+ console.log(chalk.gray('─'.repeat(60)));
910
+ console.log(chalk.gray(`\n Remote Docker: ${chalk.cyan(dockerHost)}`));
911
+ console.log(chalk.gray(` TLS Certificates: ${chalk.cyan(dockerCertPath)}`));
912
+ console.log(chalk.gray(` Service name: ${chalk.cyan(config.serviceName)}`));
913
+ console.log(chalk.gray(` Full domain: ${chalk.cyan(fullDomain)}`));
914
+ console.log(chalk.gray(` Image: ${chalk.cyan(config.imageName)}`));
915
+ console.log(chalk.gray(` Port: ${chalk.cyan(config.port)}`));
916
+ console.log(chalk.gray(` Environment variables: ${chalk.cyan(config.envVars.length)}`));
917
+ if (config.envVars.length > 0) {
918
+ config.envVars.forEach(env => {
919
+ const [key] = env.split('=');
920
+ console.log(chalk.gray(` - ${chalk.cyan(key)}`));
921
+ });
922
+ }
923
+ console.log(chalk.gray('─'.repeat(60)));
924
+
392
925
  const runSpinner = ora('Deploying container to remote server...').start();
393
926
 
394
927
  try {
928
+ // Ejecutar comando docker con parámetros TLS directamente
395
929
  execSync(dockerRunCmd, {
396
- env: dockerEnv,
397
930
  stdio: 'inherit',
398
931
  shell: '/bin/sh',
399
932
  });
@@ -401,12 +934,17 @@ async function deployToRemoteServer(config: {
401
934
  runSpinner.succeed('Container deployed successfully');
402
935
 
403
936
  console.log(chalk.green('\n✅ Remote deployment completed successfully!'));
404
- console.log(chalk.gray('Deployment details:'));
937
+ console.log(chalk.gray('📋 Deployment details:'));
938
+ console.log(chalk.gray('─'.repeat(60)));
405
939
  console.log(chalk.white(` Service: ${chalk.cyan(config.serviceName)}`));
406
940
  console.log(chalk.white(` Domain: ${chalk.cyan(fullDomain)}`));
407
941
  console.log(chalk.white(` URL: ${chalk.cyan(`https://${fullDomain}`)}`));
408
942
  console.log(chalk.white(` Image: ${chalk.cyan(config.imageName)}`));
409
943
  console.log(chalk.white(` Port: ${chalk.cyan(config.port)}`));
944
+ console.log(chalk.white(` Network: ${chalk.cyan('academy-network')}`));
945
+ console.log(chalk.white(` Restart policy: ${chalk.cyan('unless-stopped')}`));
946
+ console.log(chalk.gray('─'.repeat(60)));
947
+ console.log(chalk.green(`\n🌐 Your application is now available at: ${chalk.cyan.underline(`https://${fullDomain}`)}`));
410
948
  } catch (error) {
411
949
  runSpinner.fail('Failed to deploy container');
412
950
  console.error(chalk.red('\n❌ Error deploying container to remote server'));