small refactorings and cleanups, improved bun/node adapter, updated docs

This commit is contained in:
dswbx
2024-12-07 18:55:02 +01:00
parent 154703f873
commit 94cc4042d3
16 changed files with 224 additions and 203 deletions

View File

@@ -56,29 +56,6 @@ export class App<DB = any> {
this.modules.ctx().emgr.registerEvents(AppEvents);
}
static create(config: CreateAppConfig) {
let connection: Connection | undefined = undefined;
try {
if (Connection.isConnection(config.connection)) {
connection = config.connection;
} else if (typeof config.connection === "object") {
connection = new LibsqlConnection(config.connection.config);
} else {
connection = new LibsqlConnection({ url: ":memory:" });
console.warn("[!] No connection provided, using in-memory database");
}
} catch (e) {
console.error("Could not create connection", e);
}
if (!connection) {
throw new Error("Invalid connection");
}
return new App(connection, config.initialConfig, config.plugins, config.options);
}
get emgr() {
return this.modules.ctx().emgr;
}
@@ -149,4 +126,31 @@ export class App<DB = any> {
toJSON(secrets?: boolean) {
return this.modules.toJSON(secrets);
}
static create(config: CreateAppConfig) {
return createApp(config);
}
}
export function createApp(config: CreateAppConfig) {
let connection: Connection | undefined = undefined;
try {
if (Connection.isConnection(config.connection)) {
connection = config.connection;
} else if (typeof config.connection === "object") {
connection = new LibsqlConnection(config.connection.config);
} else {
connection = new LibsqlConnection({ url: ":memory:" });
console.warn("[!] No connection provided, using in-memory database");
}
} catch (e) {
console.error("Could not create connection", e);
}
if (!connection) {
throw new Error("Invalid connection");
}
return new App(connection, config.initialConfig, config.plugins, config.options);
}

View File

@@ -1,5 +1,4 @@
import { Api, type ApiOptions } from "bknd";
import { App, type CreateAppConfig } from "bknd";
import { Api, type ApiOptions, App, type CreateAppConfig } from "bknd";
type TAstro = {
request: Request;

View File

@@ -1,55 +1,59 @@
/// <reference types="bun-types" />
import path from "node:path";
import { App, type CreateAppConfig } from "bknd";
import { LibsqlConnection } from "bknd/data";
import type { Serve, ServeOptions } from "bun";
import { serveStatic } from "hono/bun";
async function getConnection(conn?: CreateAppConfig["connection"]) {
if (conn) {
if (LibsqlConnection.isConnection(conn)) {
return conn;
}
return new LibsqlConnection(conn.config);
}
const createClient = await import("@libsql/client/node").then((m) => m.createClient);
if (!createClient) {
throw new Error('libsql client not found, you need to install "@libsql/client/node"');
}
console.log("Using in-memory database");
return new LibsqlConnection(createClient({ url: ":memory:" }));
}
export function serve(_config: Partial<CreateAppConfig> = {}, distPath?: string) {
let app: App;
export async function createApp(_config: Partial<CreateAppConfig> = {}, distPath?: string) {
const root = path.resolve(distPath ?? "./node_modules/bknd/dist", "static");
let app: App;
return async (req: Request) => {
if (!app) {
const connection = await getConnection(_config.connection);
app = App.create({
..._config,
connection
});
if (!app) {
app = App.create(_config);
app.emgr.on(
"app-built",
async () => {
app.modules.server.get(
"/*",
serveStatic({
root
})
);
app.registerAdminController();
},
"sync"
);
app.emgr.on(
"app-built",
async () => {
app.modules.server.get(
"/*",
serveStatic({
root
})
);
app.registerAdminController();
},
"sync"
);
await app.build();
}
await app.build();
}
return app.fetch(req);
};
return app;
}
export type BunAdapterOptions = Omit<ServeOptions, "fetch"> &
CreateAppConfig & {
distPath?: string;
};
export function serve({
distPath,
connection,
initialConfig,
plugins,
options,
port = 1337,
...serveOptions
}: BunAdapterOptions = {}) {
Bun.serve({
...serveOptions,
port,
fetch: async (request: Request) => {
const app = await createApp({ connection, initialConfig, plugins, options }, distPath);
return app.fetch(request);
}
});
console.log(`Server is running on http://localhost:${port}`);
}

View File

@@ -2,51 +2,34 @@ import path from "node:path";
import { serve as honoServe } from "@hono/node-server";
import { serveStatic } from "@hono/node-server/serve-static";
import { App, type CreateAppConfig } from "bknd";
import { LibsqlConnection } from "bknd/data";
async function getConnection(conn?: CreateAppConfig["connection"]) {
if (conn) {
if (LibsqlConnection.isConnection(conn)) {
return conn;
}
return new LibsqlConnection(conn.config);
}
const createClient = await import("@libsql/client/node").then((m) => m.createClient);
if (!createClient) {
throw new Error('libsql client not found, you need to install "@libsql/client/node"');
}
console.log("Using in-memory database");
return new LibsqlConnection(createClient({ url: ":memory:" }));
}
export type NodeAdapterOptions = {
export type NodeAdapterOptions = CreateAppConfig & {
relativeDistPath?: string;
port?: number;
hostname?: string;
listener?: Parameters<typeof honoServe>[1];
};
export function serve(_config: Partial<CreateAppConfig> = {}, options: NodeAdapterOptions = {}) {
export function serve({
relativeDistPath,
port = 1337,
hostname,
listener,
...config
}: NodeAdapterOptions = {}) {
const root = path.relative(
process.cwd(),
path.resolve(options.relativeDistPath ?? "./node_modules/bknd/dist", "static")
path.resolve(relativeDistPath ?? "./node_modules/bknd/dist", "static")
);
let app: App;
honoServe(
{
port: options.port ?? 1337,
hostname: options.hostname,
port,
hostname,
fetch: async (req: Request) => {
if (!app) {
const connection = await getConnection(_config.connection);
app = App.create({
..._config,
connection
});
app = App.create(config);
app.emgr.on(
"app-built",
@@ -68,6 +51,9 @@ export function serve(_config: Partial<CreateAppConfig> = {}, options: NodeAdapt
return app.fetch(req);
}
},
options.listener
(connInfo) => {
console.log(`Server is running on http://localhost:${connInfo.port}`);
listener?.(connInfo);
}
);
}

View File

@@ -1,10 +1,8 @@
import { readFile } from "node:fs/promises";
import path from "node:path";
import type { ServeStaticOptions } from "@hono/node-server/serve-static";
import { type Config, createClient } from "@libsql/client/node";
import { Connection, LibsqlConnection, SqliteLocalConnection } from "data";
import type { Config } from "@libsql/client/node";
import type { MiddlewareHandler } from "hono";
import { fileExists, getDistPath, getRelativeDistPath } from "../../utils/sys";
import open from "open";
import { fileExists, getRelativeDistPath } from "../../utils/sys";
export const PLATFORMS = ["node", "bun"] as const;
export type Platform = (typeof PLATFORMS)[number];
@@ -33,7 +31,8 @@ export async function attachServeStatic(app: any, platform: Platform) {
export async function startServer(server: Platform, app: any, options: { port: number }) {
const port = options.port;
console.log("running on", server, port);
console.log(`(using ${server} serve)`);
switch (server) {
case "node": {
// https://github.com/honojs/node-server/blob/main/src/response.ts#L88
@@ -53,27 +52,9 @@ export async function startServer(server: Platform, app: any, options: { port: n
}
}
console.log("Server listening on", "http://localhost:" + port);
}
export async function getHtml() {
return await readFile(path.resolve(getDistPath(), "static/index.html"), "utf-8");
}
export function getConnection(connectionOrConfig?: Connection | Config): Connection {
if (connectionOrConfig) {
if (connectionOrConfig instanceof Connection) {
return connectionOrConfig;
}
if ("url" in connectionOrConfig) {
return new LibsqlConnection(createClient(connectionOrConfig));
}
}
console.log("Using in-memory database");
return new LibsqlConnection(createClient({ url: ":memory:" }));
//return new SqliteLocalConnection(new Database(":memory:"));
const url = `http://localhost:${port}`;
console.log(`Server listening on ${url}`);
await open(url);
}
export async function getConfigPath(filePath?: string) {

View File

@@ -1,16 +1,13 @@
import type { Config } from "@libsql/client/node";
import { App } from "App";
import { App, type CreateAppConfig } from "App";
import type { BkndConfig } from "adapter";
import type { CliCommand } from "cli/types";
import { Option } from "commander";
import type { Connection } from "data";
import {
PLATFORMS,
type Platform,
attachServeStatic,
getConfigPath,
getConnection,
getHtml,
startServer
} from "./platform";
@@ -41,14 +38,14 @@ export const run: CliCommand = (program) => {
};
type MakeAppConfig = {
connection: Connection;
connection?: CreateAppConfig["connection"];
server?: { platform?: Platform };
setAdminHtml?: boolean;
onBuilt?: (app: App) => Promise<void>;
};
async function makeApp(config: MakeAppConfig) {
const app = new App(config.connection);
const app = App.create({ connection: config.connection });
app.emgr.on(
"app-built",
@@ -99,9 +96,9 @@ async function action(options: {
let app: App;
if (options.dbUrl || !configFilePath) {
const connection = getConnection(
options.dbUrl ? { url: options.dbUrl, authToken: options.dbToken } : undefined
);
const connection = options.dbUrl
? { type: "libsql" as const, config: { url: options.dbUrl, authToken: options.dbToken } }
: undefined;
app = await makeApp({ connection, server: { platform: options.server } });
} else {
console.log("Using config from:", configFilePath);

View File

@@ -41,16 +41,18 @@ export type DbFunctions = {
>;
};
export abstract class Connection {
cls = "bknd:connection";
kysely: Kysely<any>;
const CONN_SYMBOL = Symbol.for("bknd:connection");
export abstract class Connection<DB = any> {
kysely: Kysely<DB>;
constructor(
kysely: Kysely<any>,
kysely: Kysely<DB>,
public fn: Partial<DbFunctions> = {},
protected plugins: KyselyPlugin[] = []
) {
this.kysely = kysely;
this[CONN_SYMBOL] = true;
}
/**
@@ -58,8 +60,9 @@ export abstract class Connection {
* coming from different places
* @param conn
*/
static isConnection(conn: any): conn is Connection {
return conn?.cls === "bknd:connection";
static isConnection(conn: unknown): conn is Connection {
if (!conn) return false;
return conn[CONN_SYMBOL] === true;
}
getIntrospector(): ConnectionIntrospector {

View File

@@ -1,6 +1,5 @@
export { App, type AppConfig, type CreateAppConfig } from "./App";
export { App, createApp, AppEvents, type AppConfig, type CreateAppConfig } from "./App";
export { MediaField } from "media/MediaField";
export {
getDefaultConfig,
getDefaultSchema,