Breaking changes
- A record type is named after the call that read it.
ListInboxEmailsEmail
isListInboxEmailsFetchEmail, after the call idfetch. The types were
numbered by the position of the call, so inserting a call moved a name onto a
different shape, which the build reported only where the two shapes differed
enough to stop compiling. Every generated record type is renamed by this, in
Go, Rust and TypeScript. (#64) - The filter of a
/queryis a typed union rather thanany. It is a
FilterOperatorOrEmailFilterCondition, a struct with one field per shape, of
which exactly one is set. Code that built a/queryor/queryChanges
arguments struct by hand has to name the shape it is passing.
(#58)
Added
WithObserverreports what the client does, for logging, metrics and
tracing. Three hooks that nest: one JMAP request, each HTTP request under it,
and each delay for a concurrency slot or before a retry.SlogObserver
writes them to aslog.Logger, and the hooks return the context their work
runs under, so a tracer can nest its spans the same way. Nothing depends on
OpenTelemetry. (#59)WithTokenSourceauthenticates with a token that expires. The client
calls the source when it has no token, shortly before the one it holds
expires, and when a server answers 401; requests arriving together share one
call, since some servers accept a refresh token only once. A 401 sends that
one request again, once, with a newly fetched token.
(#61)WithSplitGetssends a/getholding more ids thanmaxObjectsInGetin
several requests and joins the answers into one response. It is off by
default: the round trips multiply, and the records are no longer one
snapshot, so astatethat differs between requests is reported as a
*StateChangedalongside the joined response.
(#62)- A blob download can ask for part of a blob.
DownloadOptions.Fromand
Lengthare sent as an HTTPRange, which is how a download interrupted
part way is resumed, andBlob.Rangereports what came back. A server that
ignores the range fails the download rather than returning the whole blob to
a caller writing at an offset.
(#63) - The CLI help opens with a banner: the name in ASCII, in green, and under
it one line saying what jmapc is and where it lives. Neither is coloured
where the output is not a terminal orNO_COLORis set.
(#65)
Documentation
- The prose was rewritten in plain English. It attributed intent and speech
to programs — a client "asking to be refused", a server "telling the caller
to come back later" — which is not how technical documentation reads. The
README, the package documentation, the comments, and the documentation the
generator writes into every generated client all state what happens instead.
(#60) - The three languages are listed in one order everywhere, Go, Rust,
TypeScript, including the order the README's sections come in.
(#66)
Install
The generator is a Go tool, and what it generates is Go, so the usual way is to
record it in the module that uses it:
go get -tool github.com/linyows/jmapc/cmd/jmapc@v0.12.0
Binaries are attached below for anyone without a Go toolchain.