package wasmeld:resident@0.1.0;

/// Event/effect ABI for Components that remain active without monopolizing
/// their Actor thread. The Host owns timers, subscriptions, sockets, streams,
/// 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,
    bytes: list<u8>,
  }

  /// Escape hatch for Host-owned event sources such as filesystem watchers,
  /// serial devices, process signals, or platform-specific buses. `kind` and
  /// `payload` are interpreted by the separately versioned Host capability
  /// that created `source-id`.
  record source-event {
    source-id: resource-id,
    kind: string,
    payload: list<u8>,
  }

  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;
}
