This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# bknd starter: Astro
|
||||
A minimal Astro project with bknd integration.
|
||||
# userbase starter: Astro
|
||||
A minimal Astro project with userbase integration.
|
||||
|
||||
## Project Structure
|
||||
|
||||
@@ -19,7 +19,7 @@ Inside of your Astro project, you'll see the following folders and files:
|
||||
└── package.json
|
||||
```
|
||||
|
||||
To update `bknd` config, check `src/api/[...api].astro` and `src/admin/[...admin].astro`.
|
||||
To update `userbase` config, check `src/api/[...api].astro` and `src/admin/[...admin].astro`.
|
||||
|
||||
## Commands
|
||||
|
||||
@@ -36,4 +36,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/astro) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
|
||||
Feel free to check [our documentation](https://docs.userbase.io/integration/astro) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { AstroBkndConfig } from "bknd/adapter/astro";
|
||||
import { registerLocalMediaAdapter } from "bknd/adapter/node";
|
||||
import { boolean, em, entity, text } from "bknd";
|
||||
import { secureRandomString } from "bknd/utils";
|
||||
import type { AstroUserbaseConfig } from "userbase/adapter/astro";
|
||||
import { registerLocalMediaAdapter } from "userbase/adapter/node";
|
||||
import { boolean, em, entity, text } from "userbase";
|
||||
import { secureRandomString } from "userbase/utils";
|
||||
|
||||
// since we're running in node, we can register the local media adapter
|
||||
const local = registerLocalMediaAdapter();
|
||||
@@ -16,7 +16,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 {}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ export default {
|
||||
auth: {
|
||||
enabled: true,
|
||||
jwt: {
|
||||
issuer: "bknd-astro-example",
|
||||
issuer: "userbase-astro-example",
|
||||
secret: secureRandomString(64),
|
||||
},
|
||||
},
|
||||
@@ -51,15 +51,15 @@ 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",
|
||||
});
|
||||
},
|
||||
},
|
||||
} as const satisfies AstroBkndConfig;
|
||||
} as const satisfies AstroUserbaseConfig;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"@types/react": "^19.0.12",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"astro": "^5.16.9",
|
||||
"bknd": "file:../../app",
|
||||
"userbase": "file:../../app",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"typescript": "^5.7.2"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
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(
|
||||
|
||||
@@ -31,7 +31,7 @@ const items = [
|
||||
</nav>
|
||||
<main>
|
||||
<div class="center">
|
||||
<h1>bknd + <span class="text-gradient">Astro</span></h1>
|
||||
<h1>userbase + <span class="text-gradient">Astro</span></h1>
|
||||
<slot name="context" />
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
import { Admin } from "bknd/ui";
|
||||
import "bknd/dist/styles.css";
|
||||
import { Admin } from "userbase/ui";
|
||||
import "userbase/dist/styles.css";
|
||||
|
||||
import { getApi } from "../../bknd";
|
||||
import { getApi } from "../../userbase";
|
||||
|
||||
const api = await getApi(Astro, { verify: true });
|
||||
const user = api.getUser();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { APIContext } from "astro";
|
||||
import { serve } from "bknd/adapter/astro";
|
||||
import { config } from "../../bknd";
|
||||
import { serve } from "userbase/adapter/astro";
|
||||
import { config } from "../../userbase";
|
||||
|
||||
export const prerender = false;
|
||||
export const ALL = serve<APIContext>(config);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import { getApi } from "../bknd";
|
||||
import { getApi } from "../userbase";
|
||||
import Card from "../components/Card.astro";
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import { getApi } from "../bknd";
|
||||
import { getApi } from "../userbase";
|
||||
import Card from "../components/Card.astro";
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
const api = await getApi(Astro, { verify: true });
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set variables
|
||||
FUNCTION_NAME="bknd-lambda"
|
||||
ROLE_NAME="bknd-lambda-execution-role"
|
||||
FUNCTION_NAME="userbase-lambda"
|
||||
ROLE_NAME="userbase-lambda-execution-role"
|
||||
|
||||
echo "Starting cleanup of AWS resources..."
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set variables
|
||||
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"
|
||||
@@ -16,7 +16,7 @@ echo "Building Lambda package..."
|
||||
rm -rf dist && mkdir dist
|
||||
|
||||
# copy assets
|
||||
node_modules/.bin/bknd copy-assets --out=dist/static
|
||||
node_modules/.bin/userbase copy-assets --out=dist/static
|
||||
|
||||
# Run esbuild and check for errors
|
||||
# important to use --platform=browser for libsql dependency (otherwise we need to push node_modules)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { serve } from "bknd/adapter/aws";
|
||||
import { serve } from "userbase/adapter/aws";
|
||||
|
||||
export const handler = serve({
|
||||
// to get local assets, run `npx bknd copy-assets`
|
||||
// to get local assets, run `npx userbase copy-assets`
|
||||
// this is automatically done in `deploy.sh`
|
||||
assets: {
|
||||
mode: "local",
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"bknd": "file:../../app"
|
||||
"userbase": "file:../../app"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# bknd starter: Bun
|
||||
A minimal Bun project with bknd integration.
|
||||
# userbase starter: Bun
|
||||
A minimal Bun project with userbase integration.
|
||||
|
||||
## Project Structure
|
||||
|
||||
@@ -12,7 +12,7 @@ Inside of your Bun project, you'll see the following folders and files:
|
||||
└── package.json
|
||||
```
|
||||
|
||||
To update `bknd` config, check `index.ts`.
|
||||
To update `userbase` config, check `index.ts`.
|
||||
|
||||
## Commands
|
||||
|
||||
@@ -25,4 +25,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/bun) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
|
||||
Feel free to check [our documentation](https://docs.userbase.io/integration/bun) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { type BunBkndConfig, serve } from "bknd/adapter/bun";
|
||||
import { type BunUserbaseConfig, serve } from "userbase/adapter/bun";
|
||||
|
||||
// Actually, all it takes is the following line:
|
||||
// serve();
|
||||
|
||||
// this is optional, if omitted, it uses an in-memory database
|
||||
const config: BunBkndConfig = {
|
||||
const config: BunUserbaseConfig = {
|
||||
connection: {
|
||||
url: "data.db",
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"start": "bun run index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"bknd": "file:../../app"
|
||||
"userbase": "file:../../app"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest"
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
# bknd starter: Cloudflare Vite Code-Only
|
||||
A fullstack React + Vite application with bknd integration, showcasing **code-only mode** and Cloudflare Workers deployment.
|
||||
# userbase starter: Cloudflare Vite Code-Only
|
||||
A fullstack React + Vite application with userbase integration, showcasing **code-only mode** and Cloudflare Workers deployment.
|
||||
|
||||
## Key Features
|
||||
|
||||
This example demonstrates a minimal, code-first approach to building with bknd:
|
||||
This example demonstrates a minimal, code-first approach to building with userbase:
|
||||
|
||||
### 💻 Code-Only Mode
|
||||
Define your entire backend **programmatically** using a Drizzle-like API. Your data structure, authentication, and configuration live directly in code with zero build-time tooling required. Perfect for developers who prefer traditional code-first workflows.
|
||||
|
||||
### 🎯 Minimal Boilerplate
|
||||
Unlike the hybrid mode template, this example uses **no automatic type generation**, **no filesystem plugins**, and **no auto-synced configuration files**. This simulates a typical development environment where you manage types generation manually. If you prefer automatic type generation, you can easily add it using the [CLI](https://docs.bknd.io/usage/cli#generating-types-types) or [Vite plugin](https://docs.bknd.io/extending/plugins#synctypes).
|
||||
Unlike the hybrid mode template, this example uses **no automatic type generation**, **no filesystem plugins**, and **no auto-synced configuration files**. This simulates a typical development environment where you manage types generation manually. If you prefer automatic type generation, you can easily add it using the [CLI](https://docs.userbase.io/usage/cli#generating-types-types) or [Vite plugin](https://docs.userbase.io/extending/plugins#synctypes).
|
||||
|
||||
### ⚡ Split Configuration Pattern
|
||||
- **`config.ts`**: Main configuration that defines your schema and can be safely imported in your worker
|
||||
- **`bknd.config.ts`**: Wraps the configuration with `withPlatformProxy` for CLI usage with Cloudflare bindings (should NOT be imported in your worker)
|
||||
- **`userbase.config.ts`**: Wraps the configuration with `withPlatformProxy` for CLI usage with Cloudflare bindings (should NOT be imported in your worker)
|
||||
|
||||
This pattern prevents bundling `wrangler` into your worker while still allowing CLI access to Cloudflare resources.
|
||||
|
||||
@@ -27,15 +27,15 @@ Inside of your project, you'll see the following folders and files:
|
||||
│ ├── app/ # React frontend application
|
||||
│ │ ├── App.tsx
|
||||
│ │ ├── routes/
|
||||
│ │ │ ├── admin.tsx # bknd Admin UI route
|
||||
│ │ │ ├── admin.tsx # userbase Admin UI route
|
||||
│ │ │ └── home.tsx # Example frontend route
|
||||
│ │ └── main.tsx
|
||||
│ └── worker/
|
||||
│ └── index.ts # Cloudflare Worker entry
|
||||
├── config.ts # bknd configuration with schema definition
|
||||
├── bknd.config.ts # CLI configuration with platform proxy
|
||||
├── config.ts # userbase configuration with schema definition
|
||||
├── userbase.config.ts # CLI configuration with platform proxy
|
||||
├── seed.ts # Optional: seed data for development
|
||||
├── vite.config.ts # Standard Vite config (no bknd plugins)
|
||||
├── vite.config.ts # Standard Vite config (no userbase plugins)
|
||||
├── package.json
|
||||
└── wrangler.json # Cloudflare Workers configuration
|
||||
```
|
||||
@@ -49,7 +49,7 @@ Inside of your project, you'll see the following folders and files:
|
||||
|
||||
## Admin UI & Frontend
|
||||
|
||||
- `/admin` mounts `<Admin />` from `bknd/ui` with `withProvider={{ user }}` so it respects the authenticated user returned by `useAuth`.
|
||||
- `/admin` mounts `<Admin />` from `userbase/ui` with `withProvider={{ user }}` so it respects the authenticated user returned by `useAuth`.
|
||||
- `/` showcases `useEntityQuery("todos")`, mutation helpers, and authentication state — demonstrating how manually declared types flow into the React code.
|
||||
|
||||
|
||||
@@ -59,9 +59,9 @@ Inside of your project, you'll see the following folders and files:
|
||||
The main configuration file that uses the `code()` mode helper:
|
||||
|
||||
```typescript
|
||||
import type { CloudflareBkndConfig } from "bknd/adapter/cloudflare";
|
||||
import { code } from "bknd/modes";
|
||||
import { boolean, em, entity, text } from "bknd";
|
||||
import type { CloudflareUserbaseConfig } from "userbase/adapter/cloudflare";
|
||||
import { code } from "userbase/modes";
|
||||
import { boolean, em, entity, text } from "userbase";
|
||||
|
||||
// define your schema using a Drizzle-like API
|
||||
const schema = em({
|
||||
@@ -74,11 +74,11 @@ const schema = em({
|
||||
// register your schema for type completion (optional)
|
||||
// alternatively, you can use the CLI to auto-generate types
|
||||
type Database = (typeof schema)["DB"];
|
||||
declare module "bknd" {
|
||||
declare module "userbase" {
|
||||
interface DB extends Database {}
|
||||
}
|
||||
|
||||
export default code<CloudflareBkndConfig>({
|
||||
export default code<CloudflareUserbaseConfig>({
|
||||
app: (env) => ({
|
||||
config: {
|
||||
// convert schema to JSON format
|
||||
@@ -101,20 +101,20 @@ export default code<CloudflareBkndConfig>({
|
||||
```
|
||||
|
||||
Key differences from hybrid mode:
|
||||
- **No auto-generated files**: No `bknd-config.json`, `bknd-types.d.ts`, or `.env.example`
|
||||
- **Manual type declaration**: Types are declared inline using `declare module "bknd"`
|
||||
- **No auto-generated files**: No `userbase-config.json`, `userbase-types.d.ts`, or `.env.example`
|
||||
- **Manual type declaration**: Types are declared inline using `declare module "userbase"`
|
||||
- **Direct secret access**: Secrets come directly from `env` parameters
|
||||
- **Simpler setup**: No filesystem plugins or readers/writers needed
|
||||
|
||||
If you prefer automatic type generation, you can add it later using:
|
||||
- **CLI**: `npm run bknd -- types` (requires adding `typesFilePath` to config)
|
||||
- **CLI**: `npm run userbase -- types` (requires adding `typesFilePath` to config)
|
||||
- **Plugin**: Import `syncTypes` plugin and configure it in your app
|
||||
|
||||
### `bknd.config.ts`
|
||||
### `userbase.config.ts`
|
||||
Wraps the configuration for CLI usage with Cloudflare bindings:
|
||||
|
||||
```typescript
|
||||
import { withPlatformProxy } from "bknd/adapter/cloudflare/proxy";
|
||||
import { withPlatformProxy } from "userbase/adapter/cloudflare/proxy";
|
||||
import config from "./config.ts";
|
||||
|
||||
export default withPlatformProxy(config, {
|
||||
@@ -122,10 +122,10 @@ export default withPlatformProxy(config, {
|
||||
});
|
||||
```
|
||||
|
||||
**Important**: Don't import this file in your worker, as it would bundle `wrangler` into your production code. This file is only used by the bknd CLI.
|
||||
**Important**: Don't import this file in your worker, as it would bundle `wrangler` into your production code. This file is only used by the userbase CLI.
|
||||
|
||||
### `vite.config.ts`
|
||||
Standard Vite configuration without bknd-specific plugins:
|
||||
Standard Vite configuration without userbase-specific plugins:
|
||||
|
||||
```typescript
|
||||
import { defineConfig } from "vite";
|
||||
@@ -149,8 +149,8 @@ All commands are run from the root of the project, from a terminal:
|
||||
| `npm run build` | Builds the application for production |
|
||||
| `npm run preview` | Builds and previews the production build locally |
|
||||
| `npm run deploy` | Builds, syncs the schema and deploys to Cloudflare Workers|
|
||||
| `npm run bknd` | Runs bknd CLI commands |
|
||||
| `npm run bknd:seed`| Seeds the database with example data |
|
||||
| `npm run userbase` | Runs userbase CLI commands |
|
||||
| `npm run userbase:seed`| Seeds the database with example data |
|
||||
| `npm run cf:types` | Generates Cloudflare Worker types from `wrangler.json` |
|
||||
| `npm run check` | Type checks and does a dry-run deployment |
|
||||
|
||||
@@ -180,7 +180,7 @@ All commands are run from the root of the project, from a terminal:
|
||||
4. **Manually declare types** (optional, but recommended for IDE support):
|
||||
```typescript
|
||||
type Database = (typeof schema)["DB"];
|
||||
declare module "bknd" {
|
||||
declare module "userbase" {
|
||||
interface DB extends Database {}
|
||||
}
|
||||
```
|
||||
@@ -198,7 +198,7 @@ All commands are run from the root of the project, from a terminal:
|
||||
npm run dev
|
||||
|
||||
# Production database (safe operations only)
|
||||
CLOUDFLARE_ENV=production npm run bknd -- sync --force
|
||||
CLOUDFLARE_ENV=production npm run userbase -- sync --force
|
||||
```
|
||||
|
||||
## Before You Deploy
|
||||
@@ -253,7 +253,7 @@ This will:
|
||||
3. Sync the database schema (safe operations only)
|
||||
4. Deploy to Cloudflare Workers using Wrangler
|
||||
|
||||
In production, bknd will:
|
||||
In production, userbase will:
|
||||
- Use the configuration defined in `config.ts`
|
||||
- Skip config validation for better performance
|
||||
- Expect secrets to be provided via environment variables
|
||||
@@ -261,7 +261,7 @@ In production, bknd will:
|
||||
## How Code Mode Works
|
||||
|
||||
1. **Define Schema:** Create entities and fields using the Drizzle-like API in `config.ts`
|
||||
2. **Convert to JSON:** Use `schema.toJSON()` to convert your schema to bknd's configuration format
|
||||
2. **Convert to JSON:** Use `schema.toJSON()` to convert your schema to userbase's configuration format
|
||||
3. **Manual Types:** Optionally declare types inline for IDE support and type safety
|
||||
4. **Deploy:** Same configuration runs in both development and production
|
||||
|
||||
@@ -270,7 +270,7 @@ In production, bknd will:
|
||||
| Feature | Code Mode | Hybrid Mode |
|
||||
|---------|-----------|-------------|
|
||||
| Schema Definition | Code-only (`em`, `entity`, `text`) | Visual UI in dev, code in prod |
|
||||
| Configuration Files | None (all in code) | Auto-generated `bknd-config.json` |
|
||||
| Configuration Files | None (all in code) | Auto-generated `userbase-config.json` |
|
||||
| Type Generation | Manual or opt-in | Automatic |
|
||||
| Setup Complexity | Minimal | Requires plugins & filesystem access |
|
||||
| Use Case | Traditional code-first workflows | Rapid prototyping, visual development |
|
||||
@@ -289,7 +289,7 @@ Add `typesFilePath` to your config:
|
||||
|
||||
```typescript
|
||||
export default code({
|
||||
typesFilePath: "./bknd-types.d.ts",
|
||||
typesFilePath: "./userbase-types.d.ts",
|
||||
// ... rest of config
|
||||
});
|
||||
```
|
||||
@@ -297,7 +297,7 @@ export default code({
|
||||
For Cloudflare Workers, you'll need the `devFsVitePlugin`:
|
||||
```typescript
|
||||
// vite.config.ts
|
||||
import { devFsVitePlugin } from "bknd/adapter/cloudflare";
|
||||
import { devFsVitePlugin } from "userbase/adapter/cloudflare";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
@@ -311,7 +311,7 @@ Finally, add the generated types to your `tsconfig.json`:
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"types": ["./bknd-types.d.ts"]
|
||||
"types": ["./userbase-types.d.ts"]
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -323,26 +323,26 @@ This provides filesystem access for auto-syncing types despite Cloudflare's `une
|
||||
You may also use the CLI to generate types:
|
||||
|
||||
```sh
|
||||
npx bknd types --outfile ./bknd-types.d.ts
|
||||
npx userbase types --outfile ./userbase-types.d.ts
|
||||
```
|
||||
|
||||
## Database Seeding
|
||||
|
||||
Unlike UI-only and hybrid modes where bknd can automatically detect an empty database (by attempting to fetch the configuration. A "table not found" error indicates a fresh database), **code mode requires manual seeding**. This is because in code mode, the configuration is always provided from code, so bknd can't determine if the database is empty without additional queries, which would impact performance.
|
||||
Unlike UI-only and hybrid modes where userbase can automatically detect an empty database (by attempting to fetch the configuration. A "table not found" error indicates a fresh database), **code mode requires manual seeding**. This is because in code mode, the configuration is always provided from code, so userbase can't determine if the database is empty without additional queries, which would impact performance.
|
||||
|
||||
This example includes a [`seed.ts`](./seed.ts) file that you can run manually. For Cloudflare, it uses `bknd.config.ts` (with `withPlatformProxy`) to access Cloudflare resources like D1 during CLI execution:
|
||||
This example includes a [`seed.ts`](./seed.ts) file that you can run manually. For Cloudflare, it uses `userbase.config.ts` (with `withPlatformProxy`) to access Cloudflare resources like D1 during CLI execution:
|
||||
|
||||
```sh
|
||||
npm run bknd:seed
|
||||
npm run userbase:seed
|
||||
```
|
||||
|
||||
The seed script manually checks if the database is empty before inserting data. See the [seed.ts](./seed.ts) file for implementation details.
|
||||
|
||||
## Want to Learn More?
|
||||
|
||||
- [Cloudflare Integration Documentation](https://docs.bknd.io/integration/cloudflare)
|
||||
- [Code Mode Guide](https://docs.bknd.io/usage/introduction#code-only-mode)
|
||||
- [Mode Helpers Documentation](https://docs.bknd.io/usage/introduction#mode-helpers)
|
||||
- [Data Structure & Schema API](https://docs.bknd.io/usage/database#data-structure)
|
||||
- [Cloudflare Integration Documentation](https://docs.userbase.io/integration/cloudflare)
|
||||
- [Code Mode Guide](https://docs.userbase.io/usage/introduction#code-only-mode)
|
||||
- [Mode Helpers Documentation](https://docs.userbase.io/usage/introduction#mode-helpers)
|
||||
- [Data Structure & Schema API](https://docs.userbase.io/usage/database#data-structure)
|
||||
- [Discord Community](https://discord.gg/952SFk8Tb8)
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/**
|
||||
* This file gets automatically picked up by the bknd CLI. Since we're using cloudflare,
|
||||
* This file gets automatically picked up by the userbase CLI. Since we're using cloudflare,
|
||||
* we want to use cloudflare bindings (such as the database). To do this, we need to wrap
|
||||
* the configuration with the `withPlatformProxy` helper function.
|
||||
*
|
||||
* Don't import this file directly in your app, otherwise "wrangler" will be bundled with your worker.
|
||||
* That's why we split the configuration into two files: `bknd.config.ts` and `config.ts`.
|
||||
* That's why we split the configuration into two files: `userbase.config.ts` and `config.ts`.
|
||||
*/
|
||||
|
||||
import { withPlatformProxy } from "bknd/adapter/cloudflare/proxy";
|
||||
import { withPlatformProxy } from "userbase/adapter/cloudflare/proxy";
|
||||
import config from "./config.ts";
|
||||
|
||||
export default withPlatformProxy(config, {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// <reference types="./worker-configuration.d.ts" />
|
||||
|
||||
import type { CloudflareBkndConfig } from "bknd/adapter/cloudflare";
|
||||
import { code } from "bknd/modes";
|
||||
import { boolean, em, entity, text } from "bknd";
|
||||
import type { CloudflareUserbaseConfig } from "userbase/adapter/cloudflare";
|
||||
import { code } from "userbase/modes";
|
||||
import { boolean, em, entity, text } from "userbase";
|
||||
|
||||
const schema = em({
|
||||
todos: entity("todos", {
|
||||
@@ -13,13 +13,13 @@ const schema = em({
|
||||
|
||||
// register your schema to get automatic type completion
|
||||
// alternatively, you can use the CLI to generate types
|
||||
// learn more at https://docs.bknd.io/usage/cli/#generating-types-types
|
||||
// learn more at https://docs.userbase.io/usage/cli/#generating-types-types
|
||||
type Database = (typeof schema)["DB"];
|
||||
declare module "bknd" {
|
||||
declare module "userbase" {
|
||||
interface DB extends Database {}
|
||||
}
|
||||
|
||||
export default code<CloudflareBkndConfig>({
|
||||
export default code<CloudflareUserbaseConfig>({
|
||||
app: (env) => ({
|
||||
config: {
|
||||
data: schema.toJSON(),
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>bknd + Vite + Cloudflare + React + TS</title>
|
||||
<title>userbase + Vite + Cloudflare + React + TS</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
{
|
||||
"name": "cloudflare-vite-fullstack-bknd-code",
|
||||
"description": "A template for building a React application with Vite, Cloudflare Workers, and bknd",
|
||||
"name": "cloudflare-vite-fullstack-userbase-code",
|
||||
"description": "A template for building a React application with Vite, Cloudflare Workers, and userbase",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"cf:types": "wrangler types",
|
||||
"bknd": "node --experimental-strip-types node_modules/.bin/bknd",
|
||||
"bknd:seed": "NODE_NO_WARNINGS=1 node --experimental-strip-types seed.ts",
|
||||
"userbase": "node --experimental-strip-types node_modules/.bin/userbase",
|
||||
"userbase:seed": "NODE_NO_WARNINGS=1 node --experimental-strip-types seed.ts",
|
||||
"check": "tsc && vite build && wrangler deploy --dry-run",
|
||||
"deploy": "CLOUDFLARE_ENV=production vite build && CLOUDFLARE_ENV=production npm run bknd -- sync --force && wrangler deploy",
|
||||
"deploy": "CLOUDFLARE_ENV=production vite build && CLOUDFLARE_ENV=production npm run userbase -- sync --force && wrangler deploy",
|
||||
"dev": "vite",
|
||||
"preview": "npm run build && vite preview",
|
||||
"postinstall": "npm run cf:types && npm run bknd:seed"
|
||||
"postinstall": "npm run cf:types && npm run userbase:seed"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"bknd": "file:../../app",
|
||||
"userbase": "file:../../app",
|
||||
"hono": "4.10.6",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/// <reference types="./worker-configuration.d.ts" />
|
||||
|
||||
import { createFrameworkApp } from "bknd/adapter";
|
||||
import config from "./bknd.config.ts";
|
||||
import { createFrameworkApp } from "userbase/adapter";
|
||||
import config from "./userbase.config.ts";
|
||||
|
||||
const app = await createFrameworkApp(config, {});
|
||||
|
||||
@@ -15,12 +15,12 @@ const {
|
||||
// only run if the database is empty
|
||||
if (usersCount === 0 && todosCount === 0) {
|
||||
await app.em.mutator("todos").insertMany([
|
||||
{ title: "Learn bknd", done: true },
|
||||
{ title: "Learn userbase", done: true },
|
||||
{ title: "Build something cool", done: false },
|
||||
]);
|
||||
|
||||
await app.module.auth.createUser({
|
||||
email: "test@bknd.io",
|
||||
email: "test@userbase.io",
|
||||
password: "12345678",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Router, Switch, Route } from "wouter";
|
||||
import Home from "./routes/home.tsx";
|
||||
import { lazy, Suspense, useEffect, useState } from "react";
|
||||
const Admin = lazy(() => import("./routes/admin.tsx"));
|
||||
import { useAuth } from "bknd/client";
|
||||
import { useAuth } from "userbase/client";
|
||||
|
||||
export default function App() {
|
||||
const auth = useAuth();
|
||||
|
||||
@@ -2,7 +2,7 @@ import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import "./index.css";
|
||||
import App from "./App.tsx";
|
||||
import { ClientProvider } from "bknd/client";
|
||||
import { ClientProvider } from "userbase/client";
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<StrictMode>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Admin, type BkndAdminProps } from "bknd/ui";
|
||||
import "bknd/dist/styles.css";
|
||||
import { useAuth } from "bknd/client";
|
||||
import { Admin, type UserbaseAdminProps } from "userbase/ui";
|
||||
import "userbase/dist/styles.css";
|
||||
import { useAuth } from "userbase/client";
|
||||
|
||||
export default function AdminPage(props: BkndAdminProps) {
|
||||
export default function AdminPage(props: UserbaseAdminProps) {
|
||||
const auth = useAuth();
|
||||
return <Admin {...props} withProvider={{ user: auth.user }} />;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useAuth, useEntityQuery } from "bknd/client";
|
||||
import bkndLogo from "../assets/bknd.svg";
|
||||
import { useAuth, useEntityQuery } from "userbase/client";
|
||||
import userbaseLogo from "../assets/userbase.svg";
|
||||
import cloudflareLogo from "../assets/cloudflare.svg";
|
||||
import viteLogo from "../assets/vite.svg";
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function Home() {
|
||||
return (
|
||||
<div className="flex-col gap-10 max-w-96 mx-auto w-full min-h-full flex justify-center items-center">
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<img src={bkndLogo} alt="bknd" className="w-48 dark:invert" />
|
||||
<img src={userbaseLogo} alt="userbase" className="w-48 dark:invert" />
|
||||
<div className="font-mono opacity-70">&</div>
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<img src={cloudflareLogo} alt="cloudflare" className="h-10" />
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { serve } from "bknd/adapter/cloudflare";
|
||||
import { serve } from "userbase/adapter/cloudflare";
|
||||
import config from "../../config.ts";
|
||||
|
||||
export default serve(config, () => ({
|
||||
// since bknd is running code-only, we can use a pre-initialized app instance if available
|
||||
// since userbase is running code-only, we can use a pre-initialized app instance if available
|
||||
warm: true,
|
||||
}));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "cloudflare-vite-fullstack-bknd",
|
||||
"name": "cloudflare-vite-fullstack-userbase",
|
||||
"main": "./src/worker/index.ts",
|
||||
"compatibility_date": "2025-10-08",
|
||||
"compatibility_flags": ["nodejs_compat"],
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
# bknd starter: Cloudflare Vite Hybrid
|
||||
A fullstack React + Vite application with bknd integration, showcasing **hybrid mode** and Cloudflare Workers deployment.
|
||||
# userbase starter: Cloudflare Vite Hybrid
|
||||
A fullstack React + Vite application with userbase integration, showcasing **hybrid mode** and Cloudflare Workers deployment.
|
||||
|
||||
## Key Features
|
||||
|
||||
This example demonstrates several advanced bknd features:
|
||||
This example demonstrates several advanced userbase features:
|
||||
|
||||
### 🔄 Hybrid Mode
|
||||
Configure your backend **visually in development** using the Admin UI, then automatically switch to **code-only mode in production** for maximum performance. Changes made in the Admin UI are automatically synced to `bknd-config.json` and type definitions are generated in `bknd-types.d.ts`.
|
||||
Configure your backend **visually in development** using the Admin UI, then automatically switch to **code-only mode in production** for maximum performance. Changes made in the Admin UI are automatically synced to `userbase-config.json` and type definitions are generated in `userbase-types.d.ts`.
|
||||
|
||||
### 📁 Filesystem Access with Vite Plugin
|
||||
Cloudflare's Vite plugin uses `unenv` which disables Node.js APIs like `fs`. This example uses bknd's `devFsVitePlugin` and `devFsWrite` to provide filesystem access during development, enabling automatic syncing of types and configuration.
|
||||
Cloudflare's Vite plugin uses `unenv` which disables Node.js APIs like `fs`. This example uses userbase's `devFsVitePlugin` and `devFsWrite` to provide filesystem access during development, enabling automatic syncing of types and configuration.
|
||||
|
||||
### ⚡ Split Configuration Pattern
|
||||
- **`config.ts`**: Shared configuration that can be safely imported in your worker
|
||||
- **`bknd.config.ts`**: Wraps the configuration with `withPlatformProxy` for CLI usage with Cloudflare bindings (should NOT be imported in your worker)
|
||||
- **`userbase.config.ts`**: Wraps the configuration with `withPlatformProxy` for CLI usage with Cloudflare bindings (should NOT be imported in your worker)
|
||||
|
||||
This pattern prevents bundling `wrangler` into your worker while still allowing CLI access to Cloudflare resources.
|
||||
|
||||
@@ -27,15 +27,15 @@ Inside of your project, you'll see the following folders and files:
|
||||
│ ├── app/ # React frontend application
|
||||
│ │ ├── App.tsx
|
||||
│ │ ├── routes/
|
||||
│ │ │ ├── admin.tsx # bknd Admin UI route
|
||||
│ │ │ ├── admin.tsx # userbase Admin UI route
|
||||
│ │ │ └── home.tsx # Example frontend route
|
||||
│ │ └── main.tsx
|
||||
│ └── worker/
|
||||
│ └── index.ts # Cloudflare Worker entry
|
||||
├── config.ts # Shared bknd configuration (hybrid mode)
|
||||
├── bknd.config.ts # CLI configuration with platform proxy
|
||||
├── bknd-config.json # Auto-generated production config
|
||||
├── bknd-types.d.ts # Auto-generated TypeScript types
|
||||
├── config.ts # Shared userbase configuration (hybrid mode)
|
||||
├── userbase.config.ts # CLI configuration with platform proxy
|
||||
├── userbase-config.json # Auto-generated production config
|
||||
├── userbase-types.d.ts # Auto-generated TypeScript types
|
||||
├── .env.example # Auto-generated secrets template
|
||||
├── vite.config.ts # Includes devFsVitePlugin
|
||||
├── package.json
|
||||
@@ -51,8 +51,8 @@ Inside of your project, you'll see the following folders and files:
|
||||
|
||||
## Admin UI & frontend
|
||||
|
||||
- `/admin` mounts `<Admin />` from `bknd/ui` with `withProvider={{ user }}` so it respects the authenticated user returned by `useAuth`.
|
||||
- `/` showcases `useEntityQuery("todos")`, mutation helpers, and authentication state — demonstrating how the generated client types (`bknd-types.d.ts`) flow into the React code.
|
||||
- `/admin` mounts `<Admin />` from `userbase/ui` with `withProvider={{ user }}` so it respects the authenticated user returned by `useAuth`.
|
||||
- `/` showcases `useEntityQuery("todos")`, mutation helpers, and authentication state — demonstrating how the generated client types (`userbase-types.d.ts`) flow into the React code.
|
||||
|
||||
|
||||
## Configuration Files
|
||||
@@ -60,25 +60,25 @@ Inside of your project, you'll see the following folders and files:
|
||||
### `config.ts`
|
||||
The main configuration file that uses the `hybrid()` mode helper:
|
||||
|
||||
- Loads the generated config via an ESM `reader` (importing `./bknd-config.json`).
|
||||
- Loads the generated config via an ESM `reader` (importing `./userbase-config.json`).
|
||||
- Uses `devFsWrite` as the `writer` so the CLI/plugin can persist files even though Node's `fs` API is unavailable in Miniflare.
|
||||
- Sets `typesFilePath`, `configFilePath`, and `syncSecrets` (writes `.env.example`) so config, types, and secret placeholders stay aligned.
|
||||
- Seeds example data/users in `options.seed` when the database is empty.
|
||||
- Disables the built-in admin controller because the React app renders `/admin` via `bknd/ui`.
|
||||
- Disables the built-in admin controller because the React app renders `/admin` via `userbase/ui`.
|
||||
|
||||
|
||||
```typescript
|
||||
import { hybrid } from "bknd/modes";
|
||||
import { devFsWrite, type CloudflareBkndConfig } from "bknd/adapter/cloudflare";
|
||||
import { hybrid } from "userbase/modes";
|
||||
import { devFsWrite, type CloudflareUserbaseConfig } from "userbase/adapter/cloudflare";
|
||||
|
||||
export default hybrid<CloudflareBkndConfig>({
|
||||
export default hybrid<CloudflareUserbaseConfig>({
|
||||
// Special reader for Cloudflare Workers (no Node.js fs)
|
||||
reader: async () => (await import("./bknd-config.json")).default,
|
||||
reader: async () => (await import("./userbase-config.json")).default,
|
||||
// devFsWrite enables file writing via Vite plugin
|
||||
writer: devFsWrite,
|
||||
// Auto-sync these files in development
|
||||
typesFilePath: "./bknd-types.d.ts",
|
||||
configFilePath: "./bknd-config.json",
|
||||
typesFilePath: "./userbase-types.d.ts",
|
||||
configFilePath: "./userbase-config.json",
|
||||
syncSecrets: {
|
||||
enabled: true,
|
||||
outFile: ".env.example",
|
||||
@@ -93,11 +93,11 @@ export default hybrid<CloudflareBkndConfig>({
|
||||
});
|
||||
```
|
||||
|
||||
### `bknd.config.ts`
|
||||
### `userbase.config.ts`
|
||||
Wraps the configuration for CLI usage with Cloudflare bindings:
|
||||
|
||||
```typescript
|
||||
import { withPlatformProxy } from "bknd/adapter/cloudflare/proxy";
|
||||
import { withPlatformProxy } from "userbase/adapter/cloudflare/proxy";
|
||||
import config from "./config.ts";
|
||||
|
||||
export default withPlatformProxy(config);
|
||||
@@ -107,7 +107,7 @@ export default withPlatformProxy(config);
|
||||
Includes the `devFsVitePlugin` for filesystem access:
|
||||
|
||||
```typescript
|
||||
import { devFsVitePlugin } from "bknd/adapter/cloudflare";
|
||||
import { devFsVitePlugin } from "userbase/adapter/cloudflare";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
@@ -129,8 +129,8 @@ All commands are run from the root of the project, from a terminal:
|
||||
| `npm run build` | Builds the application for production |
|
||||
| `npm run preview` | Builds and previews the production build locally |
|
||||
| `npm run deploy` | Builds, syncs the schema and deploys to Cloudflare Workers|
|
||||
| `npm run bknd` | Runs bknd CLI commands |
|
||||
| `npm run bknd:types` | Generates TypeScript types from your schema |
|
||||
| `npm run userbase` | Runs userbase CLI commands |
|
||||
| `npm run userbase:types` | Generates TypeScript types from your schema |
|
||||
| `npm run cf:types` | Generates Cloudflare Worker types from `wrangler.json` |
|
||||
| `npm run check` | Type checks and does a dry-run deployment |
|
||||
|
||||
@@ -153,17 +153,17 @@ All commands are run from the root of the project, from a terminal:
|
||||
- Define permissions
|
||||
|
||||
4. **Watch for auto-generated files:**
|
||||
- `bknd-config.json` - Production configuration
|
||||
- `bknd-types.d.ts` - TypeScript types
|
||||
- `userbase-config.json` - Production configuration
|
||||
- `userbase-types.d.ts` - TypeScript types
|
||||
- `.env.example` - Required secrets
|
||||
|
||||
5. **Use the CLI** for manual operations:
|
||||
```sh
|
||||
# Generate types manually
|
||||
npm run bknd:types
|
||||
npm run userbase:types
|
||||
|
||||
# Sync the production database schema (only safe operations are applied)
|
||||
CLOUDFLARE_ENV=production npm run bknd -- sync --force
|
||||
CLOUDFLARE_ENV=production npm run userbase -- sync --force
|
||||
```
|
||||
|
||||
## Before you deploy
|
||||
@@ -200,8 +200,8 @@ This will:
|
||||
2. Build the Vite application
|
||||
3. Deploy to Cloudflare Workers using Wrangler
|
||||
|
||||
In production, bknd will:
|
||||
- Use the configuration from `bknd-config.json` (read-only)
|
||||
In production, userbase will:
|
||||
- Use the configuration from `userbase-config.json` (read-only)
|
||||
- Skip config validation for better performance
|
||||
- Expect secrets to be provided via environment variables
|
||||
|
||||
@@ -221,15 +221,15 @@ Check `.env.example` for all required secrets after running the app in developme
|
||||
```mermaid
|
||||
graph LR
|
||||
A[Development] -->|Visual Config| B[Admin UI]
|
||||
B -->|Auto-sync| C[bknd-config.json]
|
||||
B -->|Auto-sync| D[bknd-types.d.ts]
|
||||
B -->|Auto-sync| C[userbase-config.json]
|
||||
B -->|Auto-sync| D[userbase-types.d.ts]
|
||||
C -->|Deploy| E[Production]
|
||||
E -->|Read-only| F[Code-only Mode]
|
||||
```
|
||||
|
||||
1. **In Development:** `mode: "db"` - Configuration stored in database, editable via Admin UI
|
||||
2. **Auto-sync:** Changes automatically written to `bknd-config.json` and types to `bknd-types.d.ts`
|
||||
3. **In Production:** `mode: "code"` - Configuration read from `bknd-config.json`, no database overhead
|
||||
2. **Auto-sync:** Changes automatically written to `userbase-config.json` and types to `userbase-types.d.ts`
|
||||
3. **In Production:** `mode: "code"` - Configuration read from `userbase-config.json`, no database overhead
|
||||
|
||||
## Why devFsVitePlugin?
|
||||
|
||||
@@ -242,8 +242,8 @@ The `devFsVitePlugin` + `devFsWrite` combination provides a workaround by using
|
||||
|
||||
## Want to learn more?
|
||||
|
||||
- [Cloudflare Integration Documentation](https://docs.bknd.io/integration/cloudflare)
|
||||
- [Hybrid Mode Guide](https://docs.bknd.io/usage/introduction#hybrid-mode)
|
||||
- [Mode Helpers Documentation](https://docs.bknd.io/usage/introduction#mode-helpers)
|
||||
- [Cloudflare Integration Documentation](https://docs.userbase.io/integration/cloudflare)
|
||||
- [Hybrid Mode Guide](https://docs.userbase.io/usage/introduction#hybrid-mode)
|
||||
- [Mode Helpers Documentation](https://docs.userbase.io/usage/introduction#mode-helpers)
|
||||
- [Discord Community](https://discord.gg/952SFk8Tb8)
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
"secret": "",
|
||||
"alg": "HS256",
|
||||
"expires": 0,
|
||||
"issuer": "bknd-cloudflare-example",
|
||||
"issuer": "userbase-cloudflare-example",
|
||||
"fields": [
|
||||
"id",
|
||||
"email",
|
||||
|
||||
+5
-5
@@ -1,10 +1,10 @@
|
||||
import type { DB } from "bknd";
|
||||
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 {
|
||||
@@ -17,6 +17,6 @@ interface Database {
|
||||
todos: Todos;
|
||||
}
|
||||
|
||||
declare module "bknd" {
|
||||
declare module "userbase" {
|
||||
interface DB extends Database {}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
/**
|
||||
* This file gets automatically picked up by the bknd CLI. Since we're using cloudflare,
|
||||
* This file gets automatically picked up by the userbase CLI. Since we're using cloudflare,
|
||||
* we want to use cloudflare bindings (such as the database). To do this, we need to wrap
|
||||
* the configuration with the `withPlatformProxy` helper function.
|
||||
*
|
||||
* Don't import this file directly in your app, otherwise "wrangler" will be bundled with your worker.
|
||||
* That's why we split the configuration into two files: `bknd.config.ts` and `config.ts`.
|
||||
* That's why we split the configuration into two files: `userbase.config.ts` and `config.ts`.
|
||||
*/
|
||||
|
||||
import { withPlatformProxy } from "bknd/adapter/cloudflare/proxy";
|
||||
import { withPlatformProxy } from "userbase/adapter/cloudflare/proxy";
|
||||
import config from "./config.ts";
|
||||
|
||||
export default withPlatformProxy(config, {
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
/// <reference types="./worker-configuration.d.ts" />
|
||||
|
||||
import { devFsWrite, type CloudflareBkndConfig } from "bknd/adapter/cloudflare";
|
||||
import { hybrid } from "bknd/modes";
|
||||
import { devFsWrite, type CloudflareUserbaseConfig } from "userbase/adapter/cloudflare";
|
||||
import { hybrid } from "userbase/modes";
|
||||
|
||||
export default hybrid<CloudflareBkndConfig>({
|
||||
export default hybrid<CloudflareUserbaseConfig>({
|
||||
// normally you would use e.g. `readFile` from `node:fs/promises`, however, cloudflare using vite plugin removes all Node APIs, therefore we need to use the module system to import the config file
|
||||
reader: async () => {
|
||||
return (await import("./bknd-config.json").then((module) => module.default)) as any;
|
||||
return (await import("./userbase-config.json").then((module) => module.default)) as any;
|
||||
},
|
||||
// a writer is required to sync the types and config. We're using a vite plugin that proxies writing files (since Node APIs are not available)
|
||||
writer: devFsWrite,
|
||||
// the generated types are loaded using our tsconfig, and is automatically available in all bknd APIs
|
||||
typesFilePath: "./bknd-types.d.ts",
|
||||
// the generated types are loaded using our tsconfig, and is automatically available in all userbase APIs
|
||||
typesFilePath: "./userbase-types.d.ts",
|
||||
// on every change, this config file is updated. When it's time to deploy, this will be inlined into your worker
|
||||
configFilePath: "./bknd-config.json",
|
||||
configFilePath: "./userbase-config.json",
|
||||
// secrets will always be extracted from the configuration, we're writing an example env file to know which secrets we need to provide prior to deploying
|
||||
syncSecrets: {
|
||||
enabled: true,
|
||||
@@ -32,13 +32,13 @@ export default hybrid<CloudflareBkndConfig>({
|
||||
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",
|
||||
});
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>bknd + Vite + Cloudflare + React + TS</title>
|
||||
<title>userbase + Vite + Cloudflare + React + TS</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
{
|
||||
"name": "cloudflare-vite-fullstack-bknd",
|
||||
"description": "A template for building a React application with Vite, Cloudflare Workers, and bknd",
|
||||
"name": "cloudflare-vite-fullstack-userbase",
|
||||
"description": "A template for building a React application with Vite, Cloudflare Workers, and userbase",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"cf:types": "wrangler types",
|
||||
"bknd": "node --experimental-strip-types node_modules/.bin/bknd",
|
||||
"bknd:types": "bknd -- types",
|
||||
"userbase": "node --experimental-strip-types node_modules/.bin/userbase",
|
||||
"userbase:types": "userbase -- types",
|
||||
"check": "tsc && vite build && wrangler deploy --dry-run",
|
||||
"deploy": "CLOUDFLARE_ENV=production vite build && CLOUDFLARE_ENV=production npm run bknd -- sync --force && wrangler deploy",
|
||||
"deploy": "CLOUDFLARE_ENV=production vite build && CLOUDFLARE_ENV=production npm run userbase -- sync --force && wrangler deploy",
|
||||
"dev": "vite",
|
||||
"preview": "npm run build && vite preview",
|
||||
"postinstall": "npm run cf:types"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"bknd": "file:../../app",
|
||||
"userbase": "file:../../app",
|
||||
"hono": "4.10.6",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Router, Switch, Route } from "wouter";
|
||||
import Home from "./routes/home.tsx";
|
||||
import { lazy, Suspense, useEffect, useState } from "react";
|
||||
const Admin = lazy(() => import("./routes/admin.tsx"));
|
||||
import { useAuth } from "bknd/client";
|
||||
import { useAuth } from "userbase/client";
|
||||
|
||||
export default function App() {
|
||||
const auth = useAuth();
|
||||
|
||||
@@ -2,7 +2,7 @@ import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import "./index.css";
|
||||
import App from "./App.tsx";
|
||||
import { ClientProvider } from "bknd/client";
|
||||
import { ClientProvider } from "userbase/client";
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<StrictMode>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Admin, type BkndAdminProps } from "bknd/ui";
|
||||
import "bknd/dist/styles.css";
|
||||
import { useAuth } from "bknd/client";
|
||||
import { Admin, type UserbaseAdminProps } from "userbase/ui";
|
||||
import "userbase/dist/styles.css";
|
||||
import { useAuth } from "userbase/client";
|
||||
|
||||
export default function AdminPage(props: BkndAdminProps) {
|
||||
export default function AdminPage(props: UserbaseAdminProps) {
|
||||
const auth = useAuth();
|
||||
return <Admin {...props} withProvider={{ user: auth.user }} />;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useAuth, useEntityQuery } from "bknd/client";
|
||||
import bkndLogo from "../assets/bknd.svg";
|
||||
import { useAuth, useEntityQuery } from "userbase/client";
|
||||
import userbaseLogo from "../assets/userbase.svg";
|
||||
import cloudflareLogo from "../assets/cloudflare.svg";
|
||||
import viteLogo from "../assets/vite.svg";
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function Home() {
|
||||
return (
|
||||
<div className="flex-col gap-10 max-w-96 mx-auto w-full min-h-full flex justify-center items-center">
|
||||
<div className="flex flex-row items-center gap-3">
|
||||
<img src={bkndLogo} alt="bknd" className="w-48 dark:invert" />
|
||||
<img src={userbaseLogo} alt="userbase" className="w-48 dark:invert" />
|
||||
<div className="font-mono opacity-70">&</div>
|
||||
<div className="flex flex-row gap-2 items-center">
|
||||
<img src={cloudflareLogo} alt="cloudflare" className="h-10" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { serve } from "bknd/adapter/cloudflare";
|
||||
import { serve } from "userbase/adapter/cloudflare";
|
||||
import config from "../../config.ts";
|
||||
|
||||
export default serve(config);
|
||||
|
||||
@@ -6,6 +6,6 @@
|
||||
{ "path": "./tsconfig.worker.json" }
|
||||
],
|
||||
"compilerOptions": {
|
||||
"types": ["./worker-configuration.d.ts", "./bknd-types.d.ts", "node"]
|
||||
"types": ["./worker-configuration.d.ts", "./userbase-types.d.ts", "node"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { defineConfig } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import { cloudflare } from "@cloudflare/vite-plugin";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import { devFsVitePlugin } from "bknd/adapter/cloudflare";
|
||||
import { devFsVitePlugin } from "userbase/adapter/cloudflare";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "cloudflare-vite-fullstack-bknd",
|
||||
"name": "cloudflare-vite-fullstack-userbase",
|
||||
"main": "./src/worker/index.ts",
|
||||
"compatibility_date": "2025-10-08",
|
||||
"compatibility_flags": ["nodejs_compat"],
|
||||
|
||||
@@ -167,5 +167,5 @@ dist
|
||||
|
||||
.dev.vars
|
||||
.wrangler/
|
||||
bknd-types.d.ts
|
||||
userbase-types.d.ts
|
||||
worker-configuration.d.ts
|
||||
@@ -1,5 +1,5 @@
|
||||
# bknd starter: Cloudflare Workers
|
||||
A minimal Node.js project with bknd integration.
|
||||
# userbase starter: Cloudflare Workers
|
||||
A minimal Node.js project with userbase integration.
|
||||
|
||||
## Project Structure
|
||||
|
||||
@@ -13,7 +13,7 @@ Inside of your Node.js project, you'll see the following folders and files:
|
||||
└── wrangler.json
|
||||
```
|
||||
|
||||
To update `bknd` config, check `src/index.ts`.
|
||||
To update `userbase` config, check `src/index.ts`.
|
||||
|
||||
## Commands
|
||||
|
||||
@@ -34,4 +34,4 @@ npx wrangler d1 create my-database
|
||||
|
||||
## Want to learn more?
|
||||
|
||||
Feel free to check [our documentation](https://docs.bknd.io/integration/cloudflare) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
|
||||
Feel free to check [our documentation](https://docs.userbase.io/integration/cloudflare) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* We're using separate files, so that "wrangler" doesn't get bundled with your worker.
|
||||
*/
|
||||
|
||||
import { withPlatformProxy } from "bknd/adapter/cloudflare/proxy";
|
||||
import { withPlatformProxy } from "userbase/adapter/cloudflare/proxy";
|
||||
import config from "./config.ts";
|
||||
|
||||
export default withPlatformProxy(config);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { CloudflareBkndConfig } from "bknd/adapter/cloudflare";
|
||||
import type { CloudflareUserbaseConfig } from "userbase/adapter/cloudflare";
|
||||
|
||||
export default {
|
||||
d1: {
|
||||
session: true,
|
||||
},
|
||||
} satisfies CloudflareBkndConfig;
|
||||
} satisfies CloudflareUserbaseConfig;
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
"scripts": {
|
||||
"deploy": "wrangler deploy",
|
||||
"dev": "wrangler dev",
|
||||
"bknd-typegen": "PROXY=1 npx bknd types",
|
||||
"typegen": "wrangler types && npm run bknd-typegen",
|
||||
"userbase-typegen": "PROXY=1 npx userbase types",
|
||||
"typegen": "wrangler types && npm run userbase-typegen",
|
||||
"predev": "npm run typegen"
|
||||
},
|
||||
"dependencies": {
|
||||
"bknd": "file:../../app"
|
||||
"userbase": "file:../../app"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.9.2",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { serve } from "bknd/adapter/cloudflare";
|
||||
import { serve } from "userbase/adapter/cloudflare";
|
||||
import config from "../config";
|
||||
|
||||
export default serve(config);
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
"exclude": ["test"],
|
||||
"include": [
|
||||
"worker-configuration.d.ts",
|
||||
"bknd-types.d.ts",
|
||||
"bknd.config.ts",
|
||||
"userbase-types.d.ts",
|
||||
"userbase.config.ts",
|
||||
"src/**/*.ts"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "node_modules/wrangler/config-schema.json",
|
||||
"name": "bknd-cf-worker-example",
|
||||
"name": "userbase-cf-worker-example",
|
||||
"main": "src/index.ts",
|
||||
"compatibility_date": "2025-08-03",
|
||||
"compatibility_flags": ["nodejs_compat"],
|
||||
@@ -15,14 +15,14 @@
|
||||
"d1_databases": [
|
||||
{
|
||||
"binding": "DB",
|
||||
"database_name": "bknd-dev-weur",
|
||||
"database_name": "userbase-dev-weur",
|
||||
"database_id": "81d8dfcc-4eaf-4453-8f0f-8f6d463fb867"
|
||||
}
|
||||
],
|
||||
"r2_buckets": [
|
||||
{
|
||||
"binding": "BUCKET",
|
||||
"bucket_name": "bknd-cf-example"
|
||||
"bucket_name": "userbase-cf-example"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"dev": "deno serve -A --watch main.ts"
|
||||
},
|
||||
"imports": {
|
||||
"bknd": "npm:bknd@0.19.0-rc.1"
|
||||
"userbase": "npm:userbase@0.19.0-rc.1"
|
||||
},
|
||||
"links": ["../../app/"],
|
||||
"unstable": ["raw-imports"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createRuntimeApp, serveStaticViaImport } from "bknd/adapter";
|
||||
import { createRuntimeApp, serveStaticViaImport } from "userbase/adapter";
|
||||
|
||||
const app = await createRuntimeApp({
|
||||
connection: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# bknd starter: Next.js
|
||||
A minimal Next.js (app router) project with bknd integration.
|
||||
# userbase starter: Next.js
|
||||
A minimal Next.js (app router) project with userbase integration.
|
||||
|
||||
## Project Structure
|
||||
|
||||
@@ -17,16 +17,16 @@ Inside of your Next.js project, you'll see the following folders and files:
|
||||
│ │ │ └── [[...admin]]
|
||||
│ │ │ └── page.tsx
|
||||
│ │ ├── api
|
||||
│ │ │ └── [[...bknd]]
|
||||
│ │ │ └── [[...userbase]]
|
||||
│ │ │ └── route.ts
|
||||
│ │ └── ...
|
||||
│ └── bknd.ts
|
||||
│ └── userbase.ts
|
||||
└── package.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/bknd.ts`
|
||||
* API routes are exposed at `src/api/[[...bknd]]/route.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/userbase.ts`
|
||||
* API routes are exposed at `src/api/[[...userbase]]/route.ts`
|
||||
* Admin UI is rendered at `src/admin/[[...admin]]/page.tsx`
|
||||
|
||||
## Commands
|
||||
@@ -42,4 +42,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/nextjs) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
|
||||
Feel free to check [our documentation](https://docs.userbase.io/integration/nextjs) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
|
||||
@@ -1,13 +1,13 @@
|
||||
import type { NextjsBkndConfig } from "bknd/adapter/nextjs";
|
||||
import { boolean, em, entity, text } from "bknd";
|
||||
import { registerLocalMediaAdapter } from "bknd/adapter/node";
|
||||
import { secureRandomString } from "bknd/utils";
|
||||
import type { NextjsUserbaseConfig } from "userbase/adapter/nextjs";
|
||||
import { boolean, em, entity, text } from "userbase";
|
||||
import { registerLocalMediaAdapter } from "userbase/adapter/node";
|
||||
import { secureRandomString } from "userbase/utils";
|
||||
|
||||
// The local media adapter works well in development, and server based
|
||||
// deployments. However, on vercel or any other serverless deployments,
|
||||
// you shouldn't use a filesystem based media adapter.
|
||||
//
|
||||
// Additionally, if you run the bknd api on the "edge" runtime,
|
||||
// Additionally, if you run the userbase api on the "edge" runtime,
|
||||
// this would not work as well.
|
||||
//
|
||||
// For production, it is recommended to uncomment the line below.
|
||||
@@ -22,7 +22,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 {}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ export default {
|
||||
auth: {
|
||||
enabled: true,
|
||||
jwt: {
|
||||
issuer: "bknd-nextjs-example",
|
||||
issuer: "userbase-nextjs-example",
|
||||
secret: secureRandomString(64),
|
||||
},
|
||||
cookie: {
|
||||
@@ -60,15 +60,15 @@ 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",
|
||||
});
|
||||
},
|
||||
},
|
||||
} as const satisfies NextjsBkndConfig;
|
||||
} as const satisfies NextjsUserbaseConfig;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"bknd": "file:../../app",
|
||||
"userbase": "file:../../app",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"next": "15.2.0"
|
||||
|
||||
@@ -21,8 +21,8 @@ export default async function Layout({
|
||||
<div className="ml-3.5 mr-2 font-mono opacity-70">&</div>
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/bknd.svg"
|
||||
alt="bknd logo"
|
||||
src="/userbase.svg"
|
||||
alt="userbase logo"
|
||||
width={183}
|
||||
height={59}
|
||||
priority
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getApi } from "@/bknd";
|
||||
import { getApi } from "@/userbase";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { Fragment } from "react";
|
||||
import { List } from "@/components/List";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getApi } from "@/bknd";
|
||||
import { getApi } from "@/userbase";
|
||||
import { Buttons } from "@/components/Buttons";
|
||||
import { List } from "@/components/List";
|
||||
import Link from "next/link";
|
||||
@@ -32,7 +32,7 @@ export default async function SSRPage() {
|
||||
<p className="text-xs opacity-50">
|
||||
Sign in with:{" "}
|
||||
<b>
|
||||
<code>test@bknd.io</code>
|
||||
<code>test@userbase.io</code>
|
||||
</b>{" "}
|
||||
/{" "}
|
||||
<b>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { type BkndAdminProps, Admin } from "bknd/ui";
|
||||
import { type UserbaseAdminProps, Admin } from "userbase/ui";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function AdminComponent(props: BkndAdminProps) {
|
||||
export function AdminComponent(props: UserbaseAdminProps) {
|
||||
const [ready, setReady] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AdminComponent } from "./Admin";
|
||||
import { getApi } from "@/bknd";
|
||||
import "bknd/dist/styles.css";
|
||||
import { getApi } from "@/userbase";
|
||||
import "userbase/dist/styles.css";
|
||||
|
||||
export default async function AdminPage() {
|
||||
const api = await getApi({ verify: true });
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { config } from "@/bknd";
|
||||
import { serve } from "bknd/adapter/nextjs";
|
||||
import { config } from "@/userbase";
|
||||
import { serve } from "userbase/adapter/nextjs";
|
||||
|
||||
// since we're using the local media adapter in this example,
|
||||
// we can't use the edge runtime.
|
||||
@@ -8,7 +8,7 @@ import { serve } from "bknd/adapter/nextjs";
|
||||
const handler = serve({
|
||||
...config,
|
||||
cleanRequest: {
|
||||
searchParams: ["bknd"],
|
||||
searchParams: ["userbase"],
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ const geistMono = Geist_Mono({
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next & bknd App",
|
||||
description: "Presented by create next app & bknd",
|
||||
title: "Create Next & userbase App",
|
||||
description: "Presented by create next app & userbase",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { getApp as getBkndApp } from "bknd/adapter/nextjs";
|
||||
import { 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 }) {
|
||||
|
||||
@@ -19,7 +19,7 @@ export const Buttons = () => (
|
||||
</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"
|
||||
href="https://docs.userbase.io/integration/nextjs"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
||||
@@ -25,12 +25,12 @@ export function Footer() {
|
||||
</Link>
|
||||
<Link
|
||||
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
|
||||
href="https://bknd.io"
|
||||
href="https://userbase.io"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image aria-hidden src="/globe.svg" alt="Globe icon" width={16} height={16} />
|
||||
Go to bknd.io →
|
||||
Go to userbase.io →
|
||||
</Link>
|
||||
</footer>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# bknd starter: Node.js
|
||||
A minimal Node.js project with bknd integration.
|
||||
# userbase starter: Node.js
|
||||
A minimal Node.js project with userbase integration.
|
||||
|
||||
## Project Structure
|
||||
|
||||
@@ -11,7 +11,7 @@ Inside of your Node.js project, you'll see the following folders and files:
|
||||
└── package.json
|
||||
```
|
||||
|
||||
To update `bknd` config, check `index.js`.
|
||||
To update `userbase` config, check `index.js`.
|
||||
|
||||
## Commands
|
||||
|
||||
@@ -25,4 +25,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/node) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
|
||||
Feel free to check [our documentation](https://docs.userbase.io/integration/node) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { serve } from "bknd/adapter/node";
|
||||
import { serve } from "userbase/adapter/node";
|
||||
|
||||
// Actually, all it takes is the following line:
|
||||
// serve();
|
||||
|
||||
// this is optional, if omitted, it uses an in-memory database
|
||||
/** @type {import("bknd/adapter/node").NodeBkndConfig} */
|
||||
/** @type {import("userbase/adapter/node").NodeUserbaseConfig} */
|
||||
const config = {
|
||||
connection: {
|
||||
url: "data.db",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"dev": "tsx --watch index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"bknd": "file:../../app",
|
||||
"userbase": "file:../../app",
|
||||
"@hono/node-server": "^1.13.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
+12
-12
@@ -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).
|
||||
@@ -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>
|
||||
|
||||
@@ -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,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 }>;
|
||||
|
||||
@@ -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">&</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.']" />
|
||||
|
||||
@@ -19,8 +19,8 @@ onMounted(() => {
|
||||
<div class="ml-3.5 mr-2 font-mono opacity-70">&</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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"],
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 });
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bknd/plasmic": "workspace:*",
|
||||
"@userbase/plasmic": "workspace:*",
|
||||
"@plasmicapp/loader-react": "^1.0.373",
|
||||
"bknd": "workspace:*"
|
||||
"userbase": "workspace:*"
|
||||
},
|
||||
"devDependencies": {}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { registerAll } from "@bknd/plasmic";
|
||||
import { registerAll } from "@userbase/plasmic";
|
||||
import {
|
||||
type ComponentRenderData,
|
||||
PlasmicCanvasHost,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
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 config={{ basepath: "/admin" }} />;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ClientProvider } from "bknd/client";
|
||||
import { ClientProvider } from "userbase/client";
|
||||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import App from "./App.tsx";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { serve } from "bknd/adapter/vite";
|
||||
import { App, boolean, em, entity, text } from "bknd";
|
||||
import { secureRandomString } from "bknd/utils";
|
||||
import { serve } from "userbase/adapter/vite";
|
||||
import { App, boolean, em, entity, text } from "userbase";
|
||||
import { secureRandomString } from "userbase/utils";
|
||||
|
||||
export default serve({
|
||||
config: {
|
||||
@@ -20,7 +20,7 @@ export default serve({
|
||||
options: {
|
||||
seed: async (ctx) => {
|
||||
await ctx.em.mutator("todos" as any).insertMany([
|
||||
{ title: "Learn bknd", done: true },
|
||||
{ title: "Learn userbase", done: true },
|
||||
{ title: "Build something cool", done: false },
|
||||
]);
|
||||
},
|
||||
@@ -32,7 +32,7 @@ export default serve({
|
||||
async () => {
|
||||
// ... to create an initial user
|
||||
await app.module.auth.createUser({
|
||||
email: "ds@bknd.io",
|
||||
email: "ds@userbase.io",
|
||||
password: "12345678",
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
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";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { serve } from "bknd/adapter/bun";
|
||||
import { createCustomPostgresConnection } from "bknd";
|
||||
import { serve } from "userbase/adapter/bun";
|
||||
import { createCustomPostgresConnection } from "userbase";
|
||||
import { NeonDialect } from "kysely-neon";
|
||||
|
||||
const neon = createCustomPostgresConnection("neon", NeonDialect);
|
||||
@@ -9,6 +9,6 @@ export default serve({
|
||||
connectionString: process.env.NEON,
|
||||
}),
|
||||
// ignore this, it's only required within this repository
|
||||
// because bknd is installed via "workspace:*"
|
||||
// because userbase is installed via "workspace:*"
|
||||
distPath: "../../app/dist",
|
||||
});
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"@xata.io/client": "^0.0.0-next.v93343b9646f57a1e5c51c35eccf0767c2bb80baa",
|
||||
"@xata.io/kysely": "^0.2.1",
|
||||
"kysely-neon": "^1.3.0",
|
||||
"bknd": "file:../app",
|
||||
"userbase": "file:../app",
|
||||
"kysely": "0.27.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"paths": {
|
||||
"bknd": ["../app/src/index.ts"],
|
||||
"bknd/*": ["../app/src/*"]
|
||||
"userbase": ["../app/src/index.ts"],
|
||||
"userbase/*": ["../app/src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["./src/**/*.ts"],
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { serve } from "bknd/adapter/bun";
|
||||
import { createCustomPostgresConnection } from "bknd";
|
||||
import { serve } from "userbase/adapter/bun";
|
||||
import { createCustomPostgresConnection } from "userbase";
|
||||
import { XataDialect } from "@xata.io/kysely";
|
||||
import { buildClient } from "@xata.io/client";
|
||||
|
||||
@@ -19,6 +19,6 @@ const xata = createCustomPostgresConnection("xata", XataDialect, {
|
||||
export default serve({
|
||||
connection: xata(xataClient),
|
||||
// ignore this, it's only required within this repository
|
||||
// because bknd is installed via "workspace:*"
|
||||
// because userbase is installed via "workspace:*"
|
||||
distPath: "../../../app/dist",
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# bknd starter: React Router
|
||||
A minimal React Router project with bknd integration.
|
||||
# userbase starter: React Router
|
||||
A minimal React Router project with userbase integration.
|
||||
|
||||
## Project Structure
|
||||
|
||||
@@ -9,7 +9,7 @@ Inside of your React Router project, you'll see the following folders and files:
|
||||
/
|
||||
├── public/
|
||||
├── app/
|
||||
│ ├── bknd.ts
|
||||
│ ├── userbase.ts
|
||||
│ ├── root.tsx
|
||||
│ └── routes/
|
||||
│ ├── _index.tsx
|
||||
@@ -18,7 +18,7 @@ Inside of your React Router project, you'll see the following folders and files:
|
||||
└── package.json
|
||||
```
|
||||
|
||||
To update `bknd` config, check `app/routes/api.$.ts` and `app/routes/admin.$.ts`.
|
||||
To update `userbase` config, check `app/routes/api.$.ts` and `app/routes/admin.$.ts`.
|
||||
|
||||
## Commands
|
||||
|
||||
@@ -32,4 +32,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/remix) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
|
||||
Feel free to check [our documentation](https://docs.userbase.io/integration/remix) or jump into our [Discord server](https://discord.gg/952SFk8Tb8).
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { getApp as getBkndApp } from "bknd/adapter/react-router";
|
||||
import config from "../bknd.config";
|
||||
import { getApp as getUserbaseApp } from "userbase/adapter/react-router";
|
||||
import config from "../userbase.config";
|
||||
|
||||
export async function getApp() {
|
||||
return await getBkndApp(config, process.env as any);
|
||||
return await getUserbaseApp(config, process.env as any);
|
||||
}
|
||||
|
||||
export async function getApi(args?: { request: Request }, opts?: { verify?: boolean }) {
|
||||
|
||||
@@ -5,13 +5,13 @@ import {
|
||||
useFetcher,
|
||||
useLoaderData,
|
||||
} from "react-router";
|
||||
import { getApi } from "~/bknd";
|
||||
import { getApi } from "~/userbase";
|
||||
|
||||
// biome-ignore lint/correctness/noEmptyPattern: <explanation>
|
||||
export function meta({}: Route.MetaArgs) {
|
||||
return [
|
||||
{ title: "New bknd React Router App" },
|
||||
{ name: "description", content: "Welcome to bknd & React Router!" },
|
||||
{ title: "New userbase React Router App" },
|
||||
{ name: "description", content: "Welcome to userbase & React Router!" },
|
||||
];
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export default function Index() {
|
||||
<div className="flex h-screen items-center justify-center">
|
||||
<div className="flex flex-col items-center gap-16">
|
||||
<header className="flex flex-col items-center gap-9">
|
||||
<img src="/bknd.svg" alt="bknd" className="block w-48 dark:invert" />
|
||||
<img src="/userbase.svg" alt="userbase" className="block w-48 dark:invert" />
|
||||
<div className="h-[144px] w-96">
|
||||
<img
|
||||
src="/logo-light.svg"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
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 "bknd/dist/styles.css";
|
||||
const Admin = lazy(() => import("userbase/ui").then((mod) => ({ default: mod.Admin })));
|
||||
import "userbase/dist/styles.css";
|
||||
|
||||
export const loader = async (args: LoaderFunctionArgs) => {
|
||||
const api = await getApi(args, { verify: true });
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getApp } from "~/bknd";
|
||||
import { getApp } from "~/userbase";
|
||||
|
||||
const handler = async (args: { request: Request }) => {
|
||||
const app = await getApp();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { registerLocalMediaAdapter } from "bknd/adapter/node";
|
||||
import type { ReactRouterBkndConfig } from "bknd/adapter/react-router";
|
||||
import { boolean, em, entity, text } from "bknd";
|
||||
import { secureRandomString } from "bknd/utils";
|
||||
import { registerLocalMediaAdapter } from "userbase/adapter/node";
|
||||
import type { ReactRouterUserbaseConfig } from "userbase/adapter/react-router";
|
||||
import { boolean, em, entity, text } from "userbase";
|
||||
import { secureRandomString } from "userbase/utils";
|
||||
|
||||
// since we're running in node, we can register the local media adapter
|
||||
const local = registerLocalMediaAdapter();
|
||||
@@ -15,7 +15,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 {}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export default {
|
||||
auth: {
|
||||
enabled: true,
|
||||
jwt: {
|
||||
issuer: "bknd-remix-example",
|
||||
issuer: "userbase-remix-example",
|
||||
secret: secureRandomString(64),
|
||||
},
|
||||
},
|
||||
@@ -50,15 +50,15 @@ 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",
|
||||
});
|
||||
},
|
||||
},
|
||||
} as const satisfies ReactRouterBkndConfig<{ DB_URL?: string }>;
|
||||
} as const satisfies ReactRouterUserbaseConfig<{ DB_URL?: string }>;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"@react-router/fs-routes": "^7.3.0",
|
||||
"@react-router/node": "^7.3.0",
|
||||
"@react-router/serve": "^7.3.0",
|
||||
"bknd": "file:../../app",
|
||||
"userbase": "file:../../app",
|
||||
"isbot": "^5.1.17",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
|
||||
@@ -1 +1 @@
|
||||
# local bknd POC (WIP)
|
||||
# local userbase POC (WIP)
|
||||
@@ -10,7 +10,7 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"bknd": "file:../../app",
|
||||
"userbase": "file:../../app",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"sqlocal": "^0.16.0",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user