Merge pull request #34 from bknd-io/refactor/adapter-options

Refactor: Unified framework and runtime adapters
This commit is contained in:
dswbx
2024-12-24 09:45:03 +01:00
committed by GitHub
20 changed files with 276 additions and 253 deletions

View File

@@ -3,7 +3,7 @@
"type": "module",
"sideEffects": false,
"bin": "./dist/cli/index.js",
"version": "0.4.0-rc1",
"version": "0.4.0-rc2",
"scripts": {
"build:all": "NODE_ENV=production bun run build.ts --minify --types --clean && bun run build:cli",
"dev": "vite",

View File

@@ -1,4 +1,7 @@
import { Api, type ApiOptions, App, type CreateAppConfig } from "bknd";
import { type FrameworkBkndConfig, createFrameworkApp } from "adapter";
import { Api, type ApiOptions, type App } from "bknd";
export type AstroBkndConfig = FrameworkBkndConfig;
type TAstro = {
request: Request;
@@ -18,12 +21,10 @@ export function getApi(Astro: TAstro, options: Options = { mode: "static" }) {
}
let app: App;
export function serve(config: CreateAppConfig & { beforeBuild?: (app: App) => Promise<void> }) {
export function serve(config: AstroBkndConfig = {}) {
return async (args: TAstro) => {
if (!app) {
app = App.create(config);
await config.beforeBuild?.(app);
await app.build();
app = await createFrameworkApp(config);
}
return app.fetch(args.request);
};

View File

@@ -1,64 +1,47 @@
/// <reference types="bun-types" />
import path from "node:path";
import { App, type CreateAppConfig, registries } from "bknd";
import type { Serve, ServeOptions } from "bun";
import type { App } from "bknd";
import type { ServeOptions } from "bun";
import { config } from "core";
import { serveStatic } from "hono/bun";
import { registerLocalMediaAdapter } from "../index";
import { type RuntimeBkndConfig, createRuntimeApp } from "../index";
let app: App;
export type ExtendedAppCreateConfig = Partial<CreateAppConfig> & {
distPath?: string;
onBuilt?: (app: App) => Promise<void>;
buildOptions?: Parameters<App["build"]>[0];
};
export type BunBkndConfig = RuntimeBkndConfig & Omit<ServeOptions, "fetch">;
export async function createApp({
distPath,
onBuilt,
buildOptions,
buildConfig,
beforeBuild,
...config
}: ExtendedAppCreateConfig) {
registerLocalMediaAdapter();
}: RuntimeBkndConfig = {}) {
const root = path.resolve(distPath ?? "./node_modules/bknd/dist", "static");
if (!app) {
app = App.create(config);
app.emgr.onEvent(
App.Events.AppBuiltEvent,
async () => {
app.modules.server.get(
"/*",
serveStatic({
root
})
);
app.registerAdminController();
await onBuilt?.(app);
},
"sync"
);
await app.build(buildOptions);
app = await createRuntimeApp({
...config,
registerLocalMedia: true,
serveStatic: serveStatic({ root })
});
}
return app;
}
export type BunAdapterOptions = Omit<ServeOptions, "fetch"> & ExtendedAppCreateConfig;
export function serve({
distPath,
connection,
initialConfig,
plugins,
options,
port = 1337,
port = config.server.default_port,
onBuilt,
buildOptions,
buildConfig,
...serveOptions
}: BunAdapterOptions = {}) {
}: BunBkndConfig = {}) {
Bun.serve({
...serveOptions,
port,
@@ -69,7 +52,7 @@ export function serve({
plugins,
options,
onBuilt,
buildOptions,
buildConfig,
distPath
});
return app.fetch(request);

View File

@@ -1,22 +1,37 @@
import type { CreateAppConfig } from "bknd";
import { Hono } from "hono";
import { serveStatic } from "hono/cloudflare-workers";
import type { BkndConfig } from "../index";
import type { FrameworkBkndConfig } from "../index";
import { getCached } from "./modes/cached";
import { getDurable } from "./modes/durable";
import { getFresh, getWarm } from "./modes/fresh";
export type CloudflareBkndConfig<Env = any> = Omit<FrameworkBkndConfig, "app"> & {
app: CreateAppConfig | ((env: Env) => CreateAppConfig);
mode?: "warm" | "fresh" | "cache" | "durable";
bindings?: (env: Env) => {
kv?: KVNamespace;
dobj?: DurableObjectNamespace;
};
key?: string;
keepAliveSeconds?: number;
forceHttps?: boolean;
manifest?: string;
setAdminHtml?: boolean;
html?: string;
};
export type Context = {
request: Request;
env: any;
ctx: ExecutionContext;
manifest: any;
html?: string;
};
export function serve(_config: BkndConfig, manifest?: string, html?: string) {
export function serve(config: CloudflareBkndConfig) {
return {
async fetch(request: Request, env: any, ctx: ExecutionContext) {
const url = new URL(request.url);
const manifest = config.manifest;
if (manifest) {
const pathname = url.pathname.slice(1);
@@ -27,8 +42,7 @@ export function serve(_config: BkndConfig, manifest?: string, html?: string) {
hono.all("*", async (c, next) => {
const res = await serveStatic({
path: `./${pathname}`,
manifest,
onNotFound: (path) => console.log("not found", path)
manifest
})(c as any, next);
if (res instanceof Response) {
const ttl = 60 * 60 * 24 * 365;
@@ -43,12 +57,10 @@ export function serve(_config: BkndConfig, manifest?: string, html?: string) {
}
}
const config = {
..._config,
setAdminHtml: _config.setAdminHtml ?? !!manifest
};
const context = { request, env, ctx, manifest, html } as Context;
const mode = config.cloudflare?.mode ?? "warm";
config.setAdminHtml = config.setAdminHtml && !!config.manifest;
const context = { request, env, ctx } as Context;
const mode = config.mode ?? "warm";
switch (mode) {
case "fresh":

View File

@@ -1,38 +1,31 @@
import type { BkndConfig } from "adapter";
import { createRuntimeApp } from "adapter";
import { App } from "bknd";
import type { Context } from "../index";
import type { CloudflareBkndConfig, Context } from "../index";
export async function getCached(config: BkndConfig, { env, html, ctx }: Context) {
const { kv } = config.cloudflare?.bindings?.(env)!;
export async function getCached(config: CloudflareBkndConfig, { env, ctx }: Context) {
const { kv } = config.bindings?.(env)!;
if (!kv) throw new Error("kv namespace is not defined in cloudflare.bindings");
const key = config.cloudflare?.key ?? "app";
const key = config.key ?? "app";
const create_config = typeof config.app === "function" ? config.app(env) : config.app;
const cachedConfig = await kv.get(key);
const initialConfig = cachedConfig ? JSON.parse(cachedConfig) : undefined;
const app = App.create({ ...create_config, initialConfig });
async function saveConfig(__config: any) {
ctx.waitUntil(kv!.put(key, JSON.stringify(__config)));
}
if (config.onBuilt) {
app.emgr.onEvent(
App.Events.AppBuiltEvent,
async ({ params: { app } }) => {
const app = await createRuntimeApp({
...create_config,
initialConfig,
onBuilt: async (app) => {
app.module.server.client.get("/__bknd/cache", async (c) => {
await kv.delete(key);
return c.json({ message: "Cache cleared" });
});
app.registerAdminController({ html });
config.onBuilt!(app);
await config.onBuilt?.(app);
},
"sync"
);
}
beforeBuild: async (app) => {
app.emgr.onEvent(
App.Events.AppConfigUpdatedEvent,
async ({ params: { app } }) => {
@@ -40,12 +33,10 @@ export async function getCached(config: BkndConfig, { env, html, ctx }: Context)
},
"sync"
);
await app.build();
if (config.setAdminHtml) {
app.registerAdminController({ html });
}
await config.beforeBuild?.(app);
},
adminOptions: { html: config.html }
});
if (!cachedConfig) {
saveConfig(app.toJSON(true));

View File

@@ -1,15 +1,15 @@
import { DurableObject } from "cloudflare:workers";
import type { BkndConfig } from "adapter";
import type { Context } from "adapter/cloudflare";
import { App, type CreateAppConfig } from "bknd";
import { createRuntimeApp } from "adapter";
import type { CloudflareBkndConfig, Context } from "adapter/cloudflare";
import type { App, CreateAppConfig } from "bknd";
export async function getDurable(config: BkndConfig, ctx: Context) {
const { dobj } = config.cloudflare?.bindings?.(ctx.env)!;
export async function getDurable(config: CloudflareBkndConfig, ctx: Context) {
const { dobj } = config.bindings?.(ctx.env)!;
if (!dobj) throw new Error("durable object is not defined in cloudflare.bindings");
const key = config.cloudflare?.key ?? "app";
const key = config.key ?? "app";
if (config.onBuilt) {
console.log("onBuilt() is not supported with DurableObject mode");
if ([config.onBuilt, config.beforeBuild].some((x) => x)) {
console.log("onBuilt and beforeBuild are not supported with DurableObject mode");
}
const start = performance.now();
@@ -21,8 +21,8 @@ export async function getDurable(config: BkndConfig, ctx: Context) {
const res = await stub.fire(ctx.request, {
config: create_config,
html: ctx.html,
keepAliveSeconds: config.cloudflare?.keepAliveSeconds,
html: config.html,
keepAliveSeconds: config.keepAliveSeconds,
setAdminHtml: config.setAdminHtml
});
@@ -64,10 +64,9 @@ export class DurableBkndApp extends DurableObject {
config.connection.config.protocol = "wss";
}
this.app = App.create(config);
this.app.emgr.onEvent(
App.Events.AppBuiltEvent,
async ({ params: { app } }) => {
this.app = await createRuntimeApp({
...config,
onBuilt: async (app) => {
app.modules.server.get("/__do", async (c) => {
// @ts-ignore
const context: any = c.req.raw.cf ? c.req.raw.cf : c.env.cf;
@@ -80,14 +79,11 @@ export class DurableBkndApp extends DurableObject {
await this.onBuilt(app);
},
"sync"
);
await this.app.build();
if (options.setAdminHtml) {
this.app.registerAdminController({ html: options.html });
adminOptions: { html: options.html },
beforeBuild: async (app) => {
await this.beforeBuild(app);
}
});
buildtime = performance.now() - start;
}
@@ -110,6 +106,7 @@ export class DurableBkndApp extends DurableObject {
}
async onBuilt(app: App) {}
async beforeBuild(app: App) {}
protected keepAlive(seconds: number) {
console.log("keep alive for", seconds);

View File

@@ -1,36 +1,23 @@
import type { BkndConfig } from "adapter";
import { App } from "bknd";
import type { Context } from "../index";
import { createRuntimeApp } from "adapter";
import type { App } from "bknd";
import type { CloudflareBkndConfig, Context } from "../index";
export async function makeApp(config: BkndConfig, { env, html }: Context) {
export async function makeApp(config: CloudflareBkndConfig, { env }: Context) {
const create_config = typeof config.app === "function" ? config.app(env) : config.app;
const app = App.create(create_config);
if (config.onBuilt) {
app.emgr.onEvent(
App.Events.AppBuiltEvent,
async ({ params: { app } }) => {
config.onBuilt!(app);
},
"sync"
);
}
await app.build();
if (config.setAdminHtml) {
app.registerAdminController({ html });
}
return app;
return await createRuntimeApp({
...config,
...create_config,
adminOptions: config.html ? { html: config.html } : undefined
});
}
export async function getFresh(config: BkndConfig, ctx: Context) {
export async function getFresh(config: CloudflareBkndConfig, ctx: Context) {
const app = await makeApp(config, ctx);
return app.fetch(ctx.request);
}
let warm_app: App;
export async function getWarm(config: BkndConfig, ctx: Context) {
export async function getWarm(config: CloudflareBkndConfig, ctx: Context) {
if (!warm_app) {
warm_app = await makeApp(config, ctx);
}

View File

@@ -1,28 +1,19 @@
import type { IncomingMessage } from "node:http";
import { type App, type CreateAppConfig, registries } from "bknd";
import { App, type CreateAppConfig, registries } from "bknd";
import type { MiddlewareHandler } from "hono";
import { StorageLocalAdapter } from "media/storage/adapters/StorageLocalAdapter";
import type { AdminControllerOptions } from "modules/server/AdminController";
export type CloudflareBkndConfig<Env = any> = {
mode?: "warm" | "fresh" | "cache" | "durable";
bindings?: (env: Env) => {
kv?: KVNamespace;
dobj?: DurableObjectNamespace;
};
key?: string;
keepAliveSeconds?: number;
forceHttps?: boolean;
type BaseExternalBkndConfig = CreateAppConfig & {
onBuilt?: (app: App) => Promise<void>;
beforeBuild?: (app: App) => Promise<void>;
buildConfig?: Parameters<App["build"]>[0];
};
// @todo: move to App
export type BkndConfig<Env = any> = {
app: CreateAppConfig | ((env: Env) => CreateAppConfig);
setAdminHtml?: boolean;
server?: {
port?: number;
platform?: "node" | "bun";
};
cloudflare?: CloudflareBkndConfig<Env>;
onBuilt?: (app: App) => Promise<void>;
export type FrameworkBkndConfig = BaseExternalBkndConfig;
export type RuntimeBkndConfig = BaseExternalBkndConfig & {
distPath?: string;
};
export function nodeRequestToRequest(req: IncomingMessage): Request {
@@ -52,3 +43,64 @@ export function nodeRequestToRequest(req: IncomingMessage): Request {
export function registerLocalMediaAdapter() {
registries.media.register("local", StorageLocalAdapter);
}
export async function createFrameworkApp(config: FrameworkBkndConfig): Promise<App> {
const app = App.create(config);
if (config.onBuilt) {
app.emgr.onEvent(
App.Events.AppBuiltEvent,
async () => {
await config.onBuilt?.(app);
},
"sync"
);
}
await config.beforeBuild?.(app);
await app.build(config.buildConfig);
return app;
}
export async function createRuntimeApp({
serveStatic,
registerLocalMedia,
adminOptions,
...config
}: RuntimeBkndConfig & {
serveStatic?: MiddlewareHandler | [string, MiddlewareHandler];
registerLocalMedia?: boolean;
adminOptions?: AdminControllerOptions | false;
}): Promise<App> {
if (registerLocalMedia) {
registerLocalMediaAdapter();
}
const app = App.create(config);
app.emgr.onEvent(
App.Events.AppBuiltEvent,
async () => {
if (serveStatic) {
if (Array.isArray(serveStatic)) {
const [path, handler] = serveStatic;
app.modules.server.get(path, handler);
} else {
app.modules.server.get("/*", serveStatic);
}
}
await config.onBuilt?.(app);
if (adminOptions !== false) {
app.registerAdminController(adminOptions);
}
},
"sync"
);
await config.beforeBuild?.(app);
await app.build(config.buildConfig);
return app;
}

View File

@@ -1,6 +1,8 @@
import type { IncomingMessage, ServerResponse } from "node:http";
import { Api, App, type CreateAppConfig } from "bknd";
import { nodeRequestToRequest } from "../index";
import { Api, type App } from "bknd";
import { type FrameworkBkndConfig, createFrameworkApp, nodeRequestToRequest } from "../index";
export type NextjsBkndConfig = FrameworkBkndConfig;
type GetServerSidePropsContext = {
req: IncomingMessage;
@@ -42,12 +44,10 @@ function getCleanRequest(req: Request) {
}
let app: App;
export function serve(config: CreateAppConfig & { beforeBuild?: (app: App) => Promise<void> }) {
export function serve(config: NextjsBkndConfig = {}) {
return async (req: Request) => {
if (!app) {
app = App.create(config);
await config.beforeBuild?.(app);
await app.build();
app = await createFrameworkApp(config);
}
const request = getCleanRequest(req);
return app.fetch(request, process.env);

View File

@@ -1,33 +1,37 @@
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, registries } from "bknd";
import { registerLocalMediaAdapter } from "../index";
import type { App } from "bknd";
import { config as $config } from "core";
import { type RuntimeBkndConfig, createRuntimeApp } from "../index";
export type NodeAdapterOptions = CreateAppConfig & {
relativeDistPath?: string;
export type NodeBkndConfig = RuntimeBkndConfig & {
port?: number;
hostname?: string;
listener?: Parameters<typeof honoServe>[1];
onBuilt?: (app: App) => Promise<void>;
buildOptions?: Parameters<App["build"]>[0];
/** @deprecated */
relativeDistPath?: string;
};
export function serve({
distPath,
relativeDistPath,
port = 1337,
port = $config.server.default_port,
hostname,
listener,
onBuilt,
buildOptions = {},
buildConfig = {},
beforeBuild,
...config
}: NodeAdapterOptions = {}) {
registerLocalMediaAdapter();
}: NodeBkndConfig = {}) {
const root = path.relative(
process.cwd(),
path.resolve(relativeDistPath ?? "./node_modules/bknd/dist", "static")
path.resolve(distPath ?? relativeDistPath ?? "./node_modules/bknd/dist", "static")
);
if (relativeDistPath) {
console.warn("relativeDistPath is deprecated, please use distPath instead");
}
let app: App;
honoServe(
@@ -36,24 +40,11 @@ export function serve({
hostname,
fetch: async (req: Request) => {
if (!app) {
app = App.create(config);
app.emgr.onEvent(
App.Events.AppBuiltEvent,
async () => {
app.modules.server.get(
"/*",
serveStatic({
root
})
);
app.registerAdminController();
await onBuilt?.(app);
},
"sync"
);
await app.build(buildOptions);
app = await createRuntimeApp({
...config,
registerLocalMedia: true,
serveStatic: serveStatic({ root })
});
}
return app.fetch(req);

View File

@@ -1,12 +1,13 @@
import { App, type CreateAppConfig } from "bknd";
import { type FrameworkBkndConfig, createFrameworkApp } from "adapter";
import type { App } from "bknd";
export type RemixBkndConfig = FrameworkBkndConfig;
let app: App;
export function serve(config: CreateAppConfig & { beforeBuild?: (app: App) => Promise<void> }) {
export function serve(config: RemixBkndConfig = {}) {
return async (args: { request: Request }) => {
if (!app) {
app = App.create(config);
await config.beforeBuild?.(app);
await app.build();
app = await createFrameworkApp(config);
}
return app.fetch(args.request);
};

View File

@@ -1,47 +1,41 @@
import { serveStatic } from "@hono/node-server/serve-static";
import type { BkndConfig } from "bknd";
import { App } from "bknd";
import { type RuntimeBkndConfig, createRuntimeApp } from "adapter";
import type { CreateAppConfig } from "bknd";
import type { App } from "bknd";
function createApp(config: BkndConfig, env: any) {
export type ViteBkndConfig<Env = any> = RuntimeBkndConfig & {
app: CreateAppConfig | ((env: Env) => CreateAppConfig);
setAdminHtml?: boolean;
forceDev?: boolean;
html?: string;
};
async function createApp(config: ViteBkndConfig, env: any) {
const create_config = typeof config.app === "function" ? config.app(env) : config.app;
return App.create(create_config);
return await createRuntimeApp({
...create_config,
adminOptions: config.setAdminHtml
? { html: config.html, forceDev: config.forceDev }
: undefined,
serveStatic: ["/assets/*", serveStatic({ root: config.distPath ?? "./" })]
});
}
function setAppBuildListener(app: App, config: BkndConfig, html?: string) {
app.emgr.onEvent(
App.Events.AppBuiltEvent,
async () => {
await config.onBuilt?.(app);
if (config.setAdminHtml) {
app.registerAdminController({ html, forceDev: true });
app.module.server.client.get("/assets/*", serveStatic({ root: "./" }));
}
},
"sync"
);
}
export async function serveFresh(config: BkndConfig, _html?: string) {
export async function serveFresh(config: ViteBkndConfig) {
return {
async fetch(request: Request, env: any, ctx: ExecutionContext) {
const app = createApp(config, env);
setAppBuildListener(app, config, _html);
await app.build();
const app = await createApp(config, env);
return app.fetch(request, env, ctx);
}
};
}
let app: App;
export async function serveCached(config: BkndConfig, _html?: string) {
export async function serveCached(config: ViteBkndConfig) {
return {
async fetch(request: Request, env: any, ctx: ExecutionContext) {
if (!app) {
app = createApp(config, env);
setAppBuildListener(app, config, _html);
await app.build();
app = await createApp(config, env);
}
return app.fetch(request, env, ctx);

View File

@@ -287,14 +287,18 @@ export class AppAuth extends Module<typeof authConfigSchema> {
} catch (e) {}
}
async createUser(input: { email: string; password: string }) {
async createUser({
email,
password,
...additional
}: { email: string; password: string; [key: string]: any }) {
const strategy = "password";
const pw = this.authenticator.strategy(strategy) as PasswordStrategy;
const strategy_value = await pw.hash(input.password);
const strategy_value = await pw.hash(password);
const mutator = this.em.mutator(this.config.entity_name as "users");
mutator.__unstable_toggleSystemEntityCreation(false);
const { data: created } = await mutator.insertOne({
email: input.email,
...(additional as any),
strategy,
strategy_value
});

View File

@@ -1,9 +1,9 @@
import type { Config } from "@libsql/client/node";
import { App, type CreateAppConfig } from "App";
import type { BkndConfig } from "adapter";
import { StorageLocalAdapter } from "adapter/node";
import type { CliCommand } from "cli/types";
import type { CliBkndConfig, CliCommand } from "cli/types";
import { Option } from "commander";
import { config } from "core";
import { registries } from "modules/registries";
import {
PLATFORMS,
@@ -21,7 +21,7 @@ export const run: CliCommand = (program) => {
.addOption(
new Option("-p, --port <port>", "port to run on")
.env("PORT")
.default(1337)
.default(config.server.default_port)
.argParser((v) => Number.parseInt(v))
)
.addOption(new Option("-c, --config <config>", "config file"))
@@ -72,7 +72,7 @@ async function makeApp(config: MakeAppConfig) {
return app;
}
export async function makeConfigApp(config: BkndConfig, platform?: Platform) {
export async function makeConfigApp(config: CliBkndConfig, platform?: Platform) {
const appConfig = typeof config.app === "function" ? config.app(process.env) : config.app;
const app = App.create(appConfig);
@@ -82,14 +82,13 @@ export async function makeConfigApp(config: BkndConfig, platform?: Platform) {
await attachServeStatic(app, platform ?? "node");
app.registerAdminController();
if (config.onBuilt) {
await config.onBuilt(app);
}
await config.onBuilt?.(app);
},
"sync"
);
await app.build();
await config.beforeBuild?.(app);
await app.build(config.buildConfig);
return app;
}
@@ -110,7 +109,7 @@ async function action(options: {
app = await makeApp({ connection, server: { platform: options.server } });
} else {
console.log("Using config from:", configFilePath);
const config = (await import(configFilePath).then((m) => m.default)) as BkndConfig;
const config = (await import(configFilePath).then((m) => m.default)) as CliBkndConfig;
app = await makeConfigApp(config, options.server);
}

View File

@@ -1,10 +1,9 @@
import { password as $password, text as $text } from "@clack/prompts";
import type { App } from "App";
import type { BkndConfig } from "adapter";
import type { PasswordStrategy } from "auth/authenticate/strategies";
import { makeConfigApp } from "cli/commands/run";
import { getConfigPath } from "cli/commands/run/platform";
import type { CliCommand } from "cli/types";
import type { CliBkndConfig, CliCommand } from "cli/types";
import { Argument } from "commander";
export const user: CliCommand = (program) => {
@@ -22,7 +21,7 @@ async function action(action: "create" | "update", options: any) {
return;
}
const config = (await import(configFilePath).then((m) => m.default)) as BkndConfig;
const config = (await import(configFilePath).then((m) => m.default)) as CliBkndConfig;
const app = await makeConfigApp(config, options.server);
switch (action) {

View File

@@ -1,3 +1,14 @@
import type { CreateAppConfig } from "App";
import type { FrameworkBkndConfig } from "adapter";
import type { Command } from "commander";
export type CliCommand = (program: Command) => void;
export type CliBkndConfig<Env = any> = FrameworkBkndConfig & {
app: CreateAppConfig | ((env: Env) => CreateAppConfig);
setAdminHtml?: boolean;
server?: {
port?: number;
platform?: "node" | "bun";
};
};

View File

@@ -9,6 +9,9 @@ export type PrimaryFieldType = number | Generated<number>;
export interface DB {}
export const config = {
server: {
default_port: 1337
},
data: {
default_primary_field: "id"
}

View File

@@ -1,4 +1,4 @@
import { Api, App } from "bknd";
import { App } from "bknd";
import { serve } from "bknd/adapter/astro";
import { registerLocalMediaAdapter } from "bknd/adapter/node";
import { boolean, em, entity, text } from "bknd/data";

View File

@@ -2,8 +2,7 @@ import { serve } from "bknd/adapter/cloudflare";
import manifest from "__STATIC_CONTENT_MANIFEST";
export default serve(
{
export default serve({
app: (env: Env) => ({
connection: {
type: "libsql",
@@ -13,8 +12,7 @@ export default serve(
}
}),
onBuilt: async (app) => {
app.modules.server.get("/hello", (c) => c.json({ hello: "world" }));
}
app.modules.server.get("/custom", (c) => c.json({ hello: "world" }));
},
manifest
);
});

View File

@@ -4,7 +4,7 @@ import { serve } from "bknd/adapter/node";
// serve();
// this is optional, if omitted, it uses an in-memory database
/** @type {import("bknd/adapter/node").NodeAdapterOptions} */
/** @type {import("bknd/adapter/node").NodeBkndConfig} */
const config = {
connection: {
type: "libsql",
@@ -14,7 +14,7 @@ const config = {
},
// this is only required to run inside the same workspace
// leave blank if you're running this from a different project
relativeDistPath: "../../app/dist"
distPath: "../../app/dist"
};
serve(config);