ChaiBuilder Logo

API

The Pro SDK ships as chaipro with purpose-specific entry points. The rule that keeps imports correct: client APIs come from the root and /registry; server APIs come from /nextjs/server, /nextjs/render, /payload, and /db/*. Importing the root package in a server context throws by design.

Entry points

Entry point Side Purpose
chaipro client Builder component + UI extension APIs (panels, slots, hooks, flags)
chaipro/registry client Block registration - registerChaiBlock, props schemas, fonts
chaipro/web-blocks client loadWebBlocks() - the built-in block library
chaipro/types shared All public types
chaipro/utils shared HTML-to-blocks conversion, design token helpers
chaipro/nextjs server withChaiBuilder next.config wrapper
chaipro/nextjs/server server Config, context, actions, permissions
chaipro/nextjs/render server RenderChaiBlocks, ChaiPageCSS, styles utilities
chaipro/nextjs/render-client client PreviewBanner, ChaiAnimationProvider
chaipro/db/* server Database adapter factories (postgres, node-pg, libsql, d1, better-sqlite3)
chaipro/payload server Payload integration - plugin, schema hook, createPayloadChaiBuilder
chaipro/plugins/<name>/server and /client per plugin Feature plugins (redirects, revisions, trash, roles, media, ...)
chaipro/ui/* client shadcn-based UI primitives for custom panels

Client: extending the builder

All registration APIs are client-only and must run at module level before the builder mounts - centralize them in one setup file. The main families:

API What it does
registerChaiBlock(component, config) add a custom block (from /registry)
registerChaiBlockProps(schema) define a block's editable props schema
registerChaiSidebarPanel(id, options) add a sidebar panel
registerChaiSlot(CHAI_SLOT_IDS.X, Component) inject UI into a named slot
registerChaiHook(CHAI_HOOKS.X, fn) intercept lifecycle events (before/after save)
registerChaiFeatureFlag(key, options) user-toggleable flags
registerChaiLibrary(id, options) add a browsable block library
registerChaiAddBlockTab(id, options) add a tab to the Add Block drawer

Hooks for reading builder state from custom UI include useChaiAuth, useUserPermissions, useActivePage, useSavePage, useChaiFeatureFlag, and useWebsitePages. Full walkthroughs: Extending the UI and Custom Blocks.

Server: the request-scoped instance

getChaiBuilder (exported from your chaibuilder.server.ts, see Configuration) returns a request-scoped instance with all server APIs bound to the caller's context:

const cb = await getChaiBuilder(props)            // pages/layouts
const cb = await getChaiBuilder(props, request)   // route handlers
Method Returns
cb.getPagePayload(slug) full render payload - { page, pageData, settings, pageProps }
cb.generateMetaData(...) a Next.js Metadata object for the page
cb.getPageData(slug) resolved data-provider output for a page
cb.getSiteSettings() site-wide settings
cb.getSiteGlobalData() output of your globalDataProvider
cb.getPages() all pages
cb.handleHttpAction(body) dispatch a builder action from a route handler

The instance is request-scoped - never cache it or share it across requests.

The action endpoint

All client-to-server builder communication goes through one route, which the starter already includes:

// app/(builder)/api/chai/route.ts
export async function POST(request: NextRequest, props: ChaiBuilderRouteProps) {
  const cb = await getChaiBuilder(props, request)
  return cb.handleHttpAction(await request.json())
}

The body is { action: "ACTION_NAME", data: {...} }. Authentication comes from the Payload auth cookie (builder UI) or an Authorization: Bearer header (programmatic calls), and each action enforces its required permission before executing. After an action runs, any cache tags and paths it reports are revalidated automatically - see Caching & Revalidation.

Custom actions

Add your own actions by extending ChaiBaseAction:

import { ChaiBaseAction } from 'chaipro/nextjs/server'
import { z } from 'zod'

export class GetInventoryAction extends ChaiBaseAction {
  protected getValidationSchema() {
    return z.object({ productId: z.string() })
  }
  async execute(data: { productId: string }) {
    const { appId, userId } = this.context!   // set before execute()
    return fetchInventory(appId, data.productId)
  }
}

Register it in chaibuilder.config.ts under actions: { GET_INVENTORY: new GetInventoryAction() }, then call it from the builder UI through the action endpoint, or server-side with dispatchChaiAction("GET_INVENTORY", data) (throws on error) or tryChaiAction(...) (returns { ok, data | error }).

Rendering

Server components for rendering published pages, from /nextjs/render:

  • RenderChaiBlocks - renders a page payload; accepts optional linkComponent, imageComponent, buttonComponent overrides.
  • ChaiPageCSS - page CSS (Tailwind output, theme variables, fonts); must be in <head>.
  • ChaiPageJSONLD - structured data for SEO.
  • getStylesForBlocks, getChaiThemeCssVariables - lower-level utilities for custom render pipelines.

Permissions

The permission catalog is CHAI_PERMISSIONS (core keys) plus keys registered by active plugins - getPermissionCatalog() returns the runtime set. Check access in custom code with hasPermission, and resolve a user's effective set with resolvePermissions. Effective permissions are the user's grants intersected with any credential-level delegatedPermissions ceiling. See Roles & Permissions.

© ChaiBuilder. All rights reserved.