docs(wit): document capability and component contracts
This commit is contained in:
@@ -1,9 +1,16 @@
|
||||
package wasmeld:clock@0.1.0;
|
||||
|
||||
/// Actor-local monotonic time for measuring elapsed durations.
|
||||
interface monotonic-clock {
|
||||
/// Returns nanoseconds elapsed since this Actor Store was created.
|
||||
///
|
||||
/// The value is monotonic and saturates at `u64::MAX`. It is not Unix time,
|
||||
/// cannot be compared across Actor restarts, and must not be persisted as a
|
||||
/// wall-clock timestamp.
|
||||
now: func() -> u64;
|
||||
}
|
||||
|
||||
/// Host-side world used by Wasmeld to link the clock implementation.
|
||||
world clock-host {
|
||||
import monotonic-clock;
|
||||
}
|
||||
|
||||
@@ -1,17 +1,37 @@
|
||||
package wasmeld:kv@0.1.0;
|
||||
|
||||
/// Small persistent byte-value store scoped to the stable service ID.
|
||||
///
|
||||
/// Revisions of the same service share a namespace, so a deployment change
|
||||
/// preserves values. Keys are non-empty UTF-8 strings of at most 256 bytes and
|
||||
/// values are at most 64 KiB in this version of the Host implementation.
|
||||
/// Operations are not multi-key transactions.
|
||||
interface store {
|
||||
/// Expected validation or backend failures.
|
||||
variant kv-error {
|
||||
/// The key is empty or exceeds the Host byte limit.
|
||||
invalid-key(string),
|
||||
/// The attempted or stored value exceeds the Host byte limit.
|
||||
value-too-large(u64),
|
||||
/// Persistence failed, timed out, or was temporarily unavailable.
|
||||
///
|
||||
/// A timeout is not cancellation: a mutation may finish after the caller
|
||||
/// receives this error. Retried `set` and `delete` operations should be
|
||||
/// idempotent.
|
||||
operation-failed(string),
|
||||
}
|
||||
|
||||
/// Returns the current value, or `none` when the key does not exist.
|
||||
get: func(key: string) -> result<option<list<u8>>, kv-error>;
|
||||
|
||||
/// Creates or replaces one value.
|
||||
set: func(key: string, value: list<u8>) -> result<_, kv-error>;
|
||||
|
||||
/// Removes one value; deleting a missing key succeeds.
|
||||
delete: func(key: string) -> result<_, kv-error>;
|
||||
}
|
||||
|
||||
/// Host-side world used by Wasmeld to link persistent KV.
|
||||
world kv-host {
|
||||
import store;
|
||||
}
|
||||
|
||||
@@ -5,43 +5,61 @@ package wasmeld:resident@0.1.0;
|
||||
/// and all operating-system handles. A Component handles one bounded event and
|
||||
/// returns effects before control goes back to the Runtime.
|
||||
interface actor {
|
||||
/// Opaque, nonzero identity allocated by the Host for one resident session.
|
||||
///
|
||||
/// IDs are scoped to one service revision and session. They are never OS
|
||||
/// handles, must not be guessed, and become invalid after Host release.
|
||||
type resource-id = u64;
|
||||
|
||||
/// One occurrence of a previously registered and armed timer.
|
||||
record timer-fired {
|
||||
timer-id: resource-id,
|
||||
/// Driver monotonic deadline in nanoseconds, not wall-clock time.
|
||||
scheduled-at-ns: u64,
|
||||
}
|
||||
|
||||
/// A stream accepted by a previously registered TCP or Unix endpoint.
|
||||
record stream-opened {
|
||||
endpoint-id: resource-id,
|
||||
stream-id: resource-id,
|
||||
/// Driver-formatted peer address when the transport provides one.
|
||||
peer: option<string>,
|
||||
}
|
||||
|
||||
/// One bounded read chunk. Chunk boundaries are not message boundaries.
|
||||
record stream-chunk {
|
||||
stream-id: resource-id,
|
||||
bytes: list<u8>,
|
||||
}
|
||||
|
||||
/// Terminal reason reported by the Host driver.
|
||||
enum close-reason {
|
||||
/// The peer closed the transport normally.
|
||||
peer-closed,
|
||||
/// The platform or Component requested closure.
|
||||
host-closed,
|
||||
/// The configured inactivity deadline elapsed.
|
||||
idle-timeout,
|
||||
/// Protocol validation failed above the transport layer.
|
||||
protocol-error,
|
||||
/// The operating-system transport returned an error.
|
||||
transport-error,
|
||||
}
|
||||
|
||||
/// Final event for a stream identity.
|
||||
record stream-closed {
|
||||
stream-id: resource-id,
|
||||
reason: close-reason,
|
||||
}
|
||||
|
||||
/// One UDP datagram. A datagram is never split across events.
|
||||
record datagram {
|
||||
endpoint-id: resource-id,
|
||||
peer: string,
|
||||
bytes: list<u8>,
|
||||
}
|
||||
|
||||
/// One delivery from a Host-owned broker or internal queue.
|
||||
record message {
|
||||
subscription-id: resource-id,
|
||||
message-id: u64,
|
||||
@@ -59,65 +77,107 @@ interface actor {
|
||||
}
|
||||
|
||||
variant event {
|
||||
/// A registered timer reached its monotonic deadline.
|
||||
timer(timer-fired),
|
||||
/// A Host driver accepted a new stream.
|
||||
stream-opened(stream-opened),
|
||||
/// A stream produced one bounded read chunk.
|
||||
stream-data(stream-chunk),
|
||||
/// The driver can accept writes after previous backpressure.
|
||||
stream-writable(resource-id),
|
||||
/// The peer closed its write half; local writes may still be valid.
|
||||
stream-half-closed(resource-id),
|
||||
/// The stream is terminal and its identity will be released.
|
||||
stream-closed(stream-closed),
|
||||
/// A UDP endpoint received one datagram.
|
||||
datagram(datagram),
|
||||
/// A subscription delivered one message.
|
||||
message(message),
|
||||
/// A separately versioned extension source produced an event.
|
||||
source(source-event),
|
||||
/// The session is stopping. No later events will be delivered.
|
||||
shutdown,
|
||||
}
|
||||
|
||||
/// Request to enqueue bytes for a stream driver.
|
||||
record stream-write {
|
||||
stream-id: resource-id,
|
||||
bytes: list<u8>,
|
||||
}
|
||||
|
||||
/// Request to send one datagram through a registered UDP endpoint.
|
||||
record datagram-send {
|
||||
endpoint-id: resource-id,
|
||||
peer: string,
|
||||
bytes: list<u8>,
|
||||
}
|
||||
|
||||
/// Request to arm or replace a registered timer schedule.
|
||||
record timer-arm {
|
||||
timer-id: resource-id,
|
||||
/// Delay from operation application, in milliseconds.
|
||||
delay-ms: u64,
|
||||
/// Optional repeating interval in milliseconds.
|
||||
interval-ms: option<u64>,
|
||||
}
|
||||
|
||||
/// Request to acknowledge a previously delivered message.
|
||||
record message-ack {
|
||||
subscription-id: resource-id,
|
||||
message-id: u64,
|
||||
}
|
||||
|
||||
/// Driver-specific command for a separately versioned extension source.
|
||||
record source-command {
|
||||
source-id: resource-id,
|
||||
command: string,
|
||||
payload: list<u8>,
|
||||
}
|
||||
|
||||
/// Host operations requested after handling one event.
|
||||
///
|
||||
/// Effects are declarations, not completed I/O. The Host validates the
|
||||
/// entire returned list before applying any item, then the external driver
|
||||
/// performs the operations in order.
|
||||
variant effect {
|
||||
/// Enqueue bytes for an open stream.
|
||||
write-stream(stream-write),
|
||||
/// Begin closing an open stream.
|
||||
close-stream(resource-id),
|
||||
/// Stop delivering new read data until resumed.
|
||||
pause-stream(resource-id),
|
||||
/// Resume delivery after a matching pause.
|
||||
resume-stream(resource-id),
|
||||
/// Send one UDP datagram.
|
||||
send-datagram(datagram-send),
|
||||
/// Arm or replace one timer.
|
||||
arm-timer(timer-arm),
|
||||
/// Disarm one timer; its identity remains registered.
|
||||
cancel-timer(resource-id),
|
||||
/// Acknowledge one broker or queue message.
|
||||
acknowledge-message(message-ack),
|
||||
/// Forward an extension-specific command.
|
||||
source-command(source-command),
|
||||
}
|
||||
|
||||
/// Expected Component failure while processing a resident event.
|
||||
variant resident-error {
|
||||
event-failed(string),
|
||||
}
|
||||
|
||||
/// Handles exactly one serialized, bounded event.
|
||||
///
|
||||
/// This callback must not run an internal infinite loop or block on network
|
||||
/// I/O. Update Component state, return requested effects, and let the Host
|
||||
/// wait for the next external event. A trap faults the Actor; `event-failed`
|
||||
/// reports an application error without changing the ABI.
|
||||
handle-event: func(input: event) -> result<list<effect>, resident-error>;
|
||||
}
|
||||
|
||||
/// Optional export world for Components that need long-lived Host-driven I/O.
|
||||
///
|
||||
/// A Component may compose this package with `wasmeld:service` and only the
|
||||
/// capability packages it actually imports.
|
||||
world resident-component {
|
||||
export actor;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,34 @@
|
||||
package wasmeld:service@0.1.0;
|
||||
|
||||
/// Minimum request/response lifecycle implemented by every Wasmeld service.
|
||||
///
|
||||
/// The Runtime creates one Component Store per Actor, calls `init` once, then
|
||||
/// serializes `invoke` calls through that Actor's bounded mailbox. Component
|
||||
/// memory can therefore remain warm between calls, but it is not durable and
|
||||
/// is lost when the Actor or process restarts.
|
||||
world service-component {
|
||||
/// Application-level failures returned without trapping the Component.
|
||||
///
|
||||
/// Traps, fuel exhaustion, deadline interruption, and invalid ABI data are
|
||||
/// Runtime failures and do not use this variant.
|
||||
variant service-error {
|
||||
/// The Actor cannot accept calls because its initial configuration failed.
|
||||
init-failed(string),
|
||||
/// This input could not be processed; a later call may still succeed.
|
||||
call-failed(string),
|
||||
}
|
||||
|
||||
/// Initializes a newly created Actor Store.
|
||||
///
|
||||
/// `config` is opaque to the platform. Return `init-failed` for expected
|
||||
/// configuration errors; do not retain borrowed views into this byte list.
|
||||
export init: func(config: list<u8>) -> result<_, service-error>;
|
||||
|
||||
/// Processes one opaque request and returns one opaque response.
|
||||
///
|
||||
/// The management API represents these bytes as base64, while the public
|
||||
/// gateway transports them as `application/octet-stream`. The Component
|
||||
/// should return promptly and use the resident actor contract for long-lived
|
||||
/// I/O instead of blocking this call in an internal loop.
|
||||
export invoke: func(input: list<u8>) -> result<list<u8>, service-error>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user