added adapter exports, generalized env-depending config construction

This commit is contained in:
dswbx
2025-01-25 11:54:19 +01:00
parent acc504cdc9
commit 9ddacb7ae5
11 changed files with 53 additions and 35 deletions

View File

@@ -180,6 +180,14 @@ function baseConfig(adapter: string): tsup.Options {
}; };
} }
// base adapter handles
await tsup.build({
...baseConfig(""),
entry: ["src/adapter/index.ts"],
outDir: "dist/adapter"
});
// specific adatpers
await tsup.build(baseConfig("remix")); await tsup.build(baseConfig("remix"));
await tsup.build(baseConfig("bun")); await tsup.build(baseConfig("bun"));
await tsup.build(baseConfig("astro")); await tsup.build(baseConfig("astro"));

View File

@@ -148,6 +148,10 @@
"import": "./dist/adapter/cloudflare/index.js", "import": "./dist/adapter/cloudflare/index.js",
"require": "./dist/adapter/cloudflare/index.cjs" "require": "./dist/adapter/cloudflare/index.cjs"
}, },
"./adapter": {
"types": "./dist/types/adapter/index.d.ts",
"import": "./dist/adapter/index.js"
},
"./adapter/vite": { "./adapter/vite": {
"types": "./dist/types/adapter/vite/index.d.ts", "types": "./dist/types/adapter/vite/index.d.ts",
"import": "./dist/adapter/vite/index.js", "import": "./dist/adapter/vite/index.js",

View File

@@ -1,7 +1,7 @@
import { type FrameworkBkndConfig, createFrameworkApp } from "adapter"; import { type FrameworkBkndConfig, createFrameworkApp } from "adapter";
import { Api, type ApiOptions, type App } from "bknd"; import { Api, type ApiOptions, type App } from "bknd";
export type AstroBkndConfig = FrameworkBkndConfig; export type AstroBkndConfig<Args = TAstro> = FrameworkBkndConfig<Args>;
type TAstro = { type TAstro = {
request: Request; request: Request;
@@ -21,10 +21,11 @@ export function getApi(Astro: TAstro, options: Options = { mode: "static" }) {
} }
let app: App; let app: App;
export function serve(config: AstroBkndConfig = {}) { export function serve<Context extends TAstro = TAstro>(config: AstroBkndConfig<Context> = {}) {
return async (args: TAstro) => { return async (args: Context) => {
console.log("args", Object.keys(args));
if (!app) { if (!app) {
app = await createFrameworkApp(config); app = await createFrameworkApp(config, args);
} }
return app.fetch(args.request); return app.fetch(args.request);
}; };

View File

@@ -1,4 +1,3 @@
import type { CreateAppConfig } from "bknd";
import { Hono } from "hono"; import { Hono } from "hono";
import { serveStatic } from "hono/cloudflare-workers"; import { serveStatic } from "hono/cloudflare-workers";
import type { FrameworkBkndConfig } from "../index"; import type { FrameworkBkndConfig } from "../index";
@@ -6,10 +5,9 @@ import { getCached } from "./modes/cached";
import { getDurable } from "./modes/durable"; import { getDurable } from "./modes/durable";
import { getFresh, getWarm } from "./modes/fresh"; import { getFresh, getWarm } from "./modes/fresh";
export type CloudflareBkndConfig<Env = any> = Omit<FrameworkBkndConfig, "app"> & { export type CloudflareBkndConfig<Env = any> = FrameworkBkndConfig<Context<Env>> & {
app: CreateAppConfig | ((env: Env) => CreateAppConfig);
mode?: "warm" | "fresh" | "cache" | "durable"; mode?: "warm" | "fresh" | "cache" | "durable";
bindings?: (env: Env) => { bindings?: (args: Context<Env>) => {
kv?: KVNamespace; kv?: KVNamespace;
dobj?: DurableObjectNamespace; dobj?: DurableObjectNamespace;
}; };
@@ -21,15 +19,15 @@ export type CloudflareBkndConfig<Env = any> = Omit<FrameworkBkndConfig, "app"> &
html?: string; html?: string;
}; };
export type Context = { export type Context<Env = any> = {
request: Request; request: Request;
env: any; env: Env;
ctx: ExecutionContext; ctx: ExecutionContext;
}; };
export function serve(config: CloudflareBkndConfig) { export function serve<Env = any>(config: CloudflareBkndConfig<Env>) {
return { return {
async fetch(request: Request, env: any, ctx: ExecutionContext) { async fetch(request: Request, env: Env, ctx: ExecutionContext) {
const url = new URL(request.url); const url = new URL(request.url);
const manifest = config.manifest; const manifest = config.manifest;

View File

@@ -2,7 +2,7 @@ import { createRuntimeApp } from "adapter";
import { App } from "bknd"; import { App } from "bknd";
import type { CloudflareBkndConfig, Context } from "../index"; import type { CloudflareBkndConfig, Context } from "../index";
export async function getCached(config: CloudflareBkndConfig, { env, ctx }: Context) { export async function getCached(config: CloudflareBkndConfig, { env, ctx, ...args }: Context) {
const { kv } = config.bindings?.(env)!; const { kv } = config.bindings?.(env)!;
if (!kv) throw new Error("kv namespace is not defined in cloudflare.bindings"); if (!kv) throw new Error("kv namespace is not defined in cloudflare.bindings");
const key = config.key ?? "app"; const key = config.key ?? "app";
@@ -37,7 +37,7 @@ export async function getCached(config: CloudflareBkndConfig, { env, ctx }: Cont
}, },
adminOptions: { html: config.html } adminOptions: { html: config.html }
}, },
env { env, ctx, ...args }
); );
if (!cachedConfig) { if (!cachedConfig) {

View File

@@ -1,5 +1,5 @@
import { DurableObject } from "cloudflare:workers"; import { DurableObject } from "cloudflare:workers";
import { createRuntimeApp } from "adapter"; import { createRuntimeApp, makeConfig } from "adapter";
import type { CloudflareBkndConfig, Context } from "adapter/cloudflare"; import type { CloudflareBkndConfig, Context } from "adapter/cloudflare";
import type { App, CreateAppConfig } from "bknd"; import type { App, CreateAppConfig } from "bknd";
@@ -17,7 +17,7 @@ export async function getDurable(config: CloudflareBkndConfig, ctx: Context) {
const id = dobj.idFromName(key); const id = dobj.idFromName(key);
const stub = dobj.get(id) as unknown as DurableBkndApp; const stub = dobj.get(id) as unknown as DurableBkndApp;
const create_config = typeof config.app === "function" ? config.app(ctx.env) : config.app; const create_config = makeConfig(config, ctx);
const res = await stub.fire(ctx.request, { const res = await stub.fire(ctx.request, {
config: create_config, config: create_config,

View File

@@ -2,13 +2,13 @@ import { createRuntimeApp } from "adapter";
import type { App } from "bknd"; import type { App } from "bknd";
import type { CloudflareBkndConfig, Context } from "../index"; import type { CloudflareBkndConfig, Context } from "../index";
export async function makeApp(config: CloudflareBkndConfig, { env }: Context) { export async function makeApp(config: CloudflareBkndConfig, ctx: Context) {
return await createRuntimeApp( return await createRuntimeApp(
{ {
...config, ...config,
adminOptions: config.html ? { html: config.html } : undefined adminOptions: config.html ? { html: config.html } : undefined
}, },
env ctx
); );
} }

View File

@@ -5,16 +5,16 @@ import type { MiddlewareHandler } from "hono";
import { StorageLocalAdapter } from "media/storage/adapters/StorageLocalAdapter"; import { StorageLocalAdapter } from "media/storage/adapters/StorageLocalAdapter";
import type { AdminControllerOptions } from "modules/server/AdminController"; import type { AdminControllerOptions } from "modules/server/AdminController";
export type BkndConfig<Env = any> = CreateAppConfig & { export type BkndConfig<Args = any> = CreateAppConfig & {
app?: CreateAppConfig | ((env: Env) => CreateAppConfig); app?: CreateAppConfig | ((args: Args) => CreateAppConfig);
onBuilt?: (app: App) => Promise<void>; onBuilt?: (app: App) => Promise<void>;
beforeBuild?: (app: App) => Promise<void>; beforeBuild?: (app: App) => Promise<void>;
buildConfig?: Parameters<App["build"]>[0]; buildConfig?: Parameters<App["build"]>[0];
}; };
export type FrameworkBkndConfig<Env = any> = BkndConfig<Env>; export type FrameworkBkndConfig<Args = any> = BkndConfig<Args>;
export type RuntimeBkndConfig<Env = any> = BkndConfig<Env> & { export type RuntimeBkndConfig<Args = any> = BkndConfig<Args> & {
distPath?: string; distPath?: string;
}; };
@@ -46,14 +46,14 @@ export function registerLocalMediaAdapter() {
registries.media.register("local", StorageLocalAdapter); registries.media.register("local", StorageLocalAdapter);
} }
export function makeConfig<Env = any>(config: BkndConfig<Env>, env?: Env): CreateAppConfig { export function makeConfig<Args = any>(config: BkndConfig<Args>, args?: Args): CreateAppConfig {
let additionalConfig: CreateAppConfig = {}; let additionalConfig: CreateAppConfig = {};
if ("app" in config && config.app) { if ("app" in config && config.app) {
if (typeof config.app === "function") { if (typeof config.app === "function") {
if (!env) { if (!args) {
throw new Error("env is required when config.app is a function"); throw new Error("args is required when config.app is a function");
} }
additionalConfig = config.app(env); additionalConfig = config.app(args);
} else { } else {
additionalConfig = config.app; additionalConfig = config.app;
} }
@@ -62,11 +62,11 @@ export function makeConfig<Env = any>(config: BkndConfig<Env>, env?: Env): Creat
return { ...config, ...additionalConfig }; return { ...config, ...additionalConfig };
} }
export async function createFrameworkApp<Env = any>( export async function createFrameworkApp<Args = any>(
config: FrameworkBkndConfig, config: FrameworkBkndConfig,
env?: Env args?: Args
): Promise<App> { ): Promise<App> {
const app = App.create(makeConfig(config, env)); const app = App.create(makeConfig(config, args));
if (config.onBuilt) { if (config.onBuilt) {
app.emgr.onEvent( app.emgr.onEvent(

View File

@@ -1,13 +1,19 @@
import { type FrameworkBkndConfig, createFrameworkApp } from "adapter"; import { type FrameworkBkndConfig, createFrameworkApp } from "adapter";
import type { App } from "bknd"; import type { App } from "bknd";
export type RemixBkndConfig = FrameworkBkndConfig; export type RemixBkndConfig<Args = RemixContext> = FrameworkBkndConfig<Args>;
type RemixContext = {
request: Request;
};
let app: App; let app: App;
export function serve(config: RemixBkndConfig = {}) { export function serve<Args extends RemixContext = RemixContext>(
return async (args: { request: Request }) => { config: RemixBkndConfig<Args> = {}
) {
return async (args: Args) => {
if (!app) { if (!app) {
app = await createFrameworkApp(config); app = await createFrameworkApp(config, args);
} }
return app.fetch(args.request); return app.fetch(args.request);
}; };

View File

@@ -1,3 +1,4 @@
import type { APIContext } from "astro";
import { App } from "bknd"; import { App } from "bknd";
import { serve } from "bknd/adapter/astro"; import { serve } from "bknd/adapter/astro";
import { registerLocalMediaAdapter } from "bknd/adapter/node"; import { registerLocalMediaAdapter } from "bknd/adapter/node";
@@ -23,7 +24,7 @@ declare module "bknd/core" {
interface DB extends Database {} interface DB extends Database {}
} }
export const ALL = serve({ export const ALL = serve<APIContext>({
// we can use any libsql config, and if omitted, uses in-memory // we can use any libsql config, and if omitted, uses in-memory
connection: { connection: {
type: "libsql", type: "libsql",

View File

@@ -3,7 +3,7 @@ import { serve } from "bknd/adapter/cloudflare";
import manifest from "__STATIC_CONTENT_MANIFEST"; import manifest from "__STATIC_CONTENT_MANIFEST";
export default serve({ export default serve({
app: (env: Env) => ({ app: (args) => ({
connection: { connection: {
type: "libsql", type: "libsql",
config: { config: {