mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-15 20:17:22 +00:00
improved astro adapter (serving api) + added documentation
This commit is contained in:
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -249,6 +249,7 @@ export class Authenticator<Strategies extends Record<string, Strategy> = 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";
|
||||
|
||||
120
docs/integration/astro.mdx
Normal file
120
docs/integration/astro.mdx
Normal file
@@ -0,0 +1,120 @@
|
||||
---
|
||||
title: 'Astro'
|
||||
description: 'Run bknd inside Astro'
|
||||
---
|
||||
import InstallBknd from '/snippets/install-bknd.mdx';
|
||||
|
||||
## Installation
|
||||
Install bknd as a dependency:
|
||||
<InstallBknd />
|
||||
|
||||
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()]
|
||||
});
|
||||
```
|
||||
|
||||
<Note>
|
||||
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).
|
||||
</Note>
|
||||
|
||||
## 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;
|
||||
---
|
||||
|
||||
<html>
|
||||
<body>
|
||||
<Admin
|
||||
withProvider={{ user }}
|
||||
config={{ basepath: "/admin", color_scheme: "dark" }}
|
||||
client:load
|
||||
/>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## 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");
|
||||
---
|
||||
|
||||
<ul>
|
||||
{data.map((todo) => (
|
||||
<li>{todo.title}</li>
|
||||
))}
|
||||
</ul>
|
||||
```
|
||||
|
||||
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
|
||||
? <p>Logged in as <b>{user.email}</b>.</p>
|
||||
: <p>Not authenticated.</p>}
|
||||
<ul>
|
||||
{data.map((todo) => (
|
||||
<li>{todo.title}</li>
|
||||
))}
|
||||
</ul>
|
||||
```
|
||||
|
||||
Check the [astro example](https://github.com/bknd-io/bknd/tree/main/examples/astro) for more implementation details.
|
||||
@@ -45,6 +45,15 @@ in the future, so stay tuned!
|
||||
17.424c.18 2.31.18 3.394.18 4.576h-5.35c0-.258.004-.493.009-.732c.014-.743.03-1.517-.09-3.081c-.16-2.29-1.147-2.799-2.961-2.799H3.305v-4.166h8.67c2.291 0 3.437-.696 3.437-2.54c0-1.623-1.146-2.605-3.437-2.605h-8.67V2h9.624c5.189 0 7.767 2.449 7.767 6.36c0 2.926-1.814 4.834-4.265 5.152c2.069.413 3.278 1.59 3.501 3.912" clip-rule="evenodd"/><path fill="currentColor" d="M3.305 22v-3.106h5.657c.945 0 1.15.7 1.15 1.118V22z"/></svg>
|
||||
</div>}
|
||||
href="/integration/remix"
|
||||
/>
|
||||
<Card
|
||||
title="Astro"
|
||||
icon={<div className="text-primary-light">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<rect width="24" height="24" fill="none"/><path fill="currentColor" d="M9.24 19.035c-.901-.826-1.164-2.561-.789-3.819c.65.793 1.552 1.044 2.486 1.186c1.44.218 2.856.137 4.195-.524c.153-.076.295-.177.462-.278c.126.365.159.734.115 1.11c-.107.915-.56 1.622-1.283 2.158c-.289.215-.594.406-.892.608c-.916.622-1.164 1.35-.82 2.41l.034.114a2.4 2.4 0 0 1-1.07-.918a2.6 2.6 0 0 1-.412-1.401c-.003-.248-.003-.497-.036-.74c-.081-.595-.36-.86-.883-.876a1.034 1.034 0 0 0-1.075.843q-.013.058-.033.126M4.1 15.007s2.666-1.303 5.34-1.303l2.016-6.26c.075-.304.296-.51.544-.51c.25 0 .47.206.545.51l2.016 6.26c3.167 0 5.34 1.303 5.34 1.303L15.363 2.602c-.13-.366-.35-.602-.645-.602H9.283c-.296 0-.506.236-.645.602c-.01.024-4.538 12.405-4.538 12.405"/>
|
||||
</svg>
|
||||
</div>}
|
||||
href="/integration/astro"
|
||||
/>
|
||||
<Card
|
||||
title="Cloudflare"
|
||||
|
||||
@@ -108,6 +108,7 @@
|
||||
"integration/bun",
|
||||
"integration/vite",
|
||||
"integration/express",
|
||||
"integration/astro",
|
||||
"integration/nodejs",
|
||||
"integration/deno",
|
||||
"integration/browser"
|
||||
|
||||
@@ -5,6 +5,6 @@
|
||||
"dev": "mintlify dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mintlify": "^4.0.269"
|
||||
"mintlify": "^4.0.285"
|
||||
}
|
||||
}
|
||||
@@ -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({
|
||||
export const ALL = serve({
|
||||
connection: {
|
||||
type: "libsql",
|
||||
config: {
|
||||
url: "http://127.0.0.1:8080"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await app.build();
|
||||
}
|
||||
return app.fetch(request);
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user