@@ -2,8 +2,7 @@ import { execa } from 'execa';
22import { pathExists } from 'fs-extra' ;
33import { resolve } from 'path' ;
44import type { ShipnodeConfig , ShipnodeApp , Pm2App } from '../../shared/types.js' ;
5- import { getDeploymentName , getPm2Name } from '../pm2/apps.js' ;
6- import { getActiveApp } from '../workspace.js' ;
5+ import { getPm2Name } from '../pm2/apps.js' ;
76import { getInstallCommand , getRunCommand , detectPkgManager } from '../framework/detector.js' ;
87import { RSYNC_DEFAULT_EXCLUDES } from '../../shared/constants.js' ;
98import { DeployError } from '../../shared/errors.js' ;
@@ -39,12 +38,13 @@ export class BackendStrategy implements DeploymentStrategy {
3938 readonly name = 'backend' ;
4039
4140 constructor (
42- private config : ShipnodeConfig ,
41+ private workspace : ShipnodeConfig ,
42+ private app : ShipnodeApp ,
4343 private cwd : string ,
4444 ) { }
4545
46- private get app ( ) : ShipnodeApp {
47- return getActiveApp ( this . config ) ;
46+ private get appPath ( ) : string {
47+ return ` ${ this . workspace . remotePath } / ${ this . app . name } ` ;
4848 }
4949
5050 async stage ( ctx : StrategyContext ) : Promise < void > {
@@ -55,25 +55,25 @@ export class BackendStrategy implements DeploymentStrategy {
5555 const args = [
5656 '-avz' ,
5757 '--progress' ,
58- '-e' , `ssh -p ${ this . config . ssh . port } ` ,
58+ '-e' , `ssh -p ${ this . workspace . ssh . port } ` ,
5959 ...excludes . flatMap ( ( e ) => [ '--exclude' , e ] ) ,
6060 ...( hasIgnoreFile ? [ '--exclude-from' , ignoreFile ] : [ ] ) ,
6161 `${ this . cwd } /` ,
62- `${ this . config . ssh . user } @${ this . config . ssh . host } :${ ctx . workDir } /` ,
62+ `${ this . workspace . ssh . user } @${ this . workspace . ssh . host } :${ ctx . workDir } /` ,
6363 ] ;
6464
6565 await execa ( 'rsync' , args , { stdio : 'inherit' } ) ;
6666 }
6767
6868 async setupEnvironment ( ctx : StrategyContext ) : Promise < void > {
6969 const pkgManager = await this . resolvePkgManager ( ) ;
70- const installCmd = this . config . installCommand ?? getInstallCommand ( pkgManager ) ;
70+ const installCmd = this . workspace . installCommand ?? getInstallCommand ( pkgManager ) ;
7171 const runCmd = getRunCommand ( pkgManager ) ;
7272
7373 const commands = [
7474 `cd "${ ctx . workDir } "` ,
7575 `export PATH="$HOME/.local/bin:$HOME/.local/share/mise/shims:$PATH"` ,
76- `mise use -y "node@${ this . config . nodeVersion } "` ,
76+ `mise use -y "node@${ this . workspace . nodeVersion } "` ,
7777 `mise install -y` ,
7878 ] ;
7979
@@ -84,7 +84,7 @@ export class BackendStrategy implements DeploymentStrategy {
8484 if ( this . app . envFile ) {
8585 // Use the configured env filename in the shared path; the local workDir
8686 // alias stays `.env` (the well-known name framework loaders look for).
87- commands . push ( `ln -sf "${ this . config . remotePath } /shared/${ this . app . envFile } " .env` ) ;
87+ commands . push ( `ln -sf "${ this . appPath } /shared/${ this . app . envFile } " .env` ) ;
8888 // Source it so install/build see env vars (private-registry tokens in
8989 // `.npmrc` via `${TOKEN}`, build-time secrets, etc.). Affects this shell
9090 // chain only; the PM2 wrapper sources independently at process start.
@@ -133,21 +133,21 @@ export class BackendStrategy implements DeploymentStrategy {
133133 // Ecosystem lives inside the release directory (per-release snapshot, ADR-0001).
134134 // PM2 references it via the `current` symlink so it always resolves to the active release.
135135 const ecosystemWritePath = `${ ctx . workDir } /ecosystem.config.cjs` ;
136- const ecosystemRuntimePath = `${ this . config . remotePath } /current/ecosystem.config.cjs` ;
136+ const ecosystemRuntimePath = `${ this . appPath } /current/ecosystem.config.cjs` ;
137137
138138 const escaped = ecosystemContent . replace ( / ' / g, "'\"'\"'" ) ;
139139 await ctx . executor . execOrThrow ( `echo '${ escaped } ' > "${ ecosystemWritePath } "` ) ;
140140
141- const cdPath = `${ this . config . remotePath } /current` ;
141+ const cdPath = `${ this . appPath } /current` ;
142142 const mise = `export PATH="$HOME/.local/bin:$HOME/.local/share/mise/shims:$PATH"` ;
143143
144144 // Re-run install from the final directory so the pkg manager's module
145145 // resolution state matches the path PM2 will use. Packages are already
146146 // in the local store so this is a fast offline relink, not a download.
147147 // If the user supplied a custom installCommand we use it verbatim — they've
148148 // chosen their flags and appending --prefer-offline would compose poorly.
149- const baseInstall = this . config . installCommand ?? getInstallCommand ( pkgManager ) ;
150- const relinkInstall = this . config . installCommand ? baseInstall : `${ baseInstall } --prefer-offline` ;
149+ const baseInstall = this . workspace . installCommand ?? getInstallCommand ( pkgManager ) ;
150+ const relinkInstall = this . workspace . installCommand ? baseInstall : `${ baseInstall } --prefer-offline` ;
151151 // Source env before relinking too — same reason as setupEnvironment:
152152 // private-registry tokens in `.npmrc` use env-var interpolation.
153153 const sourceCmd = sourceEnvCommand ( this . app . envFile ) ;
@@ -184,8 +184,8 @@ export class BackendStrategy implements DeploymentStrategy {
184184 private generateEcosystemFile ( pkgManager : string ) : string {
185185 if ( ! this . app . pm2 ) return '' ;
186186
187- const namespace = getDeploymentName ( this . config ) ?? this . app . pm2 . apps [ 0 ] . name ;
188- const envFilePath = `${ this . config . remotePath } /shared/${ this . app . envFile } ` ;
187+ const namespace = this . app . pm2 . apps [ 0 ] . name ;
188+ const envFilePath = `${ this . appPath } /shared/${ this . app . envFile } ` ;
189189 const appBlocks = this . app . pm2 . apps . map ( ( app ) => this . generateAppBlock ( app , pkgManager , namespace , envFilePath ) ) ;
190190
191191 return `module.exports = {
@@ -237,7 +237,7 @@ ${appBlocks.join(',\n')}
237237 // resolves require paths against the app, not the workspace root.
238238 // Install/build still run at the workspace root.
239239 const cwdLine = this . app . appRoot
240- ? `\n cwd: '${ escapeSingleQuotes ( `${ this . config . remotePath } /current/${ this . app . appRoot } ` ) } ',`
240+ ? `\n cwd: '${ escapeSingleQuotes ( `${ this . appPath } /current/${ this . app . appRoot } ` ) } ',`
241241 : '' ;
242242
243243 return ` {
@@ -278,14 +278,14 @@ ${envLines}
278278
279279 if ( this . app . sharedDirs ) {
280280 for ( const dir of this . app . sharedDirs ) {
281- commands . push ( `mkdir -p "${ this . config . remotePath } /shared/${ dir } "` ) ;
282- commands . push ( `ln -sfn "${ this . config . remotePath } /shared/${ dir } " "${ workDir } /${ dir } "` ) ;
281+ commands . push ( `mkdir -p "${ this . appPath } /shared/${ dir } "` ) ;
282+ commands . push ( `ln -sfn "${ this . appPath } /shared/${ dir } " "${ workDir } /${ dir } "` ) ;
283283 }
284284 }
285285
286286 if ( this . app . sharedFiles ) {
287287 for ( const file of this . app . sharedFiles ) {
288- commands . push ( `ln -sf "${ this . config . remotePath } /shared/${ file } " "${ workDir } /${ file } "` ) ;
288+ commands . push ( `ln -sf "${ this . appPath } /shared/${ file } " "${ workDir } /${ file } "` ) ;
289289 }
290290 }
291291
@@ -307,7 +307,7 @@ ${envLines}
307307 }
308308
309309 private async resolvePkgManager ( ) {
310- if ( this . config . pkgManager ) return this . config . pkgManager ;
310+ if ( this . workspace . pkgManager ) return this . workspace . pkgManager ;
311311 const detected = await detectPkgManager ( this . cwd ) ;
312312 return detected ?? 'npm' ;
313313 }
0 commit comments