codewandler-connector-catalog-reader 0.26.0

Dependency-free reader for the flux-connectors catalog pack: every connector's canonical document in one embedded, versioned, digest-checked file.
Documentation

codewandler-connector-catalog-reader

Dependency-free reader for the flux-connectors catalog pack — every connector's canonical document, compiled into one embedded, versioned, digest-checked file.

The pack is built by flux-connectors build from the reviewed per-provider documents (catalog/<name>.catalog.json). This crate embeds the pack that matches its own release and serves it with zero non-optional dependencies: no JSON parser, no compression codec, no hash crate — the container is offset-indexed UTF-8 and the SHA-256 check is vendored.

[dependencies]
codewandler-connector-catalog-reader = "0.26"

The library name is catalog_reader:

// The embedded pack: the catalogue this crate was released with.
let zendesk = catalog_reader::provider("zendesk").expect("shipped provider");
let document: &str = zendesk.document(); // canonical JSON, byte for byte

let show = catalog_reader::operation("zendesk-ticket-show").expect("shipped operation");
assert_eq!(show.provider(), "zendesk");
let record: &str = show.record(); // the operation's own JSON object

// A newer catalogue than this crate was built with, from a file:
let pack = catalog_reader::Pack::load("catalog.pack")?;
assert!(pack.provider("zendesk").is_some());
# Ok::<(), catalog_reader::Error>(())

Records are canonical JSON text — bring whatever JSON parser you already have. Pack::load refuses a wrong container version, a wrong document schema version, or a digest mismatch before serving a single record, each by name.

Fetching a newer catalogue than the crate embeds

Every vX.Y.Z release of flux-connectors carries the pack of that release as two assets, attached by the release workflow rather than by hand:

https://github.com/codewandler/flux-connectors/releases/download/vX.Y.Z/catalog.pack
https://github.com/codewandler/flux-connectors/releases/download/vX.Y.Z/catalog.pack.sha256

So a consumer with no Rust toolchain and no clone fetches the catalogue with curl, and one that has this crate loads the fetched file. Verify out of band first:

$ base=https://github.com/codewandler/flux-connectors/releases/download/vX.Y.Z
$ curl -fsSLO "$base/catalog.pack" -O "$base/catalog.pack.sha256"
$ sha256sum -c catalog.pack.sha256
catalog.pack: OK

catalog.pack.sha256 is one line of sha256sum output over the whole asset, and the digest in it is the value the release tag's connectors.lock [pack] row records. The workflow computes it from the committed pack at the tag and fails rather than attaching a pack whose digest disagrees, so the check above is against the number the repository published — not one the file asserts about itself. Assets are the byte-identical committed pack; nothing is repacked or recompressed on the way out. They exist for every release from v0.22.0 on.

Then, in band, once:

let pack = catalog_reader::Pack::load("catalog.pack").expect("a verified pack");
let zendesk = pack.provider("zendesk").expect("shipped provider");

Pack::load verifies before it serves a single record, and every refusal is a named variant of Error:

  • UnsupportedFormat { found } — the pack declares a container format newer than this reader implements. Upgrade the reader; the file is not corrupt.
  • UnsupportedSchema { found } — the pack's documents carry a schema version this reader does not serve. It fails closed rather than handing out records it cannot vouch for.
  • DigestMismatch { stated, computed } — the pack's header digest is not the digest of its own content: truncation, corruption or a hand edit.
  • NotAPack, NotText, Malformed(_), Io(_) — not a pack, not UTF-8, structurally not a version-1 pack, or unreadable.

Two digests, deliberately. The out-of-band one above covers the asset as a whole and belongs to the tag; the in-band one is a header line covering every byte after itself, which is why it is a different value and not comparable to the first. The pair is the point: a client checks before it parses, the reader checks before it serves, and both are checking bytes the same release produced. Neither is an authentication boundary — an author who can rewrite the payload can rewrite the digest line above it — so the out-of-band value is the one that lives outside the file, in the tag and its lockfile.

For the typed &'static catalogue API (providers(), operation(), risk and idempotency enums, embedded Flux), use codewandler-connector-catalog, which re-exports this crate as catalog::reader.

License: MIT OR Apache-2.0.