Publish to the registry
This recipe ships a built plugin to a plugin registry with
meridian-plugin publish, so operators can declare it in an instance manifest
by version range instead of hand-copying a dist/ folder. It assumes you
already have a working dist/ (see Build and bundle)
and a registry you can write to (see
Set up a plugin registry).
Prerequisites
- A built plugin:
dist/plugin.yamlexists, withnameandversionset (libs/plugin-cli/src/registry/registry.ts,publishPluginreads both from the manifest — nothing is taken from the command line). - A reachable registry — a GCS bucket (
gs://bucket[/prefix]) or a local/NFS directory — with write access for your identity. meridian-pluginavailable: through the scaffold'snode_modules/.bin(npm run …) or vianpx @meridian/plugin-cli.
1. Point the CLI at the registry
publish and versions both take the registry from --registry <url> or,
if that flag is absent, from the MERIDIAN_REGISTRY environment variable —
the flag always wins when both are set
(libs/plugin-cli/src/commands/publish.ts, registryUrl). Neither present is
a hard error (registre non configuré : passez --registry <url> ou définissez MERIDIAN_REGISTRY).
export MERIDIAN_REGISTRY=gs://meridian-plugins # or a local directory / file:// URL
# — or, per invocation:
meridian-plugin publish --registry gs://meridian-plugins
2. Publish the built plugin
cd vitals
npm run build # meridian-plugin build → dist/ (bundled, self-contained)
meridian-plugin publish # registry from MERIDIAN_REGISTRY, or add --registry <url>
publish [dir=.] is convenient about where you point it
(publishCommand): if <dir>/dist/plugin.yaml exists, that dist/ is what
gets published; otherwise <dir> itself is published as-is. In practice this
means running the command from the plugin's project root (after build) and
running it from inside dist/ both work — meridian-plugin publish and
meridian-plugin publish dist are equivalent there. The directory argument
and --registry <value> can appear in either order on the command line.
A successful publish reports the name, version and file count that landed on the store:
✓ @acme/vitals@0.1.0 published to gs://meridian-plugins (7 file(s)).
Internally, every file under dist/ is uploaded first, and plugin.yaml is
written last — its presence is the marker that a version is complete, so
a download in progress never sees a half-published version
(registry.ts, publishPlugin).
3. Verify what's published
List the versions the registry currently has for that name:
meridian-plugin versions @acme/vitals --registry gs://meridian-plugins
0.1.0
0.2.0
Versions print oldest first — resolved with the npm semver package
(compare), with any non-semver folder name pushed to the end rather than
failing the listing (registry.ts, listVersions). An empty result prints
@acme/vitals : aucune version publiée sur … rather than an error, which
still confirms the registry is reachable and readable.
To confirm an operator can actually pick it up, see
Declare and install plugins —
version ranges (^0.1.0, ~0.1.0, an exact version, *) are resolved
against this same list with maxSatisfying.
Re-release after a change (versions are immutable)
A published name@version can never be overwritten. Publishing the same
version again is refused outright:
✗ @acme/vitals@0.1.0 is already published on gs://meridian-plugins — versions
are immutable, bump it.
(registry.ts, publishPlugin — the check is a plain existence test on that
version's plugin.yaml before anything is written.) To ship a new build:
- Bump
versioninplugin.yaml(semver). This is the only place the version comes from — there is no--versionflag onpublish. - Rebuild:
npm run buildcopies the bumped manifest intodist/. - Publish again. The new version is added; every previous one is untouched and still resolvable by any range that matched it before.
If a publish is interrupted
Because files land before plugin.yaml, an interrupted publish (network
drop, killed process) can leave stray files under that version's prefix even
though the version is not "complete" (no plugin.yaml yet, so versions
still won't list it). Retrying the exact same version isn't guaranteed to be
clean in that case — each file is written with a create-if-absent guard, so a
file that already landed makes the retry fail on that file rather than with
the friendly "already published" message above. If a retry fails oddly right
after an interruption, that's almost certainly why; publishing under a bumped
version sidesteps it entirely.
Related
- Build and bundle — produces the
dist/this recipe publishes. - Bundling and distribution —
why versions are immutable and what a published
dist/contains. - Set up a plugin registry — stand up the GCS bucket or directory this recipe publishes to, including the IAM/filesystem permissions publishing needs.
- Declare and install plugins — the operator side: adding the published name and a version range to an instance manifest.
- Environment variables —
MERIDIAN_REGISTRYand related. - Plugin manifest and
CLI reference — the
versionfield and the fullmeridian-plugincommand surface.