mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-15 20:17:22 +00:00
docs: added basic Admin UI configuration documentation
Added a new `BkndAdminConfig` type to streamline Admin UI configuration options, consolidating properties for base path, logo return path, theme, entities, and app shell settings. Updated `BkndAdminProps` to utilize this new configuration type. Additionally, introduced a new documentation section for extending the Admin UI, detailing customization options and providing examples for advanced usage.
This commit is contained in:
@@ -8,7 +8,33 @@ import * as AppShell from "ui/layouts/AppShell/AppShell";
|
|||||||
import { ClientProvider, useBkndWindowContext, type ClientProviderProps } from "./client";
|
import { ClientProvider, useBkndWindowContext, type ClientProviderProps } from "./client";
|
||||||
import { createMantineTheme } from "./lib/mantine/theme";
|
import { createMantineTheme } from "./lib/mantine/theme";
|
||||||
import { Routes } from "./routes";
|
import { Routes } from "./routes";
|
||||||
import type { BkndAdminAppShellOptions, BkndAdminEntitiesOptions } from "ui/options";
|
import type { BkndAdminAppShellOptions, BkndAdminEntitiesOptions } from "./options";
|
||||||
|
|
||||||
|
export type BkndAdminConfig = {
|
||||||
|
/**
|
||||||
|
* Base path of the Admin UI
|
||||||
|
* @default `/`
|
||||||
|
*/
|
||||||
|
basepath?: string;
|
||||||
|
/**
|
||||||
|
* Path to return to when clicking the logo
|
||||||
|
* @default `/`
|
||||||
|
*/
|
||||||
|
logo_return_path?: string;
|
||||||
|
/**
|
||||||
|
* Theme of the Admin UI
|
||||||
|
* @default `system`
|
||||||
|
*/
|
||||||
|
theme?: AppTheme;
|
||||||
|
/**
|
||||||
|
* Entities configuration like headers, footers, actions, field renders, etc.
|
||||||
|
*/
|
||||||
|
entities?: BkndAdminEntitiesOptions;
|
||||||
|
/**
|
||||||
|
* App shell configuration like user menu actions.
|
||||||
|
*/
|
||||||
|
appShell?: BkndAdminAppShellOptions;
|
||||||
|
};
|
||||||
|
|
||||||
export type BkndAdminProps = {
|
export type BkndAdminProps = {
|
||||||
/**
|
/**
|
||||||
@@ -16,37 +42,13 @@ export type BkndAdminProps = {
|
|||||||
*/
|
*/
|
||||||
baseUrl?: string;
|
baseUrl?: string;
|
||||||
/**
|
/**
|
||||||
* Whether to wrap Admin in a <ClientProvider />
|
* Whether to wrap Admin in a `<ClientProvider />`
|
||||||
*/
|
*/
|
||||||
withProvider?: boolean | ClientProviderProps;
|
withProvider?: boolean | ClientProviderProps;
|
||||||
/**
|
/**
|
||||||
* Admin UI customization options
|
* Admin UI customization options
|
||||||
*/
|
*/
|
||||||
config?: {
|
config?: BkndAdminConfig;
|
||||||
/**
|
|
||||||
* Base path of the Admin UI
|
|
||||||
* @default `/`
|
|
||||||
*/
|
|
||||||
basepath?: string;
|
|
||||||
/**
|
|
||||||
* Path to return to when clicking the logo
|
|
||||||
* @default `/`
|
|
||||||
*/
|
|
||||||
logo_return_path?: string;
|
|
||||||
/**
|
|
||||||
* Theme of the Admin UI
|
|
||||||
* @default `system`
|
|
||||||
*/
|
|
||||||
theme?: AppTheme;
|
|
||||||
/**
|
|
||||||
* Entities configuration like headers, footers, actions, field renders, etc.
|
|
||||||
*/
|
|
||||||
entities?: BkndAdminEntitiesOptions;
|
|
||||||
/**
|
|
||||||
* App shell configuration like user menu actions.
|
|
||||||
*/
|
|
||||||
appShell?: BkndAdminAppShellOptions;
|
|
||||||
};
|
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export { default as Admin, type BkndAdminProps } from "./Admin";
|
export { default as Admin, type BkndAdminProps, type BkndAdminConfig } from "./Admin";
|
||||||
export * from "./components/form/json-schema-form";
|
export * from "./components/form/json-schema-form";
|
||||||
export { JsonViewer } from "./components/code/JsonViewer";
|
export { JsonViewer } from "./components/code/JsonViewer";
|
||||||
export type * from "./options";
|
export type * from "./options";
|
||||||
|
|||||||
201
docs/content/docs/(documentation)/extending/admin.mdx
Normal file
201
docs/content/docs/(documentation)/extending/admin.mdx
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
---
|
||||||
|
title: Admin UI
|
||||||
|
tags: ["documentation"]
|
||||||
|
---
|
||||||
|
|
||||||
|
import { TypeTable } from "fumadocs-ui/components/type-table";
|
||||||
|
|
||||||
|
|
||||||
|
bknd features an integrated Admin UI that can be used to:
|
||||||
|
- fully manage your backend visually when run in [`db` mode](/usage/introduction/#ui-only-mode)
|
||||||
|
- manage your database contents
|
||||||
|
- manage your media contents
|
||||||
|
|
||||||
|
In case you're using bknd with a [React framework](integration/introduction/#start-with-a-framework) and render the Admin as React component, you can go further and customize the Admin UI to your liking.
|
||||||
|
|
||||||
|
<AutoTypeTable path="../app/src/ui/Admin.tsx" name="BkndAdminProps" />
|
||||||
|
|
||||||
|
|
||||||
|
## Advanced Example
|
||||||
|
|
||||||
|
The following example shows how to customize the Admin UI for each entity.
|
||||||
|
|
||||||
|
- adds a custom action item to the user menu (top right)
|
||||||
|
- adds a custom action item to the entity list
|
||||||
|
- adds a custom action item to the entity create/update form
|
||||||
|
- overrides the rendering of the title field
|
||||||
|
- renders a custom header for the entity
|
||||||
|
- renders a custom footer for the entity
|
||||||
|
- adds a custom route
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { Admin } from "bknd/ui";
|
||||||
|
import { Route } from "wouter";
|
||||||
|
|
||||||
|
export function App() {
|
||||||
|
return (
|
||||||
|
<Admin
|
||||||
|
withProvider
|
||||||
|
config={{
|
||||||
|
appShell: {
|
||||||
|
// add a custom user menu item (top right)
|
||||||
|
userMenu: [
|
||||||
|
{
|
||||||
|
label: "Custom",
|
||||||
|
onClick: () => alert("custom"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
entities: {
|
||||||
|
// use any entity that is registered
|
||||||
|
tests: {
|
||||||
|
actions: (context, entity, data) => ({
|
||||||
|
primary: [
|
||||||
|
// this action is only rendered in the update context
|
||||||
|
context === "update" && {
|
||||||
|
children: "another",
|
||||||
|
onClick: () => alert("another"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
context: [
|
||||||
|
// this action is always rendered in the dropdown
|
||||||
|
{
|
||||||
|
label: "Custom",
|
||||||
|
onClick: () =>
|
||||||
|
alert(
|
||||||
|
"custom: " +
|
||||||
|
JSON.stringify({ context, entity: entity.name, data }),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
// render a header for the entity
|
||||||
|
header: (context, entity, data) => <div>test header</div>,
|
||||||
|
// override the rendering of the title field
|
||||||
|
fields: {
|
||||||
|
title: {
|
||||||
|
render: (context, entity, field, ctx) => {
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={ctx.value}
|
||||||
|
onChange={(e) => ctx.handleChange(e.target.value)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// system entities work too
|
||||||
|
users: {
|
||||||
|
header: () => {
|
||||||
|
return <div>System entity</div>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* You may also add custom routes, these always have precedence over the Admin routes */}
|
||||||
|
<Route path="/data/custom">
|
||||||
|
<div>custom</div>
|
||||||
|
</Route>
|
||||||
|
</Admin>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## `config`
|
||||||
|
|
||||||
|
<AutoTypeTable path="../app/src/ui/Admin.tsx" name="BkndAdminConfig" />
|
||||||
|
|
||||||
|
### `entities`
|
||||||
|
|
||||||
|
With the `entities` option, you can customize the Admin UI for each entity. You can override the header, footer, add additional actions, and override each field rendering.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export type BkndAdminEntityContext = "list" | "create" | "update";
|
||||||
|
|
||||||
|
export type BkndAdminEntitiesOptions = {
|
||||||
|
[E in keyof DB]?: BkndAdminEntityOptions<E>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BkndAdminEntityOptions<E extends keyof DB | string> = {
|
||||||
|
/**
|
||||||
|
* Header to be rendered depending on the context
|
||||||
|
*/
|
||||||
|
header?: (
|
||||||
|
context: BkndAdminEntityContext,
|
||||||
|
entity: Entity,
|
||||||
|
data?: DB[E],
|
||||||
|
) => ReactNode | void | undefined;
|
||||||
|
/**
|
||||||
|
* Footer to be rendered depending on the context
|
||||||
|
*/
|
||||||
|
footer?: (
|
||||||
|
context: BkndAdminEntityContext,
|
||||||
|
entity: Entity,
|
||||||
|
data?: DB[E],
|
||||||
|
) => ReactNode | void | undefined;
|
||||||
|
/**
|
||||||
|
* Actions to be rendered depending on the context
|
||||||
|
*/
|
||||||
|
actions?: (
|
||||||
|
context: BkndAdminEntityContext,
|
||||||
|
entity: Entity,
|
||||||
|
data?: DB[E],
|
||||||
|
) => {
|
||||||
|
/**
|
||||||
|
* Primary actions are always visible
|
||||||
|
*/
|
||||||
|
primary?: (ButtonProps | undefined | null | false)[];
|
||||||
|
/**
|
||||||
|
* Context actions are rendered in a dropdown
|
||||||
|
*/
|
||||||
|
context?: DropdownProps["items"];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Field UI overrides
|
||||||
|
*/
|
||||||
|
fields?: {
|
||||||
|
[F in keyof DB[E]]?: BkndAdminEntityFieldOptions<E>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BkndAdminEntityFieldOptions<E extends keyof DB | string> = {
|
||||||
|
/**
|
||||||
|
* Override the rendering of a certain field
|
||||||
|
*/
|
||||||
|
render?: (
|
||||||
|
context: BkndAdminEntityContext,
|
||||||
|
entity: Entity,
|
||||||
|
field: Field,
|
||||||
|
ctx: {
|
||||||
|
data?: DB[E];
|
||||||
|
value?: DB[E][keyof DB[E]];
|
||||||
|
handleChange: (value: any) => void;
|
||||||
|
},
|
||||||
|
) => ReactNode | void | undefined;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### `appShell`
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export type DropdownItem =
|
||||||
|
| (() => ReactNode)
|
||||||
|
| {
|
||||||
|
label: string | ReactElement;
|
||||||
|
icon?: any;
|
||||||
|
onClick?: () => void;
|
||||||
|
destructive?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
title?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BkndAdminAppShellOptions = {
|
||||||
|
userMenu?: (DropdownItem | undefined | boolean)[];
|
||||||
|
};
|
||||||
|
```
|
||||||
@@ -23,26 +23,6 @@ export default {
|
|||||||
} satisfies BkndConfig;
|
} satisfies BkndConfig;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The `BkndConfig` extends the [`CreateAppConfig`](/usage/introduction#configuration-createappconfig) type with the following properties:
|
|
||||||
|
|
||||||
{/* <AutoTypeTable path="../app/src/adapter/index.ts" name="BkndConfig" /> */}
|
|
||||||
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
export type BkndConfig = CreateAppConfig & {
|
|
||||||
// return the app configuration as object or from a function
|
|
||||||
app?: CreateAppConfig | ((args: Args) => CreateAppConfig);
|
|
||||||
// called before the app is built
|
|
||||||
beforeBuild?: (app: App) => Promise<void>;
|
|
||||||
// called after the app has been built
|
|
||||||
onBuilt?: (app: App) => Promise<void>;
|
|
||||||
// passed as the first argument to the `App.build` method
|
|
||||||
buildConfig?: Parameters<App["build"]>[0];
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
The supported configuration file extensions are `js`, `ts`, `mjs`, `cjs` and `json`. Throughout the documentation, we'll use `ts` for the file extension.
|
The supported configuration file extensions are `js`, `ts`, `mjs`, `cjs` and `json`. Throughout the documentation, we'll use `ts` for the file extension.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
@@ -74,7 +54,177 @@ export default {
|
|||||||
} satisfies BkndConfig;
|
} satisfies BkndConfig;
|
||||||
```
|
```
|
||||||
|
|
||||||
### `app` (CreateAppConfig)
|
|
||||||
|
## Configuration (`BkndConfig`)
|
||||||
|
|
||||||
|
The `BkndConfig` type is the main configuration object for the `createApp` function. It has
|
||||||
|
the following properties:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import type { App, InitialModuleConfigs, ModuleBuildContext, Connection, MaybePromise } from "bknd";
|
||||||
|
import type { Config } from "@libsql/client";
|
||||||
|
|
||||||
|
type AppPlugin = (app: App) => Promise<void> | void;
|
||||||
|
type ManagerOptions = {
|
||||||
|
basePath?: string;
|
||||||
|
trustFetched?: boolean;
|
||||||
|
onFirstBoot?: () => Promise<void>;
|
||||||
|
seed?: (ctx: ModuleBuildContext) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type BkndConfig<Args = any> = {
|
||||||
|
connection?: Connection | Config;
|
||||||
|
config?: InitialModuleConfigs;
|
||||||
|
options?: {
|
||||||
|
plugins?: AppPlugin[];
|
||||||
|
manager?: ManagerOptions;
|
||||||
|
};
|
||||||
|
app?: BkndConfig<Args> | ((args: Args) => MaybePromise<BkndConfig<Args>>);
|
||||||
|
onBuilt?: (app: App) => Promise<void>;
|
||||||
|
beforeBuild?: (app?: App) => Promise<void>;
|
||||||
|
buildConfig?: {
|
||||||
|
sync?: boolean;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### `connection`
|
||||||
|
|
||||||
|
The `connection` property is the main connection object to the database. It can be either an object with libsql config or the actual `Connection` class.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// uses the default SQLite connection depending on the runtime
|
||||||
|
const connection = { url: "<url>" };
|
||||||
|
|
||||||
|
// the same as above, but more explicit
|
||||||
|
import { sqlite } from "bknd/adapter/sqlite";
|
||||||
|
const connection = sqlite({ url: "<url>" });
|
||||||
|
|
||||||
|
// Node.js SQLite, default on Node.js
|
||||||
|
import { nodeSqlite } from "bknd/adapter/node";
|
||||||
|
const connection = nodeSqlite({ url: "<url>" });
|
||||||
|
|
||||||
|
// Bun SQLite, default on Bun
|
||||||
|
import { bunSqlite } from "bknd/adapter/bun";
|
||||||
|
const connection = bunSqlite({ url: "<url>" });
|
||||||
|
|
||||||
|
// LibSQL, default on Cloudflare
|
||||||
|
import { libsql } from "bknd";
|
||||||
|
const connection = libsql({ url: "<url>" });
|
||||||
|
```
|
||||||
|
|
||||||
|
See a full list of available connections in the [Database](/usage/database) section. Alternatively, you can pass an instance of a `Connection` class directly, see [Custom Connection](/usage/database#custom-connection) as a reference.
|
||||||
|
|
||||||
|
If the connection object is omitted, the app will try to use an in-memory database.
|
||||||
|
|
||||||
|
### `config`
|
||||||
|
|
||||||
|
As configuration, you can either pass a partial configuration object or a complete one
|
||||||
|
with a version number. The version number is used to automatically migrate the configuration up
|
||||||
|
to the latest version upon boot ([`db` mode](/usage/introduction#ui-only-mode) only). The default configuration looks like this:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"server": {
|
||||||
|
"cors": {
|
||||||
|
"origin": "*",
|
||||||
|
"allow_methods": [
|
||||||
|
"GET",
|
||||||
|
"POST",
|
||||||
|
"PATCH",
|
||||||
|
"PUT",
|
||||||
|
"DELETE"
|
||||||
|
],
|
||||||
|
"allow_headers": [
|
||||||
|
"Content-Type",
|
||||||
|
"Content-Length",
|
||||||
|
"Authorization",
|
||||||
|
"Accept"
|
||||||
|
],
|
||||||
|
"allow_credentials": true
|
||||||
|
},
|
||||||
|
"mcp": {
|
||||||
|
"enabled": false,
|
||||||
|
"path": "/api/system/mcp",
|
||||||
|
"logLevel": "emergency"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"basepath": "/api/data",
|
||||||
|
"default_primary_format": "integer",
|
||||||
|
"entities": {},
|
||||||
|
"relations": {},
|
||||||
|
"indices": {}
|
||||||
|
},
|
||||||
|
"auth": {
|
||||||
|
"enabled": false,
|
||||||
|
"basepath": "/api/auth",
|
||||||
|
"entity_name": "users",
|
||||||
|
"allow_register": true,
|
||||||
|
"jwt": {
|
||||||
|
"secret": "",
|
||||||
|
"alg": "HS256",
|
||||||
|
"expires": 0,
|
||||||
|
"issuer": "",
|
||||||
|
"fields": [
|
||||||
|
"id",
|
||||||
|
"email",
|
||||||
|
"role"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"cookie": {
|
||||||
|
"path": "/",
|
||||||
|
"sameSite": "strict",
|
||||||
|
"secure": true,
|
||||||
|
"httpOnly": true,
|
||||||
|
"expires": 604800,
|
||||||
|
"partitioned": false,
|
||||||
|
"renew": true,
|
||||||
|
"pathSuccess": "/",
|
||||||
|
"pathLoggedOut": "/"
|
||||||
|
},
|
||||||
|
"strategies": {
|
||||||
|
"password": {
|
||||||
|
"type": "password",
|
||||||
|
"enabled": true,
|
||||||
|
"config": {
|
||||||
|
"hashing": "sha256"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"guard": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
"roles": {}
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
"enabled": false,
|
||||||
|
"basepath": "/api/media",
|
||||||
|
"entity_name": "media",
|
||||||
|
"storage": {}
|
||||||
|
},
|
||||||
|
"flows": {
|
||||||
|
"basepath": "/api/flows",
|
||||||
|
"flows": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use the [CLI](/usage/cli/#getting-the-configuration-config) to get the default configuration:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npx bknd config --default --pretty
|
||||||
|
```
|
||||||
|
|
||||||
|
To validate your configuration against a JSON schema, you can also dump the schema using the CLI:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npx bknd schema
|
||||||
|
```
|
||||||
|
|
||||||
|
To create an initial data structure, you can use helpers [described here](/usage/database#data-structure).
|
||||||
|
|
||||||
|
### `app`
|
||||||
|
|
||||||
The `app` property is a function that returns a `CreateAppConfig` object. It allows accessing the adapter specific environment variables. This is especially useful when using the [Cloudflare Workers](/integration/cloudflare) runtime, where the environment variables are only available inside the request handler.
|
The `app` property is a function that returns a `CreateAppConfig` object. It allows accessing the adapter specific environment variables. This is especially useful when using the [Cloudflare Workers](/integration/cloudflare) runtime, where the environment variables are only available inside the request handler.
|
||||||
|
|
||||||
@@ -129,6 +279,52 @@ export default {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `options.plugins`
|
||||||
|
|
||||||
|
The `plugins` property is an array of functions that are called after the app has been built,
|
||||||
|
but before its event is emitted. This is useful for adding custom routes or other functionality.
|
||||||
|
A simple plugin that adds a custom route looks like this:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import type { AppPlugin } from "bknd";
|
||||||
|
|
||||||
|
export const myPlugin: AppPlugin = (app) => {
|
||||||
|
app.server.get("/hello", (c) => c.json({ hello: "world" }));
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Since each plugin has full access to the `app` instance, it can add routes, modify the database
|
||||||
|
structure, add custom middlewares, respond to or add events, etc. Plugins are very powerful, so
|
||||||
|
make sure to only run trusted ones.
|
||||||
|
|
||||||
|
Read more about plugins in the [Plugins](/extending/plugins) section.
|
||||||
|
|
||||||
|
### `options.seed`
|
||||||
|
|
||||||
|
<Callout type="info">
|
||||||
|
The seed function will only be executed on app's first boot in `"db"` mode. If a configuration already exists in the database, or in `"code"` mode, it will not be executed.
|
||||||
|
</Callout>
|
||||||
|
|
||||||
|
The `seed` property is a function that is called when the app is booted for the first time. It is used to seed the database with initial data. The function is passed a `ModuleBuildContext` object:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type ModuleBuildContext = {
|
||||||
|
connection: Connection;
|
||||||
|
server: Hono;
|
||||||
|
em: EntityManager;
|
||||||
|
emgr: EventManager;
|
||||||
|
guard: Guard;
|
||||||
|
};
|
||||||
|
|
||||||
|
const seed = async (ctx: ModuleBuildContext) => {
|
||||||
|
// seed the database
|
||||||
|
await ctx.em.mutator("todos").insertMany([
|
||||||
|
{ title: "Learn bknd", done: true },
|
||||||
|
{ title: "Build something cool", done: false },
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
## Framework & Runtime configuration
|
## Framework & Runtime configuration
|
||||||
|
|
||||||
Depending on which framework or runtime you're using to run bknd, the configuration object will extend the `BkndConfig` type with additional properties.
|
Depending on which framework or runtime you're using to run bknd, the configuration object will extend the `BkndConfig` type with additional properties.
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"./extending/config",
|
"./extending/config",
|
||||||
"./extending/events",
|
"./extending/events",
|
||||||
"./extending/plugins",
|
"./extending/plugins",
|
||||||
|
"./extending/admin",
|
||||||
"---Integration---",
|
"---Integration---",
|
||||||
"./integration/introduction",
|
"./integration/introduction",
|
||||||
"./integration/(frameworks)/",
|
"./integration/(frameworks)/",
|
||||||
|
|||||||
@@ -184,197 +184,4 @@ To keep your config, secrets and types in sync, you can either use the CLI or th
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Configuration (`BkndConfig`)
|
|
||||||
|
|
||||||
The `BkndConfig` type is the main configuration object for the `createApp` function. It has
|
|
||||||
the following properties:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import type { App, InitialModuleConfigs, ModuleBuildContext, Connection, MaybePromise } from "bknd";
|
|
||||||
import type { Config } from "@libsql/client";
|
|
||||||
|
|
||||||
type AppPlugin = (app: App) => Promise<void> | void;
|
|
||||||
type ManagerOptions = {
|
|
||||||
basePath?: string;
|
|
||||||
trustFetched?: boolean;
|
|
||||||
onFirstBoot?: () => Promise<void>;
|
|
||||||
seed?: (ctx: ModuleBuildContext) => Promise<void>;
|
|
||||||
};
|
|
||||||
|
|
||||||
type BkndConfig<Args = any> = {
|
|
||||||
connection?: Connection | Config;
|
|
||||||
config?: InitialModuleConfigs;
|
|
||||||
options?: {
|
|
||||||
plugins?: AppPlugin[];
|
|
||||||
manager?: ManagerOptions;
|
|
||||||
};
|
|
||||||
app?: BkndConfig<Args> | ((args: Args) => MaybePromise<BkndConfig<Args>>);
|
|
||||||
onBuilt?: (app: App) => Promise<void>;
|
|
||||||
beforeBuild?: (app?: App) => Promise<void>;
|
|
||||||
buildConfig?: {
|
|
||||||
sync?: boolean;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### `connection`
|
|
||||||
|
|
||||||
The `connection` property is the main connection object to the database. It can be either an object with libsql config or the actual `Connection` class.
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// uses the default SQLite connection depending on the runtime
|
|
||||||
const connection = { url: "<url>" };
|
|
||||||
|
|
||||||
// the same as above, but more explicit
|
|
||||||
import { sqlite } from "bknd/adapter/sqlite";
|
|
||||||
const connection = sqlite({ url: "<url>" });
|
|
||||||
|
|
||||||
// Node.js SQLite, default on Node.js
|
|
||||||
import { nodeSqlite } from "bknd/adapter/node";
|
|
||||||
const connection = nodeSqlite({ url: "<url>" });
|
|
||||||
|
|
||||||
// Bun SQLite, default on Bun
|
|
||||||
import { bunSqlite } from "bknd/adapter/bun";
|
|
||||||
const connection = bunSqlite({ url: "<url>" });
|
|
||||||
|
|
||||||
// LibSQL, default on Cloudflare
|
|
||||||
import { libsql } from "bknd";
|
|
||||||
const connection = libsql({ url: "<url>" });
|
|
||||||
```
|
|
||||||
|
|
||||||
See a full list of available connections in the [Database](/usage/database) section. Alternatively, you can pass an instance of a `Connection` class directly, see [Custom Connection](/usage/database#custom-connection) as a reference.
|
|
||||||
|
|
||||||
If the connection object is omitted, the app will try to use an in-memory database.
|
|
||||||
|
|
||||||
### `config`
|
|
||||||
|
|
||||||
As [initial configuration](/usage/database#initial-structure), you can either pass a partial configuration object or a complete one
|
|
||||||
with a version number. The version number is used to automatically migrate the configuration up
|
|
||||||
to the latest version upon boot. The default configuration looks like this:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"server": {
|
|
||||||
"admin": {
|
|
||||||
"basepath": "",
|
|
||||||
"color_scheme": "light",
|
|
||||||
"logo_return_path": "/"
|
|
||||||
},
|
|
||||||
"cors": {
|
|
||||||
"origin": "*",
|
|
||||||
"allow_methods": ["GET", "POST", "PATCH", "PUT", "DELETE"],
|
|
||||||
"allow_headers": [
|
|
||||||
"Content-Type",
|
|
||||||
"Content-Length",
|
|
||||||
"Authorization",
|
|
||||||
"Accept"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"basepath": "/api/data",
|
|
||||||
"entities": {},
|
|
||||||
"relations": {},
|
|
||||||
"indices": {}
|
|
||||||
},
|
|
||||||
"auth": {
|
|
||||||
"enabled": false,
|
|
||||||
"basepath": "/api/auth",
|
|
||||||
"entity_name": "users",
|
|
||||||
"allow_register": true,
|
|
||||||
"jwt": {
|
|
||||||
"secret": "",
|
|
||||||
"alg": "HS256",
|
|
||||||
"fields": ["id", "email", "role"]
|
|
||||||
},
|
|
||||||
"cookie": {
|
|
||||||
"path": "/",
|
|
||||||
"sameSite": "lax",
|
|
||||||
"secure": true,
|
|
||||||
"httpOnly": true,
|
|
||||||
"expires": 604800,
|
|
||||||
"renew": true,
|
|
||||||
"pathSuccess": "/",
|
|
||||||
"pathLoggedOut": "/"
|
|
||||||
},
|
|
||||||
"strategies": {
|
|
||||||
"password": {
|
|
||||||
"type": "password",
|
|
||||||
"config": {
|
|
||||||
"hashing": "sha256"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"roles": {}
|
|
||||||
},
|
|
||||||
"media": {
|
|
||||||
"enabled": false,
|
|
||||||
"basepath": "/api/media",
|
|
||||||
"entity_name": "media",
|
|
||||||
"storage": {}
|
|
||||||
},
|
|
||||||
"flows": {
|
|
||||||
"basepath": "/api/flows",
|
|
||||||
"flows": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You can use the [CLI](/usage/cli/#getting-the-configuration-config) to get the default configuration:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npx bknd config --default --pretty
|
|
||||||
```
|
|
||||||
|
|
||||||
To validate your configuration against a JSON schema, you can also dump the schema using the CLI:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npx bknd schema
|
|
||||||
```
|
|
||||||
|
|
||||||
To create an initial data structure, you can use helpers [described here](/usage/database#initial-structure).
|
|
||||||
|
|
||||||
### `options.plugins`
|
|
||||||
|
|
||||||
The `plugins` property is an array of functions that are called after the app has been built,
|
|
||||||
but before its event is emitted. This is useful for adding custom routes or other functionality.
|
|
||||||
A simple plugin that adds a custom route looks like this:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import type { AppPlugin } from "bknd";
|
|
||||||
|
|
||||||
export const myPlugin: AppPlugin = (app) => {
|
|
||||||
app.server.get("/hello", (c) => c.json({ hello: "world" }));
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
Since each plugin has full access to the `app` instance, it can add routes, modify the database
|
|
||||||
structure, add custom middlewares, respond to or add events, etc. Plugins are very powerful, so
|
|
||||||
make sure to only run trusted ones.
|
|
||||||
|
|
||||||
### `options.seed`
|
|
||||||
|
|
||||||
<Callout type="info">
|
|
||||||
The seed function will only be executed on app's first boot in `"db"` mode. If a configuration already exists in the database, or in `"code"` mode, it will not be executed.
|
|
||||||
</Callout>
|
|
||||||
|
|
||||||
The `seed` property is a function that is called when the app is booted for the first time. It is used to seed the database with initial data. The function is passed a `ModuleBuildContext` object:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
type ModuleBuildContext = {
|
|
||||||
connection: Connection;
|
|
||||||
server: Hono;
|
|
||||||
em: EntityManager;
|
|
||||||
emgr: EventManager;
|
|
||||||
guard: Guard;
|
|
||||||
};
|
|
||||||
|
|
||||||
const seed = async (ctx: ModuleBuildContext) => {
|
|
||||||
// seed the database
|
|
||||||
await ctx.em.mutator("todos").insertMany([
|
|
||||||
{ title: "Learn bknd", done: true },
|
|
||||||
{ title: "Build something cool", done: false },
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user