UNPKG

@koex/bootstrap

Version:
264 lines (262 loc) 8.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.bootstrap = exports.Bootstrap = exports.getNetworkAddress = void 0; const core_1 = require("@koex/core"); const boxen = require("boxen"); const chalk = require("chalk"); const os = require("os"); const interfaces = os.networkInterfaces(); function defineReadonlyProperties(target, properties) { for (const propertyKey in properties) { Object.defineProperty(target, propertyKey, { enumerable: true, get() { return properties[propertyKey]; }, set(value) { const targetName = (target.constructor && target.constructor.name) || 'unknown'; throw new Error(`Readonly property (${propertyKey}) in ${targetName}`); }, }); } } const getNetworkAddress = () => { for (const fields of Object.values(interfaces)) { for (const interf of fields) { const { address, family, internal } = interf; if (family === 'IPv4' && !internal) { return address; } } } }; exports.getNetworkAddress = getNetworkAddress; function createTimer(name, logger = console) { const start = process.hrtime(); return { done: () => { const d = process.hrtime(start); const time = d[0] * 1e3 + d[1] / 1e6; logger.info.apply(logger, [`[load][${name}]`, `+${time.toFixed(3)}ms`]); }, }; } class Bootstrap { constructor(app = new core_1.default()) { this.app = app; this.composeLoaders = []; if (!('bootInfo' in app)) { const bootInfo = { bootStartedAt: new Date(), }; defineReadonlyProperties(app, { bootInfo, }); } } registerLoader(name, loader) { this.composeLoaders.push({ name, loader, }); return this; } async runLoader(name, loader) { const { app } = this; const timer = createTimer(name, app.logger); try { await loader(); } catch (error) { app.logger.error(error); } finally { timer.done(); } } extendsApplication(key, value) { const { app } = this; defineReadonlyProperties(app, { [key]: value, }); } extendContext(key, value) { const { app } = this; app.use(async (ctx, next) => { ctx[key] = value; return await next(); }); } extends(key, value, options) { var _a, _b; const isApp = (_a = options === null || options === void 0 ? void 0 : options.app) !== null && _a !== void 0 ? _a : true; const isContext = (_b = options === null || options === void 0 ? void 0 : options.context) !== null && _b !== void 0 ? _b : false; if (isApp) { this.extendsApplication(key, value); } if (isContext) { this.extendContext(key, value); } } loadConfig(fn) { const { app } = this; this.registerLoader('config', async () => { const config = await fn.apply(this, app); if (config) { this.extends('config', config, { app: true, context: true, }); } }); return this; } loadHelpers(fn) { const { app } = this; this.registerLoader('helpers', async () => { const helpers = await fn.apply(this, app); if (helpers) { this.extends('helpers', helpers, { app: false, context: true, }); } }); return this; } loadMiddlewares(fn) { const { app } = this; this.registerLoader('middlewares', async () => { const middlewares = await fn.apply(this, app); if (middlewares) { this.extends('middlewares', middlewares, { app: true, context: false, }); } }); return this; } loadModels(fn) { const { app } = this; this.registerLoader('models', async () => { const models = await fn.apply(this, app); if (models) { this.extends('models', models, { app: true, context: true, }); } }); return this; } loadServices(fn) { const { app } = this; this.registerLoader('services', async () => { const services = await fn.apply(this, app); if (services) { this.extends('services', services, { app: true, context: true, }); } }); return this; } loadControllers(fn) { const { app } = this; this.registerLoader('controllers', async () => { const controllers = await fn.apply(this, app); if (controllers) { this.extends('controllers', controllers, { app: true, context: false, }); } }); return this; } loadRoutes(fn) { const { app } = this; this.registerLoader('routes', async () => { const routes = await fn.apply(this, app); if (routes) { this.extends('routes', routes, { app: true, context: false, }); } }); return this; } async prepare() { const { app, runLoader } = this; for (const { name, loader } of this.composeLoaders) { await runLoader.apply(this, [name, loader]); } return new Bootstrap(app); } showBootMessage(server, host, port) { const { app } = this; app.logger.info('[bootloader] start at:', app.bootInfo.bootStartedAt); app.logger.info('[bootloader] load time:', `${app.bootInfo.bootTime.toFixed(3)}ms`); app.logger.info('[bootloader] running at:', app.bootInfo.runningStartedAt); const details = server.address(); const address = { local: `http://${host}:${port}`, network: 'unknown', }; if (typeof details === 'string') { address.local = details; } else { const host = ['::', '0.0.0.0'].indexOf(details.address) !== -1 ? 'localhost' : details.address; const port = details.port; const ip = (0, exports.getNetworkAddress)(); address.local = `http://${host}:${port}`; address.network = ip ? `http://${ip}:${port}` : 'unknown'; } const message = ` ${chalk.green('Serving!')} - ${chalk.bold('Local')}: ${address.local} - ${chalk.bold('On Your Network')}: ${address.network} ${chalk.grey('Copied local address to clipboard!')} `; console.log(boxen(message, { padding: 1, borderColor: 'green', margin: 1, })); } async startServer() { const { app, showBootMessage } = this; return new Promise((resolve, reject) => { var _a, _b; const port = ~~process.env.PORT || ((_a = app.config) === null || _a === void 0 ? void 0 : _a.port) || 8080; const host = process.env.HOST || ((_b = app.config) === null || _b === void 0 ? void 0 : _b.host) || '127.0.0.1'; const server = app.listen(port, host, () => { defineReadonlyProperties(app.bootInfo, { bootTime: +new Date() - +app.bootInfo.bootStartedAt, runningStartedAt: new Date(), }); Object.defineProperty(app.bootInfo, 'uptime', { enumerable: true, get() { return +new Date() - +app.bootInfo.runningStartedAt; }, }); showBootMessage.apply(this, [server, host, port]); resolve(server); }); }); } } exports.Bootstrap = Bootstrap; function bootstrap(app) { return new Bootstrap(app); } exports.bootstrap = bootstrap; exports.default = bootstrap; //# sourceMappingURL=index.js.map