cratefield-cli 0.2.0

The fz CLI for Cratefield ventures: migrations collect/apply, doctor, modules, push
Documentation
[package]
name = "cratefield-cli"
description = "The fz CLI for Cratefield ventures: migrations collect/apply, doctor, modules, push"
readme = "README.md"
keywords = ["cratefield", "cli", "migrations", "wrangler", "d1"]
categories = ["command-line-utilities", "development-tools"]
include = ["src/**/*", "examples/**/*", "README.md"]
version = "0.2.0"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true

[lints]
workspace = true

[features]
# `fz migrations apply --dialect postgres` (issue #18): pulls the
# native-only Postgres adapter and a tokio runtime to drive it. Opt-in so
# the default fz dependency graph stays free of sqlx and tokio — a
# venture's wasm build must never see them.
postgres = ["dep:cratefield-adapter-postgres", "dep:tokio"]
# `fz push send`'s network leg (issue #184): the runtime's own HTTP client —
# reqwest behind the outbound policy — and the tokio runtime it needs. Opt-in
# for the same reason `postgres` is, and the live-proof tool is documented as
# needing it (README, issue #186).
#
# A feature-gated *send* is not the feature-gated *doctor* the push-wiring
# note below refuses. The difference is what an `fz` without the feature
# does: `fz push send` says, in one line, exactly what to rebuild, while a
# doctor compiled without a check reports a clean bill and says nothing. Loud
# absence is a build option; silent absence is not. Everything else under
# `fz push` — keygen, inspect-subscription, and `send --dry-run`, which
# reports the transport's wiring — works in every build.
#
# This is never a feature a **venture** turns on: `cratefield-runtime-native`
# `compile_error!`s on wasm32 and a generated venture depends on this crate
# beside a wasm `cdylib`, so flipping it there breaks the build of the thing
# the venture deploys. A send-capable `fz` is installed separately
# (`cargo install cratefield-cli --features push-send`) and the Docker image
# is built with it.
#
# It pulls the whole native runtime — axum, redis, croner,
# tracing-subscriber — to obtain one `ReqwestClient` and one `TokioClock`,
# and the alternative was weighed: an `http-client` feature on
# `cratefield-runtime-native` that carried the ports without the server.
# Not taken, deliberately.
#
#   - That crate's module graph is not separable along that line today.
#     `ports/mod.rs` itself is built on axum types (`HeaderMap`,
#     `HeaderName`, the client-IP resolution the server middleware calls),
#     so an `http-client` build would have to `cfg` the ports module, the
#     runtime, the server, cron and the tracing setup — and every one of
#     those becomes a configuration nothing in CI compiles unless a matrix
#     leg is added for it.
#   - The cost it buys back is build time for one native binary that is
#     compiled once and installed. Nothing ships this graph: the venture's
#     wasm build never sees this crate (that is what the `compile_error!`
#     enforces), and the image already carries a Rust toolchain.
#   - The point of the live proof is that the send goes through *the
#     client the runtime uses*, wired the way `serve()` wires it. A leaner
#     dependency edge that reached a differently-assembled client would
#     make the proof prove less.
#
# Revisit it if a second consumer wants the same thing, which is when the
# split stops being a change made for one caller.
push-send = ["dep:cratefield-runtime-native", "dep:tokio"]

[dependencies]
cratefield-core = { workspace = true }
cratefield-adapter-sqlite = { workspace = true }
# `fz doctor` reads the push environment through the same `build_push` the
# runtimes do (issue #191), so the doctor and `serve()` cannot check different
# variable names. Pure Rust and native-safe: the push adapters speak HTTP
# through the `HttpClient` port and pull no tokio, sqlx or OpenSSL.
#
# **Not** optional, unlike `postgres` below, and the difference is deliberate.
# `fz` is built once and installed; a feature-gated doctor check is a doctor
# that silently checks less depending on how somebody's `fz` was compiled,
# which is the same class of invisible drift this crate exists to remove. The
# cost is that every `fz` links the three adapters and their crypto, and that
# `cratefield-push-wiring` must be first-published before `cratefield-cli`
# (docs/RELEASING.md).
cratefield-push-wiring = { workspace = true }
# `fz push vapid keygen` (issue #184) mints the P-256 key pair with the same
# signer the adapters present their provider tokens with, so the public half
# it prints is the one `WebPush::public_key()` derives — not a second
# derivation that could disagree about the point encoding.
cratefield-push-auth = { workspace = true }
# `fz push inspect-subscription` validates with the Web Push adapter's own
# rules — `vapid::origin_of` for the audience, `ece::SubscriptionKeys` for
# the two keys — so a subscription the CLI accepts is one the adapter
# accepts. Already in the graph through `cratefield-push-wiring`; named here
# because this crate calls it directly.
cratefield-adapter-webpush = { workspace = true }
cratefield-manifest = { workspace = true }
clap = { workspace = true }
base64 = { workspace = true }
# The VAPID scalar and its base64url form are key material: cleared on drop,
# the workspace convention (`crates/kms`, `crates/secrets`, the adapters).
zeroize = { workspace = true }
# Draws the VAPID private scalar. Backend selection is the final crate's job
# in this workspace, which for a native-only binary is the default one; the
# line matches `cratefield-kms` and `cratefield-push-auth`.
getrandom = { workspace = true }
toml = { workspace = true }
sha2 = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tracing = { workspace = true }
pollster = { workspace = true }
sea-query = { workspace = true }
cratefield-adapter-postgres = { workspace = true, optional = true }
# `push-send` only: the native runtime's reqwest client and its outbound
# policy. Native-only by construction (the crate refuses to compile on wasm),
# which is why it is optional and off by default.
cratefield-runtime-native = { workspace = true, optional = true }
# `net` and `time` on top of the workspace pin: reqwest needs the IO and
# timer drivers enabled, and `enable_all()` silently enables neither without
# them — a runtime that then panics on the first request.
tokio = { workspace = true, optional = true, features = ["net", "time"] }

[dev-dependencies]
# The push unit tests send through a scripted `HttpClient` rather than the
# network. Path-only: `cargo publish` resolves dev-dependencies against
# crates.io (the workspace manifest's note), and a path-only one is stripped
# from the packaged manifest.
cratefield-testing = { path = "../testing" }