SuperAPI AI Directory

btst-integration

Frontend & websites

View repository

Updated 10-15 20:06

About this skill

BTST Library Integration

Quick start

  1. Install @btst/stack, @tanstack/react-query, and one @btst/adapter-*.
  2. Install and register each plugin's backend and client halves.
  3. Create lib/stack.ts → export { handler, dbSchema }.
  4. Mount handler with the framework API entry factory at /api/data/*.
  5. Add @import "@btst/stack/plugins/{plugin}/css" per plugin in your global CSS.
  6. Create lib/stack-client.tsx, lib/query-client.ts, and the /pages/* catch-all route with the framework page entry factory.
  7. Create the pages layout file with QueryClientProvider + StackProvider.
  8. Run @btst/cli generate (and migrate for Kysely).

See REFERENCE.md for full code shapes for every file.

Workflow

1) Install prerequisites and packages

  • Prereqs: shadcn/ui (CSS variables enabled), Sonner <Toaster />, Tailwind v4.
  • Install: @btst/stack, @tanstack/react-query, and one adapter:
    • @btst/adapter-prisma / @btst/adapter-drizzle / @btst/adapter-kysely / @btst/adapter-mongodb
    • @btst/adapter-memory — dev/testing only, not for production
  • Install each plugin package alongside @btst/stack (they ship inside the monorepo package).

2) Register plugins (backend + client)

  • Backend (lib/stack.ts): import {plugin}BackendPlugin from @btst/stack/plugins/{plugin}/api.
    • Pass hooks and config in the backend plugin options object (e.g. blogBackendPlugin({ hooks })).
    • Use camelCase keys for plugins that have compound names: aiChat, formBuilder, uiBuilder.
  • Client (lib/stack-client.tsx): import {plugin}ClientPlugin from @btst/stack/plugins/{plugin}/client.
    • Client definitions receive only plugin-specific options such as seo, hooks, or page components. Configure api, site, and queryClient once on createClientStack(); its resolver binds that runtime to every definition.
    • Pass incoming SSR request headers through the top-level createClientStack({ api: { headers } }) configuration.
    • Resolve one trusted API/site origin snapshot on the server and hydrate it into the provider. A managed backend may use a distinct BTST_API_URL; never reconstruct it from window.location after hydration.

3) Configure backend stack

  • Call createBackendStack({ basePath: "/api/data", plugins: { ... }, adapter: (db) => createXxxAdapter(..., db, {}), auth: serverAuth }) when application authorization is enabled.
  • Create serverAuth with createServerAuth({ authorization, getIdentity }). Omitting auth intentionally preserves permissive no-authorization compatibility; plugin labels such as AI Chat's access: "authorized" are not an enforcement boundary by themselves.
  • Export handler and dbSchema.
  • Memory adapter + Next.js: pin to globalThis to avoid two instances in the same process:
    function createAppStack() {
      return createBackendStack({ ... })
    }
    
    type AppStack = ReturnType<typeof createAppStack>
    const g = globalThis as typeof globalThis & { __btst__?: AppStack }
    export const myStack = g.__btst__ ??= createAppStack()
    export const { handler, dbSchema } = myStack
    

4) CSS — edit global stylesheet

Add one line per plugin before your Tailwind layers:

@import "@btst/stack/plugins/blog/css";
@import "@btst/stack/plugins/cms/css";
@import "@btst/stack/plugins/ai-chat/css";
/* …one per selected plugin */

Do not duplicate — the patcher and manual edits must both be idempotent.

5) Wire framework routes and client runtime

  • API route: use toNextRouteHandlers, toReactRouterHandlers, or toTanStackHandlers from the framework entry point.
  • Pages route: use createNextPage, createReactRouterPage, or createTanStackPageOptions. The factory owns route matching, loader ordering, hydration, metadata, and 404 handling.
  • Pages layout ("use client" in Next.js): wrap in QueryClientProvider then StackProvider:
    • Pass the resolved client stack with stack={clientStack}. Its top-level site.basePath must match your pages catch-all prefix.
    • router={nextRouter()} / reactRouter() / tanstackRouter() for framework-wide links, images, navigation, and refresh.
    • auth={createClientAuth({ authorization, getIdentity, loginPath })} when plugins need identity or permission presentation gates.
    • overrides={{ pluginKey: { uploadImage?, ...pluginSpecificValues } }} only for plugin-specific customization.
    • Let the resolved plugin map infer override keys and values; do not duplicate a manual provider map.
    • See REFERENCE.md for provider wiring and per-plugin override shapes.
  • ai-chat plugin only: wrap the root layout (above StackProvider) with PageAIContextProvider:
    import { PageAIContextProvider } from "@btst/stack/plugins/ai-chat/client/context"
    // root layout.tsx (not the pages layout)
    export default function RootLayout({ children }) {
      return <PageAIContextProvider>{children}</PageAIContextProvider>
    }
    
    Pages then call useRegisterPageAIContext(...) to register their AI context — see the btst-ai-context skill.

6) Generate schemas and run migrations

  • Install @btst/cli as a dev dependency.
  • Prisma: npx @btst/cli generate --config=lib/stack.ts --orm=prisma --output=schema.prisma
  • Drizzle: npx @btst/cli generate --config=lib/stack.ts --orm=drizzle --output=src/db/schema.ts
  • Kysely: npx @btst/cli generate --config=lib/stack.ts --orm=kysely --output=migrations/schema.sql --database-url=...
  • Kysely migrate: npx @btst/cli migrate --config=lib/stack.ts --database-url=...
  • Prisma/Drizzle: use native migration tooling after generate.

Validation checklist

  • stack.ts exports both handler and dbSchema.
  • Protected applications pass createServerAuth(...) to createBackendStack({ auth }); omitted auth is intentionally permissive.
  • Every plugin is registered on both backend and client sides.
  • API basePath and createBackendStack({ basePath }) match exactly.
  • API and page catch-all routes use the framework entry factories.
  • Pages layout is "use client" and wraps QueryClientProvider then StackProvider.
  • The resolved client stack's site.basePath matches the /pages catch-all route prefix.
  • Global CSS has one @import line per selected plugin.
  • /pages/* routes render expected plugin pages.
  • CLI commands run with required env vars in scope.

Gotchas

  • "use client" missing on pages layout — StackProvider uses hooks and must be client-side.
  • Wrong key casing — backend/client plugin map keys must match; compound names use camelCase (aiChat, not ai-chat).
  • Missing CSS import — plugin UI breaks silently even when data loads correctly.
  • Half-registered plugin — backend-only = routes don't exist; client-only = 404 on data calls.
  • Memory adapter + Next.js — always pin to globalThis to share one in-memory store across API and page bundles.
  • Path aliases in CLI — @btst/cli executes your config file directly; use relative imports in lib/stack.ts and its dependencies.
  • Kysely generate needs DB — pass DATABASE_URL or --database-url; use dotenv-cli for .env.local.
  • Provider services copied into plugin overrides — never add Link, Image, navigation, refresh, API paths, identity, or login values to built-in plugin overrides. Use top-level router, api, and auth.