HarperFast / HarperFast/harper
Payload-deployed components are never reinstalled, so a broken install cannot recover
- Dominant language
- JavaScript
- Stars
- 89
- Forks
- 10
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 200
Description
## Summary
A component deployed by **payload** gets exactly one dependency install — at deploy time — and never again. If that install fails or its `node_modules` is lost, nothing restores it. Restarts don't help, because boot-time installation never considers the component at all.
Observed on 5.1.x: a component's `node_modules` was destroyed by a failed install (see #1973). Every subsequent restart left it broken with `Cannot find module` at resource load, and no npm run was even attempted — the npm logs were unchanged across restarts.
## Why
`deployComponent` (`components/operations.js`) only writes an application entry to the root config when the request carries a package identifier:
```js
if (req.package) {
const applicationConfig = { package: req.package };
...
await configUtils.addConfig(req.project, applicationConfig);
}
```
A payload deploy has no `req.package`, so no entry is written. `installApplications()` iterates root-config entries that have a `package` property, so a payload-deployed component is never in that set — it isn't in `harper-application-lock.json` either. It's loaded from the components directory on every boot, but its dependencies are never verified or reinstalled.
So the install is effectively one-shot, with no integrity check and no recovery path, for a whole class of deploys.
## Possibly related, unverified
Even for root-config applications, `installApplication` early-returns on mere **existence** of the directory:
```js
await access(join(application.dirPath, 'node_modules'), constants.F_OK);
// -> "already has node_modules; skipping install"
```
Separately, something in boot creates `node_modules/harper` (a symlink to the installed Harper package) so components can import `harper`. In the case observed, `node_modules` was absent before restart and afterwards contained *only* that symlink.
If that symlink is created before the existence check runs, then an empty-but-present `node_modules` would satisfy the check and suppress a needed install. **I could not confirm this**, because for the component in question `installApplication` was never reached at all (per the root-config gap above). Flagging it as a hazard worth checking rather than a diagnosis — if real, it affects root-config apps too, and an existence check is the wrong test either way.
## Suggested direction
Make dependency state verifiable and repairable independent of how the component was deployed: record what was installed, check it at load, and reinstall when it doesn't match — rather than inferring "installed" from a directory existing. At minimum, payload-deployed components should be reachable by the same boot-time install path as package-identifier ones.
Related: #1973 (how the install gets destroyed), #1975 (why the breakage stays invisible).
---
🤖 Filed by Claude on behalf of @heskew
Contributor guide
Research direction
Start in components/operations.js with deployComponent, then trace installApplications and installApplication and how harper-application-lock.json is used. Check the payload-deploy path and the node_modules existence check, including the possible harper symlink hazard. Done means payload-deployed components are included in boot-time dependency verification and can recover from a failed or missing install.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, nodejs
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100