mirror of
https://github.com/bknd-io/bknd/
synced 2026-08-02 08:06:00 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c26d646bd | |||
| 4859b99954 | |||
| 3f55c0f2c5 | |||
| 9ec31373e1 | |||
| 70b25a9f9b | |||
| 300d86ff7c | |||
| 4c9b662f6f | |||
| a862cfdcf1 | |||
| de62f4e729 | |||
| 4575d89cfe | |||
| 0ca0828581 | |||
| 07a57ebf67 | |||
| e9f1241ec3 | |||
| 80903d4ffa | |||
| c8290802e9 | |||
| ac6cd4a900 | |||
| a91ddb1ec3 |
@@ -20,7 +20,7 @@ jobs:
|
|||||||
- name: Setup Bun
|
- name: Setup Bun
|
||||||
uses: oven-sh/setup-bun@v1
|
uses: oven-sh/setup-bun@v1
|
||||||
with:
|
with:
|
||||||
bun-version: "1.2.22"
|
bun-version: "1.3.1"
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
working-directory: ./app
|
working-directory: ./app
|
||||||
|
|||||||
+2
-1
@@ -27,7 +27,8 @@ packages/media/.env
|
|||||||
.npmrc
|
.npmrc
|
||||||
/.verdaccio
|
/.verdaccio
|
||||||
.idea
|
.idea
|
||||||
.vscode
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
.git_old
|
.git_old
|
||||||
docker/tmp
|
docker/tmp
|
||||||
.debug
|
.debug
|
||||||
|
|||||||
Vendored
+19
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
|
"biome.enabled": true,
|
||||||
|
"editor.defaultFormatter": "biomejs.biome",
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.organizeImports.biome": "explicit",
|
||||||
|
"source.fixAll.biome": "explicit"
|
||||||
|
},
|
||||||
|
"typescript.preferences.importModuleSpecifier": "non-relative",
|
||||||
|
"typescript.preferences.autoImportFileExcludePatterns": [
|
||||||
|
"**/dist/**",
|
||||||
|
"**/node_modules/**/dist/**",
|
||||||
|
"**/node_modules/**/!(src|lib|esm)/**" // optional, stricter
|
||||||
|
],
|
||||||
|
"typescript.preferences.includePackageJsonAutoImports": "on",
|
||||||
|
"typescript.tsserver.watchOptions": {
|
||||||
|
"excludeDirectories": ["**/dist", "**/node_modules/**/dist"]
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"typescript.preferences.includePackageJsonAutoImports": "off",
|
||||||
|
"typescript.suggest.autoImports": true,
|
||||||
|
"typescript.preferences.importModuleSpecifier": "relative",
|
||||||
|
"search.exclude": {
|
||||||
|
"**/dist/**": true,
|
||||||
|
"**/node_modules/**": true
|
||||||
|
},
|
||||||
|
"files.exclude": {
|
||||||
|
"**/dist/**": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -108,7 +108,7 @@ describe("App tests", async () => {
|
|||||||
expect(Array.from(app.plugins.keys())).toEqual(["test"]);
|
expect(Array.from(app.plugins.keys())).toEqual(["test"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.only("drivers", async () => {
|
test("drivers", async () => {
|
||||||
const called: string[] = [];
|
const called: string[] = [];
|
||||||
const app = new App(dummyConnection, undefined, {
|
const app = new App(dummyConnection, undefined, {
|
||||||
drivers: {
|
drivers: {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const mockedBackend = new Hono()
|
|||||||
.get("/file/:name", async (c) => {
|
.get("/file/:name", async (c) => {
|
||||||
const { name } = c.req.param();
|
const { name } = c.req.param();
|
||||||
const file = Bun.file(`${assetsPath}/${name}`);
|
const file = Bun.file(`${assetsPath}/${name}`);
|
||||||
return new Response(file, {
|
return new Response(new File([await file.bytes()], name, { type: file.type }), {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": file.type,
|
"Content-Type": file.type,
|
||||||
"Content-Length": file.size.toString(),
|
"Content-Length": file.size.toString(),
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ describe("repros", async () => {
|
|||||||
expect(app.em.entities.map((e) => e.name)).toEqual(["media", "test"]);
|
expect(app.em.entities.map((e) => e.name)).toEqual(["media", "test"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.only("verify inversedBy", async () => {
|
test("verify inversedBy", async () => {
|
||||||
const schema = proto.em(
|
const schema = proto.em(
|
||||||
{
|
{
|
||||||
products: proto.entity("products", {
|
products: proto.entity("products", {
|
||||||
|
|||||||
@@ -1,30 +1,10 @@
|
|||||||
import pkg from "./package.json" with { type: "json" };
|
import pkg from "./package.json" with { type: "json" };
|
||||||
import c from "picocolors";
|
import c from "picocolors";
|
||||||
import { formatNumber } from "bknd/utils";
|
import { formatNumber } from "bknd/utils";
|
||||||
import * as esbuild from "esbuild";
|
|
||||||
|
|
||||||
const deps = Object.keys(pkg.dependencies);
|
const deps = Object.keys(pkg.dependencies);
|
||||||
const external = ["jsonv-ts/*", "wrangler", "bknd", "bknd/*", ...deps];
|
const external = ["jsonv-ts/*", "wrangler", "bknd", "bknd/*", ...deps];
|
||||||
|
|
||||||
if (process.env.DEBUG) {
|
|
||||||
const result = await esbuild.build({
|
|
||||||
entryPoints: ["./src/cli/index.ts"],
|
|
||||||
outdir: "./dist/cli",
|
|
||||||
platform: "node",
|
|
||||||
minify: true,
|
|
||||||
format: "esm",
|
|
||||||
metafile: true,
|
|
||||||
bundle: true,
|
|
||||||
external,
|
|
||||||
define: {
|
|
||||||
__isDev: "0",
|
|
||||||
__version: JSON.stringify(pkg.version),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
await Bun.write("./dist/cli/metafile-esm.json", JSON.stringify(result.metafile, null, 2));
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await Bun.build({
|
const result = await Bun.build({
|
||||||
entrypoints: ["./src/cli/index.ts"],
|
entrypoints: ["./src/cli/index.ts"],
|
||||||
target: "node",
|
target: "node",
|
||||||
|
|||||||
+13
-2
@@ -1,3 +1,4 @@
|
|||||||
|
/** biome-ignore-all lint/suspicious/noConsole: . */
|
||||||
import { $ } from "bun";
|
import { $ } from "bun";
|
||||||
import * as tsup from "tsup";
|
import * as tsup from "tsup";
|
||||||
import pkg from "./package.json" with { type: "json" };
|
import pkg from "./package.json" with { type: "json" };
|
||||||
@@ -96,6 +97,7 @@ async function buildApi() {
|
|||||||
metafile: true,
|
metafile: true,
|
||||||
target: "esnext",
|
target: "esnext",
|
||||||
platform: "browser",
|
platform: "browser",
|
||||||
|
removeNodeProtocol: false,
|
||||||
format: ["esm"],
|
format: ["esm"],
|
||||||
splitting: false,
|
splitting: false,
|
||||||
loader: {
|
loader: {
|
||||||
@@ -228,6 +230,7 @@ function baseConfig(adapter: string, overrides: Partial<tsup.Options> = {}): tsu
|
|||||||
outDir: `dist/adapter/${adapter}`,
|
outDir: `dist/adapter/${adapter}`,
|
||||||
metafile: true,
|
metafile: true,
|
||||||
splitting: false,
|
splitting: false,
|
||||||
|
removeNodeProtocol: false,
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
delayTypes();
|
delayTypes();
|
||||||
oldConsole.log(c.cyan("[Adapter]"), adapter || "base", c.green("built"));
|
oldConsole.log(c.cyan("[Adapter]"), adapter || "base", c.green("built"));
|
||||||
@@ -265,7 +268,7 @@ async function buildAdapters() {
|
|||||||
tsup.build(baseConfig("react-router")),
|
tsup.build(baseConfig("react-router")),
|
||||||
tsup.build(
|
tsup.build(
|
||||||
baseConfig("bun", {
|
baseConfig("bun", {
|
||||||
external: [/^bun\:.*/],
|
external: [/^bun:.*/],
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
tsup.build(baseConfig("astro")),
|
tsup.build(baseConfig("astro")),
|
||||||
@@ -284,6 +287,14 @@ async function buildAdapters() {
|
|||||||
external: [/bknd/, "wrangler", "node:process"],
|
external: [/bknd/, "wrangler", "node:process"],
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
tsup.build(
|
||||||
|
baseConfig("cloudflare/vite", {
|
||||||
|
target: "esnext",
|
||||||
|
entry: ["src/adapter/cloudflare/vite.ts"],
|
||||||
|
outDir: "dist/adapter/cloudflare",
|
||||||
|
metafile: false,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
|
||||||
tsup.build({
|
tsup.build({
|
||||||
...baseConfig("vite"),
|
...baseConfig("vite"),
|
||||||
@@ -320,7 +331,7 @@ async function buildAdapters() {
|
|||||||
entry: ["src/adapter/sqlite/bun.ts"],
|
entry: ["src/adapter/sqlite/bun.ts"],
|
||||||
outDir: "dist/adapter/sqlite",
|
outDir: "dist/adapter/sqlite",
|
||||||
metafile: false,
|
metafile: false,
|
||||||
external: [/^bun\:.*/],
|
external: [/^bun:.*/],
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
[install]
|
|
||||||
#registry = "http://localhost:4873"
|
|
||||||
|
|
||||||
[test]
|
|
||||||
coverageSkipTestFiles = true
|
|
||||||
console.depth = 10
|
|
||||||
+59
-49
@@ -13,7 +13,7 @@
|
|||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/bknd-io/bknd/issues"
|
"url": "https://github.com/bknd-io/bknd/issues"
|
||||||
},
|
},
|
||||||
"packageManager": "bun@1.2.22",
|
"packageManager": "bun@1.3.1",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22.13"
|
"node": ">=22.13"
|
||||||
},
|
},
|
||||||
@@ -49,93 +49,98 @@
|
|||||||
"license": "FSL-1.1-MIT",
|
"license": "FSL-1.1-MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cfworker/json-schema": "^4.1.1",
|
"@cfworker/json-schema": "^4.1.1",
|
||||||
"@codemirror/lang-html": "^6.4.9",
|
"@codemirror/lang-html": "^6.4.11",
|
||||||
"@codemirror/lang-json": "^6.0.1",
|
"@codemirror/lang-json": "^6.0.2",
|
||||||
"@hello-pangea/dnd": "^18.0.1",
|
"@hello-pangea/dnd": "^18.0.1",
|
||||||
"@hono/swagger-ui": "^0.5.1",
|
"@hono/swagger-ui": "^0.5.2",
|
||||||
"@mantine/core": "^7.17.1",
|
"@mantine/core": "^7.17.1",
|
||||||
"@mantine/hooks": "^7.17.1",
|
"@mantine/hooks": "^7.17.1",
|
||||||
"@tanstack/react-form": "^1.0.5",
|
"@tanstack/react-form": "^1.0.5",
|
||||||
"@uiw/react-codemirror": "^4.23.10",
|
"@uiw/react-codemirror": "^4.25.2",
|
||||||
"@xyflow/react": "^12.4.4",
|
"@xyflow/react": "^12.9.2",
|
||||||
"aws4fetch": "^1.0.20",
|
"aws4fetch": "^1.0.20",
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.3",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.19",
|
||||||
"fast-xml-parser": "^5.0.8",
|
"fast-xml-parser": "^5.3.1",
|
||||||
"hono": "4.8.3",
|
"hono": "4.10.4",
|
||||||
"json-schema-library": "10.0.0-rc7",
|
"json-schema-library": "10.0.0-rc7",
|
||||||
"json-schema-to-ts": "^3.1.1",
|
"json-schema-to-ts": "^3.1.1",
|
||||||
"jsonv-ts": "0.9.1",
|
"jsonv-ts": "0.9.3",
|
||||||
"kysely": "0.27.6",
|
"kysely": "0.28.8",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"oauth4webapi": "^2.11.1",
|
"oauth4webapi": "^2.11.1",
|
||||||
"object-path-immutable": "^4.1.2",
|
"object-path-immutable": "^4.1.2",
|
||||||
"radix-ui": "^1.1.3",
|
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
"swr": "^2.3.3"
|
"radix-ui": "^1.1.3",
|
||||||
|
"swr": "^2.3.6",
|
||||||
|
"use-sync-external-store": "^1.6.0",
|
||||||
|
"zustand": "^4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@aws-sdk/client-s3": "^3.758.0",
|
"@aws-sdk/client-s3": "^3.922.0",
|
||||||
"@bluwy/giget-core": "^0.1.2",
|
"@bluwy/giget-core": "^0.1.6",
|
||||||
"@clack/prompts": "^0.11.0",
|
"@clack/prompts": "^0.11.0",
|
||||||
"@cloudflare/vitest-pool-workers": "^0.9.3",
|
"@cloudflare/vitest-pool-workers": "^0.10.4",
|
||||||
"@cloudflare/workers-types": "^4.20250606.0",
|
"@cloudflare/workers-types": "^4.20251014.0",
|
||||||
"@dagrejs/dagre": "^1.1.4",
|
"@dagrejs/dagre": "^1.1.4",
|
||||||
"@hono/vite-dev-server": "^0.21.0",
|
"@hono/vite-dev-server": "^0.23.0",
|
||||||
"@hookform/resolvers": "^4.1.3",
|
"@hookform/resolvers": "^5.2.2",
|
||||||
"@libsql/client": "^0.15.9",
|
"@libsql/client": "^0.15.15",
|
||||||
"@mantine/modals": "^7.17.1",
|
"@mantine/modals": "^7.17.1",
|
||||||
"@mantine/notifications": "^7.17.1",
|
"@mantine/notifications": "^7.17.1",
|
||||||
"@playwright/test": "^1.51.1",
|
"@playwright/test": "^1.56.1",
|
||||||
"@rjsf/core": "5.22.2",
|
"@rjsf/core": "5.22.2",
|
||||||
|
"@rjsf/utils": "5.22.0",
|
||||||
"@standard-schema/spec": "^1.0.0",
|
"@standard-schema/spec": "^1.0.0",
|
||||||
"@tabler/icons-react": "3.18.0",
|
"@tabler/icons-react": "3.35.0",
|
||||||
"@tailwindcss/postcss": "^4.0.12",
|
"@tailwindcss/postcss": "^4.1.16",
|
||||||
"@tailwindcss/vite": "^4.0.12",
|
"@tailwindcss/vite": "^4.1.16",
|
||||||
|
"@tanstack/react-store": "^0.8.0",
|
||||||
"@testing-library/jest-dom": "^6.6.3",
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
"@testing-library/react": "^16.2.0",
|
"@testing-library/react": "^16.2.0",
|
||||||
"@types/node": "^22.13.10",
|
"@types/node": "^24.10.0",
|
||||||
"@types/react": "^19.0.10",
|
"@types/react": "^19.0.10",
|
||||||
"@types/react-dom": "^19.0.4",
|
"@types/react-dom": "^19.0.4",
|
||||||
"@vitejs/plugin-react": "^4.3.4",
|
"@vitejs/plugin-react": "^5.1.0",
|
||||||
"@vitest/coverage-v8": "^3.0.9",
|
"@vitest/coverage-v8": "3.0.9",
|
||||||
"autoprefixer": "^10.4.21",
|
"autoprefixer": "^10.4.21",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"dotenv": "^16.4.7",
|
"commander": "^14.0.2",
|
||||||
|
"dotenv": "^17.2.3",
|
||||||
"jotai": "^2.12.2",
|
"jotai": "^2.12.2",
|
||||||
"jsdom": "^26.0.0",
|
"jsdom": "^26.1.0",
|
||||||
"kysely-d1": "^0.3.0",
|
|
||||||
"kysely-generic-sqlite": "^1.2.1",
|
"kysely-generic-sqlite": "^1.2.1",
|
||||||
|
"libsql": "^0.5.22",
|
||||||
"libsql-stateless-easy": "^1.8.0",
|
"libsql-stateless-easy": "^1.8.0",
|
||||||
"open": "^10.1.0",
|
"miniflare": "^4.20251011.2",
|
||||||
|
"open": "^10.2.0",
|
||||||
"openapi-types": "^12.1.3",
|
"openapi-types": "^12.1.3",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
"postcss-preset-mantine": "^1.17.0",
|
"postcss-preset-mantine": "^1.18.0",
|
||||||
"postcss-simple-vars": "^7.0.1",
|
"postcss-simple-vars": "^7.0.1",
|
||||||
"posthog-js-lite": "^3.4.2",
|
"posthog-js-lite": "^3.6.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-hook-form": "^7.54.2",
|
"react-hook-form": "^7.66.0",
|
||||||
"react-icons": "5.2.1",
|
"react-icons": "5.5.0",
|
||||||
"react-json-view-lite": "^2.4.1",
|
"react-json-view-lite": "^2.5.0",
|
||||||
"sql-formatter": "^15.4.11",
|
"sql-formatter": "^15.6.10",
|
||||||
"tailwind-merge": "^3.0.2",
|
"tailwind-merge": "^3.0.2",
|
||||||
"tailwindcss": "^4.0.12",
|
"tailwindcss": "^4.1.16",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"tsc-alias": "^1.8.11",
|
"tsc-alias": "^1.8.16",
|
||||||
"tsup": "^8.4.0",
|
"tsup": "^8.5.0",
|
||||||
"tsx": "^4.19.3",
|
"tsx": "^4.20.6",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^13.0.0",
|
||||||
"vite": "^6.3.5",
|
"vite": "^7.1.12",
|
||||||
"vite-plugin-circular-dependency": "^0.5.0",
|
"vite-plugin-circular-dependency": "^0.5.0",
|
||||||
"vite-tsconfig-paths": "^5.1.4",
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
"vitest": "^3.0.9",
|
"vitest": "3.0.9",
|
||||||
"wouter": "^3.6.0",
|
"wouter": "^3.7.1",
|
||||||
"wrangler": "^4.37.1",
|
"wrangler": "^4.45.4"
|
||||||
"miniflare": "^4.20250913.0"
|
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@hono/node-server": "^1.14.3"
|
"@hono/node-server": "^1.19.6"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": ">=19",
|
"react": ">=19",
|
||||||
@@ -209,6 +214,11 @@
|
|||||||
"import": "./dist/adapter/cloudflare/proxy.js",
|
"import": "./dist/adapter/cloudflare/proxy.js",
|
||||||
"require": "./dist/adapter/cloudflare/proxy.js"
|
"require": "./dist/adapter/cloudflare/proxy.js"
|
||||||
},
|
},
|
||||||
|
"./adapter/cloudflare/vite": {
|
||||||
|
"types": "./dist/types/adapter/cloudflare/vite.d.ts",
|
||||||
|
"import": "./dist/adapter/cloudflare/vite.js",
|
||||||
|
"require": "./dist/adapter/cloudflare/vite.js"
|
||||||
|
},
|
||||||
"./adapter": {
|
"./adapter": {
|
||||||
"types": "./dist/types/adapter/index.d.ts",
|
"types": "./dist/types/adapter/index.d.ts",
|
||||||
"import": "./dist/adapter/index.js"
|
"import": "./dist/adapter/index.js"
|
||||||
|
|||||||
+3
-2
@@ -5,7 +5,6 @@ import type { em as prototypeEm } from "data/prototype";
|
|||||||
import { Connection } from "data/connection/Connection";
|
import { Connection } from "data/connection/Connection";
|
||||||
import type { Hono } from "hono";
|
import type { Hono } from "hono";
|
||||||
import {
|
import {
|
||||||
type InitialModuleConfigs,
|
|
||||||
type ModuleConfigs,
|
type ModuleConfigs,
|
||||||
type Modules,
|
type Modules,
|
||||||
ModuleManager,
|
ModuleManager,
|
||||||
@@ -381,8 +380,10 @@ export class App<
|
|||||||
if (results.length > 0) {
|
if (results.length > 0) {
|
||||||
for (const { name, result } of results) {
|
for (const { name, result } of results) {
|
||||||
if (result) {
|
if (result) {
|
||||||
$console.log(`[Plugin:${name}] schema`);
|
|
||||||
ctx.helper.ensureSchema(result);
|
ctx.helper.ensureSchema(result);
|
||||||
|
if (ctx.flags.sync_required) {
|
||||||
|
$console.log(`[Plugin:${name}] schema, sync required`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
/// <reference types="bun-types" />
|
|
||||||
|
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { type RuntimeBkndConfig, createRuntimeApp } from "bknd/adapter";
|
import { type RuntimeBkndConfig, createRuntimeApp } from "bknd/adapter";
|
||||||
import { registerLocalMediaAdapter } from ".";
|
import { registerLocalMediaAdapter } from ".";
|
||||||
import { config, type App } from "bknd";
|
import { config, type App } from "bknd";
|
||||||
import type { ServeOptions } from "bun";
|
|
||||||
import { serveStatic } from "hono/bun";
|
import { serveStatic } from "hono/bun";
|
||||||
|
|
||||||
type BunEnv = Bun.Env;
|
type BunEnv = Bun.Env;
|
||||||
export type BunBkndConfig<Env = BunEnv> = RuntimeBkndConfig<Env> & Omit<ServeOptions, "fetch">;
|
export type BunBkndConfig<Env = BunEnv> = RuntimeBkndConfig<Env> &
|
||||||
|
Omit<Bun.Serve.Options<undefined, string>, "fetch">;
|
||||||
|
|
||||||
export async function createApp<Env = BunEnv>(
|
export async function createApp<Env = BunEnv>(
|
||||||
{ distPath, serveStatic: _serveStatic, ...config }: BunBkndConfig<Env> = {},
|
{ distPath, serveStatic: _serveStatic, ...config }: BunBkndConfig<Env> = {},
|
||||||
@@ -60,7 +58,7 @@ export function serve<Env = BunEnv>(
|
|||||||
args: Env = Bun.env as Env,
|
args: Env = Bun.env as Env,
|
||||||
) {
|
) {
|
||||||
Bun.serve({
|
Bun.serve({
|
||||||
...serveOptions,
|
...(serveOptions as any),
|
||||||
port,
|
port,
|
||||||
fetch: createHandler(
|
fetch: createHandler(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { inspect } from "node:util";
|
|
||||||
|
|
||||||
export type BindingTypeMap = {
|
export type BindingTypeMap = {
|
||||||
D1Database: D1Database;
|
D1Database: D1Database;
|
||||||
KVNamespace: KVNamespace;
|
KVNamespace: KVNamespace;
|
||||||
@@ -10,21 +8,40 @@ export type BindingTypeMap = {
|
|||||||
export type GetBindingType = keyof BindingTypeMap;
|
export type GetBindingType = keyof BindingTypeMap;
|
||||||
export type BindingMap<T extends GetBindingType> = { key: string; value: BindingTypeMap[T] };
|
export type BindingMap<T extends GetBindingType> = { key: string; value: BindingTypeMap[T] };
|
||||||
|
|
||||||
|
export const bindingMatchers = {
|
||||||
|
// D1Database instance doesn't stringify to [object D1Database] (yet)
|
||||||
|
D1Database: (value: object): value is D1Database => {
|
||||||
|
if (typeof value !== "object" || value === null) return false;
|
||||||
|
if (String(value) === "[object D1Database]") return true;
|
||||||
|
if (Object.keys(value).length !== 2) return false;
|
||||||
|
return ["alwaysPrimarySession", "fetcher"].every((key) => key in value);
|
||||||
|
},
|
||||||
|
KVNamespace: (value: object): value is KVNamespace =>
|
||||||
|
String(value) === "[object KvNamespace]" && Object.keys(value).length === 0,
|
||||||
|
DurableObjectNamespace: (value: object): value is DurableObjectNamespace =>
|
||||||
|
String(value) === "[object DurableObjectNamespace]" && Object.keys(value).length === 0,
|
||||||
|
R2Bucket: (value: object): value is R2Bucket =>
|
||||||
|
String(value) === "[object R2Bucket]" && Object.keys(value).length === 0,
|
||||||
|
};
|
||||||
|
|
||||||
export function getBindings<T extends GetBindingType>(env: any, type: T): BindingMap<T>[] {
|
export function getBindings<T extends GetBindingType>(env: any, type: T): BindingMap<T>[] {
|
||||||
const bindings: BindingMap<T>[] = [];
|
const bindings: BindingMap<T>[] = [];
|
||||||
|
if (!(type in bindingMatchers)) {
|
||||||
|
console.error(`No binding matcher for type ${type}`);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const matcher = bindingMatchers[type];
|
||||||
|
|
||||||
for (const key in env) {
|
for (const key in env) {
|
||||||
try {
|
const value = env[key];
|
||||||
if (
|
if (typeof value !== "object" || value === null) continue;
|
||||||
(env[key] as any).constructor.name === type ||
|
if (!matcher(value)) continue;
|
||||||
String(env[key]) === `[object ${type}]` ||
|
|
||||||
inspect(env[key]).includes(type)
|
bindings.push({
|
||||||
) {
|
key,
|
||||||
bindings.push({
|
value,
|
||||||
key,
|
} as any);
|
||||||
value: env[key] as BindingTypeMap[T],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
}
|
||||||
return bindings;
|
return bindings;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { describe, afterAll, test, expect, beforeAll } from "vitest";
|
||||||
|
import { Miniflare } from "miniflare";
|
||||||
|
import { getBindings, type GetBindingType } from "./bindings";
|
||||||
|
|
||||||
|
let mf: Miniflare | undefined;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
mf = new Miniflare({
|
||||||
|
modules: true,
|
||||||
|
script: `import { DurableObject } from "cloudflare:workers";
|
||||||
|
export default { async fetch() { return new Response(null); } }
|
||||||
|
export class TestObject extends DurableObject {}
|
||||||
|
export class TestObject2 extends DurableObject {}`,
|
||||||
|
r2Buckets: ["BUCKET"],
|
||||||
|
d1Databases: ["DB"],
|
||||||
|
kvNamespaces: ["KV"],
|
||||||
|
durableObjects: {
|
||||||
|
DO_SQLITE: { className: "TestObject", useSQLite: true },
|
||||||
|
DO_KV: { className: "TestObject2" },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
afterAll(() => {
|
||||||
|
mf?.dispose();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("bindings", () => {
|
||||||
|
test("extracts", async () => {
|
||||||
|
const env = {
|
||||||
|
...(await mf!.getBindings()),
|
||||||
|
some: "string",
|
||||||
|
another: 123,
|
||||||
|
array: [1, 2, 3],
|
||||||
|
};
|
||||||
|
|
||||||
|
const $getBindingKeys = (type: GetBindingType) => {
|
||||||
|
const bindings = getBindings(env, type);
|
||||||
|
const keys = bindings?.map((b) => b.key);
|
||||||
|
if (!keys || keys.length === 0) {
|
||||||
|
console.error(`No ${type} binding found`, { bindings });
|
||||||
|
throw new Error(`No ${type} binding found`);
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
expect($getBindingKeys("D1Database")).toEqual(["DB"]);
|
||||||
|
expect($getBindingKeys("KVNamespace")).toEqual(["KV"]);
|
||||||
|
expect($getBindingKeys("DurableObjectNamespace")).toEqual(["DO_SQLITE", "DO_KV"]);
|
||||||
|
expect($getBindingKeys("R2Bucket")).toEqual(["BUCKET"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -16,10 +16,14 @@ export {
|
|||||||
type GetBindingType,
|
type GetBindingType,
|
||||||
type BindingMap,
|
type BindingMap,
|
||||||
} from "./bindings";
|
} from "./bindings";
|
||||||
export { constants, makeConfig, type CloudflareContext } from "./config";
|
export {
|
||||||
|
constants,
|
||||||
|
makeConfig,
|
||||||
|
type CloudflareContext,
|
||||||
|
registerAsyncsExecutionContext,
|
||||||
|
} from "./config";
|
||||||
export { StorageR2Adapter, registerMedia } from "./storage/StorageR2Adapter";
|
export { StorageR2Adapter, registerMedia } from "./storage/StorageR2Adapter";
|
||||||
export { registries } from "bknd";
|
export { registries } from "bknd";
|
||||||
export { devFsVitePlugin, devFsWrite } from "./vite";
|
|
||||||
|
|
||||||
// for compatibility with old code
|
// for compatibility with old code
|
||||||
export function d1<DB extends D1Database | D1DatabaseSession = D1Database>(
|
export function d1<DB extends D1Database | D1DatabaseSession = D1Database>(
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export function registerMedia(
|
|||||||
env: Record<string, any>,
|
env: Record<string, any>,
|
||||||
registries: typeof $registries = $registries,
|
registries: typeof $registries = $registries,
|
||||||
) {
|
) {
|
||||||
|
if (registries.media.has("r2")) return;
|
||||||
const r2_bindings = getBindings(env, "R2Bucket");
|
const r2_bindings = getBindings(env, "R2Bucket");
|
||||||
|
|
||||||
registries.media.register(
|
registries.media.register(
|
||||||
@@ -172,7 +173,7 @@ export class StorageR2Adapter extends StorageAdapter {
|
|||||||
await this.bucket.delete(this.getKey(key));
|
await this.bucket.delete(this.getKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
getObjectUrl(key: string): string {
|
getObjectUrl(): string {
|
||||||
throw new Error("Method getObjectUrl not implemented.");
|
throw new Error("Method getObjectUrl not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +184,7 @@ export class StorageR2Adapter extends StorageAdapter {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON(secrets?: boolean) {
|
toJSON() {
|
||||||
return {
|
return {
|
||||||
type: this.getName(),
|
type: this.getName(),
|
||||||
config: {},
|
config: {},
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// biome-ignore-all lint: .
|
||||||
import type { Plugin } from "vite";
|
import type { Plugin } from "vite";
|
||||||
import { writeFile as nodeWriteFile } from "node:fs/promises";
|
import { writeFile as nodeWriteFile } from "node:fs/promises";
|
||||||
import { resolve } from "node:path";
|
import { resolve } from "node:path";
|
||||||
@@ -48,7 +49,6 @@ export function devFsVitePlugin({
|
|||||||
// Skip our own debug output
|
// Skip our own debug output
|
||||||
if (output.includes("[dev-fs-plugin]") || output.includes("[dev-fs-polyfill]")) {
|
if (output.includes("[dev-fs-plugin]") || output.includes("[dev-fs-polyfill]")) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
// biome-ignore lint/style/noArguments: <explanation>
|
|
||||||
return originalStdoutWrite.apply(process.stdout, arguments);
|
return originalStdoutWrite.apply(process.stdout, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +178,6 @@ export function devFsVitePlugin({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
// biome-ignore lint:
|
|
||||||
return originalStdoutWrite.apply(process.stdout, arguments);
|
return originalStdoutWrite.apply(process.stdout, arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { createFrameworkApp, type FrameworkBkndConfig } from "bknd/adapter";
|
import { createFrameworkApp, type FrameworkBkndConfig } from "bknd/adapter";
|
||||||
import { isNode } from "bknd/utils";
|
import { isNode } from "bknd/utils";
|
||||||
|
// @ts-expect-error next is not installed
|
||||||
import type { NextApiRequest } from "next";
|
import type { NextApiRequest } from "next";
|
||||||
|
|
||||||
type NextjsEnv = NextApiRequest["env"];
|
type NextjsEnv = NextApiRequest["env"];
|
||||||
@@ -18,7 +19,9 @@ function getCleanRequest(req: Request, cleanRequest: NextjsBkndConfig["cleanRequ
|
|||||||
if (!cleanRequest) return req;
|
if (!cleanRequest) return req;
|
||||||
|
|
||||||
const url = new URL(req.url);
|
const url = new URL(req.url);
|
||||||
cleanRequest?.searchParams?.forEach((k) => url.searchParams.delete(k));
|
cleanRequest?.searchParams?.forEach((k) => {
|
||||||
|
url.searchParams.delete(k);
|
||||||
|
});
|
||||||
|
|
||||||
if (isNode()) {
|
if (isNode()) {
|
||||||
return new Request(url.toString(), {
|
return new Request(url.toString(), {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { resendEmail } from "./resend";
|
|||||||
const ALL_TESTS = !!process.env.ALL_TESTS;
|
const ALL_TESTS = !!process.env.ALL_TESTS;
|
||||||
|
|
||||||
describe.skipIf(ALL_TESTS)("resend", () => {
|
describe.skipIf(ALL_TESTS)("resend", () => {
|
||||||
it.only("should throw on failed", async () => {
|
it("should throw on failed", async () => {
|
||||||
const driver = resendEmail({ apiKey: "invalid" } as any);
|
const driver = resendEmail({ apiKey: "invalid" } as any);
|
||||||
expect(driver.send("foo@bar.com", "Test", "Test")).rejects.toThrow();
|
expect(driver.send("foo@bar.com", "Test", "Test")).rejects.toThrow();
|
||||||
});
|
});
|
||||||
|
|||||||
+2
-1
@@ -73,8 +73,9 @@ export const env = <
|
|||||||
onValid?: (valid: R) => void;
|
onValid?: (valid: R) => void;
|
||||||
},
|
},
|
||||||
): R extends undefined ? Fallback : R => {
|
): R extends undefined ? Fallback : R => {
|
||||||
|
const source = opts?.source ?? (typeof process !== "undefined" ? process?.env : {});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const source = opts?.source ?? process.env;
|
|
||||||
const c = envs[key];
|
const c = envs[key];
|
||||||
const g = source[c.key];
|
const g = source[c.key];
|
||||||
const v = c.validate(g) as any;
|
const v = c.validate(g) as any;
|
||||||
|
|||||||
@@ -120,17 +120,14 @@ export function patternMatch(target: string, pattern: RegExp | string): boolean
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function slugify(str: string): string {
|
export function slugify(str: string): string {
|
||||||
return (
|
return String(str)
|
||||||
String(str)
|
.normalize("NFKD") // split accented characters into their base characters and diacritical marks
|
||||||
.normalize("NFKD") // split accented characters into their base characters and diacritical marks
|
.replace(/[\u0300-\u036f]/g, "") // remove all the accents, which happen to be all in the \u03xx UNICODE block.
|
||||||
// biome-ignore lint/suspicious/noMisleadingCharacterClass: <explanation>
|
.trim() // trim leading or trailing whitespace
|
||||||
.replace(/[\u0300-\u036f]/g, "") // remove all the accents, which happen to be all in the \u03xx UNICODE block.
|
.toLowerCase() // convert to lowercase
|
||||||
.trim() // trim leading or trailing whitespace
|
.replace(/[^a-z0-9 -]/g, "") // remove non-alphanumeric characters
|
||||||
.toLowerCase() // convert to lowercase
|
.replace(/\s+/g, "-") // replace spaces with hyphens
|
||||||
.replace(/[^a-z0-9 -]/g, "") // remove non-alphanumeric characters
|
.replace(/-+/g, "-"); // remove consecutive hyphens
|
||||||
.replace(/\s+/g, "-") // replace spaces with hyphens
|
|
||||||
.replace(/-+/g, "-") // remove consecutive hyphens
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function truncate(str: string, length = 50, end = "..."): string {
|
export function truncate(str: string, length = 50, end = "..."): string {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
type Simplify,
|
type Simplify,
|
||||||
sql,
|
sql,
|
||||||
} from "kysely";
|
} from "kysely";
|
||||||
|
import type { jsonArrayFrom, jsonBuildObject, jsonObjectFrom } from "kysely/helpers/sqlite";
|
||||||
import type { BaseIntrospector, BaseIntrospectorConfig } from "./BaseIntrospector";
|
import type { BaseIntrospector, BaseIntrospectorConfig } from "./BaseIntrospector";
|
||||||
import type { DB } from "bknd";
|
import type { DB } from "bknd";
|
||||||
import type { Constructor } from "core/registry/Registry";
|
import type { Constructor } from "core/registry/Registry";
|
||||||
@@ -70,15 +71,9 @@ export type IndexSpec = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type DbFunctions = {
|
export type DbFunctions = {
|
||||||
jsonObjectFrom<O>(expr: SelectQueryBuilderExpression<O>): RawBuilder<Simplify<O> | null>;
|
jsonObjectFrom: typeof jsonObjectFrom;
|
||||||
jsonArrayFrom<O>(expr: SelectQueryBuilderExpression<O>): RawBuilder<Simplify<O>[]>;
|
jsonArrayFrom: typeof jsonArrayFrom;
|
||||||
jsonBuildObject<O extends Record<string, Expression<unknown>>>(
|
jsonBuildObject: typeof jsonBuildObject;
|
||||||
obj: O,
|
|
||||||
): RawBuilder<
|
|
||||||
Simplify<{
|
|
||||||
[K in keyof O]: O[K] extends Expression<infer V> ? V : never;
|
|
||||||
}>
|
|
||||||
>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ConnQuery = CompiledQuery | Compilable;
|
export type ConnQuery = CompiledQuery | Compilable;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export type LibsqlClientFns = {
|
|||||||
function getClient(clientOrCredentials: Client | LibSqlCredentials | LibsqlClientFns): Client {
|
function getClient(clientOrCredentials: Client | LibSqlCredentials | LibsqlClientFns): Client {
|
||||||
if (clientOrCredentials && "url" in clientOrCredentials) {
|
if (clientOrCredentials && "url" in clientOrCredentials) {
|
||||||
const { url, authToken } = clientOrCredentials;
|
const { url, authToken } = clientOrCredentials;
|
||||||
return createClient({ url, authToken });
|
return createClient({ url, authToken }) as unknown as Client;
|
||||||
}
|
}
|
||||||
|
|
||||||
return clientOrCredentials as Client;
|
return clientOrCredentials as Client;
|
||||||
|
|||||||
+11
-13
@@ -23,26 +23,17 @@ export type HybridMode<AdapterConfig extends BkndConfig> = AdapterConfig extends
|
|||||||
? BkndModeConfig<Args, Merge<BkndHybridModeOptions & AdapterConfig>>
|
? BkndModeConfig<Args, Merge<BkndHybridModeOptions & AdapterConfig>>
|
||||||
: never;
|
: never;
|
||||||
|
|
||||||
export function hybrid<Args>({
|
export function hybrid<Args>(hybridConfig: HybridBkndConfig<Args>): BkndConfig<Args> {
|
||||||
configFilePath = "bknd-config.json",
|
|
||||||
...rest
|
|
||||||
}: HybridBkndConfig<Args>): BkndConfig<Args> {
|
|
||||||
return {
|
return {
|
||||||
...rest,
|
|
||||||
config: undefined,
|
|
||||||
app: async (args) => {
|
app: async (args) => {
|
||||||
const {
|
const {
|
||||||
config: appConfig,
|
config: appConfig,
|
||||||
isProd,
|
isProd,
|
||||||
plugins,
|
plugins,
|
||||||
syncSchemaOptions,
|
syncSchemaOptions,
|
||||||
} = await makeModeConfig(
|
} = await makeModeConfig(hybridConfig, args);
|
||||||
{
|
|
||||||
...rest,
|
const configFilePath = appConfig.configFilePath ?? "bknd-config.json";
|
||||||
configFilePath,
|
|
||||||
},
|
|
||||||
args,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (appConfig?.options?.mode && appConfig?.options?.mode !== "db") {
|
if (appConfig?.options?.mode && appConfig?.options?.mode !== "db") {
|
||||||
$console.warn("You should not set a different mode than `db` when using hybrid mode");
|
$console.warn("You should not set a different mode than `db` when using hybrid mode");
|
||||||
@@ -80,6 +71,13 @@ export function hybrid<Args>({
|
|||||||
skipValidation: isProd,
|
skipValidation: isProd,
|
||||||
// secrets are required for hybrid mode
|
// secrets are required for hybrid mode
|
||||||
secrets: appConfig.secrets,
|
secrets: appConfig.secrets,
|
||||||
|
onModulesBuilt: async (ctx) => {
|
||||||
|
if (ctx.flags.sync_required && !isProd && syncSchemaOptions.force) {
|
||||||
|
$console.log("[hybrid] syncing schema");
|
||||||
|
await ctx.em.schema().sync(syncSchemaOptions);
|
||||||
|
}
|
||||||
|
await appConfig?.options?.manager?.onModulesBuilt?.(ctx);
|
||||||
|
},
|
||||||
...appConfig?.options?.manager,
|
...appConfig?.options?.manager,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { mark, stripMark, $console, s, SecretSchema, setPath } from "bknd/utils";
|
import { mark, stripMark, $console, s, setPath } from "bknd/utils";
|
||||||
import { BkndError } from "core/errors";
|
import { BkndError } from "core/errors";
|
||||||
import * as $diff from "core/object/diff";
|
import * as $diff from "core/object/diff";
|
||||||
import type { Connection } from "data/connection";
|
import type { Connection } from "data/connection";
|
||||||
|
|||||||
@@ -19,9 +19,10 @@ import type { RelationField } from "data/relations";
|
|||||||
import { useEntityAdminOptions } from "ui/options";
|
import { useEntityAdminOptions } from "ui/options";
|
||||||
|
|
||||||
// simplify react form types 🤦
|
// simplify react form types 🤦
|
||||||
export type FormApi = ReactFormExtendedApi<any, any, any, any, any, any, any, any, any, any>;
|
|
||||||
// biome-ignore format: ...
|
// biome-ignore format: ...
|
||||||
export type TFieldApi = FieldApi<any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any>;
|
export type FormApi = ReactFormExtendedApi<any, any, any, any, any, any, any, any, any, any, any, any>;
|
||||||
|
// biome-ignore format: ...
|
||||||
|
export type TFieldApi = FieldApi<any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any, any>;
|
||||||
|
|
||||||
type EntityFormProps = {
|
type EntityFormProps = {
|
||||||
entity: Entity;
|
entity: Entity;
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ function DataEntityUpdateImpl({ params }) {
|
|||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
fieldsDisabled={fieldsDisabled}
|
fieldsDisabled={fieldsDisabled}
|
||||||
data={data ?? undefined}
|
data={data ?? undefined}
|
||||||
Form={Form}
|
Form={Form as any}
|
||||||
action="update"
|
action="update"
|
||||||
className="flex flex-grow flex-col gap-3 p-3"
|
className="flex flex-grow flex-col gap-3 p-3"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ export function DataEntityCreate({ params }) {
|
|||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
fieldsDisabled={fieldsDisabled}
|
fieldsDisabled={fieldsDisabled}
|
||||||
data={search.value}
|
data={search.value}
|
||||||
Form={Form}
|
Form={Form as any}
|
||||||
action="create"
|
action="create"
|
||||||
className="flex flex-grow flex-col gap-3 p-3"
|
className="flex flex-grow flex-col gap-3 p-3"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { JSONSchema7 } from "json-schema";
|
import type { JSONSchema } from "json-schema-to-ts";
|
||||||
import { omitKeys, type s } from "bknd/utils";
|
import { omitKeys, type s } from "bknd/utils";
|
||||||
|
|
||||||
export function extractSchema<
|
export function extractSchema<
|
||||||
@@ -10,7 +10,7 @@ export function extractSchema<
|
|||||||
config: Config,
|
config: Config,
|
||||||
keys: Keys[],
|
keys: Keys[],
|
||||||
): [
|
): [
|
||||||
JSONSchema7,
|
Exclude<JSONSchema, boolean | null | undefined>,
|
||||||
Partial<Config>,
|
Partial<Config>,
|
||||||
{
|
{
|
||||||
[K in Keys]: {
|
[K in Keys]: {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import path from "node:path";
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [tsconfigPaths()],
|
plugins: [tsconfigPaths()],
|
||||||
test: {
|
test: {
|
||||||
projects: ["**/*.vitest.config.ts"],
|
projects: ["**/*.vitest.config.ts", "**/*/vitest.config.ts"],
|
||||||
include: ["**/*.vi-test.ts", "**/*.vitest.ts"],
|
include: ["**/*.vi-test.ts", "**/*.vitest.ts"],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
+29
-22
@@ -1,14 +1,13 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
"$schema": "https://biomejs.dev/schemas/2.3.3/schema.json",
|
||||||
"organizeImports": {
|
"assist": { "actions": { "source": { "organizeImports": "off" } } },
|
||||||
"enabled": true
|
|
||||||
},
|
|
||||||
"vcs": {
|
"vcs": {
|
||||||
"defaultBranch": "main"
|
"defaultBranch": "main"
|
||||||
},
|
},
|
||||||
"formatter": {
|
"formatter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"indentStyle": "space"
|
"indentStyle": "space",
|
||||||
|
"formatWithErrors": true
|
||||||
},
|
},
|
||||||
"javascript": {
|
"javascript": {
|
||||||
"formatter": {
|
"formatter": {
|
||||||
@@ -30,32 +29,36 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"ignore": [
|
"includes": [
|
||||||
"**/node_modules/**",
|
"**",
|
||||||
"node_modules/**",
|
"!!**/node_modules",
|
||||||
"**/.cache/**",
|
"!!**/.cache",
|
||||||
"**/.wrangler/**",
|
"!!**/.wrangler",
|
||||||
"**/build/**",
|
"!!**/build",
|
||||||
"**/dist/**",
|
"!!**/dist",
|
||||||
"**/data.sqld/**",
|
"!!**/data.sqld",
|
||||||
"data.sqld/**",
|
"!!**/data.sqld",
|
||||||
"public/**",
|
"!!**/public",
|
||||||
".history/**"
|
"!!**/.history"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"linter": {
|
"linter": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"ignore": ["**/*.spec.ts"],
|
"includes": ["**"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"recommended": true,
|
"recommended": true,
|
||||||
"a11y": {
|
"a11y": {},
|
||||||
"all": false
|
|
||||||
},
|
|
||||||
"correctness": {
|
"correctness": {
|
||||||
"useExhaustiveDependencies": "off",
|
"useExhaustiveDependencies": "off",
|
||||||
"noUnreachable": "warn",
|
"noUnreachable": "warn",
|
||||||
"noChildrenProp": "off",
|
"noChildrenProp": "off",
|
||||||
"noSwitchDeclarations": "warn"
|
"noSwitchDeclarations": "warn",
|
||||||
|
"noUnusedVariables": {
|
||||||
|
"options": {
|
||||||
|
"ignoreRestSiblings": true
|
||||||
|
},
|
||||||
|
"level": "warn"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"complexity": {
|
"complexity": {
|
||||||
"noUselessFragments": "warn",
|
"noUselessFragments": "warn",
|
||||||
@@ -70,7 +73,11 @@
|
|||||||
"noArrayIndexKey": "off",
|
"noArrayIndexKey": "off",
|
||||||
"noImplicitAnyLet": "warn",
|
"noImplicitAnyLet": "warn",
|
||||||
"noConfusingVoidType": "off",
|
"noConfusingVoidType": "off",
|
||||||
"noConsoleLog": "warn"
|
"noConsole": {
|
||||||
|
"level": "warn",
|
||||||
|
"options": { "allow": ["error", "info"] }
|
||||||
|
},
|
||||||
|
"noTsIgnore": "off"
|
||||||
},
|
},
|
||||||
"security": {
|
"security": {
|
||||||
"noDangerouslySetInnerHtml": "off"
|
"noDangerouslySetInnerHtml": "off"
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[install]
|
||||||
|
#linker = "hoisted"
|
||||||
@@ -164,7 +164,7 @@ The [Cloudflare Vite Plugin](https://developers.cloudflare.com/workers/vite-plug
|
|||||||
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:
|
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
|
```ts
|
||||||
import { devFsVitePlugin } from "bknd/adapter/cloudflare";
|
import { devFsVitePlugin } from "bknd/adapter/cloudflare/vite";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [devFsVitePlugin()], // [!code highlight]
|
plugins: [devFsVitePlugin()], // [!code highlight]
|
||||||
@@ -174,7 +174,7 @@ export default defineConfig({
|
|||||||
Now to use this polyfill, you can use the `devFsWrite` function to write files to the filesystem.
|
Now to use this polyfill, you can use the `devFsWrite` function to write files to the filesystem.
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import { devFsWrite } from "bknd/adapter/cloudflare"; // [!code highlight]
|
import { devFsWrite } from "bknd/adapter/cloudflare/vite"; // [!code highlight]
|
||||||
import { syncTypes } from "bknd/plugins";
|
import { syncTypes } from "bknd/plugins";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -6,15 +6,15 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"deploy": "wrangler deploy",
|
"deploy": "wrangler deploy",
|
||||||
"dev": "wrangler dev",
|
"dev": "wrangler dev",
|
||||||
"bknd-typegen": "PROXY=1 npx bknd types",
|
"bknd-typegen": "PROXY=1 node_modules/.bin/bknd types",
|
||||||
"typegen": "wrangler types && npm run bknd-typegen",
|
"typegen": "wrangler types && npm run bknd-typegen",
|
||||||
"predev": "npm run typegen"
|
"postinstall": "npm run typegen"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bknd": "file:../../app"
|
"bknd": "file:../../app"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5.9.2",
|
"typescript": "^5.9.3",
|
||||||
"wrangler": "^4.34.0"
|
"wrangler": "^4.46.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
"$schema": "node_modules/wrangler/config-schema.json",
|
"$schema": "node_modules/wrangler/config-schema.json",
|
||||||
"name": "bknd-cf-worker-example",
|
"name": "bknd-cf-worker-example",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"compatibility_date": "2025-08-03",
|
"compatibility_date": "2025-11-05",
|
||||||
"compatibility_flags": ["nodejs_compat"],
|
|
||||||
"workers_dev": true,
|
"workers_dev": true,
|
||||||
"minify": true,
|
"minify": true,
|
||||||
"assets": {
|
"assets": {
|
||||||
|
|||||||
+6
-6
@@ -12,13 +12,13 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "1.9.4",
|
"@biomejs/biome": "2.3.3",
|
||||||
"@tsconfig/strictest": "^2.0.5",
|
"@tsconfig/strictest": "^2.0.7",
|
||||||
|
"@types/bun": "^1.3.1",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"bun-types": "^1.1.18",
|
"miniflare": "^3.20250718.2",
|
||||||
"miniflare": "^3.20240806.0",
|
"typescript": "^5.9.3",
|
||||||
"typescript": "^5.5.3",
|
"verdaccio": "^6.2.1"
|
||||||
"verdaccio": "^5.32.1"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
|
|||||||
Reference in New Issue
Block a user