Not released yet. PeltyCMS is under development and not released yet; these docs describe the upcoming release and may change.
PeltyCMS Developer docs
User docsDevelopers
v0.1.0

Developer docs/Extension reference

WIT world and ABI

Current addon ABI: 0.3.0. Addons are WASI preview 2 components for the world below.

#Functions

InterfaceNameSignatureDescription
hostlogfunc(level: level, message: string)
hosthttp-fetchfunc(req: http-request) -> result<http-response, string>Outbound HTTP. Only hosts in capabilities.http (plus $server / $setting:<key> placeholders) are reachable; link-local and cloud metadata addresses are always refused; bodies and time are capped.
hostsettingfunc(key: string) -> option<string>Admin setting value (JSON-encoded), if set.
hostsecretfunc(key: string) -> option<string>Decrypted secret declared in capabilities.secrets.
hostkv-getfunc(key: string) -> option<string>Addon-private key/value store (needs capabilities.kv).
hostkv-setfunc(key: string, value: string) -> result<_, string>
hostkv-deletefunc(key: string)
hostnow-unixfunc() -> s64
hostrandom-bytesfunc(len: u32) -> list<u8>
powerdb-readfunc(entity: string, query: string) -> result<string, string>Read core records (capabilities.db.read lists the entities). query: JSON { "id"?, "filter"?: {column: value}, "limit"?, "offset"? }. Returns a JSON array. Password hashes, TOTP secrets, tokens and encrypted credentials are never returned.
powerdb-writefunc(op: string, input: string) -> result<string, string>Typed write through host APIs (capabilities.db.write lists the ops, e.g. client.note, ticket.reply, service.suspend). Audited.
powersqlfunc(statement: string, params: string) -> result<string, string>SQL on the addon's own tables (addon_<id>_*, capabilities.db.sql). params: JSON array bound as $1..$n. Returns JSON rows.
powerexecfunc(program: string, args: list<string>, stdin: string) -> result<exec-output, string>Run an allowlisted program (capabilities.exec, absolute paths; no shell, empty environment, output and time capped). Off in Docker.
powerjob-enqueuefunc(op: string, input: string, delay-secs: u32) -> result<_, string>Queue call(op, input) to run in the background job worker after delay-secs (capabilities.jobs must list op).
eventsemitfunc(name: string, payload: string) -> result<string, string>
addondescribefunc() -> stringJSON descriptor: kind-specific metadata (capabilities, settings, fields).
addoncallfunc(op: string, input: string) -> result<string, string>Run one operation with a JSON input; returns JSON output.
addonon-eventfunc(name: string, payload: string) -> result<_, string>Subscribed event (invoice.paid, service.created, …).

#pelty.wit

WIT
package pelty:addon@0.2.0;

/// Host services every addon may import. Each call is checked against the
/// capabilities the admin approved at install (addon.json `capabilities`).
interface host {
    enum level { debug, info, warn, error }
    log: func(level: level, message: string);

    record http-request {
        method: string,
        url: string,
        headers: list<tuple<string, string>>,
        body: string,
    }
    record http-response {
        status: u16,
        body: string,
    }
    /// Outbound HTTP. Only hosts in `capabilities.http` (plus `$server` /
    /// `$setting:<key>` placeholders) are reachable; link-local and cloud
    /// metadata addresses are always refused; bodies and time are capped.
    http-fetch: func(req: http-request) -> result<http-response, string>;

    /// Admin setting value (JSON-encoded), if set.
    setting: func(key: string) -> option<string>;
    /// Decrypted secret declared in `capabilities.secrets`.
    secret: func(key: string) -> option<string>;

    /// Addon-private key/value store (needs `capabilities.kv`).
    kv-get: func(key: string) -> option<string>;
    kv-set: func(key: string, value: string) -> result<_, string>;
    kv-delete: func(key: string);

    now-unix: func() -> s64;
    random-bytes: func(len: u32) -> list<u8>;
}

/// Opt-in powers. Every call is refused unless the matching capability was
/// approved by the admin at install (see the generated docs, "Capabilities" page).
interface power {
    /// Read core records (`capabilities.db.read` lists the entities).
    /// `query`: JSON `{ "id"?, "filter"?: {column: value}, "limit"?, "offset"? }`.
    /// Returns a JSON array. Password hashes, TOTP secrets, tokens and
    /// encrypted credentials are never returned.
    db-read: func(entity: string, query: string) -> result<string, string>;
    /// Typed write through host APIs (`capabilities.db.write` lists the ops,
    /// e.g. `client.note`, `ticket.reply`, `service.suspend`). Audited.
    db-write: func(op: string, input: string) -> result<string, string>;
    /// SQL on the addon's own tables (`addon_<id>_*`, `capabilities.db.sql`).
    /// `params`: JSON array bound as $1..$n. Returns JSON rows.
    sql: func(statement: string, params: string) -> result<string, string>;

    record exec-output {
        status: s32,
        stdout: string,
        stderr: string,
    }
    /// Run an allowlisted program (`capabilities.exec`, absolute paths; no
    /// shell, empty environment, output and time capped). Off in Docker.
    exec: func(program: string, args: list<string>, stdin: string) -> result<exec-output, string>;

    /// Queue `call(op, input)` to run in the background job worker after
    /// `delay-secs` (`capabilities.jobs` must list `op`).
    job-enqueue: func(op: string, input: string, delay-secs: u32) -> result<_, string>;
}

/// Addon-defined events (ABI 0.3 features; the package stays @0.2.0 so
/// 0.2 components keep linking). `name` must be `<own-addon-id>:<event>`
/// and be declared in `capabilities.emits`. The `before` phase runs
/// synchronously through every listener (priority order, cancel/modify);
/// the result is JSON `{ "cancelled": bool, "reason"?: string, "payload": {...} }`.
/// `after` and `finished` phases are delivered by the host afterwards.
interface events {
    emit: func(name: string, payload: string) -> result<string, string>;
}

/// The addon contract. Every kind (gateway, provisioning, registrar,
/// captcha, sso, integration) implements the same three exports; `op` names
/// and JSON shapes per kind are documented in the generated docs (`make docs`).
interface addon {
    /// JSON descriptor: kind-specific metadata (capabilities, settings, fields).
    describe: func() -> string;
    /// Run one operation with a JSON input; returns JSON output.
    call: func(op: string, input: string) -> result<string, string>;
    /// Subscribed event (`invoice.paid`, `service.created`, …).
    on-event: func(name: string, payload: string) -> result<_, string>;
}

world pelty-addon {
    import host;
    import power;
    import events;
    export addon;
}

#captcha.wit

WIT
package pelty:addon@0.1.0;

/// Host services every addon may import. Capabilities are still gated by the manifest.
interface host {
    enum level { debug, info, warn, error }
    log: func(level: level, message: string);
}

/// Captcha verification contract (ABI 0.1).
interface captcha {
    record verify-request {
        token: string,
        remote-ip: option<string>,
        /// Admin-configured secret from addon settings.
        secret: string,
    }
    record verify-result {
        success: bool,
        error-codes: list<string>,
    }
    verify: func(req: verify-request) -> result<verify-result, string>;
}

world captcha-addon {
    import host;
    export captcha;
}

#Rust SDK

extensions/addons/sdk (pelty-addon-sdk) wraps the bindings: host, power and events modules, emit, fetch, setting, reply::{proceed, modify, cancel, uncancel}, and the export!, gateway_addon!, provisioning_addon! and registrar_addon! macros.