@@ -2,8 +2,43 @@ import { exec, execFile } from "node:child_process";
22import util from "node:util" ;
33import { findServerById } from "@dokploy/server/services/server" ;
44import { Client } from "ssh2" ;
5+ import { ExecError } from "./ExecError" ;
56
6- export const execAsync = util . promisify ( exec ) ;
7+ // Re-export ExecError for easier imports
8+ export { ExecError } from "./ExecError" ;
9+
10+ const execAsyncBase = util . promisify ( exec ) ;
11+
12+ export const execAsync = async (
13+ command : string ,
14+ options ?: { cwd ?: string ; env ?: NodeJS . ProcessEnv ; shell ?: string } ,
15+ ) : Promise < { stdout : string ; stderr : string } > => {
16+ try {
17+ const result = await execAsyncBase ( command , options ) ;
18+ return {
19+ stdout : result . stdout . toString ( ) ,
20+ stderr : result . stderr . toString ( ) ,
21+ } ;
22+ } catch ( error ) {
23+ if ( error instanceof Error ) {
24+ // @ts -ignore - exec error has these properties
25+ const exitCode = error . code ;
26+ // @ts -ignore
27+ const stdout = error . stdout ?. toString ( ) || "" ;
28+ // @ts -ignore
29+ const stderr = error . stderr ?. toString ( ) || "" ;
30+
31+ throw new ExecError ( `Command execution failed: ${ error . message } ` , {
32+ command,
33+ stdout,
34+ stderr,
35+ exitCode,
36+ originalError : error ,
37+ } ) ;
38+ }
39+ throw error ;
40+ }
41+ } ;
742
843interface ExecOptions {
944 cwd ?: string ;
@@ -21,7 +56,16 @@ export const execAsyncStream = (
2156
2257 const childProcess = exec ( command , options , ( error ) => {
2358 if ( error ) {
24- reject ( error ) ;
59+ reject (
60+ new ExecError ( `Command execution failed: ${ error . message } ` , {
61+ command,
62+ stdout : stdoutComplete ,
63+ stderr : stderrComplete ,
64+ // @ts -ignore
65+ exitCode : error . code ,
66+ originalError : error ,
67+ } ) ,
68+ ) ;
2569 return ;
2670 }
2771 resolve ( { stdout : stdoutComplete , stderr : stderrComplete } ) ;
@@ -45,7 +89,14 @@ export const execAsyncStream = (
4589
4690 childProcess . on ( "error" , ( error ) => {
4791 console . log ( error ) ;
48- reject ( error ) ;
92+ reject (
93+ new ExecError ( `Command execution error: ${ error . message } ` , {
94+ command,
95+ stdout : stdoutComplete ,
96+ stderr : stderrComplete ,
97+ originalError : error ,
98+ } ) ,
99+ ) ;
49100 } ) ;
50101 } ) ;
51102} ;
@@ -108,15 +159,33 @@ export const execAsyncRemote = async (
108159 conn . exec ( command , ( err , stream ) => {
109160 if ( err ) {
110161 onData ?.( err . message ) ;
111- throw err ;
162+ reject (
163+ new ExecError ( `Remote command execution failed: ${ err . message } ` , {
164+ command,
165+ serverId,
166+ originalError : err ,
167+ } ) ,
168+ ) ;
169+ return ;
112170 }
113171 stream
114172 . on ( "close" , ( code : number , _signal : string ) => {
115173 conn . end ( ) ;
116174 if ( code === 0 ) {
117175 resolve ( { stdout, stderr } ) ;
118176 } else {
119- reject ( new Error ( `Error occurred ❌: ${ stderr } ` ) ) ;
177+ reject (
178+ new ExecError (
179+ `Remote command failed with exit code ${ code } ` ,
180+ {
181+ command,
182+ stdout,
183+ stderr,
184+ exitCode : code ,
185+ serverId,
186+ } ,
187+ ) ,
188+ ) ;
120189 }
121190 } )
122191 . on ( "data" , ( data : string ) => {
@@ -132,17 +201,25 @@ export const execAsyncRemote = async (
132201 . on ( "error" , ( err ) => {
133202 conn . end ( ) ;
134203 if ( err . level === "client-authentication" ) {
135- onData ?.(
136- `Authentication failed: Invalid SSH private key. ❌ Error: ${ err . message } ${ err . level } ` ,
137- ) ;
204+ const errorMsg = `Authentication failed: Invalid SSH private key. ❌ Error: ${ err . message } ${ err . level } ` ;
205+ onData ?.( errorMsg ) ;
138206 reject (
139- new Error (
140- `Authentication failed: Invalid SSH private key. ❌ Error: ${ err . message } ${ err . level } ` ,
141- ) ,
207+ new ExecError ( errorMsg , {
208+ command,
209+ serverId,
210+ originalError : err ,
211+ } ) ,
142212 ) ;
143213 } else {
144- onData ?.( `SSH connection error: ${ err . message } ` ) ;
145- reject ( new Error ( `SSH connection error: ${ err . message } ` ) ) ;
214+ const errorMsg = `SSH connection error: ${ err . message } ` ;
215+ onData ?.( errorMsg ) ;
216+ reject (
217+ new ExecError ( errorMsg , {
218+ command,
219+ serverId,
220+ originalError : err ,
221+ } ) ,
222+ ) ;
146223 }
147224 } )
148225 . connect ( {
0 commit comments