adapters: remove runtime options, serve app always fresh to prevent race conditions

This commit is contained in:
dswbx
2025-09-04 19:36:21 +02:00
parent e8f2c70279
commit fdec5f0693
14 changed files with 37 additions and 90 deletions

View File

@@ -1,5 +1,5 @@
import type { TestRunner } from "core/test"; import type { TestRunner } from "core/test";
import type { BkndConfig, DefaultArgs, FrameworkOptions, RuntimeOptions } from "./index"; import type { BkndConfig, DefaultArgs } from "./index";
import type { App } from "App"; import type { App } from "App";
export function adapterTestSuite< export function adapterTestSuite<
@@ -13,16 +13,8 @@ export function adapterTestSuite<
label = "app", label = "app",
overrides = {}, overrides = {},
}: { }: {
makeApp: ( makeApp: (config: Config, args?: Args) => Promise<App>;
config: Config, makeHandler?: (config?: Config, args?: Args) => (request: Request) => Promise<Response>;
args?: Args,
opts?: RuntimeOptions | FrameworkOptions,
) => Promise<App>;
makeHandler?: (
config?: Config,
args?: Args,
opts?: RuntimeOptions | FrameworkOptions,
) => (request: Request) => Promise<Response>;
label?: string; label?: string;
overrides?: { overrides?: {
dbUrl?: string; dbUrl?: string;
@@ -30,7 +22,6 @@ export function adapterTestSuite<
}, },
) { ) {
const { test, expect, mock } = testRunner; const { test, expect, mock } = testRunner;
const id = crypto.randomUUID();
test(`creates ${label}`, async () => { test(`creates ${label}`, async () => {
const beforeBuild = mock(async () => null) as any; const beforeBuild = mock(async () => null) as any;
@@ -53,7 +44,6 @@ export function adapterTestSuite<
url: overrides.dbUrl ?? ":memory:", url: overrides.dbUrl ?? ":memory:",
origin: "localhost", origin: "localhost",
} as any, } as any,
{ force: false, id },
); );
expect(app).toBeDefined(); expect(app).toBeDefined();
expect(app.toJSON().server.cors.origin).toEqual("localhost"); expect(app.toJSON().server.cors.origin).toEqual("localhost");
@@ -68,8 +58,8 @@ export function adapterTestSuite<
return { res, data }; return { res, data };
}; };
test.skip("responds with the same app id", async () => { /* test.skip("responds with the same app id", async () => {
const fetcher = makeHandler(undefined, undefined, { force: false, id }); const fetcher = makeHandler(undefined, undefined, { id });
const { res, data } = await getConfig(fetcher); const { res, data } = await getConfig(fetcher);
expect(res.ok).toBe(true); expect(res.ok).toBe(true);
@@ -79,12 +69,12 @@ export function adapterTestSuite<
test.skip("creates fresh & responds to api config", async () => { test.skip("creates fresh & responds to api config", async () => {
// set the same id, but force recreate // set the same id, but force recreate
const fetcher = makeHandler(undefined, undefined, { id, force: true }); const fetcher = makeHandler(undefined, undefined, { id });
const { res, data } = await getConfig(fetcher); const { res, data } = await getConfig(fetcher);
expect(res.ok).toBe(true); expect(res.ok).toBe(true);
expect(res.status).toBe(200); expect(res.status).toBe(200);
expect(data.server.cors.origin).toEqual("*"); expect(data.server.cors.origin).toEqual("*");
}); }); */
} }
} }

View File

@@ -10,6 +10,6 @@ afterAll(enableConsoleLog);
describe("astro adapter", () => { describe("astro adapter", () => {
adapterTestSuite(bunTestRunner, { adapterTestSuite(bunTestRunner, {
makeApp: astro.getApp, makeApp: astro.getApp,
makeHandler: (c, a, o) => (request: Request) => astro.serve(c, a, o)({ request }), makeHandler: (c, a) => (request: Request) => astro.serve(c, a)({ request }),
}); });
}); });

View File

@@ -1,4 +1,4 @@
import { type FrameworkBkndConfig, createFrameworkApp, type FrameworkOptions } from "bknd/adapter"; import { type FrameworkBkndConfig, createFrameworkApp } from "bknd/adapter";
type AstroEnv = NodeJS.ProcessEnv; type AstroEnv = NodeJS.ProcessEnv;
type TAstro = { type TAstro = {
@@ -9,17 +9,12 @@ export type AstroBkndConfig<Env = AstroEnv> = FrameworkBkndConfig<Env>;
export async function getApp<Env = AstroEnv>( export async function getApp<Env = AstroEnv>(
config: AstroBkndConfig<Env> = {}, config: AstroBkndConfig<Env> = {},
args: Env = {} as Env, args: Env = {} as Env,
opts: FrameworkOptions = {},
) { ) {
return await createFrameworkApp(config, args ?? import.meta.env, opts); return await createFrameworkApp(config, args ?? import.meta.env);
} }
export function serve<Env = AstroEnv>( export function serve<Env = AstroEnv>(config: AstroBkndConfig<Env> = {}, args: Env = {} as Env) {
config: AstroBkndConfig<Env> = {},
args: Env = {} as Env,
opts?: FrameworkOptions,
) {
return async (fnArgs: TAstro) => { return async (fnArgs: TAstro) => {
return (await getApp(config, args, opts)).fetch(fnArgs.request); return (await getApp(config, args)).fetch(fnArgs.request);
}; };
} }

View File

@@ -1,7 +1,7 @@
import type { App } from "bknd"; import type { App } from "bknd";
import { handle } from "hono/aws-lambda"; import { handle } from "hono/aws-lambda";
import { serveStatic } from "@hono/node-server/serve-static"; import { serveStatic } from "@hono/node-server/serve-static";
import { type RuntimeBkndConfig, createRuntimeApp, type RuntimeOptions } from "bknd/adapter"; import { type RuntimeBkndConfig, createRuntimeApp } from "bknd/adapter";
type AwsLambdaEnv = object; type AwsLambdaEnv = object;
export type AwsLambdaBkndConfig<Env extends AwsLambdaEnv = AwsLambdaEnv> = export type AwsLambdaBkndConfig<Env extends AwsLambdaEnv = AwsLambdaEnv> =
@@ -20,7 +20,6 @@ export type AwsLambdaBkndConfig<Env extends AwsLambdaEnv = AwsLambdaEnv> =
export async function createApp<Env extends AwsLambdaEnv = AwsLambdaEnv>( export async function createApp<Env extends AwsLambdaEnv = AwsLambdaEnv>(
{ adminOptions = false, assets, ...config }: AwsLambdaBkndConfig<Env> = {}, { adminOptions = false, assets, ...config }: AwsLambdaBkndConfig<Env> = {},
args: Env = {} as Env, args: Env = {} as Env,
opts?: RuntimeOptions,
): Promise<App> { ): Promise<App> {
let additional: Partial<RuntimeBkndConfig> = { let additional: Partial<RuntimeBkndConfig> = {
adminOptions, adminOptions,
@@ -57,17 +56,15 @@ export async function createApp<Env extends AwsLambdaEnv = AwsLambdaEnv>(
...additional, ...additional,
}, },
args ?? process.env, args ?? process.env,
opts,
); );
} }
export function serve<Env extends AwsLambdaEnv = AwsLambdaEnv>( export function serve<Env extends AwsLambdaEnv = AwsLambdaEnv>(
config: AwsLambdaBkndConfig<Env> = {}, config: AwsLambdaBkndConfig<Env> = {},
args: Env = {} as Env, args: Env = {} as Env,
opts?: RuntimeOptions,
) { ) {
return async (event) => { return async (event) => {
const app = await createApp(config, args, opts); const app = await createApp(config, args);
return await handle(app.server)(event); return await handle(app.server)(event);
}; };
} }

View File

@@ -11,8 +11,8 @@ describe("aws adapter", () => {
adapterTestSuite(bunTestRunner, { adapterTestSuite(bunTestRunner, {
makeApp: awsLambda.createApp, makeApp: awsLambda.createApp,
// @todo: add a request to lambda event translator? // @todo: add a request to lambda event translator?
makeHandler: (c, a, o) => async (request: Request) => { makeHandler: (c, a) => async (request: Request) => {
const app = await awsLambda.createApp(c, a, o); const app = await awsLambda.createApp(c, a);
return app.fetch(request); return app.fetch(request);
}, },
}); });

View File

@@ -1,7 +1,7 @@
/// <reference types="bun-types" /> /// <reference types="bun-types" />
import path from "node:path"; import path from "node:path";
import { type RuntimeBkndConfig, createRuntimeApp, type RuntimeOptions } from "bknd/adapter"; import { type RuntimeBkndConfig, createRuntimeApp } from "bknd/adapter";
import { registerLocalMediaAdapter } from "."; import { registerLocalMediaAdapter } from ".";
import { config, type App } from "bknd"; import { config, type App } from "bknd";
import type { ServeOptions } from "bun"; import type { ServeOptions } from "bun";
@@ -13,7 +13,6 @@ export type BunBkndConfig<Env = BunEnv> = RuntimeBkndConfig<Env> & Omit<ServeOpt
export async function createApp<Env = BunEnv>( export async function createApp<Env = BunEnv>(
{ distPath, serveStatic: _serveStatic, ...config }: BunBkndConfig<Env> = {}, { distPath, serveStatic: _serveStatic, ...config }: BunBkndConfig<Env> = {},
args: Env = {} as Env, args: Env = {} as Env,
opts?: RuntimeOptions,
) { ) {
const root = path.resolve(distPath ?? "./node_modules/bknd/dist", "static"); const root = path.resolve(distPath ?? "./node_modules/bknd/dist", "static");
registerLocalMediaAdapter(); registerLocalMediaAdapter();
@@ -28,19 +27,17 @@ export async function createApp<Env = BunEnv>(
...config, ...config,
}, },
args ?? (process.env as Env), args ?? (process.env as Env),
opts,
); );
} }
export function createHandler<Env = BunEnv>( export function createHandler<Env = BunEnv>(
config: BunBkndConfig<Env> = {}, config: BunBkndConfig<Env> = {},
args: Env = {} as Env, args: Env = {} as Env,
opts?: RuntimeOptions,
) { ) {
let app: App | undefined; let app: App | undefined;
return async (req: Request) => { return async (req: Request) => {
if (!app) { if (!app) {
app = await createApp(config, args ?? (process.env as Env), opts); app = await createApp(config, args ?? (process.env as Env));
} }
return app.fetch(req); return app.fetch(req);
}; };
@@ -60,7 +57,6 @@ export function serve<Env = BunEnv>(
...serveOptions ...serveOptions
}: BunBkndConfig<Env> = {}, }: BunBkndConfig<Env> = {},
args: Env = {} as Env, args: Env = {} as Env,
opts?: RuntimeOptions,
) { ) {
Bun.serve({ Bun.serve({
...serveOptions, ...serveOptions,
@@ -77,7 +73,6 @@ export function serve<Env = BunEnv>(
serveStatic, serveStatic,
}, },
args, args,
opts,
), ),
}); });

View File

@@ -41,10 +41,10 @@ describe("cf adapter", () => {
}); });
adapterTestSuite<CloudflareBkndConfig, CloudflareContext<any>>(bunTestRunner, { adapterTestSuite<CloudflareBkndConfig, CloudflareContext<any>>(bunTestRunner, {
makeApp: async (c, a, o) => { makeApp: async (c, a) => {
return await createApp(c, { env: a } as any, o); return await createApp(c, { env: a } as any);
}, },
makeHandler: (c, a, o) => { makeHandler: (c, a) => {
console.log("args", a); console.log("args", a);
return async (request: any) => { return async (request: any) => {
const app = await createApp( const app = await createApp(
@@ -53,7 +53,6 @@ describe("cf adapter", () => {
connection: { url: DB_URL }, connection: { url: DB_URL },
}, },
a as any, a as any,
o,
); );
return app.fetch(request); return app.fetch(request);
}; };

View File

@@ -5,7 +5,7 @@ import { Hono } from "hono";
import { serveStatic } from "hono/cloudflare-workers"; import { serveStatic } from "hono/cloudflare-workers";
import type { MaybePromise } from "bknd"; import type { MaybePromise } from "bknd";
import { $console } from "bknd/utils"; import { $console } from "bknd/utils";
import { createRuntimeApp, type RuntimeOptions } from "bknd/adapter"; import { createRuntimeApp } from "bknd/adapter";
import { registerAsyncsExecutionContext, makeConfig, type CloudflareContext } from "./config"; import { registerAsyncsExecutionContext, makeConfig, type CloudflareContext } from "./config";
declare global { declare global {
@@ -36,10 +36,6 @@ export type CloudflareBkndConfig<Env = CloudflareEnv> = RuntimeBkndConfig<Env> &
export async function createApp<Env extends CloudflareEnv = CloudflareEnv>( export async function createApp<Env extends CloudflareEnv = CloudflareEnv>(
config: CloudflareBkndConfig<Env>, config: CloudflareBkndConfig<Env>,
ctx: Partial<CloudflareContext<Env>> = {}, ctx: Partial<CloudflareContext<Env>> = {},
opts: RuntimeOptions = {
// by default, require the app to be rebuilt every time
force: true,
},
) { ) {
const appConfig = await makeConfig( const appConfig = await makeConfig(
{ {
@@ -53,7 +49,7 @@ export async function createApp<Env extends CloudflareEnv = CloudflareEnv>(
}, },
ctx, ctx,
); );
return await createRuntimeApp<Env>(appConfig, ctx?.env, opts); return await createRuntimeApp<Env>(appConfig, ctx?.env);
} }
// compatiblity // compatiblity

View File

@@ -21,13 +21,6 @@ export type BkndConfig<Args = any> = CreateAppConfig & {
export type FrameworkBkndConfig<Args = any> = BkndConfig<Args>; export type FrameworkBkndConfig<Args = any> = BkndConfig<Args>;
export type CreateAdapterAppOptions = {
force?: boolean;
id?: string;
};
export type FrameworkOptions = CreateAdapterAppOptions;
export type RuntimeOptions = CreateAdapterAppOptions;
export type RuntimeBkndConfig<Args = any> = BkndConfig<Args> & { export type RuntimeBkndConfig<Args = any> = BkndConfig<Args> & {
distPath?: string; distPath?: string;
serveStatic?: MiddlewareHandler | [string, MiddlewareHandler]; serveStatic?: MiddlewareHandler | [string, MiddlewareHandler];
@@ -63,7 +56,6 @@ const apps = new Map<string, App>();
export async function createAdapterApp<Config extends BkndConfig = BkndConfig, Args = DefaultArgs>( export async function createAdapterApp<Config extends BkndConfig = BkndConfig, Args = DefaultArgs>(
config: Config = {} as Config, config: Config = {} as Config,
args?: Args, args?: Args,
opts?: CreateAdapterAppOptions,
): Promise<App> { ): Promise<App> {
const appConfig = await makeConfig(config, args); const appConfig = await makeConfig(config, args);
if (!appConfig.connection || !Connection.isConnection(appConfig.connection)) { if (!appConfig.connection || !Connection.isConnection(appConfig.connection)) {
@@ -85,9 +77,8 @@ export async function createAdapterApp<Config extends BkndConfig = BkndConfig, A
export async function createFrameworkApp<Args = DefaultArgs>( export async function createFrameworkApp<Args = DefaultArgs>(
config: FrameworkBkndConfig = {}, config: FrameworkBkndConfig = {},
args?: Args, args?: Args,
opts?: FrameworkOptions,
): Promise<App> { ): Promise<App> {
const app = await createAdapterApp(config, args, opts); const app = await createAdapterApp(config, args);
if (!app.isBuilt()) { if (!app.isBuilt()) {
if (config.onBuilt) { if (config.onBuilt) {
@@ -110,9 +101,8 @@ export async function createFrameworkApp<Args = DefaultArgs>(
export async function createRuntimeApp<Args = DefaultArgs>( export async function createRuntimeApp<Args = DefaultArgs>(
{ serveStatic, adminOptions, ...config }: RuntimeBkndConfig<Args> = {}, { serveStatic, adminOptions, ...config }: RuntimeBkndConfig<Args> = {},
args?: Args, args?: Args,
opts?: RuntimeOptions,
): Promise<App> { ): Promise<App> {
const app = await createAdapterApp(config, args, opts); const app = await createAdapterApp(config, args);
if (!app.isBuilt()) { if (!app.isBuilt()) {
app.emgr.onEvent( app.emgr.onEvent(

View File

@@ -1,4 +1,4 @@
import { createFrameworkApp, type FrameworkBkndConfig, type FrameworkOptions } from "bknd/adapter"; import { createFrameworkApp, type FrameworkBkndConfig } from "bknd/adapter";
import { isNode } from "bknd/utils"; import { isNode } from "bknd/utils";
import type { NextApiRequest } from "next"; import type { NextApiRequest } from "next";
@@ -10,9 +10,8 @@ export type NextjsBkndConfig<Env = NextjsEnv> = FrameworkBkndConfig<Env> & {
export async function getApp<Env = NextjsEnv>( export async function getApp<Env = NextjsEnv>(
config: NextjsBkndConfig<Env>, config: NextjsBkndConfig<Env>,
args: Env = {} as Env, args: Env = {} as Env,
opts?: FrameworkOptions,
) { ) {
return await createFrameworkApp(config, args ?? (process.env as Env), opts); return await createFrameworkApp(config, args ?? (process.env as Env));
} }
function getCleanRequest(req: Request, cleanRequest: NextjsBkndConfig["cleanRequest"]) { function getCleanRequest(req: Request, cleanRequest: NextjsBkndConfig["cleanRequest"]) {
@@ -41,10 +40,9 @@ function getCleanRequest(req: Request, cleanRequest: NextjsBkndConfig["cleanRequ
export function serve<Env = NextjsEnv>( export function serve<Env = NextjsEnv>(
{ cleanRequest, ...config }: NextjsBkndConfig<Env> = {}, { cleanRequest, ...config }: NextjsBkndConfig<Env> = {},
args: Env = {} as Env, args: Env = {} as Env,
opts?: FrameworkOptions,
) { ) {
return async (req: Request) => { return async (req: Request) => {
const app = await getApp(config, args, opts); const app = await getApp(config, args);
const request = getCleanRequest(req, cleanRequest); const request = getCleanRequest(req, cleanRequest);
return app.fetch(request); return app.fetch(request);
}; };

View File

@@ -2,7 +2,7 @@ import path from "node:path";
import { serve as honoServe } from "@hono/node-server"; import { serve as honoServe } from "@hono/node-server";
import { serveStatic } from "@hono/node-server/serve-static"; import { serveStatic } from "@hono/node-server/serve-static";
import { registerLocalMediaAdapter } from "adapter/node/storage"; import { registerLocalMediaAdapter } from "adapter/node/storage";
import { type RuntimeBkndConfig, createRuntimeApp, type RuntimeOptions } from "bknd/adapter"; import { type RuntimeBkndConfig, createRuntimeApp } from "bknd/adapter";
import { config as $config, type App } from "bknd"; import { config as $config, type App } from "bknd";
import { $console } from "bknd/utils"; import { $console } from "bknd/utils";
@@ -18,7 +18,6 @@ export type NodeBkndConfig<Env = NodeEnv> = RuntimeBkndConfig<Env> & {
export async function createApp<Env = NodeEnv>( export async function createApp<Env = NodeEnv>(
{ distPath, relativeDistPath, ...config }: NodeBkndConfig<Env> = {}, { distPath, relativeDistPath, ...config }: NodeBkndConfig<Env> = {},
args: Env = {} as Env, args: Env = {} as Env,
opts?: RuntimeOptions,
) { ) {
const root = path.relative( const root = path.relative(
process.cwd(), process.cwd(),
@@ -36,19 +35,17 @@ export async function createApp<Env = NodeEnv>(
}, },
// @ts-ignore // @ts-ignore
args ?? { env: process.env }, args ?? { env: process.env },
opts,
); );
} }
export function createHandler<Env = NodeEnv>( export function createHandler<Env = NodeEnv>(
config: NodeBkndConfig<Env> = {}, config: NodeBkndConfig<Env> = {},
args: Env = {} as Env, args: Env = {} as Env,
opts?: RuntimeOptions,
) { ) {
let app: App | undefined; let app: App | undefined;
return async (req: Request) => { return async (req: Request) => {
if (!app) { if (!app) {
app = await createApp(config, args ?? (process.env as Env), opts); app = await createApp(config, args ?? (process.env as Env));
} }
return app.fetch(req); return app.fetch(req);
}; };
@@ -57,13 +54,12 @@ export function createHandler<Env = NodeEnv>(
export function serve<Env = NodeEnv>( export function serve<Env = NodeEnv>(
{ port = $config.server.default_port, hostname, listener, ...config }: NodeBkndConfig<Env> = {}, { port = $config.server.default_port, hostname, listener, ...config }: NodeBkndConfig<Env> = {},
args: Env = {} as Env, args: Env = {} as Env,
opts?: RuntimeOptions,
) { ) {
honoServe( honoServe(
{ {
port, port,
hostname, hostname,
fetch: createHandler(config, args, opts), fetch: createHandler(config, args),
}, },
(connInfo) => { (connInfo) => {
$console.log(`Server is running on http://localhost:${connInfo.port}`); $console.log(`Server is running on http://localhost:${connInfo.port}`);

View File

@@ -10,6 +10,6 @@ afterAll(enableConsoleLog);
describe("react-router adapter", () => { describe("react-router adapter", () => {
adapterTestSuite(bunTestRunner, { adapterTestSuite(bunTestRunner, {
makeApp: rr.getApp, makeApp: rr.getApp,
makeHandler: (c, a, o) => (request: Request) => rr.serve(c, a?.env, o)({ request }), makeHandler: (c, a) => (request: Request) => rr.serve(c, a?.env)({ request }),
}); });
}); });

View File

@@ -1,5 +1,4 @@
import { type FrameworkBkndConfig, createFrameworkApp } from "bknd/adapter"; import { type FrameworkBkndConfig, createFrameworkApp } from "bknd/adapter";
import type { FrameworkOptions } from "adapter";
type ReactRouterEnv = NodeJS.ProcessEnv; type ReactRouterEnv = NodeJS.ProcessEnv;
type ReactRouterFunctionArgs = { type ReactRouterFunctionArgs = {
@@ -10,17 +9,15 @@ export type ReactRouterBkndConfig<Env = ReactRouterEnv> = FrameworkBkndConfig<En
export async function getApp<Env = ReactRouterEnv>( export async function getApp<Env = ReactRouterEnv>(
config: ReactRouterBkndConfig<Env>, config: ReactRouterBkndConfig<Env>,
args: Env = {} as Env, args: Env = {} as Env,
opts?: FrameworkOptions,
) { ) {
return await createFrameworkApp(config, args ?? process.env, opts); return await createFrameworkApp(config, args ?? process.env);
} }
export function serve<Env = ReactRouterEnv>( export function serve<Env = ReactRouterEnv>(
config: ReactRouterBkndConfig<Env> = {}, config: ReactRouterBkndConfig<Env> = {},
args: Env = {} as Env, args: Env = {} as Env,
opts?: FrameworkOptions,
) { ) {
return async (fnArgs: ReactRouterFunctionArgs) => { return async (fnArgs: ReactRouterFunctionArgs) => {
return (await getApp(config, args, opts)).fetch(fnArgs.request); return (await getApp(config, args)).fetch(fnArgs.request);
}; };
} }

View File

@@ -1,7 +1,7 @@
import { serveStatic } from "@hono/node-server/serve-static"; import { serveStatic } from "@hono/node-server/serve-static";
import { type DevServerOptions, default as honoViteDevServer } from "@hono/vite-dev-server"; import { type DevServerOptions, default as honoViteDevServer } from "@hono/vite-dev-server";
import type { App } from "bknd"; import type { App } from "bknd";
import { type RuntimeBkndConfig, createRuntimeApp, type FrameworkOptions } from "bknd/adapter"; import { type RuntimeBkndConfig, createRuntimeApp } from "bknd/adapter";
import { registerLocalMediaAdapter } from "bknd/adapter/node"; import { registerLocalMediaAdapter } from "bknd/adapter/node";
import { devServerConfig } from "./dev-server-config"; import { devServerConfig } from "./dev-server-config";
import type { MiddlewareHandler } from "hono"; import type { MiddlewareHandler } from "hono";
@@ -30,7 +30,6 @@ ${addBkndContext ? "<!-- BKND_CONTEXT -->" : ""}
async function createApp<ViteEnv>( async function createApp<ViteEnv>(
config: ViteBkndConfig<ViteEnv> = {}, config: ViteBkndConfig<ViteEnv> = {},
env: ViteEnv = {} as ViteEnv, env: ViteEnv = {} as ViteEnv,
opts: FrameworkOptions = {},
): Promise<App> { ): Promise<App> {
registerLocalMediaAdapter(); registerLocalMediaAdapter();
return await createRuntimeApp( return await createRuntimeApp(
@@ -47,18 +46,13 @@ async function createApp<ViteEnv>(
], ],
}, },
env, env,
opts,
); );
} }
export function serve<ViteEnv>( export function serve<ViteEnv>(config: ViteBkndConfig<ViteEnv> = {}, args?: ViteEnv) {
config: ViteBkndConfig<ViteEnv> = {},
args?: ViteEnv,
opts?: FrameworkOptions,
) {
return { return {
async fetch(request: Request, env: any, ctx: ExecutionContext) { async fetch(request: Request, env: any, ctx: ExecutionContext) {
const app = await createApp(config, env, opts); const app = await createApp(config, env);
return app.fetch(request, env, ctx); return app.fetch(request, env, ctx);
}, },
}; };