felixmosh / bull-board

🎯 Queue background jobs inspector
MIT License
2.14k stars 342 forks source link

Support ElysiaJS #691

Closed cameronwiebe closed 1 month ago

cameronwiebe commented 4 months ago

ElysiaJS is a TypeScript framework with a great developer experience. I would love to see support for Elysia in bull-board so I wrote a simple adapter for my project which seems to be working okay. Hopefully this will be helpful for someone else, it would be great to see official support for Elysia in the future.

import {
    AppControllerRoute,
    AppViewRoute,
    BullBoardQueues,
    ControllerHandlerReturnType,
    HTTPMethod,
    IServerAdapter,
    UIConfig,
} from '@bull-board/api/dist/typings/app';
import ejs from 'ejs';
import Elysia from 'elysia';
import { staticPlugin } from '@elysiajs/static';
import { html } from '@elysiajs/html';

export class ElysiaAdapter implements IServerAdapter {
    protected app: Elysia;
    protected basePath = '';
    protected bullBoardQueues: BullBoardQueues | undefined;
    protected errorHandler:
        | ((error: Error) => ControllerHandlerReturnType)
        | undefined;
    protected uiConfig: UIConfig = {};
    protected viewPath: string = '';

    constructor(app: Elysia) {
        this.app = app;
    }

    public setBasePath(path: string): ElysiaAdapter {
        this.basePath = path;
        return this;
    }

    public setStaticPath(
        staticsRoute: string,
        staticsPath: string
    ): ElysiaAdapter {
        this.app.use(
            staticPlugin({
                assets: staticsPath,
                prefix: this.basePath + staticsRoute,
            })
        );
        this.app.use(html({ autoDoctype: 'full' }));
        return this;
    }

    public setViewsPath(viewPath: string): ElysiaAdapter {
        this.viewPath = viewPath;
        return this;
    }

    public setErrorHandler(
        handler: (error: Error) => ControllerHandlerReturnType
    ) {
        this.errorHandler = handler;
        return this;
    }

    public setApiRoutes(routes: AppControllerRoute[]): ElysiaAdapter {
        routes.forEach((route) =>
            (Array.isArray(route.method)
                ? route.method
                : [route.method]
            ).forEach((method: HTTPMethod) => {
                this.app[method](
                    Array.isArray(route.route)
                        ? this.basePath + route.route[0]
                        : this.basePath + route.route,
                    async (ctx) => {
                        const response = await route.handler({
                            queues: this.bullBoardQueues as BullBoardQueues,
                            query: ctx.query,
                            params: ctx.params,
                        });
                        ctx.set.status = response.status || 200;
                        return response.body;
                    }
                );
            })
        );
        return this;
    }

    public setEntryRoute(routeDef: AppViewRoute): ElysiaAdapter {
        const viewHandler = async ({ set }: { set: any }) => {
            const { name, params } = routeDef.handler({
                basePath: this.basePath,
                uiConfig: this.uiConfig,
            });

            const renderedHtml = await ejs.renderFile(
                this.viewPath + '/' + name,
                params,
                { async: true }
            );
            set.status = 200;
            return renderedHtml;
        };

        const routes = Array.isArray(routeDef.route)
            ? routeDef.route
            : [routeDef.route];

        routes.forEach((route) => {
            this.app[routeDef.method](this.basePath + route, viewHandler);
        });
        return this;
    }

    public setQueues(bullBoardQueues: BullBoardQueues): ElysiaAdapter {
        this.bullBoardQueues = bullBoardQueues;
        return this;
    }

    setUIConfig(config: UIConfig = {}): ElysiaAdapter {
        this.uiConfig = config;
        return this;
    }

    public getRouter(): any {
        return this.app;
    }
}

How to use:

const app = new Elysia();
const serverAdapter = new ElysiaAdapter(app);
serverAdapter.setBasePath('/ui');
createBullBoard({
    queues: [...],
    serverAdapter
});
felixmosh commented 4 months ago

Will be able to create a PR for it?

stale[bot] commented 1 month ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.