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
+12 -12
View File
@@ -1,5 +1,5 @@
# bknd starter: Nuxt
A minimal example of a Nuxt project with bknd integration.
# userbase starter: Nuxt
A minimal example of a Nuxt project with userbase integration.
## Project Structure
@@ -20,14 +20,14 @@ Inside of your Nuxt project, you'll see the following folders and files:
│ └── pages
│ ├── index.vue
│ └── user.vue
├── bknd.config.ts
├── userbase.config.ts
├── bun.lock
├── nuxt.config.ts
├── package.json
├── public
│ ├── admin # generated by bknd and contains the admin UI
│ ├── bknd.ico
│ ├── bknd.svg
│ ├── admin # generated by userbase and contains the admin UI
│ ├── userbase.ico
│ ├── userbase.svg
│ ├── favicon.ico
│ ├── file.svg
│ ├── globe.svg
@@ -37,17 +37,17 @@ Inside of your Nuxt project, you'll see the following folders and files:
├── README.md
├── server
│ ├── middleware
│ │ └── bknd.ts # intercepts api and admin ui requests
│ │ └── userbase.ts # intercepts api and admin ui requests
│ ├── routes
│ │ └── todos.post.ts
│ └── utils
│ └── bknd.ts # initializes bknd instance
│ └── userbase.ts # initializes userbase instance
└── tsconfig.json
```
Here is a quick overview about how to adjust the behavior of `bknd`:
* Initialization of the `bknd` config with helper functions are located at `src/server/utils/bknd.ts`
* Admin UI is rendered at `src/server/middleware/bknd.ts`
Here is a quick overview about how to adjust the behavior of `userbase`:
* Initialization of the `userbase` config with helper functions are located at `src/server/utils/userbase.ts`
* Admin UI is rendered at `src/server/middleware/userbase.ts`
## Commands
@@ -61,4 +61,4 @@ All commands are run from the root of the project, from a terminal:
## Want to learn more?
Feel free to check [our documentation](https://docs.bknd.io/integration/nuxt) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
Feel free to check [our documentation](https://docs.userbase.io/integration/nuxt) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
+4 -4
View File
@@ -1,12 +1,12 @@
<template>
<div className="flex gap-4 items-center flex-col sm:flex-row">
<a className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground gap-2 text-white hover:bg-[#383838] dark:hover:bg-[#ccc] text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5"
href="https://bknd.io/" target="_blank" rel="noopener noreferrer">
<img className="grayscale" src="/bknd.ico" alt="bknd logomark" width={20} height={20} />
Go To Bknd.io
href="https://userbase.io/" target="_blank" rel="noopener noreferrer">
<img className="grayscale" src="/userbase.ico" alt="userbase logomark" width={20} height={20} />
Go To Userbase.io
</a>
<a className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:min-w-44"
href="https://docs.bknd.io/integration/nextjs" target="_blank" rel="noopener noreferrer">
href="https://docs.userbase.io/integration/nextjs" target="_blank" rel="noopener noreferrer">
Read our docs
</a>
</div>
+2 -2
View File
@@ -20,10 +20,10 @@ const pathname = computed(() => route.path)
Admin
</NuxtLink>
<a class="flex items-center gap-2 hover:underline hover:underline-offset-4" href="https://bknd.io" target="_blank"
<a class="flex items-center gap-2 hover:underline hover:underline-offset-4" href="https://userbase.io" target="_blank"
rel="noopener noreferrer">
<img aria-hidden src="/globe.svg" alt="Globe icon" width="16" height="16" />
Go to bknd.io →
Go to userbase.io →
</a>
</footer>
</template>
@@ -1,4 +1,4 @@
import type { DB } from "bknd";
import type { DB } from "userbase";
type Todo = DB["todos"];
+1 -1
View File
@@ -1,4 +1,4 @@
import type { User } from "bknd";
import type { User } from "userbase";
export const useUser = () => {
const getUser = () => $fetch("/api/auth/me") as Promise<{ user: User }>;
+1 -1
View File
@@ -24,7 +24,7 @@ async function handleSubmit(event: Event) {
<div class="flex flex-row items-center justify-evenly min-w-full">
<img class="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>
<List :items="['Get started with a full backend.', 'Focus on what matters instead of repetition.']" />
+3 -3
View File
@@ -19,8 +19,8 @@ onMounted(() => {
<div class="ml-3.5 mr-2 font-mono opacity-70">&amp;</div>
<img
class="dark:invert"
src="/bknd.svg"
alt="bknd logo"
src="/userbase.svg"
alt="userbase logo"
width="183"
height="59"
/>
@@ -41,7 +41,7 @@ onMounted(() => {
<p className="text-xs opacity-50">
Sign in with:
<b>
<code>test@bknd.io</code>
<code>test@userbase.io</code>
</b>
/
<b>
+8 -8
View File
@@ -1,7 +1,7 @@
import { em, entity, text, boolean, } from "bknd";
import { secureRandomString } from "bknd/utils";
import type { NuxtBkndConfig } from "bknd/adapter/nuxt";
import { registerLocalMediaAdapter } from "bknd/adapter/node";
import { em, entity, text, boolean, } from "userbase";
import { secureRandomString } from "userbase/utils";
import type { NuxtUserbaseConfig } from "userbase/adapter/nuxt";
import { registerLocalMediaAdapter } from "userbase/adapter/node";
const local = registerLocalMediaAdapter();
@@ -14,7 +14,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 { }
}
@@ -25,13 +25,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",
});
},
@@ -56,4 +56,4 @@ export default {
assetsPath: "/admin/",
logoReturnPath: "../..",
},
} satisfies NuxtBkndConfig;
} satisfies NuxtUserbaseConfig;
+1 -1
View File
@@ -5,7 +5,7 @@ export default defineNuxtConfig({
modules: ["@nuxtjs/tailwindcss"],
app: {
head: {
title: "Nuxt 🤝 Bknd.io",
title: "Nuxt 🤝 Userbase.io",
},
},
css: ["assets/css/main.css"],
+4 -4
View File
@@ -1,5 +1,5 @@
{
"name": "nuxbknd",
"name": "nuxuserbase",
"type": "module",
"private": true,
"scripts": {
@@ -7,13 +7,13 @@
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"typegen": "bunx tsx node_modules/.bin/bknd types --outfile bknd-types.d.ts",
"postinstall": "nuxt prepare && bun run bknd copy-assets --out public/admin"
"typegen": "bunx tsx node_modules/.bin/userbase types --outfile userbase-types.d.ts",
"postinstall": "nuxt prepare && bun run userbase copy-assets --out public/admin"
},
"dependencies": {
"@nuxtjs/tailwindcss": "6.14.0",
"@types/node": "^25.2.3",
"bknd": "file:../../app",
"userbase": "file:../../app",
"nuxt": "^4.3.1",
"vue": "^3.5.28",
"vue-router": "^4.6.4"
+2 -2
View File
@@ -1,5 +1,5 @@
import { serve } from "bknd/adapter/nuxt";
import config from "../../bknd.config";
import { serve } from "userbase/adapter/nuxt";
import config from "../../userbase.config";
export default defineEventHandler(async (event) => {
const pathname = event.path
+4 -4
View File
@@ -1,15 +1,15 @@
import { type NuxtBkndConfig, getApp as getNuxtApp } from "bknd/adapter/nuxt";
import bkndConfig from "../../bknd.config";
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 });