added a few initial plugins

This commit is contained in:
dswbx
2025-06-12 19:58:18 +02:00
parent fe5ccd4206
commit 8517c9b90b
12 changed files with 125 additions and 8 deletions

View File

@@ -51,6 +51,9 @@ describe("App tests", async () => {
},
);
},
onBoot: async () => {
called.push("onBoot");
},
beforeBuild: async () => {
called.push("beforeBuild");
},
@@ -90,6 +93,7 @@ describe("App tests", async () => {
},
]);
expect(called).toEqual([
"onBoot",
"onServerInit",
"beforeBuild",
"onServerInit",

View File

@@ -78,6 +78,7 @@ async function buildApi() {
"src/core/utils/index.ts",
"src/data/index.ts",
"src/media/index.ts",
"src/plugins/index.ts",
],
outDir: "dist",
external: [...external],

View File

@@ -183,6 +183,11 @@
"import": "./dist/media/index.js",
"require": "./dist/media/index.js"
},
"./plugins": {
"types": "./dist/types/plugins/index.d.ts",
"import": "./dist/plugins/index.js",
"require": "./dist/plugins/index.js"
},
"./adapter/cloudflare": {
"types": "./dist/types/adapter/cloudflare/index.d.ts",
"import": "./dist/adapter/cloudflare/index.js",
@@ -231,6 +236,23 @@
"./dist/styles.css": "./dist/ui/styles.css",
"./dist/manifest.json": "./dist/static/.vite/manifest.json"
},
"typesVersions": {
"*": {
"data": ["./dist/types/data/index.d.ts"],
"core": ["./dist/types/core/index.d.ts"],
"utils": ["./dist/types/core/utils/index.d.ts"],
"cli": ["./dist/types/cli/index.d.ts"],
"media": ["./dist/types/media/index.d.ts"],
"plugins": ["./dist/types/plugins/index.d.ts"],
"adapter": ["./dist/types/adapter/index.d.ts"],
"adapter/cloudflare": ["./dist/types/adapter/cloudflare/index.d.ts"],
"adapter/vite": ["./dist/types/adapter/vite/index.d.ts"],
"adapter/nextjs": ["./dist/types/adapter/nextjs/index.d.ts"],
"adapter/react-router": ["./dist/types/adapter/react-router/index.d.ts"],
"adapter/bun": ["./dist/types/adapter/bun/index.d.ts"],
"adapter/node": ["./dist/types/adapter/node/index.d.ts"]
}
},
"publishConfig": {
"access": "public"
},

View File

@@ -27,6 +27,7 @@ export type AppPluginConfig = {
onBuilt?: () => MaybePromise<void>;
onServerInit?: (server: Hono<ServerEnv>) => MaybePromise<void>;
onFirstBoot?: () => MaybePromise<void>;
onBoot?: () => MaybePromise<void>;
};
export type AppPlugin = (app: App) => AppPluginConfig;
@@ -93,6 +94,7 @@ export class App {
private options?: AppOptions,
) {
this.plugins = (options?.plugins ?? []).map((plugin) => plugin(this));
this.runPlugins("onBoot");
this.modules = new ModuleManager(connection, {
...(options?.manager ?? {}),
initial: _initialConfig,

View File

@@ -1,5 +1,4 @@
import { D1Connection, type D1ConnectionConfig } from "./connection/D1Connection";
import { ImageOptimizationPlugin } from "./plugins/image-optimization.plugin";
export * from "./cloudflare-workers.adapter";
export { makeApp, getFresh } from "./modes/fresh";
@@ -14,9 +13,6 @@ export {
type BindingMap,
} from "./bindings";
export { constants } from "./config";
export const plugins = {
imageOptimization: ImageOptimizationPlugin,
};
export function d1(config: D1ConnectionConfig) {
return new D1Connection(config);

View File

@@ -56,7 +56,7 @@ export class EntityTypescript {
return this.em.entities.map((e) => e.toTypes());
}
protected getTab(count = 1) {
getTab(count = 1) {
return this.options.indentChar.repeat(this.options.indentWidth).repeat(count);
}

View File

@@ -317,6 +317,7 @@ export class SystemController extends Controller {
local: datetimeStringLocal(),
utc: datetimeStringUTC(),
},
plugins: this.app.plugins.map((p) => p.name),
}),
);

View File

@@ -1,18 +1,18 @@
import type { App, AppPlugin } from "bknd";
export type ImageOptimizationPluginOptions = {
export type CloudflareImageOptimizationOptions = {
accessUrl?: string;
resolvePath?: string;
autoFormat?: boolean;
devBypass?: string;
};
export function ImageOptimizationPlugin({
export function cloudflareImageOptimization({
accessUrl = "/_plugin/image/optimize",
resolvePath = "/api/media/file",
autoFormat = true,
devBypass,
}: ImageOptimizationPluginOptions = {}): AppPlugin {
}: CloudflareImageOptimizationOptions = {}): AppPlugin {
const disallowedAccessUrls = ["/api", "/admin", "/_optimize"];
if (disallowedAccessUrls.includes(accessUrl) || accessUrl.length < 2) {
throw new Error(`Disallowed accessUrl: ${accessUrl}`);

View File

@@ -0,0 +1,18 @@
import type { App, AppPlugin } from "bknd";
import { showRoutes as showRoutesHono } from "hono/dev";
export type ShowRoutesOptions = {
once?: boolean;
};
export function showRoutes({ once = false }: ShowRoutesOptions = {}): AppPlugin {
let shown = false;
return (app: App) => ({
name: "bknd-show-routes",
onBuilt: () => {
if (once && shown) return;
shown = true;
showRoutesHono(app.server);
},
});
}

View File

@@ -0,0 +1,35 @@
import { App, type AppConfig, type AppPlugin } from "bknd";
export type SyncConfigOptions = {
enabled?: boolean;
includeSecrets?: boolean;
write: (config: AppConfig) => Promise<void>;
};
export function syncConfig({
enabled = true,
includeSecrets = false,
write,
}: SyncConfigOptions): AppPlugin {
let firstBoot = true;
return (app: App) => ({
name: "bknd-sync-config",
onBuilt: async () => {
if (!enabled) return;
app.emgr.onEvent(
App.Events.AppConfigUpdatedEvent,
async () => {
await write?.(app.toJSON(includeSecrets));
},
{
id: "sync-config",
},
);
if (firstBoot) {
firstBoot = false;
await write?.(app.toJSON(true));
}
},
});
}

View File

@@ -0,0 +1,31 @@
import { App, type AppPlugin } from "bknd";
import { EntityTypescript } from "data/entities/EntityTypescript";
export type SyncTypesOptions = {
enabled?: boolean;
write: (et: EntityTypescript) => Promise<void>;
};
export function syncTypes({ enabled = true, write }: SyncTypesOptions): AppPlugin {
let firstBoot = true;
return (app: App) => ({
name: "bknd-sync-types",
onBuilt: async () => {
if (!enabled) return;
app.emgr.onEvent(
App.Events.AppConfigUpdatedEvent,
async () => {
await write?.(new EntityTypescript(app.em));
},
{
id: "sync-types",
},
);
if (firstBoot) {
firstBoot = false;
await write?.(new EntityTypescript(app.em));
}
},
});
}

7
app/src/plugins/index.ts Normal file
View File

@@ -0,0 +1,7 @@
export {
cloudflareImageOptimization,
type CloudflareImageOptimizationOptions,
} from "./cloudflare/image-optimization.plugin";
export { showRoutes, type ShowRoutesOptions } from "./dev/show-routes.plugin";
export { syncConfig, type SyncConfigOptions } from "./dev/sync-config.plugin";
export { syncTypes, type SyncTypesOptions } from "./dev/sync-types.plugin";