# Publishing the embedded crates to crates.io The 22 crates of the SQLite engine are published to crates.io. `pg_mentat`, `mentatd`, the SQLite/DuckDB loadable extensions, `mentat_ffi` and the benchmark runner are **not** published (`publish = false`); they ship via PGXN and the DuckDB Community registry instead. ## Package names vs library names Package names (what goes in `[dependencies]`) were chosen to be free on crates.io. **Library names are unchanged**, so `use mentat::`, `use edn::`, `use gc::`, `use core_traits::` keep compiling. The mapping: | Package (crates.io) | Library (`[lib] name`) | |---|---| | `mentatdb` | `mentat` | | `mentat_edn` | `edn` | | `mino_gc`, `mino_gc_derive` (vendored) | `gc`, `gc_derive` | | `mentat_core_traits`, `mentat_db_traits`, `mentat_sql_traits`, `mentat_public_traits` | `core_traits`, … | | `mentat_query_{algebrizer,pull,projector}_traits` | `query_*_traits` | | the rest (`mentat_core`, `mentat_db`, `mentat_query_*`, `mentat_transaction`, `mentat_script`, `mentat_cli`, `mino-rs`) | same | A crate that keeps a non-default library name sets it explicitly in `[lib]` (e.g. `mentatdb` has `[lib] name = "mentat"`). Dependents reference it by the library name with a `package =` override, e.g. `edn = { package = "mentat_edn", path = "../edn", version = "=1.12.0" }`. ## Consuming from crates.io ```toml [dependencies] mentatdb = "1.12" # the crate is still imported as `mentat` ``` ## Per-release publish 1. Confirm the tag's tree is checked out and the version is bumped everywhere (the release.yml gate checks Cargo.toml / pg_mentat.control / META.json). 2. Credentials live in `~/.cargo/credentials.toml`. On this host `CARGO_HOME` is set to the repo's `.cargo/` (which has **no** credentials), so publish with it unset and the token passed explicitly: ```sh unset CARGO_HOME export CARGO_REGISTRY_TOKEN="$(python3 -c "import tomllib;print(tomllib.load(open('$HOME/.cargo/credentials.toml','rb'))['registry']['token'])")" ``` 3. Publish in dependency order (`~/.cache/mentat/pub_order.txt`, regenerated from `cargo metadata`), one crate at a time, waiting for each to appear on the index. The script `~/.cache/mentat/publish.sh` is idempotent (skips a crate+version already on the index) and honors crates.io's rate limit. ## Gotchas (each one cost a failed publish) - **New-crate rate limit.** After an initial burst of ~5 new crates, crates.io allows roughly **one new crate per 10 minutes** and returns `429 ... try again after `. The publish script parses that timestamp and sleeps until it. First publish of ~22 names takes ~3 hours. - **Every dependency needs a version.** `cargo publish` rejects a path dep with no `version`. All intra-workspace deps carry `version = "=1.12.0"`. The vendored `gc` dep from `mino` needed `version = "0.5.1"` added by hand (the bump script skipped the vendored path). - **Versioned dev-deps are validated against the index even though the path is stripped.** A *circular* dev-dep then can't be satisfied: `mentat_query_projector_traits` dev-depends on `mentat_query_projector`, which build-depends back on it. Make such circular dev-deps **path-only (no version)** so cargo strips them without an index lookup. - **`description` is required.** `mentatdb` (formerly `mentat`) never had one; crates.io rejects a publish with no description. - **cargo-deny + a self-referential renamed dev-dep panics.** The vendored `gc` crate's self dev-dep (`gc = { package = "mino_gc", path = "." }`) made `krates` (cargo-deny) hit `unreachable!`. Fixed by giving `gc` an explicit `[lib] name = "gc"` so the self-reference resolves to the library name. ## Verify A clean consumer must build against crates.io alone: ```sh cargo new /tmp/c && cd /tmp/c echo 'mentatdb = "1.12"' >> Cargo.toml # use mentat::{Store, Queryable, QueryResults}; open "", transact, q_once cargo run ```