orbis-plugin-api 1.0.0

Public API for developing Orbis plugins
Documentation
# orbis-plugin-api

Public API for developing Orbis WASM plugins. This crate contains all the types, host functions, and utilities needed to create secure, stateful plugins for the Orbis application platform.

## Features

- **WASM Runtime Interface**: Complete host function bindings for plugin development
- **Stateful by Default**: Built-in state management with JSON serialization
- **Plugin Manifest**: Define plugin metadata, dependencies, permissions, and routes
- **UI Schema**: Declarative JSON-based UI definition system for creating plugin pages
- **Type Safety**: Strongly-typed Rust definitions that serialize to JSON
- **Comprehensive Logging**: Multiple log levels (ERROR, WARN, INFO, DEBUG, TRACE)
- **Memory Management**: Automatic allocation/deallocation patterns
- **Minimal Dependencies**: Only requires `serde`, `serde_json`, `semver`, and `thiserror`

## Usage

Add this to your `Cargo.toml`:

```toml
[dependencies]
orbis-plugin-api = "0.1"
```

## Quick Start: WASM Plugin

### 1. Project Setup

```toml
[package]
name = "my-plugin"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
orbis-plugin-api = { path = "path/to/orbis-plugin-api" }
serde = { version = "1.0", features = ["derive"], default-features = false }
serde_json = { version = "1.0", default-features = false, features = ["alloc"] }

[profile.release]
opt-level = "z"
lto = true
strip = true
```

### 2. Plugin Implementation

```rust
#![no_std]

extern crate alloc;

use alloc::{format, string::String, vec::Vec};
use orbis_plugin_api::{LogLevel, PluginContext};
use serde::{Deserialize, Serialize};

// Import host functions
unsafe extern "C" {
    fn log(level: i32, ptr: *const u8, len: i32);
    fn state_get(key_ptr: *const u8, key_len: i32) -> *const u8;
    fn state_set(key_ptr: *const u8, key_len: i32, value_ptr: *const u8, value_len: i32) -> i32;
}

// Memory management (required)
#[unsafe(no_mangle)]
pub extern "C" fn allocate(size: i32) -> *mut u8 {
    let mut buf = Vec::with_capacity(size as usize);
    let ptr = buf.as_mut_ptr();
    core::mem::forget(buf);
    ptr
}

#[unsafe(no_mangle)]
pub extern "C" fn deallocate(ptr: *mut u8, size: i32) {
    unsafe { let _ = Vec::from_raw_parts(ptr, 0, size as usize); }
}

// Lifecycle hooks
#[unsafe(no_mangle)]
pub extern "C" fn init() -> i32 {
    // Initialize plugin
    1 // Success
}

// Handler function
#[unsafe(no_mangle)]
pub extern "C" fn my_handler(context_ptr: i32, context_len: i32) -> i32 {
    // Process request and return response pointer
    0
}

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
    loop {}
}
```

### 3. Build

```bash
cargo build --target wasm32-unknown-unknown --release
```

## Host Functions Reference

### State Management

#### `state_get(key_ptr, key_len) -> ptr`

Get a value from plugin state. Returns NULL if key not found, otherwise returns pointer to length-prefixed JSON data.

#### `state_set(key_ptr, key_len, value_ptr, value_len) -> i32`

Set a value in plugin state. Returns 1 on success, 0 on failure.

#### `state_remove(key_ptr, key_len) -> i32`

Remove a value from plugin state. Returns 1 on success, 0 on failure.

### Logging

#### `log(level, ptr, len)`

Log a message at the specified level:

- `0` = ERROR
- `1` = WARN
- `2` = INFO
- `3` = DEBUG
- `4` = TRACE

See `examples/basic-plugin.rs` for complete working examples.

## Creating UI Manifests

### Creating a Plugin Manifest

```rust
use orbis_plugin_api::{PluginManifest, PluginPermission, PageDefinition};

let manifest = PluginManifest {
    name: "my-plugin".to_string(),
    version: "0.1.0".to_string(),
    description: "My awesome plugin".to_string(),
    permissions: vec![PluginPermission::DatabaseRead],
    pages: vec![
        PageDefinition {
            route: "/dashboard".to_string(),
            title: "Dashboard".to_string(),
            // ... more configuration
        }
    ],
    // ... more fields
};

// Validate the manifest
manifest.validate()?;
```

### Defining UI Pages

```rust
use orbis_plugin_api::{PageDefinition, ComponentSchema, StateFieldDefinition, StateFieldType};
use std::collections::HashMap;

let page = PageDefinition {
    route: "/users".to_string(),
    title: "User Management".to_string(),
    state: {
        let mut state = HashMap::new();
        state.insert("users".to_string(), StateFieldDefinition {
            field_type: StateFieldType::Array,
            default: Some(serde_json::json!([])),
            nullable: false,
            description: Some("List of users".to_string()),
        });
        state
    },
    sections: vec![
        ComponentSchema::new("Container")
            .with_id("main")
            .with_child(
                ComponentSchema::new("Table")
                    .with_prop("dataSource", serde_json::json!("state:users"))
            )
    ],
    // ... more configuration
};
```

## Type Reference

### Core Types

- `PluginContext`: Context passed to handler functions
- `PluginManifest`: Main manifest structure describing the plugin
- `PageDefinition`: UI page definition with routes, state, and components
- `ComponentSchema`: Individual UI component schema
- `Action`: Actions that can be triggered by UI events
- `LogLevel`: Enum for logging levels

### Permissions

Plugins can request various permissions:

- `DatabaseRead` / `DatabaseWrite`
- `FileRead` / `FileWrite`
- `Network`
- `System`
- `Shell` (dangerous - requires explicit user approval)
- `Environment`

### State Management

Pages can define typed state fields:

- `String`
- `Number`
- `Boolean`
- `Object`
- `Array`

## Error Handling

All validation methods return `orbis_plugin_api::Result<T>`:

```rust
use orbis_plugin_api::{Result, Error};

fn validate_my_manifest(manifest: &PluginManifest) -> Result<()> {
    manifest.validate()?;
    // Additional validation
    Ok(())
}
```