;
+ // called right after modules are created, before build
+ onModulesCreated?: (modules: Modules, ctx: ModuleBuildContext) => void;
/** @deprecated */
verbosity?: Verbosity;
};
@@ -127,8 +129,16 @@ export class ModuleManagerConfigUpdateEvent<
}> {
static override slug = "mm-config-update";
}
+export class ModuleManagerModulesCreatedEvent extends ModuleManagerEvent<{
+ modules: Modules;
+ ctx: ModuleBuildContext;
+}> {
+ static override slug = "mm-modules-created";
+}
+
export const ModuleManagerEvents = {
ModuleManagerConfigUpdateEvent,
+ ModuleManagerModulesCreatedEvent,
};
// @todo: cleanup old diffs on upgrade
@@ -195,6 +205,11 @@ export class ModuleManager {
this.modules[key] = module;
}
+
+ if (this.options?.onModulesCreated) {
+ this.options.onModulesCreated(this.modules, context);
+ }
+
this.logger.log("modules created");
} catch (e) {
this.logger.log("failed to create modules", e);
diff --git a/app/src/ui/components/form/json-schema-form/Field.tsx b/app/src/ui/components/form/json-schema-form/Field.tsx
index e516b8f4..cb8bea48 100644
--- a/app/src/ui/components/form/json-schema-form/Field.tsx
+++ b/app/src/ui/components/form/json-schema-form/Field.tsx
@@ -64,12 +64,13 @@ const FieldImpl = ({
const id = `${name}-${useId()}`;
const required = typeof _required === "boolean" ? _required : ctx.required;
- if (!isTypeSchema(schema))
+ if (!schema) {
return (
[Field] {path} has no schema ({JSON.stringify(schema)})
);
+ }
if (isType(schema.type, "object")) {
return ;
diff --git a/app/tsconfig.json b/app/tsconfig.json
index a40d88a7..8b82a267 100644
--- a/app/tsconfig.json
+++ b/app/tsconfig.json
@@ -49,5 +49,5 @@
"__test__",
"e2e/**/*.ts"
],
- "exclude": ["node_modules", "dist", "dist/types", "**/*.d.ts"]
+ "exclude": ["node_modules", "dist", "dist/types", "**/*.d.ts", "**/dist/**"]
}
diff --git a/app/vite.dev.ts b/app/vite.dev.ts
index 1274d21f..bc4b9c50 100644
--- a/app/vite.dev.ts
+++ b/app/vite.dev.ts
@@ -1,8 +1,8 @@
import { readFile } from "node:fs/promises";
import { serveStatic } from "@hono/node-server/serve-static";
import { showRoutes } from "hono/dev";
-import { App, registries } from "./src";
-import { StorageLocalAdapter } from "./src/adapter/node";
+import { App } from "./src/App";
+import { StorageLocalAdapter } from "./src/adapter/node/storage/StorageLocalAdapter";
import type { Connection } from "./src/data/connection/Connection";
import { __bknd } from "modules/ModuleManager";
import { nodeSqlite } from "./src/adapter/node/connection/NodeSqliteConnection";
@@ -10,8 +10,6 @@ import { libsql } from "./src/data/connection/sqlite/libsql/LibsqlConnection";
import { $console } from "core/utils";
import { createClient } from "@libsql/client";
-registries.media.register("local", StorageLocalAdapter);
-
const example = import.meta.env.VITE_EXAMPLE;
let connection: Connection;
@@ -70,7 +68,7 @@ if (import.meta.env.VITE_DB_LIBSQL_URL) {
} */
let app: App;
-const recreate = import.meta.env.VITE_APP_FRESH === "1";
+const recreate = true; //import.meta.env.VITE_APP_FRESH === "1";
const debugRerenders = import.meta.env.VITE_DEBUG_RERENDERS === "1";
let firstStart = true;
export default {
@@ -78,6 +76,13 @@ export default {
if (!app || recreate) {
app = App.create({
connection,
+ options: {
+ manager: {
+ onModulesCreated: (modules, ctx) => {
+ modules.media.adapters.set("local", StorageLocalAdapter);
+ },
+ },
+ },
});
app.emgr.onEvent(
App.Events.AppBuiltEvent,
diff --git a/examples/astro/bknd.config.ts b/examples/astro/bknd.config.ts
index 8ddea7e8..fbd55b27 100644
--- a/examples/astro/bknd.config.ts
+++ b/examples/astro/bknd.config.ts
@@ -3,9 +3,6 @@ import { registerLocalMediaAdapter } from "bknd/adapter/node";
import { boolean, em, entity, text } from "bknd/data";
import { secureRandomString } from "bknd/utils";
-// since we're running in node, we can register the local media adapter
-const local = registerLocalMediaAdapter();
-
// the em() function makes it easy to create an initial schema
const schema = em({
todos: entity("todos", {
@@ -41,11 +38,17 @@ export default {
// ... and media
media: {
enabled: true,
- adapter: local({
- path: "./public/uploads",
- }),
+ adapter: {
+ type: "local",
+ config: {
+ path: "./public/uploads",
+ },
+ },
},
},
+ beforeBuild: (app) => {
+ registerLocalMediaAdapter(app);
+ },
options: {
// the seed option is only executed if the database was empty
seed: async (ctx) => {
diff --git a/examples/nextjs/bknd.config.ts b/examples/nextjs/bknd.config.ts
index 39a12a7f..e8c43825 100644
--- a/examples/nextjs/bknd.config.ts
+++ b/examples/nextjs/bknd.config.ts
@@ -3,16 +3,6 @@ import { boolean, em, entity, text } from "bknd/data";
import { registerLocalMediaAdapter } from "bknd/adapter/node";
import { secureRandomString } from "bknd/utils";
-// The local media adapter works well in development, and server based
-// deployments. However, on vercel or any other serverless deployments,
-// you shouldn't use a filesystem based media adapter.
-//
-// Additionally, if you run the bknd api on the "edge" runtime,
-// this would not work as well.
-//
-// For production, it is recommended to uncomment the line below.
-const local = registerLocalMediaAdapter();
-
const schema = em({
todos: entity("todos", {
title: text(),
@@ -50,11 +40,23 @@ export default {
// ... and media
media: {
enabled: true,
- adapter: local({
- path: "./public/uploads",
- }),
+ adapter: {
+ type: "local",
+ config: {
+ path: "./public/uploads",
+ },
+ },
},
},
+ beforeBuild: (app) => {
+ // The local media adapter works well in development, and server based
+ // deployments. However, on vercel or any other serverless deployments,
+ // you shouldn't use a filesystem based media adapter.
+ //
+ // Additionally, if you run the bknd api on the "edge" runtime,
+ // this would not work as well.
+ registerLocalMediaAdapter(app);
+ },
options: {
// the seed option is only executed if the database was empty
seed: async (ctx) => {
diff --git a/examples/react-router/bknd.config.ts b/examples/react-router/bknd.config.ts
index 06239b34..1850f447 100644
--- a/examples/react-router/bknd.config.ts
+++ b/examples/react-router/bknd.config.ts
@@ -3,9 +3,6 @@ import type { ReactRouterBkndConfig } from "bknd/adapter/react-router";
import { boolean, em, entity, text } from "bknd/data";
import { secureRandomString } from "bknd/utils";
-// since we're running in node, we can register the local media adapter
-const local = registerLocalMediaAdapter();
-
const schema = em({
todos: entity("todos", {
title: text(),
@@ -40,11 +37,18 @@ export default {
// ... and media
media: {
enabled: true,
- adapter: local({
- path: "./public/uploads",
- }),
+ adapter: {
+ type: "local",
+ config: {
+ path: "./public/uploads",
+ },
+ },
},
},
+ beforeBuild: (app) => {
+ // since we're running in node, we can register the local media adapter
+ registerLocalMediaAdapter(app);
+ },
options: {
// the seed option is only executed if the database was empty
seed: async (ctx) => {