Compare commits

..

12 Commits

Author SHA1 Message Date
dswbx dedfb77884 removed durable mode as it requires an import from "cloudflare:" that often fails in non-cf environments 2025-08-12 14:16:22 +02:00
dswbx b5b4c5eef0 Merge pull request #231 from DimplesY/main
fix: add missing @clack/prompts dependency
2025-08-08 13:37:53 +02:00
Dimples_YJ 7af8e09468 fix: add missing @clack/prompts dependency 2025-08-08 13:51:12 +08:00
dswbx fd966b6aef Merge pull request #230 from stormbyte/main
Update Dockerfile to node 24
2025-08-06 20:01:54 +02:00
stormbyte 6bed2e4fca Update to node 24 2025-08-06 16:06:03 +02:00
dswbx dfb1457dfa Merge pull request #229 from DimplesY/main
docs: fix <Admin /> config props
2025-08-06 10:00:33 +02:00
Jie 4f945842a9 docs: update astro.mdx 2025-08-06 15:52:05 +08:00
Jie 44fdfcc8d9 docs: Correct the incorrect value of the config attribute in the admin component 2025-08-06 15:19:28 +08:00
dswbx 143d6a55ff updated lock to 0.16.1 2025-08-06 08:31:19 +02:00
dswbx 8fa905a8f1 docs: adding poster to assets (#228)
* docs: adding poster to assets

* readme: fix poster image
2025-08-06 08:29:46 +02:00
dswbx ad0d2e6ff8 add jsonv-ts as dependency for type inference, fix media api types (#227)
* add jsonv-ts as dependency for type inference, fix media api types

* add jsonv-ts as dependency for type inference, fix media api types

* add jsonv-ts as dependency for type inference, fix media api types
2025-08-06 08:21:17 +02:00
dswbx aa0e6f90d9 examples: fixing imports due to 0.16 (#226) 2025-08-06 08:19:29 +02:00
33 changed files with 5900 additions and 226 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[![npm version](https://img.shields.io/npm/v/bknd.svg)](https://npmjs.org/package/bknd)
![bknd](https://raw.githubusercontent.com/bknd-io/bknd/refs/heads/main/docs/_assets/poster.png)
![bknd](https://raw.githubusercontent.com/bknd-io/bknd/refs/heads/main/docs/public/assets/poster.png)
<p align="center" width="100%">
<a href="https://stackblitz.com/github/bknd-io/bknd-examples?hideExplorer=1&embed=1&view=preview&startScript=example-admin-rich&initialPath=%2Fdata%2Fschema" target="_blank">
+6 -6
View File
@@ -9,16 +9,16 @@ beforeAll(disableConsoleLog);
afterAll(enableConsoleLog);
describe("adapter", () => {
it("makes config", () => {
expect(omitKeys(adapter.makeConfig({}), ["connection"])).toEqual({});
expect(omitKeys(adapter.makeConfig({}, { env: { TEST: "test" } }), ["connection"])).toEqual(
{},
);
it("makes config", async () => {
expect(omitKeys(await adapter.makeConfig({}), ["connection"])).toEqual({});
expect(
omitKeys(await adapter.makeConfig({}, { env: { TEST: "test" } }), ["connection"]),
).toEqual({});
// merges everything returned from `app` with the config
expect(
omitKeys(
adapter.makeConfig(
await adapter.makeConfig(
{ app: (a) => ({ initialConfig: { server: { cors: { origin: a.env.TEST } } } }) },
{ env: { TEST: "test" } },
),
+4 -3
View File
@@ -3,7 +3,7 @@
"type": "module",
"sideEffects": false,
"bin": "./dist/cli/index.js",
"version": "0.16.0",
"version": "0.16.1",
"description": "Lightweight Firebase/Supabase alternative built to run anywhere — incl. Next.js, React Router, Astro, Cloudflare, Bun, Node, AWS Lambda & more.",
"homepage": "https://bknd.io",
"repository": {
@@ -64,7 +64,8 @@
"hono": "4.8.3",
"json-schema-library": "10.0.0-rc7",
"json-schema-to-ts": "^3.1.1",
"kysely": "^0.27.6",
"jsonv-ts": "0.3.2",
"kysely": "0.27.6",
"lodash-es": "^4.17.21",
"oauth4webapi": "^2.11.1",
"object-path-immutable": "^4.1.2",
@@ -74,6 +75,7 @@
"devDependencies": {
"@aws-sdk/client-s3": "^3.758.0",
"@bluwy/giget-core": "^0.1.2",
"@clack/prompts": "^0.11.0",
"@cloudflare/vitest-pool-workers": "^0.8.38",
"@cloudflare/workers-types": "^4.20250606.0",
"@dagrejs/dagre": "^1.1.4",
@@ -100,7 +102,6 @@
"dotenv": "^16.4.7",
"jotai": "^2.12.2",
"jsdom": "^26.0.0",
"jsonv-ts": "^0.3.2",
"kysely-d1": "^0.3.0",
"kysely-generic-sqlite": "^1.2.1",
"libsql-stateless-easy": "^1.8.0",
@@ -18,7 +18,7 @@ describe("cf adapter", () => {
});
it("makes config", async () => {
const staticConfig = makeConfig(
const staticConfig = await makeConfig(
{
connection: { url: DB_URL },
initialConfig: { data: { basepath: DB_URL } },
@@ -28,7 +28,7 @@ describe("cf adapter", () => {
expect(staticConfig.initialConfig).toEqual({ data: { basepath: DB_URL } });
expect(staticConfig.connection).toBeDefined();
const dynamicConfig = makeConfig(
const dynamicConfig = await makeConfig(
{
app: (env) => ({
initialConfig: { data: { basepath: env.DB_URL } },
@@ -5,7 +5,6 @@ import { Hono } from "hono";
import { serveStatic } from "hono/cloudflare-workers";
import { getFresh } from "./modes/fresh";
import { getCached } from "./modes/cached";
import { getDurable } from "./modes/durable";
import type { App } from "bknd";
import { $console } from "core/utils";
@@ -17,10 +16,9 @@ declare global {
export type CloudflareEnv = Cloudflare.Env;
export type CloudflareBkndConfig<Env = CloudflareEnv> = RuntimeBkndConfig<Env> & {
mode?: "warm" | "fresh" | "cache" | "durable";
mode?: "warm" | "fresh" | "cache";
bindings?: (args: Env) => {
kv?: KVNamespace;
dobj?: DurableObjectNamespace;
db?: D1Database;
};
d1?: {
@@ -93,8 +91,6 @@ export function serve<Env extends CloudflareEnv = CloudflareEnv>(
case "cache":
app = await getCached(config, context);
break;
case "durable":
return await getDurable(config, context);
default:
throw new Error(`Unknown mode ${mode}`);
}
+3 -3
View File
@@ -89,7 +89,7 @@ export function d1SessionHelper(config: CloudflareBkndConfig<any>) {
}
let media_registered: boolean = false;
export function makeConfig<Env extends CloudflareEnv = CloudflareEnv>(
export async function makeConfig<Env extends CloudflareEnv = CloudflareEnv>(
config: CloudflareBkndConfig<Env>,
args?: CfMakeConfigArgs<Env>,
) {
@@ -102,7 +102,7 @@ export function makeConfig<Env extends CloudflareEnv = CloudflareEnv>(
media_registered = true;
}
const appConfig = makeAdapterConfig(config, args?.env);
const appConfig = await makeAdapterConfig(config, args?.env);
// if connection instance is given, don't do anything
// other than checking if D1 session is defined
@@ -115,7 +115,7 @@ export function makeConfig<Env extends CloudflareEnv = CloudflareEnv>(
}
// if connection is given, try to open with unified sqlite adapter
} else if (appConfig.connection) {
appConfig.connection = sqlite(appConfig.connection);
appConfig.connection = sqlite(appConfig.connection) as any;
// if connection is not given, but env is set
// try to make D1 from bindings
-1
View File
@@ -3,7 +3,6 @@ import { d1Sqlite, type D1ConnectionConfig } from "./connection/D1Connection";
export * from "./cloudflare-workers.adapter";
export { makeApp, getFresh } from "./modes/fresh";
export { getCached } from "./modes/cached";
export { DurableBkndApp, getDurable } from "./modes/durable";
export { d1Sqlite, type D1ConnectionConfig };
export {
getBinding,
-134
View File
@@ -1,134 +0,0 @@
import { DurableObject } from "cloudflare:workers";
import type { App, CreateAppConfig } from "bknd";
import { createRuntimeApp, makeConfig } from "bknd/adapter";
import type { CloudflareBkndConfig, Context, CloudflareEnv } from "../index";
import { constants, registerAsyncsExecutionContext } from "../config";
import { $console } from "core/utils";
export async function getDurable<Env extends CloudflareEnv = CloudflareEnv>(
config: CloudflareBkndConfig<Env>,
ctx: Context<Env>,
) {
const { dobj } = config.bindings?.(ctx.env)!;
if (!dobj) throw new Error("durable object is not defined in cloudflare.bindings");
const key = config.key ?? "app";
if ([config.onBuilt, config.beforeBuild].some((x) => x)) {
$console.warn("onBuilt and beforeBuild are not supported with DurableObject mode");
}
const start = performance.now();
const id = dobj.idFromName(key);
const stub = dobj.get(id) as unknown as DurableBkndApp;
const create_config = makeConfig(config, ctx.env);
const res = await stub.fire(ctx.request, {
config: create_config,
keepAliveSeconds: config.keepAliveSeconds,
});
const headers = new Headers(res.headers);
headers.set("X-TTDO", String(performance.now() - start));
return new Response(res.body, {
status: res.status,
statusText: res.statusText,
headers,
});
}
export class DurableBkndApp extends DurableObject {
protected id = Math.random().toString(36).slice(2);
protected app?: App;
protected interval?: any;
async fire(
request: Request,
options: {
config: CreateAppConfig;
html?: string;
keepAliveSeconds?: number;
setAdminHtml?: boolean;
},
) {
let buildtime = 0;
if (!this.app) {
const start = performance.now();
const config = options.config;
// change protocol to websocket if libsql
if (
config?.connection &&
"type" in config.connection &&
config.connection.type === "libsql"
) {
//config.connection.config.protocol = "wss";
}
this.app = await createRuntimeApp({
...config,
onBuilt: async (app) => {
registerAsyncsExecutionContext(app, this.ctx);
app.modules.server.get(constants.do_endpoint, async (c) => {
// @ts-ignore
const context: any = c.req.raw.cf ? c.req.raw.cf : c.env.cf;
return c.json({
id: this.id,
keepAliveSeconds: options?.keepAliveSeconds ?? 0,
colo: context.colo,
});
});
await this.onBuilt(app);
},
adminOptions: { html: options.html },
beforeBuild: async (app) => {
await this.beforeBuild(app);
},
});
buildtime = performance.now() - start;
}
if (options?.keepAliveSeconds) {
this.keepAlive(options.keepAliveSeconds);
}
const res = await this.app!.fetch(request);
const headers = new Headers(res.headers);
headers.set("X-BuildTime", buildtime.toString());
headers.set("X-DO-ID", this.id);
return new Response(res.body, {
status: res.status,
statusText: res.statusText,
headers,
});
}
async onBuilt(app: App) {}
async beforeBuild(app: App) {}
protected keepAlive(seconds: number) {
if (this.interval) {
clearInterval(this.interval);
}
let i = 0;
this.interval = setInterval(() => {
i += 1;
if (i === seconds) {
console.log("cleared");
clearInterval(this.interval);
// ping every 30 seconds
} else if (i % 30 === 0) {
console.log("ping");
this.app?.modules.ctx().connection.ping();
}
}, 1000);
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ export async function makeApp<Env extends CloudflareEnv = CloudflareEnv>(
args?: CfMakeConfigArgs<Env>,
opts?: RuntimeOptions,
) {
return await createRuntimeApp<Env>(makeConfig(config, args), args?.env, opts);
return await createRuntimeApp<Env>(await makeConfig(config, args), args?.env, opts);
}
export async function getFresh<Env extends CloudflareEnv = CloudflareEnv>(
@@ -1,4 +1,4 @@
import { registries, isDebug, guessMimeType } from "bknd";
import { registries as $registries, isDebug, guessMimeType } from "bknd";
import { getBindings } from "../bindings";
import { s } from "bknd/utils";
import { StorageAdapter, type FileBody } from "bknd";
@@ -12,7 +12,10 @@ export function makeSchema(bindings: string[] = []) {
);
}
export function registerMedia(env: Record<string, any>) {
export function registerMedia(
env: Record<string, any>,
registries: typeof $registries = $registries,
) {
const r2_bindings = getBindings(env, "R2Bucket");
registries.media.register(
+18 -10
View File
@@ -1,13 +1,21 @@
import { config as $config, App, type CreateAppConfig, Connection, guessMimeType } from "bknd";
import {
config as $config,
App,
type CreateAppConfig,
Connection,
guessMimeType,
type MaybePromise,
registries as $registries,
} from "bknd";
import { $console } from "bknd/utils";
import type { Context, MiddlewareHandler, Next } from "hono";
import type { AdminControllerOptions } from "modules/server/AdminController";
import type { Manifest } from "vite";
export type BkndConfig<Args = any> = CreateAppConfig & {
app?: CreateAppConfig | ((args: Args) => CreateAppConfig);
app?: CreateAppConfig | ((args: Args) => MaybePromise<CreateAppConfig>);
onBuilt?: (app: App) => Promise<void>;
beforeBuild?: (app: App) => Promise<void>;
beforeBuild?: (app: App, registries?: typeof $registries) => Promise<void>;
buildConfig?: Parameters<App["build"]>[0];
};
@@ -30,10 +38,10 @@ export type DefaultArgs = {
[key: string]: any;
};
export function makeConfig<Args = DefaultArgs>(
export async function makeConfig<Args = DefaultArgs>(
config: BkndConfig<Args>,
args?: Args,
): CreateAppConfig {
): Promise<CreateAppConfig> {
let additionalConfig: CreateAppConfig = {};
const { app, ...rest } = config;
if (app) {
@@ -41,7 +49,7 @@ export function makeConfig<Args = DefaultArgs>(
if (!args) {
throw new Error("args is required when config.app is a function");
}
additionalConfig = app(args);
additionalConfig = await app(args);
} else {
additionalConfig = app;
}
@@ -60,7 +68,7 @@ export async function createAdapterApp<Config extends BkndConfig = BkndConfig, A
const id = opts?.id ?? "app";
let app = apps.get(id);
if (!app || opts?.force) {
const appConfig = makeConfig(config, args);
const appConfig = await makeConfig(config, args);
if (!appConfig.connection || !Connection.isConnection(appConfig.connection)) {
let connection: Connection | undefined;
if (Connection.isConnection(config.connection)) {
@@ -68,7 +76,7 @@ export async function createAdapterApp<Config extends BkndConfig = BkndConfig, A
} else {
const sqlite = (await import("bknd/adapter/sqlite")).sqlite;
const conf = appConfig.connection ?? { url: ":memory:" };
connection = sqlite(conf);
connection = sqlite(conf) as any;
$console.info(`Using ${connection!.name} connection`, conf.url);
}
appConfig.connection = connection;
@@ -98,7 +106,7 @@ export async function createFrameworkApp<Args = DefaultArgs>(
);
}
await config.beforeBuild?.(app);
await config.beforeBuild?.(app, $registries);
await app.build(config.buildConfig);
}
@@ -131,7 +139,7 @@ export async function createRuntimeApp<Args = DefaultArgs>(
"sync",
);
await config.beforeBuild?.(app);
await config.beforeBuild?.(app, $registries);
await app.build(config.buildConfig);
}
+1 -1
View File
@@ -77,7 +77,7 @@ async function makeApp(config: MakeAppConfig) {
}
export async function makeConfigApp(_config: CliBkndConfig, platform?: Platform) {
const config = makeConfig(_config, process.env);
const config = await makeConfig(_config, process.env);
return makeApp({
...config,
server: { platform },
+1
View File
@@ -39,6 +39,7 @@ export { registries } from "modules/registries";
/**
* Core
*/
export type { MaybePromise } from "core/types";
export { Exception, BkndError } from "core/errors";
export { isDebug, env } from "core/env";
export { type PrimaryFieldType, config, type DB, type AppEntity } from "core/config";
+3 -3
View File
@@ -68,7 +68,7 @@ export class MediaApi extends ModuleApi<MediaApiOptions> {
}
protected uploadFile(
body: File | Blob | ReadableStream,
body: File | Blob | ReadableStream | Buffer<ArrayBufferLike>,
opts?: {
filename?: string;
path?: TInput;
@@ -110,7 +110,7 @@ export class MediaApi extends ModuleApi<MediaApiOptions> {
}
async upload(
item: Request | Response | string | File | Blob | ReadableStream,
item: Request | Response | string | File | Blob | ReadableStream | Buffer<ArrayBufferLike>,
opts: {
filename?: string;
_init?: Omit<RequestInit, "body">;
@@ -148,7 +148,7 @@ export class MediaApi extends ModuleApi<MediaApiOptions> {
entity: string,
id: PrimaryFieldType,
field: string,
item: Request | Response | string | File | ReadableStream,
item: Request | Response | string | File | ReadableStream | Buffer<ArrayBufferLike>,
opts?: {
_init?: Omit<RequestInit, "body">;
fetcher?: typeof fetch;
@@ -183,13 +183,13 @@ export class StorageS3Adapter extends StorageAdapter {
method: "GET",
headers: pickHeaders2(headers, [
"if-none-match",
"accept-encoding",
//"accept-encoding", (causes 403 on r2)
"accept",
"if-modified-since",
]),
});
// Response has to be copied, because of middlewares that might set headers
// response has to be copied, because of middlewares that might set headers
return new Response(res.body, {
status: res.status,
statusText: res.statusText,
@@ -94,8 +94,8 @@ export const TriggerNode = (props: NodeProps<Node<TAppFlowTriggerSchema & { labe
control={control}
/>
</div>
{data.type === "manual" && <Manual />}
{data.type === "http" && (
{data?.type === "manual" && <Manual />}
{data?.type === "http" && (
<Http form={{ watch, register, setValue, getValues, control }} />
)}
</form>
+8 -3
View File
@@ -15,7 +15,7 @@
},
"app": {
"name": "bknd",
"version": "0.16.0-rc.0",
"version": "0.16.1",
"bin": "./dist/cli/index.js",
"dependencies": {
"@cfworker/json-schema": "^4.1.1",
@@ -35,7 +35,8 @@
"hono": "4.8.3",
"json-schema-library": "10.0.0-rc7",
"json-schema-to-ts": "^3.1.1",
"kysely": "^0.27.6",
"jsonv-ts": "0.3.2",
"kysely": "0.27.6",
"lodash-es": "^4.17.21",
"oauth4webapi": "^2.11.1",
"object-path-immutable": "^4.1.2",
@@ -45,6 +46,7 @@
"devDependencies": {
"@aws-sdk/client-s3": "^3.758.0",
"@bluwy/giget-core": "^0.1.2",
"@clack/prompts": "^0.11.0",
"@cloudflare/vitest-pool-workers": "^0.8.38",
"@cloudflare/workers-types": "^4.20250606.0",
"@dagrejs/dagre": "^1.1.4",
@@ -71,7 +73,6 @@
"dotenv": "^16.4.7",
"jotai": "^2.12.2",
"jsdom": "^26.0.0",
"jsonv-ts": "^0.3.2",
"kysely-d1": "^0.3.0",
"kysely-generic-sqlite": "^1.2.1",
"libsql-stateless-easy": "^1.8.0",
@@ -503,6 +504,10 @@
"@cfworker/json-schema": ["@cfworker/json-schema@4.1.1", "", {}, "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og=="],
"@clack/core": ["@clack/core@0.5.0", "https://registry.npmmirror.com/@clack/core/-/core-0.5.0.tgz", { "dependencies": { "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow=="],
"@clack/prompts": ["@clack/prompts@0.11.0", "https://registry.npmmirror.com/@clack/prompts/-/prompts-0.11.0.tgz", { "dependencies": { "@clack/core": "0.5.0", "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw=="],
"@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.4.0", "", { "dependencies": { "mime": "^3.0.0" } }, "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA=="],
"@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.3.2", "", { "peerDependencies": { "unenv": "2.0.0-rc.17", "workerd": "^1.20250508.0" }, "optionalPeers": ["workerd"] }, "sha512-MtUgNl+QkQyhQvv5bbWP+BpBC1N0me4CHHuP2H4ktmOMKdB/6kkz/lo+zqiA4mEazb4y+1cwyNjVrQ2DWeE4mg=="],
+3 -3
View File
@@ -1,5 +1,5 @@
# Stage 1: Build stage
FROM node:20 as builder
FROM node:24 as builder
WORKDIR /app
@@ -12,7 +12,7 @@ RUN npm install --omit=dev bknd@${VERSION}
RUN mkdir /output && cp -r node_modules/bknd/dist /output/dist
# Stage 2: Final minimal image
FROM node:20-alpine
FROM node:24-alpine
WORKDIR /app
@@ -29,4 +29,4 @@ ENV DEFAULT_ARGS="--db-url file:/data/data.db"
COPY --from=builder /output/dist ./dist
EXPOSE 1337
CMD ["pm2-runtime", "dist/cli/index.js run ${ARGS:-${DEFAULT_ARGS}} --no-open"]
CMD ["pm2-runtime", "dist/cli/index.js run ${ARGS:-${DEFAULT_ARGS}} --no-open"]
@@ -173,7 +173,7 @@ export const prerender = false;
withProvider={{ user }}
config={{
basepath: "/admin",
color_scheme: "dark",
theme: "dark",
logo_return_path: "/../"
}}
client:only
@@ -145,7 +145,7 @@ export default async function AdminPage() {
config={{
basepath: "/admin",
logo_return_path: "/../",
color_scheme: "system",
theme: "system",
}}
/>
);
Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

+2 -2
View File
@@ -1,6 +1,6 @@
import type { AstroBkndConfig } from "bknd/adapter/astro";
import { registerLocalMediaAdapter } from "bknd/adapter/node";
import { boolean, em, entity, text } from "bknd/data";
import { boolean, em, entity, text } from "bknd";
import { secureRandomString } from "bknd/utils";
// since we're running in node, we can register the local media adapter
@@ -16,7 +16,7 @@ const schema = em({
// register your schema to get automatic type completion
type Database = (typeof schema)["DB"];
declare module "bknd/core" {
declare module "bknd" {
interface DB extends Database {}
}
+2
View File
@@ -170,3 +170,5 @@ dist
.dev.vars
.wrangler/
bknd-types.d.ts
worker-configuration.d.ts
+47
View File
@@ -0,0 +1,47 @@
/**
* The configuration below is for advanced use cases. In order to enable types generation,
* we need access to the database. However, for Cloudflare D1, we need the platform proxy.
*
* Since this configuration should serve all purposes, including usage within the worker itself,
* we need to use an environment variable to determine if we need to extract the DB from proxy.
*
* To make D1 session work in the actual worker,
*/
import { d1, registerMedia, type CloudflareBkndConfig } from "bknd/adapter/cloudflare";
import type { PlatformProxy } from "wrangler";
import process from "node:process";
const use_proxy = process.env.PROXY === "1";
let proxy: PlatformProxy | undefined;
async function getEnv(env?: Env): Promise<Env> {
if (use_proxy) {
if (!proxy) {
const getPlatformProxy = await import("wrangler").then((mod) => mod.getPlatformProxy);
proxy = await getPlatformProxy();
setTimeout(proxy?.dispose, 1000);
}
return proxy.env as unknown as Env;
}
return env!;
}
export default {
app: async (_env) => {
if (!use_proxy) return {};
const env = await getEnv(_env);
return {
connection: d1({
binding: env.DB,
}),
};
},
beforeBuild: async (app, registries) => {
if (!use_proxy) return;
registerMedia(await getEnv(), registries);
},
d1: {
session: true,
},
} satisfies CloudflareBkndConfig<Env>;
+4 -1
View File
@@ -2,10 +2,13 @@
"name": "cloudflare-worker",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"deploy": "wrangler deploy",
"dev": "wrangler dev",
"typegen": "wrangler types"
"bknd-typegen": "PROXY=1 npx bknd types",
"typegen": "wrangler types && npm run bknd-typegen",
"predev": "npm run typegen"
},
"dependencies": {
"bknd": "file:../../app"
+2 -6
View File
@@ -1,8 +1,4 @@
import { serve } from "bknd/adapter/cloudflare";
import config from "../bknd.config";
export default serve({
mode: "warm",
d1: {
session: true,
},
});
export default serve(config);
+10 -7
View File
@@ -1,11 +1,9 @@
{
"compilerOptions": {
"target": "es2021",
"lib": ["es2021"],
"jsx": "react-jsx",
"module": "es2022",
"moduleResolution": "Bundler",
"types": ["./worker-configuration.d.ts"],
"lib": ["ES2022"],
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"allowJs": true,
"checkJs": false,
@@ -18,5 +16,10 @@
"skipLibCheck": true
},
"exclude": ["test"],
"include": ["worker-configuration.d.ts", "src/**/*.ts"]
"include": [
"worker-configuration.d.ts",
"bknd-types.d.ts",
"bknd.config.ts",
"src/**/*.ts"
]
}
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,5 +1,5 @@
import type { NextjsBkndConfig } from "bknd/adapter/nextjs";
import { boolean, em, entity, text } from "bknd/data";
import { boolean, em, entity, text } from "bknd";
import { registerLocalMediaAdapter } from "bknd/adapter/node";
import { secureRandomString } from "bknd/utils";
@@ -22,7 +22,7 @@ const schema = em({
// register your schema to get automatic type completion
type Database = (typeof schema)["DB"];
declare module "bknd/core" {
declare module "bknd" {
interface DB extends Database {}
}
+11 -12
View File
@@ -1,6 +1,5 @@
import { App } from "bknd";
import { serve } from "bknd/adapter/vite";
import { boolean, em, entity, text } from "bknd/data";
import { App, boolean, em, entity, text } from "bknd";
import { secureRandomString } from "bknd/utils";
export default serve({
@@ -8,23 +7,23 @@ export default serve({
data: em({
todos: entity("todos", {
title: text(),
done: boolean()
})
done: boolean(),
}),
}).toJSON(),
auth: {
enabled: true,
jwt: {
secret: secureRandomString(64)
}
}
secret: secureRandomString(64),
},
},
},
options: {
seed: async (ctx) => {
await ctx.em.mutator("todos" as any).insertMany([
{ title: "Learn bknd", done: true },
{ title: "Build something cool", done: false }
{ title: "Build something cool", done: false },
]);
}
},
},
// here we can hook into the app lifecycle events ...
beforeBuild: async (app) => {
@@ -34,10 +33,10 @@ export default serve({
// ... to create an initial user
await app.module.auth.createUser({
email: "ds@bknd.io",
password: "12345678"
password: "12345678",
});
},
"sync"
"sync",
);
}
},
});
+2 -2
View File
@@ -1,6 +1,6 @@
import { registerLocalMediaAdapter } from "bknd/adapter/node";
import type { ReactRouterBkndConfig } from "bknd/adapter/react-router";
import { boolean, em, entity, text } from "bknd/data";
import { boolean, em, entity, text } from "bknd";
import { secureRandomString } from "bknd/utils";
// since we're running in node, we can register the local media adapter
@@ -15,7 +15,7 @@ const schema = em({
// register your schema to get automatic type completion
type Database = (typeof schema)["DB"];
declare module "bknd/core" {
declare module "bknd" {
interface DB extends Database {}
}
+2 -3
View File
@@ -1,7 +1,6 @@
import { lazy, Suspense, useEffect, useState } from "react";
import { App } from "bknd";
import { checksum } from "bknd/utils";
import { boolean, em, entity, text } from "bknd/data";
import { App, boolean, em, entity, text } from "bknd";
import { SQLocalConnection } from "@bknd/sqlocal";
import { Route, Router, Switch } from "wouter";
import IndexPage from "~/routes/_index";
@@ -68,7 +67,7 @@ const schema = em({
// register your schema to get automatic type completion
type Database = (typeof schema)["DB"];
declare module "bknd/core" {
declare module "bknd" {
interface DB extends Database {}
}
+2 -2
View File
@@ -1,6 +1,6 @@
import { registerLocalMediaAdapter } from "bknd/adapter/node";
import type { BkndConfig } from "bknd/adapter";
import { boolean, em, entity, text } from "bknd/data";
import { boolean, em, entity, text } from "bknd";
import { secureRandomString } from "bknd/utils";
// since we're running in node, we can register the local media adapter
@@ -15,7 +15,7 @@ const schema = em({
// register your schema to get automatic type completion
type Database = (typeof schema)["DB"];
declare module "bknd/core" {
declare module "bknd" {
interface DB extends Database {}
}