jmap-cid-types 0.1.1

JMAP Blob Content Identifiers extension data types (draft-atwood-jmap-cid-00)
Documentation
  • Coverage
  • 100%
    16 out of 16 items documented2 out of 6 items with examples
  • Size
  • Source code size: 56.68 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 687.55 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 8s Average build duration of successful builds.
  • all releases: 13s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • MarkAtwood/crate-jmap
    1 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • MarkAtwood

jmap-cid-types

draft-atwood-jmap-cid-00 wire-format types for the jmap-* crate family.

The urn:ietf:params:jmap:cid JMAP capability plus the sha256 typed string shape used in blob upload responses and FileNode objects.

What it is

When a server advertises urn:ietf:params:jmap:cid, blob upload responses (RFC 8620 §6.1) carry a sha256 field with the SHA-256 digest of the uploaded content, encoded as a lowercase hexadecimal string of exactly 64 characters. When the JMAP FileNode extension is also advertised, FileNode objects gain the same sha256 property.

This crate carries the typed sha256 wire shape ([Sha256]) plus the matching parse-error type ([Sha256DigestError]). Wiring the shape into the Blob upload response surface and Session capability detection happens in jmap-base-client.

Why a separate crate

CID is not tied to any single consumer extension. The sha256 field is referenced by draft-atwood-jmap-chat-00 (which defers to the CID document as the normative definition), and the spec is structured to fold cleanly into a future RFC 8620 bis or draft-ietf-jmap-filenode. Standing CID up as its own crate keeps the dep graph honest and avoids forcing a jmap-chat-* or jmap-filenode-* dependency on consumers that only want content identifiers.

What it's for

The typed wire shape here is consumed by jmap-base-client for the BlobUploadResponse.sha256 field and the Session::supports_cid() helper (both landed in jmap-base-client), and by a future jmap-filenode-types revision for the FileNode sha256 property. The CID document — capability URI urn:ietf:params:jmap:cid, draft owned by Mark Atwood — is deliberately independent of any single consumer extension because the same content-hash field feeds Blob upload responses, FileNode integrity, and the JMAP Chat draft's attachment references.

How to use

[dependencies]
jmap-cid-types = "0.1"

Pulls in serde and serde_json at runtime. No async runtime, no jmap-types, no jmap-server, no jmap-base-client. Parse and validate a sha256 digest from a wire string:

use jmap_cid_types::Sha256;

// 64 lowercase hex characters per draft-atwood-jmap-cid-00 §2.
let digest: Sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
    .parse()?;
assert_eq!(digest.as_ref().len(), 64);
# Ok::<(), jmap_cid_types::Sha256DigestError>(())

Use Sha256::from(&[u8; 32]) (or Sha256::from([u8; 32]) for an owned array) to build a digest from the raw 32-byte output of a SHA-256 hash function (e.g. sha2::Sha256) without going through a hex string. The capability URI "urn:ietf:params:jmap:cid" is detected via the Session.capabilities map in jmap-base-client.

How it works

  • [Sha256] is a String-backed newtype with parse-time ABNF validation per the draft sha256-value rule (64( %x30-39 / %x61-66 )): exactly 64 characters, lowercase hex only. Validation runs on from_hex, TryFrom<&str>, FromStr, and the Deserialize impl.
  • From<[u8; 32]> / From<&[u8; 32]> for Sha256 build a digest infallibly by formatting the raw 32-byte SHA-256 output as lowercase hex; no parse step is needed because the output is always valid by construction. The input is the output of a hash function (e.g. sha2::Sha256::digest(data).into()) — this crate carries no hash computation.
  • The error type [Sha256DigestError] is a single-tier enum (WrongLength { got } or NonHexLowercase { at, byte }) with #[non_exhaustive] at the type level and per-variant #[non_exhaustive] so variant additions and per-variant field additions both remain semver-additive. Diagnostics carry byte position so callers can point at the bad byte without re-indexing the input.
  • #[non_exhaustive] on every public struct and enum, so additive spec evolution stays a non-breaking change.
  • No async. #[forbid(unsafe_code)] at the crate root.
  • Runtime dependencies limited to serde and serde_json (the latter for the CidCapability.extra Map<String, Value> surface per workspace extras-preservation policy).

Gotchas

  • Blob upload-response and Session-capability wiring live in jmap-base-client, not here. jmap_base_client::blob::BlobUploadResponse.sha256: Option<jmap_cid_types::Sha256> is the typed binding for the upload-response sha256 field; Session::supports_cid() is the helper that checks the capability map. This crate is the wire-shape source of truth; the binding lives one layer up.
  • CID and the RFC 9404 BLOBEXT Blob/get digest:sha-256 request are deliberately separate mechanisms with different encodings (lowercase hex vs base64) and different access patterns (unconditional at upload vs on-demand via Blob/get). See the draft §2.3.

References

  • draft-atwood-jmap-cid-00 — JMAP Blob Content Identifiers (normative for Sha256 and the urn:ietf:params:jmap:cid capability)
  • RFC 8620 — JMAP Core (Blob upload §6.1 is the binding point)