camel-wit 0.45.2

WIT interface definitions for rust-camel WASM plugins
Documentation
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>;
}