Context
An operation’s implementation receives plain values: input, state, and one more argument, the context. The context is the only way an operation reaches anything beyond its own input and state. Whatever the implementation needs from the platform, it asks the context for.
§What it provides
Calls. context.remote addresses other components; context.local addresses the
operation’s own component. Both are described in Calls.
Configuration. A component declares the configuration it needs as a schema with defaults. The values arrive through the context, already validated:
configuration:
schema:
type: object
properties:
limit: { type: integer }
defaults:
limit: 5000 export async function observation (input: Input, entry: Entity, context: Context) {
return entry.total <= context.configuration.limit
} Where the values come from — a default, an environment-specific override, a secret, a change made while the application is running — is outside the operation.
Values the runtime owns. context.id(), context.now(), and context.random() supply a
new identifier, the current time, and a random number. Taking them from the context instead of
from the language keeps them among the things the runtime can see and, where needed, reproduce.
Where it runs. The context names the deployment environment and the application, for the rare logic that depends on them.
§Aspects
Extensions add capabilities to the context. Each one appears as an aspect: a named member of the context. Some are present for every component; others a component asks for in its manifest.
# manifest.toa.yaml
stash: ~ export async function computation (input: Input, context: Context) {
return await context.stash.get(input.key)
} The aspects supplied with the runtime include:
| Aspect | Provides |
|---|---|
configuration | The component’s configuration values. |
logs | Structured logging. |
fetch | HTTP requests to systems outside the application. |
stash | A cache shared by the component’s replicas. |
storages | Storage for binary objects. |
state | Memory that belongs to one process of the component. |
atom | Decisions the replicas of a component make together, such as locks. |
delay | Calls handed over to be made later. |
An operation uses an aspect without knowing what stands behind it. Which cache server, which object store, and which credentials are declared for the application as a whole, in its Context.
§Why one door
An operation could, technically, import an HTTP client or open a socket of its own. The model asks it not to, and the reason is the same trade that runs through the rest of the runtime.
The runtime can only take responsibility for what it can see. A call made through the context is traced, attributed to the request that caused it, checked against the callee’s contract, and counted in the application’s topology. It can be refused when the request may only read, repeated safely where the runtime knows its identity, and given back from a record when an interrupted operation is resumed. A call made around the context has none of this.
The manifest stays truthful. Because capabilities are requested by declaration, a component’s manifest shows what it depends on. The platform knows what to provision, and a reader knows what the component can touch.
The implementation stays portable. Nothing in the operation names a host, a driver, or a credential. The same code runs in a test, on a developer’s machine, and in production, with the context supplying a different world each time.
The context is therefore not a utility bag. It is the boundary of product–platform separation as seen from inside an operation: on one side, business logic; on the other, everything that carries it out.