Refactor: Rename api mode to headless

The 'api' mode is being renamed to 'headless' to better reflect its
purpose: serving the API without the admin UI. This change aligns with
the existing framework concept of a headless backend.

The 'standalone' mode is renamed to 'admin' to indicate that it serves
both the API and the admin UI.
This commit is contained in:
Cameron Pak
2026-04-06 07:55:08 -05:00
parent 9e0382389e
commit dfae51c368
4 changed files with 30 additions and 27 deletions
@@ -9,33 +9,33 @@ afterAll(enableConsoleLog);
describe("universal adapter via createBknd", () => {
adapterTestSuite(bunTestRunner, {
makeApp: (options, args) => createBknd({ mode: "api", options }, args).getApp(),
makeHandler: (options, args) => createBknd({ mode: "api", options: options ?? {} }, args).serve(),
makeApp: (options, args) => createBknd({ mode: "headless", options }, args).getApp(),
makeHandler: (options, args) => createBknd({ mode: "headless", options: options ?? {} }, args).serve(),
});
// ------------------------ MODE API ------------------------
// ------------------------ MODE HEADLESS ------------------------
test("caches app instance", async () => {
const bknd = createBknd({ mode: "api", options: { connection: { url: ":memory:" } } });
const bknd = createBknd({ mode: "headless", options: { connection: { url: ":memory:" } } });
const app1 = await bknd.getApp();
const app2 = await bknd.getApp();
expect(app1).toBe(app2);
});
test("getApi returns api", async () => {
const bknd = createBknd({ mode: "api", options: { connection: { url: ":memory:" } } });
const bknd = createBknd({ mode: "headless", options: { connection: { url: ":memory:" } } });
const api = await bknd.getApi();
expect(api).toBeDefined();
});
test("uses createFrameworkApp ", async () => {
const bknd = createBknd({ mode: "api", options: { connection: { url: ":memory:" } } });
test("uses createFrameworkApp in headless mode", async () => {
const bknd = createBknd({ mode: "headless", options: { connection: { url: ":memory:" } } });
const app = await bknd.getApp();
expect(app).toBeDefined();
expect(app.isBuilt()).toBe(true);
});
test("serve returns a fetch handler", async () => {
const bknd = createBknd({ mode: "api", options: { connection: { url: ":memory:" } } });
const bknd = createBknd({ mode: "headless", options: { connection: { url: ":memory:" } } });
const handler = bknd.serve();
const res = await handler(new Request("http://localhost:3000/api/system/config"));
expect(res.status).toBe(200);
@@ -43,29 +43,29 @@ describe("universal adapter via createBknd", () => {
});
// ------------------------ MODE STANDALONE ------------------------
describe("universal adapter via createBknd in standalone mode", () => {
// ------------------------ MODE ADMIN ------------------------
describe("universal adapter via createBknd in admin mode", () => {
adapterTestSuite(bunTestRunner, {
makeApp: (options, args) => createBknd({ mode: "standalone", options }, args).getApp(),
makeHandler: (options, args) => createBknd({ mode: "standalone", options: options ?? {} }, args).serve(),
makeApp: (options, args) => createBknd({ mode: "admin", options }, args).getApp(),
makeHandler: (options, args) => createBknd({ mode: "admin", options: options ?? {} }, args).serve(),
});
test("caches app instance", async () => {
const bknd = createBknd({ mode: "standalone", options: { connection: { url: ":memory:" } } });
const bknd = createBknd({ mode: "admin", options: { connection: { url: ":memory:" } } });
const app1 = await bknd.getApp();
const app2 = await bknd.getApp();
expect(app1).toBe(app2);
});
test("getApi returns api", async () => {
const bknd = createBknd({ mode: "standalone", options: { connection: { url: ":memory:" } } });
const bknd = createBknd({ mode: "admin", options: { connection: { url: ":memory:" } } });
const api = await bknd.getApi();
expect(api).toBeDefined();
});
test("uses createRuntimeApp", async () => {
test("uses createRuntimeApp in admin mode", async () => {
const bknd = createBknd({
mode: "standalone",
mode: "admin",
options: {
connection: { url: ":memory:" },
adminOptions: { adminBasepath: "/admin" },
@@ -78,7 +78,7 @@ describe("universal adapter via createBknd in standalone mode", () => {
test("serve returns a fetch handler", async () => {
const bknd = createBknd({
mode: "standalone",
mode: "admin",
options: {
connection: { url: ":memory:" },
adminOptions: { adminBasepath: "/admin" },
@@ -91,7 +91,7 @@ describe("universal adapter via createBknd in standalone mode", () => {
test("check admin route", async () => {
const bknd = createBknd({
mode: "standalone",
mode: "admin",
options: {
connection: { url: ":memory:" },
adminOptions: { adminBasepath: "/admin" },
@@ -9,11 +9,13 @@ import type { App } from "App";
export type AdapterModeWithOptions<Env = Record<string, string | undefined>> =
| {
mode: "standalone";
/** Serves the API along with the admin UI and static assets */
mode: "admin";
options: RuntimeBkndConfig<Env>;
}
| {
mode: "api";
/** Serves the API only, without the admin UI — use when your framework handles rendering */
mode: "headless";
options: FrameworkBkndConfig<Env>;
};
@@ -24,7 +26,7 @@ export function createBknd<Env>(config: AdapterModeWithOptions<Env>, env?: Env)
async function getApp(): Promise<App> {
if (!appPromise) {
if (mode === "standalone") {
if (mode === "admin") {
if (options.adminOptions && !options.serveStatic) {
$console.warn(
"adminOptions provided without serveStatic — admin UI assets may not be served. " +
@@ -59,7 +61,8 @@ export function createBknd<Env>(config: AdapterModeWithOptions<Env>, env?: Env)
return { getApp, getApi, serve };
}
/** Utility type to determine the config type based on mode,
/**
* Utility type to determine the config type based on mode,
* Usage `Config<"standalone">` or `Config<"api">`
*/
export type Config<T extends AdapterModeWithOptions["mode"]> = Extract<
+1 -1
View File
@@ -57,4 +57,4 @@ export default {
assetsPath: "/admin/",
logoReturnPath: "../..",
},
} satisfies Config<"standalone">;
} satisfies Config<"admin">;
+1 -1
View File
@@ -2,7 +2,7 @@ import { createBknd } from "bknd/adapter/universal";
import bkndConfig from "../../bknd.config";
import type { EnvGetter } from "@builder.io/qwik-city/middleware/request-handler";
export const getApp = async (env?: EnvGetter) => createBknd({ mode: "standalone", options: bkndConfig }, env);
export const getApp = async (env?: EnvGetter) => createBknd({ mode: "admin", options: bkndConfig }, env);
export const handler = async (req: Request, env?: EnvGetter) => {
return (await getApp(env)).serve()(req);