bknd is dead long live userbase
Run Tests / test (pull_request) Successful in 4m57s

This commit is contained in:
2026-09-27 19:34:06 +05:30
parent 05e0086fcd
commit 0bfcb5ad71
529 changed files with 2385 additions and 2924 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
# bknd-docs
# userbase-docs
This is a Next.js application generated with
[Create Fumadocs](https://github.com/fuma-nama/fumadocs).
+1 -1
View File
@@ -30,7 +30,7 @@ export default async function Page(props: {
<LLMCopyButton markdownUrl={`${page.url}.mdx`} />
<ViewOptions
markdownUrl={`${page.url}.mdx`}
githubUrl={`https://github.com/bknd-io/bknd/blob/dev/apps/docs/content/docs/${page.path}`}
githubUrl={`https://github.com/userbase-io/userbase/blob/dev/apps/docs/content/docs/${page.path}`}
/>
</div>
<DocsBody>
+1 -1
View File
@@ -5,7 +5,7 @@ export function FooterIcons() {
<div className="flex justify-between items-center w-full px-2">
<div className="flex items-center gap-3">
<a
href="https://github.com/bknd-io/bknd"
href="https://github.com/userbase-io/userbase"
target="_blank"
rel="noopener noreferrer"
aria-label="GitHub"
+4 -4
View File
@@ -4,16 +4,16 @@ export function Logo() {
return (
<>
<Image
src="/logo/bknd_logo_white.svg"
alt="bknd logo"
src="/logo/userbase_logo_white.svg"
alt="userbase logo"
width={110}
height={24}
className="hidden dark:block pl-1.5"
priority
/>
<Image
src="/logo/bknd_logo_black.svg"
alt="bknd logo"
src="/logo/userbase_logo_black.svg"
alt="userbase logo"
width={110}
height={24}
className="block dark:hidden pl-1.5"
+2 -2
View File
@@ -4,7 +4,7 @@ import * as React from "react";
export const examples = {
adminRich: {
path: "github/bknd-io/bknd-examples",
path: "github/userbase-io/userbase-examples",
startScript: "example-admin-rich",
initialPath: "/data/schema",
},
@@ -22,7 +22,7 @@ export const StackBlitz = ({
[key: string]: unknown;
}) => {
const selected = example ? examples[example] : undefined;
const finalPath = path || selected?.path || "github/bknd-io/bknd-examples";
const finalPath = path || selected?.path || "github/userbase-io/userbase-examples";
const params = new URLSearchParams({
ctl: "1",
+41 -41
View File
@@ -1,4 +1,4 @@
Subject: [PATCH] bknd ui in docs
Subject: [PATCH] userbase ui in docs
---
Index: docs/package.json
IDEA additional info:
@@ -14,7 +14,7 @@ diff --git a/docs/package.json b/docs/package.json
"tailwind-merge": "^3.3.1",
- "twoslash": "^0.3.2"
+ "twoslash": "^0.3.2",
+ "bknd": "file:../app"
+ "userbase": "file:../app"
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.11",
@@ -30,7 +30,7 @@ diff --git a/docs/package-lock.json b/docs/package-lock.json
"dependencies": {
"@iconify/react": "^6.0.0",
"@orama/orama": "^3.1.10",
+ "bknd": "file:../app",
+ "userbase": "file:../app",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"fumadocs-core": "^15.6.1",
@@ -39,7 +39,7 @@ diff --git a/docs/package-lock.json b/docs/package-lock.json
}
},
+ "../app": {
+ "name": "bknd",
+ "name": "userbase",
+ "version": "0.18.0-rc.3",
+ "license": "FSL-1.1-MIT",
+ "dependencies": {
@@ -70,7 +70,7 @@ diff --git a/docs/package-lock.json b/docs/package-lock.json
+ "swr": "^2.3.3"
+ },
+ "bin": {
+ "bknd": "dist/cli/index.js"
+ "userbase": "dist/cli/index.js"
+ },
+ "devDependencies": {
+ "@aws-sdk/client-s3": "^3.758.0",
@@ -149,7 +149,7 @@ diff --git a/docs/package-lock.json b/docs/package-lock.json
"dev": true,
"license": "MIT"
},
+ "node_modules/bknd": {
+ "node_modules/userbase": {
+ "resolved": "../app",
+ "link": true
+ },
@@ -187,12 +187,12 @@ new file mode 100644
+tags: ["documentation"]
+---
+import { TypeTable } from 'fumadocs-ui/components/type-table';
+import { Button } from "bknd-ui"
+import { BkndUi } from "@/app/_components/BkndUi";
+import { Button } from "userbase-ui"
+import { UserbaseUi } from "@/app/_components/UserbaseUi";
+
+Describe how to extend the Admin UI.
+
+<BkndUi code={`import { Button } from "bknd/ui"
+<UserbaseUi code={`import { Button } from "userbase/ui"
+
+function ButtonDemo() {
+ return <div className="flex flex-row gap-4">
@@ -230,14 +230,14 @@ new file mode 100644
+ Subtlered
+ </Button>
+ </div>
+</BkndUi>
+</UserbaseUi>
+
+<AutoTypeTable path="../app/src/ui/Admin.tsx" name="BkndAdminProps" />
+<AutoTypeTable path="../app/src/ui/Admin.tsx" name="UserbaseAdminProps" />
+
+<AutoTypeTable path="../app/src/ui/options/index.ts" name="BkndAdminEntityOptions" />
+<AutoTypeTable path="../app/src/ui/options/index.ts" name="BkndAdminEntityFieldOptions" />
+<AutoTypeTable path="../app/src/ui/options/index.ts" name="UserbaseAdminEntityOptions" />
+<AutoTypeTable path="../app/src/ui/options/index.ts" name="UserbaseAdminEntityFieldOptions" />
+
+<AutoTypeTable path="../app/src/ui/options/index.ts" name="BkndAdminAppShellOptions" />
+<AutoTypeTable path="../app/src/ui/options/index.ts" name="UserbaseAdminAppShellOptions" />
\ No newline at end of file
Index: docs/tsconfig.json
IDEA additional info:
@@ -250,38 +250,38 @@ diff --git a/docs/tsconfig.json b/docs/tsconfig.json
@@ -18,6 +18,7 @@
"paths": {
"@/.source": ["./.source/index.ts"],
"@/bknd/*": ["../app/src/"],
+ "bknd-ui": ["../app/dist/ui/index.js"],
"@/userbase/*": ["../app/src/"],
+ "userbase-ui": ["../app/dist/ui/index.js"],
"@/*": ["./*"]
},
Index: docs/app/_components/BkndUi.tsx
Index: docs/app/_components/UserbaseUi.tsx
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/docs/app/_components/BkndUi.tsx b/docs/app/_components/BkndUi.tsx
diff --git a/docs/app/_components/UserbaseUi.tsx b/docs/app/_components/UserbaseUi.tsx
new file mode 100644
--- /dev/null (date 1758280846757)
+++ b/docs/app/_components/BkndUi.tsx (date 1758280846757)
+++ b/docs/app/_components/UserbaseUi.tsx (date 1758280846757)
@@ -0,0 +1,36 @@
+import { readFileSync } from "node:fs";
+import { join } from "node:path";
+import { BkndUiClient } from "./BkndUiClient";
+import { UserbaseUiClient } from "./UserbaseUiClient";
+
+// Server component that reads CSS from disk
+export function BkndUi({ children, code }: { children: React.ReactNode; code?: string }) {
+ let bkndCss = "";
+export function UserbaseUi({ children, code }: { children: React.ReactNode; code?: string }) {
+ let userbaseCss = "";
+
+ try {
+ // Try to read the CSS file from the app directory
+ const cssPath = join(process.cwd(), "node_modules", "bknd", "dist", "ui", "main.css");
+ bkndCss = readFileSync(cssPath, "utf-8");
+ const cssPath = join(process.cwd(), "node_modules", "userbase", "dist", "ui", "main.css");
+ userbaseCss = readFileSync(cssPath, "utf-8");
+ } catch (error) {
+ console.warn("Could not read bknd CSS file:", error);
+ console.warn("Could not read userbase CSS file:", error);
+ // Fallback CSS
+ bkndCss = `
+ .bknd-admin {
+ userbaseCss = `
+ .userbase-admin {
+ --color-primary: #18181b;
+ --color-background: #fafafa;
+ --color-muted: #e4e4e7;
@@ -296,9 +296,9 @@ new file mode 100644
+ }
+
+ return (
+ <BkndUiClient bkndCss={bkndCss} code={code}>
+ <UserbaseUiClient userbaseCss={userbaseCss} code={code}>
+ {children}
+ </BkndUiClient>
+ </UserbaseUiClient>
+ );
+}
Index: docs/next.config.mjs
@@ -311,23 +311,23 @@ diff --git a/docs/next.config.mjs b/docs/next.config.mjs
+++ b/docs/next.config.mjs (date 1758281330764)
@@ -19,6 +19,9 @@
webpack(config) {
config.resolve.alias["@/bknd"] = path.resolve(__dirname, "../app/src");
config.resolve.alias["@/userbase"] = path.resolve(__dirname, "../app/src");
config.resolve.alias["@"] = path.resolve(__dirname);
+
+ // @todo: this doesn't work with turbo
+ config.resolve.alias["bknd-ui"] = path.resolve(__dirname, "../app/dist/ui/index.js");
+ config.resolve.alias["userbase-ui"] = path.resolve(__dirname, "../app/dist/ui/index.js");
return config;
},
eslint: {
Index: docs/app/_components/BkndUiClient.tsx
Index: docs/app/_components/UserbaseUiClient.tsx
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/docs/app/_components/BkndUiClient.tsx b/docs/app/_components/BkndUiClient.tsx
diff --git a/docs/app/_components/UserbaseUiClient.tsx b/docs/app/_components/UserbaseUiClient.tsx
new file mode 100644
--- /dev/null (date 1758281176041)
+++ b/docs/app/_components/BkndUiClient.tsx (date 1758281176041)
+++ b/docs/app/_components/UserbaseUiClient.tsx (date 1758281176041)
@@ -0,0 +1,62 @@
+"use client";
+
@@ -337,13 +337,13 @@ new file mode 100644
+import { DynamicCodeBlock } from "fumadocs-ui/components/dynamic-codeblock";
+import { useTheme } from "next-themes";
+
+interface BkndUiClientProps {
+ bkndCss: string;
+interface UserbaseUiClientProps {
+ userbaseCss: string;
+ children: React.ReactNode;
+ code?: string;
+}
+
+export function BkndUiClient({ bkndCss, children, code }: BkndUiClientProps) {
+export function UserbaseUiClient({ userbaseCss, children, code }: UserbaseUiClientProps) {
+ const { theme } = useTheme();
+ const containerRef = useRef<HTMLDivElement>(null);
+ const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null);
@@ -362,26 +362,26 @@ new file mode 100644
+ display: block;
+ isolation: isolate;
+ }
+ ${bkndCss}
+ ${userbaseCss}
+ `;
+
+ shadow.appendChild(style);
+
+ // Create mount point for React content
+ const mount = document.createElement("div");
+ mount.className = `bknd-admin ${theme}`;
+ mount.className = `userbase-admin ${theme}`;
+ shadow.appendChild(mount);
+
+ setShadowRoot(shadow);
+ setMountPoint(mount);
+ }, [shadowRoot, bkndCss]);
+ }, [shadowRoot, userbaseCss]);
+
+ return (
+ <>
+ {/* @ts-ignore */}
+ <Card className="p-0">
+ <div className="flex flex-col justify-center items-center p-4">
+ <div ref={containerRef} className="bknd-ui-shadow-host">
+ <div ref={containerRef} className="userbase-ui-shadow-host">
+ <div>Loading...</div>
+ {shadowRoot && mountPoint && createPortal(children, mountPoint)}
+ </div>
@@ -6,14 +6,14 @@ tags: ["documentation"]
import { TypeTable } from "fumadocs-ui/components/type-table";
bknd features an integrated Admin UI that can be used to:
userbase features an integrated Admin UI that can be used to:
- fully manage your backend visually when run in [`db` mode](/usage/setup/#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.
In case you're using userbase 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" />
<AutoTypeTable path="../app/src/ui/Admin.tsx" name="UserbaseAdminProps" />
## Advanced Example
@@ -29,7 +29,7 @@ The following example shows how to customize the Admin UI for each entity.
- adds a custom route
```tsx
import { Admin } from "bknd/ui";
import { Admin } from "userbase/ui";
import { Route } from "wouter";
export function App() {
@@ -107,25 +107,25 @@ export function App() {
## `config`
<AutoTypeTable path="../app/src/ui/Admin.tsx" name="BkndAdminConfig" />
<AutoTypeTable path="../app/src/ui/Admin.tsx" name="UserbaseAdminConfig" />
### `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 UserbaseAdminEntityContext = "list" | "create" | "update";
export type BkndAdminEntitiesOptions = {
[E in keyof DB]?: BkndAdminEntityOptions<E>;
export type UserbaseAdminEntitiesOptions = {
[E in keyof DB]?: UserbaseAdminEntityOptions<E>;
};
export type BkndAdminEntityOptions<E extends keyof DB | string> = {
export type UserbaseAdminEntityOptions<E extends keyof DB | string> = {
/**
* Header to be rendered depending on the context
*/
header?: (
context: BkndAdminEntityContext,
context: UserbaseAdminEntityContext,
entity: Entity,
data?: DB[E],
) => ReactNode | void | undefined;
@@ -133,7 +133,7 @@ export type BkndAdminEntityOptions<E extends keyof DB | string> = {
* Footer to be rendered depending on the context
*/
footer?: (
context: BkndAdminEntityContext,
context: UserbaseAdminEntityContext,
entity: Entity,
data?: DB[E],
) => ReactNode | void | undefined;
@@ -141,7 +141,7 @@ export type BkndAdminEntityOptions<E extends keyof DB | string> = {
* Actions to be rendered depending on the context
*/
actions?: (
context: BkndAdminEntityContext,
context: UserbaseAdminEntityContext,
entity: Entity,
data?: DB[E],
) => {
@@ -158,16 +158,16 @@ export type BkndAdminEntityOptions<E extends keyof DB | string> = {
* Field UI overrides
*/
fields?: {
[F in keyof DB[E]]?: BkndAdminEntityFieldOptions<E>;
[F in keyof DB[E]]?: UserbaseAdminEntityFieldOptions<E>;
};
};
export type BkndAdminEntityFieldOptions<E extends keyof DB | string> = {
export type UserbaseAdminEntityFieldOptions<E extends keyof DB | string> = {
/**
* Override the rendering of a certain field
*/
render?: (
context: BkndAdminEntityContext,
context: UserbaseAdminEntityContext,
entity: Entity,
field: Field,
ctx: {
@@ -195,7 +195,7 @@ export type DropdownItem =
[key: string]: any;
};
export type BkndAdminAppShellOptions = {
export type UserbaseAdminAppShellOptions = {
userMenu?: (DropdownItem | undefined | boolean)[];
};
```
@@ -1,9 +1,9 @@
---
title: bknd.config.ts
title: userbase.config.ts
tags: ["documentation"]
---
The central configuration file to extend bknd should be placed in the root of your project, so that the [CLI](/usage/cli#using-configuration-file-bknd-config) can automatically pick it up. It allows to:
The central configuration file to extend userbase should be placed in the root of your project, so that the [CLI](/usage/cli#using-configuration-file-userbase-config) can automatically pick it up. It allows to:
- define your database connection centrally
- pass in [initial configuration](/usage/database#initial-structure) or [data seeds](/usage/database#seeding-the-database) when booting the first time
@@ -11,16 +11,16 @@ The central configuration file to extend bknd should be placed in the root of yo
- hook into system events
- define custom routes and endpoints
A simple example of a `bknd.config.ts` file:
A simple example of a `userbase.config.ts` file:
```typescript title="bknd.config.ts"
import type { BkndConfig } from "bknd/adapter";
```typescript title="userbase.config.ts"
import type { UserbaseConfig } from "userbase/adapter";
export default {
connection: {
url: "file:data.db",
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
The supported configuration file extensions are `js`, `ts`, `mjs`, `cjs` and `json`. Throughout the documentation, we'll use `ts` for the file extension.
@@ -30,8 +30,8 @@ The supported configuration file extensions are `js`, `ts`, `mjs`, `cjs` and `js
Here is an example of a configuration file that specifies a database connection, registers a plugin, add custom routes using [Hono](https://hono.dev/) and performs a [Kysely](https://kysely.dev/) query.
```typescript
import type { BkndConfig } from "bknd/adapter";
import { showRoutes } from "bknd/plugins";
import type { UserbaseConfig } from "userbase/adapter";
import { showRoutes } from "userbase/plugins";
export default {
connection: {
@@ -51,17 +51,17 @@ export default {
options: {
plugins: [showRoutes()],
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
## Configuration (`BkndConfig`)
## Configuration (`UserbaseConfig`)
The `BkndConfig` type is the main configuration object for the `createApp` function. It has
The `UserbaseConfig` 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 { App, InitialModuleConfigs, ModuleBuildContext, Connection, MaybePromise } from "userbase";
import type { Config } from "@libsql/client";
type AppPlugin = (app: App) => Promise<void> | void;
@@ -72,14 +72,14 @@ type ManagerOptions = {
seed?: (ctx: ModuleBuildContext) => Promise<void>;
};
type BkndConfig<Args = any> = {
type UserbaseConfig<Args = any> = {
connection?: Connection | Config;
config?: InitialModuleConfigs;
options?: {
plugins?: AppPlugin[];
manager?: ManagerOptions;
};
app?: BkndConfig<Args> | ((args: Args) => MaybePromise<BkndConfig<Args>>);
app?: UserbaseConfig<Args> | ((args: Args) => MaybePromise<UserbaseConfig<Args>>);
onBuilt?: (app: App) => Promise<void>;
beforeBuild?: (app?: App) => Promise<void>;
buildConfig?: {
@@ -97,19 +97,19 @@ The `connection` property is the main connection object to the database. It can
const connection = { url: "<url>" };
// the same as above, but more explicit
import { sqlite } from "bknd/adapter/sqlite";
import { sqlite } from "userbase/adapter/sqlite";
const connection = sqlite({ url: "<url>" });
// Node.js SQLite, default on Node.js
import { nodeSqlite } from "bknd/adapter/node";
import { nodeSqlite } from "userbase/adapter/node";
const connection = nodeSqlite({ url: "<url>" });
// Bun SQLite, default on Bun
import { bunSqlite } from "bknd/adapter/bun";
import { bunSqlite } from "userbase/adapter/bun";
const connection = bunSqlite({ url: "<url>" });
// LibSQL, default on Cloudflare
import { libsql } from "bknd";
import { libsql } from "userbase";
const connection = libsql({ url: "<url>" });
```
@@ -217,13 +217,13 @@ to the latest version upon boot ([`db` mode](/usage/setup#ui-only-mode) only). T
You can use the [CLI](/usage/cli/#getting-the-configuration-config) to get the default configuration:
```sh
npx bknd config --default --pretty
npx userbase config --default --pretty
```
To validate your configuration against a JSON schema, you can also dump the schema using the CLI:
```sh
npx bknd schema
npx userbase schema
```
To create an initial data structure, you can use helpers [described here](/usage/database#data-structure).
@@ -233,7 +233,7 @@ To create an initial data structure, you can use helpers [described here](/usage
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.
```typescript
import type { BkndConfig } from "bknd/adapter";
import type { UserbaseConfig } from "userbase/adapter";
export default {
app: (env) => ({
@@ -241,7 +241,7 @@ export default {
url: env.DB_URL,
},
}),
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
See [Database](/usage/database) for more information on how to configure the database connection.
@@ -251,7 +251,7 @@ See [Database](/usage/database) for more information on how to configure the dat
The `beforeBuild` property is an async function that is called before the app is built. It allows to modify the app instance that may influence the build process.
```typescript
import type { BkndConfig } from "bknd/adapter";
import type { UserbaseConfig } from "userbase/adapter";
export default {
beforeBuild: async (app: App) => {
@@ -265,8 +265,8 @@ export default {
The `onBuilt` property is an async function that is called after the app has been built. It allows to hook into the app after it has been built. This is useful for defining event listeners or register custom routes, as both the event manager and the server are recreated during the build process.
```typescript
import { type App, AppEvents } from "bknd";
import type { BkndConfig } from "bknd/adapter";
import { type App, AppEvents } from "userbase";
import type { UserbaseConfig } from "userbase/adapter";
export default {
onBuilt: async (app: App) => {
@@ -290,7 +290,7 @@ but before its event is emitted. This is useful for adding custom routes or othe
A simple plugin that adds a custom route looks like this:
```ts
import type { AppPlugin } from "bknd";
import type { AppPlugin } from "userbase";
export const myPlugin: AppPlugin = (app) => {
app.server.get("/hello", (c) => c.json({ hello: "world" }));
@@ -323,7 +323,7 @@ type ModuleBuildContext = {
const seed = async (ctx: ModuleBuildContext) => {
// seed the database
await ctx.em.mutator("todos").insertMany([
{ title: "Learn bknd", done: true },
{ title: "Learn userbase", done: true },
{ title: "Build something cool", done: false },
]);
};
@@ -331,14 +331,14 @@ const seed = async (ctx: ModuleBuildContext) => {
## 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 userbase, the configuration object will extend the `UserbaseConfig` type with additional properties.
### `RuntimeBkndConfig`
### `RuntimeUserbaseConfig`
[Runtime adapters](/integration/runtime) need additional configuration to serve static assets for the admin UI.
```typescript
export type RuntimeBkndConfig<Args = any> = BkndConfig<Args> & {
export type RuntimeUserbaseConfig<Args = any> = UserbaseConfig<Args> & {
// the path to the dist folder to serve static assets for the admin UI
distPath?: string;
// custom middleware to serve static assets for the admin UI
@@ -348,13 +348,13 @@ export type RuntimeBkndConfig<Args = any> = BkndConfig<Args> & {
};
```
### `FrameworkBkndConfig`
### `FrameworkUserbaseConfig`
[Framework adapters](/integration/framework) may need additional configuration based on the framework's requirements. For example, the `NextjsBkndConfig` type extends the `BkndConfig` type with the following additional properties:
[Framework adapters](/integration/framework) may need additional configuration based on the framework's requirements. For example, the `NextjsUserbaseConfig` type extends the `UserbaseConfig` type with the following additional properties:
```typescript
type NextjsEnv = NextApiRequest["env"];
export type NextjsBkndConfig<Env = NextjsEnv> = FrameworkBkndConfig<Env> & {
export type NextjsUserbaseConfig<Env = NextjsEnv> = FrameworkUserbaseConfig<Env> & {
cleanRequest?: { searchParams?: string[] };
};
```
@@ -363,16 +363,16 @@ Next.js adds the mounted path to the request object, so that the `cleanRequest`
## Using the configuration file
The configuration file is automatically picked up if you're using the [CLI](/usage/cli). This allows interacting with your application using the `bknd` command. For example, you can run the following command in the root of your project to start an instance:
The configuration file is automatically picked up if you're using the [CLI](/usage/cli). This allows interacting with your application using the `userbase` command. For example, you can run the following command in the root of your project to start an instance:
```bash
npx bknd run
npx userbase run
```
When serving your application, you need to make sure to import the contents of your configuration file. If you're using Next.js for example, it's recommended to follow these steps:
1. create a `bknd.config.ts` file in the root of your project which defines the connection to the database, adds event listeners and custom routes.
2. create a `bknd.ts` file inside your app folder which exports helper functions to instantiate the bknd instance and retrieve the API.
3. create a catch-all route file at `src/api/[[...bknd]]/route.ts` which serves the bknd API.
1. create a `userbase.config.ts` file in the root of your project which defines the connection to the database, adds event listeners and custom routes.
2. create a `userbase.ts` file inside your app folder which exports helper functions to instantiate the userbase instance and retrieve the API.
3. create a catch-all route file at `src/api/[[...userbase]]/route.ts` which serves the userbase API.
This way, your application and the CLI are using the same configuration.
@@ -3,7 +3,7 @@ title: Events & Hooks
tags: ["documentation"]
---
bknd comes with a powerful built-in event system that allows you to hook into the app lifecycle and extend its functionality. You can hook into these events in two ways:
userbase comes with a powerful built-in event system that allows you to hook into the app lifecycle and extend its functionality. You can hook into these events in two ways:
- `async`: Your listener is not blocking the main execution flow. E.g. on Cloudflare Workers, by default, the `ExecutionContext`'s `waitUntil` method is used so that the listeners runs after the response is sent.
- `sync`: Your listener is blocking the main execution flow. This allows to abort the request in your custom conditions. Some events also allow to return a modified event payload.
@@ -24,7 +24,7 @@ You can listen to events by using the `EventManager` exposed at `app.emgr`. To r
- `onAny`: Register a listener for all events.
```typescript
import { createApp, AppEvents } from "bknd";
import { createApp, AppEvents } from "userbase";
const app = createApp();
app.emgr.onEvent(AppEvents.AppRequest, async (event) => {
@@ -41,10 +41,10 @@ app.emgr.onAny(async (event, name) => {
});
```
You may want to register your listeners inside [`bknd.config.ts`](/extending/config) to make sure they are registered before the app is built:
You may want to register your listeners inside [`userbase.config.ts`](/extending/config) to make sure they are registered before the app is built:
```typescript title="bknd.config.ts"
import { AppEvents } from "bknd";
```typescript title="userbase.config.ts"
import { AppEvents } from "userbase";
export default {
onBuilt: (app) => {
@@ -76,7 +76,7 @@ This works for all three methods.
These events are emitted by the `App` class and are available on the `AppEvents` object.
```typescript
import { AppEvents } from "bknd";
import { AppEvents } from "userbase";
```
Available events:
@@ -95,7 +95,7 @@ Available events:
These events are emitted by the `Database` class and are available on the `DatabaseEvents` object. These are divided by events triggered by the `Mutator` and `Repository` classes.
```typescript
import { DatabaseEvents } from "bknd";
import { DatabaseEvents } from "userbase";
```
### Mutator Events
@@ -127,7 +127,7 @@ These events are emitted during database queries (find operations).
These events are emitted by the `Storage` class and are available on the `MediaEvents` object.
```typescript
import { MediaEvents } from "bknd";
import { MediaEvents } from "userbase";
```
| Event | Params | Description |
@@ -5,7 +5,7 @@ tags: ["documentation"]
import { TypeTable } from 'fumadocs-ui/components/type-table';
bknd allows you to extend its functionality by creating plugins. These allows to hook into the app lifecycle and to provide a data structure that is guaranteed to be merged. A plugin is a function that takes in an instance of `App` and returns the following structure:
userbase allows you to extend its functionality by creating plugins. These allows to hook into the app lifecycle and to provide a data structure that is guaranteed to be merged. A plugin is a function that takes in an instance of `App` and returns the following structure:
<AutoTypeTable path="../app/src/App.ts" name="AppPluginConfig" />
@@ -15,7 +15,7 @@ To create a simple plugin which guarantees an entity `pages` to be available and
```tsx title="myPagesPlugin.tsx"
/** @jsxImportSource hono/jsx */
import { type App, type AppPlugin, em, entity, text } from "bknd";
import { type App, type AppPlugin, em, entity, text } from "userbase";
export const myPagesPlugin: AppPlugin = (app) => ({
name: "my-pages-plugin",
@@ -29,7 +29,7 @@ export const myPagesPlugin: AppPlugin = (app) => ({
}),
// execute code after the app is built
onBuilt: () => {
// register a new endpoint, make sure that you choose an endpoint that is reachable for bknd
// register a new endpoint, make sure that you choose an endpoint that is reachable for userbase
app.server.get("/my-pages", async (c) => {
const { data: pages } = await app.em.repo("pages").findMany({});
return c.html(
@@ -48,17 +48,17 @@ export const myPagesPlugin: AppPlugin = (app) => ({
```
And then register it in your `bknd.config.ts` file:
And then register it in your `userbase.config.ts` file:
```typescript
import type { BkndConfig } from "bknd/adapter";
import type { UserbaseConfig } from "userbase/adapter";
import { myPagesPlugin } from "./myPagesPlugin";
export default {
options: {
plugins: [myPagesPlugin],
}
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
The schema returned from the plugin will be merged into the schema of the app.
@@ -66,14 +66,14 @@ The schema returned from the plugin will be merged into the schema of the app.
## Built-in plugins
bknd comes with a few built-in plugins that you can use.
userbase comes with a few built-in plugins that you can use.
### `syncTypes`
A simple plugin that writes down the TypeScript types of the data schema on boot and each build. The output is equivalent to running `npx bknd types`.
A simple plugin that writes down the TypeScript types of the data schema on boot and each build. The output is equivalent to running `npx userbase types`.
```typescript title="bknd.config.ts"
import { syncTypes } from "bknd/plugins";
```typescript title="userbase.config.ts"
import { syncTypes } from "userbase/plugins";
import { writeFile } from "node:fs/promises";
export default {
@@ -84,20 +84,20 @@ export default {
enabled: true,
// your writing function (required)
write: async (et) => {
await writeFile("bknd-types.d.ts", et.toString(), "utf-8");
await writeFile("userbase-types.d.ts", et.toString(), "utf-8");
}
}),
]
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
### `syncConfig`
A simple plugin that writes down the app configuration on boot and each build.
```typescript title="bknd.config.ts"
import { syncConfig } from "bknd/plugins";
```typescript title="userbase.config.ts"
import { syncConfig } from "userbase/plugins";
import { writeFile } from "node:fs/promises";
export default {
@@ -113,15 +113,15 @@ export default {
}),
]
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
### `syncSecrets`
A simple plugin that writes down the app secrets on boot and each build.
```typescript title="bknd.config.ts"
import { syncSecrets } from "bknd/plugins";
```typescript title="userbase.config.ts"
import { syncSecrets } from "userbase/plugins";
import { writeFile } from "node:fs/promises";
export default {
@@ -143,15 +143,15 @@ export default {
}),
]
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
### `showRoutes`
A simple plugin that logs the routes of your app in the console.
```typescript title="bknd.config.ts"
import { showRoutes } from "bknd/plugins";
```typescript title="userbase.config.ts"
import { showRoutes } from "userbase/plugins";
export default {
options: {
@@ -162,7 +162,7 @@ export default {
})
],
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
### `cloudflareImageOptimization`
@@ -173,8 +173,8 @@ export default {
A plugin that add Cloudflare Image Optimization to your app's media storage.
```typescript title="bknd.config.ts"
import { cloudflareImageOptimization } from "bknd/plugins";
```typescript title="userbase.config.ts"
import { cloudflareImageOptimization } from "userbase/plugins";
export default {
options: {
@@ -191,7 +191,7 @@ export default {
})
],
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
Here is a break down of all configuration options:
@@ -243,8 +243,8 @@ Now you can add query parameters for the transformations, e.g. `?width=1000&heig
A plugin that adds `created_at` and `updated_at` fields to the specified entities.
```typescript title="bknd.config.ts"
import { timestamps } from "bknd/plugins";
```typescript title="userbase.config.ts"
import { timestamps } from "userbase/plugins";
export default {
options: {
@@ -257,7 +257,7 @@ export default {
})
],
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
@@ -300,9 +300,9 @@ Content-Type: application/json
If the code is valid, the user will be authenticated by sending a `Set-Cookie` header and a body property `token` with the JWT token (equally to the login endpoint).
```typescript title="bknd.config.ts"
import { emailOTP } from "bknd/plugins";
import { resendEmail } from "bknd";
```typescript title="userbase.config.ts"
import { emailOTP } from "userbase/plugins";
import { resendEmail } from "userbase";
export default {
options: {
@@ -331,7 +331,7 @@ export default {
})
],
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
<AutoTypeTable path="../app/src/plugins/auth/email-otp.plugin.ts" name="EmailOTPPluginOptions" />
@@ -341,8 +341,8 @@ export default {
A plugin that maintains sequential numeric positions for one or more entities. Positions are updated automatically when items are inserted or moved. You can optionally configure a scope so that positions are maintained independently within groups, such as tasks within a project.
```typescript title="bknd.config.ts"
import { sort } from "bknd/plugins";
```typescript title="userbase.config.ts"
import { sort } from "userbase/plugins";
export default {
options: {
@@ -357,7 +357,7 @@ export default {
}),
],
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
The configured `field` is used for the numeric position. If the field does not exist, the plugin adds it as a number field with a default value of `0`; if it already exists, it must be a number field. The plugin also adds an index for the field when one is not already present. The optional `scope` field limits reordering to records with the same scope value.
@@ -1,41 +1,41 @@
---
title: "Astro"
description: "Run bknd inside Astro"
description: "Run userbase inside Astro"
tags: ["documentation"]
---
## Installation
To get started with Astro and bknd you can either install the package manually, and follow the descriptions below, or use the CLI starter:
To get started with Astro and userbase you can either install the package manually, and follow the descriptions below, or use the CLI starter:
### CLI Starter
Create a new Astro CLI starter project by running the following command:
```sh
npx bknd create -i astro
npx userbase create -i astro
```
### Manual
Create a new Astro project by following the [official guide](https://docs.astro.build/en/install-and-setup/), and then install bknd as a dependency:
Create a new Astro project by following the [official guide](https://docs.astro.build/en/install-and-setup/), and then install userbase as a dependency:
<Tabs groupId='package-manager' persist items={[ 'npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm install bknd
npm install userbase
```
```bash tab="pnpm"
pnpm install bknd
pnpm install userbase
```
```bash tab="yarn"
yarn add bknd
yarn add userbase
```
```bash tab="bun"
bun add bknd
bun add userbase
```
</Tabs>
@@ -61,10 +61,10 @@ export default defineConfig({
<Callout type="info">
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
the userbase 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).
GitHub](https://github.com/userbase-io/userbase/issues/new).
</Callout>
## Configuration
@@ -75,38 +75,38 @@ export default defineConfig({
[upgrade](https://nodejs.org/en/download/) if necessary.
</Callout>
Now create a `bknd.config.ts` file in the root of your project. If you created the project using the CLI starter, this file is already created for you.
Now create a `userbase.config.ts` file in the root of your project. If you created the project using the CLI starter, this file is already created for you.
```typescript title="bknd.config.ts"
import type { AstroBkndConfig } from "bknd/adapter/astro";
```typescript title="userbase.config.ts"
import type { AstroUserbaseConfig } from "userbase/adapter/astro";
export default {
connection: {
url: "file:data.db",
},
} satisfies AstroBkndConfig;
} satisfies AstroUserbaseConfig;
```
See [bknd.config.ts](/extending/config) for more information on how to configure bknd. The `AstroBkndConfig` type extends the `BkndConfig` type with the following additional properties:
See [userbase.config.ts](/extending/config) for more information on how to configure userbase. The `AstroUserbaseConfig` type extends the `UserbaseConfig` type with the following additional properties:
```typescript
type AstroEnv = NodeJS.ProcessEnv;
export type AstroBkndConfig<Env = AstroEnv> = FrameworkBkndConfig<Env>;
export type AstroUserbaseConfig<Env = AstroEnv> = FrameworkUserbaseConfig<Env>;
```
## Serve the API
Create a helper file to instantiate the bknd instance and retrieve the API, importing the configurationfrom the `bknd.config.ts` file:
Create a helper file to instantiate the userbase instance and retrieve the API, importing the configurationfrom the `userbase.config.ts` file:
```ts title="src/bknd.ts"
```ts title="src/userbase.ts"
import type { AstroGlobal } from "astro";
import { getApp as getBkndApp } from "bknd/adapter/astro";
import config from "../bknd.config";
import { getApp as getUserbaseApp } from "userbase/adapter/astro";
import config from "../userbase.config";
export { config };
export async function getApp() {
return await getBkndApp(config);
return await getUserbaseApp(config);
}
export async function getApi(
@@ -127,7 +127,7 @@ export async function getApi(
Create a new catch-all route at `src/pages/api/[...api].ts`.
```ts title="src/pages/api/[...api].ts"
import { serve } from "bknd/adapter/astro";
import { serve } from "userbase/adapter/astro";
export const prerender = false;
@@ -150,10 +150,10 @@ Create a new catch-all route at `src/pages/admin/[...admin].astro`:
```jsx title="src/pages/admin/[...admin].astro"
---
import { Admin } from "bknd/ui";
import "bknd/dist/styles.css";
import { Admin } from "userbase/ui";
import "userbase/dist/styles.css";
import { getApi } from "../../../bknd.ts"; // /src/bknd.ts
import { getApi } from "../../../userbase.ts"; // /src/userbase.ts
const api = await getApi(Astro, { mode: "dynamic" });
const user = api.getUser();
@@ -185,7 +185,7 @@ Here is an example of using the API in static context:
```jsx
---
import { getApi } from "bknd/adapter/astro";
import { getApi } from "userbase/adapter/astro";
const api = await getApi(Astro);
const { data } = await api.data.readMany("todos");
---
@@ -201,7 +201,7 @@ On SSR pages, you can also access the authenticated user:
```jsx
---
import { getApi } from "bknd/adapter/astro";
import { getApi } from "userbase/adapter/astro";
const api = await getApi(Astro, { mode: "dynamic" });
const user = api.getUser();
const { data } = await api.data.readMany("todos");
@@ -219,5 +219,5 @@ export const prerender = false;
</ul>
```
Check the [astro repository example](https://github.com/bknd-io/bknd/tree/main/examples/astro)
for more implementation details or a [fully working example using Astro DB](https://github.com/dswbx/bknd-astro-example).
Check the [astro repository example](https://github.com/userbase-io/userbase/tree/main/examples/astro)
for more implementation details or a [fully working example using Astro DB](https://github.com/dswbx/userbase-astro-example).
@@ -1,41 +1,41 @@
---
title: "Next.js"
description: "Run bknd inside Next.js"
description: "Run userbase inside Next.js"
tags: ["documentation"]
---
## Installation
To get started with Next.js and bknd you can either install the package manually, and follow the descriptions below, or use the CLI starter.
To get started with Next.js and userbase you can either install the package manually, and follow the descriptions below, or use the CLI starter.
### CLI Starter
Create a new Next.js CLI starter project by running the following command:
```sh
npx bknd create -i nextjs
npx userbase create -i nextjs
```
### Manual
Create a new Next.js project by following the [official guide](https://nextjs.org/docs/pages/api-reference/cli/create-next-app), and then install bknd as a dependency:
Create a new Next.js project by following the [official guide](https://nextjs.org/docs/pages/api-reference/cli/create-next-app), and then install userbase as a dependency:
<Tabs groupId='package-manager' persist items={[ 'npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm install bknd
npm install userbase
```
```bash tab="pnpm"
pnpm install bknd
pnpm install userbase
```
```bash tab="yarn"
yarn add bknd
yarn add userbase
```
```bash tab="bun"
bun add bknd
bun add userbase
```
</Tabs>
@@ -48,43 +48,43 @@ bun add bknd
[upgrade](https://nodejs.org/en/download/) if necessary.
</Callout>
Now create a `bknd.config.ts` file in the root of your project. If you created the project using the CLI starter, this file is already created for you.
Now create a `userbase.config.ts` file in the root of your project. If you created the project using the CLI starter, this file is already created for you.
```typescript title="bknd.config.ts"
import type { NextjsBkndConfig } from "bknd/adapter/nextjs";
```typescript title="userbase.config.ts"
import type { NextjsUserbaseConfig } from "userbase/adapter/nextjs";
export default {
connection: {
url: "file:data.db",
},
} satisfies NextjsBkndConfig;
} satisfies NextjsUserbaseConfig;
```
See [bknd.config.ts](/extending/config) for more information on how to configure bknd. The `NextjsBkndConfig` type extends the `BkndConfig` type with the following additional properties:
See [userbase.config.ts](/extending/config) for more information on how to configure userbase. The `NextjsUserbaseConfig` type extends the `UserbaseConfig` type with the following additional properties:
```typescript
type NextjsEnv = NextApiRequest["env"];
export type NextjsBkndConfig<Env = NextjsEnv> = FrameworkBkndConfig<Env> & {
export type NextjsUserbaseConfig<Env = NextjsEnv> = FrameworkUserbaseConfig<Env> & {
cleanRequest?: { searchParams?: string[] };
};
```
## Serve the API
Create a helper file to instantiate the bknd instance and retrieve the API, importing the configuration from the `bknd.config.ts` file:
Create a helper file to instantiate the userbase instance and retrieve the API, importing the configuration from the `userbase.config.ts` file:
```ts title="src/bknd.ts"
```ts title="src/userbase.ts"
import {
type NextjsBkndConfig,
getApp as getBkndApp,
} from "bknd/adapter/nextjs";
type NextjsUserbaseConfig,
getApp as getUserbaseApp,
} from "userbase/adapter/nextjs";
import { headers } from "next/headers";
import config from "../bknd.config";
import config from "../userbase.config";
export { config };
export async function getApp() {
return await getBkndApp(config, process.env);
return await getUserbaseApp(config, process.env);
}
export async function getApi(opts?: { verify?: boolean }) {
@@ -101,11 +101,11 @@ export async function getApi(opts?: { verify?: boolean }) {
For more information about the connection object, refer to the [Database](/usage/database) guide.
Now to expose the API, create a catch-all route file at `src/api/[[...bknd]]/route.ts`:
Now to expose the API, create a catch-all route file at `src/api/[[...userbase]]/route.ts`:
```ts title="src/api/[[...bknd]]/route.ts"
import { config } from "@/bknd";
import { serve } from "bknd/adapter/nextjs";
```ts title="src/api/[[...userbase]]/route.ts"
import { config } from "@/userbase";
import { serve } from "userbase/adapter/nextjs";
// optionally, you can set the runtime to edge for better performance
// export const runtime = "edge";
@@ -115,7 +115,7 @@ const handler = serve({
cleanRequest: {
// depending on what name you used for the catch-all route,
// you need to change this to clean it from the request.
searchParams: ["bknd"],
searchParams: ["userbase"],
},
});
@@ -133,7 +133,7 @@ Create a file at `admin/[[...admin]]/page.client.tsx`:
"use client";
import dynamic from "next/dynamic";
export const Admin = dynamic(async () => (await import("bknd/ui")).Admin, {
export const Admin = dynamic(async () => (await import("userbase/ui")).Admin, {
ssr: false,
});
```
@@ -144,8 +144,8 @@ export const Admin = dynamic(async () => (await import("bknd/ui")).Admin, {
Create a page at `admin/[[...admin]]/page.tsx`:
```tsx title="admin/[[...admin]]/page.tsx"
import { getApi } from "@/bknd";
import "bknd/dist/styles.css";
import { getApi } from "@/userbase";
import "userbase/dist/styles.css";
import { Admin } from "./page.client";
import { Suspense } from "react";
import { redirect } from "next/navigation";
@@ -176,12 +176,12 @@ export default async function AdminPage() {
## React SDK configuration
To use queries and mutation on client side, bknd provides first class support for it with it's [React SDK](/usage/react)
To use queries and mutation on client side, userbase provides first class support for it with it's [React SDK](/usage/react)
to set it up with Next.js add the `ClientProvider` to your root layout
```tsx title="app/layout.tsx"
import { ClientProvider } from "bknd/client";
import { ClientProvider } from "userbase/client";
export default function RootLayout({
children,
@@ -206,7 +206,7 @@ export default function RootLayout({
You can use the `getApi` helper function we've already set up to fetch and mutate in static pages and server components:
```tsx title="app/page.tsx"
import { getApi } from "@/bknd";
import { getApi } from "@/userbase";
export default async function Home() {
const api = await getApi();
@@ -1,29 +1,29 @@
---
title: "Nuxt"
description: "Run bknd inside Nuxt"
description: "Run userbase inside Nuxt"
tags: ["documentation"]
---
## Installation
To get started with Nuxt and bknd, create a new Nuxt project by following the [official guide](https://nuxt.com/docs/4.x/getting-started/installation), and then install bknd as a dependency:
To get started with Nuxt and userbase, create a new Nuxt project by following the [official guide](https://nuxt.com/docs/4.x/getting-started/installation), and then install userbase as a dependency:
<Tabs groupId='package-manager' persist items={[ 'npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm install bknd
npm install userbase
```
```bash tab="pnpm"
pnpm install bknd
pnpm install userbase
```
```bash tab="yarn"
yarn add bknd
yarn add userbase
```
```bash tab="bun"
bun add bknd
bun add userbase
```
</Tabs>
@@ -36,12 +36,12 @@ bun add bknd
[upgrade](https://nodejs.org/en/download/) if necessary.
</Callout>
Now create a `bknd.config.ts` file in the root of your project:
Now create a `userbase.config.ts` file in the root of your project:
```typescript title="bknd.config.ts"
import type NuxtBkndConfig from "bknd/adapter/nuxt";
import { em, entity, text, boolean } from "bknd";
import { secureRandomString } from "bknd/utils";
```typescript title="userbase.config.ts"
import type NuxtUserbaseConfig from "userbase/adapter/nuxt";
import { em, entity, text, boolean } from "userbase";
import { secureRandomString } from "userbase/utils";
const schema = em({
todos: entity("todos", {
@@ -68,36 +68,36 @@ export default {
seed: async (ctx) => {
// create some entries
await ctx.em.mutator("todos").insertMany([
{ title: "Learn bknd", done: true },
{ title: "Learn userbase", done: true },
{ title: "Build something cool", done: false },
]);
// and create a user
await ctx.app.module.auth.createUser({
email: "test@bknd.io",
email: "test@userbase.io",
password: "12345678",
});
},
},
} satisfies NuxtBkndConfig;
} satisfies NuxtUserbaseConfig;
```
For more information about the connection object, refer to the [Database](/usage/database) guide.
See [bknd.config.ts](/extending/config) for more information on how to configure bknd. The `NuxtBkndConfig` type extends the base config type with the following properties:
See [userbase.config.ts](/extending/config) for more information on how to configure userbase. The `NuxtUserbaseConfig` type extends the base config type with the following properties:
```typescript
export type NuxtBkndConfig<Env = NuxtEnv> = FrameworkBkndConfig<Env>;
export type NuxtUserbaseConfig<Env = NuxtEnv> = FrameworkUserbaseConfig<Env>;
```
## Serve the API and Admin UI
The Nuxt adapter uses Nuxt middleware to handle API requests and serve the Admin UI. Create a `/server/middleware/bknd.ts` file:
The Nuxt adapter uses Nuxt middleware to handle API requests and serve the Admin UI. Create a `/server/middleware/userbase.ts` file:
```typescript title="/server/middleware/bknd.ts"
import { serve } from "bknd/adapter/nuxt";
import config from "../../bknd.config";
```typescript title="/server/middleware/userbase.ts"
import { serve } from "userbase/adapter/nuxt";
import config from "../../userbase.config";
const handler = serve(config, process.env);
@@ -119,21 +119,21 @@ export default defineEventHandler(async (event) => {
You can visit https://localhost:3000/admin to see the admin UI. Additionally you can create more todos as you explore the admin UI.
</Callout>
Create a helper file to instantiate the bknd instance and retrieve the API, importing the configuration from the `bknd.config.ts` file:
Create a helper file to instantiate the userbase instance and retrieve the API, importing the configuration from the `userbase.config.ts` file:
```ts title="server/utils/bknd.ts"
import { type NuxtBkndConfig, getApp as getNuxtApp } from "bknd/adapter/nuxt";
import bkndConfig from "../../bknd.config";
```ts title="server/utils/userbase.ts"
import { type NuxtUserbaseConfig, getApp as getNuxtApp } from "userbase/adapter/nuxt";
import userbaseConfig from "../../userbase.config";
export async function getApp<Env = NodeJS.ProcessEnv>(
config: NuxtBkndConfig<Env>,
config: NuxtUserbaseConfig<Env>,
args: Env = process.env as Env,
) {
return await getNuxtApp(config, args);
}
export async function getApi({ headers, verify }: { verify?: boolean; headers?: Headers }) {
const app = await getApp(bkndConfig, process.env);
const app = await getApp(userbaseConfig, process.env);
if (verify) {
const api = app.getApi({ headers });
@@ -152,7 +152,7 @@ export async function getApi({ headers, verify }: { verify?: boolean; headers?:
## Example usage of the API
You can use the `getApp` function to access the bknd API in your app to expose endpoints,
You can use the `getApp` function to access the userbase API in your app to expose endpoints,
Here are some examples:
```typescript title="server/routes/todos.post.ts"
@@ -198,7 +198,7 @@ export default defineEventHandler(async (event) => {
To use the API in your frontend components/pages, you can create a composable that uses the enpoints created in previous steps:
```typescript title="app/composables/useTodoActions.ts"
import type { DB } from "bknd";
import type { DB } from "userbase";
type Todo = DB["todos"];
@@ -236,7 +236,7 @@ export const useTodoActions = () => {
Make a composable to fetch the todos:
```ts title="app/composables/useTodoActions.ts"
import type { DB } from "bknd";
import type { DB } from "userbase";
type Todo = DB["todos"];
@@ -289,7 +289,7 @@ onMounted(() => {
<div class="flex flex-row items-center ">
<img class="dark:invert size-24" src="/nuxt.svg" alt="Nuxt logo" />
<div class="ml-3.5 mr-2 font-mono opacity-70">&amp;</div>
<img class="dark:invert" src="/bknd.svg" alt="bknd logo" width="183" height="59" />
<img class="dark:invert" src="/userbase.svg" alt="userbase logo" width="183" height="59" />
</div>
<div v-if="data?.todos">
<ul>
@@ -323,7 +323,7 @@ onMounted(() => {
Make a composable to fetch the user:
```ts title="app/composables/useUser.ts"
import type { User } from "bknd";
import type { User } from "userbase";
export const useUser = () => {
const getUser = () => $fetch("/api/auth/me") as Promise<{ user: User }>;
@@ -353,7 +353,7 @@ onMounted(() => {
<div class="flex flex-row items-center ">
<img class="dark:invert size-24" src="/nuxt.svg" alt="Nuxt logo" />
<div class="ml-3.5 mr-2 font-mono opacity-70">&amp;</div>
<img class="dark:invert" src="/bknd.svg" alt="bknd logo" width="183" height="59" />
<img class="dark:invert" src="/userbase.svg" alt="userbase logo" width="183" height="59" />
</div>
<div v-if="data?.user">
Logged in as {{ data.user.email }}.
@@ -371,7 +371,7 @@ onMounted(() => {
<p className="text-xs opacity-50">
Sign in with:
<b>
<code>test@bknd.io</code>
<code>test@userbase.io</code>
</b>
/
<b>
@@ -387,7 +387,7 @@ onMounted(() => {
## Important Note
Use `external` attribute on Nuxt links, anytime you are traversing to an external route (like `/api/*` which are handled by bknd's middleware) to prevent vue router from intercepting the link.
Use `external` attribute on Nuxt links, anytime you are traversing to an external route (like `/api/*` which are handled by userbase's middleware) to prevent vue router from intercepting the link.
```vue
<NuxtLink external href="/admin">
@@ -399,4 +399,4 @@ Use `external` attribute on Nuxt links, anytime you are traversing to an externa
If you don't use the `external` attribute, vue router will intercept the link and try to navigate to it, which will fail and result in a 404 error.
</Callout>
Check the [Nuxt repository example](https://github.com/bknd-io/bknd/tree/main/examples/nuxt) for more implementation details.
Check the [Nuxt repository example](https://github.com/userbase-io/userbase/tree/main/examples/nuxt) for more implementation details.
@@ -1,41 +1,41 @@
---
title: "React Router"
description: "Run bknd inside React Router"
description: "Run userbase inside React Router"
tags: ["documentation"]
---
## Installation
To get started with React Router and bknd you can either install the package manually, and follow the descriptions below, or use the CLI starter:
To get started with React Router and userbase you can either install the package manually, and follow the descriptions below, or use the CLI starter:
### CLI Starter
Create a new React Router CLI starter project by running the following command:
```sh
npx bknd create -i react-router
npx userbase create -i react-router
```
### Manual
Create a new React Router project by following the [official guide](https://reactrouter.com/start/framework/installation), and then install bknd as a dependency:
Create a new React Router project by following the [official guide](https://reactrouter.com/start/framework/installation), and then install userbase as a dependency:
<Tabs groupId='package-manager' persist items={[ 'npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm install bknd
npm install userbase
```
```bash tab="pnpm"
pnpm install bknd
pnpm install userbase
```
```bash tab="yarn"
yarn add bknd
yarn add userbase
```
```bash tab="bun"
bun add bknd
bun add userbase
```
</Tabs>
@@ -48,41 +48,41 @@ bun add bknd
[upgrade](https://nodejs.org/en/download/) if necessary.
</Callout>
Now create a `bknd.config.ts` file in the root of your project. If you created the project using the CLI starter, this file is already created for you.
Now create a `userbase.config.ts` file in the root of your project. If you created the project using the CLI starter, this file is already created for you.
```typescript title="bknd.config.ts"
import type { ReactRouterBkndConfig } from "bknd/adapter/react-router";
```typescript title="userbase.config.ts"
import type { ReactRouterUserbaseConfig } from "userbase/adapter/react-router";
export default {
connection: {
url: "file:data.db",
},
} satisfies ReactRouterBkndConfig;
} satisfies ReactRouterUserbaseConfig;
```
See [bknd.config.ts](/extending/config) for more information on how to configure bknd. The `ReactRouterBkndConfig` type extends the `BkndConfig` type with the following additional properties:
See [userbase.config.ts](/extending/config) for more information on how to configure userbase. The `ReactRouterUserbaseConfig` type extends the `UserbaseConfig` type with the following additional properties:
```typescript
type ReactRouterEnv = NodeJS.ProcessEnv;
type ReactRouterFunctionArgs = {
request: Request;
};
export type ReactRouterBkndConfig<Env = ReactRouterEnv> =
FrameworkBkndConfig<Env>;
export type ReactRouterUserbaseConfig<Env = ReactRouterEnv> =
FrameworkUserbaseConfig<Env>;
```
## Serve the API
### Helper Functions (Optional)
For convenience, you can create a helper file to instantiate the bknd instance and retrieve the API. This is optional but recommended as it simplifies usage throughout your app. The examples below assume you've created this helper, but you can adjust the approach according to your needs.
For convenience, you can create a helper file to instantiate the userbase instance and retrieve the API. This is optional but recommended as it simplifies usage throughout your app. The examples below assume you've created this helper, but you can adjust the approach according to your needs.
```ts title="app/bknd.ts"
```ts title="app/userbase.ts"
import {
type ReactRouterBkndConfig,
getApp as getBkndApp,
} from "bknd/adapter/react-router";
import config from "../bknd.config";
type ReactRouterUserbaseConfig,
getApp as getUserbaseApp,
} from "userbase/adapter/react-router";
import config from "../userbase.config";
export { config };
@@ -90,7 +90,7 @@ export { config };
// e.g. when deploying to cloudflare workers, you'd want the FunctionArgs to be passed in
// to resolve environment variables
export async function getApp() {
return await getBkndApp(config, process.env as any);
return await getUserbaseApp(config, process.env as any);
}
export async function getApi(
@@ -112,10 +112,10 @@ For more information about the connection object, refer to the [Database](/usage
### API Route
Create a catch-all route file at `app/routes/api.$.ts` that forwards requests to bknd:
Create a catch-all route file at `app/routes/api.$.ts` that forwards requests to userbase:
```ts title="app/routes/api.$.ts"
import { getApp } from "~/bknd";
import { getApp } from "~/userbase";
const handler = async (args: { request: Request }) => {
const app = await getApp();
@@ -141,17 +141,17 @@ export default [
## Enabling the Admin UI
Create a route file at `app/routes/admin.$.tsx` to enable the bknd Admin UI for managing your data, schema, and users:
Create a route file at `app/routes/admin.$.tsx` to enable the userbase Admin UI for managing your data, schema, and users:
```tsx title="app/routes/admin.$.tsx"
import { lazy, Suspense, useSyncExternalStore } from "react";
import { type LoaderFunctionArgs, useLoaderData } from "react-router";
import { getApi } from "~/bknd";
import { getApi } from "~/userbase";
const Admin = lazy(() =>
import("bknd/ui").then((mod) => ({ default: mod.Admin })),
import("userbase/ui").then((mod) => ({ default: mod.Admin })),
);
import "bknd/dist/styles.css";
import "userbase/dist/styles.css";
export const loader = async (args: LoaderFunctionArgs) => {
const api = await getApi(args, { verify: true });
@@ -201,7 +201,7 @@ You can use the `getApi` helper function we've already set up to fetch and mutat
```tsx title="app/routes/_index.tsx"
import { useLoaderData, type LoaderFunctionArgs } from "react-router";
import { getApi } from "~/bknd";
import { getApi } from "~/userbase";
export const loader = async (args: LoaderFunctionArgs) => {
// use authentication from request
@@ -226,11 +226,11 @@ export default function Index() {
## Using React Hooks (Optional)
If you want to use bknd's client-side React hooks (like `useEntityQuery`, `useAuth`, etc.), wrap your app in the `ClientProvider` component. This is typically done in `app/root.tsx`:
If you want to use userbase's client-side React hooks (like `useEntityQuery`, `useAuth`, etc.), wrap your app in the `ClientProvider` component. This is typically done in `app/root.tsx`:
```tsx title="app/root.tsx"
// other imports
import { ClientProvider } from "bknd/client";
import { ClientProvider } from "userbase/client";
// ...
export default function App() {
@@ -243,4 +243,4 @@ export default function App() {
// ...
```
The `ClientProvider` automatically uses the same origin for API requests, which works perfectly when bknd is served from your React Router app. For more details on using React hooks, see the [React SDK documentation](/usage/react).
The `ClientProvider` automatically uses the same origin for API requests, which works perfectly when userbase is served from your React Router app. For more details on using React hooks, see the [React SDK documentation](/usage/react).
@@ -1,31 +1,31 @@
---
title: "Solid Start"
description: "Run bknd inside Solid Start"
description: "Run userbase inside Solid Start"
tags: ["documentation"]
---
## Installation
To get started with Solid Start and bknd you can either install the package manually, and follow the descriptions below, or use the CLI starter.
To get started with Solid Start and userbase you can either install the package manually, and follow the descriptions below, or use the CLI starter.
Create a new Solid Start project by following the [official guide](https://docs.solidjs.com/solid-start/getting-started), and then install bknd as a dependency:
Create a new Solid Start project by following the [official guide](https://docs.solidjs.com/solid-start/getting-started), and then install userbase as a dependency:
<Tabs groupId='package-manager' persist items={[ 'npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm install bknd
npm install userbase
```
```bash tab="pnpm"
pnpm install bknd
pnpm install userbase
```
```bash tab="yarn"
yarn add bknd
yarn add userbase
```
```bash tab="bun"
bun add bknd
bun add userbase
```
</Tabs>
@@ -38,12 +38,12 @@ bun add bknd
[upgrade](https://nodejs.org/en/download/) if necessary.
</Callout>
Now create a `bknd.config.ts` file in the root of your project. If you created the project using the CLI starter, this file is already created for you.
Now create a `userbase.config.ts` file in the root of your project. If you created the project using the CLI starter, this file is already created for you.
```typescript title="bknd.config.ts"
import type { SolidStartBkndConfig } from "bknd/adapter/solid-start";
import { em, entity, text, boolean } from "bknd";
import { secureRandomString } from "bknd/utils";
```typescript title="userbase.config.ts"
import type { SolidStartUserbaseConfig } from "userbase/adapter/solid-start";
import { em, entity, text, boolean } from "userbase";
import { secureRandomString } from "userbase/utils";
const schema = em({
todos: entity("todos", {
@@ -54,7 +54,7 @@ const schema = em({
// register your schema to get automatic type completion
type Database = (typeof schema)["DB"];
declare module "bknd" {
declare module "userbase" {
interface DB extends Database {}
}
@@ -67,13 +67,13 @@ export default {
seed: async (ctx) => {
// create some entries
await ctx.em.mutator("todos").insertMany([
{ title: "Learn bknd", done: true },
{ title: "Learn userbase", done: true },
{ title: "Build something cool", done: false },
]);
// and create a user
await ctx.app.module.auth.createUser({
email: "test@bknd.io",
email: "test@userbase.io",
password: "12345678",
});
},
@@ -87,20 +87,20 @@ export default {
},
},
},
// please run `bun bknd copy-assets --out public/admin` to copy the admin assets into the public directory
// please run `bun userbase copy-assets --out public/admin` to copy the admin assets into the public directory
// alternatively add this as a postinstall script in your package.json like this:
// "postinstall": "bknd copy-assets --out public/admin"
// "postinstall": "userbase copy-assets --out public/admin"
adminOptions: {
adminBasepath: "/admin",
assetsPath: "/admin/", // trailing slash is important
},
} satisfies SolidStartBkndConfig;
} satisfies SolidStartUserbaseConfig;
```
See [bknd.config.ts](/extending/config) for more information on how to configure bknd. The `SolidStartBkndConfig` type extends the `BkndConfig` type with the following additional properties:
See [userbase.config.ts](/extending/config) for more information on how to configure userbase. The `SolidStartUserbaseConfig` type extends the `UserbaseConfig` type with the following additional properties:
```typescript
export type SolidStartBkndConfig<Env = SolidStartEnv> = RuntimeBkndConfig<Env>;
export type SolidStartUserbaseConfig<Env = SolidStartEnv> = RuntimeUserbaseConfig<Env>;
```
## Serve the API and Admin UI
@@ -109,8 +109,8 @@ The Solid Start adapter uses middleware to handle API requests and serve the Adm
```ts title="src/middleware/index.ts"
import { createMiddleware } from "@solidjs/start/middleware";
import config from "../../bknd.config";
import { serve } from "bknd/adapter/solid-start";
import config from "../../userbase.config";
import { serve } from "userbase/adapter/solid-start";
const handler = serve(config);
@@ -170,16 +170,16 @@ export default defineConfig({
You can visit https://localhost:3000/admin to see the admin UI. Additionally you can create more todos as you explore the admin UI.
</Callout>
Create a helper file to instantiate the bknd instance and retrieve the API, importing the configuration from the `bknd.config.ts` file:
Create a helper file to instantiate the userbase instance and retrieve the API, importing the configuration from the `userbase.config.ts` file:
```ts title="src/lib/bknd.ts"
import { getApp as getBkndApp } from "bknd/adapter/solid-start";
import bkndConfig from "../../bknd.config";
import type { App } from "bknd";
```ts title="src/lib/userbase.ts"
import { getApp as getUserbaseApp } from "userbase/adapter/solid-start";
import userbaseConfig from "../../userbase.config";
import type { App } from "userbase";
export const getApp = async () => {
return await getBkndApp(bkndConfig);
return await getUserbaseApp(userbaseConfig);
};
export async function getApi({
@@ -205,7 +205,7 @@ export async function getApi({
You can use the `getApi` helper function we've already set up to fetch and mutate in static pages and server components:
```tsx title="src/routes/index.tsx"
import { getApi } from "~/lib/bknd";
import { getApi } from "~/lib/userbase";
import { query, createAsync } from "@solidjs/router";
export const getTodo = async () => {
@@ -240,7 +240,7 @@ When using authentication, you'll need to pass the headers to the `getApi` funct
import { createResource, Suspense } from "solid-js";
import { A } from "@solidjs/router";
import { getRequestEvent } from "solid-js/web";
import { getApi } from "~/lib/bknd";
import { getApi } from "~/lib/userbase";
export const getUser = async () => {
"use server"
@@ -271,8 +271,8 @@ export default function Auth() {
<div class="ml-3.5 mr-2 opacity-70">&amp;</div>
<img
class="dark:invert"
src="/bknd.svg"
alt="bknd logo"
src="/userbase.svg"
alt="userbase logo"
width={183}
height={59}
/>
@@ -306,7 +306,7 @@ export default function Auth() {
<p class="text-xs opacity-50">
Sign in with:
<b>
<code>test@bknd.io</code>
<code>test@userbase.io</code>
</b>
/
<b>
@@ -326,7 +326,7 @@ export default function Auth() {
## Tips
Use `target="_self"` on links, anytime your traversing to an external route (like `/api/auth/logout` which are handled by bknd's middleware) to prevent solid router from intercepting the link.
Use `target="_self"` on links, anytime your traversing to an external route (like `/api/auth/logout` which are handled by userbase's middleware) to prevent solid router from intercepting the link.
```jsx
<A href="/api/auth/logout" target="_self">
Logout
@@ -1,29 +1,29 @@
---
title: "SvelteKit"
description: "Run bknd inside SvelteKit"
description: "Run userbase inside SvelteKit"
tags: ["documentation"]
---
## Installation
To get started with SvelteKit and bknd, create a new SvelteKit project by following the [official guide](https://svelte.dev/docs/kit/creating-a-project), and then install bknd as a dependency:
To get started with SvelteKit and userbase, create a new SvelteKit project by following the [official guide](https://svelte.dev/docs/kit/creating-a-project), and then install userbase as a dependency:
<Tabs groupId='package-manager' persist items={[ 'npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm install bknd
npm install userbase
```
```bash tab="pnpm"
pnpm install bknd
pnpm install userbase
```
```bash tab="yarn"
yarn add bknd
yarn add userbase
```
```bash tab="bun"
bun add bknd
bun add userbase
```
</Tabs>
@@ -36,22 +36,22 @@ bun add bknd
[upgrade](https://nodejs.org/en/download/) if necessary.
</Callout>
Now create a `bknd.config.ts` file in the root of your project:
Now create a `userbase.config.ts` file in the root of your project:
```typescript title="bknd.config.ts"
import type { SvelteKitBkndConfig } from "bknd/adapter/sveltekit";
```typescript title="userbase.config.ts"
import type { SvelteKitUserbaseConfig } from "userbase/adapter/sveltekit";
export default {
connection: {
url: "file:data.db",
},
} satisfies SvelteKitBkndConfig;
} satisfies SvelteKitUserbaseConfig;
```
See [bknd.config.ts](/extending/config) for more information on how to configure bknd. The `SvelteKitBkndConfig` type extends the base config type with the following properties:
See [userbase.config.ts](/extending/config) for more information on how to configure userbase. The `SvelteKitUserbaseConfig` type extends the base config type with the following properties:
```typescript
export type SvelteKitBkndConfig<Env> = Pick<RuntimeBkndConfig<Env>, "adminOptions">;
export type SvelteKitUserbaseConfig<Env> = Pick<RuntimeUserbaseConfig<Env>, "adminOptions">;
```
## Serve the API
@@ -60,17 +60,17 @@ The SvelteKit adapter uses SvelteKit's hooks mechanism to handle API requests. C
```typescript title="src/hooks.server.ts"
import type { Handle } from "@sveltejs/kit";
import { serve } from "bknd/adapter/sveltekit";
import { serve } from "userbase/adapter/sveltekit";
import { env } from "$env/dynamic/private";
import config from "../bknd.config";
import config from "../userbase.config";
const bkndHandler = serve(config, env);
const userbaseHandler = serve(config, env);
export const handle: Handle = async ({ event, resolve }) => {
// handle bknd API requests
// handle userbase API requests
const pathname = event.url.pathname;
if (pathname.startsWith("/api/")) {
const res = await bkndHandler(event);
const res = await userbaseHandler(event);
if (res.status !== 404) {
return res;
}
@@ -94,15 +94,15 @@ The SvelteKit adapter supports serving the Admin UI statically. First, copy the
```json title="package.json"
{
"scripts": {
"postinstall": "bknd copy-assets --out static" // [!code highlight]
"postinstall": "userbase copy-assets --out static" // [!code highlight]
}
}
```
Then update your `bknd.config.ts` to configure the admin base path:
Then update your `userbase.config.ts` to configure the admin base path:
```typescript title="bknd.config.ts"
import type { SvelteKitBkndConfig } from "bknd/adapter/sveltekit";
```typescript title="userbase.config.ts"
import type { SvelteKitUserbaseConfig } from "userbase/adapter/sveltekit";
export default {
connection: {
@@ -111,24 +111,24 @@ export default {
adminOptions: { // [!code highlight]
adminBasepath: "/admin" // [!code highlight]
}, // [!code highlight]
} satisfies SvelteKitBkndConfig;
} satisfies SvelteKitUserbaseConfig;
```
Finally, update your `hooks.server.ts` to also handle admin routes:
```typescript title="src/hooks.server.ts"
import type { Handle } from "@sveltejs/kit";
import { serve } from "bknd/adapter/sveltekit";
import { serve } from "userbase/adapter/sveltekit";
import { env } from "$env/dynamic/private";
import config from "../bknd.config";
import config from "../userbase.config";
const bkndHandler = serve(config, env);
const userbaseHandler = serve(config, env);
export const handle: Handle = async ({ event, resolve }) => {
// handle bknd API and admin requests
// handle userbase API and admin requests
const pathname = event.url.pathname;
if (pathname.startsWith("/api/") || pathname.startsWith("/admin")) { // [!code highlight]
const res = await bkndHandler(event);
const res = await userbaseHandler(event);
if (res.status !== 404) {
return res;
}
@@ -140,13 +140,13 @@ export const handle: Handle = async ({ event, resolve }) => {
## Example usage of the API
You can use the `getApp` function to access the bknd API in your server-side load functions:
You can use the `getApp` function to access the userbase API in your server-side load functions:
```typescript title="src/routes/+page.server.ts"
import type { PageServerLoad } from "./$types";
import { getApp } from "bknd/adapter/sveltekit";
import { getApp } from "userbase/adapter/sveltekit";
import { env } from "$env/dynamic/private";
import config from "../../bknd.config";
import config from "../../userbase.config";
export const load: PageServerLoad = async () => {
const app = await getApp(config, env);
@@ -183,9 +183,9 @@ To use authentication in your load functions, pass the request headers to the AP
```typescript title="src/routes/+page.server.ts"
import type { PageServerLoad } from "./$types";
import { getApp } from "bknd/adapter/sveltekit";
import { getApp } from "userbase/adapter/sveltekit";
import { env } from "$env/dynamic/private";
import config from "../../bknd.config";
import config from "../../userbase.config";
export const load: PageServerLoad = async ({ request }) => {
const app = await getApp(config, env);
@@ -201,4 +201,4 @@ export const load: PageServerLoad = async ({ request }) => {
};
```
Check the [SvelteKit repository example](https://github.com/bknd-io/bknd/tree/main/examples/sveltekit) for more implementation details.
Check the [SvelteKit repository example](https://github.com/userbase-io/userbase/tree/main/examples/sveltekit) for more implementation details.
@@ -1,29 +1,29 @@
---
title: "Tanstack Start"
description: "Run bknd inside Tanstack Start"
description: "Run userbase inside Tanstack Start"
tags: ["documentation"]
---
## Installation
To get started with Tanstack Start and bknd, create a new Tanstack Start project by following the [official guide](https://tanstack.com/start/latest/docs/framework/react/getting-started#start-a-new-project-from-scratch), and then install bknd as a dependency:
To get started with Tanstack Start and userbase, create a new Tanstack Start project by following the [official guide](https://tanstack.com/start/latest/docs/framework/react/getting-started#start-a-new-project-from-scratch), and then install userbase as a dependency:
<Tabs groupId='package-manager' persist items={[ 'npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm install bknd
npm install userbase
```
```bash tab="pnpm"
pnpm install bknd
pnpm install userbase
```
```bash tab="yarn"
yarn add bknd
yarn add userbase
```
```bash tab="bun"
bun add bknd
bun add userbase
```
</Tabs>
@@ -36,11 +36,11 @@ bun add bknd
[upgrade](https://nodejs.org/en/download/) if necessary.
</Callout>
Now create a `bknd.config.ts` file in the root of your project:
Now create a `userbase.config.ts` file in the root of your project:
```typescript title="bknd.config.ts"
import { type TanstackStartConfig } from "bknd/adapter/tanstack-start";
import { em, entity, text, boolean } from "bknd";
```typescript title="userbase.config.ts"
import { type TanstackStartConfig } from "userbase/adapter/tanstack-start";
import { em, entity, text, boolean } from "userbase";
const schema = em({
todos: entity("todos", {
@@ -68,13 +68,13 @@ export default {
seed: async (ctx) => {
// create some entries
await ctx.em.mutator("todos").insertMany([
{ title: "Learn bknd", done: true },
{ title: "Learn userbase", done: true },
{ title: "Build something cool", done: false },
]);
// and create a user
await ctx.app.module.auth.createUser({
email: "test@bknd.io",
email: "test@userbase.io",
password: "12345678",
});
},
@@ -85,10 +85,10 @@ export default {
For more information about the connection object, refer to the [Database](/usage/database) guide.
See [bknd.config.ts](/extending/config) for more information on how to configure bknd. The `TanstackStartConfig` type extends the base config type with the following properties:
See [userbase.config.ts](/extending/config) for more information on how to configure userbase. The `TanstackStartConfig` type extends the base config type with the following properties:
```typescript
export type TanstackStartConfig<Env = TanstackStartEnv> = FrameworkBkndConfig<Env>;
export type TanstackStartConfig<Env = TanstackStartEnv> = FrameworkUserbaseConfig<Env>;
```
## Serve the API
@@ -97,8 +97,8 @@ The Tanstack Start adapter uses Tanstack Start's hooks mechanism to handle API r
```typescript title="/src/routes/api.$.ts"
import { createFileRoute } from "@tanstack/react-router";
import config from "../../bknd.config";
import { serve } from "bknd/adapter/tanstack-start";
import config from "../../userbase.config";
import { serve } from "userbase/adapter/tanstack-start";
const handler = serve(config);
@@ -111,11 +111,11 @@ export const Route = createFileRoute("/api/$")({
});
```
Create a helper file to instantiate the bknd instance and retrieve the API, importing the configuration from the `bknd.config.ts` file:
Create a helper file to instantiate the userbase instance and retrieve the API, importing the configuration from the `userbase.config.ts` file:
```ts title="src/bknd.ts"
import config from "../bknd.config";
import { getApp } from "bknd/adapter/tanstack-start";
```ts title="src/userbase.ts"
import config from "../userbase.config";
import { getApp } from "userbase/adapter/tanstack-start";
export async function getApi({
headers,
@@ -146,9 +146,9 @@ Create a page at /src/routes/admin.$.tsx:
```typescript title="/src/routes/admin.$.tsx"
import { createFileRoute } from "@tanstack/react-router";
import { useAuth } from "bknd/client";
import "bknd/dist/styles.css";
import { Admin } from "bknd/ui";
import { useAuth } from "userbase/client";
import "userbase/dist/styles.css";
import { Admin } from "userbase/ui";
export const Route = createFileRoute("/admin/$")({
ssr: false, // [!code highlight] "data-only" works too
@@ -178,12 +178,12 @@ function RouteComponent() {
## Example usage of the API
You can use the `getApp` function to access the bknd API in your app:
You can use the `getApp` function to access the userbase API in your app:
These are a few examples how you can validate user and handle server-side requests using `createServerFn`.
```typescript title="src/routes/index.tsx"
import { createFileRoute } from "@tanstack/react-router";
import { getApi } from "@/bknd";
import { getApi } from "@/userbase";
import { createServerFn } from "@tanstack/react-start";
export const getTodo = createServerFn()
@@ -225,7 +225,7 @@ function App() {
To use authentication in your app, pass the request headers to the API:
```typescript title="src/routes/user.tsx"
import { getApi } from "@/bknd";
import { getApi } from "@/userbase";
import { createServerFn } from "@tanstack/react-start";
import { Link } from "@tanstack/react-router";
import { createFileRoute } from "@tanstack/react-router";
@@ -274,7 +274,7 @@ function RouteComponent() {
<p className="text-xs opacity-50">
Sign in with:
<b>
<code>test@bknd.io</code>
<code>test@userbase.io</code>
</b>
/
<b>
@@ -288,4 +288,4 @@ function RouteComponent() {
}
```
Check the [Tanstack Start repository example](https://github.com/bknd-io/bknd/tree/main/examples/tanstack-start) for more implementation details.
Check the [Tanstack Start repository example](https://github.com/userbase-io/userbase/tree/main/examples/tanstack-start) for more implementation details.
@@ -1,6 +1,6 @@
---
title: "Vite"
description: "Run bknd inside Vite"
description: "Run userbase inside Vite"
tags: ["documentation"]
---
@@ -9,24 +9,24 @@ Vite is a powerful toolkit to accelerate your local development.
## Installation
Create a new vite project by following the [official guide](https://vite.dev/guide/#scaffolding-your-first-vite-project)
and then install bknd as a dependency:
and then install userbase as a dependency:
<Tabs groupId='package-manager' persist items={[ 'npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm install bknd
npm install userbase
```
```bash tab="pnpm"
pnpm install bknd
pnpm install userbase
```
```bash tab="yarn"
yarn add bknd
yarn add userbase
```
```bash tab="bun"
bun add bknd
bun add userbase
```
</Tabs>
@@ -45,47 +45,47 @@ npm install @hono/vite-dev-server
[upgrade](https://nodejs.org/en/download/) if necessary.
</Callout>
Now create a `bknd.config.ts` file in the root of your project.
Now create a `userbase.config.ts` file in the root of your project.
```typescript title="bknd.config.ts"
import type { ViteBkndConfig } from "bknd/adapter/vite";
```typescript title="userbase.config.ts"
import type { ViteUserbaseConfig } from "userbase/adapter/vite";
export default {
connection: {
url: "file:data.db",
},
} satisfies ViteBkndConfig;
} satisfies ViteUserbaseConfig;
```
See [bknd.config.ts](/extending/config) for more information on how to configure bknd.
The `ViteBkndConfig` type extends the `BkndConfig` type with the following additional properties:
See [userbase.config.ts](/extending/config) for more information on how to configure userbase.
The `ViteUserbaseConfig` type extends the `UserbaseConfig` type with the following additional properties:
```typescript
export type ViteEnv = NodeJS.ProcessEnv;
export type ViteBkndConfig<Env = ViteEnv> = RuntimeBkndConfig<Env> & {};
export type ViteUserbaseConfig<Env = ViteEnv> = RuntimeUserbaseConfig<Env> & {};
```
## Serve the API
To serve the **bknd** API, you first have to create a local server file for you vite environment.
To serve the **userbase** API, you first have to create a local server file for you vite environment.
Create a `server.ts` file:
```typescript title="server.ts"
import { serve } from "bknd/adapter/vite";
import config from "./bknd.config";
import { serve } from "userbase/adapter/vite";
import config from "./userbase.config";
export default serve(config);
```
You can also run your vite server in `mode: "fresh"`, this will re-create the app on every fetch.
This is only useful for when working on the `bknd` repository directly.
This is only useful for when working on the `userbase` repository directly.
For more information about the connection object, refer to the [Database](/usage/database) guide.
Next, adjust your `vite.config.ts` to look like the following:
```ts title="vite.config.ts"
import { devServer } from "bknd/adapter/vite";
import { devServer } from "userbase/adapter/vite";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
import tsconfigPaths from "vite-tsconfig-paths";
@@ -105,7 +105,7 @@ export default defineConfig({
Now you can start your application using `npm run dev`. Now opening http://localhost:5174/
looks like an empty project. That's because we only registered the API, head over to
http://localhost:5174/api/system/config to see **bknd** respond.
http://localhost:5174/api/system/config to see **userbase** respond.
## Serve the Admin UI
@@ -113,8 +113,8 @@ After adding the API, you can easily add the Admin UI by simply returning it in
Replace all of its content with the following:
```tsx title="App.tsx"
import { Admin } from "bknd/ui";
import "bknd/dist/styles.css";
import { Admin } from "userbase/ui";
import "userbase/dist/styles.css";
export default function App() {
return <Admin withProvider />;
@@ -131,12 +131,12 @@ options you can make use of to adjust it according to your setup.
### Use custom HTML to serve the Admin UI
There might be cases you want to be sure to be in control over the HTML that is being used.
`bknd` generates it automatically, but you use your own one as follows:
`userbase` generates it automatically, but you use your own one as follows:
```typescript title="server.ts"
import { serve, addViteScript } from "bknd/adapter/vite";
import { serve, addViteScript } from "userbase/adapter/vite";
import { readFile } from "node:fs/promises";
import config from "./bknd.config";
import config from "./userbase.config";
let html = await readFile("./index.html", "utf-8");
@@ -160,8 +160,8 @@ By default, the entry point `/src/main.tsx` is used and should fit most cases. I
you can supply a different one like so:
```typescript title="server.ts"
import { serve } from "bknd/adapter/vite";
import config from "./bknd.config";
import { serve } from "userbase/adapter/vite";
import config from "./userbase.config";
// the configuration given is optional
export default serve({
@@ -1,41 +1,41 @@
---
title: "AWS Lambda"
description: "Run bknd inside AWS Lambda"
description: "Run userbase inside AWS Lambda"
tags: ["documentation"]
---
## Installation
To get started with AWS Lambda and bknd you can either install the package manually and follow the descriptions below, or use the CLI starter:
To get started with AWS Lambda and userbase you can either install the package manually and follow the descriptions below, or use the CLI starter:
### CLI Starter
Create a new Bun CLI starter project by running the following command:
```sh
npx bknd create -i aws
npx userbase create -i aws
```
### Manual
Create a new AWS Lambda project and then install bknd as a dependency:
Create a new AWS Lambda project and then install userbase as a dependency:
<Tabs groupId='package-manager' persist items={[ 'npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm install bknd
npm install userbase
```
```bash tab="pnpm"
pnpm install bknd
pnpm install userbase
```
```bash tab="yarn"
yarn add bknd
yarn add userbase
```
```bash tab="bun"
bun add bknd
bun add userbase
```
</Tabs>
@@ -45,8 +45,8 @@ bun add bknd
To serve the API, you can use the `serveLambda` function of the AWS Lambda adapter.
```tsx title="index.mjs"
import { serveLambda } from "bknd/adapter/aws";
import { libsql } from "bknd";
import { serveLambda } from "userbase/adapter/aws";
import { libsql } from "userbase";
export const handler = serveLambda({
connection: libsql({
@@ -65,13 +65,13 @@ Lambda functions should be as small as possible. Therefore, the static files for
Instead, we recommend to copy the static files and bundle them with the lambda function. To copy the static files, you can use the `copy-assets` command:
```bash
npx bknd copy-assets --out static
npx userbase copy-assets --out static
```
This will copy the static files to the `static` directory and then serve them from there:
```tsx title="index.mjs"
import { serveLambda } from "bknd/adapter/aws";
import { serveLambda } from "userbase/adapter/aws";
export const handler = serveLambda({
connection: {
@@ -97,7 +97,7 @@ To deploy a lambda function, you could follow these steps:
5. Create a lambda function
6. Create a function URL for the lambda function & make it publicly accessible (optional)
Depending on your use case, you may want to skip step 6 and use the AWS API Gateway to serve the lambda function. Here is an [example deployment script](https://github.com/bknd-io/bknd/blob/main/examples/aws-lambda/deploy.sh) which creates the AWS resources described above, bundles the lambda function and uploads it.
Depending on your use case, you may want to skip step 6 and use the AWS API Gateway to serve the lambda function. Here is an [example deployment script](https://github.com/userbase-io/userbase/blob/main/examples/aws-lambda/deploy.sh) which creates the AWS resources described above, bundles the lambda function and uploads it.
### Using the CLI starter
@@ -111,8 +111,8 @@ To make adjustments to the lambda function created (e.g. architecture, memory, t
```sh title="deploy.sh"
# cat deploy.sh | head -12
FUNCTION_NAME="bknd-lambda"
ROLE_NAME="bknd-lambda-execution-role"
FUNCTION_NAME="userbase-lambda"
ROLE_NAME="userbase-lambda-execution-role"
RUNTIME="nodejs22.x"
HANDLER="index.handler"
ARCHITECTURE="arm64" # or "x86_64"
@@ -1,41 +1,41 @@
---
title: "Bun"
description: "Run bknd inside Bun"
description: "Run userbase inside Bun"
tags: ["documentation"]
---
## Installation
To get started with Bun and bknd you can either install the package manually, and follow the descriptions below, or use the CLI starter:
To get started with Bun and userbase you can either install the package manually, and follow the descriptions below, or use the CLI starter:
## CLI Starter
Create a new Bun CLI starter project by running the following command:
```sh
npx bknd create -i bun
npx userbase create -i bun
```
### Manual
Create a new Bun project and then install bknd as a dependency:
Create a new Bun project and then install userbase as a dependency:
<Tabs groupId='package-manager' persist items={[ 'npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm install bknd
npm install userbase
```
```bash tab="pnpm"
pnpm install bknd
pnpm install userbase
```
```bash tab="yarn"
yarn add bknd
yarn add userbase
```
```bash tab="bun"
bun add bknd
bun add userbase
```
</Tabs>
@@ -46,7 +46,7 @@ The `serve` function of the Bun adapter makes sure to also serve the static file
the admin panel.
```tsx title="index.ts"
import { serve } from "bknd/adapter/bun";
import { serve } from "userbase/adapter/bun";
// if the configuration is omitted, it uses an in-memory database
serve({
@@ -1,41 +1,41 @@
---
title: "Cloudflare"
description: "Run bknd inside Cloudflare Worker"
description: "Run userbase inside Cloudflare Worker"
tags: ["documentation"]
---
## Installation
To get started with Cloudflare Workers and bknd you can either install the package manually, and follow the descriptions below, or use the CLI starter:
To get started with Cloudflare Workers and userbase you can either install the package manually, and follow the descriptions below, or use the CLI starter:
### CLI Starter
Create a new Cloudflare CLI starter project by running the following command:
```sh
npx bknd create -i cloudflare
npx userbase create -i cloudflare
```
### Manual
Create a new cloudflare worker project by following the [official guide](https://developers.cloudflare.com/workers/get-started/guide/), and then install bknd as a dependency:
Create a new cloudflare worker project by following the [official guide](https://developers.cloudflare.com/workers/get-started/guide/), and then install userbase as a dependency:
<Tabs groupId='package-manager' persist items={[ 'npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm install bknd
npm install userbase
```
```bash tab="pnpm"
pnpm install bknd
pnpm install userbase
```
```bash tab="yarn"
yarn add bknd
yarn add userbase
```
```bash tab="bun"
bun add bknd
bun add userbase
```
</Tabs>
@@ -45,7 +45,7 @@ bun add bknd
If you don't choose anything specific, it uses the first D1 binding it finds.
```ts title="src/index.ts"
import { serve, d1 } from "bknd/adapter/cloudflare";
import { serve, d1 } from "userbase/adapter/cloudflare";
// scans your environment for the first D1 binding it finds
export default serve();
@@ -83,25 +83,25 @@ Now in order to also server the static admin files, you have to modify the `wran
### Assets (recommended)
Make sure your assets point to the static assets included in the bknd package:
Make sure your assets point to the static assets included in the userbase package:
```toml title="wrangler.toml"
assets = { directory = "node_modules/bknd/dist/static" }
assets = { directory = "node_modules/userbase/dist/static" }
```
### Workers Sites (legacy)
Make sure your site points to the static assets included in the bknd package:
Make sure your site points to the static assets included in the userbase package:
```toml title="wrangler.toml"
[site]
bucket = "node_modules/bknd/dist/static"
bucket = "node_modules/userbase/dist/static"
```
And then modify the worker entry as follows:
```ts title="src/index.ts"
import { serve } from "bknd/adapter/cloudflare";
import { serve } from "userbase/adapter/cloudflare";
import manifest from "__STATIC_CONTENT_MANIFEST"; // [!code highlight]
export default serve<Env>({
@@ -118,7 +118,7 @@ export default serve<Env>({
You can also add custom routes by defining them after the app has been built, like so:
```ts
import { serve } from "bknd/adapter/cloudflare";
import { serve } from "userbase/adapter/cloudflare";
export default serve<Env>({
// ...
@@ -132,10 +132,10 @@ The property `app.server` is a [Hono](https://hono.dev/) instance, you can liter
## D1 Sessions (experimental)
D1 now supports to enable [global read replication](https://developers.cloudflare.com/d1/best-practices/read-replication/). This allows to reduce latency by reading from the closest region. In order for this to work, D1 has to be started from a bookmark. You can enable this behavior on bknd by setting the `d1.session` property:
D1 now supports to enable [global read replication](https://developers.cloudflare.com/d1/best-practices/read-replication/). This allows to reduce latency by reading from the closest region. In order for this to work, D1 has to be started from a bookmark. You can enable this behavior on userbase by setting the `d1.session` property:
```typescript title="src/index.ts"
import { serve } from "bknd/adapter/cloudflare";
import { serve } from "userbase/adapter/cloudflare";
export default serve({
// ...
@@ -152,7 +152,7 @@ export default serve({
});
```
If bknd is used in a stateful user context (like in a browser), it'll automatically send the session cookie to the server to set the correct bookmark. If you need to manually set the bookmark, you can do so by setting the `x-cf-d1-session` header:
If userbase is used in a stateful user context (like in a browser), it'll automatically send the session cookie to the server to set the correct bookmark. If you need to manually set the bookmark, you can do so by setting the `x-cf-d1-session` header:
```bash
curl -H "x-cf-d1-session: <bookmark>" ...
@@ -161,10 +161,10 @@ curl -H "x-cf-d1-session: <bookmark>" ...
## Filesystem access with Vite Plugin
The [Cloudflare Vite Plugin](https://developers.cloudflare.com/workers/vite-plugin/) allows to use Vite with Miniflare to emulate the Cloudflare Workers runtime. This is great, however, `unenv` disables any Node.js APIs that aren't supported, including the `fs` module. If you want to use plugins such as [`syncTypes`](/extending/plugins#synctypes), this will cause issues.
To fix this, bknd exports a Vite plugin that provides filesystem access during development. You can use it by adding the following to your `vite.config.ts` file:
To fix this, userbase exports a Vite plugin that provides filesystem access during development. You can use it by adding the following to your `vite.config.ts` file:
```ts
import { devFsVitePlugin } from "bknd/adapter/cloudflare";
import { devFsVitePlugin } from "userbase/adapter/cloudflare";
export default defineConfig({
plugins: [devFsVitePlugin()], // [!code highlight]
@@ -174,29 +174,29 @@ export default defineConfig({
Now to use this polyfill, you can use the `devFsWrite` function to write files to the filesystem.
```ts
import { devFsWrite } from "bknd/adapter/cloudflare"; // [!code highlight]
import { syncTypes } from "bknd/plugins";
import { devFsWrite } from "userbase/adapter/cloudflare"; // [!code highlight]
import { syncTypes } from "userbase/plugins";
export default {
options: {
plugins: [
syncTypes({
write: async (et) => {
await devFsWrite("bknd-types.d.ts", et.toString()); // [!code highlight]
await devFsWrite("userbase-types.d.ts", et.toString()); // [!code highlight]
}
}),
]
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
## Cloudflare Bindings in CLI
The bknd CLI does not automatically have access to the Cloudflare bindings. We need to manually proxy them to the CLI by using the `withPlatformProxy` helper function:
The userbase CLI does not automatically have access to the Cloudflare bindings. We need to manually proxy them to the CLI by using the `withPlatformProxy` helper function:
```typescript title="bknd.config.ts"
import { d1 } from "bknd/adapter/cloudflare";
import { withPlatformProxy } from "bknd/adapter/cloudflare/proxy";
```typescript title="userbase.config.ts"
import { d1 } from "userbase/adapter/cloudflare";
import { withPlatformProxy } from "userbase/adapter/cloudflare/proxy";
export default withPlatformProxy({
app: (env) => ({
@@ -211,22 +211,22 @@ Now you can use the CLI with your Cloudflare resources.
Make sure to not import from this file in your app, as this would include `wrangler` as a dependency.
</Callout>
Instead, it's recommended to split this configuration into separate files, e.g. `bknd.config.ts` and `config.ts`:
Instead, it's recommended to split this configuration into separate files, e.g. `userbase.config.ts` and `config.ts`:
```typescript title="config.ts"
import { d1, type CloudflareBkndConfig } from "bknd/adapter/cloudflare";
import { d1, type CloudflareUserbaseConfig } from "userbase/adapter/cloudflare";
export default {
app: (env) => ({
connection: d1({ binding: env.DB }),
}),
} satisfies CloudflareBkndConfig;
} satisfies CloudflareUserbaseConfig;
```
`config.ts` now holds the configuration, and can safely be imported in your app. Since the CLI looks for a `bknd.config.ts` file by default, we change it to wrap the configuration from `config.ts` in the `withPlatformProxy` helper function.
`config.ts` now holds the configuration, and can safely be imported in your app. Since the CLI looks for a `userbase.config.ts` file by default, we change it to wrap the configuration from `config.ts` in the `withPlatformProxy` helper function.
```typescript title="bknd.config.ts"
import { withPlatformProxy } from "bknd/adapter/cloudflare/proxy";
```typescript title="userbase.config.ts"
import { withPlatformProxy } from "userbase/adapter/cloudflare/proxy";
import config from "./config";
export default withPlatformProxy(config);
@@ -235,5 +235,5 @@ export default withPlatformProxy(config);
As an additional safe guard, you have to set a `PROXY` environment variable to `1` to enable the proxy.
```bash
PROXY=1 npx bknd types
PROXY=1 npx userbase types
```
@@ -1,27 +1,27 @@
---
title: "Deno"
description: "Run bknd inside Deno"
description: "Run userbase inside Deno"
tags: ["documentation"]
---
## Installation
To get started with Deno and bknd you can either install the package manually, and follow the descriptions below, or use the CLI starter:
To get started with Deno and userbase you can either install the package manually, and follow the descriptions below, or use the CLI starter:
### CLI Starter
Create a new Deno CLI starter project by running the following command:
```sh
deno run npm:bknd create -i deno
deno run npm:userbase create -i deno
```
### Manual
Deno is fully supported as a runtime for bknd. If you plan to solely use the API, the setup is pretty straightforward.
Deno is fully supported as a runtime for userbase. If you plan to solely use the API, the setup is pretty straightforward.
```ts title="main.ts"
import { createAdapterApp } from "npm:bknd/adapter";
import { createAdapterApp } from "npm:userbase/adapter";
const app = await createAdapterApp({
connection: {
@@ -38,13 +38,13 @@ export default {
In order to also serve the static assets of the admin UI, you have 3 choices:
1. Use the `serveStaticViaImport` function to serve the static assets from the `bknd` package directly. Requires unstable `raw-imports`, but it's the easiest way to serve the static assets.
1. Use the `serveStaticViaImport` function to serve the static assets from the `userbase` package directly. Requires unstable `raw-imports`, but it's the easiest way to serve the static assets.
2. Copy the static assets to your local project and use Hono's `serveStatic` middleware.
3. Use the `adminOptions.assetsPath` property to point to a remote address with the static assets.
### `serveStaticViaImport`
The `serveStaticViaImport` function is a middleware that serves the static assets from the `bknd` package directly using dynamic raw imports. It requires the unstable `raw-imports` feature to be enabled. You can enable it by adding the following to your `deno.json`:
The `serveStaticViaImport` function is a middleware that serves the static assets from the `userbase` package directly using dynamic raw imports. It requires the unstable `raw-imports` feature to be enabled. You can enable it by adding the following to your `deno.json`:
```json title="deno.json"
{
@@ -55,7 +55,7 @@ The `serveStaticViaImport` function is a middleware that serves the static asset
Or by using the `--unstable-raw-imports` flag when running your script. Now create a `main.ts` file to serve the API and static assets:
```ts title="main.ts"
import { createRuntimeApp, serveStaticViaImport } from "bknd/adapter";
import { createRuntimeApp, serveStaticViaImport } from "userbase/adapter";
const app = await createRuntimeApp({
connection: {
@@ -69,12 +69,12 @@ export default {
};
```
In case you don't want to point your bknd dependency to the latest version, either add an `imports` section to your `deno.json` file:
In case you don't want to point your userbase dependency to the latest version, either add an `imports` section to your `deno.json` file:
```json title="deno.json"
{
"imports": {
"bknd": "npm:bknd@<VERSION>" // [!code highlight]
"userbase": "npm:userbase@<VERSION>" // [!code highlight]
}
}
```
@@ -84,7 +84,7 @@ Or specify the package with the version specified to the `serveStaticViaImport`
```ts
const app = await createRuntimeApp({
serveStatic: serveStaticViaImport({
package: "bknd@<VERSION>", // [!code highlight]
package: "userbase@<VERSION>", // [!code highlight]
}),
});
```
@@ -96,13 +96,13 @@ Replace `<VERSION>` with the version you want to use.
You can also serve the static assets from your local project by using Hono's `serveStatic` middleware. You can do so by copying the static assets to your local project and using the `serveStatic` middleware. First, you have to copy the static assets, by running the following command:
```bash
deno run npm:bknd copy-assets --out public
deno run npm:userbase copy-assets --out public
```
This will copy the static assets to the `public` directory and then serve them from there:
```ts title="main.ts"
import { createRuntimeApp, serveStatic } from "bknd/adapter";
import { createRuntimeApp, serveStatic } from "userbase/adapter";
import { serveStatic } from "npm:hono/deno";
const app = await createRuntimeApp({
@@ -124,7 +124,7 @@ export default {
You can also use the `adminOptions.assetsPath` property to point to a remote address with the static assets. This is useful in case none of the other methods work for you.
```ts title="main.ts"
import { createRuntimeApp } from "bknd/adapter";
import { createRuntimeApp } from "userbase/adapter";
const app = await createRuntimeApp({
connection: {
@@ -1,27 +1,27 @@
---
title: "Docker"
description: "Official docker image for bknd"
description: "Official docker image for userbase"
tags: ["documentation"]
---
# Official `bknd` Docker image
# Official `userbase` Docker image
The docker image intentially doesn't copy any data into the image for now, so you can copy the Dockerfile and build the image anywhere.
Locate the Dockerfile either by pulling the [repository](https://github.com/bknd-io/bknd) and navigating to the `docker` directory, or download from [here](https://github.com/bknd-io/bknd/blob/main/docker/Dockerfile).
Locate the Dockerfile either by pulling the [repository](https://github.com/userbase-io/userbase) and navigating to the `docker` directory, or download from [here](https://github.com/userbase-io/userbase/blob/main/docker/Dockerfile).
## Building the Docker image
To build the Docker image, run the following command:
```bash
docker build -t bknd .
docker build -t userbase .
```
If you want to override the bknd version used, you can pass a `VERSION` build argument:
If you want to override the userbase version used, you can pass a `VERSION` build argument:
```bash
docker build --build-arg VERSION=<version> -t bknd .
docker build --build-arg VERSION=<version> -t userbase .
```
## Running the Docker container
@@ -29,19 +29,19 @@ docker build --build-arg VERSION=<version> -t bknd .
To run the Docker container, run the following command:
```bash
docker run -p 1337:1337 bknd
docker run -p 1337:1337 userbase
```
You can pass the same CLI arguments (see [Using the CLI](https://docs.bknd.io/cli) guide) to the docker container as you'd do with `npx bknd run`, like so:
You can pass the same CLI arguments (see [Using the CLI](https://docs.userbase.io/cli) guide) to the docker container as you'd do with `npx userbase run`, like so:
```bash
docker run -p 1337:1337 -e ARGS="--db-url file:/data/data.db" bknd
docker run -p 1337:1337 -e ARGS="--db-url file:/data/data.db" userbase
```
To mount the data directory to the host, you can use the `-v` flag:
```bash
docker run -p 1337:1337 -v /path/to/data:/data bknd
docker run -p 1337:1337 -v /path/to/data:/data userbase
```
## Docker compose example
@@ -50,9 +50,9 @@ If you want to use docker compose and build the image directly from the git repo
```yaml title="compose.yml"
services:
bknd:
userbase:
pull_policy: build
build: https://github.com/bknd-io/bknd.git#main:docker
build: https://github.com/userbase-io/userbase.git#main:docker
ports:
- 1337:1337
environment:
@@ -61,20 +61,20 @@ services:
- ${DATA_DIR:-.}/data:/data
```
The docker compose file can be extended to build a specific version of bknd.
The docker compose file can be extended to build a specific version of userbase.
Extend the `build` section with `args` and `labels`.
Inside `args`, you can pass a `VERSION` build argument, and use `labels` so the built image receives a unique identifier.
```yaml title="compose.yml"
services:
bknd:
userbase:
pull_policy: build
build:
context: https://github.com/bknd-io/bknd.git#main:docker
context: https://github.com/userbase-io/userbase.git#main:docker
args:
VERSION: <version>
labels:
- x-bknd-version=<version>
- x-userbase-version=<version>
ports:
- 1337:1337
environment:
@@ -1,41 +1,41 @@
---
title: "Node"
description: "Run bknd inside Node"
description: "Run userbase inside Node"
tags: ["documentation"]
---
## Installation
To get started with Node and bknd you can either install the package manually, and follow the descriptions below, or use the CLI starter:
To get started with Node and userbase you can either install the package manually, and follow the descriptions below, or use the CLI starter:
### CLI Starter
Create a new Node CLI starter project by running the following command:
```sh
npx bknd create -i node
npx userbase create -i node
```
### Manual
Create a new Node project and then install bknd as a dependency:
Create a new Node project and then install userbase as a dependency:
<Tabs groupId='package-manager' persist items={[ 'npm', 'pnpm', 'yarn', 'bun']}>
```bash tab="npm"
npm install bknd
npm install userbase
```
```bash tab="pnpm"
pnpm install bknd
pnpm install userbase
```
```bash tab="yarn"
yarn add bknd
yarn add userbase
```
```bash tab="bun"
bun add bknd
bun add userbase
```
</Tabs>
@@ -46,10 +46,10 @@ The `serve` function of the Node adapter makes sure to also serve the static fil
the admin panel.
```tsx title="server.ts"
import { serve } from "bknd/adapter/node";
import { serve } from "userbase/adapter/node";
// if the configuration is omitted, it uses an in-memory database
/** @type {import("bknd/adapter/node").NodeAdapterOptions} */
/** @type {import("userbase/adapter/node").NodeAdapterOptions} */
const config = {
connection: {
url: "file:data.db",
@@ -1,6 +1,6 @@
---
title: "Introduction"
description: "Integrate bknd into your runtime/framework of choice"
description: "Integrate userbase into your runtime/framework of choice"
tags: ["documentation"]
---
@@ -8,7 +8,7 @@ import { Icon } from "@iconify/react";
## Start with a Framework
bknd seamlessly integrates with popular frameworks, allowing you to use what you're already familar with. The following guides will help you get started with your framework of choice.
userbase seamlessly integrates with popular frameworks, allowing you to use what you're already familar with. The following guides will help you get started with your framework of choice.
<Cards>
<Card icon={<Icon icon="tabler:brand-nextjs" className="text-fd-primary !size-6" />} title="NextJS" href="/integration/nextjs" />
@@ -51,7 +51,7 @@ bknd seamlessly integrates with popular frameworks, allowing you to use what you
href="/integration/solid-start"
/>
<Card title="Yours missing?" href="https://github.com/bknd-io/bknd/issues/new">
<Card title="Yours missing?" href="https://github.com/userbase-io/userbase/issues/new">
Create a new issue to request a guide for your framework.
</Card>
</Cards>
@@ -114,7 +114,7 @@ If you prefer to use a runtime instead of a framework, you can choose from the f
href="/integration/docker"
/>
<Card title="Yours missing?" href="https://github.com/bknd-io/bknd/issues/new">
<Card title="Yours missing?" href="https://github.com/userbase-io/userbase/issues/new">
Create a new issue to request a guide for your runtime.
</Card>
</Cards>
@@ -128,7 +128,7 @@ Serve the backend as an API for any JS runtime or framework. The latter is espec
Here is an example of serving the API using node:
```js title="index.js"
import { serve } from "bknd/adapter/node";
import { serve } from "userbase/adapter/node";
serve();
```
@@ -137,8 +137,8 @@ serve();
The admin UI allows to manage your data including full configuration of your backend using a graphical user interface. Using `vite`, your admin route looks like this:
```tsx title="admin.tsx"
import { Admin } from "bknd/ui";
import "bknd/dist/styles.css";
import { Admin } from "userbase/ui";
import "userbase/dist/styles.css";
export default function AdminPage() {
return <Admin withProvider />;
@@ -6,11 +6,11 @@ tags: ["documentation"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
Authentication is essential for securing applications, and **bknd** provides a straightforward approach to implementing robust strategies.
Authentication is essential for securing applications, and **userbase** provides a straightforward approach to implementing robust strategies.
### **Core Features**
@@ -26,7 +26,7 @@ Authentication is essential for securing applications, and **bknd** provides a s
- **OAuth/OIDC**: Works with providers like Google and GitHub.
- Compatible with any specification-compliant provider.
With a focus on flexibility and ease of integration, bknd's authentication system offers the essentials for managing secure user access in your applications.
With a focus on flexibility and ease of integration, userbase's authentication system offers the essentials for managing secure user access in your applications.
---
@@ -88,8 +88,8 @@ Complete these steps **in order** before turning on the Guard:
If you enabled the Guard without setting up an admin user, you'll need to access your database directly:
1. Connect to your database using a database client or CLI tool
2. Find the `__bknd` table
2. Find the `__userbase` table
3. Locate the row where `type = 'config'`
4. In the `json` column, set `auth.guard.enabled` to `false`
5. Restart your bknd instance
5. Restart your userbase instance
6. Complete the checklist above, then re-enable the Guard
@@ -6,11 +6,11 @@ tags: ["documentation"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
Data is the lifeblood of any application, and **bknd** provides the tools to handle it effortlessly. From defining entities to executing complex queries, bknd offers a developer-friendly, intuitive, and powerful data management experience.
Data is the lifeblood of any application, and **userbase** provides the tools to handle it effortlessly. From defining entities to executing complex queries, userbase offers a developer-friendly, intuitive, and powerful data management experience.
### **Define Your Data**
@@ -49,5 +49,5 @@ Hook into critical lifecycle events for fine-grained control:
The **Connection** class communicates with the database. It's based on kysely, so that it
generally supports multiple database dialects (but currently only SQLite/LibSQL is supported).
Whether you're modeling simple data structures or managing complex relationships, bknd's data tools empower you to build applications with confidence and scalability.
Whether you're modeling simple data structures or managing complex relationships, userbase's data tools empower you to build applications with confidence and scalability.
@@ -10,7 +10,7 @@ tags: ["documentation"]
be available very soon.
</Callout>
**bknd** enables you to automate tasks and processes through flexible and powerful workflows.
**userbase** enables you to automate tasks and processes through flexible and powerful workflows.
## **Core Features**
@@ -6,11 +6,11 @@ tags: ["documentation"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
**bknd** provides a flexible and efficient way to handle media files, making it easy to upload, manage, and deliver content across various platforms.
**userbase** provides a flexible and efficient way to handle media files, making it easy to upload, manage, and deliver content across various platforms.
### **Core Features**
@@ -27,11 +27,11 @@ and control without added complexity.
### Pre-built support for S3
There are two ways to enable S3 or S3 compatible storage in bknd.
There are two ways to enable S3 or S3 compatible storage in userbase.
1. Enable via the admin UI.
Simply navigate to the **Media** tab of the bknd admin UI and enable the S3 media support.
Simply navigate to the **Media** tab of the userbase admin UI and enable the S3 media support.
Enter your AWS S3-compatible storage Access Key, Secret Access Key, and URL.
This will automatically configure the S3 adapter for you.
@@ -42,10 +42,10 @@ There are two ways to enable S3 or S3 compatible storage in bknd.
2. Enable programmatically.
To enable using a code-first approach, create corresponding configuration using the `config` option in your `bknd.config.ts` file.
To enable using a code-first approach, create corresponding configuration using the `config` option in your `userbase.config.ts` file.
```typescript title="bknd.config.ts"
import type { BkndConfig } from "bknd/adapter";
```typescript title="userbase.config.ts"
import type { UserbaseConfig } from "userbase/adapter";
export default {
config: {
@@ -61,16 +61,16 @@ export default {
},
},
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
### Local adapter for development
For local development and testing, you can use the local file system adapter. This is particularly useful when working with Node.js environments.
```typescript title="bknd.config.ts"
import { registerLocalMediaAdapter } from "bknd/adapter/node";
import type { BkndConfig } from "bknd/adapter";
```typescript title="userbase.config.ts"
import { registerLocalMediaAdapter } from "userbase/adapter/node";
import type { UserbaseConfig } from "userbase/adapter";
// Register the local media adapter
const local = registerLocalMediaAdapter();
@@ -84,7 +84,7 @@ export default {
}),
},
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
This configuration will store uploaded files in the specified directory,
@@ -8,7 +8,7 @@ import { Icon } from "@iconify/react";
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
@@ -6,6 +6,6 @@ tags: ["documentation"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
@@ -26,7 +26,7 @@ As the developer of a backend system, you must make tough decisions, one of whic
But isn't the database known to be the hardest part to scale? Isn't more logic moving to the application layer? Haven't NoSQL databases proven this? If you're like me, you may have dipped your toes into the NoSQL world only to quickly return to SQL. SQL is known, predictable, and safe. But what if we could have both? NoSQL offers flexibility and scalability, yet querying it is tedious due to vendor-specific implementations.
To get the best of both worlds, bknd focuses on the weakest SQL database (SQLite), treating it as a data store and query interface. Schema details and enforcement are moved to the application layer, making it easy to adjust a default value or property length. The added benefit is that any SQL database could theoretically work the same way, and since it's all TypeScript, the same validation logic can be used on both the client and server sides–you can validate your data before it even reaches your server. It even works without database-enforced referential integrity, as the integrity checks occur on the application layer. This opens the door to NewSQL systems like PlanetScale.
To get the best of both worlds, userbase focuses on the weakest SQL database (SQLite), treating it as a data store and query interface. Schema details and enforcement are moved to the application layer, making it easy to adjust a default value or property length. The added benefit is that any SQL database could theoretically work the same way, and since it's all TypeScript, the same validation logic can be used on both the client and server sides–you can validate your data before it even reaches your server. It even works without database-enforced referential integrity, as the integrity checks occur on the application layer. This opens the door to NewSQL systems like PlanetScale.
## Environment and framework lock-in
@@ -34,7 +34,7 @@ There are backend systems that embed themselves into a specific React framework.
Alternatively, you could develop for the weakest environment (workerd) by strictly using Web APIs, avoiding shortcuts, and implementing certain logic manually because the go-to package is using Node APIs. This isn't always fun, but it's essential. The benefit? It works anywhere JavaScript does.
bknd is the only backend system that not only works with any JavaScript framework but also integrates directly into it. It runs within the framework, enabling a single deployment for your entire app.
userbase is the only backend system that not only works with any JavaScript framework but also integrates directly into it. It runs within the framework, enabling a single deployment for your entire app.
_"But isn't it ironic that it forces a JavaScript environment?"_ you might ask. And you're right, but it also allows running standalone via CLI or Docker.
@@ -44,14 +44,14 @@ One of the biggest frustrations I've encountered is when software vendors choose
The issue is that users may rely on HTTP clients that offer built-in authentication methods, which won't include your custom solution. Custom `SearchParams` implementations might be convenient, but translating them across different environments and languages can be challenging without trial and error.
bknd strives to adhere to web standards as much as possible while offering handy alternatives. Here's an example of the `select` search parameter for retrieving a list of entities:
userbase strives to adhere to web standards as much as possible while offering handy alternatives. Here's an example of the `select` search parameter for retrieving a list of entities:
```bash
/api/data/todos?select=id&select=name # web standard
/api/data/todos?select=id,name # handy alternative
```
If you ever find an instance where bknd isn't adhering to standards or could be improved, please feel free to [file an issue](https://github.com/bknd-io/bknd/issues/new). Your feedback is greatly appreciated!
If you ever find an instance where userbase isn't adhering to standards or could be improved, please feel free to [file an issue](https://github.com/userbase-io/userbase/issues/new). Your feedback is greatly appreciated!
## Wrong-for-your-use-case implementations
@@ -66,10 +66,10 @@ Since it's impossible to satisfy all requirements, why implement them at all? _"
Additional security measures, such as short-lived tokens, can be added, but the concept remains simple.
Instead of hardcoding such features, bknd offers a powerful event system that supports asynchronous (like webhooks) and synchronous execution, blocking further actions if needed. With integrated workflows (UI coming soon), you can listen to and react to system events, and even map them to endpoints. Since workflows, like everything else in bknd, are JSON-serializable, they're easy to export and import.
Instead of hardcoding such features, userbase offers a powerful event system that supports asynchronous (like webhooks) and synchronous execution, blocking further actions if needed. With integrated workflows (UI coming soon), you can listen to and react to system events, and even map them to endpoints. Since workflows, like everything else in userbase, are JSON-serializable, they're easy to export and import.
## Complex self-hosting
Finally, hosting. It's a business advantage if your system is highly sought after but difficult to self-host, forcing users to opt for your cloud service. The truth is, if it's hard for users, it's also hard for the vendor, which drives up costs.
If you know how to deploy your Next.js, Remix, or Astro application, you can deploy bknd. It's straightforward to deploy using Cloudflare Workers/Pages or with just 28 lines of a Dockerfile. No PhD required.
If you know how to deploy your Next.js, Remix, or Astro application, you can deploy userbase. It's straightforward to deploy using Cloudflare Workers/Pages or with just 28 lines of a Dockerfile. No PhD required.
+18 -18
View File
@@ -8,21 +8,21 @@ import { Icon } from "@iconify/react";
import { examples } from "@/app/_components/StackBlitz";
import { SquareMousePointer, Code, Blend, Rocket } from 'lucide-react';
## bknd is a lightweight batteries-included backend that embeds into your frontend app
## userbase is a lightweight batteries-included backend that embeds into your frontend app
<Callout type="warning" title="We are in beta">
We're making great progress towards v1, but don't recommend production use yet.
Follow along for updates on [GitHub Releases](https://github.com/bknd-io/bknd/releases) and in our [Discord community](https://discord.gg/952SFk8Tb8)
Follow along for updates on [GitHub Releases](https://github.com/userbase-io/userbase/releases) and in our [Discord community](https://discord.gg/952SFk8Tb8)
</Callout>
bknd includes full REST APIs, an admin dashboard, auth, media uploads, a [type-safe SDK](/usage/sdk), [React hooks](/usage/react), and plugins to extend it. Host it with your SSR app or as a standalone service. Built on Web Standards, it runs anywhere JavaScript runs.
userbase includes full REST APIs, an admin dashboard, auth, media uploads, a [type-safe SDK](/usage/sdk), [React hooks](/usage/react), and plugins to extend it. Host it with your SSR app or as a standalone service. Built on Web Standards, it runs anywhere JavaScript runs.
Bring your [favorite frontend](./#start-with-a-frameworkruntime) and [favorite SQL database](./#use-your-favorite-sql-database), and we'll bring the ~~backend~~ bknd.
Bring your [favorite frontend](./#start-with-a-frameworkruntime) and [favorite SQL database](./#use-your-favorite-sql-database), and we'll bring the ~~backend~~ userbase.
<Cards>
<Card
href="/motivation"
title="Learn about why we built bknd"
title="Learn about why we built userbase"
icon={<Rocket />}
>
Why another backend system?
@@ -31,27 +31,27 @@ Bring your [favorite frontend](./#start-with-a-frameworkruntime) and [favorite S
## Quickstart
<Callout type="info" title="This demo bknd instance is for playing and learning">
Don't worry about messing anything up in this stage since you're learning the ropes of bknd. If you want to start over, please delete the generated `data.db` database file and follow this tutorial again.
<Callout type="info" title="This demo userbase instance is for playing and learning">
Don't worry about messing anything up in this stage since you're learning the ropes of userbase. If you want to start over, please delete the generated `data.db` database file and follow this tutorial again.
</Callout>
Spin up a bknd instance via the [bknd CLI](/usage/cli):
Spin up a userbase instance via the [userbase CLI](/usage/cli):
<Tabs groupId='package-manager' persist items={[ 'npm','bun' ]}>
```bash tab="npm"
npx bknd run
npx userbase run
```
```bash tab="bun"
bunx bknd run
bunx userbase run
```
</Tabs>
This creates a local `data.db` SQLite database and starts the bknd web server at http://localhost:1337.
This creates a local `data.db` SQLite database and starts the userbase web server at http://localhost:1337.
By default, the admin dashboard is open and not guarded. This is intentional — bknd uses an opt-in philosophy to allow quick prototyping. Let's enable authentication and guard the dashboard to secure it.
By default, the admin dashboard is open and not guarded. This is intentional — userbase uses an opt-in philosophy to allow quick prototyping. Let's enable authentication and guard the dashboard to secure it.
1. Visit http://localhost:1337/auth/settings. Toggle "Authentication Enabled" to enable auth. Select "Update" to save.
2. Visit http://localhost:1337/data/entity/users. Create a user by selecting "New User" and entering an email and password.
@@ -60,11 +60,11 @@ By default, the admin dashboard is open and not guarded. This is intentional —
5. It's time to guard your admin dashboard. Visit http://localhost:1337/settings/auth. Select "Edit". Scroll to "Guard" and enable it. Then, select "Save". _(This should log you out!)_
6. Now, log in to your secured admin dashboard at http://localhost:1337/auth/login.
You did it! You've started the bknd server, created an admin user, and protected your app by enabling the guard.
You did it! You've started the userbase server, created an admin user, and protected your app by enabling the guard.
## Modes
What you just experienced is **UI-only mode** — bknd's data and configuration is managed entirely via the admin dashboard. But that's not the only way to use bknd:
What you just experienced is **UI-only mode** — userbase's data and configuration is managed entirely via the admin dashboard. But that's not the only way to use userbase:
<Cards className="grid-cols-3">
<Card title="UI-only" href="/usage/setup#ui-only-mode" icon={<SquareMousePointer className="text-fd-primary !size-6" />}>
@@ -80,10 +80,10 @@ What you just experienced is **UI-only mode** — bknd's data and configuration
Learn more about each mode and the underlying configuration in [Setup & Modes](/usage/setup).
## Try bknd in the browser
## Try userbase in the browser
<Card className="p-0 pb-1">
<StackBlitz path="github/bknd-io/bknd-demo" initialPath="/" />
<StackBlitz path="github/userbase-io/userbase-demo" initialPath="/" />
<Accordions className="m-1">
<Accordion title="What's going on?">
The example shown is starting a [node server](/integration/node) using an [in-memory database](/usage/database#sqlite-in-memory). To ensure there are a few entities defined, it is using an [initial structure](/usage/database#initial-structure) using the prototype methods. Furthermore it uses the [seed option](/usage/database#seeding-the-database) to seed some data in the structure created.
@@ -191,7 +191,7 @@ Pick your framework or runtime to get started.
href="/integration/docker"
/>
<Card title="Yours missing?" href="https://github.com/bknd-io/bknd/issues/new">
<Card title="Yours missing?" href="https://github.com/userbase-io/userbase/issues/new">
Create a new issue to request a guide for your runtime or framework.
</Card>
</Cards>
@@ -228,7 +228,7 @@ The following databases are currently supported. Request a new integration if yo
href="/usage/database#cloudflare-d1"
/>
<Card title="Yours missing?" href="https://github.com/bknd-io/bknd/issues/new">
<Card title="Yours missing?" href="https://github.com/userbase-io/userbase/issues/new">
Create a new issue to request a new database integration.
</Card>
</Cards>
+49 -49
View File
@@ -1,21 +1,21 @@
---
title: "Using the CLI"
description: "How to start a bknd instance using the CLI."
description: "How to start a userbase instance using the CLI."
icon: Terminal
tags: ["documentation"]
---
The bknd package includes a command-line interface (CLI) that allows you to run a bknd instance and perform various tasks.
The userbase package includes a command-line interface (CLI) that allows you to run a userbase instance and perform various tasks.
```sh
npx bknd
npx userbase
```
Here is the output:
```sh
$ npx bknd
Usage: bknd [options] [command]
$ npx userbase
Usage: userbase [options] [command]
Options:
-V, --version output the version number
@@ -25,7 +25,7 @@ Commands:
config [options] get app config
copy-assets [options] copy static assets
create [options] create a new project
debug <subject> debug bknd
debug <subject> debug userbase
mcp [options] mcp server stdio transport
run [options] run an instance
schema [options] get schema
@@ -37,11 +37,11 @@ Commands:
## Starting an instance (`run`)
To see all available `run` options, execute `npx bknd run --help`.
To see all available `run` options, execute `npx userbase run --help`.
```sh
$ npx bknd run --help
Usage: bknd run [options]
$ npx userbase run --help
Usage: userbase run [options]
Options:
-p, --port <port> port to run on (default: 1337, env: PORT)
@@ -57,7 +57,7 @@ Options:
To order in which the connection is determined is as follows:
1. `--db-url`
2. `--config` or reading the filesystem looking for `bknd.config.[js|ts|mjs|cjs|json]`
2. `--config` or reading the filesystem looking for `userbase.config.[js|ts|mjs|cjs|json]`
3. `--memory`
4. Environment variables `DB_URL` and `DB_TOKEN` in `.env` or `.dev.vars`
5. Fallback to file-based database `data.db`
@@ -67,17 +67,17 @@ To order in which the connection is determined is as follows:
By default, a file-based database `data.db` is used when running without any arguments. You can specify a different file name or path using the `--db-url` option. The database file will be created in the current working directory if it does not exist.
```
npx bknd run --db-url file:data.db
npx userbase run --db-url file:data.db
```
### Using configuration file (`bknd.config.*`)
### Using configuration file (`userbase.config.*`)
You can create a configuration file on the working directory that automatically gets picked up: `bknd.config.[js|ts|mjs|cjs|json]`
You can create a configuration file on the working directory that automatically gets picked up: `userbase.config.[js|ts|mjs|cjs|json]`
Here is an example of a `bknd.config.ts` file:
Here is an example of a `userbase.config.ts` file:
```ts
import type { BkndConfig } from "bknd/adapter";
import type { UserbaseConfig } from "userbase/adapter";
export default {
// you can either specify the connection directly
@@ -90,16 +90,16 @@ export default {
url: env.DB_URL,
},
}),
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
The `app` function is useful if you need a cross-platform way to access the environment variables. For example, on Cloudflare Workers, you can only access environment variables inside a request handler. If you're exclusively using a node-like environment, it's safe to access the environment variables directly from `process.env`.
If you're using `npx bknd run`, make sure to create a file in a file format that `node` can load, otherwise you may run into an error that the file couldn't be found:
If you're using `npx userbase run`, make sure to create a file in a file format that `node` can load, otherwise you may run into an error that the file couldn't be found:
```
[INF] 2025-03-28 18:02:21 Using config from bknd.config.ts
[ERR] 2025-03-28 18:02:21 Failed to load config: Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'bknd.config.ts' imported from [...]
[INF] 2025-03-28 18:02:21 Using config from userbase.config.ts
[ERR] 2025-03-28 18:02:21 Failed to load config: Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'userbase.config.ts' imported from [...]
at packageResolve (node:internal/modules/esm/resolve:857:9)
at [...] {
code: 'ERR_MODULE_NOT_FOUND'
@@ -109,13 +109,13 @@ If you're using `npx bknd run`, make sure to create a file in a file format that
If you still want to use a `.ts` extension, you can start the CLI e.g. using `node` (>=v22.6.0):
```sh
node --experimental-strip-types node_modules/.bin/bknd run
node --experimental-strip-types node_modules/.bin/userbase run
```
Or with `tsx`:
```sh
npx tsx node_modules/.bin/bknd run
npx tsx node_modules/.bin/userbase run
```
### Turso/LibSQL database
@@ -123,7 +123,7 @@ npx tsx node_modules/.bin/bknd run
To start an instance with a Turso/LibSQL database, run the following:
```sh
npx bknd run --db-url libsql://your-db.turso.io --db-token <your-token>
npx userbase run --db-url libsql://your-db.turso.io --db-token <your-token>
```
The `--db-token` option is optional and only required if the database is protected.
@@ -133,23 +133,23 @@ The `--db-token` option is optional and only required if the database is protect
To start an instance with an ephemeral in-memory database, run the following:
```sh
npx bknd run --memory
npx userbase run --memory
```
Keep in mind that the database is not persisted and will be lost when the process is terminated.
## Generating types (`types`)
To see all available `types` options, execute `npx bknd types --help`.
To see all available `types` options, execute `npx userbase types --help`.
```sh
$ npx bknd types --help
Usage: bknd types [options]
$ npx userbase types --help
Usage: userbase types [options]
generate types
Options:
-o, --outfile <outfile> output file (default: "bknd-types.d.ts")
-o, --outfile <outfile> output file (default: "userbase-types.d.ts")
--no-write do not write to file
-h, --help display help for command
```
@@ -157,19 +157,19 @@ Options:
To generate types for the database, run the following:
```sh
npx bknd types
npx userbase types
```
This will generate types for your database schema in `bknd-types.d.ts`. The generated file could look like this:
This will generate types for your database schema in `userbase-types.d.ts`. The generated file could look like this:
```typescript title="bknd-types.d.ts"
import type { DB } from "bknd";
```typescript title="userbase-types.d.ts"
import type { DB } from "userbase";
import type { Insertable, Selectable, Updateable, Generated } from "kysely";
declare global {
type BkndEntity<T extends keyof DB> = Selectable<DB[T]>;
type BkndEntityCreate<T extends keyof DB> = Insertable<DB[T]>;
type BkndEntityUpdate<T extends keyof DB> = Updateable<DB[T]>;
type UserbaseEntity<T extends keyof DB> = Selectable<DB[T]>;
type UserbaseEntityCreate<T extends keyof DB> = Insertable<DB[T]>;
type UserbaseEntityUpdate<T extends keyof DB> = Updateable<DB[T]>;
}
export interface Todos {
@@ -182,7 +182,7 @@ interface Database {
todos: Todos;
}
declare module "bknd" {
declare module "userbase" {
interface DB extends Database {}
}
```
@@ -191,27 +191,27 @@ Make sure to add the generated file in your `tsconfig.json` file:
```json title="tsconfig.json"
{
"include": ["bknd-types.d.ts"]
"include": ["userbase-types.d.ts"]
}
```
You can then use the types by importing them from `bknd`:
You can then use the types by importing them from `userbase`:
```typescript
import type { DB } from "bknd";
import type { DB } from "userbase";
type Todo = DB["todos"];
```
All bknd methods that involve your database schema will be automatically typed. You may use the [`syncTypes`](/extending/plugins/#synctypes) plugin to automatically write the types to a file.
All userbase methods that involve your database schema will be automatically typed. You may use the [`syncTypes`](/extending/plugins/#synctypes) plugin to automatically write the types to a file.
## Getting the configuration (`config`)
To see all available `config` options, execute `npx bknd config --help`.
To see all available `config` options, execute `npx userbase config --help`.
```sh
$ npx bknd config --help
Usage: bknd config [options]
$ npx userbase config --help
Usage: userbase config [options]
get app config
@@ -228,24 +228,24 @@ Options:
To get the configuration of your app, and to write it to a file, run the following:
```sh
npx bknd config --out appconfig.json
npx userbase config --out appconfig.json
```
To get a template configuration instead, run the following:
```sh
npx bknd config --default
npx userbase config --default
```
To automatically sync your configuration to a file, you may also use the [`syncConfig`](/extending/plugins/#syncconfig) plugin.
## Getting the secrets (`secrets`)
To see all available `secrets` options, execute `npx bknd secrets --help`.
To see all available `secrets` options, execute `npx userbase secrets --help`.
```sh
$ npx bknd secrets --help
Usage: bknd secrets [options]
$ npx userbase secrets --help
Usage: userbase secrets [options]
get app secrets
@@ -266,8 +266,8 @@ To automatically sync your secrets to a file, you may also use the [`syncSecrets
Sync your database can be useful when running in [`code`](/usage/setup/#code-only-mode) mode. When you're ready to deploy, you can point to the production configuration and sync the database. Schema mutations are only applied when running with the `--force` option.
```bash
$ npx bknd sync --help
Usage: bknd sync [options]
$ npx userbase sync --help
Usage: userbase sync [options]
sync database
@@ -5,7 +5,7 @@ icon: Database
tags: ["documentation"]
---
In order to use **bknd**, you need to prepare access information to your database and potentially install additional dependencies. Connections to the database are managed using Kysely. Therefore, all [its dialects](https://kysely.dev/docs/dialects) are theoretically supported.
In order to use **userbase**, you need to prepare access information to your database and potentially install additional dependencies. Connections to the database are managed using Kysely. Therefore, all [its dialects](https://kysely.dev/docs/dialects) are theoretically supported.
Currently supported and tested databases are:
@@ -13,7 +13,7 @@ Currently supported and tested databases are:
- SQLite (remote): Turso, Cloudflare D1
- Postgres: Vanilla Postgres, Supabase, Neon, Xata
By default, bknd will try to use a SQLite database in-memory. Depending on your runtime, a different SQLite implementation will be used.
By default, userbase will try to use a SQLite database in-memory. Depending on your runtime, a different SQLite implementation will be used.
## Defining the connection
@@ -21,13 +21,13 @@ There are mainly 3 ways to define the connection to your database, when
1. creating an app using `App.create()` or `createApp()`
2. creating an app using a [Framework or Runtime adapter](/integration/introduction)
3. starting a quick instance using the [CLI](/usage/cli#using-configuration-file-bknd-config)
3. starting a quick instance using the [CLI](/usage/cli#using-configuration-file-userbase-config)
When creating an app using `App.create()` or `createApp()`, you can pass a connection object in the configuration object.
```typescript title="app.ts"
import { createApp } from "bknd";
import { sqlite } from "bknd/adapter/sqlite";
import { createApp } from "userbase";
import { sqlite } from "userbase/adapter/sqlite";
// a connection is required when creating an app like this
const app = createApp({
@@ -35,10 +35,10 @@ const app = createApp({
});
```
When using an adapter, or using the CLI, bknd will automatically try to use a SQLite implementation depending on the runtime:
When using an adapter, or using the CLI, userbase will automatically try to use a SQLite implementation depending on the runtime:
```javascript title="app.js"
import { serve } from "bknd/adapter/node";
import { serve } from "userbase/adapter/node";
serve({
// connection is optional, but recommended
@@ -49,25 +49,25 @@ serve({
You can also pass a connection instance to the `connection` property to explictly use a specific connection.
```javascript title="app.js"
import { serve } from "bknd/adapter/node";
import { sqlite } from "bknd/adapter/sqlite";
import { serve } from "userbase/adapter/node";
import { sqlite } from "userbase/adapter/sqlite";
serve({
connection: sqlite({ url: "file:data.db" }),
});
```
If you're using [`bknd.config.*`](/extending/config), you can specify the connection on the exported object.
If you're using [`userbase.config.*`](/extending/config), you can specify the connection on the exported object.
```typescript title="bknd.config.ts"
import type { BkndConfig } from "bknd";
```typescript title="userbase.config.ts"
import type { UserbaseConfig } from "userbase";
export default {
connection: { url: "file:data.db" },
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
Throughout the documentation, it is assumed you use `bknd.config.ts` to define your connection.
Throughout the documentation, it is assumed you use `userbase.config.ts` to define your connection.
## SQLite
@@ -89,30 +89,30 @@ The `sqlite` adapter is automatically resolved based on the runtime.
The bundled version of the `libsql` connection only works with remote databases. However, you can pass in a `Client` from `@libsql/client`, see [LibSQL](#libsql) for more details.
```typescript title="bknd.config.ts"
import type { BkndConfig } from "bknd";
```typescript title="userbase.config.ts"
import type { UserbaseConfig } from "userbase";
// no connection is required, bknd will use a SQLite database in-memory
// no connection is required, userbase will use a SQLite database in-memory
// this does not work on edge environments!
export default {} satisfies BkndConfig;
export default {} satisfies UserbaseConfig;
// or explicitly in-memory
export default {
connection: { url: ":memory:" },
} satisfies BkndConfig;
} satisfies UserbaseConfig;
// or explicitly as a file
export default {
connection: { url: "file:<path/to/your/database.db>" },
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
### Node.js SQLite
To use the Node.js SQLite adapter directly, use the `nodeSqlite` function as value for the `connection` property. This lets you customize the database connection, such as enabling WAL mode.
```typescript title="bknd.config.ts"
import { nodeSqlite, type NodeBkndConfig } from "bknd/adapter/node";
```typescript title="userbase.config.ts"
import { nodeSqlite, type NodeUserbaseConfig } from "userbase/adapter/node";
export default {
connection: nodeSqlite({
@@ -121,15 +121,15 @@ export default {
db.exec("PRAGMA journal_mode = WAL;");
},
}),
} satisfies NodeBkndConfig;
} satisfies NodeUserbaseConfig;
```
### Bun SQLite
You can explicitly use the Bun SQLite adapter by passing the `bunSqlite` function to the `connection` property. This allows further configuration of the database, e.g. enabling WAL mode.
```typescript title="bknd.config.ts"
import { bunSqlite, type BunBkndConfig } from "bknd/adapter/bun";
```typescript title="userbase.config.ts"
import { bunSqlite, type BunUserbaseConfig } from "userbase/adapter/bun";
export default {
connection: bunSqlite({
@@ -138,28 +138,28 @@ export default {
db.run("PRAGMA journal_mode = WAL;");
},
}),
} satisfies BunBkndConfig;
} satisfies BunUserbaseConfig;
```
### LibSQL
Turso offers a SQLite-fork called LibSQL that runs a server around your SQLite database. The edge-version of the adapter is included in the bundle (remote only):
```typescript title="bknd.config.ts"
import { libsql, type BkndConfig } from "bknd";
```typescript title="userbase.config.ts"
import { libsql, type UserbaseConfig } from "userbase";
export default {
connection: libsql({
url: "libsql://<database>.turso.io",
authToken: "<auth-token>",
}),
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
If you wish to use LibSQL as file, in-memory or make use of [Embedded Replicas](https://docs.turso.tech/features/embedded-replicas/introduction), you have to pass in the `Client` from `@libsql/client`:
```typescript title="bknd.config.ts"
import { libsql, type BkndConfig } from "bknd";
```typescript title="userbase.config.ts"
import { libsql, type UserbaseConfig } from "userbase";
import { createClient } from "@libsql/client";
const client = createClient({
@@ -169,7 +169,7 @@ const client = createClient({
export default {
connection: libsql(client),
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
### Cloudflare D1
@@ -179,7 +179,7 @@ Using the [Cloudflare Adapter](/integration/cloudflare), you can choose to use a
To manually specify which D1 database to take, you can specify it explicitly:
```ts
import { serve, d1 } from "bknd/adapter/cloudflare";
import { serve, d1 } from "userbase/adapter/cloudflare";
export default serve<Env>({
app: (env) => d1({ binding: env.D1_BINDING }),
@@ -188,7 +188,7 @@ export default serve<Env>({
### SQLocal
To use bknd with `sqlocal` for a offline expierence, you need to install the `sqlocal` package. You can do so by running the following command:
To use userbase with `sqlocal` for a offline expierence, you need to install the `sqlocal` package. You can do so by running the following command:
```bash
npm install sqlocal
@@ -197,7 +197,7 @@ npm install sqlocal
Consult the [sqlocal documentation](https://sqlocal.dallashoffman.com/guide/setup) for connection options:
```ts
import { createApp, sqlocal } from "bknd";
import { createApp, sqlocal } from "userbase";
import { SQLocalKysely } from "sqlocal/kysely";
const app = createApp({
@@ -207,15 +207,15 @@ const app = createApp({
## PostgreSQL
Postgres is built-in to bknd, you can connect to your Postgres database using `pg` or `postgres` dialects. Additionally, you may also define your custom connection.
Postgres is built-in to userbase, you can connect to your Postgres database using `pg` or `postgres` dialects. Additionally, you may also define your custom connection.
### Using `pg`
To establish a connection to your database, you can use any connection options available on the [`pg`](https://node-postgres.com/apis/client) package. Wrap the `Pool` in the `pg` function to create a connection.
```ts
import { serve } from "bknd/adapter/node";
import { pg } from "bknd";
import { serve } from "userbase/adapter/node";
import { pg } from "userbase";
import { Pool } from "pg";
serve({
@@ -232,8 +232,8 @@ serve({
To establish a connection to your database, you can use any connection options available on the [`postgres`](https://github.com/porsager/postgres) package. Wrap the `Sql` in the `postgresJs` function to create a connection.
```ts
import { serve } from "bknd/adapter/node";
import { postgresJs } from "bknd";
import { serve } from "userbase/adapter/node";
import { postgresJs } from "userbase";
import postgres from 'postgres'
serve({
@@ -250,7 +250,7 @@ Several Postgres hosting providers offer their own clients to connect to their d
Example using `@neondatabase/serverless`:
```ts
import { createCustomPostgresConnection } from "bknd";
import { createCustomPostgresConnection } from "userbase";
import { NeonDialect } from "kysely-neon";
const neon = createCustomPostgresConnection("neon", NeonDialect);
@@ -265,7 +265,7 @@ serve({
Example using `@xata.io/client`:
```ts
import { createCustomPostgresConnection } from "bknd";
import { createCustomPostgresConnection } from "userbase";
import { XataDialect } from "@xata.io/kysely";
import { buildClient } from "@xata.io/client";
@@ -292,7 +292,7 @@ serve({
Creating a custom connection is as easy as extending the `Connection` class and passing constructing a Kysely instance.
```ts
import { createApp, Connection } from "bknd";
import { createApp, Connection } from "userbase";
import { Kysely } from "kysely";
class CustomConnection extends Connection {
@@ -315,7 +315,7 @@ To provide a database structure, you can pass `config` to the creation of an app
Here is a quick example:
```typescript
import { createApp, em, entity, text, number } from "bknd";
import { createApp, em, entity, text, number } from "userbase";
const schema = em(
{
@@ -382,7 +382,7 @@ You can add additional fields to these entities. System-defined fields don't hav
If you'd like to connect your entities to system entities, you need them in the schema to access their reference when making relations. From the example above, if you'd like to connect the `posts` entity to the `users` entity, you can do so like this:
```typescript
import { em, entity, text, number, systemEntity } from "bknd";
import { em, entity, text, number, systemEntity } from "userbase";
const schema = em(
{
@@ -419,7 +419,7 @@ If media is enabled, you can upload media directly or associate it with an entit
3. specify the mapped field name by using the `mappedBy` option
```typescript
import { em, entity, text, number, systemEntity, medium, media } from "bknd";
import { em, entity, text, number, systemEntity, medium, media } from "userbase";
const schema = em(
{
@@ -463,16 +463,16 @@ To get type completion, there are two options:
1. Use the CLI to [generate the types](/usage/cli#generating-types-types) (recommended)
2. If you have an initial structure created with the prototype functions, you can extend the `DB` interface with your own schema.
All entity related functions use the types defined in `DB` from `bknd`. To get type completion, you can extend that interface with your own schema:
All entity related functions use the types defined in `DB` from `userbase`. To get type completion, you can extend that interface with your own schema:
```typescript
import { em } from "bknd";
import { Api } from "bknd/client";
import { em } from "userbase";
import { Api } from "userbase/client";
const schema = em({ /* ... */ });
type Database = (typeof schema)["DB"];
declare module "bknd" {
declare module "userbase" {
interface DB extends Database {}
}
@@ -490,7 +490,7 @@ provides the `ModuleBuildContext` as the first argument.
```typescript
import { createApp, type ModuleBuildContext } from "bknd";
import { createApp, type ModuleBuildContext } from "userbase";
const app = createApp({
connection: { /* ... */ },
@@ -511,7 +511,7 @@ Note that in [`db` mode](/usage/setup#ui-only-mode), the seed function will only
In [`code` mode](/usage/setup#code-only-mode), the seed function will not be automatically executed. You can manually execute it by running the following command:
```bash
npx bknd sync --seed --force
npx userbase sync --seed --force
```
See the [sync command](/usage/cli#syncing-the-database-sync) documentation for more details.
@@ -5,7 +5,7 @@ icon: Box
tags: ["documentation"]
---
Not only creating and maintaing a backend is time-consuming, but also integrating it into your frontend can be a hassle. With `bknd/elements`, you can easily add media uploads and authentication forms to your app without having to figure out API details.
Not only creating and maintaing a backend is time-consuming, but also integrating it into your frontend can be a hassle. With `userbase/elements`, you can easily add media uploads and authentication forms to your app without having to figure out API details.
<Callout type="info">
In order to use these exported elements, make sure to wrap your app inside
@@ -17,10 +17,10 @@ Not only creating and maintaing a backend is time-consuming, but also integratin
### Media.Dropzone
The `Media.Dropzone` element allows retrieving from and uploading media items to your bknd instance. Without any properties specified, it will behave similar to your media library inside the bknd Admin UI. Here is how to get the last 10 items:
The `Media.Dropzone` element allows retrieving from and uploading media items to your userbase instance. Without any properties specified, it will behave similar to your media library inside the userbase Admin UI. Here is how to get the last 10 items:
```tsx
import { Media } from "bknd/elements";
import { Media } from "userbase/elements";
export default function MediaGallery() {
return <Media.Dropzone query={{ limit: 10, sort: "-id" }} />;
@@ -30,7 +30,7 @@ export default function MediaGallery() {
Since you can also upload media to a specific entity, you can also point that `Dropzone` to it. Here is an example of a single user avatar that gets overwritten on re-upload:
```tsx
import { Media } from "bknd/elements";
import { Media } from "userbase/elements";
export default function UserAvatar() {
return (
@@ -53,7 +53,7 @@ export default function UserAvatar() {
You can also customize the rendering of the media items and its uploading by passing a react element as a child. Here is an example of a custom `Media.Dropzone` that renders an user avatar (styled using tailwind):
```tsx
import { Media, useMediaDropzone, useMediaDropzoneState } from "bknd/elements";
import { Media, useMediaDropzone, useMediaDropzoneState } from "userbase/elements";
export default function CustomUserAvatar() {
return (
@@ -105,14 +105,14 @@ function CustomUserAvatar() {
## Auth
Adding authentication to your app with bknd is as easy as adding a `<form method="POST" />` with an action pointing to the action (`login` or `register`) to the strategy you want to use, e.g. for the password strategy, use `/api/auth/password/login`. But to make it even easier, you can use the `Auth.*` elements.
Adding authentication to your app with userbase is as easy as adding a `<form method="POST" />` with an action pointing to the action (`login` or `register`) to the strategy you want to use, e.g. for the password strategy, use `/api/auth/password/login`. But to make it even easier, you can use the `Auth.*` elements.
### `Auth.Screen`
The `Auth.Screen` element is a wrapper around the `Auth.Form` element that provides a full page screen. The current layout is admittedly very basic, but there will be more customization options in the future.
```tsx
import { Auth } from "bknd/elements";
import { Auth } from "userbase/elements";
export default function LoginScreen() {
return <Auth.Screen action="login" />;
@@ -128,10 +128,10 @@ Note that this component doesn't require any strategy-specific information, as i
### `Auth.Form`
If you only wish to render the form itself without the screen, you can use the `Auth.Form` element. Unlike the `Auth.Screen`, this element requires the `strategy` prop to be set to the strategy you want to use. You can either specify it manually, use use the exported hook `useAuthStrategies()` for fetch them from your bknd instance.
If you only wish to render the form itself without the screen, you can use the `Auth.Form` element. Unlike the `Auth.Screen`, this element requires the `strategy` prop to be set to the strategy you want to use. You can either specify it manually, use use the exported hook `useAuthStrategies()` for fetch them from your userbase instance.
```tsx
import { Auth, useAuthStrategies } from "bknd/elements";
import { Auth, useAuthStrategies } from "userbase/elements";
export default function LoginForm() {
const { strategies, basepath, loading } = useAuthStrategies();
@@ -8,12 +8,12 @@ import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
<Callout type="warning">
The MCP server is currently experimental and may change in the future. During this period, it is disabled by default. To stabilize it, and make **bknd MCP native**, all configuration changes you can make today with the integrated Admin UI will be migrated to use the MCP server.
The MCP server is currently experimental and may change in the future. During this period, it is disabled by default. To stabilize it, and make **userbase MCP native**, all configuration changes you can make today with the integrated Admin UI will be migrated to use the MCP server.
</Callout>
bknd includes a fully featured MCP server that can be used to interact with the bknd instance. It uses a lightweight MCP implementation that works in any environment bknd works in. Unlike other MCP servers, the exposed tools and resources are mainly dynamically generated from the schema, extracted from defined hono routes, and manually defined ones. This means exposed tools and resources are always up to date, and requires little overhead to maintain.
userbase includes a fully featured MCP server that can be used to interact with the userbase instance. It uses a lightweight MCP implementation that works in any environment userbase works in. Unlike other MCP servers, the exposed tools and resources are mainly dynamically generated from the schema, extracted from defined hono routes, and manually defined ones. This means exposed tools and resources are always up to date, and requires little overhead to maintain.
- Fully featured, always up to date MCP server natively integrated with bknd
- Fully featured, always up to date MCP server natively integrated with userbase
- Integrated MCP UI accessible from the Admin UI
- Built-in MCP client directly usable from your app instance
- CLI command to run an MCP server on stdio transport
@@ -31,7 +31,7 @@ Once enabled, you can access the MCP UI at `/mcp`, or choose "MCP" from the top
If you're using a `config`, you can enable the MCP server by setting the `server.mcp.enabled` property to `true`.
```typescript
import type { BkndConfig } from "bknd";
import type { UserbaseConfig } from "userbase";
export default {
config: {
@@ -41,7 +41,7 @@ export default {
}
}
}
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
Using the Admin UI, you can either navigate to `/settings/server` or click top right on the user menu, select "Settings", then "Server". Enable the MCP server by checking the "Enabled" checkbox under "Mcp".
@@ -51,7 +51,7 @@ Using the Admin UI, you can either navigate to `/settings/server` or click top r
The implementation is closely following the [MCP spec 2025-06-18](https://modelcontextprotocol.io/specification/2025-06-18) powered by [jsonv-ts](https://github.com/jsonv-ts/jsonv-ts), therefore any spec compliant client will work. However, there is a built-in MCP client:
```typescript
import { McpClient } from "bknd/utils";
import { McpClient } from "userbase/utils";
const client = new McpClient({
url: "http://localhost:1337/api/system/mcp",
@@ -61,7 +61,7 @@ const client = new McpClient({
Alternatively, similar to the `getApi` function, you can use the `getMcpClient` function to get the client from your app instance that doesn't travel through the network.
```typescript
import { createApp } from "bknd";
import { createApp } from "userbase";
const app = createApp();
const client = app.getMcpClient();
@@ -94,13 +94,13 @@ Refer to the [jsonv-ts docs](https://github.com/dswbx/jsonv-ts#mcp-client) for m
To start an MCP server on stdio transport, you can use the `mcp` CLI command. This is useful when you want to use it with IDEs or other tools that support stdio transport.
```bash
npx bknd mcp
npx userbase mcp
```
If you want have the Streamable HTTP endpoint disabled, you can still use the STDIO transport by passing the `--force` option.
```bash
npx bknd mcp --force
npx userbase mcp --force
```
## Usage in external tools
@@ -116,9 +116,9 @@ Pasting the following config into your Cursor `~/.cursor/mcp.json` file is the r
```json tab="Local"
{
"mcpServers": {
"bknd": {
"userbase": {
"command": "npx",
"args": ["-y", "bknd@latest", "mcp"]
"args": ["-y", "userbase@latest", "mcp"]
}
}
}
@@ -127,7 +127,7 @@ Pasting the following config into your Cursor `~/.cursor/mcp.json` file is the r
```json tab="Remote"
{
"mcpServers": {
"bknd": {
"userbase": {
"url": "http://localhost:1337/api/system/mcp"
}
}
@@ -141,10 +141,10 @@ Add this to your VS Code MCP config. See [VS Code MCP docs](https://code.visuals
```json tab="Local"
{
"servers": {
"bknd": {
"userbase": {
"type": "stdio",
"command": "npx",
"args": ["-y", "bknd@latest", "mcp"]
"args": ["-y", "userbase@latest", "mcp"]
}
}
}
@@ -153,7 +153,7 @@ Add this to your VS Code MCP config. See [VS Code MCP docs](https://code.visuals
```json tab="Remote"
{
"servers": {
"bknd": {
"userbase": {
"type": "http",
"url": "http://localhost:1337/api/system/mcp"
}
@@ -168,9 +168,9 @@ Add this to your Claude Desktop `claude_desktop_config.json` file. See [Claude D
```json title="claude_desktop_config.json"
{
"mcpServers": {
"bknd": {
"userbase": {
"command": "npx",
"args": ["-y", "bknd@latest", "mcp"]
"args": ["-y", "userbase@latest", "mcp"]
}
}
}
@@ -178,7 +178,7 @@ Add this to your Claude Desktop `claude_desktop_config.json` file. See [Claude D
</Accordion>
</Accordions>
If a tool you're using is not listed here, please let us know by [opening an issue](https://github.com/bknd-dev/bknd/issues/new) or [contacting us on Discord](https://discord.com/invite/Qjz9nNHYTB).
If a tool you're using is not listed here, please let us know by [opening an issue](https://github.com/userbase-dev/userbase/issues/new) or [contacting us on Discord](https://discord.com/invite/Qjz9nNHYTB).
## Authentication
@@ -198,11 +198,11 @@ const client = new McpClient({
When using the STDIO transport, you can pass an `--token` option to the CLI command.
```bash
npx bknd mcp --token <token>
npx userbase mcp --token <token>
```
Alternatively, you can also use the `BEARER_TOKEN` environment variable.
```bash
BEARER_TOKEN=<token> npx bknd mcp
BEARER_TOKEN=<token> npx userbase mcp
```
@@ -1,6 +1,6 @@
---
title: "SDK (React)"
description: "Use the bknd SDK for React"
description: "Use the userbase SDK for React"
icon: React
tags: ["documentation"]
---
@@ -21,10 +21,10 @@ There are several useful hooks to work with your backend:
## Setup
In order to use the React hooks, make sure you wrap your `<App />` inside `<ClientProvider />`. This provides the bknd API instance to all hooks in your component tree:
In order to use the React hooks, make sure you wrap your `<App />` inside `<ClientProvider />`. This provides the userbase API instance to all hooks in your component tree:
```tsx
import { ClientProvider } from "bknd/client";
import { ClientProvider } from "userbase/client";
export default function App() {
return <ClientProvider>{/* your app */}</ClientProvider>;
@@ -38,11 +38,11 @@ The `ClientProvider` accepts the following props:
<TypeTable
type={{
baseUrl: {
description: 'The base URL of your bknd instance (similar to host in the API). If left blank, it points to the same origin, which is useful when bknd is served from your framework (e.g., Next.js, Astro, React Router)',
description: 'The base URL of your userbase instance (similar to host in the API). If left blank, it points to the same origin, which is useful when userbase is served from your framework (e.g., Next.js, Astro, React Router)',
type: 'string',
},
children: {
description: 'React components that will have access to the bknd context',
description: 'React components that will have access to the userbase context',
type: 'ReactNode',
},
}}
@@ -77,24 +77,24 @@ All [Api options](/usage/sdk#setup) are also supported and will be passed to the
### Usage Examples
**Using with a remote bknd instance:**
**Using with a remote userbase instance:**
```tsx
import { ClientProvider } from "bknd/client";
import { ClientProvider } from "userbase/client";
export default function App() {
return (
<ClientProvider baseUrl="https://your-bknd-instance.com">
<ClientProvider baseUrl="https://your-userbase-instance.com">
{/* your app */}
</ClientProvider>
);
}
```
**Using with an embedded bknd instance (same origin):**
**Using with an embedded userbase instance (same origin):**
```tsx
import { ClientProvider } from "bknd/client";
import { ClientProvider } from "userbase/client";
export default function App() {
// no baseUrl needed - will use window.location.origin
@@ -105,12 +105,12 @@ export default function App() {
**Using with custom authentication:**
```tsx
import { ClientProvider } from "bknd/client";
import { ClientProvider } from "userbase/client";
export default function App() {
return (
<ClientProvider
baseUrl="https://your-bknd-instance.com"
baseUrl="https://your-userbase-instance.com"
token="your-auth-token"
onAuthStateChange={(state) => {
console.log("Auth state changed:", state);
@@ -129,7 +129,7 @@ For all examples below, we'll assume that your app is wrapped inside the `Client
Returns the [Api instance](/usage/sdk) from the `ClientProvider` context. This gives you direct access to all API methods for data, auth, media, and system operations.
```tsx
import { useApi } from "bknd/client";
import { useApi } from "userbase/client";
export default async function App() {
const api = useApi();
@@ -165,7 +165,7 @@ See the [SDK documentation](/usage/sdk) for all available API methods and option
Provides authentication state and helper functions for login, register, logout, and token management. This hook automatically tracks the authentication state from the `ClientProvider` context.
```tsx
import { useAuth } from "bknd/client";
import { useAuth } from "userbase/client";
export default function AuthComponent() {
const { user, verified, login, logout } = useAuth();
@@ -199,7 +199,7 @@ export default function AuthComponent() {
<TypeTable
type={{
baseUrl: {
description: 'Optional base URL to use a different bknd instance',
description: 'Optional base URL to use a different userbase instance',
type: 'string',
},
}}
@@ -264,7 +264,7 @@ Depending on your deployment architecture, there are different ways to handle au
Use this pattern when your frontend and backend are deployed independently on different domains. The token is stored in the browser's localStorage.
```tsx
import { ClientProvider, useAuth } from "bknd/client";
import { ClientProvider, useAuth } from "userbase/client";
import { useEffect, useState } from "react";
// setup ClientProvider with localStorage
@@ -328,7 +328,7 @@ function AuthComponent() {
Use this pattern when your frontend and backend are deployed on the same domain or when using a framework that serves both. Authentication is handled via HTTP-only cookies.
```tsx
import { ClientProvider, useAuth } from "bknd/client";
import { ClientProvider, useAuth } from "userbase/client";
import { useEffect } from "react";
// setup ClientProvider with credentials included
@@ -391,12 +391,12 @@ function InnerApp() {
#### 3. Full Stack (Embedded Mode)
Use this pattern when bknd is embedded in your framework (e.g., Next.js, Astro, React Router). The backend and frontend run in the same process.
Use this pattern when userbase is embedded in your framework (e.g., Next.js, Astro, React Router). The backend and frontend run in the same process.
```tsx
// this example is not specific to any framework, but you can use it with any framework that supports server-side rendering
import { ClientProvider, useAuth } from "bknd/client";
import { ClientProvider, useAuth } from "userbase/client";
import { useEffect } from "react";
// setup: extract user from server-side
@@ -465,7 +465,7 @@ This hook wraps the API class in an SWR hook for convenience. You can use any AP
supported, like so:
```tsx
import { useApiQuery } from "bknd/client";
import { useApiQuery } from "userbase/client";
export default function App() {
const { data, ...swr } = useApiQuery((api) => api.data.readMany("comments"));
@@ -516,7 +516,7 @@ following example we'll also use a `refine` function as well as `revalidateOnFoc
```tsx
import { useEffect, useState } from "react";
import { useApiQuery } from "bknd/client";
import { useApiQuery } from "userbase/client";
export default function App() {
const [text, setText] = useState("");
@@ -572,7 +572,7 @@ This hook wraps the endpoints of `DataApi` and returns CRUD options as parameter
```tsx
import { useState, useEffect } from "react";
import { useEntity } from "bknd/client";
import { useEntity } from "userbase/client";
export default function App() {
const [data, setData] = useState<any>();
@@ -633,7 +633,7 @@ of entities instead of a single entry.
This hook wraps the actions from `useEntity` around `SWR` for automatic data fetching, caching, and revalidation. It combines the power of SWR with CRUD operations for your entities.
```tsx
import { useEntityQuery } from "bknd/client";
import { useEntityQuery } from "userbase/client";
export default function App() {
const { data } = useEntityQuery("comments", 1);
@@ -717,7 +717,7 @@ The `query` parameter accepts a `RepoQueryIn` object with the following options:
#### Options
The `options` parameter extends SWR's configuration and adds bknd-specific options:
The `options` parameter extends SWR's configuration and adds userbase-specific options:
<TypeTable
type={{
@@ -820,7 +820,7 @@ The hook returns an object with the following properties:
Fetching a limited, sorted list of entities:
```tsx
import { useEntityQuery } from "bknd/client";
import { useEntityQuery } from "userbase/client";
export default function TodoList() {
const { data: todos, isLoading } = useEntityQuery("todos", undefined, {
@@ -846,7 +846,7 @@ All actions returned from `useEntityQuery` are conveniently wrapped to automatic
```tsx
import { useState, useEffect } from "react";
import { useEntityQuery } from "bknd/client";
import { useEntityQuery } from "userbase/client";
export default function App() {
const [text, setText] = useState("");
@@ -889,7 +889,7 @@ export default function App() {
Here's a comprehensive example showing all CRUD operations with query parameters:
```tsx
import { useEntityQuery } from "bknd/client";
import { useEntityQuery } from "userbase/client";
export default function TodoList() {
const { data: todos, create, update, _delete, isLoading } = useEntityQuery(
@@ -973,7 +973,7 @@ await mutate(commentId);
This hook provides a convenient way to invalidate SWR cache entries for manual revalidation.
```tsx
import { useInvalidate } from "bknd/client";
import { useInvalidate } from "userbase/client";
export default function App() {
const invalidate = useInvalidate();
@@ -1018,7 +1018,7 @@ export default function App() {
This hook provides mutation actions without fetching data. Useful when you only need to perform CRUD operations without subscribing to data updates.
```tsx
import { useEntityMutate } from "bknd/client";
import { useEntityMutate } from "userbase/client";
export default function QuickActions() {
const { create, update, _delete, mutate } = useEntityMutate("todos");
+11 -11
View File
@@ -1,14 +1,14 @@
---
title: "SDK (TypeScript)"
description: "Use the bknd SDK in TypeScript"
description: "Use the userbase SDK in TypeScript"
icon: TypeScript
tags: ["documentation"]
---
To start using the bknd API, start by creating a new API instance:
To start using the userbase API, start by creating a new API instance:
```ts
import { Api } from "bknd/client";
import { Api } from "userbase/client";
const api = new Api();
@@ -16,7 +16,7 @@ const api = new Api();
await api.verifyAuth();
```
The `Api` class is the main entry point for interacting with the bknd API. It provides methods
The `Api` class is the main entry point for interacting with the userbase API. It provides methods
for all available modules described below.
## Setup
@@ -28,7 +28,7 @@ You can initialize an API instance by providing the `Request` object, or manuall
The recommended way to create an API instance is by passing the current `Request` object. This will automatically point the API to your current instance and extract the token from the headers (either from cookies or `Authorization` header):
```ts
import { Api } from "bknd/client";
import { Api } from "userbase/client";
// replace this with the actual request
let request: Request;
@@ -36,10 +36,10 @@ let request: Request;
const api = new Api({ request });
```
If the authentication details are contained in the current request, but you're hosting your bknd instance somewhere else, you can specify a `host` option:
If the authentication details are contained in the current request, but you're hosting your userbase instance somewhere else, you can specify a `host` option:
```ts
import { Api } from "bknd/client";
import { Api } from "userbase/client";
// replace this with the actual request
let request: Request;
@@ -55,7 +55,7 @@ const api = new Api({
If you want to have an API instance that is using a different token, e.g. an admin token, you can create it by specifying the `host` and `token` option:
```ts
import { Api } from "bknd/client";
import { Api } from "userbase/client";
const api = new Api({
host: "https://<your-endpoint>",
token: "<your-token>",
@@ -64,11 +64,11 @@ const api = new Api({
### Using a local API
In case the place where you're using the API is the same as your bknd instance (e.g. when using it embedded in a React framework), you can specify a `fetcher` option to point to your bknd app. This way, requests won't travel over the network and instead processed locally:
In case the place where you're using the API is the same as your userbase instance (e.g. when using it embedded in a React framework), you can specify a `fetcher` option to point to your userbase app. This way, requests won't travel over the network and instead processed locally:
```ts
import type { App } from "bknd";
import { Api } from "bknd/client";
import type { App } from "userbase";
import { Api } from "userbase/client";
// replace this with your actual `App` instance
let app: App;
@@ -1,13 +1,13 @@
---
title: "Setup & Modes"
description: "Choose a mode and get bknd running with your app"
description: "Choose a mode and get userbase running with your app"
icon: Pin
tags: ["documentation"]
---
import { SquareMousePointer, Code, Blend } from 'lucide-react';
bknd supports three modes. Each mode determines how your backend is configured and where that configuration lives.
userbase supports three modes. Each mode determines how your backend is configured and where that configuration lives.
## Choose your mode
@@ -35,34 +35,34 @@ You can always change modes later. Start with UI-only if you're exploring.
## UI-only mode
This is the default. Run bknd and configure everything through the Admin UI. No setup code required beyond a database connection.
This is the default. Run userbase and configure everything through the Admin UI. No setup code required beyond a database connection.
```typescript title="bknd.config.ts"
import type { BkndConfig } from "bknd";
```typescript title="userbase.config.ts"
import type { UserbaseConfig } from "userbase";
export default {
connection: { url: "file:data.db" },
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
If you want to provide an initial data structure (entities, auth settings, etc.), pass it via `config`. It will only be applied when the database is empty.
```typescript title="bknd.config.ts"
import type { BkndConfig } from "bknd";
```typescript title="userbase.config.ts"
import type { UserbaseConfig } from "userbase";
export default {
connection: { url: "file:data.db" },
config: {
auth: { enabled: true },
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
<Callout type="info">
In UI-only mode, the `config` property is only applied on first boot. After that, all changes are made through the Admin UI.
</Callout>
**Next step:** Pick your [framework or runtime integration](/integration/introduction) to wire bknd into your app.
**Next step:** Pick your [framework or runtime integration](/integration/introduction) to wire userbase into your app.
---
@@ -70,9 +70,9 @@ export default {
Define your data structure programmatically with a Drizzle-like API. The Admin UI becomes read-only for configuration — you still use it to manage data.
```typescript title="bknd.config.ts"
import { type BkndConfig, em, entity, text, boolean } from "bknd";
import { secureRandomString } from "bknd/utils";
```typescript title="userbase.config.ts"
import { type UserbaseConfig, em, entity, text, boolean } from "userbase";
import { secureRandomString } from "userbase/utils";
const schema = em({
todos: entity("todos", {
@@ -93,12 +93,12 @@ export default {
options: {
mode: "code",
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
Unlike UI-only mode, the `config` is applied on every boot. If you change the schema, you may need to [sync the database](/usage/cli#syncing-the-database-sync).
**Next step:** Pick your [framework or runtime integration](/integration/introduction) to wire bknd into your app.
**Next step:** Pick your [framework or runtime integration](/integration/introduction) to wire userbase into your app.
---
@@ -106,8 +106,8 @@ Unlike UI-only mode, the `config` is applied on every boot. If you change the sc
Use the Admin UI to configure your backend while developing. When you're ready to deploy, export the config and run in code mode for production.
```typescript title="bknd.config.ts"
import type { BkndConfig } from "bknd";
```typescript title="userbase.config.ts"
import type { UserbaseConfig } from "userbase";
import appConfig from "./appconfig.json" with { type: "json" };
export default {
@@ -119,49 +119,49 @@ export default {
secrets: process.env,
},
},
} satisfies BkndConfig;
} satisfies UserbaseConfig;
```
To export your config, secrets, and types, use the CLI or plugins:
| What | CLI Command | Plugin |
|------|-------------|--------|
| Configuration | [`bknd config`](/usage/cli/#getting-the-configuration-config) | [`syncConfig`](/extending/plugins/#syncconfig) |
| Secrets | [`bknd secrets`](/usage/cli/#getting-the-secrets-secrets) | [`syncSecrets`](/extending/plugins/#syncsecrets) |
| Types | [`bknd types`](/usage/cli/#generating-types-types) | [`syncTypes`](/extending/plugins/#synctypes) |
| Configuration | [`userbase config`](/usage/cli/#getting-the-configuration-config) | [`syncConfig`](/extending/plugins/#syncconfig) |
| Secrets | [`userbase secrets`](/usage/cli/#getting-the-secrets-secrets) | [`syncSecrets`](/extending/plugins/#syncsecrets) |
| Types | [`userbase types`](/usage/cli/#generating-types-types) | [`syncTypes`](/extending/plugins/#synctypes) |
**Next step:** Pick your [framework or runtime integration](/integration/introduction) to wire bknd into your app.
**Next step:** Pick your [framework or runtime integration](/integration/introduction) to wire userbase into your app.
---
## Mode helpers
For code and hybrid modes, bknd provides helper functions that handle syncing, mode switching, and schema validation automatically.
For code and hybrid modes, userbase provides helper functions that handle syncing, mode switching, and schema validation automatically.
```typescript title="bknd.config.ts (code mode with Bun)"
import { code } from "bknd/modes";
import { type BunBkndConfig, writer } from "bknd/adapter/bun";
```typescript title="userbase.config.ts (code mode with Bun)"
import { code } from "userbase/modes";
import { type BunUserbaseConfig, writer } from "userbase/adapter/bun";
export default code<BunBkndConfig>({
export default code<BunUserbaseConfig>({
connection: { url: "file:data.db" },
writer,
isProduction: Bun.env.NODE_ENV === "production",
typesFilePath: "bknd-types.d.ts",
typesFilePath: "userbase-types.d.ts",
});
```
```typescript title="bknd.config.ts (hybrid mode with Bun)"
import { hybrid } from "bknd/modes";
import { type BunBkndConfig, writer, reader } from "bknd/adapter/bun";
```typescript title="userbase.config.ts (hybrid mode with Bun)"
import { hybrid } from "userbase/modes";
import { type BunUserbaseConfig, writer, reader } from "userbase/adapter/bun";
export default hybrid<BunBkndConfig>({
export default hybrid<BunUserbaseConfig>({
connection: { url: "file:data.db" },
writer,
reader,
secrets: await Bun.file(".env.local").json(),
isProduction: Bun.env.NODE_ENV === "production",
typesFilePath: "bknd-types.d.ts",
configFilePath: "bknd-config.json",
typesFilePath: "userbase-types.d.ts",
configFilePath: "userbase-config.json",
});
```
@@ -175,6 +175,6 @@ Mode helpers give you:
## Further reading
- [Framework & runtime integrations](/integration/introduction) — wire bknd into Next.js, Astro, Bun, Cloudflare, etc.
- [Framework & runtime integrations](/integration/introduction) — wire userbase into Next.js, Astro, Bun, Cloudflare, etc.
- [Database configuration](/usage/database) — choose and configure your SQL database
- [Configuration reference](/extending/config) — full `BkndConfig` API, plugins, events, and lifecycle hooks
- [Configuration reference](/extending/config) — full `UserbaseConfig` API, plugins, events, and lifecycle hooks
+1 -1
View File
@@ -6,7 +6,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
@@ -6,7 +6,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
+1 -1
View File
@@ -6,7 +6,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
+1 -1
View File
@@ -5,7 +5,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
+1 -1
View File
@@ -5,7 +5,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
+1 -1
View File
@@ -5,7 +5,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
+1 -1
View File
@@ -5,7 +5,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
+1 -1
View File
@@ -5,7 +5,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
+1 -1
View File
@@ -5,7 +5,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
+1 -1
View File
@@ -5,7 +5,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
@@ -5,7 +5,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
@@ -5,7 +5,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
+1 -1
View File
@@ -5,7 +5,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
@@ -5,7 +5,7 @@ tags: ["guide"]
<Callout type="info" title="The documentation is currently a work in progress">
Check back soon — or stay updated on our progress on
[GitHub](https://github.com/bknd-io/bknd) and join the conversation in
[GitHub](https://github.com/userbase-io/userbase) and join the conversation in
[Discord](https://discord.gg/952SFk8Tb8).
</Callout>
+1 -1
View File
@@ -1,7 +1,7 @@
{
"title": "User Guide",
"root": true,
"description": "Instructions for building with bknd",
"description": "Instructions for building with userbase",
"icon": "Bolt",
"pages": [
"---User Guide---",
+7 -7
View File
@@ -4221,37 +4221,37 @@
],
"resources": [
{
"uri": "bknd://data/entities",
"uri": "userbase://data/entities",
"name": "data_entities",
"title": "Entities",
"description": "Retrieve all entities"
},
{
"uri": "bknd://data/relations",
"uri": "userbase://data/relations",
"name": "data_relations",
"title": "Relations",
"description": "Retrieve all relations"
},
{
"uri": "bknd://data/indices",
"uri": "userbase://data/indices",
"name": "data_indices",
"title": "Indices",
"description": "Retrieve all indices"
},
{
"uri": "bknd://system/config",
"uri": "userbase://system/config",
"name": "system_config"
},
{
"uriTemplate": "bknd://system/config/{module}",
"uriTemplate": "userbase://system/config/{module}",
"name": "system_config_module"
},
{
"uri": "bknd://system/schema",
"uri": "userbase://system/schema",
"name": "system_schema"
},
{
"uriTemplate": "bknd://system/schema/{module}",
"uriTemplate": "userbase://system/schema/{module}",
"name": "system_schema_module"
}
]
+1 -1
View File
@@ -17,7 +17,7 @@ const config = {
serverExternalPackages: ["typescript", "twoslash"],
webpack(config) {
config.resolve.alias["@/bknd"] = path.resolve(__dirname, "../app/src");
config.resolve.alias["@/userbase"] = path.resolve(__dirname, "../app/src");
config.resolve.alias["@"] = path.resolve(__dirname);
return config;
},
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -1,11 +1,11 @@
{
"name": "bknd-docs",
"name": "userbase-docs",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "bknd-docs",
"name": "userbase-docs",
"hasInstallScript": true,
"dependencies": {
"@iconify/react": "^6.0.0",
+1 -1
View File
@@ -1,5 +1,5 @@
{
"name": "bknd-docs",
"name": "userbase-docs",
"private": true,
"scripts": {
"dev": "next dev",
+1 -1
View File
@@ -16,7 +16,7 @@
"incremental": true,
"paths": {
"@/.source": ["./.source/index.ts"],
"@/bknd/*": ["../app/src/"],
"@/userbase/*": ["../app/src/"],
"@/*": ["./*"]
},
+1 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "bknd-docs",
"name": "userbase-docs",
"compatibility_date": "2025-07-24",
"compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
"assets": {