mirror of
https://github.com/bknd-io/bknd/
synced 2026-08-03 16:46:00 +00:00
docs: added plugins docs, updated cloudflare docs
This commit is contained in:
+22
-1
@@ -23,13 +23,34 @@ import type { IEmailDriver, ICacheDriver } from "core/drivers";
|
|||||||
import { Api, type ApiOptions } from "Api";
|
import { Api, type ApiOptions } from "Api";
|
||||||
|
|
||||||
export type AppPluginConfig = {
|
export type AppPluginConfig = {
|
||||||
|
/**
|
||||||
|
* The name of the plugin.
|
||||||
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
|
/**
|
||||||
|
* The schema of the plugin.
|
||||||
|
*/
|
||||||
schema?: () => MaybePromise<ReturnType<typeof prototypeEm> | void>;
|
schema?: () => MaybePromise<ReturnType<typeof prototypeEm> | void>;
|
||||||
|
/**
|
||||||
|
* Called before the app is built.
|
||||||
|
*/
|
||||||
beforeBuild?: () => MaybePromise<void>;
|
beforeBuild?: () => MaybePromise<void>;
|
||||||
|
/**
|
||||||
|
* Called after the app is built.
|
||||||
|
*/
|
||||||
onBuilt?: () => MaybePromise<void>;
|
onBuilt?: () => MaybePromise<void>;
|
||||||
|
/**
|
||||||
|
* Called when the server is initialized.
|
||||||
|
*/
|
||||||
onServerInit?: (server: Hono<ServerEnv>) => MaybePromise<void>;
|
onServerInit?: (server: Hono<ServerEnv>) => MaybePromise<void>;
|
||||||
onFirstBoot?: () => MaybePromise<void>;
|
/**
|
||||||
|
* Called when the app is booted.
|
||||||
|
*/
|
||||||
onBoot?: () => MaybePromise<void>;
|
onBoot?: () => MaybePromise<void>;
|
||||||
|
/**
|
||||||
|
* Called when the app is first booted.
|
||||||
|
*/
|
||||||
|
onFirstBoot?: () => MaybePromise<void>;
|
||||||
};
|
};
|
||||||
export type AppPlugin = (app: App) => AppPluginConfig;
|
export type AppPlugin = (app: App) => AppPluginConfig;
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ type BunEnv = Bun.Env;
|
|||||||
export type BunBkndConfig<Env = BunEnv> = RuntimeBkndConfig<Env> & Omit<ServeOptions, "fetch">;
|
export type BunBkndConfig<Env = BunEnv> = RuntimeBkndConfig<Env> & Omit<ServeOptions, "fetch">;
|
||||||
|
|
||||||
export async function createApp<Env = BunEnv>(
|
export async function createApp<Env = BunEnv>(
|
||||||
{ distPath, ...config }: BunBkndConfig<Env> = {},
|
{ distPath, serveStatic: _serveStatic, ...config }: BunBkndConfig<Env> = {},
|
||||||
args: Env = {} as Env,
|
args: Env = {} as Env,
|
||||||
opts?: RuntimeOptions,
|
opts?: RuntimeOptions,
|
||||||
) {
|
) {
|
||||||
@@ -20,7 +20,11 @@ export async function createApp<Env = BunEnv>(
|
|||||||
|
|
||||||
return await createRuntimeApp(
|
return await createRuntimeApp(
|
||||||
{
|
{
|
||||||
serveStatic: serveStatic({ root }),
|
serveStatic:
|
||||||
|
_serveStatic ??
|
||||||
|
serveStatic({
|
||||||
|
root,
|
||||||
|
}),
|
||||||
...config,
|
...config,
|
||||||
},
|
},
|
||||||
args ?? (process.env as Env),
|
args ?? (process.env as Env),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { resolve } from "node:path";
|
|||||||
* Vite plugin that provides Node.js filesystem access during development
|
* Vite plugin that provides Node.js filesystem access during development
|
||||||
* by injecting a polyfill into the SSR environment
|
* by injecting a polyfill into the SSR environment
|
||||||
*/
|
*/
|
||||||
export function devFsPlugin({
|
export function devFsVitePlugin({
|
||||||
verbose = false,
|
verbose = false,
|
||||||
configFile = "bknd.config.ts",
|
configFile = "bknd.config.ts",
|
||||||
}: {
|
}: {
|
||||||
|
|||||||
@@ -19,22 +19,41 @@ const schema = s.partialObject({
|
|||||||
type ImageOptimizationSchema = s.Static<typeof schema>;
|
type ImageOptimizationSchema = s.Static<typeof schema>;
|
||||||
|
|
||||||
export type CloudflareImageOptimizationOptions = {
|
export type CloudflareImageOptimizationOptions = {
|
||||||
|
/**
|
||||||
|
* The url to access the image optimization plugin, defaults to `/api/plugin/image/optimize`
|
||||||
|
*/
|
||||||
accessUrl?: string;
|
accessUrl?: string;
|
||||||
|
/**
|
||||||
|
* The path to resolve the image from, defaults to `/api/media/file`
|
||||||
|
*/
|
||||||
resolvePath?: string;
|
resolvePath?: string;
|
||||||
|
/**
|
||||||
|
* Whether to explain the image optimization schema, defaults to `false`
|
||||||
|
*/
|
||||||
explain?: boolean;
|
explain?: boolean;
|
||||||
|
/**
|
||||||
|
* The default options to use, defaults to `{}`
|
||||||
|
* @param: config
|
||||||
|
*/
|
||||||
defaultOptions?: ImageOptimizationSchema;
|
defaultOptions?: ImageOptimizationSchema;
|
||||||
|
/**
|
||||||
|
* The fixed options to use, defaults to `{}`
|
||||||
|
*/
|
||||||
fixedOptions?: ImageOptimizationSchema;
|
fixedOptions?: ImageOptimizationSchema;
|
||||||
|
/**
|
||||||
|
* The cache control to use, defaults to `public, max-age=31536000, immutable`
|
||||||
|
*/
|
||||||
cacheControl?: string;
|
cacheControl?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function cloudflareImageOptimization({
|
export function cloudflareImageOptimization({
|
||||||
accessUrl = "/_plugin/image/optimize",
|
accessUrl = "/api/plugin/image/optimize",
|
||||||
resolvePath = "/api/media/file",
|
resolvePath = "/api/media/file",
|
||||||
explain = false,
|
explain = false,
|
||||||
defaultOptions = {},
|
defaultOptions = {},
|
||||||
fixedOptions = {},
|
fixedOptions = {},
|
||||||
}: CloudflareImageOptimizationOptions = {}): AppPlugin {
|
}: CloudflareImageOptimizationOptions = {}): AppPlugin {
|
||||||
const disallowedAccessUrls = ["/api", "/admin", "/_optimize"];
|
const disallowedAccessUrls = ["/api", "/admin", "/api/plugin"];
|
||||||
if (disallowedAccessUrls.includes(accessUrl) || accessUrl.length < 2) {
|
if (disallowedAccessUrls.includes(accessUrl) || accessUrl.length < 2) {
|
||||||
throw new Error(`Disallowed accessUrl: ${accessUrl}`);
|
throw new Error(`Disallowed accessUrl: ${accessUrl}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,209 @@
|
|||||||
|
---
|
||||||
|
title: Plugins
|
||||||
|
tags: ["documentation"]
|
||||||
|
---
|
||||||
|
import { TypeTable } from 'fumadocs-ui/components/type-table';
|
||||||
|
|
||||||
|
|
||||||
|
bknd allows you to extend its functionality by creating plugins. These allows to hook into the app lifecycle and to provide a data structure that is guaranteed to be merged. A plugin is a function that takes in an instance of `App` and returns the following structure:
|
||||||
|
|
||||||
|
<AutoTypeTable path="../app/src/App.ts" name="AppPluginConfig" />
|
||||||
|
|
||||||
|
## Creating a simple plugin
|
||||||
|
|
||||||
|
To create a simple plugin which guarantees an entity `pages` to be available and an additioanl endpoint to render a html list of pages, you can create it as follows:
|
||||||
|
|
||||||
|
```tsx title="myPagesPlugin.tsx"
|
||||||
|
/** @jsxImportSource hono/jsx */
|
||||||
|
import { type App, type AppPlugin, em, entity, text } from "bknd";
|
||||||
|
|
||||||
|
export const myPagesPlugin: AppPlugin = (app) => ({
|
||||||
|
name: "my-pages-plugin",
|
||||||
|
// define the schema of the plugin
|
||||||
|
// this will always be merged into the app's schema
|
||||||
|
schema: () => em({
|
||||||
|
pages: entity("pages", {
|
||||||
|
title: text(),
|
||||||
|
content: text(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
// execute code after the app is built
|
||||||
|
onBuilt: () => {
|
||||||
|
// register a new endpoint, make sure that you choose an endpoint that is reachable for bknd
|
||||||
|
app.server.get("/my-pages", async (c) => {
|
||||||
|
const { data: pages } = await app.em.repo("pages").findMany({});
|
||||||
|
return c.html(
|
||||||
|
<body>
|
||||||
|
<h1>Pages: {pages.length}</h1>
|
||||||
|
<ul>
|
||||||
|
{pages.map((page: any) => (
|
||||||
|
<li key={page.id}>{page.title}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</body>,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
And then register it in your `bknd.config.ts` file:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import type { BkndConfig } from "bknd/adapter";
|
||||||
|
import { myPagesPlugin } from "./myPagesPlugin";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
options: {
|
||||||
|
plugins: [myPagesPlugin],
|
||||||
|
}
|
||||||
|
} satisfies BkndConfig;
|
||||||
|
```
|
||||||
|
|
||||||
|
The schema returned from the plugin will be merged into the schema of the app.
|
||||||
|
|
||||||
|
|
||||||
|
## Built-in plugins
|
||||||
|
|
||||||
|
bknd comes with a few built-in plugins that you can use.
|
||||||
|
|
||||||
|
### `syncTypes`
|
||||||
|
|
||||||
|
A simple plugin that writes down the TypeScript types of the data schema on boot and each build. The output is equivalent to running `npx bknd types`.
|
||||||
|
|
||||||
|
```typescript title="bknd.config.ts"
|
||||||
|
import { syncTypes } from "bknd/plugins";
|
||||||
|
import { writeFile } from "node:fs/promises";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
options: {
|
||||||
|
plugins: [
|
||||||
|
syncTypes({
|
||||||
|
// whether to enable the plugin, make sure to disable in production
|
||||||
|
enabled: true,
|
||||||
|
// your writing function (required)
|
||||||
|
write: async (et) => {
|
||||||
|
await writeFile("bknd-types.d.ts", et.toString(), "utf-8");
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
} satisfies BkndConfig;
|
||||||
|
```
|
||||||
|
|
||||||
|
### `syncConfig`
|
||||||
|
|
||||||
|
A simple plugin that writes down the app configuration on boot and each build.
|
||||||
|
|
||||||
|
```typescript title="bknd.config.ts"
|
||||||
|
import { syncConfig } from "bknd/plugins";
|
||||||
|
import { writeFile } from "node:fs/promises";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
options: {
|
||||||
|
plugins: [
|
||||||
|
syncConfig({
|
||||||
|
// whether to enable the plugin, make sure to disable in production
|
||||||
|
enabled: true,
|
||||||
|
// your writing function (required)
|
||||||
|
write: async (config) => {
|
||||||
|
await writeFile("config.json", JSON.stringify(config, null, 2), "utf-8");
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
} satisfies BkndConfig;
|
||||||
|
```
|
||||||
|
|
||||||
|
### `showRoutes`
|
||||||
|
|
||||||
|
A simple plugin that logs the routes of your app in the console.
|
||||||
|
|
||||||
|
```typescript title="bknd.config.ts"
|
||||||
|
import { showRoutes } from "bknd/plugins";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
options: {
|
||||||
|
plugins: [
|
||||||
|
showRoutes({
|
||||||
|
// whether to show the routes only once (on first build)
|
||||||
|
once: true
|
||||||
|
})
|
||||||
|
],
|
||||||
|
},
|
||||||
|
} satisfies BkndConfig;
|
||||||
|
```
|
||||||
|
|
||||||
|
### `cloudflareImageOptimization`
|
||||||
|
|
||||||
|
A plugin that add Cloudflare Image Optimization to your app's media storage.
|
||||||
|
|
||||||
|
```typescript title="bknd.config.ts"
|
||||||
|
import { cloudflareImageOptimization } from "bknd/plugins";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
options: {
|
||||||
|
plugins: [
|
||||||
|
cloudflareImageOptimization({
|
||||||
|
// the url to access the image optimization plugin
|
||||||
|
accessUrl: "/api/plugin/image/optimize",
|
||||||
|
// the path to resolve the image from, defaults to `/api/media/file`
|
||||||
|
resolvePath: "/api/media/file",
|
||||||
|
// for example, you may want to have default option to limit to a width of 1000px
|
||||||
|
defaultOptions: {
|
||||||
|
width: 1000,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
|
},
|
||||||
|
} satisfies BkndConfig;
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is a break down of all configuration options:
|
||||||
|
|
||||||
|
<AutoTypeTable path="../app/src/plugins/cloudflare/image-optimization.plugin.ts" name="CloudflareImageOptimizationOptions" />
|
||||||
|
|
||||||
|
When enabled, you can now access your images at your configured `accessUrl`. For example, if you have a media file at `/api/media/file/image.jpg`, you can access the optimized image at `/api/plugin/image/optimize/image.jpg` for optimization.
|
||||||
|
|
||||||
|
Now you can add query parameters for the transformations, e.g. `?width=1000&height=1000`.
|
||||||
|
|
||||||
|
<TypeTable
|
||||||
|
type={{
|
||||||
|
dpr: {
|
||||||
|
description:
|
||||||
|
'The device pixel ratio to use',
|
||||||
|
type: 'number',
|
||||||
|
default: 1,
|
||||||
|
},
|
||||||
|
fit: {
|
||||||
|
description: 'The fit mode to use',
|
||||||
|
type: '"scale-down" | "contain" | "cover" | "crop" | "pad"',
|
||||||
|
},
|
||||||
|
format: {
|
||||||
|
description: 'The format to use',
|
||||||
|
type: '"auto" | "avif" | "webp" | "jpeg" | "baseline-jpeg" | "json"'
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
description: 'The height to use',
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
description: 'The width to use',
|
||||||
|
type: 'number',
|
||||||
|
},
|
||||||
|
metadata: {
|
||||||
|
description: 'The metadata to use',
|
||||||
|
type: '"copyright" | "keep" | "none"'
|
||||||
|
},
|
||||||
|
quality: {
|
||||||
|
description: 'The quality to use',
|
||||||
|
type: 'number'
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -123,9 +123,8 @@ import { serve } from "bknd/adapter/cloudflare";
|
|||||||
export default serve<Env>({
|
export default serve<Env>({
|
||||||
// ...
|
// ...
|
||||||
onBuilt: async (app) => {
|
onBuilt: async (app) => {
|
||||||
// [!code highlight]
|
|
||||||
app.server.get("/hello", (c) => c.json({ hello: "world" })); // [!code highlight]
|
app.server.get("/hello", (c) => c.json({ hello: "world" })); // [!code highlight]
|
||||||
}, // [!code highlight]
|
},
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -141,7 +140,6 @@ With the Cloudflare Workers adapter, you're being offered to 4 modes to choose f
|
|||||||
| `fresh` | On every request, the configuration gets refetched, app built and then served. | Ideal if you don't want to deal with eviction, KV or Durable Objects. |
|
| `fresh` | On every request, the configuration gets refetched, app built and then served. | Ideal if you don't want to deal with eviction, KV or Durable Objects. |
|
||||||
| `warm` | It tries to keep the built app in memory for as long as possible, and rebuilds if evicted. | Better response times, should be the default choice. |
|
| `warm` | It tries to keep the built app in memory for as long as possible, and rebuilds if evicted. | Better response times, should be the default choice. |
|
||||||
| `cache` | The configuration is fetched from KV to reduce the initial roundtrip to the database. | Generally faster response times with irregular access patterns. |
|
| `cache` | The configuration is fetched from KV to reduce the initial roundtrip to the database. | Generally faster response times with irregular access patterns. |
|
||||||
| `durable` | The bknd app is ran inside a Durable Object and can be configured to stay alive. | Slowest boot time, but fastest responses. Can be kept alive for as long as you want, giving similar response times as server instances. |
|
|
||||||
|
|
||||||
### Modes: `fresh` and `warm`
|
### Modes: `fresh` and `warm`
|
||||||
|
|
||||||
@@ -172,76 +170,6 @@ export default serve<Env>({
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Mode: `durable` (advanced)
|
|
||||||
|
|
||||||
To use the `durable` mode, you have to specify the Durable Object to extract from your
|
|
||||||
environment, and additionally export the `DurableBkndApp` class:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import { serve, DurableBkndApp } from "bknd/adapter/cloudflare";
|
|
||||||
|
|
||||||
export { DurableBkndApp };
|
|
||||||
export default serve<Env>({
|
|
||||||
// ...
|
|
||||||
mode: "durable",
|
|
||||||
bindings: ({ env }) => ({ dobj: env.DOBJ }),
|
|
||||||
keepAliveSeconds: 60, // optional
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
Next, you need to define the Durable Object in your `wrangler.toml` file (refer to the [Durable
|
|
||||||
Objects](https://developers.cloudflare.com/durable-objects/) documentation):
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[[durable_objects.bindings]]
|
|
||||||
name = "DOBJ"
|
|
||||||
class_name = "DurableBkndApp"
|
|
||||||
|
|
||||||
[[migrations]]
|
|
||||||
tag = "v1"
|
|
||||||
new_classes = ["DurableBkndApp"]
|
|
||||||
```
|
|
||||||
|
|
||||||
Since the communication between the Worker and Durable Object is serialized, the `onBuilt`
|
|
||||||
property won't work. To use it (e.g. to specify special routes), you need to extend from the
|
|
||||||
`DurableBkndApp`:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
import type { App } from "bknd";
|
|
||||||
import { serve, DurableBkndApp } from "bknd/adapter/cloudflare";
|
|
||||||
|
|
||||||
export default serve({
|
|
||||||
// ...
|
|
||||||
mode: "durable",
|
|
||||||
bindings: ({ env }) => ({ dobj: env.DOBJ }),
|
|
||||||
keepAliveSeconds: 60, // optional
|
|
||||||
});
|
|
||||||
|
|
||||||
export class CustomDurableBkndApp extends DurableBkndApp {
|
|
||||||
async onBuilt(app: App) {
|
|
||||||
app.modules.server.get("/custom/endpoint", (c) => c.text("Custom"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
In case you've already deployed your Worker, the deploy command may complain about a new class
|
|
||||||
being used. To fix this issue, you need to add a "rename migration":
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[[durable_objects.bindings]]
|
|
||||||
name = "DOBJ"
|
|
||||||
class_name = "CustomDurableBkndApp"
|
|
||||||
|
|
||||||
[[migrations]]
|
|
||||||
tag = "v1"
|
|
||||||
new_classes = ["DurableBkndApp"]
|
|
||||||
|
|
||||||
[[migrations]]
|
|
||||||
tag = "v2"
|
|
||||||
renamed_classes = [{from = "DurableBkndApp", to = "CustomDurableBkndApp"}]
|
|
||||||
deleted_classes = ["DurableBkndApp"]
|
|
||||||
```
|
|
||||||
|
|
||||||
## D1 Sessions (experimental)
|
## D1 Sessions (experimental)
|
||||||
|
|
||||||
D1 now supports to enable [global read replication](https://developers.cloudflare.com/d1/best-practices/read-replication/). This allows to reduce latency by reading from the closest region. In order for this to work, D1 has to be started from a bookmark. You can enable this behavior on bknd by setting the `d1.session` property:
|
D1 now supports to enable [global read replication](https://developers.cloudflare.com/d1/best-practices/read-replication/). This allows to reduce latency by reading from the closest region. In order for this to work, D1 has to be started from a bookmark. You can enable this behavior on bknd by setting the `d1.session` property:
|
||||||
@@ -272,3 +200,83 @@ If bknd is used in a stateful user context (like in a browser), it'll automatica
|
|||||||
```bash
|
```bash
|
||||||
curl -H "x-cf-d1-session: <bookmark>" ...
|
curl -H "x-cf-d1-session: <bookmark>" ...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Filesystem access with Vite Plugin
|
||||||
|
The [Cloudflare Vite Plugin](https://developers.cloudflare.com/workers/vite-plugin/) allows to use Vite with Miniflare to emulate the Cloudflare Workers runtime. This is great, however, `unenv` disables any Node.js APIs that aren't supported, including the `fs` module. If you want to use plugins such as [`syncTypes`](/extending/plugins#synctypes), this will cause issues.
|
||||||
|
|
||||||
|
To fix this, bknd exports a Vite plugin that provides filesystem access during development. You can use it by adding the following to your `vite.config.ts` file:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { devFsVitePlugin } from "bknd/adapter/cloudflare/vite";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [devFsVitePlugin()], // [!code highlight]
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Now to use this polyfill, you can use the `devFsWrite` function to write files to the filesystem.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { devFsWrite } from "bknd/adapter/cloudflare/vite"; // [!code highlight]
|
||||||
|
import { syncTypes } from "bknd/plugins";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
options: {
|
||||||
|
plugins: [
|
||||||
|
syncTypes({
|
||||||
|
write: async (et) => {
|
||||||
|
await devFsWrite("bknd-types.d.ts", et.toString()); // [!code highlight]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
} satisfies BkndConfig;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cloudflare Bindings in CLI
|
||||||
|
|
||||||
|
The bknd CLI does not automatically have access to the Cloudflare bindings. We need to manually proxy them to the CLI by using the `withPlatformProxy` helper function:
|
||||||
|
|
||||||
|
```typescript title="bknd.config.ts"
|
||||||
|
import { d1 } from "bknd/adapter/cloudflare";
|
||||||
|
import { withPlatformProxy } from "bknd/adapter/cloudflare/proxy";
|
||||||
|
|
||||||
|
export default withPlatformProxy({
|
||||||
|
app: ({ env }) => ({
|
||||||
|
connection: d1({ binding: env.DB }),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you can use the CLI with your Cloudflare resources.
|
||||||
|
|
||||||
|
<Callout type="warning">
|
||||||
|
Make sure to not import from this file in your app, as this would include `wrangler` as a dependency.
|
||||||
|
</Callout>
|
||||||
|
|
||||||
|
Instead, it's recommended to split this configuration into separate files, e.g. `bknd.config.ts` and `config.ts`:
|
||||||
|
|
||||||
|
```typescript title="config.ts"
|
||||||
|
import type { CloudflareBkndConfig } from "bknd/adapter/cloudflare";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
app: ({ env }) => ({
|
||||||
|
connection: d1({ binding: env.DB }),
|
||||||
|
}),
|
||||||
|
} satisfies CloudflareBkndConfig;
|
||||||
|
```
|
||||||
|
|
||||||
|
`config.ts` now holds the configuration, and can safely be imported in your app. Since the CLI looks for a `bknd.config.ts` file by default, we change it to wrap the configuration from `config.ts` in the `withPlatformProxy` helper function.
|
||||||
|
|
||||||
|
```typescript title="bknd.config.ts"
|
||||||
|
import { withPlatformProxy } from "bknd/adapter/cloudflare/proxy";
|
||||||
|
import config from "./config";
|
||||||
|
|
||||||
|
export default withPlatformProxy(config);
|
||||||
|
```
|
||||||
|
|
||||||
|
As an additional safe guard, you have to set a `PROXY` environment variable to `1` to enable the proxy.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PROXY=1 npx bknd types
|
||||||
|
```
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
"---Extending---",
|
"---Extending---",
|
||||||
"./extending/config",
|
"./extending/config",
|
||||||
"./extending/events",
|
"./extending/events",
|
||||||
|
"./extending/plugins",
|
||||||
"---Integration---",
|
"---Integration---",
|
||||||
"./integration/introduction",
|
"./integration/introduction",
|
||||||
"./integration/(frameworks)/",
|
"./integration/(frameworks)/",
|
||||||
|
|||||||
Reference in New Issue
Block a user