Anytype gRPC client
The gRPC api isn't officially supported (by Anytype) for third party clients. However, it's used heavily by Anytype applications, including the desktop app and headless cli, and it's the only way for applications to access certain functionality that is not available over the HTTP api, such as Files, Chats, Blocks, and Relations.
Before using this crate, check whether anytype and its AnytypeClient interface meets your needs.
AnytypeClient's api:
- has a more ergonomic, hand-designed api surface.
- uses HTTP/REST for most (>90%) apis, as recommended by the Anytype team, only using gRPC backend (through this crate) to fill gaps.
- will be more stable across releases. This crate's api is automatically generated from the anytype-heart protobuf definitions.
Compatibility
| anytype-rpc version | anytype-heart version |
|---|---|
| 0.5.0 | 0.50.10 |
| 0.3.0 – 0.3.1 | 0.48.0 |
| 0.2.1 | 0.44 |
Logical deadlines
AnytypeGrpcClient applies a resolved GrpcTimeoutPolicy to generated RPCs.
The default boundaries are 120 seconds for credential setup and ordinary
unary calls, 30 minutes for long imports, exports, uploads, and downloads, 120
seconds through streaming response headers, and five seconds for cleanup.
Established-stream idle and total-lifetime boundaries are disabled by default.
Policy resolution has three modes:
- An explicit
AnytypeGrpcConfig::grpc_timeoutspolicy wins and ignores the process environment. EachNonefield disables that boundary. - Without an explicit policy,
ANYTYPE_GRPC_TIMEOUT_SECS=1..3600gives credential, ordinary, long, and stream-setup calls one inherited value;0disables those four boundaries. In either case, established-stream idle and lifetime remain disabled and cleanup retains its five-second default. - Without either setting, the defaults above apply.
Finite credential, ordinary, stream-setup, idle, and lifetime values must be one through 3,600 seconds. Long unary values may be as high as 7,200 seconds; cleanup may be at most 30 seconds. The environment value must be an exact ASCII decimal with no sign, whitespace, or leading zero. Invalid policy or environment values fail before connection activity.
Generated methods are classified as credential, ordinary, long, stream setup,
or cleanup operations. An unknown generated RPC is conservatively treated as
an ordinary mutation. Reads that expire are reported as aborted, mutations
that may have reached Heart are indeterminate, and established-stream expiry
terminates the stream. Inspect the typed GrpcDeadlineError class, outcome,
source, and elapsed time. A transport failure is consumed after conversion: the
wrapper retains its error-type marker and closed tonic status code, but not the
original error value or payload. Standard source traversal returns a synthetic
status containing that code and fixed redacted text.
The effective boundary is the earliest of the selected policy duration, an
absolute GrpcEnclosingDeadline, and an existing, tighter grpc-timeout. It
includes service readiness, and the remaining budget is propagated after
readiness. StreamSetup is intentionally different: the library profile is a
local response-header/setup boundary and is not sent as grpc-timeout, because
tonic applies that header to the whole stream. Only a caller-supplied
whole-call grpc-timeout is propagated for this class, with its remaining
absolute budget reduced by readiness time; the library setup and enclosing
budgets remain local to response setup.
scope_grpc_enclosing_deadline installs an absolute task scope for composed
workflows. Generated calls made inside that scope take its minimum with their
explicit options and policy profile, so retries and later calls cannot mint a
fresh workflow budget. Channel connection keeps its separate fixed 30-second
boundary. Higher-level applications should normally use
anytype::scope_grpc_deadline and retain the documented crate dependency
direction.
When idle or lifetime limits are enabled, GrpcStreamDeadline observes raw,
nonempty HTTP data frames before tonic decodes a message. Such progress resets
idle; empty frames do not, and neither progress nor reconnect resets total
lifetime or an enclosing deadline. Reconnect backoff, resubscription, and
caller-provided replay work can remain inside those absolute bounds.
client_commands() returns generated clients over the deadline-aware
AnytypeGrpcService; deadline_channel() exposes a clone of that service for
other generated clients. channel() remains a raw tonic::transport::Channel
for compatibility. Calls made through the raw channel bypass this logical
policy, and a disabled boundary is unbounded unless the caller supplies a
separate timeout.
Related projects
-
anytype An ergonomic Anytype API client in Rust. Includes http rest api plus gRPC backend using this crate, for access to Files and Chats.
The dependency remains one-way:
anytypeusesanytype-rpc; this crate does not depend onanytype. -
anyr a CLI tool for listing, searching, and performing CRUD operations on anytype objects. via
anytype, also includes operations on Files and Chats.
Building
config::load_headless_config reads the account fields used for gRPC
authentication from an explicit path or the default
~/.anytype/config.json. It returns None only when the file is absent;
unreadable and malformed files are errors.
For normal builds, you need a rust toolchain. protoc is not required, as the crate ships with generated Rust sources in src/gen.
cargo build
To regenerate src/gen from anytype-heart's protobuf files, you need
protoc(from the protobuf package)just(to run the justfile recipe)curl,tarandbash
just gen-protos
By default, this uses the develop branch. You can also pull from a specific git branch, tag, or commit:
just gen-protos ref=develop
just gen-protos ref=0.50.10
just gen-protos ref=abcdef123
Each generated source records the UTC generation date and the requested ref.
An unprefixed release version such as 0.50.10 resolves the corresponding
Anytype Heart v0.50.10 tag.
License
Apache License, Version 2.0