MemberJunction / MemberJunction/MJ

mj app install writes app packages into workspace package.json before verifying they resolve, wedging npm install for the whole monorepo

Open
#3,796 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TSQL
Stars
29
Forks
6
Avg merge
1d 8h
Merged PRs (30d)
308

Description

## Summary

`mj app install` writes an app's package names into the workspace `package.json` files **before** anything verifies those packages actually resolve. When an app's packages are unpublished (or misnamed), the entries land anyway and wedge `npm install` / `pnpm install` at the workspace root — for the *whole monorepo*, not just the app — until someone removes them by hand.

This is the last untracked finding from the #3337 review; the other two are #3302 and #3338.

## Mechanism

`AddAppPackages` distributes manifest packages to the server/client workspaces and writes them straight through:

- [`packages/OpenApp/Engine/src/install/package-manager.ts#L110-L132`](https://github.com/MemberJunction/MJ/blob/next/packages/OpenApp/Engine/src/install/package-manager.ts#L110-L132) — `AddAppPackages`
- [`packages/OpenApp/Engine/src/install/package-manager.ts#L361-L373`](https://github.com/MemberJunction/MJ/blob/next/packages/OpenApp/Engine/src/install/package-manager.ts#L361-L373) — `AddDependenciesToPackageJson`

```ts
for (const pkg of packages) {
pkgJson.dependencies[pkg.name] = versionStr; // no existence / resolvability check
}
writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2) + '\n', 'utf-8');
```

The name comes from the app manifest and is trusted verbatim. There is no registry probe (`npm view`, or a dry-run resolve) before the write, and the `try/catch` only catches filesystem/JSON errors — an unresolvable-but-well-formed name is a complete success as far as this code is concerned.

## Impact

- **Blast radius is the workspace, not the app.** A single unpublished app package makes root `npm install` fail, so unrelated work in the monorepo is blocked too.
- **Manual recovery.** The user has to know to open `packages/MJExplorer/package.json` and `packages/MJAPI/package.json` and delete the entries. Nothing in the failure output points there.
- **Partial writes stick.** `AddAppPackages` writes per target in a loop and returns `Success: false` mid-way on error, but does not roll back the `package.json` files it already wrote.
- **It is the expected path for a private/in-development app**, not an exotic edge case — which is why it was hit during ordinary manual testing.

## Reproduction

Reported by @MS-BC during the live verification for #3337 ([PR description](https://github.com/MemberJunction/MJ/pull/3337)), installing `https://github.com/MemberJunction/mj-sample-open-app` against a live database:

1. `mj app install ` for an app whose `-ng` / entities / actions packages are not published to npm.
2. Install completes far enough to write `@mj-sample-app/ng`, `@mj-sample-app/entities`, `@mj-sample-app/actions` into the MJExplorer/MJAPI `package.json` files.
3. `npm install` at the workspace root now fails (404 for the unpublished names).
4. The only fix is to hand-edit both `package.json` files.

## Suggested direction

Options, roughly in increasing order of effort:

1. **Verify before writing** — resolve each package (registry probe or `npm view`) up front; fail the install with a clear message naming the unresolvable packages, before touching any `package.json`.
2. **Roll back on failure** — make the `package.json` writes transactional across targets so a failed install leaves the workspace as it found it.
3. **Tell the user how to recover** — at minimum, when install fails after the dependency write, print the exact files and entries to remove.

(1) + (3) probably covers the real pain. Related: #3273 (`mj app link`) would give unpublished/local apps a supported path, but it does not remove the need for this guard on the published path.

## Notes

Filed from a code review of #3337 rather than a fresh reproduction — the mechanism above is verified by reading the code on `next`; the end-to-end symptom is as reported in the PR description.

Contributor guide

Open the contributing guide

Research direction

Start in packages/OpenApp/Engine/src/install/package-manager.ts with AddAppPackages and AddDependenciesToPackageJson, then trace the mj app install path. Reproduce with an app whose packages are unpublished and inspect the MJExplorer and MJAPI package.json files. Done means unresolved packages are reported before writes, or failed installs leave no partial dependency changes and explain recovery.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
50/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.