mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-16 20:37:21 +00:00
added a few initial plugins
This commit is contained in:
86
app/src/plugins/cloudflare/image-optimization.plugin.ts
Normal file
86
app/src/plugins/cloudflare/image-optimization.plugin.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import type { App, AppPlugin } from "bknd";
|
||||
|
||||
export type CloudflareImageOptimizationOptions = {
|
||||
accessUrl?: string;
|
||||
resolvePath?: string;
|
||||
autoFormat?: boolean;
|
||||
devBypass?: string;
|
||||
};
|
||||
|
||||
export function cloudflareImageOptimization({
|
||||
accessUrl = "/_plugin/image/optimize",
|
||||
resolvePath = "/api/media/file",
|
||||
autoFormat = true,
|
||||
devBypass,
|
||||
}: CloudflareImageOptimizationOptions = {}): AppPlugin {
|
||||
const disallowedAccessUrls = ["/api", "/admin", "/_optimize"];
|
||||
if (disallowedAccessUrls.includes(accessUrl) || accessUrl.length < 2) {
|
||||
throw new Error(`Disallowed accessUrl: ${accessUrl}`);
|
||||
}
|
||||
|
||||
return (app: App) => ({
|
||||
name: "cf-image-optimization",
|
||||
onBuilt: () => {
|
||||
app.server.get(`${accessUrl}/:path{.+$}`, async (c) => {
|
||||
const request = c.req.raw;
|
||||
const url = new URL(request.url);
|
||||
|
||||
if (devBypass) {
|
||||
return c.redirect(devBypass + url.pathname + url.search, 302);
|
||||
}
|
||||
|
||||
const storage = app.module.media?.storage;
|
||||
if (!storage) {
|
||||
throw new Error("No media storage configured");
|
||||
}
|
||||
|
||||
const path = c.req.param("path");
|
||||
if (!path) {
|
||||
throw new Error("No url provided");
|
||||
}
|
||||
|
||||
const imageURL = `${url.origin}${resolvePath}/${path}`;
|
||||
const metadata = await storage.objectMetadata(path);
|
||||
|
||||
// Cloudflare-specific options are in the cf object.
|
||||
const params = Object.fromEntries(url.searchParams.entries());
|
||||
const options: RequestInitCfPropertiesImage = {};
|
||||
|
||||
// Copy parameters from query string to request options.
|
||||
// You can implement various different parameters here.
|
||||
if ("fit" in params) options.fit = params.fit as any;
|
||||
if ("width" in params) options.width = Number.parseInt(params.width);
|
||||
if ("height" in params) options.height = Number.parseInt(params.height);
|
||||
if ("quality" in params) options.quality = Number.parseInt(params.quality);
|
||||
|
||||
// Your Worker is responsible for automatic format negotiation. Check the Accept header.
|
||||
if (autoFormat) {
|
||||
const accept = request.headers.get("Accept")!;
|
||||
if (/image\/avif/.test(accept)) {
|
||||
options.format = "avif";
|
||||
} else if (/image\/webp/.test(accept)) {
|
||||
options.format = "webp";
|
||||
}
|
||||
}
|
||||
|
||||
// Build a request that passes through request headers
|
||||
const imageRequest = new Request(imageURL, {
|
||||
headers: request.headers,
|
||||
});
|
||||
|
||||
// Returning fetch() with resizing options will pass through response with the resized image.
|
||||
const res = await fetch(imageRequest, { cf: { image: options } });
|
||||
|
||||
return new Response(res.body, {
|
||||
status: res.status,
|
||||
statusText: res.statusText,
|
||||
headers: {
|
||||
"Cache-Control": "public, max-age=600",
|
||||
"Content-Type": metadata.type,
|
||||
"Content-Length": metadata.size.toString(),
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
18
app/src/plugins/dev/show-routes.plugin.ts
Normal file
18
app/src/plugins/dev/show-routes.plugin.ts
Normal 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);
|
||||
},
|
||||
});
|
||||
}
|
||||
35
app/src/plugins/dev/sync-config.plugin.ts
Normal file
35
app/src/plugins/dev/sync-config.plugin.ts
Normal 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));
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
31
app/src/plugins/dev/sync-types.plugin.ts
Normal file
31
app/src/plugins/dev/sync-types.plugin.ts
Normal 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
7
app/src/plugins/index.ts
Normal 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";
|
||||
Reference in New Issue
Block a user