App SDK

Build revenexx Apps with a typed data client over your app's tables and a small HTTP router for the app's function.

The App SDK is the toolkit for building revenexx Apps. An App declares its data in JSON and runs a function for its custom logic. The SDK gives that function two things: a typed data client over the app's own tables, and a small HTTP router for the function's request handling. It also ships a CLI that generates the typed client from your app's declarations.

Status: early (0.x), under active development. It's available for JavaScript/TypeScript and PHP.

If you're new to Apps, read the App Marketplace overview and the app model first — this page is about the SDK you write the app's code with.

Install

npm
npm install @revenexx/app-sdk

For an app written in PHP, the Composer package is revenexx/app-sdk (PHP 8.2 or newer).

Composer
composer require revenexx/app-sdk

Generate the typed client

Your app declares its tables in schema.json and its identity and permissions in manifest.json. The CLI reads both and generates a typed data client. Generate JavaScript or PHP.

Generate
npx appsdk generate \
  --schema ./schema.json \
  --manifest ./manifest.json \
  --out ./src/db \
  --target js

The generated client only exposes the operations your manifest grants. If the manifest gives an entity read access, the client has list and get; create, update, and delete follow the matching grants. Ungranted operations aren't generated, so the permission boundary is enforced in the types, not just at runtime.

Adapters: the same code in every environment

The data client takes an adapter. Your app code stays the same; you swap the adapter for where it runs.

AdapterWhat it doesUse it for
mockIn-memory fixtures, no infrastructure.Unit tests and fast local iteration.
remoteReal data over HTTP against a dev tenant.Checking behavior against the real data plane before deploy.
runtimeProduction. Auto-configured from the function's invocation context.The deployed App (JavaScript only).
Generated client
import { createDb } from "./db/db.generated.js";

const db = createDb({ adapter: "mock", seed: { greetings: [] } });

await db.greetings.create({ name: "Max" });

const list = await db.greetings.list({
  where: { locale: "en" },
  order: "created_at.desc",
  limit: 20,
});

Queries take where, select, order, limit, and offset. The where operators are eq, neq, gt, gte, lt, lte, like, ilike, in, and is.

The app's function handler

For an App with custom logic, the SDK's router turns the function's request into declarative routes. createApp makes the router; mountCrud exposes an entity over standard CRUD paths.

App function
const { createApp, mountCrud } = require("@revenexx/app-sdk/router");
const { createDb, ENTITIES } = require("./db.generated");

module.exports = (context) => {
  const app = createApp({ name: "markets" });
  const db = createDb({ adapter: "runtime", context });

  mountCrud(app, db.markets, {
    path: "/markets",
    columns: ENTITIES.markets.columns,
  });

  return app.handler()(context);
};

In production the runtime adapter reads the App's invocation context, so you don't wire up the endpoint, tenant, or credentials yourself. When you use the remote adapter to test against a dev tenant, the data-plane call carries the public auth contract: Authorization: Bearer <token> and X-Revenexx-Tenant: <slug>.

The router also gives you HTTP error helpers — notFound, badRequest, forbidden, conflict, and the HttpError class — for returning correct status codes from custom routes.

Where to go next

Was this page helpful?