diff --git a/app/package.json b/app/package.json index 93a4f7b..b852dc9 100644 --- a/app/package.json +++ b/app/package.json @@ -3,7 +3,7 @@ "type": "module", "sideEffects": false, "bin": "./dist/cli/index.js", - "version": "0.8.0-rc.9", + "version": "0.8.0-rc.10", "description": "Lightweight Firebase/Supabase alternative built to run anywhere — incl. Next.js, Remix, Astro, Cloudflare, Bun, Node, AWS Lambda & more.", "homepage": "https://bknd.io", "repository": { diff --git a/app/src/App.ts b/app/src/App.ts index ab4b87a..cd4abc5 100644 --- a/app/src/App.ts +++ b/app/src/App.ts @@ -4,6 +4,7 @@ import { Connection, type LibSqlCredentials, LibsqlConnection } from "data"; import type { Hono } from "hono"; import { type InitialModuleConfigs, + type ModuleBuildContext, ModuleManager, type ModuleManagerOptions, type Modules @@ -28,7 +29,8 @@ export const AppEvents = { AppConfigUpdatedEvent, AppBuiltEvent, AppFirstBoot } export type AppOptions = { plugins?: AppPlugin[]; - manager?: Omit; + seed?: (ctx: ModuleBuildContext) => Promise; + manager?: Omit; }; export type CreateAppConfig = { connection?: @@ -61,6 +63,7 @@ export class App { this.modules = new ModuleManager(connection, { ...(options?.manager ?? {}), initial: _initialConfig, + seed: options?.seed, onUpdated: async (key, config) => { // if the EventManager was disabled, we assume we shouldn't // respond to events, such as "onUpdated". diff --git a/docs/usage/database.mdx b/docs/usage/database.mdx index 04f3a62..638abd9 100644 --- a/docs/usage/database.mdx +++ b/docs/usage/database.mdx @@ -67,6 +67,7 @@ described above, or an class instance that extends from `Connection`: ```ts import { createApp } from "bknd"; import { Connection } from "bknd/data"; +import { Kysely } from "kysely"; class CustomConnection extends Connection { constructor() { @@ -85,6 +86,7 @@ const app = createApp({ connection }) To provide an initial database structure, you can pass `initialConfig` to the creation of an app. This will only be used if there isn't an existing configuration found in the database given. Here is a quick example: ```ts +import { createApp } from "bknd"; import { em, entity, text, number } from "bknd/data"; const schema = em({ @@ -142,9 +144,9 @@ All entity related functions use the types defined in `DB` from `bknd/core`. To ```ts import { em } from "bknd/data"; -import { Api } from "bknd"; +import { Api } from "bknd/client"; -// const schema = em({ ... }); + const schema = em({ /* ... */ }); type Database = (typeof schema)["DB"]; declare module "bknd/core" { @@ -160,7 +162,7 @@ The type completion is available for the API as well as all provided [React hook ### Seeding the database To seed your database with initial data, you can pass a `seed` function to the configuration. It -provides the `ModuleBuildContext` ([reference](/usage/introduction#modulebuildcontext)) as the first argument. +provides the `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/introduction.mdx b/docs/usage/introduction.mdx index 985be99..f5a62bf 100644 --- a/docs/usage/introduction.mdx +++ b/docs/usage/introduction.mdx @@ -157,7 +157,7 @@ npx bknd schema To create an initial data structure, you can use helpers [described here](/usage/database#initial-structure). -### `plugins` +### `options.plugins` The `plugins` property is an array of functions that are called after the app has been built, but before its event is emitted. This is useful for adding custom routes or other functionality. A simple plugin that adds a custom route looks like this: @@ -174,23 +174,9 @@ Since each plugin has full access to the `app` instance, it can add routes, modi structure, add custom middlewares, respond to or add events, etc. Plugins are very powerful, so make sure to only run trusted ones. -### `options` -This object is passed to the `ModuleManager` which is responsible for: -- validating and maintaining configuration of all modules -- building all modules (data, auth, media, flows) -- maintaining the `ModuleBuildContext` used by the modules +### `options.seed` +The `seed` property is a function that is called when the app is booted for the first time. It is used to seed the database with initial data. The function is passed a `ModuleBuildContext` object: -The `options` object has the following properties: -- `basePath` (`string`): The base path for the Hono instance. This is used to prefix all routes. -- `trustFetched` (`boolean`): If set to `true`, the app will not perform any validity checks for -the given or fetched configuration. -- `onFirstBoot` (`() => Promise`): A function that is called when the app is booted for -the first time. -- `seed` (`(ctx: ModuleBuildContext) => Promise`): A function that is called when the app is -booted for the first time and an initial partial configuration is provided. - - -## `ModuleBuildContext` ```ts type ModuleBuildContext = { connection: Connection; @@ -199,4 +185,25 @@ type ModuleBuildContext = { emgr: EventManager; guard: Guard; }; -``` \ No newline at end of file + +const seed = async (ctx: ModuleBuildContext) => { + // seed the database + await ctx.em.mutator("todos").insertMany([ + { title: "Learn bknd", done: true }, + { title: "Build something cool", done: false } + ]); +}; +``` + +### `options.manager` +This object is passed to the `ModuleManager` which is responsible for: +- validating and maintaining configuration of all modules +- building all modules (data, auth, media, flows) +- maintaining the `ModuleBuildContext` used by the modules + +The `options.manager` object has the following properties: +- `basePath` (`string`): The base path for the Hono instance. This is used to prefix all routes. +- `trustFetched` (`boolean`): If set to `true`, the app will not perform any validity checks for +the given or fetched configuration. +- `onFirstBoot` (`() => Promise`): A function that is called when the app is booted for +the first time. diff --git a/examples/astro/src/pages/api/[...api].ts b/examples/astro/src/pages/api/[...api].ts index c1423a8..5d48762 100644 --- a/examples/astro/src/pages/api/[...api].ts +++ b/examples/astro/src/pages/api/[...api].ts @@ -27,7 +27,7 @@ declare module "bknd/core" { export const ALL = serve({ // we can use any libsql config, and if omitted, uses in-memory connection: { - url: "file:test.db" + url: "file:data.db" }, // an initial config is only applied if the database is empty initialConfig: { diff --git a/examples/bun/index.ts b/examples/bun/index.ts index a900a6f..3375019 100644 --- a/examples/bun/index.ts +++ b/examples/bun/index.ts @@ -7,7 +7,7 @@ import { type BunBkndConfig, serve } from "bknd/adapter/bun"; // this is optional, if omitted, it uses an in-memory database const config: BunBkndConfig = { connection: { - url: ":memory:" + url: "file:data.db" } }; diff --git a/examples/node/index.js b/examples/node/index.js index edb6b80..30010c8 100644 --- a/examples/node/index.js +++ b/examples/node/index.js @@ -7,7 +7,7 @@ import { serve } from "bknd/adapter/node"; /** @type {import("bknd/adapter/node").NodeBkndConfig} */ const config = { connection: { - url: ":memory:" + url: "file:data.db" } }; diff --git a/examples/remix/app/routes/_index.tsx b/examples/remix/app/routes/_index.tsx index 1cbbe19..4337d0e 100644 --- a/examples/remix/app/routes/_index.tsx +++ b/examples/remix/app/routes/_index.tsx @@ -1,6 +1,5 @@ import { type MetaFunction, useLoaderData } from "@remix-run/react"; import type { LoaderFunctionArgs } from "@remix-run/server-runtime"; -import { useAuth } from "bknd/client"; export const meta: MetaFunction = () => { return [{ title: "Remix & bknd" }, { name: "description", content: "Welcome to Remix & bknd!" }]; @@ -13,8 +12,6 @@ export const loader = async ({ context: { api } }: LoaderFunctionArgs) => { export default function Index() { const { data, user } = useLoaderData(); - const auth = useAuth(); - console.log("auth", auth); return (