UNPKG

@trifrost/core

Version:

Blazingly fast, runtime-agnostic server framework for modern edge and node environments

94 lines (93 loc) 3.4 kB
/// <reference types="bun-types" /> import { isInt, isIntBetween } from '@valkyriestudios/utils/number'; import { ConsoleExporter } from '../../modules/Logger'; import { BunContext } from './Context'; import { determineHost, determinePort, determineTrustProxy, isDevMode } from '../../utils/Generic'; export class BunRuntime { /* Bun Http server instance */ #server = null; /* Global logger instance when runtime has started */ #logger = null; /* Incoming handler which is to be called by the runtime when an incoming request happens */ #onIncoming = null; /** * MARK: Runtime Implementation */ exports = null; get name() { return 'Bun'; } get version() { return Bun.version || null; } async boot(opts) { let serve; let file; try { ({ serve, file } = await import('bun')); } catch { throw new Error('BunRuntime@boot: Failed to load required modules'); } /* Reject if server is already set */ if (this.#server !== null) { throw new Error('BunRuntime@boot: Server already listening'); } /* Set onIncoming handler */ this.#onIncoming = opts.onIncoming; /* Set logger instance */ this.#logger = opts.logger; /* Specific APIs used by the context */ const apis = { file }; /** * Context config. * Take Note: Given that we don't know whether or not bun will run standalone or * behind a proxy we default trustProxy to false here. */ const cfg = { ...opts.cfg, env: { ...process.env, ...opts.cfg.env }, }; /* Determine trust proxy */ cfg.trustProxy = determineTrustProxy(cfg.env, false); /* Construct options for serve */ const serveOpts = { port: determinePort(cfg.env, cfg.port), hostname: determineHost(cfg.env), fetch: async (req) => { const ctx = new BunContext(cfg, opts.logger, apis, req); try { await this.#onIncoming(ctx); if (!ctx.response) throw new Error('BunContext@onIncoming: Handler did not respond'); return ctx.response; } catch (err) { opts.logger.error(err); return new Response('Internal Server Error', { status: 500 }); } }, }; /* Use timeout as idleTimeout if configured */ if (isInt(cfg.timeout)) { const timeout_s = cfg.timeout / 1000; /* Ensure timeout stays within 255 seconds as bun limitation */ serveOpts.idleTimeout = isIntBetween(timeout_s, 0, 255) ? timeout_s : 255; } /* Bun serve */ this.#server = serve(serveOpts); this.#logger.debug(`BunRuntime@boot: Listening on port ${opts.cfg.port}`); } defaultExporter(env) { return isDevMode(env) ? new ConsoleExporter() : new ConsoleExporter({ include: ['trace_id'] }); } async shutdown() { if (!this.#server) return; this.#logger.debug('BunRuntime@shutdown'); this.#server.stop(); this.#server = null; this.#onIncoming = null; this.#logger = null; } }