bknd
Version:
Lightweight Firebase/Supabase alternative built to run anywhere — incl. Next.js, React Router, Astro, Cloudflare, Bun, Node, AWS Lambda & more.
132 lines (131 loc) • 3.8 kB
JavaScript
// src/adapter/index.ts
import {
config as $config,
App,
Connection,
guessMimeType,
registries as $registries
} from "bknd";
import { $console } from "bknd/utils";
async function makeConfig(config, args) {
let additionalConfig = {};
const { app, ...rest } = config;
if (app) {
if (typeof app === "function") {
if (!args) {
throw new Error("args is required when config.app is a function");
}
additionalConfig = await app(args);
} else {
additionalConfig = app;
}
}
return { ...rest, ...additionalConfig };
}
async function createAdapterApp(config = {}, args) {
await config.beforeBuild?.(void 0, $registries);
const appConfig = await makeConfig(config, args);
if (!appConfig.connection || !Connection.isConnection(appConfig.connection)) {
let connection;
if (Connection.isConnection(config.connection)) {
connection = config.connection;
} else {
const sqlite = (await import("bknd/adapter/sqlite")).sqlite;
const conf = appConfig.connection ?? { url: "file:data.db" };
connection = sqlite(conf);
$console.info(`Using ${connection.name} connection`, conf.url);
}
appConfig.connection = connection;
}
return {
app: App.create(appConfig),
config: appConfig
};
}
async function createFrameworkApp(config = {}, args) {
const { app, config: appConfig } = await createAdapterApp(config, args);
if (!app.isBuilt()) {
if (config.onBuilt) {
app.emgr.onEvent(
App.Events.AppBuiltEvent,
async () => {
await appConfig.onBuilt?.(app);
},
"sync"
);
}
await appConfig.beforeBuild?.(app, $registries);
await app.build(config.buildConfig);
}
return app;
}
async function createRuntimeApp({ serveStatic, adminOptions, ...config } = {}, args) {
const { app, config: appConfig } = await createAdapterApp(config, args);
if (!app.isBuilt()) {
app.emgr.onEvent(
App.Events.AppBuiltEvent,
async () => {
if (serveStatic) {
const [path, handler] = Array.isArray(serveStatic) ? serveStatic : [$config.server.assets_path + "*", serveStatic];
app.modules.server.get(path, handler);
}
await appConfig.onBuilt?.(app);
if (adminOptions !== false) {
app.registerAdminController(adminOptions);
}
},
"sync"
);
await appConfig.beforeBuild?.(app, $registries);
await app.build(config.buildConfig);
}
return app;
}
function serveStaticViaImport(opts) {
let files;
const pkg = opts?.package ?? "bknd";
return async (c, next) => {
if (!files) {
const manifest = opts?.manifest || (await import(
/* @vite-ignore */
`${pkg}/dist/manifest.json`,
{
with: { type: "json" }
}
)).default;
files = Object.values(manifest).flatMap((asset) => [asset.file, ...asset.css || []]);
}
const path = c.req.path.substring(1);
if (files.includes(path)) {
try {
const url = `${pkg}/static/${path}${opts?.appendRaw ? "?raw" : ""}`;
const content = await import(
/* @vite-ignore */
url,
{
with: { type: "text" }
}
).then((m) => m.default);
if (content) {
return c.body(content, {
headers: {
"Content-Type": guessMimeType(path),
"Cache-Control": "public, max-age=31536000, immutable"
}
});
}
} catch (e) {
console.error(`Error serving static file "${path}":`, String(e));
return c.text("File not found", 404);
}
}
await next();
};
}
export {
createAdapterApp,
createFrameworkApp,
createRuntimeApp,
makeConfig,
serveStaticViaImport
};