Mini Plan — Plugin npm Source Resolution (local dir + public registry)
Status: IMPLEMENTED.
resolve_npm_source(name, version, mode=…)inymerflow_plugin_build/build.pydoes local-first / local-only / registry-only perPLUGIN_NPM_SOURCE_MODE; registry fetch is vianpm pack(unifying both paths to a tarball). Settings live inbackend/config.py, are injected byjob_orchestrator.py, and documented inconfig.env.example/docs/deployment.md/docs/plugin-author-guide.md. Tests:tests/test_npm_source_resolution.py(unit) + verified registry fetch from real npmjs.
Goal
The build_frontend_plugin build must be able to fetch a plugin's npm source package from
either:
- Public npm registry (
registry.npmjs.orgor a configured private registry) — the production default. - Server-local directory — packages (
.tgztarballs fromnpm pack, or unpacked source dirs) that the server admin places ahead of time. Primarily for testing and air-gapped deployments.
Both must be supported simultaneously. The current implementation (server-local only) is a subset; this plan adds the registry path and a clean resolution order so neither is special-cased.
Context: the local-dir path was built first because it lets us test the whole user-install flow without publishing test packages to npm. It is not a replacement for the registry path — both ship.
Resolution model
A build is parameterised by { npm_name, npm_version }. A source resolver decides where the
tarball comes from, in this order:
- Local override — if
<PLUGIN_NPM_SOURCE_DIR>/<name>-<version>.tgz(or a matching source dir) exists, use it. Lets an admin pin/override a specific package without touching the registry. - Registry — otherwise
npm install <name>@<version>againstPLUGIN_NPM_REGISTRY(defaulthttps://registry.npmjs.org).
Local-first means a deployment can run fully offline by populating the directory, while an
unmodified deployment "just works" against npm. The resolver returns a concrete install spec
(a tarball path or a name@version registry spec) that the build step passes to npm install.
Configuration
| Setting | Env var | Default | Meaning |
|---|---|---|---|
| Local source dir | PLUGIN_NPM_SOURCE_DIR |
"" (disabled) |
Directory of admin-placed .tgz/source packages. Empty ⇒ registry-only. |
| Registry URL | PLUGIN_NPM_REGISTRY |
https://registry.npmjs.org |
Registry used when no local match. Point at a private mirror for locked-down installs. |
| Source mode | PLUGIN_NPM_SOURCE_MODE |
auto |
auto = local-first then registry; local = local only (fail if absent); registry = registry only (ignore local dir). |
PLUGIN_NPM_SOURCE_MODE=local reproduces today's behaviour for tests; registry is the
strict-production setting; auto is the convenient default.
Changes
- Config — add the three settings above to the backend/build config (wherever
PLUGIN_NPM_SOURCE_DIRalready landed). Keep them in one place the build step reads. - Source resolver — a single function
resolve_npm_source(name, version) -> install_specimplementing the order/mode above. Unit-testable in isolation (no network): given a temp dir with/without a matching tarball and each mode, assert the chosen spec. - Build step — replace the hard-coded local-tarball install with a call to the resolver, then
npm install <install_spec>with--registry <PLUGIN_NPM_REGISTRY>when the spec is a registry spec. Everything downstream (MF build, content-addressing, register) is unchanged. - Pod vs local — the resolver runs identically in the K8s pod and the local subprocess path;
only the egress policy differs (the pod's only allowed egress is
PLUGIN_NPM_REGISTRY; the local dir is mounted read-only). - Errors — surface a clear process-log failure when
mode=localand no local package matches, or when the registry fetch fails (unknown package / network), rather than a generic build error.
Testing
- Unit: resolver picks local tarball when present; falls back to registry when absent;
respects each
PLUGIN_NPM_SOURCE_MODE; errors clearly whenlocalmode has no match. - Integration (local dir): existing flow — admin drops a
.tgz, build installs from it. - Integration (registry): point
PLUGIN_NPM_REGISTRYat a throwaway/private registry (or npmjs with a real published test package) and build with no local file present; confirm the registry path produces an identical MF remote.
Out of scope
- Auth tokens /
.npmrccredentials for private registries (add later asPLUGIN_NPM_REGISTRY_TOKENif needed). - Provenance/signature verification of fetched packages.
- Caching/dedup of identical
(source, host-versions)builds across projects (already tracked in the main plan's open questions).