JavaScript GitHub Action (action.yml → runs.using: 'node20' → main: 'dist/index.js').
Bootstrap (src/index.ts) runs npm ci --production at runtime if node_modules/ is missing, then loads dist/main.js. This means node_modules/ must NOT be committed, but package.json + package-lock.json must be.
Two deploy modes (deploy-mode input):
ssh(default) — SSHes in viasshpass, runsgit pull && npm ci && npm run build, reports via GitHub Deployments APIsftp— uploadssource-dir(defaultout/) viassh2-sftp-client
npm run buildrunstsconly (no bundler).src/→dist/.prebuildscript removesdist/first.dist/is tracked in git — it is what the runner executes.- Tagging:
git tag -f v1 && git push -f origin v1. Thev1tag is a moving branch-tag on latest main. No GitHub Releases.
.github/workflows/test.yml: npm ci → npm run build → checks dist/main.js exists. No lint or typecheck step, but tsc enforces types at build time.
~/domains/{domain}/
public_html/.builds/last-source/ ← git repo (has remote origin)
nodejs/ ← deployed app (package.json, .next/, server.js)
Auto-detection (findMatchingDir in ssh-deploy.ts): scans */public_html/.builds/last-source for .git, checks git remote get-url origin against owner/repo, extracts domain from path.
- Deps install at runtime. Each workflow run compiles native
ssh2C++ addons on the runner. Adds ~20s to every run. - Inputs via
INPUT_*env vars.@actions/corereadsprocess.env['INPUT_LIVE-URL']. Only works withruns.using: 'node20'— composite actions break hyphenated names. tokendefault is${{ github.token }}. Must resolve for Deployments API calls. Without it, action silently skips deployment status with a warning.cleanis parsed manually (core.getInput('clean')?.toLowerCase() === 'true').getBooleanInputrejects empty defaults.domaininput preferred overtarget-dir. Constructs/home/{user}/domains/{domain}/nodejsautomatically.- SSH timeouts configured in
sshArgs():ConnectTimeout=15, ServerAliveInterval=10, ServerAliveCountMax=3. Git remote lookup wrapped intimeout 10. sshpassinstalled at runtime viaapt-getif password auth is used. Only on firstensureSshpass()call per runner.findMatchingDiruses glob scan over all*/public_html/.builds/last-sourcedirs. If the scan hangs, SSH connection is likely the issue (not the command itself).
The old auto and ftp deploy modes were removed. build-command and install-command now default to npm run build and npm ci (always runs on server). The action does NOT poll for Hostinger's own build completion — it runs its own build and reports that result.