greentic-distributor-client
WIT-based client for the greentic:distributor-api@1.0.0 world. Provides:
DistributorClientasync trait for resolving components, querying pack status, and warming packs.WitDistributorClientadapter that translates DTOs togreentic-interfaces-guestdistributor-api bindings; useGeneratedDistributorApiBindingson WASM targets to call the distributor imports.- Optional HTTP runtime client behind the
http-runtimefeature for JSON endpoints that mirror the runtime API. greentic-distCLI (featuredist-cli) for resolving/pulling components into a shared cache, plus a libraryDistClientAPI for pack/runner integration.
Uses DTOs from greentic-types.
Usage
use ;
use json;
let bindings = default;
let client = new;
let resp = client.resolve_component.await?;
println!;
println!;
GeneratedDistributorApiBindings calls the distributor imports on WASM targets. On non-WASM targets it returns an error; consumers can provide their own bindings implementation for testing.
secret_requirements is present when talking to distributor versions that support it; otherwise it is None. When requirements are returned, run greentic-secrets init --pack <pack-id> ahead of time so secrets are available to the runtime.
HTTP runtime client (feature http-runtime)
Enable the feature and construct HttpDistributorClient:
[]
= { = "0.4", = ["http-runtime"] }
use ;
use json;
let config = DistributorClientConfig ;
let client = new?;
let resp = client.resolve_component.await?;
println!;
println!;
Fetch typed pack status (includes secret requirements):
let status = client
.get_pack_status_v2
.await?;
println!;
greentic-dist CLI (feature dist-cli)
Build with the CLI feature to get the greentic-dist binary:
Commands:
resolve <REF>: print digest (use--jsonfor structured output).pull <REF>: ensure cached; prints path. Use--lock <pack.lock>to pull all components from a lockfile.cache ls|rm|gc: list cache entries, remove entries through retention-aware eviction, or clean orphaned cache state.auth login <tenant> [--token <token>]: save GHCR auth forstore://greentic-biz/<tenant>/...; if--tokenis omitted, the CLI prompts without echoing the token.
Control cache location with --cache-dir or GREENTIC_DIST_CACHE_DIR; defaults to ${XDG_CACHE_HOME:-~/.cache}/greentic/components/<sha256>/component.wasm. Set GREENTIC_SILENCE_DEPRECATION_WARNINGS=1 to silence the temporary greentic-distributor-client shim binary warning.
Exit codes:
0success2invalid input (bad ref/lockfile/missing args)3not found (cache miss)4offline blocked (network needed)5auth required/missing credentials (repo://, store://)10internal error
Library API (feature dist-client)
Use DistClient to reuse the same resolution and cache logic programmatically. The dist-client feature also includes the OCI pack fetcher APIs (fetch_pack, OciPackFetcher).
OciPackFetcher accepts the default Greentic pack media types plus opaque tarball-style OCI layer media types ending in +tar, +tar+gzip, or +tar+zstd. Downstream clients can append exact custom layer media types through PackFetchOptions::add_accepted_layer_media_type(...) without copying the default allowlist, which is also exposed via default_pack_layer_media_types().
For callers that prefer the crate-level helpers over constructing OciPackFetcher directly, use fetch_pack_with_options(...) or fetch_pack_to_cache_with_options(...). Test-only or advanced integrations can also inject a custom registry client through fetch_pack_with_options_and_client(...) / fetch_pack_to_cache_with_options_and_client(...).
The canonical PR-01 flow is:
- build an
ArtifactSource - call
resolve(...)to get anArtifactDescriptor - call
fetch(...)to materialize a localResolvedArtifact - later call
open_cached(...)orstat_cache(...)using the digest/cache key
use ;
let client = new;
let source = ArtifactSource ;
let descriptor = client.resolve.await?;
let resolved = client.fetch.await?;
let reopened = client.open_cached?;
println!;
println!;
Compatibility helpers like resolve_ref(...) and ensure_cached(...) still exist, but the digest-first descriptor/fetch/open flow is now the authoritative contract.
The cache entry format is now persisted alongside fetched artifacts as a versioned entry.json record under a digest-keyed cache tree.
The embedded lifecycle contract also exposes:
stage_bundle(...)to resolve, fetch, verify, and persist a stablebundle_idwarm_bundle(...)to reopen cached artifacts, rerun verification, and hand off to anArtifactOpenerrollback_bundle(...)to reopen a previously staged bundle bybundle_idwithout network accessstat_bundle(...)/list_bundles(...)to inspect the persisted localbundle_id -> cache_key/canonical_refreopen indexset_bundle_state(...)to transition bundle records betweenstaged,warming,ready,draining, andinactiveevaluate_retention(...)/apply_retention(...)for deterministic GC decisions that protect active/session/rollback-relevant bundles
That means the production-safe offline path is now:
stage_bundle(...)- persist the returned
bundle_idandcanonical_refin operator state warm_bundle(...)for readiness checks and open-mode handoffrollback_bundle(...)bybundle_idif a later activation must be revertedapply_retention(...)when the operator wants explainable cache GC
The persisted bundle index is now strict rather than fail-open:
- malformed bundle record files surface as cache errors
- automatic cache-pressure protection uses bundle lifecycle state, not just bundle existence
ArtifactOpener is intentionally format-neutral. greentic-distributor-client owns reopen/verification/cache concerns; the owning crate for the artifact format should provide the actual open/parse implementation.
Older cache helpers such as evict_cache(...), remove_cached(...), and gc() remain for compatibility, but they are now wrappers around or adjacent to the retention-aware cache lifecycle and should not be the primary production integration surface.
The public source model supports:
oci://...https://...file://...or existing local pathsfixture://...whenfixture-resolveris enabledrepo://...andstore://...as source kinds
repo://... is still a placeholder mapping source kind. store://greentic-biz/<tenant>/<package-path> maps to ghcr.io/greentic-biz/<package-path> and uses credentials saved with auth login <tenant>.
Compatibility-only example:
use ;
let client = new;
let resolved = client.ensure_cached.await?;
println!;
ResolvedArtifact now includes additive optional metadata:
describe_artifact_ref: Option<String>content_length: Option<u64>content_type: Option<String>
When describe_artifact_ref is present, it is advisory only. WASM describe() remains authoritative; downstream tools must verify any cached describe artifact against the wasm-derived describe_hash.
Integration examples
- Resolve a ref:
greentic-dist resolve oci://ghcr.io/greenticai/components/hello-world:1 - Pull everything from a lockfile:
greentic-dist pull --lock pack.lock.json - Offline workflow:
greentic-dist pull --lock pack.lock.jsonthengreentic-runner run mypack.gtpack --offline
Using greentic-config-types (host-resolved config)
Resolve configuration in your host binary with greentic-config and map it into the distributor client with DistributorClientConfig::from_greentic:
use GreenticConfig;
use ;
let cfg: GreenticConfig = /* resolved in the host via greentic-config */;
let tenant = new;
let mut client_cfg = from_greentic
.with_base_url; // host still provides the endpoint/auth
// pass client_cfg to your chosen DistributorClient implementation
Local dev distributor
Use the companion greentic-distributor-dev crate to serve packs/components from a local directory, useful for greentic-dev and conformance tests:
use ;
use ;
let dev_source = new;
let sources = new;
let pack_bytes = sources.fetch_pack;
println!;
Repo maintenance
- Enable GitHub's "Allow auto-merge" setting for the repository.
- Configure branch protection with the required checks you want enforced before merges.