From feeb13c053ad012866b5d7aa520c0c027465ae26 Mon Sep 17 00:00:00 2001 From: dswbx Date: Sun, 1 Dec 2024 08:58:08 +0100 Subject: [PATCH] improved astro adapter (serving api) + added documentation --- app/src/adapter/astro/astro.adapter.ts | 18 +++- app/src/auth/api/AuthController.ts | 13 ++- app/src/auth/authenticate/Authenticator.ts | 1 + bun.lockb | Bin 825208 -> 824648 bytes docs/integration/astro.mdx | 120 +++++++++++++++++++++ docs/introduction.mdx | 9 ++ docs/mint.json | 1 + docs/package.json | 2 +- examples/astro/src/pages/api/[...api].ts | 25 ++--- 9 files changed, 166 insertions(+), 23 deletions(-) create mode 100644 docs/integration/astro.mdx diff --git a/app/src/adapter/astro/astro.adapter.ts b/app/src/adapter/astro/astro.adapter.ts index 6076750..71ad9f6 100644 --- a/app/src/adapter/astro/astro.adapter.ts +++ b/app/src/adapter/astro/astro.adapter.ts @@ -1,10 +1,8 @@ import { Api, type ApiOptions } from "bknd"; +import { App, type CreateAppConfig } from "bknd"; type TAstro = { - request: { - url: string; - headers: Headers; - }; + request: Request; }; export type Options = { @@ -19,3 +17,15 @@ export function getApi(Astro: TAstro, options: Options = { mode: "static" }) { headers: options.mode === "dynamic" ? Astro.request.headers : undefined }); } + +let app: App; +export function serve(config: CreateAppConfig) { + return async (args: TAstro) => { + if (!app) { + app = App.create(config); + + await app.build(); + } + return app.fetch(args.request); + }; +} diff --git a/app/src/auth/api/AuthController.ts b/app/src/auth/api/AuthController.ts index 5b0de2d..9afd302 100644 --- a/app/src/auth/api/AuthController.ts +++ b/app/src/auth/api/AuthController.ts @@ -11,10 +11,21 @@ export class AuthController implements ClassController { getMiddleware: MiddlewareHandler = async (c, next) => { // @todo: ONLY HOTFIX + // middlewares are added for all routes are registered. But we need to make sure that + // only HTML/JSON routes are adding a cookie to the response. Config updates might + // also use an extension "syntax", e.g. /api/system/patch/data/entities.posts + // This middleware should be extracted and added by each Controller individually, + // but it requires access to the auth secret. + // Note: This doesn't mean endpoints aren't protected, just the cookie is not set. const url = new URL(c.req.url); const last = url.pathname.split("/")?.pop(); const ext = last?.includes(".") ? last.split(".")?.pop() : undefined; - if (ext) { + if ( + !this.auth.authenticator.isJsonRequest(c) && + ["GET", "HEAD", "OPTIONS"].includes(c.req.method) && + ext && + ["js", "css", "png", "jpg", "jpeg", "svg", "ico"].includes(ext) + ) { isDebug() && console.log("Skipping auth", { ext }, url.pathname); } else { const user = await this.auth.authenticator.resolveAuthFromRequest(c); diff --git a/app/src/auth/authenticate/Authenticator.ts b/app/src/auth/authenticate/Authenticator.ts index 1955643..9040440 100644 --- a/app/src/auth/authenticate/Authenticator.ts +++ b/app/src/auth/authenticate/Authenticator.ts @@ -249,6 +249,7 @@ export class Authenticator = Record< } } + // @todo: move this to a server helper isJsonRequest(c: Context): boolean { //return c.req.header("Content-Type") === "application/x-www-form-urlencoded"; return c.req.header("Content-Type") === "application/json"; diff --git a/bun.lockb b/bun.lockb index 5ea65b55cf9f054b844fdc59741a9cc8e900e5cc..9717d2930aa347afc4dc09d33b6bc45a953a492b 100755 GIT binary patch delta 46310 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 diff --git a/docs/integration/astro.mdx b/docs/integration/astro.mdx new file mode 100644 index 0000000..7625494 --- /dev/null +++ b/docs/integration/astro.mdx @@ -0,0 +1,120 @@ +--- +title: 'Astro' +description: 'Run bknd inside Astro' +--- +import InstallBknd from '/snippets/install-bknd.mdx'; + +## Installation +Install bknd as a dependency: + + +For the Astro integration to work, you also need to [add the react integration](https://docs.astro.build/en/guides/integrations-guide/react/): +```bash +npx astro add react +``` + +You also need to make sure to set the output to `hybrid` in your Astro config: +```js {6} +// astro.config.mjs +import { defineConfig } from "astro/config"; +import react from "@astrojs/react"; + +export default defineConfig({ + output: "hybrid", + integrations: [react()] +}); +``` + + + If you don't want to use React with Astro, there is also an option to serve the bknd Admin UI + statically using Astro's middleware. In case you're interested in this, feel free to reach + out in [Discord](https://discord.gg/952SFk8Tb8) or open an [issue on GitHub](https://github.com/bknd-io/bknd/issues/new). + + +## Serve the API +Create a new catch-all route at `src/pages/api/[...api].ts`: +```ts src/pages/api/[...api].ts +import { serve } from "bknd/adapter/astro"; + +export const prerender = false; + +export const ALL = serve({ + connection: { + type: "libsql", + config: { + url: "http://127.0.0.1:8080" + } + } +}); +``` +For more information about the connection object, refer to the [Setup](/setup) guide. In the +special case of astro, you may also use your Astro DB credentials since it's also using LibSQL +under the hood. Refer to the [Astro DB documentation](https://docs.astro.build/en/guides/astro-db/) for more information. + +## Enabling the Admin UI +Create a new catch-all route at `src/pages/admin/[...admin].astro`: +```jsx src/pages/admin/[...admin].astro +--- +import { Admin } from "bknd/ui"; +import "bknd/dist/styles.css"; + +import { getApi } from "bknd/adapter/astro"; + +const api = getApi(Astro, { mode: "dynamic" }); +const user = api.getUser(); + +export const prerender = false; +--- + + + + + + +``` + +## Example usage of the API +You use the API in both static and SSR pages. Just note that on static pages, authentication +might not work as expected, because Cookies are not available in the static context. + +Here is an example of using the API in static context: +```jsx +--- +import { getApi } from "bknd/adapter/astro"; +const api = getApi(Astro); +const { data } = await api.data.readMany("todos"); +--- + +
    + {data.map((todo) => ( +
  • {todo.title}
  • + ))} +
+``` + +On SSR pages, you can also access the authenticated user: +```jsx +--- +import { getApi } from "bknd/adapter/astro"; +const api = getApi(Astro, { mode: "dynamic" }); +const user = api.getUser(); +const { data } = await api.data.readMany("todos"); + +export const prerender = false; +--- + +{user + ?

Logged in as {user.email}.

+ :

Not authenticated.

} +
    + {data.map((todo) => ( +
  • {todo.title}
  • + ))} +
+``` + +Check the [astro example](https://github.com/bknd-io/bknd/tree/main/examples/astro) for more implementation details. \ No newline at end of file diff --git a/docs/introduction.mdx b/docs/introduction.mdx index 38c4e63..d456f2b 100644 --- a/docs/introduction.mdx +++ b/docs/introduction.mdx @@ -46,6 +46,15 @@ in the future, so stay tuned! } href="/integration/remix" /> + + + + + } + href="/integration/astro" + /> diff --git a/docs/mint.json b/docs/mint.json index ecb2342..01f1cb4 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -108,6 +108,7 @@ "integration/bun", "integration/vite", "integration/express", + "integration/astro", "integration/nodejs", "integration/deno", "integration/browser" diff --git a/docs/package.json b/docs/package.json index 3459b6e..f9d266c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,6 +5,6 @@ "dev": "mintlify dev" }, "devDependencies": { - "mintlify": "^4.0.269" + "mintlify": "^4.0.285" } } \ No newline at end of file diff --git a/examples/astro/src/pages/api/[...api].ts b/examples/astro/src/pages/api/[...api].ts index 5baa0fa..ac2a896 100644 --- a/examples/astro/src/pages/api/[...api].ts +++ b/examples/astro/src/pages/api/[...api].ts @@ -1,21 +1,12 @@ -import type { APIRoute } from "astro"; -import { App } from "bknd"; +import { serve } from "bknd/adapter/astro"; export const prerender = false; -let app: App; -export const ALL: APIRoute = async ({ request }) => { - if (!app) { - app = App.create({ - connection: { - type: "libsql", - config: { - url: "http://127.0.0.1:8080" - } - } - }); - - await app.build(); +export const ALL = serve({ + connection: { + type: "libsql", + config: { + url: "http://127.0.0.1:8080" + } } - return app.fetch(request); -}; +});