Every capability block is optional and additive: an app may extend MJ via a schema,
metadata, packages, any combination, or be manifest-only. Each step below is gated on
its block being present, so a manifest-only app simply records itself and finishes. The
persisted MJ: Open Apps.ManifestJSON is the source of truth re-read by upgrade/remove.
Steps (each no-ops when its block is absent):
Fetch manifest from GitHub
Validate manifest (Zod)
Validate MJ version compatibility
Resolve the FULL transitive dependency graph (fetch every dependency's
manifest, detect cross-repo cycles, topologically sort) — skipped when
this call is itself a pre-resolved member of a parent's graph
Install dependencies in leaf-first order (each via _skipDependencyResolution)
Check schema (no collision)
Create schema
Run migrations (Skyway - DDL + metadata DML)
Record installation with 'Installing' status
Update package.json files
Run npm install
Update server + client config (dynamicPackages.server/.client in mj.config.cjs;
client imports are materialized into MJExplorer's manifest at its next prebuild)
Update angular.json prebundle excludes (prevents Vite singleton duplication)
Executes the full install flow for an Open App.
Every capability block is optional and additive: an app may extend MJ via a schema, metadata, packages, any combination, or be manifest-only. Each step below is gated on its block being present, so a manifest-only app simply records itself and finishes. The persisted
MJ: Open Apps.ManifestJSONis the source of truth re-read by upgrade/remove.Steps (each no-ops when its block is absent):