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.
- 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 +644 -136
- 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/package.json +1 -1
- package/src/commands/auth.ts +71 -8
- package/src/commands/deploy-sc.ts +182 -0
- package/src/commands/deploy.ts +688 -150
- package/src/commands/doctor.ts +498 -0
- package/src/index.ts +2 -0
- package/token.json +69 -0
- package/docker-build/Dockerfile +0 -14
- package/docker-build/standalone/.next/BUILD_ID +0 -1
- package/docker-build/standalone/.next/app-path-routes-manifest.json +0 -13
- package/docker-build/standalone/.next/build-manifest.json +0 -20
- package/docker-build/standalone/.next/package.json +0 -1
- package/docker-build/standalone/.next/prerender-manifest.json +0 -186
- package/docker-build/standalone/.next/required-server-files.json +0 -164
- package/docker-build/standalone/.next/routes-manifest.json +0 -110
- package/docker-build/standalone/.next/server/app/_global-error/page/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/_global-error/page/build-manifest.json +0 -17
- package/docker-build/standalone/.next/server/app/_global-error/page/next-font-manifest.json +0 -6
- package/docker-build/standalone/.next/server/app/_global-error/page/react-loadable-manifest.json +0 -1
- package/docker-build/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +0 -4
- package/docker-build/standalone/.next/server/app/_global-error/page.js +0 -11
- package/docker-build/standalone/.next/server/app/_global-error/page.js.map +0 -5
- package/docker-build/standalone/.next/server/app/_global-error/page.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +0 -2
- package/docker-build/standalone/.next/server/app/_global-error.html +0 -2
- package/docker-build/standalone/.next/server/app/_global-error.meta +0 -15
- package/docker-build/standalone/.next/server/app/_global-error.rsc +0 -13
- package/docker-build/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +0 -5
- package/docker-build/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +0 -13
- package/docker-build/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +0 -6
- package/docker-build/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +0 -4
- package/docker-build/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +0 -1
- package/docker-build/standalone/.next/server/app/_not-found/page/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/_not-found/page/build-manifest.json +0 -17
- package/docker-build/standalone/.next/server/app/_not-found/page/next-font-manifest.json +0 -11
- package/docker-build/standalone/.next/server/app/_not-found/page/react-loadable-manifest.json +0 -1
- package/docker-build/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +0 -4
- package/docker-build/standalone/.next/server/app/_not-found/page.js +0 -14
- package/docker-build/standalone/.next/server/app/_not-found/page.js.map +0 -5
- package/docker-build/standalone/.next/server/app/_not-found/page.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +0 -2
- package/docker-build/standalone/.next/server/app/_not-found.html +0 -1
- package/docker-build/standalone/.next/server/app/_not-found.meta +0 -16
- package/docker-build/standalone/.next/server/app/_not-found.rsc +0 -14
- package/docker-build/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +0 -14
- package/docker-build/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +0 -6
- package/docker-build/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +0 -5
- package/docker-build/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +0 -5
- package/docker-build/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +0 -4
- package/docker-build/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +0 -2
- package/docker-build/standalone/.next/server/app/api/deploy/route/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/api/deploy/route/build-manifest.json +0 -11
- package/docker-build/standalone/.next/server/app/api/deploy/route/server-reference-manifest.json +0 -4
- package/docker-build/standalone/.next/server/app/api/deploy/route.js +0 -7
- package/docker-build/standalone/.next/server/app/api/deploy/route.js.map +0 -5
- package/docker-build/standalone/.next/server/app/api/deploy/route.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/api/deploy/route_client-reference-manifest.js +0 -2
- package/docker-build/standalone/.next/server/app/api/deploy-image/route/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/api/deploy-image/route/build-manifest.json +0 -11
- package/docker-build/standalone/.next/server/app/api/deploy-image/route/server-reference-manifest.json +0 -4
- package/docker-build/standalone/.next/server/app/api/deploy-image/route.js +0 -6
- package/docker-build/standalone/.next/server/app/api/deploy-image/route.js.map +0 -5
- package/docker-build/standalone/.next/server/app/api/deploy-image/route.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/api/deploy-image/route_client-reference-manifest.js +0 -2
- package/docker-build/standalone/.next/server/app/api/docker-images/route/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/api/docker-images/route/build-manifest.json +0 -11
- package/docker-build/standalone/.next/server/app/api/docker-images/route/server-reference-manifest.json +0 -4
- package/docker-build/standalone/.next/server/app/api/docker-images/route.js +0 -6
- package/docker-build/standalone/.next/server/app/api/docker-images/route.js.map +0 -5
- package/docker-build/standalone/.next/server/app/api/docker-images/route.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/api/docker-images/route_client-reference-manifest.js +0 -2
- package/docker-build/standalone/.next/server/app/api/faucet/route/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/api/faucet/route/build-manifest.json +0 -11
- package/docker-build/standalone/.next/server/app/api/faucet/route/server-reference-manifest.json +0 -4
- package/docker-build/standalone/.next/server/app/api/faucet/route.js +0 -9
- package/docker-build/standalone/.next/server/app/api/faucet/route.js.map +0 -5
- package/docker-build/standalone/.next/server/app/api/faucet/route.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/api/faucet/route_client-reference-manifest.js +0 -2
- package/docker-build/standalone/.next/server/app/deploy/page/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/deploy/page/build-manifest.json +0 -17
- package/docker-build/standalone/.next/server/app/deploy/page/next-font-manifest.json +0 -11
- package/docker-build/standalone/.next/server/app/deploy/page/react-loadable-manifest.json +0 -1
- package/docker-build/standalone/.next/server/app/deploy/page/server-reference-manifest.json +0 -4
- package/docker-build/standalone/.next/server/app/deploy/page.js +0 -16
- package/docker-build/standalone/.next/server/app/deploy/page.js.map +0 -5
- package/docker-build/standalone/.next/server/app/deploy/page.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/deploy/page_client-reference-manifest.js +0 -2
- package/docker-build/standalone/.next/server/app/deploy.html +0 -1
- package/docker-build/standalone/.next/server/app/deploy.meta +0 -15
- package/docker-build/standalone/.next/server/app/deploy.rsc +0 -20
- package/docker-build/standalone/.next/server/app/deploy.segments/_full.segment.rsc +0 -20
- package/docker-build/standalone/.next/server/app/deploy.segments/_head.segment.rsc +0 -6
- package/docker-build/standalone/.next/server/app/deploy.segments/_index.segment.rsc +0 -5
- package/docker-build/standalone/.next/server/app/deploy.segments/_tree.segment.rsc +0 -4
- package/docker-build/standalone/.next/server/app/deploy.segments/deploy/__PAGE__.segment.rsc +0 -9
- package/docker-build/standalone/.next/server/app/deploy.segments/deploy.segment.rsc +0 -4
- package/docker-build/standalone/.next/server/app/faucet/page/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/faucet/page/build-manifest.json +0 -17
- package/docker-build/standalone/.next/server/app/faucet/page/next-font-manifest.json +0 -11
- package/docker-build/standalone/.next/server/app/faucet/page/react-loadable-manifest.json +0 -1
- package/docker-build/standalone/.next/server/app/faucet/page/server-reference-manifest.json +0 -4
- package/docker-build/standalone/.next/server/app/faucet/page.js +0 -16
- package/docker-build/standalone/.next/server/app/faucet/page.js.map +0 -5
- package/docker-build/standalone/.next/server/app/faucet/page.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/faucet/page_client-reference-manifest.js +0 -2
- package/docker-build/standalone/.next/server/app/faucet.html +0 -1
- package/docker-build/standalone/.next/server/app/faucet.meta +0 -15
- package/docker-build/standalone/.next/server/app/faucet.rsc +0 -20
- package/docker-build/standalone/.next/server/app/faucet.segments/_full.segment.rsc +0 -20
- package/docker-build/standalone/.next/server/app/faucet.segments/_head.segment.rsc +0 -6
- package/docker-build/standalone/.next/server/app/faucet.segments/_index.segment.rsc +0 -5
- package/docker-build/standalone/.next/server/app/faucet.segments/_tree.segment.rsc +0 -4
- package/docker-build/standalone/.next/server/app/faucet.segments/faucet/__PAGE__.segment.rsc +0 -9
- package/docker-build/standalone/.next/server/app/faucet.segments/faucet.segment.rsc +0 -4
- package/docker-build/standalone/.next/server/app/favicon.ico/route/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/favicon.ico/route/build-manifest.json +0 -11
- package/docker-build/standalone/.next/server/app/favicon.ico/route.js +0 -7
- package/docker-build/standalone/.next/server/app/favicon.ico/route.js.map +0 -5
- package/docker-build/standalone/.next/server/app/favicon.ico/route.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/favicon.ico.body +0 -0
- package/docker-build/standalone/.next/server/app/favicon.ico.meta +0 -1
- package/docker-build/standalone/.next/server/app/images/page/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/images/page/build-manifest.json +0 -17
- package/docker-build/standalone/.next/server/app/images/page/next-font-manifest.json +0 -11
- package/docker-build/standalone/.next/server/app/images/page/react-loadable-manifest.json +0 -1
- package/docker-build/standalone/.next/server/app/images/page/server-reference-manifest.json +0 -4
- package/docker-build/standalone/.next/server/app/images/page.js +0 -16
- package/docker-build/standalone/.next/server/app/images/page.js.map +0 -5
- package/docker-build/standalone/.next/server/app/images/page.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/images/page_client-reference-manifest.js +0 -2
- package/docker-build/standalone/.next/server/app/images.html +0 -1
- package/docker-build/standalone/.next/server/app/images.meta +0 -15
- package/docker-build/standalone/.next/server/app/images.rsc +0 -20
- package/docker-build/standalone/.next/server/app/images.segments/_full.segment.rsc +0 -20
- package/docker-build/standalone/.next/server/app/images.segments/_head.segment.rsc +0 -6
- package/docker-build/standalone/.next/server/app/images.segments/_index.segment.rsc +0 -5
- package/docker-build/standalone/.next/server/app/images.segments/_tree.segment.rsc +0 -4
- package/docker-build/standalone/.next/server/app/images.segments/images/__PAGE__.segment.rsc +0 -9
- package/docker-build/standalone/.next/server/app/images.segments/images.segment.rsc +0 -4
- package/docker-build/standalone/.next/server/app/index.html +0 -1
- package/docker-build/standalone/.next/server/app/index.meta +0 -14
- package/docker-build/standalone/.next/server/app/index.rsc +0 -25
- package/docker-build/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +0 -8
- package/docker-build/standalone/.next/server/app/index.segments/_full.segment.rsc +0 -25
- package/docker-build/standalone/.next/server/app/index.segments/_head.segment.rsc +0 -6
- package/docker-build/standalone/.next/server/app/index.segments/_index.segment.rsc +0 -5
- package/docker-build/standalone/.next/server/app/index.segments/_tree.segment.rsc +0 -4
- package/docker-build/standalone/.next/server/app/page/app-paths-manifest.json +0 -3
- package/docker-build/standalone/.next/server/app/page/build-manifest.json +0 -17
- package/docker-build/standalone/.next/server/app/page/next-font-manifest.json +0 -11
- package/docker-build/standalone/.next/server/app/page/react-loadable-manifest.json +0 -1
- package/docker-build/standalone/.next/server/app/page/server-reference-manifest.json +0 -4
- package/docker-build/standalone/.next/server/app/page.js +0 -16
- package/docker-build/standalone/.next/server/app/page.js.map +0 -5
- package/docker-build/standalone/.next/server/app/page.js.nft.json +0 -1
- package/docker-build/standalone/.next/server/app/page_client-reference-manifest.js +0 -2
- package/docker-build/standalone/.next/server/app-paths-manifest.json +0 -13
- package/docker-build/standalone/.next/server/chunks/10072_infra_server-cc__next-internal_server_app_api_deploy_route_actions_6cdc6432.js +0 -3
- package/docker-build/standalone/.next/server/chunks/10072_infra_server-cc__next-internal_server_app_api_faucet_route_actions_f54ec975.js +0 -3
- package/docker-build/standalone/.next/server/chunks/10072_infra_server-cc__next-internal_server_app_favicon_ico_route_actions_d73715d1.js +0 -3
- package/docker-build/standalone/.next/server/chunks/66d90_server-cc__next-internal_server_app_api_deploy-image_route_actions_b340a7f4.js +0 -3
- package/docker-build/standalone/.next/server/chunks/66d90_server-cc__next-internal_server_app_api_docker-images_route_actions_4adcb030.js +0 -3
- package/docker-build/standalone/.next/server/chunks/6f6aa_4d460f49._.js +0 -30
- package/docker-build/standalone/.next/server/chunks/6f6aa_@noble_curves_esm_secp256k1_c7f9b58b.js +0 -3
- package/docker-build/standalone/.next/server/chunks/6f6aa_next_dist_esm_build_templates_app-route_1a9ee783.js +0 -6
- package/docker-build/standalone/.next/server/chunks/6f6aa_next_dist_esm_build_templates_app-route_8d132e6a.js +0 -3
- package/docker-build/standalone/.next/server/chunks/6f6aa_viem__esm_utils_ccip_bb7bf310.js +0 -3
- package/docker-build/standalone/.next/server/chunks/[externals]_next_dist_b01ab6e1._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__0928cca7._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__0c6b3bd9._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__1846bb23._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__8f8a2ff9._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__90ea784b._.js +0 -21
- package/docker-build/standalone/.next/server/chunks/[root-of-the-server]__f6379956._.js +0 -39
- package/docker-build/standalone/.next/server/chunks/[turbopack]_runtime.js +0 -795
- package/docker-build/standalone/.next/server/chunks/ssr/10072_infra_server-cc__next-internal_server_app__global-error_page_actions_bdbde336.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/10072_infra_server-cc__next-internal_server_app__not-found_page_actions_41269af3.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/10072_infra_server-cc__next-internal_server_app_deploy_page_actions_3988cfb8.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/10072_infra_server-cc__next-internal_server_app_faucet_page_actions_e5e8dd8a.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/10072_infra_server-cc__next-internal_server_app_images_page_actions_bcdfd86b.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_293382c4._.js +0 -4
- package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_55723634._.js +0 -4
- package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_821445df._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_8545ebc7._.js +0 -4
- package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_acad38a1._.js +0 -6
- package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_app_b373a582._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/2025_cc_CODECRYPTO_infra_server-cc_d03dcb7a._.js +0 -4
- package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_7c51ed4c._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_05cd73d5._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_3e60adb5._.js +0 -6
- package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_5002976b._.js +0 -4
- package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_client_components_a432b2d3._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_client_components_builtin_forbidden_b4e63d3a.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_client_components_builtin_global-error_edcabd66.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_client_components_builtin_unauthorized_f08488ad.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/6f6aa_next_dist_esm_build_templates_app-page_c7a8656a.js +0 -4
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e0d983d._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__0f25bf3b._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__10dae68a._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ebd727b._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__30996048._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__587c95dd._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__5ecc39a2._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__6382fff8._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__8ed1042a._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__91644c56._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__a2833bcd._.js +0 -10
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__acf31a1c._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__ae009f46._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__daca67ae._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__f2372d3f._.js +0 -4
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__f2ed834a._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[root-of-the-server]__ff0dddf3._.js +0 -3
- package/docker-build/standalone/.next/server/chunks/ssr/[turbopack]_runtime.js +0 -795
- package/docker-build/standalone/.next/server/chunks/ssr/e6d68_cc_CODECRYPTO_infra_server-cc__next-internal_server_app_page_actions_12ae3ff1.js +0 -3
- package/docker-build/standalone/.next/server/functions-config-manifest.json +0 -4
- package/docker-build/standalone/.next/server/middleware-build-manifest.js +0 -21
- package/docker-build/standalone/.next/server/middleware-manifest.json +0 -6
- package/docker-build/standalone/.next/server/next-font-manifest.js +0 -1
- package/docker-build/standalone/.next/server/next-font-manifest.json +0 -27
- package/docker-build/standalone/.next/server/pages/404.html +0 -1
- package/docker-build/standalone/.next/server/pages/500.html +0 -2
- package/docker-build/standalone/.next/server/pages-manifest.json +0 -4
- package/docker-build/standalone/.next/server/server-reference-manifest.js +0 -1
- package/docker-build/standalone/.next/server/server-reference-manifest.json +0 -5
- package/docker-build/standalone/.next/static/ZrQJjBH5oznRmy8xN4NKX/_buildManifest.js +0 -11
- package/docker-build/standalone/.next/static/ZrQJjBH5oznRmy8xN4NKX/_clientMiddlewareManifest.json +0 -1
- package/docker-build/standalone/.next/static/ZrQJjBH5oznRmy8xN4NKX/_ssgManifest.js +0 -1
- package/docker-build/standalone/.next/static/chunks/0c03a563297c48f4.js +0 -1
- package/docker-build/standalone/.next/static/chunks/3142ddfdb448fd24.js +0 -1
- package/docker-build/standalone/.next/static/chunks/35b2ae0057b43b20.js +0 -1
- package/docker-build/standalone/.next/static/chunks/5a1aef391fd12242.js +0 -1
- package/docker-build/standalone/.next/static/chunks/66401b6fc62891de.js +0 -4
- package/docker-build/standalone/.next/static/chunks/782a67ca986fb1bd.js +0 -1
- package/docker-build/standalone/.next/static/chunks/8b27abf6cb0fca62.js +0 -2
- package/docker-build/standalone/.next/static/chunks/8dba80aa68873762.css +0 -3
- package/docker-build/standalone/.next/static/chunks/902797f337bf356c.js +0 -1
- package/docker-build/standalone/.next/static/chunks/9706b17cfd50df01.js +0 -1
- package/docker-build/standalone/.next/static/chunks/a6dad97d9634a72d.js +0 -1
- package/docker-build/standalone/.next/static/chunks/a6dad97d9634a72d.js.map +0 -1
- package/docker-build/standalone/.next/static/chunks/df3b8eb181fde7c2.js +0 -1
- package/docker-build/standalone/.next/static/chunks/turbopack-237950634fd3a365.js +0 -4
- 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 +0 -35
- package/docker-build/standalone/public/deploy-test.html +0 -276
- package/docker-build/standalone/public/file.svg +0 -1
- package/docker-build/standalone/public/globe.svg +0 -1
- package/docker-build/standalone/public/next.svg +0 -1
- package/docker-build/standalone/public/vercel.svg +0 -1
- package/docker-build/standalone/public/window.svg +0 -1
- package/docker-build/standalone/server.js +0 -38
package/src/commands/deploy.ts
CHANGED
|
@@ -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
|
|
11
|
-
.argument('<project-path>', 'Path to the
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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(
|
|
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 (
|
|
135
|
-
|
|
136
|
-
const envLines = envContent.split('\n');
|
|
177
|
+
|
|
178
|
+
if (projectType === 'nextjs') {
|
|
179
|
+
// ========== LÓGICA PARA NEXT.JS ==========
|
|
137
180
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
|
|
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 (!
|
|
200
|
-
|
|
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
|
-
|
|
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✅
|
|
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:
|
|
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
|
-
//
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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
|
-
//
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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
|
|
831
|
+
const stopSpinner = ora('Checking and removing existing container...').start();
|
|
340
832
|
try {
|
|
341
|
-
|
|
342
|
-
|
|
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
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
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
|
-
|
|
356
|
-
|
|
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
|
-
|
|
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 =
|
|
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'));
|