Midwess

The PgPaw unb node owns the application data plane: migrations, schema, raw SQL, and realtime. Worldant retains only its private durability kernel and generates no application data client.

The root worldant.ts configures the data plane only through the strict pgpaw object. Embedded mode (builtin: true) uses dataDir and databaseName; databaseName applies to the embedded PostgreSQL engine. Remote mode (builtin: false) uses remoteAddress, whose DSN reaches the PgPaw-owned PostgreSQL carrying the durability kernel. Both modes require minConnections and maxConnections.

In embedded mode, PgPaw owns the primary and exposes its DSN through its Rust API. Worldant opens a direct SQLx PostgreSQL pool from that DSN for kernel SQL; application SQL binds in-process to the primary's SQL operations under the neutral pgpaw_public role. The primary also attaches PgPaw's services to the Worldant node as a listenerless child over a private Unix socket. This adds the routed pgpaw.sql and pgpaw.live services without creating another database, replica, or public PgPaw listener.

Applications define schema with ordered SQL migrations, applied through PgPaw's schema surface at build. A migration is immutable once applied and must remain present on disk; each file commits in its own transaction, so a mid-chain failure keeps earlier files applied. A destructive contraction (DROP TABLE, DROP COLUMN) is refused unless the file carries the -- pgpaw: acknowledge-destructive comment — acknowledge only after every run and snapshot depending on the prior schema has retired.

The client

Commands and Steps reach application data by subject over the activation-bound session:

import { session } from "worldant/client"

type SqlReply<Row> = { command: string; rows: Row[]; rowsAffected: number }

const reply = (await session.request("pgpaw.sql", {
  sql: "select id from toys where owner = $1",
  params: [input.owner],
})) as SqlReply<{ id: string }>
// reply = { command: "SELECT", rows: [...], rowsAffected: 0 }

session.request("pgpaw.sql", { sql, params }) executes exactly one parameterized statement and always answers { command, rows, rowsAffected }; you supply the row type. Each call commits independently — there is no handler-wide or multi-statement transaction, and a retried Step may re-issue a committed write, so mutations must be idempotent. Row-returning SQL must expose unique output column names. Realtime-safe live reads are served by the PgPaw node's own pgpaw.live root; session.subscribe throws inside an activation, so pgpaw.live is a client-session subscription.

Parameter binding

Parameters bind as JSON values against the statement's described types. Three consequences:

Types outside the JSON families need a text cast. Bind the value as text and cast in SQL:

await session.request("pgpaw.sql", {
  sql: "select * from toys where id = ($1::text)::uuid",
  params: [input.id],
})

A JS array binds as jsonb, not a Postgres array. = any($1) fails. Unnest the jsonb value instead:

await session.request("pgpaw.sql", {
  sql: "select * from toys where id in (select jsonb_array_elements_text($1)::uuid)",
  params: [input.ids],
})

Absence is an empty rows array. Check reply.rows.length when zero rows is a normal outcome.

Authorization

Worldant does not define users, JWTs, claims, tenants, or token validation. Applications bring their own authentication and authorization model.

Application SQL executes under the fixed neutral pgpaw_public role (NOLOGIN, NOBYPASSRLS). The activation's ingress headers are projected onto every outgoing request, so row-level-security policies keyed on request.headers hold across the wire. For served requests, the activation's preserved headers reach SQL as transaction-local JSON:

current_setting('request.headers', true)::jsonb

Application-table authorization is normal PostgreSQL row-level security:

ALTER TABLE todos ENABLE ROW LEVEL SECURITY;
ALTER TABLE todos FORCE ROW LEVEL SECURITY;

CREATE POLICY todos_owner ON todos
TO pgpaw_public
USING (
  owner_id = current_setting('request.headers', true)::jsonb->>'authorization'
)
WITH CHECK (
  owner_id = current_setting('request.headers', true)::jsonb->>'authorization'
);

Do not trust raw client headers in production unless they have been validated by a trusted gateway, middleware, or SQL function.

Root worldant.policy.json can select kernel event visibility with events and ownerHeader. Application-table RLS belongs in migrations.