diff --git a/README.md b/README.md index 7f47c83..4689c7f 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,9 @@ -[![npm version](https://img.shields.io/npm/v/bknd.svg)](https://npmjs.org/package/bknd -"View this project on NPM") +[![npm version](https://img.shields.io/npm/v/bknd.svg)](https://npmjs.org/package/bknd) [![npm downloads](https://img.shields.io/npm/dm/bknd)](https://www.npmjs.com/package/bknd) ![bknd](https://raw.githubusercontent.com/bknd-io/bknd/refs/heads/main/docs/_assets/poster.png) -bknd simplifies app development by providing fully functional backend for data management, -authentication, workflows and media. Since it's lightweight and built on Web Standards, it can -be deployed nearly anywhere, including running inside your framework of choice. No more -deploying multiple separate services! +bknd simplifies app development by providing fully functional backend for database management, authentication, media and workflows. Being lightweight and built on Web Standards, it can be deployed nearly anywhere, including running inside your framework of choice. No more deploying multiple separate services! **For documentation and examples, please visit https://docs.bknd.io.** @@ -15,33 +11,115 @@ deploying multiple separate services! > Please keep in mind that **bknd** is still under active development > and therefore full backward compatibility is not guaranteed before reaching v1.0.0. -## ✨ Features -**📊 Data**: Define, query, and control your data with ease. - - Define entities with fields and relationships, synced directly to your database. - - Supported field types: `primary`, `text`, `number`, `date`, `boolean`, `enum`, `json`, `jsonschema`. - - Relationship types: `one-to-one`, `many-to-one`, `many-to-many`, and `polymorphic`. - - Advanced querying with the **Repository**: filtering, sorting, pagination, and relational data handling. - - Seamlessly manage data with mutators and a robust event system. - - Extend database functionality with batching, introspection, and support for multiple SQL dialects. +## Size +![gzipped size of bknd](https://img.badgesize.io/https://unpkg.com/bknd@0.6.1/dist/index.js?compression=gzip&label=bknd) +![gzipped size of bknd/client](https://img.badgesize.io/https://unpkg.com/bknd@0.6.1/dist/ui/client/index.js?compression=gzip&label=bknd/client) +![gzipped size of bknd/elements](https://img.badgesize.io/https://unpkg.com/bknd@0.6.1/dist/ui/elements/index.js?compression=gzip&label=bknd/elements) +![gzipped size of bknd/ui](https://img.badgesize.io/https://unpkg.com/bknd@0.6.1/dist/ui/index.js?compression=gzip&label=bknd/ui) -**🔐 Auth**: Easily implement reliable authentication strategies. - - Built-in `user` entity with customizable fields. - - Supports multiple authentication strategies: - - Email/password (with hashed storage). - - OAuth/OIDC (Google, GitHub, and more). - - Secure JWT generation and session management. +The unpacked size on npm is misleading, as the `bknd` package includes the backend, the ui components as well as the whole backend bundled into the cli including static assets. -**🖼️ Media**: Effortlessly manage and serve all your media files. - - Upload files with ease. - - Adapter-based support for S3, S3-compatible storage (e.g., R2, Tigris), and Cloudinary. +## Motivation +Creating digital products always requires developing both the backend (the logic) and the frontend (the appearance). Building a backend from scratch demands deep knowledge in areas such as authentication and database management. Using a backend framework can speed up initial development, but it still requires ongoing effort to work within its constraints (e.g., *"how to do X with Y?"*), which can quickly slow you down. Choosing a backend system is a tough decision, as you might not be aware of its limitations until you encounter them. -**🔄 Flows** (UI integration coming soon!): Design and run workflows with seamless automation. - - Create and run workflows with trigger-based automation: - - Manual triggers or events from data, auth, media, or server actions. - - HTTP triggers for external integrations. - - Define tasks in sequence, parallel, or loops, with conditional execution. - - Use reusable sub-workflows to organize complex processes. - - Leverage OpenAPI specifications for API-based tasks. +**The solution:** A backend system that only assumes and implements primitive details, integrates into multiple environments, and adheres to industry standards. + +## Features +* ⚡ Instant backend with full REST API: + * **Data**: Define, query, and control your data with ease. + * **Auth**: Easily implement reliable authentication strategies. + * **Media**: Effortlessly manage and serve all your media files. + * **Flows**: Design and run workflows with seamless automation. (UI integration coming soon!) +* 🌐 Built on Web Standards for maximum compatibility +* 🏃‍♂️ Multiple run modes + * standalone using the CLI + * using a JavaScript runtime (Node, Bun, workerd) + * using a React framework (Astro, Remix, Next.js) +* 📦 Official API and React SDK with type-safety +* ⚛️ React elements for auto-configured authentication and media components + +## Structure +The package is mainly split into 4 parts, each serving a specific purpose: + +| Import | Purpose | +|-----------------------------|------------------------------------------------------| +| `bknd`
`bknd/adapter/*` | Backend including all APIs | +| `bknd/ui` | Admin UI components for react frameworks at | +| `bknd/client` | TypeScript SDK and React hooks for the API endpoints | +| `bknd/elements` | React components for authentication and media | + + +### The backend (`bknd`) +Serve the backend as an API for any JS runtime or framework. The latter is especially handy, as it allows you to deploy your frontend and backend bundled together. Furthermore it allows adding additional logic in a way you're already familar with. Just add another route and you're good to go. + +Here is an example of serving the API using node: +```js index.js +import { serve } from "bknd/adapter/node" +serve(); +``` + +### Integrated admin UI (`bknd/ui`) +The admin UI allows to manage your data including full configuration of your backend using a graphical user interface. Using `vite`, your admin route looks like this: +```tsx +import { Admin } from "bknd/ui" +import "bknd/dist/styles.css"; + +export default function AdminPage() { + return +} +``` + +### Using the REST API or TypeScript SDK (`bknd/client`) +If you're not using a JavaScript environment, you can still access any endpoint using the REST API: +```bash +curl -XGET /api/data/ +{ + "data": [ + { "id": 1, ... }, + { "id": 2, ... } + ], + "meta": { /* ... */ } +} +``` + +In a JavaScript environment, you can use the TypeScript SDK with type-safety. The above example would look like this: +```ts +import { Api } from "bknd/client"; + +const api = new Api({ host: "" }); +const { data } = await api.data.readMany(""); +``` + +If you're using React, there are 2 hooks exposed (`useApi`, `useEntity`), as well as an `swr` wrapper around each (`useApiQuery`, `useEntityQuery`). The `swr` wrapped hooks automatically handled query invalidation: + +```tsx +import { useState } from "react"; +import { useEntityQuery } from "bknd/client"; + +export default function App() { + const { data } = useEntityQuery("todos"); + return
    + {data?.map(todo => ( +
  • {todo.name}
  • + ))} +
+} +``` + +### React elements (`bknd/elements`) +You don't have to figure out API details to include media uploads to your app. For an user avatar upload, this is all you need: +```tsx +import { Media } from "bknd/elements" + +export function UserAvatar() { + return +} +``` +The import path also exports components for login and registration forms which are automatically pointed to the `bknd` defaults. ## 🚀 Quick start diff --git a/docs/development.mdx b/docs/development.mdx deleted file mode 100644 index c2f2ccd..0000000 --- a/docs/development.mdx +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: 'Development' -description: 'Preview changes locally to update your docs' ---- - - - **Prerequisite**: Please install Node.js (version 19 or higher) before proceeding. - - -Follow these steps to install and run Mintlify on your operating system: - -**Step 1**: Install Mintlify: - - - - ```bash npm - npm i -g mintlify - ``` - -```bash yarn -yarn global add mintlify -``` - - - -**Step 2**: Navigate to the docs directory (where the `mint.json` file is located) and execute the following command: - -```bash -mintlify dev -``` - -A local preview of your documentation will be available at `http://localhost:3000`. - -### Custom Ports - -By default, Mintlify uses port 3000. You can customize the port Mintlify runs on by using the `--port` flag. To run Mintlify on port 3333, for instance, use this command: - -```bash -mintlify dev --port 3333 -``` - -If you attempt to run Mintlify on a port that's already in use, it will use the next available port: - -```md -Port 3000 is already in use. Trying 3001 instead. -``` - -## Mintlify Versions - -Please note that each CLI release is associated with a specific version of Mintlify. If your local website doesn't align with the production version, please update the CLI: - - - -```bash npm -npm i -g mintlify@latest -``` - -```bash yarn -yarn global upgrade mintlify -``` - - - -## Validating Links - -The CLI can assist with validating reference links made in your documentation. To identify any broken links, use the following command: - -```bash -mintlify broken-links -``` - -## Deployment - - - Unlimited editors available under the [Pro - Plan](https://mintlify.com/pricing) and above. - - -If the deployment is successful, you should see the following: - - - - - -## Code Formatting - -We suggest using extensions on your IDE to recognize and format MDX. If you're a VSCode user, consider the [MDX VSCode extension](https://marketplace.visualstudio.com/items?itemName=unifiedjs.vscode-mdx) for syntax highlighting, and [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) for code formatting. - -## Troubleshooting - - - - - This may be due to an outdated version of node. Try the following: - 1. Remove the currently-installed version of mintlify: `npm remove -g mintlify` - 2. Upgrade to Node v19 or higher. - 3. Reinstall mintlify: `npm install -g mintlify` - - - - - Solution: Go to the root of your device and delete the \~/.mintlify folder. Afterwards, run `mintlify dev` again. - - - -Curious about what changed in the CLI version? [Check out the CLI changelog.](https://www.npmjs.com/package/mintlify?activeTab=versions) diff --git a/docs/integration/astro.mdx b/docs/integration/astro.mdx index bf123bc..63c2f31 100644 --- a/docs/integration/astro.mdx +++ b/docs/integration/astro.mdx @@ -52,7 +52,7 @@ export const ALL = serve({ } }); ``` -For more information about the connection object, refer to the [Setup](/setup/introduction) guide. In the +For more information about the connection object, refer to the [Database](/usage/database) guide. In the special case of astro, you may also use your Astro DB credentials since it's also using LibSQL under the hood. Refer to the [Astro DB documentation](https://docs.astro.build/en/guides/astro-db/) for more information. diff --git a/docs/integration/bun.mdx b/docs/integration/bun.mdx index fb6259c..1882b86 100644 --- a/docs/integration/bun.mdx +++ b/docs/integration/bun.mdx @@ -27,7 +27,7 @@ serve({ } }); ``` -For more information about the connection object, refer to the [Setup](/setup/introduction) guide. +For more information about the connection object, refer to the [Database](/usage/database) guide. Run the application using Bun by executing: ```bash diff --git a/docs/integration/cloudflare.mdx b/docs/integration/cloudflare.mdx index 7639221..22785f8 100644 --- a/docs/integration/cloudflare.mdx +++ b/docs/integration/cloudflare.mdx @@ -31,7 +31,7 @@ export default serve({ }) }); ``` -For more information about the connection object, refer to the [Setup](/setup/introduction) guide. +For more information about the connection object, refer to the [Database](/usage/database) guide. Now run the worker: ```bash diff --git a/docs/integration/introduction.mdx b/docs/integration/introduction.mdx new file mode 100644 index 0000000..22235f7 --- /dev/null +++ b/docs/integration/introduction.mdx @@ -0,0 +1,94 @@ +--- +title: 'Introduction' +description: 'Integrate bknd into your runtime/framework of choice' +--- + +import { cloudflare, nextjs, remix, astro, bun, node, docker, vite } from "/snippets/integration-icons.mdx" + +## Start with a Framework +bknd seamlessly integrates with popular frameworks, allowing you to use what you're already familar with. The following guides will help you get started with your framework of choice. + + + {nextjs}} + href="/integration/nextjs" + /> + {remix}} + href="/integration/remix" + /> + {astro}} + href="/integration/astro" + /> + + Create a new issue to request a guide for your framework. + + + +## Start with a Runtime +If you prefer to use a runtime instead of a framework, you can choose from the following options. These runtimes allow you to serve the API and UI in the runtime's native server and serve the UI assets statically from `node_modules`. + + + {node}} + href="/integration/node" + /> + {bun}} + href="/integration/bun" + /> + {cloudflare}} + href="/integration/cloudflare" + /> + {vite}} + href="/integration/vite" + /> + {docker}} + href="/integration/docker" + /> + + Create a new issue to request a guide for your runtime. + + + +## Overview + +### Serving the backend (API) +Serve the backend as an API for any JS runtime or framework. The latter is especially handy, as it allows you to deploy your frontend and backend bundled together. Furthermore it allows adding additional logic in a way you're already familar with. Just add another route and you're good to go. + +Here is an example of serving the API using node: +```js index.js +import { serve } from "bknd/adapter/node" +serve(); +``` + +### Serving the Admin UI +The admin UI allows to manage your data including full configuration of your backend using a graphical user interface. Using `vite`, your admin route looks like this: +```tsx admin.tsx +import { Admin } from "bknd/ui" +import "bknd/dist/styles.css"; + +export default function AdminPage() { + return +} +``` \ No newline at end of file diff --git a/docs/integration/nextjs.mdx b/docs/integration/nextjs.mdx index 414b76f..855e907 100644 --- a/docs/integration/nextjs.mdx +++ b/docs/integration/nextjs.mdx @@ -28,7 +28,7 @@ export default serve({ } }); ``` -For more information about the connection object, refer to the [Setup](/setup/introduction) guide. +For more information about the connection object, refer to the [Database](/usage/database) guide. ## Enabling the Admin UI Create a file `[[...admin]].tsx` inside the `pages/admin` folder: diff --git a/docs/integration/node.mdx b/docs/integration/node.mdx index 0cc04ba..57670d2 100644 --- a/docs/integration/node.mdx +++ b/docs/integration/node.mdx @@ -29,7 +29,7 @@ const config = { serve(config); ``` -For more information about the connection object, refer to the [Setup](/setup/introduction) guide. +For more information about the connection object, refer to the [Database](/usage/database) guide. Run the application using node by executing: ```bash diff --git a/docs/integration/remix.mdx b/docs/integration/remix.mdx index 21db4da..3aaadc6 100644 --- a/docs/integration/remix.mdx +++ b/docs/integration/remix.mdx @@ -26,7 +26,7 @@ const handler = serve({ export const loader = handler; export const action = handler; ``` -For more information about the connection object, refer to the [Setup](/setup/introduction) guide. +For more information about the connection object, refer to the [Database](/usage/database) guide. Now make sure that you wrap your root layout with the `ClientProvider` so that all components share the same context: diff --git a/docs/integration/vite.mdx b/docs/integration/vite.mdx index 749788b..a5dda5e 100644 --- a/docs/integration/vite.mdx +++ b/docs/integration/vite.mdx @@ -33,7 +33,7 @@ export default serve({ } }) ``` -For more information about the connection object, refer to the [Setup](/setup/introduction) guide. +For more information about the connection object, refer to the [Database](/usage/database) guide. You can also run your vite server in `mode: "fresh"`, this will re-create the app on every fetch. This is only useful for when working on the `bknd` repository directly. diff --git a/docs/introduction.mdx b/docs/introduction.mdx index b568eb0..3a862f4 100644 --- a/docs/introduction.mdx +++ b/docs/introduction.mdx @@ -2,13 +2,26 @@ title: Introduction --- +import { cloudflare, nextjs, remix, astro, bun, node, docker, vite } from "/snippets/integration-icons.mdx" +import { Stackblitz, examples } from "/snippets/stackblitz.mdx" + Glad you're here! This is about **bknd**, a feature-rich backend that is so lightweight it could run on your toaster (probably). - The documentation is currently a work in progress and not complete. Updates will be made soon. + The documentation is currently a work in progress and not complete. Updates will be made regularily. +## Preview +**bknd** is so lightweight that it fully runs inside StackBlitz. Take a look at the preview below: + + + + The example shown is starting a [node server](/integration/node) using an [in-memory database](/usage/database#sqlite-in-memory). To ensure there are a few entities defined, it is using an [initial structure](/usage/database#initial-structure) using the prototype methods. Furthermore it uses the [seed option](/usage/database#seeding-the-database) to seed some data in the structure created. + + To ensure there are users defined on first boot, it hooks into the `App.Events.AppFirstBoot` event to create them (documentation pending). + + ## Quickstart Enter the following command to spin up an instance: @@ -20,7 +33,8 @@ Enter the following command to spin up an instance: bunx bknd run ``` -To learn more about the CLI, check out the [Using the CLI](/cli) guide. + +To learn more about the CLI, check out the [Using the CLI](/usage/cli) guide. ## Start with a Framework/Runtime @@ -30,73 +44,42 @@ in the future, so stay tuned! - } + icon={
{nextjs}
} href="/integration/nextjs" /> - - } + icon={
{remix}
} href="/integration/remix" /> - - - - } + icon={
{astro}
} href="/integration/astro" /> + {node}} + href="/integration/node" + /> - - - - } + icon={
{cloudflare}
} href="/integration/cloudflare" /> - - - - } + icon={
{bun}
} href="/integration/bun" /> - - - - - } - href="/integration/node" - /> - - - - } + icon={
{vite}
} href="/integration/vite" /> - - } + icon={
{docker}
} href="/integration/docker" />
diff --git a/docs/mint.json b/docs/mint.json index e848206..ef327a3 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -61,11 +61,43 @@ "navigation": [ { "group": "Getting Started", - "pages": ["introduction", "sdk", "react", "cli"] + "pages": ["introduction", "motivation"] }, { - "group": "Setup", - "pages": ["setup/introduction", "setup/database"] + "group": "Usage", + "pages": [ + "usage/introduction", + "usage/database", + "usage/cli", + "usage/sdk", + "usage/react", + "usage/elements" + ] + }, + { + "group": "Integration", + "pages": [ + "integration/introduction", + { + "group": "Frameworks", + "pages": [ + "integration/nextjs", + "integration/remix", + "integration/astro", + "integration/vite" + ] + }, + { + "group": "Runtimes", + "pages": [ + "integration/node", + "integration/bun", + "integration/cloudflare", + "integration/deno", + "integration/docker" + ] + } + ] }, { "group": "Modules", @@ -78,21 +110,6 @@ "modules/flows" ] }, - { - "group": "Integration", - "pages": [ - "integration/extending", - "integration/nextjs", - "integration/remix", - "integration/cloudflare", - "integration/bun", - "integration/astro", - "integration/node", - "integration/deno", - "integration/vite", - "integration/docker" - ] - }, { "group": "Deployment", "pages": [ diff --git a/docs/motivation.mdx b/docs/motivation.mdx new file mode 100644 index 0000000..668184c --- /dev/null +++ b/docs/motivation.mdx @@ -0,0 +1,71 @@ +--- +title: "Motivation" +description: "Why another backend system?" +--- + +Creating digital products always requires developing both the backend (the logic) and the frontend (the appearance). Building a backend from scratch demands deep knowledge in areas such as authentication and database management. Using a backend framework can speed up initial development, but it still requires ongoing effort to work within its constraints (e.g., *"how to do X with Y?"*), which can quickly slow you down. Choosing a backend system is a tough decision, as you might not be aware of its limitations until you encounter them. + + + **The solution:** A backend system that only assumes and implements primitive details, integrates into multiple environments, and adheres to industry standards. + + +For the sake of brevity, let's assume you are looking for a "backend system" rather than dealing with custom implementations yourself. Let's identify the most common challenges: + +1. Database lock-in +2. Environment and framework lock-in +3. Deviation from standards (such as `X-Auth` headers for authentication) +4. *Wrong-for-your-use-case* implementations +5. Complex self-hosting + +## Database lock-in +As the developer of a backend system, you must make tough decisions, one of which is choosing which database(s) to support. To simplify development, many systems lock you into a single database, leveraging its advanced features. + +But isn't the database known to be the hardest part to scale? Isn't more logic moving to the application layer? Haven't NoSQL databases proven this? If you're like me, you may have dipped your toes into the NoSQL world only to quickly return to SQL. SQL is known, predictable, and safe. But what if we could have both? NoSQL offers flexibility and scalability, yet querying it is tedious due to vendor-specific implementations. + +To get the best of both worlds, bknd focuses on the weakest SQL database (SQLite), treating it as a data store and query interface. Schema details and enforcement are moved to the application layer, making it easy to adjust a default value or property length. The added benefit is that any SQL database could theoretically work the same way, and since it's all TypeScript, the same validation logic can be used on both the client and server sides–you can validate your data before it even reaches your server. It even works without database-enforced referential integrity, as the integrity checks occur on the application layer. This opens the door to NewSQL systems like PlanetScale. + +## Environment and framework lock-in +There are backend systems that embed themselves into a specific React framework. This works well until you realize it doesn't support your preferred framework or the new hyped one you're considering switching to. Just like database choices, decisions must be made. The easiest path is to select a single option and let people live with it. + +Alternatively, you could develop for the weakest environment (workerd) by strictly using Web APIs, avoiding shortcuts, and implementing certain logic manually because the go-to package is using Node APIs. This isn't always fun, but it's essential. The benefit? It works anywhere JavaScript does. + +bknd is the only backend system that not only works with any JavaScript framework but also integrates directly into it. It runs within the framework, enabling a single deployment for your entire app. + +*"But isn't it ironic that it forces a JavaScript environment?"* you might ask. And you're right, but it also allows running standalone via CLI or Docker. + + +## Deviation from standards +One of the biggest frustrations I've encountered is when software vendors choose custom headers for authentication or implement query parameters in a format they find more suitable—such as unencoded JSON for simplicity. When you are in full control, it's tempting to use a more suitable format, or just use an auth-ish name for the header property–after all, it's just a header, right? + +The issue is that users may rely on HTTP clients that offer built-in authentication methods, which won't include your custom solution. Custom `SearchParams` implementations might be convenient, but translating them across different environments and languages can be challenging without trial and error. + +bknd strives to adhere to web standards as much as possible while offering handy alternatives. Here's an example of the `select` search parameter for retrieving a list of entities: +```bash +/api/data/todos?select=id&select=name # web standard +/api/data/todos?select=id,name # handy alternative +``` + +If you ever find an instance where bknd isn't adhering to standards or could be improved, please feel free to [file an issue](https://github.com/bknd-io/bknd/issues/new). Your feedback is greatly appreciated! + + +## Wrong-for-your-use-case implementations +If you've ever developed a social chat application, you likely discovered the extensive feature depth required—features we often take for granted. Things like socket connections for single and group chats, partial loading, asset attachments, and emoji reactions. Even more frustrating, these features make the app being considered incomplete until delivered. + +The same applies to backend systems. Features such as email sending, password resets, and image transformations are expected. Worse still, you'll receive feedback requesting different email verification methods—PIN codes instead of links, 4-digit codes versus 6-digit ones, or UUIDs like Axiom uses. + +Since it's impossible to satisfy all requirements, why implement them at all? *"Because people expect it."* That's fair. But technically, email verification is not a core backend feature—it's business logic. Setting it up involves: +1. Adding a `code` and `verified` field to the users' entity and generating a random code on creation. +2. Creating an endpoint to accept the code, retrieve the authenticated user, check the code, clear it, and mark the user as verified. + +Additional security measures, such as short-lived tokens, can be added, but the concept remains simple. + +Instead of hardcoding such features, bknd offers a powerful event system that supports asynchronous (like webhooks) and synchronous execution, blocking further actions if needed. With integrated workflows (UI coming soon), you can listen to and react to system events, and even map them to endpoints. Since workflows, like everything else in bknd, are JSON-serializable, they're easy to export and import. + +## Complex self-hosting +Finally, hosting. It's a business advantage if your system is highly sought after but difficult to self-host, forcing users to opt for your cloud service. The truth is, if it's hard for users, it's also hard for the vendor, which drives up costs. + +If you know how to deploy your Next.js, Remix, or Astro application, you can deploy bknd. It's straightforward to deploy using Cloudflare Workers/Pages or with just 28 lines of a Dockerfile. No PhD required. + + + + diff --git a/docs/snippets/integration-icons.mdx b/docs/snippets/integration-icons.mdx new file mode 100644 index 0000000..8832c4d --- /dev/null +++ b/docs/snippets/integration-icons.mdx @@ -0,0 +1,31 @@ +export const nextjs = + +export const remix = ; + +export const astro = + + + +export const cloudflare = + + + +export const bun = + + + +export const node = + + + +export const vite = + + + +export const docker = \ No newline at end of file diff --git a/docs/snippets/stackblitz.mdx b/docs/snippets/stackblitz.mdx new file mode 100644 index 0000000..0b690b1 --- /dev/null +++ b/docs/snippets/stackblitz.mdx @@ -0,0 +1,45 @@ +export const examples = { + adminRich: { + path: "github/bknd-io/bknd-examples", + startScript: "example-admin-rich", + initialPath: "/data/schema" + } +} + +export const Stackblitz = ({ + path = "github/bknd-io/bknd-examples", + ratio = 9/16, + ...props +}) => { + const params = new URLSearchParams({ + ctl: 1, + hideExplorer: 1, + embed: 1, + view: "preview", + ...props + }) + const url = new URL(`https://stackblitz.com/${path}?${params.toString()}`) + + return ( + <> +
+ +
+
If you're having issues viewing it inline, try in a new tab.
+ + ) +} \ No newline at end of file diff --git a/docs/cli.mdx b/docs/usage/cli.mdx similarity index 100% rename from docs/cli.mdx rename to docs/usage/cli.mdx diff --git a/docs/setup/database.mdx b/docs/usage/database.mdx similarity index 92% rename from docs/setup/database.mdx rename to docs/usage/database.mdx index dda5773..a6464e1 100644 --- a/docs/setup/database.mdx +++ b/docs/usage/database.mdx @@ -12,9 +12,21 @@ the dependencies. ## Database +### SQLite in-memory +The easiest to get started is using SQLite in-memory. When serving the API in the "Integrations", +the function accepts an object with connection details. To use an in-memory database, you can either omit the object completely or explicitly use it as follows: +```json +{ + "type": "libsql", + "config": { + "url": ":memory:" + } +} +``` + ### SQLite as file -The easiest to get started is using SQLite as a file. When serving the API in the "Integrations", -the function accepts an object with connection details. To use a file, use the following: +Just like the in-memory option, using a file is just as easy: + ```json { "type": "libsql", @@ -156,11 +168,11 @@ const { data: posts } = await api.data.readMany("posts", {}) // `posts` is now typed as Database["posts"] ``` -The type completion is available for the API as well as all provided [React hooks](/react). +The type completion is available for the API as well as all provided [React hooks](/usage/react). ### Seeding the database To seed your database with initial data, you can pass a `seed` function to the configuration. It -provides the `ModuleBuildContext` ([reference](/setup/introduction#modulebuildcontext)) as the first argument. +provides the `ModuleBuildContext` ([reference](/usage/introduction#modulebuildcontext)) as the first argument. Note that the seed function will only be executed on app's first boot. If a configuration already exists in the database, it will not be executed. diff --git a/docs/usage/elements.mdx b/docs/usage/elements.mdx new file mode 100644 index 0000000..0a517fa --- /dev/null +++ b/docs/usage/elements.mdx @@ -0,0 +1,25 @@ +--- +title: "React Elements" +description: "Speed up your frontend development" +--- + + + The documentation is currently a work in progress and not complete. + + + +Not only creating and maintaing a backend is time-consuming, but also integrating it into your frontend can be a hassle. With `bknd/elements`, you can easily add media uploads and authentication forms to your app without having to figure out API details. + +## Media uploads + +```tsx +import { Media } from "bknd/elements" + +export function UserAvatar() { + return +} +``` \ No newline at end of file diff --git a/docs/setup/introduction.mdx b/docs/usage/introduction.mdx similarity index 96% rename from docs/setup/introduction.mdx rename to docs/usage/introduction.mdx index 70b508d..d3ac8c2 100644 --- a/docs/setup/introduction.mdx +++ b/docs/usage/introduction.mdx @@ -4,7 +4,7 @@ description: 'Setting up bknd' --- There are several methods to get **bknd** up and running. You can choose between these options: -1. [Run it using the CLI](/cli): That's the easiest and fastest way to get started. +1. [Run it using the CLI](/usage/cli): That's the easiest and fastest way to get started. 2. Use a runtime like [Node](/integration/node), [Bun](/integration/bun) or [Cloudflare](/integration/cloudflare) (workerd). This will run the API and UI in the runtime's native server and serves the UI assets statically from `node_modules`. @@ -78,7 +78,7 @@ const connection = { ``` Alternatively, you can pass an instance of a `Connection` class directly, -see [Custom Connection](/setup/database#custom-connection) as a reference. +see [Custom Connection](/usage/database#custom-connection) as a reference. If the connection object is omitted, the app will try to use an in-memory database. @@ -160,7 +160,7 @@ To validate your configuration against a JSON schema, you can also dump the sche npx bknd schema ``` -To create an initial data structure, you can use helpers [described here](/setup/database#initial-structure). +To create an initial data structure, you can use helpers [described here](/usage/database#initial-structure). ### `plugins` The `plugins` property is an array of functions that are called after the app has been built, diff --git a/docs/react.mdx b/docs/usage/react.mdx similarity index 89% rename from docs/react.mdx rename to docs/usage/react.mdx index 1c30c2c..753e93b 100644 --- a/docs/react.mdx +++ b/docs/usage/react.mdx @@ -3,10 +3,15 @@ title: 'SDK (React)' description: 'Use the bknd SDK for React' --- -For all SDK options targeting React, you always have 2 options: -1. use simple hooks which are solely based on the [API](/sdk) -2. use the query hook that makes wraps the API in [SWR](https://swr.vercel.app/) +bknd exports 4 useful hooks to work with your backend: +1. simple hooks which are solely based on the [API](/usage/sdk): + - [`useApi`](#useapi) + - [`useEntity`](#useentity) +2. query hooks that wraps the API in [SWR](https://swr.vercel.app/): + - [`useApiQuery`](#useapiquery) + - [`useEntityQuery`](#useentityquery) +## `useApi()` To use the simple hook that returns the Api, you can use: ```tsx import { useApi } from "bknd/client"; @@ -17,7 +22,7 @@ export default function App() { } ``` -## `useApiQuery([selector], [options])` +## `useApiQuery()` This hook wraps the API class in an SWR hook for convenience. You can use any API endpoint supported, like so: ```tsx @@ -41,12 +46,12 @@ export default function App() { * `options`: optional object that inherits from `SWRConfiguration` - ```ts - type Options = SWRConfiguration & { - enabled?: boolean; - refine?: (data: Data) => Data | any; - } - ``` +```ts +type Options = import("swr").SWRConfiguration & { + enabled? : boolean; + refine? : (data: Data) => Data | any; +} +``` * `enabled`: Determines whether this hook should trigger a fetch of the data or not. * `refine`: Optional refinement that is called after a response from the API has been @@ -58,7 +63,7 @@ following example we'll also use a `refine` function as well as `revalidateOnFoc `SWRConfiguration`) so that our data keeps updating on window focus change. ```tsx -import { useState } from "react"; +import { useEffect, useState } from "react"; import { useApiQuery } from "bknd/client"; export default function App() { @@ -108,7 +113,7 @@ export default function App() { ## `useEntity()` This hook wraps the endpoints of `DataApi` and returns CRUD options as parameters: ```tsx -import { useState } from "react", +import { useState, useEffect } from "react"; import { useEntity } from "bknd/client"; export default function App() { @@ -144,7 +149,6 @@ optional. Deletes the given entry. This hook wraps the actions from `useEntity` around `SWR`. The previous example would look like this: ```tsx -import { useState } from "react", import { useEntityQuery } from "bknd/client"; export default function App() { @@ -158,7 +162,7 @@ export default function App() { All actions returned from `useEntityQuery` are conveniently wrapped around the `mutate` function, so you don't have think about this: ```tsx -import { useState } from "react"; +import { useState, useEffect } from "react"; import { useEntityQuery } from "bknd/client"; export default function App() { diff --git a/docs/sdk.mdx b/docs/usage/sdk.mdx similarity index 98% rename from docs/sdk.mdx rename to docs/usage/sdk.mdx index 5361316..ccb5cb2 100644 --- a/docs/sdk.mdx +++ b/docs/usage/sdk.mdx @@ -10,6 +10,9 @@ import { Api } from "bknd"; const api = new Api({ host: "..." // point to your bknd instance }); + +// make sure to verify auth +await api.verifyAuth(); ``` The `Api` class is the main entry point for interacting with the bknd API. It provides methods