Package Registry
Project Links: GitHub
MaìLang ships with a small filesystem-first package registry. Its behavior lines up with the core crates.io workflow (publish / install / search / yank / index), but it works fully offline. You can also host the registry directory as static files and serve it over HTTP.
Canonical fields and layout are documented in MODULE_SPEC.md.
Quick Start
# 1. Create an empty registry
mailang registry init ./.mailang-registry
# 2. Publish from a package project (requires mailang.toml + lib.mai)
mailang publish --registry ./.mailang-registry
# 3. Install in another project
mailang install mypkg --registry ./.mailang-registry
# 4. Search
mailang search json --registry ./.mailang-registry
# 5. Yank a bad version (install rejects it by default)
mailang yank mypkg 0.1.0 --registry ./.mailang-registryDirectory Layout
<registry-root>/
├── registry.toml
├── index/<name-prefix>/<name> # JSON Lines index
└── pkgs/<name>/
├── <vers>/ # package directory copy
└── <name>-<vers>.mpkg # single-file package (for HTTP)name-prefix rules (same as crates.io):
- 1 character →
1/<name> - 2 characters →
2/<name> - 3 characters →
3/<first-char>/<name> - ≥4 characters →
<first-two-chars>/<name>
For example, the index path for json is index/js/json.
Default Registry Location
Resolved in the following priority order (override with --registry):
- Environment variable
MAILANG_REGISTRY ./.mailang-registryin the current directory- User directory
~/.mailang/registry(Windows:%USERPROFILE%\.mailang\registry\)
# Specify a registry globally
export MAILANG_REGISTRY=/var/mailang/registry # or https://reg.example.com
mailang publish
mailang install mypkgPublish
Run in the package project root (the directory that contains mailang.toml):
# mailang.toml
[package]
name = "greet"
version = "0.1.0"
description = "hello helpers"// lib.mai
fn ping() {
return "greet"
}mailang publish --registry ./.mailang-registry
# published greet@0.1.0 -> ./.mailang-registry
# cksum: a1b2c3d4e5f60718
# dir: .\.mailang-registry\pkgs\greet\0.1.0
# mpkg: .\.mailang-registry\pkgs\greet\greet-0.1.0.mpkgBehavior notes:
| Rule | Description |
|---|---|
| Packaged contents | mailang.toml, lib.mai, mailib.ini, README/README.md, top-level *.mai |
| Content hash | FNV-1a 64 over the .mpkg bytes, written to the index as cksum |
| Version conflict | Rejected if the same name@vers already exists; --allow-republish allows overwrite |
| Dependency record | The index deps field lists names from [dependencies] |
Install
mailang install greet # latest non-yanked version
mailang install greet@0.1.0 # exact version
mailang install greet --global # install to ~/.mailang/pkg/greet
mailang install greet --allow-yanked # allow installing a yanked version
mailang install greet --no-manifest # do not rewrite mailang.tomlInstall results:
- Package files are copied to
vendor/<name>/(or~/.mailang/pkg/<name>/with--global) - By default,
mailang.toml[dependencies]is rewritten to a path dependency pointing atvendor/<name> - Afterwards,
mailang deps/mailang runresolve fully offline
Example of a rewritten mailang.toml:
[package]
name = "app"
version = "0.0.1"
[dependencies]
# greet = registry install -> vendor/greet (do not edit by hand)
greet = "vendor/greet"Search
mailang search hello --registry ./.mailang-registry
# NAME VERSION YANKED DESCRIPTION
# greet 0.1.0 no hello helpersMatching rules: case-insensitive substring match on the package name and description. An empty query lists everything. HTTP registries cannot walk index/ — search on a local mirror instead.
Yank
mailang yank greet 0.1.0 --registry ./.mailang-registry
mailang yank greet 0.1.0 --undo --registry ./.mailang-registry # restore- After a yank,
installfails by default (the error message suggests--allow-yanked). - Bare-name "latest" resolution skips yanked versions; if every version is yanked, it errors.
HTTP Hosting
Put the entire <registry-root> directory on any static file server:
https://reg.example.com/index/js/json
https://reg.example.com/pkgs/greet/greet-0.1.0.mpkgmailang install greet --registry https://reg.example.comImplementation details:
- Index / package reads go through
curl -fsSL(no HTTP dependency crate is introduced) - Install uses the
.mpkgsingle-file package and verifiescksum - Write operations (
publish/yank/registry init) require a filesystem path; HTTP is read-only
Offline and Workflow Tips
- Local development:
registry init ./.mailang-registry, then publish/install packages and apps on the same machine. - Team sharing: put the registry directory on a shared drive or in Git, or rsync it to a static server.
- CI:
publishto an internal path in the pipeline; the artifact directory doubles as a registry snapshot. - Coexisting with path/github dependencies:
installwrites path dependencies, fully compatible withmailang addandmailang.lock.
Troubleshooting
| Symptom | Fix |
|---|---|
already published | Bump version, or use --allow-republish |
yanked: … | Use --allow-yanked, or mailang yank … --undo |
checksum mismatch | Index and .mpkg disagree — publish again or repair the mirror |
publish requires a filesystem registry | Do not publish to http://; write locally first, then sync |
search requires a filesystem registry | Search on a local index/ mirror |
API Entry Points
crates/mailang-module/src/registry.rs:
RegistrySource::default_source/parse/initpublish/install/search/set_yanked/resolve_versionread_index/write_index/upsert_index_entrypack_mpkg/unpack_mpkg/name_prefix