mero.admin (AdminApi) is the node’s /admin-api REST surface — the full set
of methods across applications, contexts, namespaces, groups, blobs, aliases,
capabilities, metadata, upgrades, and TEE. It’s a Sendable struct over the
shared HttpClient; every method is
async throws.
⚠️ identities-owned answers a different question depending on who asks: the
node’s own signing identities for a node-owner session, the calling account’s
certified devices for a delegated one. core 0.11.0-rc.41 added identitiesOf
(members / node / caller) so the response says which reading it is,
instead of leaving a caller to infer it from its own token. It is optional — a
node predating the field said nothing, and nil is the honest answer for one.
A variant this SDK does not recognise also decodes as nil rather than failing
the whole response: the identities are still the identities.
core 0.11.0-rc.21 gave a node one identity, one signing key and one root, and
rc.23 deleted the route that asked a namespace who it was. rc.28 then moved
device pairing off the namespace as well: a device pairs to an account once
and is linked into namespaces afterwards. Revocation stayed per-namespace,
because that is where the group key gets rotated.
⚠️ Since rc.27 removed base58, an account id and a device key are both 64
hex characters. getNodeIdentity() is the only thing that maps one to the
other, and it matters: every authorization subject is an account, while group
membership listings report devices. A device key handed to a role grant succeeds
and authorizes nobody.
rc.32 added NodeIdentity.holdsAccountRoot (core#3774): whether this node holds
the root key of the account it speaks for, and so whether it can certify another
device into that account. It is not “does this node have a root” — a paired node
has one of its own and still answers false, because the account it speaks for
is rooted elsewhere. The field is defaulted, so a response from an older node
decodes as false rather than failing.
rc.41 added NodeIdentity.revokedFrom: which account withdrew this node’s
device, and which device it was. Absent on a node no revocation has reached —
skipped rather than sent as null — so it is worth checking before reporting a
node as merely unauthorized. A device its account revoked is not a login
problem.
rc.41 also gave a device a name. AccountDeviceEntry.label is the
replicated name the account gave it (every device of the account reads the same
one), and labelDevice sets it. rescopeDevice is the counterpart to
relinkDevice, which is add-only: it REPLACES the scope, so an application can
be taken away again. DeviceScope is tagged — "all" or {"only": [...]} —
rather than a list whose emptiness means everything, so the slip a caller can
make is never silently the widest ask; an only naming nothing is a 400.
Read descoped[].keyRotated before calling a narrowing done: false means the
device stopped writing there but still holds the key it had, until an admin
rotates.
⚠️ Name the context. core 0.11.0-rc.39 removed blob discovery from the DHT,
so context_id is now the only way to find a blob a peer holds. Without it
getBlob and getBlobInfo see this node’s local store and nothing else, and
answer 404 for a blob that plainly exists on the node next to it. The parameter
is optional in the type and effectively required in practice.
Discovery is a probe sweep with a 30s deadline on the node’s side, so these
calls raise their own timeout when a context is named — a client timeout under
that aborts the sweep and reads as “no such blob” rather than as a timeout.
rc.41 added X-Blob-Source to the HEAD, surfaced as
GetBlobInfoResponseData.source. local means this node holds the blob and
every field is its own; peer means only a context peer does, so hash and
mimeType are absent — both are derived from bytes this node does not have,
and a HEAD never transfers the blob to find out — and size is that peer’s
word, verified by nobody. size is also optional: a peer that reported none
omits Content-Length, and “exists, size unknown” is true where 0 would be a
lie about a blob that exists.
An alias scopes to a device, and a listing comes back as a map keyed by alias
name (ListAliasesResponseData.entries, with .aliases for a name-sorted array).
The four …ContextIdentityAlias methods this table used to list called
/alias/*/identity/…, which no released node serves — a live 0.11.0-rc.32
answers all four with 404.