From b0c5f6307aabc58d5b2db94fb630df5cff859514 Mon Sep 17 00:00:00 2001 From: dswbx Date: Sat, 25 Jan 2025 09:09:09 +0100 Subject: [PATCH 1/3] updated adapters to automatically verify auth --- app/src/adapter/astro/astro.adapter.ts | 6 ++-- app/src/adapter/nextjs/nextjs.adapter.ts | 6 ++-- app/src/adapter/remix/AdminPage.tsx | 4 ++- app/src/adapter/remix/remix.adapter.ts | 17 ++++++++++ docs/integration/astro.mdx | 6 ++-- docs/integration/remix.mdx | 34 ++++++------------- .../astro/src/pages/admin/[...admin].astro | 3 +- examples/astro/src/pages/index.astro | 3 +- examples/astro/src/pages/ssr.astro | 3 +- examples/remix/app/root.tsx | 28 ++++++--------- examples/remix/app/routes/_index.tsx | 7 ++-- 11 files changed, 60 insertions(+), 57 deletions(-) diff --git a/app/src/adapter/astro/astro.adapter.ts b/app/src/adapter/astro/astro.adapter.ts index 479b873..fccfd7d 100644 --- a/app/src/adapter/astro/astro.adapter.ts +++ b/app/src/adapter/astro/astro.adapter.ts @@ -13,11 +13,13 @@ export type Options = { host?: string; }; -export function getApi(Astro: TAstro, options: Options = { mode: "static" }) { - return new Api({ +export async function getApi(Astro: TAstro, options: Options = { mode: "static" }) { + const api = new Api({ host: new URL(Astro.request.url).origin, headers: options.mode === "dynamic" ? Astro.request.headers : undefined }); + await api.verifyAuth(); + return api; } let app: App; diff --git a/app/src/adapter/nextjs/nextjs.adapter.ts b/app/src/adapter/nextjs/nextjs.adapter.ts index 65d5ffa..7e30d26 100644 --- a/app/src/adapter/nextjs/nextjs.adapter.ts +++ b/app/src/adapter/nextjs/nextjs.adapter.ts @@ -29,8 +29,10 @@ export function createApi({ req }: GetServerSidePropsContext) { } export function withApi(handler: (ctx: GetServerSidePropsContext & { api: Api }) => T) { - return (ctx: GetServerSidePropsContext & { api: Api }) => { - return handler({ ...ctx, api: createApi(ctx) }); + return async (ctx: GetServerSidePropsContext & { api: Api }) => { + const api = createApi(ctx); + await api.verifyAuth(); + return handler({ ...ctx, api }); }; } diff --git a/app/src/adapter/remix/AdminPage.tsx b/app/src/adapter/remix/AdminPage.tsx index 9361cc2..5c9e90b 100644 --- a/app/src/adapter/remix/AdminPage.tsx +++ b/app/src/adapter/remix/AdminPage.tsx @@ -1,9 +1,11 @@ +import { useAuth } from "bknd/client"; import type { BkndAdminProps } from "bknd/ui"; import { Suspense, lazy, useEffect, useState } from "react"; export function adminPage(props?: BkndAdminProps) { const Admin = lazy(() => import("bknd/ui").then((mod) => ({ default: mod.Admin }))); return () => { + const auth = useAuth(); const [loaded, setLoaded] = useState(false); useEffect(() => { if (typeof window === "undefined") return; @@ -13,7 +15,7 @@ export function adminPage(props?: BkndAdminProps) { return ( - + ); }; diff --git a/app/src/adapter/remix/remix.adapter.ts b/app/src/adapter/remix/remix.adapter.ts index c3d0c78..ed2818b 100644 --- a/app/src/adapter/remix/remix.adapter.ts +++ b/app/src/adapter/remix/remix.adapter.ts @@ -1,5 +1,6 @@ import { type FrameworkBkndConfig, createFrameworkApp } from "adapter"; import type { App } from "bknd"; +import { Api } from "bknd/client"; export type RemixBkndConfig = FrameworkBkndConfig; @@ -12,3 +13,19 @@ export function serve(config: RemixBkndConfig = {}) { return app.fetch(args.request); }; } + +export function withApi( + handler: (args: Args, api: Api) => Promise +) { + return async (args: Args) => { + if (!args.context.api) { + args.context.api = new Api({ + host: new URL(args.request.url).origin, + headers: args.request.headers + }); + await args.context.api.verifyAuth(); + } + + return handler(args, args.context.api); + }; +} diff --git a/docs/integration/astro.mdx b/docs/integration/astro.mdx index 63c2f31..057e0b1 100644 --- a/docs/integration/astro.mdx +++ b/docs/integration/astro.mdx @@ -65,7 +65,7 @@ import "bknd/dist/styles.css"; import { getApi } from "bknd/adapter/astro"; -const api = getApi(Astro, { mode: "dynamic" }); +const api = await getApi(Astro, { mode: "dynamic" }); const user = api.getUser(); export const prerender = false; @@ -94,7 +94,7 @@ Here is an example of using the API in static context: ```jsx --- import { getApi } from "bknd/adapter/astro"; -const api = getApi(Astro); +const api = await getApi(Astro); const { data } = await api.data.readMany("todos"); --- @@ -109,7 +109,7 @@ On SSR pages, you can also access the authenticated user: ```jsx --- import { getApi } from "bknd/adapter/astro"; -const api = getApi(Astro, { mode: "dynamic" }); +const api = await getApi(Astro, { mode: "dynamic" }); const user = api.getUser(); const { data } = await api.data.readMany("todos"); diff --git a/docs/integration/remix.mdx b/docs/integration/remix.mdx index 3aaadc6..d89c888 100644 --- a/docs/integration/remix.mdx +++ b/docs/integration/remix.mdx @@ -32,6 +32,9 @@ Now make sure that you wrap your root layout with the `ClientProvider` so that a share the same context: ```tsx // app/root.tsx +import { withApi } from "bknd/adapter/remix" +import { type Api, ClientProvider } from "bknd/client"; + export function Layout(props) { // nothing to change here, just for orientation return ( @@ -48,21 +51,12 @@ declare module "@remix-run/server-runtime" { } // export a loader that initiates the API -// and pass it through the context -export const loader = async (args: LoaderFunctionArgs) => { - const api = new Api({ - host: new URL(args.request.url).origin, - headers: args.request.headers - }); - - // get the user from the API - const user = api.getUser(); - - // add api to the context - args.context.api = api; - - return { user }; -}; +// and passes it down to args.context.api +export const loader = withApi(async (args: LoaderFunctionArgs, api: Api) => { + return { + user: api.getUser() + }; +}); export default function App() { const { user } = useLoaderData(); @@ -93,15 +87,9 @@ Since the API has already been constructed in the root layout, you can now use i import type { LoaderFunctionArgs } from "@remix-run/server-runtime"; import { useLoaderData } from "@remix-run/react"; -export const loader = async (args: LoaderFunctionArgs) => { - const { api } = args.context; - - // get the authenticated user - const user = api.getAuthState().user; - - // get the data from the API +export const loader = async ({ context: { api } }: LoaderFunctionArgs) => { const { data } = await api.data.readMany("todos"); - return { data, user }; + return { data, user: api.getUser() }; }; export default function Index() { diff --git a/examples/astro/src/pages/admin/[...admin].astro b/examples/astro/src/pages/admin/[...admin].astro index 612b801..8d34e21 100644 --- a/examples/astro/src/pages/admin/[...admin].astro +++ b/examples/astro/src/pages/admin/[...admin].astro @@ -4,8 +4,7 @@ import "bknd/dist/styles.css"; import { getApi } from "bknd/adapter/astro"; -const api = getApi(Astro, { mode: "dynamic" }); -await api.verifyAuth(); +const api = await getApi(Astro, { mode: "dynamic" }); const user = api.getUser(); export const prerender = false; diff --git a/examples/astro/src/pages/index.astro b/examples/astro/src/pages/index.astro index 4c2f31b..854df7f 100644 --- a/examples/astro/src/pages/index.astro +++ b/examples/astro/src/pages/index.astro @@ -2,7 +2,8 @@ import { getApi } from "bknd/adapter/astro"; import Card from "../components/Card.astro"; import Layout from "../layouts/Layout.astro"; -const api = getApi(Astro); + +const api = await getApi(Astro); const { data } = await api.data.readMany("todos"); --- diff --git a/examples/astro/src/pages/ssr.astro b/examples/astro/src/pages/ssr.astro index 726076d..ca8f380 100644 --- a/examples/astro/src/pages/ssr.astro +++ b/examples/astro/src/pages/ssr.astro @@ -2,8 +2,7 @@ import { getApi } from "bknd/adapter/astro"; import Card from "../components/Card.astro"; import Layout from "../layouts/Layout.astro"; -const api = getApi(Astro, { mode: "dynamic" }); -await api.verifyAuth(); +const api = await getApi(Astro, { mode: "dynamic" }); const { data } = await api.data.readMany("todos"); const user = api.getUser(); diff --git a/examples/remix/app/root.tsx b/examples/remix/app/root.tsx index 8930b4f..004ec11 100644 --- a/examples/remix/app/root.tsx +++ b/examples/remix/app/root.tsx @@ -1,12 +1,7 @@ import type { LoaderFunctionArgs } from "@remix-run/node"; import { Links, Meta, Outlet, Scripts, ScrollRestoration, useLoaderData } from "@remix-run/react"; -import { Api, ClientProvider } from "bknd/client"; - -declare module "@remix-run/server-runtime" { - export interface AppLoadContext { - api: Api; - } -} +import { withApi } from "bknd/adapter/remix"; +import { type Api, ClientProvider } from "bknd/client"; export function Layout({ children }: { children: React.ReactNode }) { return ( @@ -26,20 +21,17 @@ export function Layout({ children }: { children: React.ReactNode }) { ); } -export const loader = async (args: LoaderFunctionArgs) => { - const api = new Api({ - host: new URL(args.request.url).origin, - headers: args.request.headers - }); +declare module "@remix-run/server-runtime" { + export interface AppLoadContext { + api: Api; + } +} - // add api to the context - args.context.api = api; - - await api.verifyAuth(); +export const loader = withApi(async (args: LoaderFunctionArgs, api: Api) => { return { - user: api.getAuthState()?.user + user: api.getUser() }; -}; +}); export default function App() { const data = useLoaderData(); diff --git a/examples/remix/app/routes/_index.tsx b/examples/remix/app/routes/_index.tsx index eef795d..1cbbe19 100644 --- a/examples/remix/app/routes/_index.tsx +++ b/examples/remix/app/routes/_index.tsx @@ -1,19 +1,20 @@ import { type MetaFunction, useLoaderData } from "@remix-run/react"; import type { LoaderFunctionArgs } from "@remix-run/server-runtime"; +import { useAuth } from "bknd/client"; export const meta: MetaFunction = () => { return [{ title: "Remix & bknd" }, { name: "description", content: "Welcome to Remix & bknd!" }]; }; -export const loader = async (args: LoaderFunctionArgs) => { - const api = args.context.api; - await api.verifyAuth(); +export const loader = async ({ context: { api } }: LoaderFunctionArgs) => { const { data } = await api.data.readMany("todos"); return { data, user: api.getUser() }; }; export default function Index() { const { data, user } = useLoaderData(); + const auth = useAuth(); + console.log("auth", auth); return (
From 9ddacb7ae568270d0c7d0d5493ecb8513d1637eb Mon Sep 17 00:00:00 2001 From: dswbx Date: Sat, 25 Jan 2025 11:54:19 +0100 Subject: [PATCH 2/3] added adapter exports, generalized env-depending config construction --- app/build.ts | 8 +++++++ app/package.json | 4 ++++ app/src/adapter/astro/astro.adapter.ts | 9 ++++---- .../cloudflare/cloudflare-workers.adapter.ts | 14 +++++------- app/src/adapter/cloudflare/modes/cached.ts | 4 ++-- app/src/adapter/cloudflare/modes/durable.ts | 4 ++-- app/src/adapter/cloudflare/modes/fresh.ts | 4 ++-- app/src/adapter/index.ts | 22 +++++++++---------- app/src/adapter/remix/remix.adapter.ts | 14 ++++++++---- examples/astro/src/pages/api/[...api].ts | 3 ++- examples/cloudflare-worker/src/index.ts | 2 +- 11 files changed, 53 insertions(+), 35 deletions(-) diff --git a/app/build.ts b/app/build.ts index e931021..3c37c6e 100644 --- a/app/build.ts +++ b/app/build.ts @@ -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("bun")); await tsup.build(baseConfig("astro")); diff --git a/app/package.json b/app/package.json index a04b686..a2c0893 100644 --- a/app/package.json +++ b/app/package.json @@ -148,6 +148,10 @@ "import": "./dist/adapter/cloudflare/index.js", "require": "./dist/adapter/cloudflare/index.cjs" }, + "./adapter": { + "types": "./dist/types/adapter/index.d.ts", + "import": "./dist/adapter/index.js" + }, "./adapter/vite": { "types": "./dist/types/adapter/vite/index.d.ts", "import": "./dist/adapter/vite/index.js", diff --git a/app/src/adapter/astro/astro.adapter.ts b/app/src/adapter/astro/astro.adapter.ts index 479b873..764e100 100644 --- a/app/src/adapter/astro/astro.adapter.ts +++ b/app/src/adapter/astro/astro.adapter.ts @@ -1,7 +1,7 @@ import { type FrameworkBkndConfig, createFrameworkApp } from "adapter"; import { Api, type ApiOptions, type App } from "bknd"; -export type AstroBkndConfig = FrameworkBkndConfig; +export type AstroBkndConfig = FrameworkBkndConfig; type TAstro = { request: Request; @@ -21,10 +21,11 @@ export function getApi(Astro: TAstro, options: Options = { mode: "static" }) { } let app: App; -export function serve(config: AstroBkndConfig = {}) { - return async (args: TAstro) => { +export function serve(config: AstroBkndConfig = {}) { + return async (args: Context) => { + console.log("args", Object.keys(args)); if (!app) { - app = await createFrameworkApp(config); + app = await createFrameworkApp(config, args); } return app.fetch(args.request); }; diff --git a/app/src/adapter/cloudflare/cloudflare-workers.adapter.ts b/app/src/adapter/cloudflare/cloudflare-workers.adapter.ts index da3c762..cfcba5d 100644 --- a/app/src/adapter/cloudflare/cloudflare-workers.adapter.ts +++ b/app/src/adapter/cloudflare/cloudflare-workers.adapter.ts @@ -1,4 +1,3 @@ -import type { CreateAppConfig } from "bknd"; import { Hono } from "hono"; import { serveStatic } from "hono/cloudflare-workers"; import type { FrameworkBkndConfig } from "../index"; @@ -6,10 +5,9 @@ import { getCached } from "./modes/cached"; import { getDurable } from "./modes/durable"; import { getFresh, getWarm } from "./modes/fresh"; -export type CloudflareBkndConfig = Omit & { - app: CreateAppConfig | ((env: Env) => CreateAppConfig); +export type CloudflareBkndConfig = FrameworkBkndConfig> & { mode?: "warm" | "fresh" | "cache" | "durable"; - bindings?: (env: Env) => { + bindings?: (args: Context) => { kv?: KVNamespace; dobj?: DurableObjectNamespace; }; @@ -21,15 +19,15 @@ export type CloudflareBkndConfig = Omit & html?: string; }; -export type Context = { +export type Context = { request: Request; - env: any; + env: Env; ctx: ExecutionContext; }; -export function serve(config: CloudflareBkndConfig) { +export function serve(config: CloudflareBkndConfig) { return { - async fetch(request: Request, env: any, ctx: ExecutionContext) { + async fetch(request: Request, env: Env, ctx: ExecutionContext) { const url = new URL(request.url); const manifest = config.manifest; diff --git a/app/src/adapter/cloudflare/modes/cached.ts b/app/src/adapter/cloudflare/modes/cached.ts index a238ae0..2c04f51 100644 --- a/app/src/adapter/cloudflare/modes/cached.ts +++ b/app/src/adapter/cloudflare/modes/cached.ts @@ -2,7 +2,7 @@ import { createRuntimeApp } from "adapter"; import { App } from "bknd"; 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)!; if (!kv) throw new Error("kv namespace is not defined in cloudflare.bindings"); const key = config.key ?? "app"; @@ -37,7 +37,7 @@ export async function getCached(config: CloudflareBkndConfig, { env, ctx }: Cont }, adminOptions: { html: config.html } }, - env + { env, ctx, ...args } ); if (!cachedConfig) { diff --git a/app/src/adapter/cloudflare/modes/durable.ts b/app/src/adapter/cloudflare/modes/durable.ts index 3787b5c..4c7233b 100644 --- a/app/src/adapter/cloudflare/modes/durable.ts +++ b/app/src/adapter/cloudflare/modes/durable.ts @@ -1,5 +1,5 @@ import { DurableObject } from "cloudflare:workers"; -import { createRuntimeApp } from "adapter"; +import { createRuntimeApp, makeConfig } from "adapter"; import type { CloudflareBkndConfig, Context } from "adapter/cloudflare"; import type { App, CreateAppConfig } from "bknd"; @@ -17,7 +17,7 @@ export async function getDurable(config: CloudflareBkndConfig, ctx: Context) { const id = dobj.idFromName(key); 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, { config: create_config, diff --git a/app/src/adapter/cloudflare/modes/fresh.ts b/app/src/adapter/cloudflare/modes/fresh.ts index cb5ece7..30272bf 100644 --- a/app/src/adapter/cloudflare/modes/fresh.ts +++ b/app/src/adapter/cloudflare/modes/fresh.ts @@ -2,13 +2,13 @@ import { createRuntimeApp } from "adapter"; import type { App } from "bknd"; 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( { ...config, adminOptions: config.html ? { html: config.html } : undefined }, - env + ctx ); } diff --git a/app/src/adapter/index.ts b/app/src/adapter/index.ts index 19bcdef..492f55e 100644 --- a/app/src/adapter/index.ts +++ b/app/src/adapter/index.ts @@ -5,16 +5,16 @@ import type { MiddlewareHandler } from "hono"; import { StorageLocalAdapter } from "media/storage/adapters/StorageLocalAdapter"; import type { AdminControllerOptions } from "modules/server/AdminController"; -export type BkndConfig = CreateAppConfig & { - app?: CreateAppConfig | ((env: Env) => CreateAppConfig); +export type BkndConfig = CreateAppConfig & { + app?: CreateAppConfig | ((args: Args) => CreateAppConfig); onBuilt?: (app: App) => Promise; beforeBuild?: (app: App) => Promise; buildConfig?: Parameters[0]; }; -export type FrameworkBkndConfig = BkndConfig; +export type FrameworkBkndConfig = BkndConfig; -export type RuntimeBkndConfig = BkndConfig & { +export type RuntimeBkndConfig = BkndConfig & { distPath?: string; }; @@ -46,14 +46,14 @@ export function registerLocalMediaAdapter() { registries.media.register("local", StorageLocalAdapter); } -export function makeConfig(config: BkndConfig, env?: Env): CreateAppConfig { +export function makeConfig(config: BkndConfig, args?: Args): CreateAppConfig { let additionalConfig: CreateAppConfig = {}; if ("app" in config && config.app) { if (typeof config.app === "function") { - if (!env) { - throw new Error("env is required when config.app is a function"); + if (!args) { + throw new Error("args is required when config.app is a function"); } - additionalConfig = config.app(env); + additionalConfig = config.app(args); } else { additionalConfig = config.app; } @@ -62,11 +62,11 @@ export function makeConfig(config: BkndConfig, env?: Env): Creat return { ...config, ...additionalConfig }; } -export async function createFrameworkApp( +export async function createFrameworkApp( config: FrameworkBkndConfig, - env?: Env + args?: Args ): Promise { - const app = App.create(makeConfig(config, env)); + const app = App.create(makeConfig(config, args)); if (config.onBuilt) { app.emgr.onEvent( diff --git a/app/src/adapter/remix/remix.adapter.ts b/app/src/adapter/remix/remix.adapter.ts index c3d0c78..7681fd4 100644 --- a/app/src/adapter/remix/remix.adapter.ts +++ b/app/src/adapter/remix/remix.adapter.ts @@ -1,13 +1,19 @@ import { type FrameworkBkndConfig, createFrameworkApp } from "adapter"; import type { App } from "bknd"; -export type RemixBkndConfig = FrameworkBkndConfig; +export type RemixBkndConfig = FrameworkBkndConfig; + +type RemixContext = { + request: Request; +}; let app: App; -export function serve(config: RemixBkndConfig = {}) { - return async (args: { request: Request }) => { +export function serve( + config: RemixBkndConfig = {} +) { + return async (args: Args) => { if (!app) { - app = await createFrameworkApp(config); + app = await createFrameworkApp(config, args); } return app.fetch(args.request); }; diff --git a/examples/astro/src/pages/api/[...api].ts b/examples/astro/src/pages/api/[...api].ts index abbcca7..82d3c4e 100644 --- a/examples/astro/src/pages/api/[...api].ts +++ b/examples/astro/src/pages/api/[...api].ts @@ -1,3 +1,4 @@ +import type { APIContext } from "astro"; import { App } from "bknd"; import { serve } from "bknd/adapter/astro"; import { registerLocalMediaAdapter } from "bknd/adapter/node"; @@ -23,7 +24,7 @@ declare module "bknd/core" { interface DB extends Database {} } -export const ALL = serve({ +export const ALL = serve({ // we can use any libsql config, and if omitted, uses in-memory connection: { type: "libsql", diff --git a/examples/cloudflare-worker/src/index.ts b/examples/cloudflare-worker/src/index.ts index e7a0f5e..dbb2e9b 100644 --- a/examples/cloudflare-worker/src/index.ts +++ b/examples/cloudflare-worker/src/index.ts @@ -3,7 +3,7 @@ import { serve } from "bknd/adapter/cloudflare"; import manifest from "__STATIC_CONTENT_MANIFEST"; export default serve({ - app: (env: Env) => ({ + app: (args) => ({ connection: { type: "libsql", config: { From 1beac5043be234c26edcb56b2ddfce10f0c60134 Mon Sep 17 00:00:00 2001 From: dswbx Date: Sat, 25 Jan 2025 12:33:05 +0100 Subject: [PATCH 3/3] updated cloudflare adapter docs to match new args --- app/src/adapter/astro/astro.adapter.ts | 1 - docs/integration/cloudflare.mdx | 35 +++++++++++++------------- docs/integration/remix.mdx | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/src/adapter/astro/astro.adapter.ts b/app/src/adapter/astro/astro.adapter.ts index b608419..e8cb58a 100644 --- a/app/src/adapter/astro/astro.adapter.ts +++ b/app/src/adapter/astro/astro.adapter.ts @@ -25,7 +25,6 @@ export async function getApi(Astro: TAstro, options: Options = { mode: "static" let app: App; export function serve(config: AstroBkndConfig = {}) { return async (args: Context) => { - console.log("args", Object.keys(args)); if (!app) { app = await createFrameworkApp(config, args); } diff --git a/docs/integration/cloudflare.mdx b/docs/integration/cloudflare.mdx index 22785f8..6cf92ee 100644 --- a/docs/integration/cloudflare.mdx +++ b/docs/integration/cloudflare.mdx @@ -16,11 +16,11 @@ and then install bknd as a dependency: If you don't choose anything specific, the following code will use the `warm` mode. See the chapter [Using a different mode](#using-a-different-mode) for available modes. -``` ts +```ts import { serve } from "bknd/adapter/cloudflare"; -export default serve({ - app: (env: Env) => ({ +export default serve({ + app: ({ env }) => ({ connection: { type: "libsql", config: { @@ -50,12 +50,12 @@ bucket = "node_modules/bknd/dist/static" ``` And then modify the worker entry as follows: -``` ts {2, 14, 15} +```ts {2, 14, 15} import { serve } from "bknd/adapter/cloudflare"; import manifest from "__STATIC_CONTENT_MANIFEST"; -export default serve({ - app: (env: Env) => ({ +export default serve({ + app: ({ env }) => ({ connection: { type: "libsql", config: { @@ -75,8 +75,8 @@ You can also add custom routes by defining them after the app has been built, li import { serve } from "bknd/adapter/cloudflare"; import manifest from "__STATIC_CONTENT_MANIFEST"; -export default serve({ - app: (env: Env) => ({ +export default serve({ + app: ({ env }) => ({ connection: { type: "libsql", config: { @@ -111,7 +111,7 @@ mode`, like so: import { serve } from "bknd/adapter/cloudflare"; export default serve({ - /* ... */, + // ... mode: "fresh" // mode: "fresh" | "warm" | "cache" | "durable" }); ``` @@ -119,13 +119,14 @@ export default serve({ ### Mode: `cache` For the cache mode to work, you also need to specify the KV to be used. For this, use the `bindings` property: + ```ts import { serve } from "bknd/adapter/cloudflare"; -export default serve({ - /* ... */, +export default serve({ + // ... mode: "cache", - bindings: (env: Env) => ({ kv: env.KV }) + bindings: ({ env }) => ({ kv: env.KV }) }); ``` @@ -136,10 +137,10 @@ environment, and additionally export the `DurableBkndApp` class: import { serve, DurableBkndApp } from "bknd/adapter/cloudflare"; export { DurableBkndApp }; -export default serve({ - /* ... */, +export default serve({ + // ... mode: "durable", - bindings: (env: Env) => ({ dobj: env.DOBJ }), + bindings: ({ env }) => ({ dobj: env.DOBJ }), keepAliveSeconds: 60 // optional }); ``` @@ -164,9 +165,9 @@ import type { App } from "bknd"; import { serve, DurableBkndApp } from "bknd/adapter/cloudflare"; export default serve({ - /* ... */, + // ... mode: "durable", - bindings: (env: Env) => ({ dobj: env.DOBJ }), + bindings: ({ env }) => ({ dobj: env.DOBJ }), keepAliveSeconds: 60 // optional }); diff --git a/docs/integration/remix.mdx b/docs/integration/remix.mdx index d89c888..5029859 100644 --- a/docs/integration/remix.mdx +++ b/docs/integration/remix.mdx @@ -10,7 +10,7 @@ Install bknd as a dependency: ## Serve the API Create a new api splat route file at `app/routes/api.$.ts`: -``` tsx +```ts // app/routes/api.$.ts import { serve } from "bknd/adapter/remix";