mirror of
https://github.com/bknd-io/bknd/
synced 2026-08-04 00:56:01 +00:00
Add web adapter
This commit introduces a new web adapter, allowing applications to be served in a web environment. The web adapter provides functionality to create and manage application instances, handle API requests, and serve the application via a fetch handler. It also includes support for integrating with admin functionalities when admin options are provided.
This commit is contained in:
@@ -340,6 +340,11 @@ async function buildAdapters() {
|
|||||||
platform: "node",
|
platform: "node",
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
tsup.build({
|
||||||
|
...baseConfig("web"),
|
||||||
|
platform: "neutral",
|
||||||
|
}),
|
||||||
|
|
||||||
tsup.build({
|
tsup.build({
|
||||||
...baseConfig("node"),
|
...baseConfig("node"),
|
||||||
platform: "node",
|
platform: "node",
|
||||||
|
|||||||
@@ -278,6 +278,11 @@
|
|||||||
"import": "./dist/adapter/tanstack-start/index.js",
|
"import": "./dist/adapter/tanstack-start/index.js",
|
||||||
"require": "./dist/adapter/tanstack-start/index.js"
|
"require": "./dist/adapter/tanstack-start/index.js"
|
||||||
},
|
},
|
||||||
|
"./adapter/web": {
|
||||||
|
"types": "./dist/types/adapter/web/index.d.ts",
|
||||||
|
"import": "./dist/adapter/web/index.js",
|
||||||
|
"require": "./dist/adapter/web/index.js"
|
||||||
|
},
|
||||||
"./dist/main.css": "./dist/ui/main.css",
|
"./dist/main.css": "./dist/ui/main.css",
|
||||||
"./dist/styles.css": "./dist/ui/styles.css",
|
"./dist/styles.css": "./dist/ui/styles.css",
|
||||||
"./dist/manifest.json": "./dist/static/.vite/manifest.json",
|
"./dist/manifest.json": "./dist/static/.vite/manifest.json",
|
||||||
@@ -298,6 +303,7 @@
|
|||||||
"adapter/node": ["./dist/types/adapter/node/index.d.ts"],
|
"adapter/node": ["./dist/types/adapter/node/index.d.ts"],
|
||||||
"adapter/sveltekit": ["./dist/types/adapter/sveltekit/index.d.ts"],
|
"adapter/sveltekit": ["./dist/types/adapter/sveltekit/index.d.ts"],
|
||||||
"adapter/tanstack-start": ["./dist/types/adapter/tanstack-start/index.d.ts"],
|
"adapter/tanstack-start": ["./dist/types/adapter/tanstack-start/index.d.ts"],
|
||||||
|
"adapter/web": ["./dist/types/adapter/web/index.d.ts"],
|
||||||
"adapter/sqlite": ["./dist/types/adapter/sqlite/edge.d.ts"]
|
"adapter/sqlite": ["./dist/types/adapter/sqlite/edge.d.ts"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from "./web.adapter";
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { afterAll, beforeAll, describe, test, expect } from "bun:test";
|
||||||
|
import { createBknd } from "./web.adapter";
|
||||||
|
import type { WebBkndConfig } from "./web.adapter";
|
||||||
|
import { disableConsoleLog, enableConsoleLog } from "core/utils";
|
||||||
|
import { adapterTestSuite } from "adapter/adapter-test-suite";
|
||||||
|
import { bunTestRunner } from "adapter/bun/test";
|
||||||
|
|
||||||
|
beforeAll(disableConsoleLog);
|
||||||
|
afterAll(enableConsoleLog);
|
||||||
|
|
||||||
|
describe("web adapter via createBknd", () => {
|
||||||
|
adapterTestSuite(bunTestRunner, {
|
||||||
|
makeApp: (config, args) => createBknd(config, args).getApp(),
|
||||||
|
makeHandler: (config, args) => createBknd(config ?? {}, args).serve(),
|
||||||
|
});
|
||||||
|
|
||||||
|
test("caches app instance", async () => {
|
||||||
|
const bknd = createBknd({ 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({ connection: { url: ":memory:" } });
|
||||||
|
const api = await bknd.getApi();
|
||||||
|
expect(api).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("serve returns a fetch handler", async () => {
|
||||||
|
const bknd = createBknd({ connection: { url: ":memory:" } });
|
||||||
|
const handler = bknd.serve();
|
||||||
|
const res = await handler(new Request("http://localhost:3000/api/system/config"));
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("uses createRuntimeApp when adminOptions provided", async () => {
|
||||||
|
const bknd = createBknd({
|
||||||
|
connection: { url: ":memory:" },
|
||||||
|
adminOptions: { adminBasepath: "/admin" },
|
||||||
|
});
|
||||||
|
const app = await bknd.getApp();
|
||||||
|
expect(app).toBeDefined();
|
||||||
|
expect(app.isBuilt()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("uses createFrameworkApp when no adminOptions", async () => {
|
||||||
|
const bknd = createBknd({ connection: { url: ":memory:" } });
|
||||||
|
const app = await bknd.getApp();
|
||||||
|
expect(app).toBeDefined();
|
||||||
|
expect(app.isBuilt()).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import {
|
||||||
|
createFrameworkApp,
|
||||||
|
createRuntimeApp,
|
||||||
|
type FrameworkBkndConfig,
|
||||||
|
} from "bknd/adapter";
|
||||||
|
import type { AdminControllerOptions } from "modules/server/AdminController";
|
||||||
|
import type { App } from "App";
|
||||||
|
|
||||||
|
export type WebBkndConfig<Env = any> = FrameworkBkndConfig<Env> & {
|
||||||
|
adminOptions?: AdminControllerOptions | false;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createBknd<Env>(config: WebBkndConfig<Env>, args?: Env) {
|
||||||
|
let appPromise: Promise<App> | undefined;
|
||||||
|
|
||||||
|
const { adminOptions, ...frameworkConfig } = config;
|
||||||
|
|
||||||
|
async function getApp() {
|
||||||
|
if (!appPromise) {
|
||||||
|
if (adminOptions != null) {
|
||||||
|
appPromise = createRuntimeApp({ ...frameworkConfig, adminOptions }, args);
|
||||||
|
} else {
|
||||||
|
appPromise = createFrameworkApp(frameworkConfig, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return appPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getApi(opts?: { headers?: Headers; verify?: boolean }) {
|
||||||
|
const app = await getApp();
|
||||||
|
if (opts?.verify) {
|
||||||
|
const api = app.getApi({ headers: opts.headers });
|
||||||
|
await api.verifyAuth();
|
||||||
|
return api;
|
||||||
|
}
|
||||||
|
return app.getApi();
|
||||||
|
}
|
||||||
|
|
||||||
|
function serve() {
|
||||||
|
return async (req: Request) => {
|
||||||
|
const app = await getApp();
|
||||||
|
return app.fetch(req);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return { getApp, getApi, serve };
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user