Calls
A component calls another component’s operations through context.remote. Calls use logical
addresses, so the caller does not need to know where the other component runs.
An address is the component’s name followed by the endpoint: orders.reduce. A component may
belong to a namespace, which groups related components and becomes the first part of the
address: an invoices component in the billing namespace is called as context.remote.billing.invoices.issue.
§Input/Query Segregation
A component implements an operation; the caller determines which entity data it applies to and supplies its arguments. These are separate parts of a call:
- Query selects the entity data.
- Input carries the arguments of the operation.
Suppose the orders component implements an operation that reduces an order’s total:
export async function transition (input: Input, entry: State) {
if (input.amount > entry.total)
return new Error('AMOUNT_EXCEEDS_TOTAL')
entry.total -= input.amount
} A call to this operation looks like this:
await context.remote.orders.reduce({
query: { id: orderId },
input: { amount: 500 }
}) An endpoint is a named operation exposed by a component. Here, reduce is an endpoint of orders, addressed as orders.reduce.
The runtime uses the query to retrieve the order and passes its state alongside the input to the implementation. The order identifier does not have to become part of the operation’s input contract merely to locate its state.
§Input
Each operation declares the shape of its arguments with an input schema:
operations:
reduce:
type: transition
input:
type: object
properties:
amount:
type: integer
minimum: 1
required: [amount] The runtime validates the input before executing the operation. A missing amount, a fractional value, or a value below one is rejected without running the implementation.
The schema describes valid arguments. Rules that depend on current entity state remain in the
operation: the runtime can check that amount is a positive integer, while reduce checks that
it does not exceed the selected order’s total.
§Query
A query selects data within the operation’s declared scope: one entity object, a set, or a
stream. It can select by identity (id or ids) or filter entity properties through criteria.
It can also order the selection with sort and, for observations, choose the state properties
supplied to the operation with projection.
Criteria use RSQL: == tests
equality, >= compares values, ; joins conditions with AND, and , joins them with OR.
Parentheses group conditions.
For example, a call to an observation over a set of orders can select a page of pending orders:
const orders = await context.remote.orders.enumerate({
query: {
criteria: 'status==pending;total>=1000',
sort: ['total:desc', 'id:asc'],
omit: 20,
limit: 10
}
}) The query selects pending orders with a total of at least 1000, orders them by descending total
and then by identity, skips the first 20, and supplies at most 10 to the observation. The enumerate operation returns the selected entries.
omit and limit apply to the entity selection, not to the operation’s eventual reply. Their
availability depends on the operation’s scope, not on its type:
- An operation over a set (
scope: entries) — an observation, a transition or an effect — is called with theidsof its set, or with alimiton what itscriteriaselect. A call with neither is refused: a set is loaded whole, so every set is bounded. omitskips entities of an ordered selection, so it is refused withoutsort: pages of an unordered set repeat and miss entities.- A stream accepts
limitto bound a window but does not acceptomit; continuation uses a token. Whenlimitor a token is supplied, sorting is restricted toidandCREATED. - An operation over one entity accepts neither, and neither does an assignment: its changeset is written to whatever its query selects.
limit is a positive integer and omit a non-negative one. The runtime validates the query
against the operation’s contract before executing it.
§Local calls
A local call is the same kind of operation call addressed to the caller’s own component. context.local supplies that address implicitly:
await context.local.reduce({
query: { id: orderId },
input: { amount: 500 }
}) Within orders, this calls its own reduce endpoint. Input validation, query selection, and
the operation’s execution phases still apply; it is not a direct invocation of the function.
§Calls nobody waits for
Every call above waits for its reply. A call can also be handed over as a task: it is accepted, kept, and run later, and its caller carries on without an answer. Tasks describes what that changes.