Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Verne Software Rust SDK

Crates.io docs.rs License: MIT Rust

The official Rust SDK for the Verne Nautilus platform.

Server-side only. API keys carry full service access and must never be used in WASM or client-side contexts.

Requirements

Rust 1.75 or later.

Installation

[dependencies]
nautilus-rs = "1.1"

Quick Start

use nautilus_rs::Verne;

#[tokio::main]
async fn main() -> Result<(), nautilus_rs::Error> {
    let verne = Verne::builder()
        .relay(std::env::var("VERNE_RELAY_KEY").unwrap())
        .gate(std::env::var("VERNE_GATE_KEY").unwrap())
        .build()?;

    Ok(())
}

You can also instantiate services independently if you only need one:

use nautilus_rs::{Relay, Gate};

let relay = Relay::new("vrn_relay_live_sk_...");
let gate  = Gate::new("vrn_gate_live_sk_...");

Relay — Webhooks-as-a-Service

Send events to all subscribed endpoints:

verne.relay()?.messages().send(nautilus_rs::SendMessageParams {
    event_type: "user.created".into(),
    payload: serde_json::json!({ "id": "usr_123" }),
    ..Default::default()
}).await?;

Optional parameters:

verne.relay()?.messages().send(nautilus_rs::SendMessageParams {
    event_type: "order.placed".into(),
    payload: serde_json::json!({ "order_id": "999" }),
    idempotency_key: Some("evt_abc".into()), // prevent duplicate delivery within 24h
    channels: Some(vec!["team-a".into()]),   // restrict to specific endpoint channels
}).await?;

List previously sent events:

let page = verne.relay()?.messages().list(nautilus_rs::ListMessagesParams {
    limit: Some(20),
    event_type: Some("user.created".into()),
    cursor: None,
}).await?;

println!("{:?}", page.data);        // Vec<Message>
println!("{}", page.has_more);      // bool
println!("{:?}", page.next_cursor); // pass to the next call to paginate

Gate — Auth-as-a-Service

Identity Management

Manage your end-users. The tenant_id is automatically scoped to your API key.

// Create a user
let identity = verne.gate()?.identities().create(nautilus_rs::CreateIdentityParams {
    schema_id: "user".into(),
    traits: nautilus_rs::IdentityTraitsInput {
        email: "user@example.com".into(),
        custom_data: Some(serde_json::json!({ "role": "editor" })),
    },
    credentials: Some(serde_json::json!({
        "password": { "config": { "password": "StrongPassword123!" } }
    })),
    state: Some("active".into()),
}).await?;

// Get a user
verne.gate()?.identities().get(&identity.id).await?;

// Update a user (JSON Patch — RFC 6902)
verne.gate()?.identities().patch(&identity.id, vec![
    nautilus_rs::JsonPatchOp {
        op: "replace".into(),
        path: "/traits/custom_data/role".into(),
        value: Some(serde_json::json!("admin")),
        from: None,
    },
]).await?;

// Delete a user
verne.gate()?.identities().delete(&identity.id).await?;

// Activate / deactivate a user (an inactive user cannot log in)
verne.gate()?.identities().deactivate(&identity.id).await?;
verne.gate()?.identities().activate(&identity.id).await?;
// …or set the state explicitly:
verne.gate()?.identities().set_state(&identity.id, "inactive").await?;

// Resend the email verification link
verne.gate()?.identities().resend_verification(&identity.id).await?;

Security Settings

Read or replace the tenant's security settings (passwordless login, TOTP MFA):

let security = verne.gate()?.settings().get_security().await?;
// security.passwordless_enabled, security.mfa_enabled

// Both fields are always sent — the update is a full replacement, not a merge.
verne.gate()?.settings().update_security(nautilus_rs::SecuritySettings {
    passwordless_enabled: true,
    mfa_enabled: false,
}).await?;

Access Tokens

Exchange your long-lived API key for a short-lived access token:

let token = verne.gate()?.tokens().create(nautilus_rs::CreateTokenParams {
    subject: "usr_123".into(),
    scopes: Some(vec!["gate.tokens.read".into()]), // optional
    ttl_seconds: Some(3600),                       // optional, default 3600, max 86400
}).await?;

// token.access_token — attach to downstream requests
// token.expires_at   — ISO 8601 expiry

Validate a token:

let info = verne.gate()?.tokens().introspect(&token.access_token).await?;

if !info.active {
    // token is expired or invalid
}

Authorization

Check whether a subject is allowed to perform an action:

let decision = verne.gate()?.authorize(nautilus_rs::AuthorizeParams {
    subject: "usr_123".into(),
    action: "relay.messages.read".into(),
    resource: "tenant:ten_001".into(),
    context: None,
}).await?;

if !decision.allowed {
    eprintln!("Forbidden: {}", decision.reason);
}

Clockwork — Cron-as-a-Service

Schedule recurring cron jobs and one-off delayed jobs that invoke your HTTP endpoints, and inspect their execution history. List and executions endpoints return a plain Vec<T> (no pagination).

Cron Jobs

// Create a recurring job
let job = verne.clockwork()?.jobs().create(nautilus_rs::CreateCronJobParams {
    name: "nightly-report".into(),
    schedule: "0 2 * * *".into(),
    url: "https://example.com/hooks/report".into(),
    method: Some("POST".into()),          // optional
    headers: Some(serde_json::json!({ "X-Token": "abc" })), // optional
    body: Some("{}".into()),              // optional
}).await?;

// List all cron jobs
for job in verne.clockwork()?.jobs().list().await? {
    println!("{} — {}", job.name, job.schedule);
}

// Update a job (only the fields you set are changed)
verne.clockwork()?.jobs().update(&job.id, nautilus_rs::UpdateCronJobParams {
    schedule: Some("*/15 * * * *".into()),
    is_active: Some(false),
    ..Default::default()
}).await?;

// Inspect execution history
for exec in verne.clockwork()?.jobs().executions(&job.id).await? {
    println!("{} — {:?}", exec.status, exec.response_status);
}

// Delete a job
verne.clockwork()?.jobs().delete(&job.id).await?;

Delayed Jobs

// Schedule a one-off job
let job = verne.clockwork()?.delayed().create(nautilus_rs::CreateDelayedJobParams {
    name: "send-reminder".into(),
    run_at: "2026-01-01T12:00:00Z".into(),
    url: "https://example.com/hooks/reminder".into(),
    ..Default::default()
}).await?;

// List all delayed jobs
for job in verne.clockwork()?.delayed().list().await? {
    println!("{} runs at {}", job.name, job.run_at);
}

// Inspect execution history
verne.clockwork()?.delayed().executions(&job.id).await?;

// Cancel a pending job
verne.clockwork()?.delayed().cancel(&job.id).await?;

Error Handling

All errors are returned as nautilus_rs::Error:

use nautilus_rs::Error;

match verne.relay()?.messages().send(params).await {
    Ok(msg) => println!("{}", msg.id),
    Err(Error::Api(e)) => {
        eprintln!("code: {}", e.code);       // e.g. "invalid_payload", "unauthorized"
        eprintln!("status: {}", e.status);   // HTTP status code
        eprintln!("request_id: {}", e.request_id); // include in support requests
    }
    Err(Error::Http(e)) => eprintln!("network error: {e}"),
    Err(Error::Config(msg)) => eprintln!("config error: {msg}"),
    Err(e) => eprintln!("error: {e}"),
}

Configuration

Both Verne and the per-service builders accept an optional timeout (default 30 seconds):

let verne = Verne::builder()
    .relay(std::env::var("VERNE_RELAY_KEY").unwrap())
    .timeout_secs(10)
    .build()?;

License

MIT

Releases

Contributors

Languages