UNPKG

@noxfly/noxus

Version:

Simulate lightweight HTTP-like requests between renderer and main process in Electron applications with MessagePort, with structured and modular design.

1,422 lines (1,402 loc) 72.4 kB
/** * @copyright 2025 NoxFly * @license MIT * @author NoxFly */ "use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); // src/main.ts var main_exports = {}; __export(main_exports, { AppInjector: () => AppInjector, Authorize: () => Authorize, BadGatewayException: () => BadGatewayException, BadRequestException: () => BadRequestException, CONTROLLER_METADATA_KEY: () => CONTROLLER_METADATA_KEY, ConflictException: () => ConflictException, Controller: () => Controller, Delete: () => Delete, ForbiddenException: () => ForbiddenException, ForwardReference: () => ForwardReference, GatewayTimeoutException: () => GatewayTimeoutException, Get: () => Get, HttpVersionNotSupportedException: () => HttpVersionNotSupportedException, INJECTABLE_METADATA_KEY: () => INJECTABLE_METADATA_KEY, INJECT_METADATA_KEY: () => INJECT_METADATA_KEY, Inject: () => Inject, Injectable: () => Injectable, InsufficientStorageException: () => InsufficientStorageException, InternalServerException: () => InternalServerException, Logger: () => Logger, LoopDetectedException: () => LoopDetectedException, MODULE_METADATA_KEY: () => MODULE_METADATA_KEY, MethodNotAllowedException: () => MethodNotAllowedException, Module: () => Module, NetworkAuthenticationRequiredException: () => NetworkAuthenticationRequiredException, NetworkConnectTimeoutException: () => NetworkConnectTimeoutException, NotAcceptableException: () => NotAcceptableException, NotExtendedException: () => NotExtendedException, NotFoundException: () => NotFoundException, NotImplementedException: () => NotImplementedException, NoxApp: () => NoxApp, NoxSocket: () => NoxSocket, Patch: () => Patch, PaymentRequiredException: () => PaymentRequiredException, Post: () => Post, Put: () => Put, RENDERER_EVENT_TYPE: () => RENDERER_EVENT_TYPE, ROUTE_METADATA_KEY: () => ROUTE_METADATA_KEY, Request: () => Request, RequestTimeoutException: () => RequestTimeoutException, ResponseException: () => ResponseException, RootInjector: () => RootInjector, Router: () => Router, ServiceUnavailableException: () => ServiceUnavailableException, TooManyRequestsException: () => TooManyRequestsException, UnauthorizedException: () => UnauthorizedException, UpgradeRequiredException: () => UpgradeRequiredException, UseMiddlewares: () => UseMiddlewares, VariantAlsoNegotiatesException: () => VariantAlsoNegotiatesException, bootstrapApplication: () => bootstrapApplication, createRendererEventMessage: () => createRendererEventMessage, forwardRef: () => forwardRef, getControllerMetadata: () => getControllerMetadata, getGuardForController: () => getGuardForController, getGuardForControllerAction: () => getGuardForControllerAction, getInjectableMetadata: () => getInjectableMetadata, getMiddlewaresForController: () => getMiddlewaresForController, getMiddlewaresForControllerAction: () => getMiddlewaresForControllerAction, getModuleMetadata: () => getModuleMetadata, getRouteMetadata: () => getRouteMetadata, hasInjectableMetadata: () => hasInjectableMetadata, inject: () => inject, isRendererEventMessage: () => isRendererEventMessage }); module.exports = __toCommonJS(main_exports); // src/DI/app-injector.ts var import_reflect_metadata2 = require("reflect-metadata"); // src/decorators/inject.decorator.ts var import_reflect_metadata = require("reflect-metadata"); var INJECT_METADATA_KEY = "custom:inject"; function Inject(token) { return (target, propertyKey, parameterIndex) => { const existingParameters = Reflect.getOwnMetadata(INJECT_METADATA_KEY, target) || []; existingParameters[parameterIndex] = token; Reflect.defineMetadata(INJECT_METADATA_KEY, existingParameters, target); }; } __name(Inject, "Inject"); // src/exceptions.ts var _ResponseException = class _ResponseException extends Error { constructor(statusOrMessage, message) { let statusCode; if (typeof statusOrMessage === "number") { statusCode = statusOrMessage; } else if (typeof statusOrMessage === "string") { message = statusOrMessage; } super(message ?? ""); __publicField(this, "status", 0); if (statusCode !== void 0) { this.status = statusCode; } this.name = this.constructor.name.replace(/([A-Z])/g, " $1"); } }; __name(_ResponseException, "ResponseException"); var ResponseException = _ResponseException; var _BadRequestException = class _BadRequestException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 400); } }; __name(_BadRequestException, "BadRequestException"); var BadRequestException = _BadRequestException; var _UnauthorizedException = class _UnauthorizedException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 401); } }; __name(_UnauthorizedException, "UnauthorizedException"); var UnauthorizedException = _UnauthorizedException; var _PaymentRequiredException = class _PaymentRequiredException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 402); } }; __name(_PaymentRequiredException, "PaymentRequiredException"); var PaymentRequiredException = _PaymentRequiredException; var _ForbiddenException = class _ForbiddenException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 403); } }; __name(_ForbiddenException, "ForbiddenException"); var ForbiddenException = _ForbiddenException; var _NotFoundException = class _NotFoundException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 404); } }; __name(_NotFoundException, "NotFoundException"); var NotFoundException = _NotFoundException; var _MethodNotAllowedException = class _MethodNotAllowedException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 405); } }; __name(_MethodNotAllowedException, "MethodNotAllowedException"); var MethodNotAllowedException = _MethodNotAllowedException; var _NotAcceptableException = class _NotAcceptableException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 406); } }; __name(_NotAcceptableException, "NotAcceptableException"); var NotAcceptableException = _NotAcceptableException; var _RequestTimeoutException = class _RequestTimeoutException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 408); } }; __name(_RequestTimeoutException, "RequestTimeoutException"); var RequestTimeoutException = _RequestTimeoutException; var _ConflictException = class _ConflictException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 409); } }; __name(_ConflictException, "ConflictException"); var ConflictException = _ConflictException; var _UpgradeRequiredException = class _UpgradeRequiredException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 426); } }; __name(_UpgradeRequiredException, "UpgradeRequiredException"); var UpgradeRequiredException = _UpgradeRequiredException; var _TooManyRequestsException = class _TooManyRequestsException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 429); } }; __name(_TooManyRequestsException, "TooManyRequestsException"); var TooManyRequestsException = _TooManyRequestsException; var _InternalServerException = class _InternalServerException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 500); } }; __name(_InternalServerException, "InternalServerException"); var InternalServerException = _InternalServerException; var _NotImplementedException = class _NotImplementedException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 501); } }; __name(_NotImplementedException, "NotImplementedException"); var NotImplementedException = _NotImplementedException; var _BadGatewayException = class _BadGatewayException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 502); } }; __name(_BadGatewayException, "BadGatewayException"); var BadGatewayException = _BadGatewayException; var _ServiceUnavailableException = class _ServiceUnavailableException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 503); } }; __name(_ServiceUnavailableException, "ServiceUnavailableException"); var ServiceUnavailableException = _ServiceUnavailableException; var _GatewayTimeoutException = class _GatewayTimeoutException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 504); } }; __name(_GatewayTimeoutException, "GatewayTimeoutException"); var GatewayTimeoutException = _GatewayTimeoutException; var _HttpVersionNotSupportedException = class _HttpVersionNotSupportedException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 505); } }; __name(_HttpVersionNotSupportedException, "HttpVersionNotSupportedException"); var HttpVersionNotSupportedException = _HttpVersionNotSupportedException; var _VariantAlsoNegotiatesException = class _VariantAlsoNegotiatesException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 506); } }; __name(_VariantAlsoNegotiatesException, "VariantAlsoNegotiatesException"); var VariantAlsoNegotiatesException = _VariantAlsoNegotiatesException; var _InsufficientStorageException = class _InsufficientStorageException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 507); } }; __name(_InsufficientStorageException, "InsufficientStorageException"); var InsufficientStorageException = _InsufficientStorageException; var _LoopDetectedException = class _LoopDetectedException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 508); } }; __name(_LoopDetectedException, "LoopDetectedException"); var LoopDetectedException = _LoopDetectedException; var _NotExtendedException = class _NotExtendedException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 510); } }; __name(_NotExtendedException, "NotExtendedException"); var NotExtendedException = _NotExtendedException; var _NetworkAuthenticationRequiredException = class _NetworkAuthenticationRequiredException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 511); } }; __name(_NetworkAuthenticationRequiredException, "NetworkAuthenticationRequiredException"); var NetworkAuthenticationRequiredException = _NetworkAuthenticationRequiredException; var _NetworkConnectTimeoutException = class _NetworkConnectTimeoutException extends ResponseException { constructor() { super(...arguments); __publicField(this, "status", 599); } }; __name(_NetworkConnectTimeoutException, "NetworkConnectTimeoutException"); var NetworkConnectTimeoutException = _NetworkConnectTimeoutException; // src/utils/forward-ref.ts var _ForwardReference = class _ForwardReference { constructor(forwardRefFn) { __publicField(this, "forwardRefFn"); this.forwardRefFn = forwardRefFn; } }; __name(_ForwardReference, "ForwardReference"); var ForwardReference = _ForwardReference; function forwardRef(fn) { return new ForwardReference(fn); } __name(forwardRef, "forwardRef"); // src/DI/app-injector.ts var _AppInjector = class _AppInjector { constructor(name = null) { __publicField(this, "name"); __publicField(this, "bindings", /* @__PURE__ */ new Map()); __publicField(this, "singletons", /* @__PURE__ */ new Map()); __publicField(this, "scoped", /* @__PURE__ */ new Map()); this.name = name; } /** * Typically used to create a dependency injection scope * at the "scope" level (i.e., per-request lifetime). * * SHOULD NOT BE USED by anything else than the framework itself. */ createScope() { const scope = new _AppInjector(); scope.bindings = this.bindings; scope.singletons = this.singletons; return scope; } /** * Called when resolving a dependency, * i.e., retrieving the instance of a given class. */ resolve(target) { if (target instanceof ForwardReference) { return new Proxy({}, { get: /* @__PURE__ */ __name((obj, prop, receiver) => { const realType = target.forwardRefFn(); const instance = this.resolve(realType); const value = Reflect.get(instance, prop, receiver); return typeof value === "function" ? value.bind(instance) : value; }, "get"), set: /* @__PURE__ */ __name((obj, prop, value, receiver) => { const realType = target.forwardRefFn(); const instance = this.resolve(realType); return Reflect.set(instance, prop, value, receiver); }, "set"), getPrototypeOf: /* @__PURE__ */ __name(() => { const realType = target.forwardRefFn(); return realType.prototype; }, "getPrototypeOf") }); } const binding = this.bindings.get(target); if (!binding) { if (target === void 0) { throw new InternalServerException("Failed to resolve a dependency injection : Undefined target type.\nThis might be caused by a circular dependency."); } const name = target.name || "unknown"; throw new InternalServerException(`Failed to resolve a dependency injection : No binding for type ${name}. Did you forget to use @Injectable() decorator ?`); } switch (binding.lifetime) { case "transient": return this.instantiate(binding.implementation); case "scope": { if (this.scoped.has(target)) { return this.scoped.get(target); } const instance = this.instantiate(binding.implementation); this.scoped.set(target, instance); return instance; } case "singleton": { if (binding.instance === void 0 && this.name === "root") { binding.instance = this.instantiate(binding.implementation); this.singletons.set(target, binding.instance); } return binding.instance; } } } /** * Instantiates a class, resolving its dependencies. */ instantiate(target) { const paramTypes = Reflect.getMetadata("design:paramtypes", target) || []; const injectParams = Reflect.getMetadata(INJECT_METADATA_KEY, target) || []; const params = paramTypes.map((paramType, index) => { const overrideToken = injectParams[index]; const actualToken = overrideToken !== void 0 ? overrideToken : paramType; return this.resolve(actualToken); }); return new target(...params); } }; __name(_AppInjector, "AppInjector"); var AppInjector = _AppInjector; function inject(t) { return RootInjector.resolve(t); } __name(inject, "inject"); var RootInjector = new AppInjector("root"); // src/router.ts var import_reflect_metadata4 = require("reflect-metadata"); // src/decorators/guards.decorator.ts function Authorize(...guardClasses) { return (target, propertyKey) => { let key; if (propertyKey) { const ctrlName = target.constructor.name; const actionName = propertyKey; key = `${ctrlName}.${actionName}`; } else { const ctrlName = target.name; key = `${ctrlName}`; } if (authorizations.has(key)) { throw new Error(`Guard(s) already registered for ${key}`); } authorizations.set(key, guardClasses); }; } __name(Authorize, "Authorize"); function getGuardForController(controllerName) { const key = `${controllerName}`; return authorizations.get(key) ?? []; } __name(getGuardForController, "getGuardForController"); function getGuardForControllerAction(controllerName, actionName) { const key = `${controllerName}.${actionName}`; return authorizations.get(key) ?? []; } __name(getGuardForControllerAction, "getGuardForControllerAction"); var authorizations = /* @__PURE__ */ new Map(); // src/decorators/injectable.metadata.ts var INJECTABLE_METADATA_KEY = Symbol("INJECTABLE_METADATA_KEY"); function defineInjectableMetadata(target, lifetime) { Reflect.defineMetadata(INJECTABLE_METADATA_KEY, lifetime, target); } __name(defineInjectableMetadata, "defineInjectableMetadata"); function getInjectableMetadata(target) { return Reflect.getMetadata(INJECTABLE_METADATA_KEY, target); } __name(getInjectableMetadata, "getInjectableMetadata"); function hasInjectableMetadata(target) { return Reflect.hasMetadata(INJECTABLE_METADATA_KEY, target); } __name(hasInjectableMetadata, "hasInjectableMetadata"); // src/decorators/method.decorator.ts function createRouteDecorator(verb) { return (path2) => { return (target, propertyKey) => { const existingRoutes = Reflect.getMetadata(ROUTE_METADATA_KEY, target.constructor) || []; const metadata = { method: verb, path: path2.trim().replace(/^\/|\/$/g, ""), handler: propertyKey, guards: getGuardForControllerAction(target.constructor.__controllerName, propertyKey) }; existingRoutes.push(metadata); Reflect.defineMetadata(ROUTE_METADATA_KEY, existingRoutes, target.constructor); }; }; } __name(createRouteDecorator, "createRouteDecorator"); function getRouteMetadata(target) { return Reflect.getMetadata(ROUTE_METADATA_KEY, target) || []; } __name(getRouteMetadata, "getRouteMetadata"); var Get = createRouteDecorator("GET"); var Post = createRouteDecorator("POST"); var Put = createRouteDecorator("PUT"); var Patch = createRouteDecorator("PATCH"); var Delete = createRouteDecorator("DELETE"); var ROUTE_METADATA_KEY = Symbol("ROUTE_METADATA_KEY"); // src/decorators/module.decorator.ts function Module(metadata) { return (target) => { const checkModule = /* @__PURE__ */ __name((arr, arrName) => { if (!arr) return; for (const clazz of arr) { if (!Reflect.getMetadata(MODULE_METADATA_KEY, clazz)) { throw new Error(`Class ${clazz.name} in ${arrName} must be decorated with @Module`); } } }, "checkModule"); const checkInjectable = /* @__PURE__ */ __name((arr) => { if (!arr) return; for (const clazz of arr) { if (!Reflect.getMetadata(INJECTABLE_METADATA_KEY, clazz)) { throw new Error(`Class ${clazz.name} in providers must be decorated with @Injectable`); } } }, "checkInjectable"); const checkController = /* @__PURE__ */ __name((arr) => { if (!arr) return; for (const clazz of arr) { if (!Reflect.getMetadata(CONTROLLER_METADATA_KEY, clazz)) { throw new Error(`Class ${clazz.name} in controllers must be decorated with @Controller`); } } }, "checkController"); checkModule(metadata.imports, "imports"); checkModule(metadata.exports, "exports"); checkInjectable(metadata.providers); checkController(metadata.controllers); Reflect.defineMetadata(MODULE_METADATA_KEY, metadata, target); Injectable("singleton")(target); }; } __name(Module, "Module"); function getModuleMetadata(target) { return Reflect.getMetadata(MODULE_METADATA_KEY, target); } __name(getModuleMetadata, "getModuleMetadata"); var MODULE_METADATA_KEY = Symbol("MODULE_METADATA_KEY"); // src/utils/logger.ts var fs = __toESM(require("fs")); var path = __toESM(require("path")); function getPrettyTimestamp() { const now = /* @__PURE__ */ new Date(); return `${now.getDate().toString().padStart(2, "0")}/${(now.getMonth() + 1).toString().padStart(2, "0")}/${now.getFullYear()} ${now.getHours().toString().padStart(2, "0")}:${now.getMinutes().toString().padStart(2, "0")}:${now.getSeconds().toString().padStart(2, "0")}`; } __name(getPrettyTimestamp, "getPrettyTimestamp"); function getLogPrefix(callee, messageType, color) { const timestamp = getPrettyTimestamp(); const spaces = " ".repeat(10 - messageType.length); let colReset = Logger.colors.initial; let colCallee = Logger.colors.yellow; if (color === void 0) { color = ""; colReset = ""; colCallee = ""; } return `${color}[APP] ${process.pid} - ${colReset}${timestamp}${spaces}${color}${messageType.toUpperCase()}${colReset} ${colCallee}[${callee}]${colReset}`; } __name(getLogPrefix, "getLogPrefix"); function formatObject(prefix, arg, enableColor = true) { const json = JSON.stringify(arg, null, 2); let colStart = ""; let colLine = ""; let colReset = ""; if (enableColor) { colStart = Logger.colors.darkGrey; colLine = Logger.colors.grey; colReset = Logger.colors.initial; } const prefixedJson = json.split("\n").map((line, idx) => idx === 0 ? `${colStart}${line}` : `${prefix} ${colLine}${line}`).join("\n") + colReset; return prefixedJson; } __name(formatObject, "formatObject"); function formattedArgs(prefix, args, color) { let colReset = Logger.colors.initial; if (color === void 0) { color = ""; colReset = ""; } return args.map((arg) => { if (typeof arg === "string") { return `${color}${arg}${colReset}`; } else if (typeof arg === "object") { return formatObject(prefix, arg, color !== ""); } return arg; }); } __name(formattedArgs, "formattedArgs"); function getCallee() { const stack = new Error().stack?.split("\n") ?? []; const caller = stack[3]?.trim().match(/at (.+?)(?:\..+)? .+$/)?.[1]?.replace("Object", "").replace(/^_/, "") || "App"; return caller; } __name(getCallee, "getCallee"); function canLog(level) { return logLevels.has(level); } __name(canLog, "canLog"); function processLogQueue(filepath) { const state = fileStates.get(filepath); if (!state || state.isWriting || state.queue.length === 0) { return; } state.isWriting = true; const messagesToWrite = state.queue.join("\n") + "\n"; state.queue = []; const dir = path.dirname(filepath); fs.mkdir(dir, { recursive: true }, (err) => { if (err) { console.error(`[Logger] Failed to create directory ${dir}`, err); state.isWriting = false; return; } fs.appendFile(filepath, messagesToWrite, { encoding: "utf-8" }, (err2) => { state.isWriting = false; if (err2) { console.error(`[Logger] Failed to write log to ${filepath}`, err2); } if (state.queue.length > 0) { processLogQueue(filepath); } }); }); } __name(processLogQueue, "processLogQueue"); function enqueue(filepath, message) { if (!fileStates.has(filepath)) { fileStates.set(filepath, { queue: [], isWriting: false }); } const state = fileStates.get(filepath); state.queue.push(message); processLogQueue(filepath); } __name(enqueue, "enqueue"); function output(level, args) { if (!canLog(level)) { return; } const callee = getCallee(); { const prefix = getLogPrefix(callee, level, logLevelColors[level]); const data = formattedArgs(prefix, args, logLevelColors[level]); logLevelChannel[level](prefix, ...data); } { const prefix = getLogPrefix(callee, level); const data = formattedArgs(prefix, args); const filepath = fileSettings.get(level)?.filepath; if (filepath) { const message = prefix + " " + data.join(" ").replace(/\x1b\[[0-9;]*m/g, ""); enqueue(filepath, message); } } } __name(output, "output"); (function(Logger2) { function setLogLevel(level) { logLevels.clear(); if (Array.isArray(level)) { for (const lvl of level) { logLevels.add(lvl); } } else { const targetRank = logLevelRank[level]; for (const [lvl, rank] of Object.entries(logLevelRank)) { if (rank >= targetRank) { logLevels.add(lvl); } } } } __name(setLogLevel, "setLogLevel"); Logger2.setLogLevel = setLogLevel; function log(...args) { output("log", args); } __name(log, "log"); Logger2.log = log; function info(...args) { output("info", args); } __name(info, "info"); Logger2.info = info; function warn(...args) { output("warn", args); } __name(warn, "warn"); Logger2.warn = warn; function error(...args) { output("error", args); } __name(error, "error"); Logger2.error = error; function errorStack(...args) { output("error", args); } __name(errorStack, "errorStack"); Logger2.errorStack = errorStack; function debug(...args) { output("debug", args); } __name(debug, "debug"); Logger2.debug = debug; function comment(...args) { output("comment", args); } __name(comment, "comment"); Logger2.comment = comment; function critical(...args) { output("critical", args); } __name(critical, "critical"); Logger2.critical = critical; function enableFileLogging(filepath, levels = [ "debug", "comment", "log", "info", "warn", "error", "critical" ]) { for (const level of levels) { fileSettings.set(level, { filepath }); } } __name(enableFileLogging, "enableFileLogging"); Logger2.enableFileLogging = enableFileLogging; function disableFileLogging(levels = [ "debug", "comment", "log", "info", "warn", "error", "critical" ]) { for (const level of levels) { fileSettings.delete(level); } } __name(disableFileLogging, "disableFileLogging"); Logger2.disableFileLogging = disableFileLogging; Logger2.colors = { black: "\x1B[0;30m", grey: "\x1B[0;37m", red: "\x1B[0;31m", green: "\x1B[0;32m", brown: "\x1B[0;33m", blue: "\x1B[0;34m", purple: "\x1B[0;35m", darkGrey: "\x1B[1;30m", lightRed: "\x1B[1;31m", lightGreen: "\x1B[1;32m", yellow: "\x1B[1;33m", lightBlue: "\x1B[1;34m", magenta: "\x1B[1;35m", cyan: "\x1B[1;36m", white: "\x1B[1;37m", initial: "\x1B[0m" }; })(Logger || (Logger = {})); var fileSettings = /* @__PURE__ */ new Map(); var fileStates = /* @__PURE__ */ new Map(); var logLevels = /* @__PURE__ */ new Set(); var logLevelRank = { debug: 0, comment: 1, log: 2, info: 3, warn: 4, error: 5, critical: 6 }; var logLevelColors = { debug: Logger.colors.purple, comment: Logger.colors.grey, log: Logger.colors.green, info: Logger.colors.blue, warn: Logger.colors.brown, error: Logger.colors.red, critical: Logger.colors.lightRed }; var logLevelChannel = { debug: console.debug, comment: console.debug, log: console.log, info: console.info, warn: console.warn, error: console.error, critical: console.error }; Logger.setLogLevel("debug"); var Logger; // src/DI/injector-explorer.ts var _InjectorExplorer = class _InjectorExplorer { /** * Enqueues a class for deferred registration. * Called by the @Injectable decorator at import time. * * If {@link processPending} has already been called (i.e. after bootstrap) * and accumulation mode is not active, the class is registered immediately * so that late dynamic imports (e.g. middlewares loaded after bootstrap) * work correctly. * * When accumulation mode is active (between {@link beginAccumulate} and * {@link flushAccumulated}), classes are queued instead — preserving the * two-phase binding/resolution guarantee for lazy-loaded modules. */ static enqueue(target, lifetime) { if (_InjectorExplorer.processed && !_InjectorExplorer.accumulating) { _InjectorExplorer.registerImmediate(target, lifetime); return; } _InjectorExplorer.pending.push({ target, lifetime }); } /** * Enters accumulation mode. While active, all decorated classes discovered * via dynamic imports are queued in {@link pending} rather than registered * immediately. Call {@link flushAccumulated} to process them with the * full two-phase (bind-then-resolve) guarantee. */ static beginAccumulate() { _InjectorExplorer.accumulating = true; } /** * Exits accumulation mode and processes every class queued since * {@link beginAccumulate} was called. Uses the same two-phase strategy * as {@link processPending} (register all bindings first, then resolve * singletons / controllers) so import ordering within a lazy batch * does not cause resolution failures. */ static flushAccumulated() { _InjectorExplorer.accumulating = false; const queue = [ ..._InjectorExplorer.pending ]; _InjectorExplorer.pending.length = 0; for (const { target, lifetime } of queue) { if (!RootInjector.bindings.has(target)) { RootInjector.bindings.set(target, { implementation: target, lifetime }); } } for (const { target, lifetime } of queue) { _InjectorExplorer.processRegistration(target, lifetime); } } /** * Processes all pending registrations in two phases: * 1. Register all bindings (no instantiation) so every dependency is known. * 2. Resolve singletons, register controllers and log module readiness. * * This two-phase approach makes the system resilient to import ordering: * all bindings exist before any singleton is instantiated. */ static processPending() { const queue = _InjectorExplorer.pending; for (const { target, lifetime } of queue) { if (!RootInjector.bindings.has(target)) { RootInjector.bindings.set(target, { implementation: target, lifetime }); } } for (const { target, lifetime } of queue) { _InjectorExplorer.processRegistration(target, lifetime); } queue.length = 0; _InjectorExplorer.processed = true; } /** * Registers a single class immediately (post-bootstrap path). * Used for classes discovered via late dynamic imports. */ static registerImmediate(target, lifetime) { if (RootInjector.bindings.has(target)) { return; } RootInjector.bindings.set(target, { implementation: target, lifetime }); _InjectorExplorer.processRegistration(target, lifetime); } /** * Performs phase-2 work for a single registration: resolve singletons, * register controllers, and log module readiness. */ static processRegistration(target, lifetime) { if (lifetime === "singleton") { RootInjector.resolve(target); } if (getModuleMetadata(target)) { Logger.log(`${target.name} dependencies initialized`); return; } const controllerMeta = getControllerMetadata(target); if (controllerMeta) { const router = RootInjector.resolve(Router); router?.registerController(target); return; } if (getRouteMetadata(target).length > 0) { return; } if (getInjectableMetadata(target)) { Logger.log(`Registered ${target.name} as ${lifetime}`); } } }; __name(_InjectorExplorer, "InjectorExplorer"); __publicField(_InjectorExplorer, "pending", []); __publicField(_InjectorExplorer, "processed", false); __publicField(_InjectorExplorer, "accumulating", false); var InjectorExplorer = _InjectorExplorer; // src/decorators/injectable.decorator.ts function Injectable(lifetime = "scope") { return (target) => { if (typeof target !== "function" || !target.prototype) { throw new Error(`@Injectable can only be used on classes, not on ${typeof target}`); } defineInjectableMetadata(target, lifetime); InjectorExplorer.enqueue(target, lifetime); }; } __name(Injectable, "Injectable"); // src/decorators/controller.decorator.ts function Controller(path2) { return (target) => { const data = { path: path2, guards: getGuardForController(target.name) }; Reflect.defineMetadata(CONTROLLER_METADATA_KEY, data, target); Injectable("scope")(target); }; } __name(Controller, "Controller"); function getControllerMetadata(target) { return Reflect.getMetadata(CONTROLLER_METADATA_KEY, target); } __name(getControllerMetadata, "getControllerMetadata"); var CONTROLLER_METADATA_KEY = Symbol("CONTROLLER_METADATA_KEY"); // src/decorators/middleware.decorator.ts function UseMiddlewares(mdlw) { return (target, propertyKey) => { let key; if (propertyKey) { const ctrlName = target.constructor.name; const actionName = propertyKey; key = `${ctrlName}.${actionName}`; } else { const ctrlName = target.name; key = `${ctrlName}`; } if (middlewares.has(key)) { throw new Error(`Middlewares(s) already registered for ${key}`); } middlewares.set(key, mdlw); }; } __name(UseMiddlewares, "UseMiddlewares"); function getMiddlewaresForController(controllerName) { const key = `${controllerName}`; return middlewares.get(key) ?? []; } __name(getMiddlewaresForController, "getMiddlewaresForController"); function getMiddlewaresForControllerAction(controllerName, actionName) { const key = `${controllerName}.${actionName}`; return middlewares.get(key) ?? []; } __name(getMiddlewaresForControllerAction, "getMiddlewaresForControllerAction"); var middlewares = /* @__PURE__ */ new Map(); // src/request.ts var import_reflect_metadata3 = require("reflect-metadata"); var _Request = class _Request { constructor(event, senderId, id, method, path2, body) { __publicField(this, "event"); __publicField(this, "senderId"); __publicField(this, "id"); __publicField(this, "method"); __publicField(this, "path"); __publicField(this, "body"); __publicField(this, "context", RootInjector.createScope()); __publicField(this, "params", {}); this.event = event; this.senderId = senderId; this.id = id; this.method = method; this.path = path2; this.body = body; this.path = path2.replace(/^\/|\/$/g, ""); } }; __name(_Request, "Request"); var Request = _Request; var RENDERER_EVENT_TYPE = "noxus:event"; function createRendererEventMessage(event, payload) { return { type: RENDERER_EVENT_TYPE, event, payload }; } __name(createRendererEventMessage, "createRendererEventMessage"); function isRendererEventMessage(value) { if (value === null || typeof value !== "object") { return false; } const possibleMessage = value; return possibleMessage.type === RENDERER_EVENT_TYPE && typeof possibleMessage.event === "string"; } __name(isRendererEventMessage, "isRendererEventMessage"); // src/utils/radix-tree.ts var _a; var RadixNode = (_a = class { /** * Creates a new RadixNode. * @param segment - The segment of the path this node represents. */ constructor(segment) { __publicField(this, "segment"); __publicField(this, "children", []); __publicField(this, "value"); __publicField(this, "isParam"); __publicField(this, "paramName"); this.segment = segment; this.isParam = segment.startsWith(":"); if (this.isParam) { this.paramName = segment.slice(1); } } /** * Matches a child node against a given segment. * This method checks if the segment matches any of the children nodes. * @param segment - The segment to match against the children of this node. * @returns A child node that matches the segment, or undefined if no match is found. */ matchChild(segment) { for (const child of this.children) { if (child.isParam || segment.startsWith(child.segment)) return child; } return void 0; } /** * Finds a child node that matches the segment exactly. * This method checks if there is a child node that matches the segment exactly. * @param segment - The segment to find an exact match for among the children of this node. * @returns A child node that matches the segment exactly, or undefined if no match is found. */ findExactChild(segment) { return this.children.find((c) => c.segment === segment); } /** * Adds a child node to this node's children. * This method adds a new child node to the list of children for this node. * @param node - The child node to add to this node's children. */ addChild(node) { this.children.push(node); } }, __name(_a, "RadixNode"), _a); var _RadixTree = class _RadixTree { constructor() { __publicField(this, "root", new RadixNode("")); } /** * Inserts a path and its associated value into the Radix Tree. * This method normalizes the path and inserts it into the tree, associating it with * @param path - The path to insert into the tree. * @param value - The value to associate with the path. */ insert(path2, value) { const segments = this.normalize(path2); this.insertRecursive(this.root, segments, value); } /** * Recursively inserts a path into the Radix Tree. * This method traverses the tree and inserts the segments of the path, creating new nodes * @param node - The node to start inserting from. * @param segments - The segments of the path to insert. * @param value - The value to associate with the path. */ insertRecursive(node, segments, value) { if (segments.length === 0) { node.value = value; return; } const segment = segments[0] ?? ""; let child = node.children.find((c) => c.isParam === segment.startsWith(":") && (c.isParam || c.segment === segment)); if (!child) { child = new RadixNode(segment); node.addChild(child); } this.insertRecursive(child, segments.slice(1), value); } /** * Searches for a path in the Radix Tree. * This method normalizes the path and searches for it in the tree, returning the node * @param path - The path to search for in the Radix Tree. * @returns An ISearchResult containing the node and parameters if a match is found, otherwise undefined. */ search(path2) { const segments = this.normalize(path2); return this.searchRecursive(this.root, segments, {}); } /** * Recursively searches for a path in the Radix Tree. * This method traverses the tree and searches for the segments of the path, collecting parameters * @param node - The node to start searching from. * @param segments - The segments of the path to search for. * @param params - The parameters collected during the search. * @returns An ISearchResult containing the node and parameters if a match is found, otherwise undefined. */ searchRecursive(node, segments, params) { if (segments.length === 0) { if (node.value !== void 0) { return { node, params }; } return void 0; } const [segment, ...rest] = segments; for (const child of node.children) { if (child.isParam) { const paramName = child.paramName; const childParams = { ...params, [paramName]: segment ?? "" }; if (rest.length === 0) { return { node: child, params: childParams }; } const result = this.searchRecursive(child, rest, childParams); if (result) return result; } else if (segment === child.segment) { if (rest.length === 0) { return { node: child, params }; } const result = this.searchRecursive(child, rest, params); if (result) return result; } } return void 0; } /** * Normalizes a path into an array of segments. * This method removes leading and trailing slashes, splits the path by slashes, and * @param path - The path to normalize. * @returns An array of normalized path segments. */ normalize(path2) { const segments = path2.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean); return [ "", ...segments ]; } }; __name(_RadixTree, "RadixTree"); var RadixTree = _RadixTree; // src/router.ts function _ts_decorate(decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; } __name(_ts_decorate, "_ts_decorate"); var ATOMIC_HTTP_METHODS = /* @__PURE__ */ new Set([ "GET", "POST", "PUT", "PATCH", "DELETE" ]); function isAtomicHttpMethod(method) { return typeof method === "string" && ATOMIC_HTTP_METHODS.has(method); } __name(isAtomicHttpMethod, "isAtomicHttpMethod"); var _Router = class _Router { constructor() { __publicField(this, "routes", new RadixTree()); __publicField(this, "rootMiddlewares", []); __publicField(this, "lazyRoutes", /* @__PURE__ */ new Map()); } /** * Registers a controller class with the router. * This method extracts the route metadata from the controller class and registers it in the routing tree. * It also handles the guards and middlewares associated with the controller. * @param controllerClass - The controller class to register. */ registerController(controllerClass) { const controllerMeta = getControllerMetadata(controllerClass); const controllerGuards = getGuardForController(controllerClass.name); const controllerMiddlewares = getMiddlewaresForController(controllerClass.name); if (!controllerMeta) throw new Error(`Missing @Controller decorator on ${controllerClass.name}`); const routeMetadata = getRouteMetadata(controllerClass); for (const def of routeMetadata) { const fullPath = `${controllerMeta.path}/${def.path}`.replace(/\/+/g, "/"); const routeGuards = getGuardForControllerAction(controllerClass.name, def.handler); const routeMiddlewares = getMiddlewaresForControllerAction(controllerClass.name, def.handler); const guards = /* @__PURE__ */ new Set([ ...controllerGuards, ...routeGuards ]); const middlewares2 = /* @__PURE__ */ new Set([ ...controllerMiddlewares, ...routeMiddlewares ]); const routeDef = { method: def.method, path: fullPath, controller: controllerClass, handler: def.handler, guards: [ ...guards ], middlewares: [ ...middlewares2 ] }; this.routes.insert(fullPath + "/" + def.method, routeDef); const hasActionGuards = routeDef.guards.length > 0; const actionGuardsInfo = hasActionGuards ? "<" + routeDef.guards.map((g) => g.name).join("|") + ">" : ""; Logger.log(`Mapped {${routeDef.method} /${fullPath}}${actionGuardsInfo} route`); } const hasCtrlGuards = controllerMeta.guards.length > 0; const controllerGuardsInfo = hasCtrlGuards ? "<" + controllerMeta.guards.map((g) => g.name).join("|") + ">" : ""; Logger.log(`Mapped ${controllerClass.name}${controllerGuardsInfo} controller's routes`); return this; } /** * Registers a lazy route. The module behind this route prefix will only * be imported (and its controllers/services registered in DI) the first * time a request targets this prefix. * * @param pathPrefix - Route prefix (e.g. "auth"). Matched against the first segment of the request path. * @param loadModule - A function that returns a dynamic import promise. */ registerLazyRoute(pathPrefix, loadModule) { const normalized = pathPrefix.replace(/^\/+|\/+$/g, ""); this.lazyRoutes.set(normalized, { loadModule, loading: null, loaded: false }); Logger.log(`Registered lazy route prefix {${normalized}}`); return this; } /** * Defines a middleware for the root of the application. * This method allows you to register a middleware that will be applied to all requests * to the application, regardless of the controller or action. * @param middleware - The middleware class to register. */ defineRootMiddleware(middleware) { this.rootMiddlewares.push(middleware); return this; } /** * Shuts down the message channel for a specific sender ID. * This method closes the IPC channel for the specified sender ID and * removes it from the messagePorts map. * @param channelSenderId - The ID of the sender channel to shut down. */ async handle(request) { if (request.method === "BATCH") { return this.handleBatch(request); } return this.handleAtomic(request); } async handleAtomic(request) { Logger.comment(`> ${request.method} /${request.path}`); const t0 = performance.now(); const response = { requestId: request.id, status: 200, body: null }; let isCritical = false; try { const routeDef = await this.findRoute(request); await this.resolveController(request, response, routeDef); if (response.status > 400) { throw new ResponseException(response.status, response.error); } } catch (error) { response.body = void 0; if (error instanceof ResponseException) { response.status = error.status; response.error = error.message; response.stack = error.stack; } else if (error instanceof Error) { isCritical = true; response.status = 500; response.error = error.message || "Internal Server Error"; response.stack = error.stack || "No stack trace available"; } else { isCritical = true; response.status = 500; response.error = "Unknown error occurred"; response.stack = "No stack trace available"; } } finally { const t1 = performance.now(); const message = `< ${response.status} ${request.method} /${request.path} ${Logger.colors.yellow}${Math.round(t1 - t0)}ms${Logger.colors.initial}`; if (response.status < 400) { Logger.log(message); } else if (response.status < 500) { Logger.warn(message); } else { if (isCritical) { Logger.critical(message); } else { Logger.error(message); } } if (response.error !== void 0) { if (isCritical) { Logger.critical(response.error); } else { Logger.error(response.error); } if (response.stack !== void 0) { Logger.errorStack(response.stack); } } return response; } } async handleBatch(request) { Logger.comment(`> ${request.method} /${request.path}`); const t0 = performance.now(); const response = { requestId: request.id, status: 200, body: { responses: [] } }; let isCritical = false; try { const payload = this.normalizeBatchPayload(request.body); const batchPromises = payload.requests.map((item, index) => { const subRequestId = item.requestId ?? `${request.id}:${index}`; const atomicRequest = new Request(request.event, request.senderId, subRequestId, item.method, item.path, item.body); return this.handleAtomic(atomicRequest); }); response.body.responses = await Promise.all(batchPromises); } catch (error) { response.body = void 0; if (error instanceof ResponseException) { response.status = error.status; response.error = error.message; response.stack = error.stack; } else if (error instanceof Error) { isCritical = true; response.status = 500; response.error = error.message || "Internal Server Error"; response.stack = error.stack || "No stack trace available"; } else { isCritical = true; response.status = 500; response.error = "Unknown error occurred"; response.stack = "No stack trace available"; } } finally { const t1 = performance.now(); const message = `< ${response.status} ${request.method} /${request.path} ${Logger.colors.yellow}${Math.round(t1 - t0)}ms${Logger.colors.initial}`; if (response.status < 400) { Logger.log(message); } else if (response.status < 500) {