For developers
Publish an extension
Extensions are published from the CLI with a user token. The registry validates the version, refuses to overwrite history, and serves the archive to anyone entitled to it.
# install the CLI
$ npm install -g module-registry-client-lib
# publish to the stable channel
$ msc publish --modulePath=./dist \
--userToken=$USER_TOKEN --tag=main
What your package must contain
These fields drive everything a visitor sees on the marketplace — name, summary and category. Most of them live in package.json; the two long texts are read from files in the module root.
| Field | Comes from | Required | What it is |
|---|---|---|---|
| appIdstring | package.json | Required | Unique id in the registry and in every install command. Lowercase, no spaces — it is the primary key, so it can never be changed after the first publish. |
| appNamestring | package.json | Required | The human-readable name shown on the card and detail page. Falls back to appId when omitted. |
| versionstring (semver) | package.json | Required | The release being published, e.g. 1.4.2. Must be valid semver and higher than the current latest on the tag; an existing version is never overwritten. |
| descriptionmarkdown | README.md | Required | The long description rendered on the detail page. Not read from package.json — the whole README.md in the module root is taken as-is. |
| changelogmarkdown | CHANGELOG.md | Required | The release history shown on the Changelog tab. Also taken from the file in the module root, not from package.json. |
| categorystring (slug) | package.json | Required | The slug of an existing marketplace category, e.g. payment. An unknown slug is silently dropped and the extension ends up uncategorised. |
| appTagsstring[] | package.json | Optional | Filter chips on the catalog page. When missing, the standard keywords array is used instead. |
| iconstring (SVG markup) | package.json / icon.svg | Optional | The card and detail icon, stored as inline SVG source rather than a URL. An icon.svg file in the module root always wins over this field. |
| appSupportstring (URL) | package.json | Optional | Issue tracker link shown in the Support block. When missing, the issue field is used instead. |
| mmDependencies{ appId: semver range } | package.json | Optional | Other registry extensions this build needs, as an id → version-range map. The resolver picks a compatible version at install time, so this is not the same as npm dependencies. |
{
"name": "sails-hook-my-extension",
"version": "1.4.2",
"appId": "my-extension",
"appName": "My Extension",
"category": "payment",
"appTags": ["payment", "checkout"],
"appSupport": "https://github.com/acme/my-extension/issues",
"mmDependencies": {
"another-extension": "^2.0.0"
}
}Publishing rules
- 1
Versions are semantic and final
- 2
Each tag only moves forward
- 3
main is the default channel
How users install your builds
- Stable — the default
msc install --appId=your-extension- Staging, falling back to stable
msc install --appId=your-extension --channel=staging- Highest version across every channel
msc install --appId=your-extension --channel=any- An exact version
msc install --appId=your-extension --version=1.4.2
Get a publisher token
Publishing needs a user token tied to your account. Write to us with the appId you want to claim and what the extension does.