An entity source. Given the Entity, every member it declares (fields,
relations, derived members) may be requested; given anything with a
name and fields, those fields. A request for anything else never
reaches read or authorize. Given only a name, every field passes.
A refusal of mutation, as a value of its declared Refusal: fail a
Source with it (yield* RemoteServer.refuse(SavePost, { _tag: 'Field', ... }))
and the client reads it, decoded, with Data.refusal. message is what a
person reads, beside it.
A refusal of who is asking: fail a Source with it
(yield* RemoteServer.forbid()) and the write never runs. reason, when
given, is what the person who asked reads; without it the refusal says
nothing of why. answer sends it as a 403, and the client's mutation
fails with _tag: 'Forbidden'.
A refusal of a caller who could not be told: a serveFetch or
defineDocumentHost resolver fails with it (RemoteServer.unauthenticated())
when the credential it was sent no longer holds. It answers 401, with
reason, when given, for the person who asked.
The Source of a mutation that is a declared Write, with no handler: the
input bound to the write lands through writer, and the row as written
answers as a patch (a deletion as deleted). An update writes only the
keys the client named, when it named some, and fails for a row that is not
there; an insert of an id already holding what it writes (a retry)
answers with that row, and of one holding anything else fails; a delete of
a row already gone succeeds. A row that moved past the revision the write
expects is refused as a conflict.
A LiveHub over entity sources. Pass it to handlers as live, and every
mutation's answered patches and deletions are published to it; call
hub.changed(ref, fields) yourself only for a write that is not a
mutation (a database trigger, a job). Each subscriber that selects any of
those fields receives them, re-read through the entity source under its
own principal.
Checks every source name against the declared domain, so an undeclared
entity/query/mutation fails at startup rather than returning nothing at
call time.
Reads entity requirements through the entity sources, level by level,
following relations as FoldkitRemoteRead does. Shared by the read
handler and the query handler's payload: a query page's items are just
requirements the page names, so one response carries both.
Answers one JSON request through handlers: what an HTTP endpoint, a
worker or a server in the page calls with the body it received, parsed.
The request and its payload are decoded by the protocol's own schemas
before a handler sees them, so an operation name is one of Remote's three
and nothing else. A body that is not a request is a 400; a caller who
could not be told a 401; a refusal of who is asking a 403; a handler's
failure a 500 with its message; a defect a 500 that says nothing of it.
Remote.json and Remote.http are the other end.
Compiles the server into Remote's RPC handlers, answering as principal:
a value, or a Context key (G.Principal) read on each call, which
authentication provides per request. Unknown entities, entities with no
allowed fields, and unknown mutations return an error or nothing rather
than leaking existence.