package camel:plugin@1.0.0;
// TODO(WIT-001): This file duplicates content from camel-plugin.wit and camel-bean.wit.
// Consider generating this at build time from the canonical source files instead.
/// Simplified exchange types crossing the WASM boundary.
///
/// These types mirror the host's Exchange/Message/Body but exclude
/// non-serializable fields (streams, Arc<dyn Any>, OpenTelemetry Context).
interface types {
/// Handle for a streaming body crossing the WASM boundary.
/// %stream escapes the `stream` WIT keyword.
record stream-body-handle {
%stream: stream<u8>,
terminal: future<result<_, wasm-error>>,
size-hint: option<u64>,
content-type: option<string>,
origin: option<string>,
}
/// Body content variants crossing the WASM boundary.
variant wasm-body {
empty,
text(string),
bytes(list<u8>),
json(string),
xml(string),
%stream(stream-body-handle),
}
/// Exchange pattern: fire-and-forget or request-reply.
enum wasm-pattern {
in-only,
in-out,
}
/// Message with headers and body.
record wasm-message {
headers: list<tuple<string, string>>,
body: wasm-body,
}
/// Simplified exchange crossing the WASM boundary.
record wasm-exchange {
input: wasm-message,
output: option<wasm-message>,
properties: list<tuple<string, string>>,
pattern: wasm-pattern,
correlation-id: string,
route-id: option<string>,
message-id: option<string>,
}
/// Error variants from guest processing.
variant wasm-error {
processor-error(string),
type-conversion(string),
io(string),
timeout,
}
}
/// Host functions imported by the guest plugin.
///
/// These are implemented by the host runtime and allow
/// the guest to call back into Camel infrastructure.
interface host {
use types.{wasm-error};
/// Invoke any Camel endpoint asynchronously.
/// TODO(WIT-009): Only string payloads are supported; binary/bytes support is deferred.
camel-call: async func(uri: string, payload: string) -> result<string, wasm-error>;
/// Poll an endpoint for a message asynchronously (pull model).
/// Returns the body as a string, or an error on timeout/failure.
camel-poll: async func(uri: string, timeout-ms: u32) -> result<string, wasm-error>;
/// Read a property from the host Exchange.
get-property: func(key: string) -> option<string>;
/// Write a property to the host Exchange.
set-property: func(key: string, value: string);
/// Store a value that persists across process() calls for this route endpoint.
host-store: func(key: string, value: string) -> result<_, wasm-error>;
/// Load a previously stored value. Returns none if the key has not been stored.
host-load: func(key: string) -> result<option<string>, wasm-error>;
}
/// The guest (plugin) world.
///
/// Plugins implement the `Guest` trait and export `process` (required)
/// and `init` (optional initialization hook).
world plugin {
import host;
use types.{wasm-exchange, wasm-error};
export process: async func(exchange: wasm-exchange) -> result<wasm-exchange, wasm-error>;
export init: func() -> result<_, string>;
}
/// Guest bean plugin with multi-method dispatch.
///
/// Beans declare their methods via `methods()` and handle invocations
/// via `invoke(method, exchange)`.
world bean {
import host;
use types.{wasm-exchange, wasm-error};
export invoke: async func(method: string, exchange: wasm-exchange) -> result<wasm-exchange, wasm-error>;
export methods: func() -> list<string>;
export init: func(config: list<tuple<string, string>>) -> result<_, string>;
}
/// Guest authorization-policy world — authorization only.
///
/// The host validates JWT and populates camel.auth.* properties
/// BEFORE calling evaluate(). The guest reads auth context via
/// get-property("camel.auth.roles") etc. and returns:
/// - Ok(None) → access granted
/// - Ok(Some(reason)) → access denied
/// - Err(wasm-error) → processing error
world authorization-policy {
import host;
use types.{wasm-exchange, wasm-error};
/// Evaluate the exchange and return an authorization decision.
/// None = Granted, Some(reason) = Denied.
export evaluate: func(exchange: wasm-exchange) -> result<option<string>, wasm-error>;
/// Initialization hook with config from registration.
export init: func(config: list<tuple<string, string>>) -> result<_, string>;
}
/// Host-provided capabilities for guest-driven sources.
interface source-host {
use types.{wasm-exchange, wasm-error};
/// Host-owned HTTP listener handle. Created by the host when
/// the guest requests an http-listener capability in configure().
resource http-listener;
/// Incoming HTTP request delivered to the guest.
record http-request {
method: string,
path: string,
headers: list<tuple<string, string>>,
body: list<u8>,
}
/// Specification for an HTTP listener capability request.
record http-listener-spec {
bind: string,
path: option<string>,
}
/// What the guest requests from the host during configure().
variant capability-request {
http-listener(http-listener-spec),
}
/// The guest's concurrency model declaration.
variant concurrency-model {
sequential,
concurrent(u16),
}
/// Result of configure() — declares what the guest needs.
/// Host rejects if capabilities.len() > 1 or unsupported capability.
record source-plan {
capabilities: list<capability-request>,
concurrency: concurrency-model,
}
/// Outcome of submit-exchange.
variant submit-outcome {
accepted,
stopped,
}
/// Accept the next HTTP request, or none if cancelled. Async: the guest
/// `await`s, yielding back to the host until a request arrives (or the run
/// is cancelled). Bodies stay materialized (`list<u8>`) for this task.
accept-http: async func(listener: borrow<http-listener>)
-> result<option<http-request>, wasm-error>;
/// Push an exchange into the pipeline. Returns once the pipeline accepts
/// the envelope (before full body drain). The guest MUST keep `run` alive
/// while a submitted body stream is still draining; the stream's terminal
/// future resolves when the body finished.
submit-exchange: async func(exchange: wasm-exchange)
-> result<submit-outcome, wasm-error>;
/// Check if the host has cancelled the run loop. Stays sync — a quick
/// peek that must not yield (called in tight guest loops).
is-cancelled: func() -> bool;
}
/// The guest source world.
world source {
import source-host;
use types.{wasm-exchange, wasm-error};
use source-host.{source-plan, http-listener};
export configure: func(config: list<tuple<string, string>>)
-> result<source-plan, wasm-error>;
export run: async func(listener: borrow<http-listener>) -> result<_, wasm-error>;
}