Skip to main content
SPEC
// wp-graphql bleep

WP GraphQL Bleep Interface

ragbaz:wp-graphql — version 0.1.0

A WebAssembly component interface that exposes a stripped WordPress instance as a GraphQL API. PHP compiled to WASM via php-wasm/Emscripten, WordPress core + WPGraphQL bundled into the component, read-only DB access provided by the platform host.

WIT · WASM · GRAPHQL · WORDPRESS · BLEEP

No HTTP server, no wp-admin, no wp-cron — query in, response out. The component is published as an OCI artifact, signed, and registered as a Bleep of kind source or transform.

Draft v0.1 WIT ragbaz:wp-graphql

Interface Overview

The WIT package defines three interfaces: types (shared records), platform (host ABI imported by the bleep), and graphql-backend (exported by the bleep).


Shared Types

interface types {
record graphql-request {
query: string,
variables: option<string>,
operation-name: option<string>,
}

record graphql-response {
data: option<string>,
errors: option<string>,
extensions: option<string>,
}

variant wp-error {
parse-error(string),
execution-error(string),
not-found(string),
forbidden(string),
internal(string),
}
}
graphql-request.queryThe GraphQL query or mutation string
graphql-request.variablesJSON-encoded variables object (optional)
graphql-response.dataJSON-encoded `data` field (null on top-level error)
graphql-response.errorsJSON-encoded error array
wp-error.internalPHP fatal, OOM, or unrecoverable error

Platform Host ABI (imported)

interface platform {
enum log-level { debug, info, warn, error }

log: func(level: log-level, message: string);
get-secret: func(name: string) -> result<string, wp-error>;
db-query: func(sql: string, params: list<string>) -> result<string, wp-error>;
read-wp-content: func(path: string) -> result<list<u8>, wp-error>;
}

Security constraints: db-query only accepts SELECT statements — the host enforces this at the SQL parser level. Only secret names declared in the bleep manifest's required-secrets are accepted by get-secret.

FunctionPurpose
logEmit log line to platform log stream
get-secretRetrieve a declared secret (e.g. DB password)
db-queryRead-only SQL against the WordPress database
read-wp-contentRead a file from wp-content/

GraphQL Backend (exported)

interface graphql-backend {
record backend-descriptor {
name: string,
version: string,
wp-version: string,
plugins: list<string>,
schema-hash: string,
readonly: bool,
max-depth: u32,
max-complexity: u32,
}

execute: func(request: graphql-request) -> result<graphql-response, wp-error>;
introspect: func() -> result<graphql-response, wp-error>;
describe: func() -> backend-descriptor;
}

describe() returns static metadata about the bleep without touching the DB. introspect() returns the full __schema introspection result in one call, bypassing query parsing.

The component is responsible for parsing and validating the query, resolving fields via WordPress data layers (post, user, taxonomy, etc.), and applying depth / complexity limits declared in describe(). Field-level errors are surfaced in graphql-response.errorsexecute only returns Err for unrecoverable failures (OOM, fatal PHP exception).


World

world wp-graphql-bleep {
import platform;
export graphql-backend;
}
Toolchain`wp-wasm-build` CLI (wraps Emscripten + WordPress bundler)
RegisterPush the .wasm component as an OCI artifact, sign it, create a Bleep
MutationsOpt-in via manifest `allow-mutations: true`; default is readonly
Outbound HTTPThe component MUST NOT call any network socket
DB accessRead-only; host enforces at SQL parser level

Security Model

1

No network — The component must not call any network socket. No outbound HTTP. Query in, response out.

2

Read-only DB — Host parses SQL and rejects DML/DDL. Only SELECT statements reach WordPress.

3

Declared secrets — Only secret names listed in the bleep manifest's required-secrets can be retrieved. Host rejects undeclared names.

4

Mutations opt-in — GraphQL mutations are disabled by default. Bleep manifest must declare allow-mutations: true to enable them.

5

Depth & complexity limits — Each bleep declares max-depth and max-complexity in its descriptor. Host can override at the platform level.