@navios/core 1.0.0-alpha.2 → 1.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +90 -0
- package/lib/{index-BJjk2X1S.d.mts → index-6S7veHKD.d.mts} +845 -294
- package/lib/index-6S7veHKD.d.mts.map +1 -0
- package/lib/{index-DZ6NU03y.d.cts → index-r0i2txmg.d.cts} +845 -294
- package/lib/index-r0i2txmg.d.cts.map +1 -0
- package/lib/index.cjs +4420 -84
- package/lib/index.cjs.map +1 -0
- package/lib/index.d.cts +2 -2
- package/lib/index.d.mts +2 -2
- package/lib/index.mjs +4328 -3
- package/lib/index.mjs.map +1 -0
- package/lib/legacy-compat/index.cjs +41 -126
- package/lib/legacy-compat/index.cjs.map +1 -1
- package/lib/legacy-compat/index.d.cts +4 -60
- package/lib/legacy-compat/index.d.cts.map +1 -1
- package/lib/legacy-compat/index.d.mts +4 -60
- package/lib/legacy-compat/index.d.mts.map +1 -1
- package/lib/legacy-compat/index.mjs +14 -119
- package/lib/legacy-compat/index.mjs.map +1 -1
- package/lib/navios.factory-BanZIvtR.cjs +4134 -0
- package/lib/navios.factory-BanZIvtR.cjs.map +1 -0
- package/lib/navios.factory-C75yZCoD.mjs +3831 -0
- package/lib/navios.factory-C75yZCoD.mjs.map +1 -0
- package/lib/testing/index.cjs +3 -3
- package/lib/testing/index.cjs.map +1 -1
- package/lib/testing/index.d.cts +1 -1
- package/lib/testing/index.d.mts +1 -1
- package/lib/testing/index.mjs +2 -2
- package/lib/tokens-4J9sredA.mjs +100 -0
- package/lib/tokens-4J9sredA.mjs.map +1 -0
- package/lib/tokens-BuXXB01L.cjs +196 -0
- package/lib/tokens-BuXXB01L.cjs.map +1 -0
- package/lib/{use-guards.decorator-Be_QUx6b.mjs → use-guards.decorator-BecoQSmE.mjs} +3 -70
- package/lib/use-guards.decorator-BecoQSmE.mjs.map +1 -0
- package/lib/{use-guards.decorator-B6tghdxM.cjs → use-guards.decorator-DgD-kxF5.cjs} +7 -158
- package/lib/use-guards.decorator-DgD-kxF5.cjs.map +1 -0
- package/package.json +4 -4
- package/src/__tests__/attribute.factory.spec.mts +300 -0
- package/src/__tests__/console-logger.service.spec.mts +312 -0
- package/src/__tests__/guard-runner.service.spec.mts +399 -0
- package/src/__tests__/logger.service.spec.mts +147 -0
- package/src/__tests__/responders.spec.mts +6 -5
- package/src/factories/adapter.factory.mts +20 -0
- package/src/factories/endpoint-adapter.factory.mts +1 -1
- package/src/factories/http-adapter.factory.mts +1 -1
- package/src/factories/index.mts +1 -0
- package/src/factories/multipart-adapter.factory.mts +1 -1
- package/src/factories/reply.factory.mts +1 -1
- package/src/factories/request.factory.mts +1 -1
- package/src/factories/stream-adapter.factory.mts +1 -1
- package/src/factories/xml-stream-adapter.factory.mts +1 -1
- package/src/index.mts +1 -0
- package/src/interfaces/abstract-adapter.interface.mts +32 -0
- package/src/interfaces/abstract-http-adapter.interface.mts +27 -20
- package/src/interfaces/abstract-http-handler-adapter.interface.mts +86 -2
- package/src/interfaces/adapter-environment.interface.mts +74 -0
- package/src/interfaces/index.mts +2 -0
- package/src/interfaces/plugin.interface.mts +50 -16
- package/src/legacy-compat/attribute.factory.mts +2 -2
- package/src/legacy-compat/decorators/controller.decorator.mts +1 -1
- package/src/legacy-compat/decorators/endpoint.decorator.mts +1 -1
- package/src/legacy-compat/decorators/header.decorator.mts +2 -1
- package/src/legacy-compat/decorators/http-code.decorator.mts +2 -1
- package/src/legacy-compat/decorators/index.mts +2 -2
- package/src/legacy-compat/decorators/module.decorator.mts +1 -1
- package/src/legacy-compat/decorators/multipart.decorator.mts +1 -1
- package/src/legacy-compat/decorators/stream.decorator.mts +1 -1
- package/src/legacy-compat/decorators/use-guards.decorator.mts +1 -1
- package/src/legacy-compat/index.mts +10 -5
- package/src/logger/console-logger.service.mts +97 -7
- package/src/metadata/module.metadata.mts +43 -0
- package/src/navios.application.mts +172 -60
- package/src/navios.environment.mts +22 -12
- package/src/navios.factory.mts +31 -10
- package/src/services/abstract-handler-adapter.service.mts +366 -0
- package/src/services/index.mts +1 -0
- package/src/services/module-loader.service.mts +1 -0
- package/src/tokens/adapter.token.mts +6 -0
- package/src/tokens/http-adapter.token.mts +1 -1
- package/src/tokens/index.mts +1 -0
- package/src/utils/adapter-supports.util.mts +47 -0
- package/src/utils/index.mts +1 -0
- package/lib/index-BJjk2X1S.d.mts.map +0 -1
- package/lib/index-DZ6NU03y.d.cts.map +0 -1
- package/lib/src-C46ePe3d.cjs +0 -8022
- package/lib/src-C46ePe3d.cjs.map +0 -1
- package/lib/src-K2k0riYJ.mjs +0 -7587
- package/lib/src-K2k0riYJ.mjs.map +0 -1
- package/lib/use-guards.decorator-B6tghdxM.cjs.map +0 -1
- package/lib/use-guards.decorator-Be_QUx6b.mjs.map +0 -1
- package/src/legacy-compat/context-compat.mts +0 -95
- package/src/legacy-compat/decorators/factory.decorator.mts +0 -37
- package/src/legacy-compat/decorators/injectable.decorator.mts +0 -41
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navios.factory-C75yZCoD.mjs","names":["LOG_LEVELS","LOG_LEVELS","isLogLevel","maybeLogLevel","includes","LOG_LEVELS","isLogLevel","filterLogLevels","parseableString","sanitizedString","replaceAll","toLowerCase","orEqual","logLevelIndex","indexOf","substring","Error","slice","includes","split","filter","LOG_LEVEL_VALUES","verbose","debug","log","warn","error","fatal","isLogLevelEnabled","targetLevel","logLevels","Array","isArray","length","includes","highestLogLevelValue","map","level","sort","a","b","targetLevelValue","AsyncLocalStorage","requestCounter","generateRequestId","requestIdStore","getRequestIdStore","requestIdEnabled","setRequestIdEnabled","enabled","runWithRequestId","requestId","fn","run","getRequestId","undefined","getStore","InjectionToken","z","LoggerOutput","create","loggerOptionsSchema","object","context","string","optional","Logger","inspect","Injectable","getRequestId","LoggerOutput","clc","isFunction","isLogLevelEnabled","isPlainObject","isString","isUndefined","yellow","DEFAULT_DEPTH","DEFAULT_LOG_LEVELS","dateTimeFormatter","Intl","DateTimeFormat","undefined","year","hour","minute","second","day","month","token","ConsoleLogger","create","contextOrOptions","options","logger","setup","context","originalContext","inspectOptions","getInspectOptions","lastTimestampAt","opts","logLevels","colors","json","prefix","log","message","optionalParams","isLevelEnabled","messages","getContextAndMessagesToPrint","printMessages","error","stack","getContextAndStackAndMessagesToPrint","printStackTrace","warn","debug","verbose","fatal","setLogLevels","levels","setContext","resetContext","level","getCurrentRequestId","requestId","getTimestamp","format","Date","now","logLevel","writeStreamType","errorStack","resolvedRequestId","forEach","printAsJson","pidMessage","formatPid","process","pid","contextMessage","formatContext","timestampDiff","updateAndGetTimestampDiff","formattedLogLevel","toUpperCase","padStart","formattedMessage","formatMessage","write","logObject","timestamp","compact","JSON","stringify","stringifyReplacer","showPrefix","showPid","pidPart","separator","suffix","showContext","output","stringifyMessage","showLogLevel","showTimestamp","colorize","requestIdPart","parts","push","trimEnd","length","join","messageAsStr","Function","prototype","toString","call","isClass","startsWith","name","outputText","Object","keys","Array","isArray","color","getColorByLogLevel","stderr","showTimeDiff","includeTimestamp","result","formatTimestampDiff","formattedDiff","breakLength","Infinity","depth","sorted","showHidden","maxArrayLength","maxStringLength","key","value","Map","Set","Error","args","lastElement","isContext","slice","isStackFormat","isStack","test","magentaBright","red","cyanBright","bold","green","inject","Injectable","Logger","LoggerOutput","token","LoggerInstance","config","context","localInstance","error","message","optionalParams","length","undefined","concat","log","warn","debug","verbose","fatal","HttpException","statusCode","response","error","FrameworkError","InjectionToken","InternalServerErrorResponderToken","create","NotFoundResponderToken","ValidationErrorResponderToken","ForbiddenResponderToken","inject","Injectable","FrameworkError","ForbiddenResponderToken","InternalServerErrorResponderToken","NotFoundResponderToken","ValidationErrorResponderToken","ErrorResponseProducerService","forbiddenResponder","internalServerErrorResponder","notFoundResponder","validationErrorResponder","respond","type","error","description","NotFound","getResponse","Forbidden","InternalServerError","ValidationError","handleUnknown","notFound","validationError","internalServerError","forbidden","Container","getInjectableToken","inject","Injectable","InjectableScope","InstanceResolverService","container","resolve","classType","cachedInstance","get","token","getRegistry","updateScope","Request","cached","instance","scoped","resolveMany","classTypes","length","instances","results","Promise","all","map","success","allCached","every","r","cachedInstances","ControllerResolverService","inject","optional","NaviosOptionsToken","InstanceResolverService","defaultOptions","adapter","validateResponses","enableRequestId","AbstractHandlerAdapterService","instanceResolver","options","prepareArguments","handlerMetadata","createArgumentGetters","hasSchema","config","requestSchema","querySchema","provideSchema","_handlerMetadata","provideHandler","controller","getters","formatArguments","buildFormatArguments","hasArguments","length","context","methodName","classMethod","statusCode","successStatusCode","headers","resolution","resolve","cached","cachedController","instance","boundMethod","bind","createStaticHandler","createDynamicHandler","emptyArgs","Object","freeze","hasAsyncGetters","some","g","name","request","argument","promises","getter","res","Promise","push","all","hasUrlParams","url","includes","wrapWithErrorHandling","fn","args","error","inject","Injectable","HttpException","Logger","FrameworkError","ErrorResponseProducerService","GuardRunnerService","errorProducer","logger","context","name","runGuards","allGuards","executionContext","guardsArray","Array","from","reverse","guardInstances","Promise","all","map","guard","guardInstance","get","canActivate","Error","executeGuards","runGuardsStatic","error","getReply","status","statusCode","send","response","errorResponse","respond","InternalServerError","payload","Forbidden","makeContext","moduleMetadata","controllerMetadata","endpoint","guards","Set","endpointGuards","controllerGuards","moduleGuards","size","add","Container","getInjectableToken","inject","Injectable","Logger","extractModuleMetadata","ModuleLoaderService","logger","context","name","container","modulesMetadata","Map","loadedModules","initialized","loadModules","appModule","traverseModules","extendModules","extensions","Error","extension","module","controllers","moduleName","registerControllers","has","existing","get","controller","add","debug","length","metadata","Set","imports","guards","overrides","customAttributes","customEntries","set","parentMetadata","mergeMetadata","moduleToken","id","loadingPromises","Array","from","map","importedModule","Promise","all","validateOverrides","instance","onModuleInit","error","size","registry","getRegistry","overrideClass","overrideToken","allRegistrations","getAll","warn","highestPriorityRegistration","target","overrideRegistration","find","r","toString","priority","guard","key","value","getAllModules","dispose","clear","adapterSupports","adapter","method","assertAdapterSupports","Error","Injectable","AdapterToken","NaviosEnvironment","adapterConfigured","tokens","Map","setupEnvironment","hasAdapterToken","has","Error","token","value","set","getToken","get","hasAdapterSetup","Container","inject","Injectable","Logger","NaviosEnvironment","ModuleLoaderService","AdapterToken","assertAdapterSupports","NaviosApplication","environment","moduleLoader","adapter","logger","context","name","container","appModule","options","plugins","isInitialized","setup","hasAdapterSetup","get","getContainer","getAdapter","Error","usePlugin","definition","push","init","loadModules","setupAdapter","initPlugins","initModules","ready","debug","modules","getAllModules","onModulesInit","length","plugin","register","token","args","configure","enableCors","enableMultipart","setGlobalPrefix","prefix","getServer","listen","dispose","close","Container","isNil","LoggerOutput","NaviosApplication","NaviosEnvironment","setRequestIdEnabled","NaviosOptionsToken","NaviosFactory","create","appModule","options","adapter","container","registry","enableRequestId","addInstance","registerLoggerConfiguration","adapters","Array","isArray","registerEnvironment","app","get","setup","environment","naviosEnvironment","tokens","setupEnvironment","logger","loggerInstance","logLevels","undefined","requestId"],"sources":["../src/logger/utils/cli-colors.util.mts","../src/logger/log-levels.mts","../src/logger/utils/is-log-level.util.mts","../src/logger/utils/filter-log-levelts.util.mts","../src/logger/utils/is-log-level-enabled.mts","../src/logger/utils/shared.utils.mts","../src/stores/request-id.store.mts","../src/logger/logger.tokens.mts","../src/logger/console-logger.service.mts","../src/logger/logger.service.mts","../src/exceptions/http.exception.mts","../src/responders/enums/framework-error.enum.mts","../src/responders/tokens/responder.tokens.mts","../src/responders/services/error-response-producer.service.mts","../src/services/instance-resolver.service.mts","../src/services/abstract-handler-adapter.service.mts","../src/services/guard-runner.service.mts","../src/services/module-loader.service.mts","../src/utils/adapter-supports.util.mts","../src/navios.environment.mts","../src/navios.application.mts","../src/navios.factory.mts"],"sourcesContent":["type ColorTextFn = (text: string) => string\n\nconst isColorAllowed = () => !process.env.NO_COLOR\nconst colorIfAllowed = (colorFn: ColorTextFn) => (text: string) =>\n isColorAllowed() ? colorFn(text) : text\n\nexport const clc = {\n bold: colorIfAllowed((text: string) => `\\x1B[1m${text}\\x1B[0m`),\n green: colorIfAllowed((text: string) => `\\x1B[32m${text}\\x1B[39m`),\n yellow: colorIfAllowed((text: string) => `\\x1B[33m${text}\\x1B[39m`),\n red: colorIfAllowed((text: string) => `\\x1B[31m${text}\\x1B[39m`),\n magentaBright: colorIfAllowed((text: string) => `\\x1B[95m${text}\\x1B[39m`),\n cyanBright: colorIfAllowed((text: string) => `\\x1B[96m${text}\\x1B[39m`),\n}\nexport const yellow = colorIfAllowed(\n (text: string) => `\\x1B[38;5;3m${text}\\x1B[39m`,\n)\n","/**\n * Available log levels in order of severity (lowest to highest).\n */\nexport const LOG_LEVELS = [\n 'verbose',\n 'debug',\n 'log',\n 'warn',\n 'error',\n 'fatal',\n] as const satisfies string[]\n\n/**\n * Log level type.\n * \n * Represents the severity level of a log message.\n * Levels are: 'verbose', 'debug', 'log', 'warn', 'error', 'fatal'\n * \n * @publicApi\n */\nexport type LogLevel = (typeof LOG_LEVELS)[number]\n","import type { LogLevel } from '../log-levels.mjs'\n\nimport { LOG_LEVELS } from '../log-levels.mjs'\n\n/**\n * @publicApi\n */\nexport function isLogLevel(maybeLogLevel: any): maybeLogLevel is LogLevel {\n return LOG_LEVELS.includes(maybeLogLevel)\n}\n","import type { LogLevel } from '../log-levels.mjs'\n\nimport { LOG_LEVELS } from '../log-levels.mjs'\nimport { isLogLevel } from './is-log-level.util.mjs'\n\n/**\n * @publicApi\n */\nexport function filterLogLevels(parseableString = ''): LogLevel[] {\n const sanitizedString = parseableString.replaceAll(' ', '').toLowerCase()\n\n if (sanitizedString[0] === '>') {\n const orEqual = sanitizedString[1] === '='\n\n const logLevelIndex = (LOG_LEVELS as string[]).indexOf(\n sanitizedString.substring(orEqual ? 2 : 1),\n )\n\n if (logLevelIndex === -1) {\n throw new Error(`parse error (unknown log level): ${sanitizedString}`)\n }\n\n return LOG_LEVELS.slice(orEqual ? logLevelIndex : logLevelIndex + 1)\n } else if (sanitizedString.includes(',')) {\n return sanitizedString.split(',').filter(isLogLevel)\n }\n\n return isLogLevel(sanitizedString) ? [sanitizedString] : LOG_LEVELS\n}\n","import type { LogLevel } from '../log-levels.mjs'\n\nconst LOG_LEVEL_VALUES: Record<LogLevel, number> = {\n verbose: 0,\n debug: 1,\n log: 2,\n warn: 3,\n error: 4,\n fatal: 5,\n}\n\n/**\n * Checks if target level is enabled.\n * @param targetLevel target level\n * @param logLevels array of enabled log levels\n */\nexport function isLogLevelEnabled(\n targetLevel: LogLevel,\n logLevels: LogLevel[] | undefined,\n): boolean {\n if (!logLevels || (Array.isArray(logLevels) && logLevels?.length === 0)) {\n return false\n }\n if (logLevels.includes(targetLevel)) {\n return true\n }\n const highestLogLevelValue = logLevels\n .map((level) => LOG_LEVEL_VALUES[level])\n .sort((a, b) => b - a)?.[0]\n\n const targetLevelValue = LOG_LEVEL_VALUES[targetLevel]\n return targetLevelValue >= highestLogLevelValue\n}\n","export const isUndefined = (obj: any): obj is undefined =>\n typeof obj === 'undefined'\n\nexport const isObject = (fn: any): fn is object =>\n !isNil(fn) && typeof fn === 'object'\n\nexport const isPlainObject = (fn: any): fn is object => {\n if (!isObject(fn)) {\n return false\n }\n const proto = Object.getPrototypeOf(fn)\n if (proto === null) {\n return true\n }\n const ctor =\n Object.prototype.hasOwnProperty.call(proto, 'constructor') &&\n proto.constructor\n return (\n typeof ctor === 'function' &&\n ctor instanceof ctor &&\n Function.prototype.toString.call(ctor) ===\n Function.prototype.toString.call(Object)\n )\n}\n\nexport const addLeadingSlash = (path?: string): string =>\n path && typeof path === 'string'\n ? path.charAt(0) !== '/' && path.substring(0, 2) !== '{/'\n ? '/' + path\n : path\n : ''\n\nexport const normalizePath = (path?: string): string =>\n path\n ? path.startsWith('/')\n ? ('/' + path.replace(/\\/+$/, '')).replace(/\\/+/g, '/')\n : '/' + path.replace(/\\/+$/, '')\n : '/'\n\nexport const stripEndSlash = (path: string) =>\n path[path.length - 1] === '/' ? path.slice(0, path.length - 1) : path\n\nexport const isFunction = (val: any): val is Function =>\n typeof val === 'function'\nexport const isString = (val: any): val is string => typeof val === 'string'\nexport const isNumber = (val: any): val is number => typeof val === 'number'\nexport const isConstructor = (val: any): boolean => val === 'constructor'\nexport const isNil = (val: any): val is null | undefined =>\n isUndefined(val) || val === null\nexport const isEmpty = (array: any): boolean => !(array && array.length > 0)\nexport const isSymbol = (val: any): val is symbol => typeof val === 'symbol'\n","import { AsyncLocalStorage } from 'node:async_hooks'\n\nlet requestCounter = 0\n\n/**\n * Generates a simple incremental request ID.\n * Much faster than crypto.randomUUID() and sufficient for request tracking.\n *\n * @returns A unique request ID string (e.g., \"req-1\", \"req-2\", ...)\n */\nexport function generateRequestId(): string {\n return `req-${++requestCounter}`\n}\n\n/**\n * AsyncLocalStorage store for the current request ID.\n *\n * This allows logging and other services to access the current request ID\n * without explicitly passing it through the call stack.\n *\n * @example\n * ```typescript\n * import { requestIdStore, runWithRequestId, getRequestId } from '@navios/core'\n *\n * // Run code with a request ID in context\n * runWithRequestId('req-123', () => {\n * // Inside this callback, getRequestId() returns 'req-123'\n * logger.log('Processing request') // Will include request ID if logger is configured\n * })\n *\n * // Get current request ID (returns undefined if not in a request context)\n * const currentId = getRequestId()\n * ```\n */\nlet requestIdStore: AsyncLocalStorage<string> | null = null\n\nfunction getRequestIdStore(): AsyncLocalStorage<string> {\n if (!requestIdStore) {\n requestIdStore = new AsyncLocalStorage<string>()\n }\n return requestIdStore!\n}\n/**\n * Whether request ID propagation is enabled.\n * When disabled, runWithRequestId is a pass-through for better performance.\n */\nlet requestIdEnabled = false\n\n/**\n * Enables or disables request ID propagation.\n * Called by NaviosFactory based on the enableRequestId option.\n *\n * @param enabled - Whether to enable request ID propagation\n */\nexport function setRequestIdEnabled(enabled: boolean): void {\n requestIdEnabled = enabled\n}\n\n/**\n * Runs a function with a request ID in the async local storage context.\n * If request ID propagation is disabled, the function is called directly\n * without AsyncLocalStorage overhead.\n *\n * @param requestId - The request ID to set for this context\n * @param fn - The function to run within this context\n * @returns The return value of the function\n */\nexport function runWithRequestId<R>(requestId: string, fn: () => R): R {\n if (!requestIdEnabled) {\n return fn()\n }\n return getRequestIdStore().run(requestId, fn)\n}\n\n/**\n * Gets the current request ID from the async local storage context.\n *\n * @returns The current request ID, or undefined if not in a request context\n */\nexport function getRequestId(): string | undefined {\n if (!requestIdEnabled) {\n return undefined\n }\n return getRequestIdStore().getStore()\n}\n","import { InjectionToken } from '@navios/di'\n\nimport z from 'zod/v4'\n\nimport type { LoggerService } from './logger-service.interface.mjs'\nimport type { LoggerInstance } from './logger.service.mjs'\n\n/**\n * Injection token for the logger output service.\n * \n * This token is used to provide a custom logger implementation.\n * By default, it's bound to ConsoleLogger.\n */\nexport const LoggerOutput = InjectionToken.create<LoggerService>('LoggerOutput')\n\n/**\n * Schema for logger options.\n */\nexport const loggerOptionsSchema = z\n .object({\n context: z.string().optional(),\n })\n .optional()\n\n/**\n * Options for creating a logger instance.\n */\nexport type LoggerOptions = z.infer<typeof loggerOptionsSchema>\n\n/**\n * Injection token for the Logger service.\n * \n * Use this token to inject a contextualized logger instance.\n * \n * @example\n * ```typescript\n * const logger = inject(Logger, { context: 'MyService' })\n * logger.log('Hello world') // Logs with context: [MyService]\n * ```\n */\nexport const Logger = InjectionToken.create<\n LoggerInstance,\n typeof loggerOptionsSchema\n>('Logger', loggerOptionsSchema)\n","import type { InspectOptions } from 'util'\n\nimport { inspect } from 'util'\n\nimport { Injectable } from '@navios/di'\n\nimport type { LogLevel } from './log-levels.mjs'\nimport type { LoggerService } from './logger-service.interface.mjs'\n\nimport { getRequestId } from '../stores/request-id.store.mjs'\nimport { LoggerOutput } from './logger.tokens.mjs'\nimport {\n clc,\n isFunction,\n isLogLevelEnabled,\n isPlainObject,\n isString,\n isUndefined,\n yellow,\n} from './utils/index.mjs'\n\nconst DEFAULT_DEPTH = 5\n\n/**\n * @publicApi\n */\nexport interface ConsoleLoggerOptions {\n /**\n * Enabled log levels.\n */\n logLevels?: LogLevel[]\n /**\n * If enabled, will print timestamp difference between current and previous log message.\n * Note: This option is not used when `json` is enabled.\n * @default false\n */\n showTimeDiff?: boolean\n /**\n * A prefix to be used for each log message.\n * Note: This option is not used when `json` is enabled.\n */\n prefix?: string\n /**\n * If true, will print the process ID in the log message.\n * Note: This option is not used when `json` is enabled.\n * @default true\n */\n showPid?: boolean\n /**\n * If true, will print the log level in the log message.\n * Note: This option is not used when `json` is enabled.\n * @default true\n */\n showLogLevel?: boolean\n /**\n * If true, will print the prefix/app name in the log message.\n * Note: This option is not used when `json` is enabled.\n * @default true\n */\n showPrefix?: boolean\n /**\n * If true, will print the context in the log message.\n * Note: This option is not used when `json` is enabled.\n * @default true\n */\n showContext?: boolean\n /**\n * If true, will print the absolute timestamp in the log message.\n * Note: This option is not used when `json` is enabled.\n * @default true\n */\n showTimestamp?: boolean\n /**\n * If enabled, will add a request ID to the log message.\n */\n requestId?: boolean\n /**\n * If enabled, will print the log message in JSON format.\n */\n json?: boolean\n /**\n * If enabled, will print the log message in color.\n * Default true if json is disabled, false otherwise\n */\n colors?: boolean\n /**\n * The context of the logger.\n */\n context?: string\n /**\n * If enabled, will print the log message in a single line, even if it is an object with multiple properties.\n * If set to a number, the most n inner elements are united on a single line as long as all properties fit into breakLength. Short array elements are also grouped together.\n * Default true when `json` is enabled, false otherwise.\n */\n compact?: boolean | number\n /**\n * Specifies the maximum number of Array, TypedArray, Map, Set, WeakMap, and WeakSet elements to include when formatting.\n * Set to null or Infinity to show all elements. Set to 0 or negative to show no elements.\n * Ignored when `json` is enabled, colors are disabled, and `compact` is set to true as it produces a parseable JSON output.\n * @default 100\n */\n maxArrayLength?: number\n /**\n * Specifies the maximum number of characters to include when formatting.\n * Set to null or Infinity to show all elements. Set to 0 or negative to show no characters.\n * Ignored when `json` is enabled, colors are disabled, and `compact` is set to true as it produces a parseable JSON output.\n * @default 10000.\n */\n maxStringLength?: number\n /**\n * If enabled, will sort keys while formatting objects.\n * Can also be a custom sorting function.\n * Ignored when `json` is enabled, colors are disabled, and `compact` is set to true as it produces a parseable JSON output.\n * @default false\n */\n sorted?: boolean | ((a: string, b: string) => number)\n /**\n * Specifies the number of times to recurse while formatting object. T\n * This is useful for inspecting large objects. To recurse up to the maximum call stack size pass Infinity or null.\n * Ignored when `json` is enabled, colors are disabled, and `compact` is set to true as it produces a parseable JSON output.\n * @default 5\n */\n depth?: number\n /**\n * If true, object's non-enumerable symbols and properties are included in the formatted result.\n * WeakMap and WeakSet entries are also included as well as user defined prototype properties\n * @default false\n */\n showHidden?: boolean\n /**\n * The length at which input values are split across multiple lines. Set to Infinity to format the input as a single line (in combination with \"compact\" set to true).\n * Default Infinity when \"compact\" is true, 80 otherwise.\n * Ignored when `json` is enabled, colors are disabled, and `compact` is set to true as it produces a parseable JSON output.\n */\n breakLength?: number\n}\n\nconst DEFAULT_LOG_LEVELS: LogLevel[] = [\n 'log',\n 'error',\n 'warn',\n 'debug',\n 'verbose',\n 'fatal',\n]\n\nconst dateTimeFormatter = new Intl.DateTimeFormat(undefined, {\n year: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n day: '2-digit',\n month: '2-digit',\n})\n\n/**\n * @publicApi\n */\n@Injectable({\n token: LoggerOutput,\n})\nexport class ConsoleLogger implements LoggerService {\n /**\n * Creates a new ConsoleLogger instance with the given options.\n * This is a convenience method that instantiates and sets up the logger in one call.\n */\n static create(): ConsoleLogger\n static create(context: string): ConsoleLogger\n static create(options: ConsoleLoggerOptions): ConsoleLogger\n static create(context: string, options: ConsoleLoggerOptions): ConsoleLogger\n static create(\n contextOrOptions?: string | ConsoleLoggerOptions,\n options?: ConsoleLoggerOptions,\n ): ConsoleLogger {\n const logger = new ConsoleLogger()\n if (contextOrOptions !== undefined) {\n if (typeof contextOrOptions === 'string') {\n logger.setup(contextOrOptions, options ?? {})\n } else {\n logger.setup(contextOrOptions)\n }\n } else {\n logger.setup()\n }\n return logger\n }\n\n /**\n * The options of the logger.\n */\n protected options: ConsoleLoggerOptions = {}\n /**\n * The context of the logger (can be set manually or automatically inferred).\n */\n protected context?: string\n /**\n * The original context of the logger (set in the constructor).\n */\n protected originalContext?: string\n /**\n * The options used for the \"inspect\" method.\n */\n protected inspectOptions: InspectOptions = this.getInspectOptions()\n /**\n * The last timestamp at which the log message was printed.\n */\n protected lastTimestampAt?: number\n\n setup(): void\n setup(context: string): void\n setup(options: ConsoleLoggerOptions): void\n setup(context: string, options: ConsoleLoggerOptions): void\n setup(\n contextOrOptions?: string | ConsoleLoggerOptions,\n options?: ConsoleLoggerOptions,\n ) {\n // eslint-disable-next-line prefer-const\n let [context, opts] = isString(contextOrOptions)\n ? [contextOrOptions, options]\n : options\n ? [undefined, options]\n : [contextOrOptions?.context, contextOrOptions]\n\n opts = opts ?? {}\n opts.logLevels ??= DEFAULT_LOG_LEVELS\n opts.colors ??= opts.colors ?? (opts.json ? false : true)\n opts.prefix ??= 'Navios'\n\n this.options = opts\n this.inspectOptions = this.getInspectOptions()\n\n if (context) {\n this.context = context\n this.originalContext = context\n }\n }\n\n /**\n * Write a 'log' level log, if the configured level allows for it.\n * Prints to `stdout` with newline.\n */\n log(message: any, context?: string): void\n log(message: any, ...optionalParams: [...any, string?]): void\n log(message: any, ...optionalParams: any[]) {\n if (!this.isLevelEnabled('log')) {\n return\n }\n const { messages, context } = this.getContextAndMessagesToPrint([\n message,\n ...optionalParams,\n ])\n this.printMessages(messages, context, 'log')\n }\n\n /**\n * Write an 'error' level log, if the configured level allows for it.\n * Prints to `stderr` with newline.\n */\n error(message: any, stackOrContext?: string): void\n error(message: any, stack?: string, context?: string): void\n error(message: any, ...optionalParams: [...any, string?, string?]): void\n error(message: any, ...optionalParams: any[]) {\n if (!this.isLevelEnabled('error')) {\n return\n }\n const { messages, context, stack } =\n this.getContextAndStackAndMessagesToPrint([message, ...optionalParams])\n\n this.printMessages(messages, context, 'error', undefined, 'stderr', stack)\n this.printStackTrace(stack!)\n }\n\n /**\n * Write a 'warn' level log, if the configured level allows for it.\n * Prints to `stdout` with newline.\n */\n warn(message: any, context?: string): void\n warn(message: any, ...optionalParams: [...any, string?]): void\n warn(message: any, ...optionalParams: any[]) {\n if (!this.isLevelEnabled('warn')) {\n return\n }\n const { messages, context } = this.getContextAndMessagesToPrint([\n message,\n ...optionalParams,\n ])\n this.printMessages(messages, context, 'warn')\n }\n\n /**\n * Write a 'debug' level log, if the configured level allows for it.\n * Prints to `stdout` with newline.\n */\n debug(message: any, context?: string): void\n debug(message: any, ...optionalParams: [...any, string?]): void\n debug(message: any, ...optionalParams: any[]) {\n if (!this.isLevelEnabled('debug')) {\n return\n }\n const { messages, context } = this.getContextAndMessagesToPrint([\n message,\n ...optionalParams,\n ])\n this.printMessages(messages, context, 'debug')\n }\n\n /**\n * Write a 'verbose' level log, if the configured level allows for it.\n * Prints to `stdout` with newline.\n */\n verbose(message: any, context?: string): void\n verbose(message: any, ...optionalParams: [...any, string?]): void\n verbose(message: any, ...optionalParams: any[]) {\n if (!this.isLevelEnabled('verbose')) {\n return\n }\n const { messages, context } = this.getContextAndMessagesToPrint([\n message,\n ...optionalParams,\n ])\n this.printMessages(messages, context, 'verbose')\n }\n\n /**\n * Write a 'fatal' level log, if the configured level allows for it.\n * Prints to `stdout` with newline.\n */\n fatal(message: any, context?: string): void\n fatal(message: any, ...optionalParams: [...any, string?]): void\n fatal(message: any, ...optionalParams: any[]) {\n if (!this.isLevelEnabled('fatal')) {\n return\n }\n const { messages, context } = this.getContextAndMessagesToPrint([\n message,\n ...optionalParams,\n ])\n this.printMessages(messages, context, 'fatal')\n }\n\n /**\n * Set log levels\n * @param levels log levels\n */\n setLogLevels(levels: LogLevel[]) {\n if (!this.options) {\n this.options = {}\n }\n this.options.logLevels = levels\n }\n\n /**\n * Set logger context\n * @param context context\n */\n setContext(context: string) {\n this.context = context\n }\n\n /**\n * Resets the logger context to the value that was passed in the constructor.\n */\n resetContext() {\n this.context = this.originalContext\n }\n\n isLevelEnabled(level: LogLevel): boolean {\n const logLevels = this.options?.logLevels\n return isLogLevelEnabled(level, logLevels)\n }\n\n /**\n * Gets the current request ID from the AsyncLocalStorage store.\n * Only returns a value if the requestId option is enabled.\n */\n protected getCurrentRequestId(): string | undefined {\n if (!this.options.requestId) {\n return undefined\n }\n return getRequestId()\n }\n\n protected getTimestamp(): string {\n return dateTimeFormatter.format(Date.now())\n }\n\n protected printMessages(\n messages: unknown[],\n context = '',\n logLevel: LogLevel = 'log',\n requestId?: string,\n writeStreamType?: 'stdout' | 'stderr',\n errorStack?: unknown,\n ) {\n const resolvedRequestId = requestId ?? this.getCurrentRequestId()\n messages.forEach((message) => {\n if (this.options.json) {\n this.printAsJson(message, {\n context,\n logLevel,\n writeStreamType,\n errorStack,\n requestId: resolvedRequestId,\n })\n return\n }\n const pidMessage = this.formatPid(process.pid)\n const contextMessage = this.formatContext(context)\n const timestampDiff = this.updateAndGetTimestampDiff()\n const formattedLogLevel = logLevel.toUpperCase().padStart(7, ' ')\n const formattedMessage = this.formatMessage(\n logLevel,\n message,\n pidMessage,\n formattedLogLevel,\n contextMessage,\n timestampDiff,\n resolvedRequestId,\n )\n\n process[writeStreamType ?? 'stdout'].write(formattedMessage)\n })\n }\n\n protected printAsJson(\n message: unknown,\n options: {\n context: string\n logLevel: LogLevel\n writeStreamType?: 'stdout' | 'stderr'\n errorStack?: unknown\n requestId?: string\n },\n ) {\n type JsonLogObject = {\n level: LogLevel\n pid: number\n timestamp: number\n message: unknown\n context?: string\n stack?: unknown\n requestId?: string\n }\n\n const logObject: JsonLogObject = {\n level: options.logLevel,\n pid: process.pid,\n timestamp: Date.now(),\n message,\n }\n\n if (options.context) {\n logObject.context = options.context\n }\n\n if (options.errorStack) {\n logObject.stack = options.errorStack\n }\n if (this.options.requestId && options.requestId) {\n logObject.requestId = options.requestId\n }\n\n const formattedMessage =\n !this.options.colors && this.inspectOptions.compact === true\n ? JSON.stringify(logObject, this.stringifyReplacer)\n : inspect(logObject, this.inspectOptions)\n process[options.writeStreamType ?? 'stdout'].write(`${formattedMessage}\\n`)\n }\n\n protected formatPid(pid: number) {\n const showPrefix = this.options.showPrefix ?? true\n const showPid = this.options.showPid ?? true\n\n if (!showPrefix && !showPid) {\n return ''\n }\n\n const prefix = showPrefix ? `[${this.options.prefix}]` : ''\n const pidPart = showPid ? `${pid}` : ''\n const separator = showPrefix && showPid ? ' ' : ''\n const suffix = showPrefix || showPid ? ' - ' : ''\n\n return `${prefix}${separator}${pidPart}${suffix}`\n }\n\n protected formatContext(context: string): string {\n const showContext = this.options.showContext ?? true\n if (!context || !showContext) {\n return ''\n }\n\n context = `[${context}] `\n return this.options.colors ? yellow(context) : context\n }\n\n protected formatMessage(\n logLevel: LogLevel,\n message: unknown,\n pidMessage: string,\n formattedLogLevel: string,\n contextMessage: string,\n timestampDiff: string,\n requestId?: string,\n ) {\n const output = this.stringifyMessage(message, logLevel)\n const showLogLevel = this.options.showLogLevel ?? true\n const showTimestamp = this.options.showTimestamp ?? true\n\n pidMessage = this.colorize(pidMessage, logLevel)\n formattedLogLevel = showLogLevel\n ? this.colorize(formattedLogLevel, logLevel)\n : ''\n\n const timestamp = showTimestamp ? this.getTimestamp() : ''\n const requestIdPart = this.getRequestId(requestId)\n\n // Build the message parts, filtering out empty ones\n const parts: string[] = []\n\n if (pidMessage) parts.push(pidMessage.trimEnd())\n if (requestIdPart) parts.push(requestIdPart.trimEnd())\n if (timestamp) parts.push(timestamp)\n if (formattedLogLevel) parts.push(formattedLogLevel)\n if (contextMessage) parts.push(contextMessage.trimEnd())\n\n const prefix = parts.length > 0 ? parts.join(' ') + ' ' : ''\n\n return `${prefix}${output}${timestampDiff}\\n`\n }\n\n protected getRequestId(requestId?: string) {\n if (this.options.requestId && requestId) {\n return `(${this.colorize(requestId, 'log')}) `\n }\n return ''\n }\n\n protected stringifyMessage(message: unknown, logLevel: LogLevel): string {\n if (isFunction(message)) {\n const messageAsStr = Function.prototype.toString.call(message)\n const isClass = messageAsStr.startsWith('class ')\n if (isClass) {\n // If the message is a class, we will display the class name.\n return this.stringifyMessage(message.name, logLevel)\n }\n // If the message is a non-class function, call it and re-resolve its value.\n return this.stringifyMessage(message(), logLevel)\n }\n\n if (typeof message === 'string') {\n return this.colorize(message, logLevel)\n }\n\n const outputText = inspect(message, this.inspectOptions)\n if (isPlainObject(message)) {\n return `Object(${Object.keys(message).length}) ${outputText}`\n }\n if (Array.isArray(message)) {\n return `Array(${message.length}) ${outputText}`\n }\n return outputText\n }\n\n protected colorize(message: string, logLevel: LogLevel) {\n if (!this.options.colors || this.options.json) {\n return message\n }\n const color = this.getColorByLogLevel(logLevel)\n return color(message)\n }\n\n protected printStackTrace(stack: string) {\n if (!stack || this.options.json) {\n return\n }\n process.stderr.write(`${stack}\\n`)\n }\n\n protected updateAndGetTimestampDiff(): string {\n const showTimeDiff = this.options?.showTimeDiff ?? false\n const includeTimestamp = this.lastTimestampAt && showTimeDiff\n const result = includeTimestamp\n ? this.formatTimestampDiff(Date.now() - this.lastTimestampAt!)\n : ''\n this.lastTimestampAt = Date.now()\n return result\n }\n\n protected formatTimestampDiff(timestampDiff: number) {\n const formattedDiff = ` +${timestampDiff}ms`\n return this.options.colors ? yellow(formattedDiff) : formattedDiff\n }\n\n protected getInspectOptions() {\n let breakLength = this.options.breakLength\n if (typeof breakLength === 'undefined') {\n breakLength = this.options.colors\n ? this.options.compact\n ? Infinity\n : undefined\n : this.options.compact === false\n ? undefined\n : Infinity // default breakLength to Infinity if inline is not set and colors is false\n }\n\n const inspectOptions: InspectOptions = {\n depth: this.options.depth ?? DEFAULT_DEPTH,\n sorted: this.options.sorted,\n showHidden: this.options.showHidden,\n compact: this.options.compact ?? (this.options.json ? true : false),\n colors: this.options.colors,\n breakLength,\n }\n\n if (this.options.maxArrayLength) {\n inspectOptions.maxArrayLength = this.options.maxArrayLength\n }\n if (this.options.maxStringLength) {\n inspectOptions.maxStringLength = this.options.maxStringLength\n }\n\n return inspectOptions\n }\n\n protected stringifyReplacer(key: string, value: unknown) {\n // Mimic util.inspect behavior for JSON logger with compact on and colors off\n if (typeof value === 'bigint') {\n return value.toString()\n }\n if (typeof value === 'symbol') {\n return value.toString()\n }\n\n if (\n value instanceof Map ||\n value instanceof Set ||\n value instanceof Error\n ) {\n return `${inspect(value, this.inspectOptions)}`\n }\n return value\n }\n\n private getContextAndMessagesToPrint(args: unknown[]) {\n if (args?.length <= 1) {\n return { messages: args, context: this.context }\n }\n const lastElement = args[args.length - 1]\n const isContext = isString(lastElement)\n if (!isContext) {\n return { messages: args, context: this.context }\n }\n return {\n context: lastElement,\n messages: args.slice(0, args.length - 1),\n }\n }\n\n private getContextAndStackAndMessagesToPrint(args: unknown[]) {\n if (args.length === 2) {\n return this.isStackFormat(args[1])\n ? {\n messages: [args[0]],\n stack: args[1] as string,\n context: this.context,\n }\n : {\n messages: [args[0]],\n context: args[1] as string,\n }\n }\n\n const { messages, context } = this.getContextAndMessagesToPrint(args)\n if (messages?.length <= 1) {\n return { messages, context }\n }\n const lastElement = messages[messages.length - 1]\n const isStack = isString(lastElement)\n // https://github.com/nestjs/nest/issues/11074#issuecomment-1421680060\n if (!isStack && !isUndefined(lastElement)) {\n return { messages, context }\n }\n return {\n stack: lastElement,\n messages: messages.slice(0, messages.length - 1),\n context,\n }\n }\n\n private isStackFormat(stack: unknown) {\n if (!isString(stack) && !isUndefined(stack)) {\n return false\n }\n\n return /^(.)+\\n\\s+at .+:\\d+:\\d+/.test(stack!)\n }\n\n private getColorByLogLevel(level: LogLevel) {\n switch (level) {\n case 'debug':\n return clc.magentaBright\n case 'warn':\n return clc.yellow\n case 'error':\n return clc.red\n case 'verbose':\n return clc.cyanBright\n case 'fatal':\n return clc.bold\n default:\n return clc.green\n }\n }\n}\n","import { inject, Injectable } from '@navios/di'\n\nimport type { LoggerService } from './logger-service.interface.mjs'\nimport type { LoggerOptions } from './logger.tokens.mjs'\n\nimport { Logger, LoggerOutput } from './logger.tokens.mjs'\n\n/**\n * Logger service instance that can be injected into services and controllers.\n *\n * Provides contextualized logging with automatic context injection.\n * The context is set when the logger is injected using the `inject` function.\n *\n * @example\n * ```typescript\n * @Injectable()\n * export class UserService {\n * private logger = inject(Logger, { context: UserService.name })\n *\n * async findUser(id: string) {\n * this.logger.log(`Finding user ${id}`)\n * // Logs with context: [UserService]\n * }\n * }\n * ```\n */\n@Injectable({\n token: Logger,\n})\nexport class LoggerInstance implements LoggerService {\n protected localInstance = inject(LoggerOutput)\n\n protected context?: string\n\n constructor(config: LoggerOptions = {}) {\n this.context = config.context\n }\n\n /**\n * Write an 'error' level log.\n */\n error(message: any, stack?: string, context?: string): void\n error(message: any, ...optionalParams: [...any, string?, string?]): void\n error(message: any, ...optionalParams: any[]) {\n optionalParams = this.context\n ? (optionalParams.length ? optionalParams : [undefined]).concat(\n this.context,\n )\n : optionalParams\n\n this.localInstance?.error(message, ...optionalParams)\n }\n\n /**\n * Write a 'log' level log.\n */\n log(message: any, context?: string): void\n log(message: any, ...optionalParams: [...any, string?]): void\n log(message: any, ...optionalParams: any[]) {\n optionalParams = this.context\n ? optionalParams.concat(this.context)\n : optionalParams\n this.localInstance?.log(message, ...optionalParams)\n }\n\n /**\n * Write a 'warn' level log.\n */\n warn(message: any, context?: string): void\n warn(message: any, ...optionalParams: [...any, string?]): void\n warn(message: any, ...optionalParams: any[]) {\n optionalParams = this.context\n ? optionalParams.concat(this.context)\n : optionalParams\n this.localInstance?.warn(message, ...optionalParams)\n }\n\n /**\n * Write a 'debug' level log.\n */\n debug(message: any, context?: string): void\n debug(message: any, ...optionalParams: [...any, string?]): void\n debug(message: any, ...optionalParams: any[]) {\n optionalParams = this.context\n ? optionalParams.concat(this.context)\n : optionalParams\n this.localInstance?.debug?.(message, ...optionalParams)\n }\n\n /**\n * Write a 'verbose' level log.\n */\n verbose(message: any, context?: string): void\n verbose(message: any, ...optionalParams: [...any, string?]): void\n verbose(message: any, ...optionalParams: any[]) {\n optionalParams = this.context\n ? optionalParams.concat(this.context)\n : optionalParams\n this.localInstance?.verbose?.(message, ...optionalParams)\n }\n\n /**\n * Write a 'fatal' level log.\n */\n fatal(message: any, context?: string): void\n fatal(message: any, ...optionalParams: [...any, string?]): void\n fatal(message: any, ...optionalParams: any[]) {\n optionalParams = this.context\n ? optionalParams.concat(this.context)\n : optionalParams\n this.localInstance?.fatal?.(message, ...optionalParams)\n }\n}\n","/**\n * Base exception class for all HTTP exceptions in Navios.\n * \n * All HTTP exception classes extend this base class. When thrown from an endpoint handler,\n * Navios will automatically convert it to an appropriate HTTP response with the specified\n * status code and response body.\n * \n * @example\n * ```typescript\n * @Endpoint(getUserEndpoint)\n * async getUser(request: EndpointParams<typeof getUserEndpoint>) {\n * const user = await this.userService.findById(request.urlParams.userId)\n * if (!user) {\n * throw new HttpException(404, 'User not found')\n * }\n * return user\n * }\n * ```\n */\nexport class HttpException {\n /**\n * Creates a new HttpException instance.\n * \n * @param statusCode - HTTP status code (e.g., 400, 404, 500)\n * @param response - Response body (string or object)\n * @param error - Optional underlying error for logging/debugging\n */\n constructor(\n public readonly statusCode: number,\n public readonly response: string | object,\n public readonly error?: Error,\n ) {}\n}\n","/**\n * Enumeration of framework-level error types.\n * Used to explicitly specify which error responder should handle an error.\n *\n * @example\n * ```typescript\n * // In adapter error handling\n * if (error instanceof ZodError) {\n * return errorProducer.respond(FrameworkError.ValidationError, error)\n * }\n * return errorProducer.handleUnknown(error)\n * ```\n */\nexport enum FrameworkError {\n /**\n * Resource not found (HTTP 404).\n * Use when a requested resource does not exist.\n */\n NotFound = 'NotFound',\n\n /**\n * Forbidden (HTTP 403).\n * Use when access to a resource is denied (e.g., guard rejection).\n */\n Forbidden = 'Forbidden',\n\n /**\n * Internal server error (HTTP 500).\n * Use for unexpected errors that don't fit other categories.\n */\n InternalServerError = 'InternalServerError',\n\n /**\n * Validation error (HTTP 400).\n * Use when request data fails validation (e.g., Zod errors).\n */\n ValidationError = 'ValidationError',\n}\n","import { InjectionToken } from '@navios/di'\n\nimport type { ErrorResponder } from '../interfaces/error-responder.interface.mjs'\n\n/**\n * Injection token for the Internal Server Error responder.\n * Default implementation returns HTTP 500 with RFC 7807 Problem Details.\n *\n * @example Override with custom implementation:\n * ```typescript\n * @Injectable({\n * token: InternalServerErrorResponderToken,\n * priority: 0, // Higher than default -10\n * })\n * export class CustomInternalErrorResponder implements ErrorResponder {\n * getResponse(error: unknown, description?: string): ErrorResponse {\n * // Custom implementation\n * }\n * }\n * ```\n */\nexport const InternalServerErrorResponderToken =\n InjectionToken.create<ErrorResponder>('InternalServerErrorResponder')\n\n/**\n * Injection token for the Not Found responder.\n * Default implementation returns HTTP 404 with RFC 7807 Problem Details.\n *\n * @example Override with custom implementation:\n * ```typescript\n * @Injectable({\n * token: NotFoundResponderToken,\n * priority: 0, // Higher than default -10\n * })\n * export class CustomNotFoundResponder implements ErrorResponder {\n * getResponse(error: unknown, description?: string): ErrorResponse {\n * // Custom implementation\n * }\n * }\n * ```\n */\nexport const NotFoundResponderToken =\n InjectionToken.create<ErrorResponder>('NotFoundResponder')\n\n/**\n * Injection token for the Validation Error responder.\n * Default implementation returns HTTP 400 with RFC 7807 Problem Details\n * and includes validation errors from ZodError.\n *\n * @example Override with custom implementation:\n * ```typescript\n * @Injectable({\n * token: ValidationErrorResponderToken,\n * priority: 0, // Higher than default -10\n * })\n * export class CustomValidationResponder implements ErrorResponder {\n * getResponse(error: unknown, description?: string): ErrorResponse {\n * // Custom implementation\n * }\n * }\n * ```\n */\nexport const ValidationErrorResponderToken =\n InjectionToken.create<ErrorResponder>('ValidationErrorResponder')\n\n/**\n * Injection token for the Forbidden responder.\n * Default implementation returns HTTP 403 with RFC 7807 Problem Details.\n *\n * @example Override with custom implementation:\n * ```typescript\n * @Injectable({\n * token: ForbiddenResponderToken,\n * priority: 0, // Higher than default -10\n * })\n * export class CustomForbiddenResponder implements ErrorResponder {\n * getResponse(error: unknown, description?: string): ErrorResponse {\n * // Custom implementation\n * }\n * }\n * ```\n */\nexport const ForbiddenResponderToken =\n InjectionToken.create<ErrorResponder>('ForbiddenResponder')\n","import { inject, Injectable } from '@navios/di'\n\nimport { FrameworkError } from '../enums/framework-error.enum.mjs'\nimport type { ErrorResponse } from '../interfaces/error-response.interface.mjs'\nimport {\n ForbiddenResponderToken,\n InternalServerErrorResponderToken,\n NotFoundResponderToken,\n ValidationErrorResponderToken,\n} from '../tokens/responder.tokens.mjs'\n\n/**\n * Service for producing standardized error responses.\n *\n * This service coordinates error responders to produce RFC 7807 compliant\n * Problem Details responses. Adapters use this service to convert errors\n * into standardized HTTP responses.\n *\n * The caller explicitly specifies which type of error response to produce\n * via the FrameworkError enum, giving full control to the adapter.\n *\n * @example Usage in an adapter:\n * ```typescript\n * @Injectable()\n * class MyAdapter {\n * private errorProducer = inject(ErrorResponseProducerService)\n *\n * handleError(error: unknown): Response {\n * if (error instanceof ZodError) {\n * const response = this.errorProducer.respond(\n * FrameworkError.ValidationError,\n * error,\n * )\n * return new Response(JSON.stringify(response.payload), {\n * status: response.statusCode,\n * headers: response.headers,\n * })\n * }\n *\n * // Fallback for unknown errors\n * const response = this.errorProducer.handleUnknown(error)\n * return new Response(JSON.stringify(response.payload), {\n * status: response.statusCode,\n * headers: response.headers,\n * })\n * }\n * }\n * ```\n */\n@Injectable()\nexport class ErrorResponseProducerService {\n private readonly forbiddenResponder = inject(ForbiddenResponderToken)\n private readonly internalServerErrorResponder = inject(\n InternalServerErrorResponderToken,\n )\n private readonly notFoundResponder = inject(NotFoundResponderToken)\n private readonly validationErrorResponder = inject(\n ValidationErrorResponderToken,\n )\n\n /**\n * Produces an error response for a specific framework error type.\n *\n * @param type - The type of framework error (from FrameworkError enum)\n * @param error - The original error that was thrown\n * @param description - Optional custom description to include in the response\n * @returns ErrorResponse with status code, RFC 7807 payload, and headers\n */\n respond(\n type: FrameworkError,\n error: unknown,\n description?: string,\n ): ErrorResponse {\n switch (type) {\n case FrameworkError.NotFound:\n return this.notFoundResponder.getResponse(error, description)\n case FrameworkError.Forbidden:\n return this.forbiddenResponder.getResponse(error, description)\n case FrameworkError.InternalServerError:\n return this.internalServerErrorResponder.getResponse(error, description)\n case FrameworkError.ValidationError:\n return this.validationErrorResponder.getResponse(error, description)\n }\n }\n\n /**\n * Handles unknown errors by producing an Internal Server Error response.\n *\n * Use this as a fallback when the error type is not known or doesn't\n * match any specific framework error type.\n *\n * @param error - The original error that was thrown\n * @param description - Optional custom description to include in the response\n * @returns ErrorResponse with 500 status code\n */\n handleUnknown(error: unknown, description?: string): ErrorResponse {\n return this.internalServerErrorResponder.getResponse(error, description)\n }\n\n /**\n * Convenience method to produce a Not Found error response.\n *\n * @param error - The original error that was thrown\n * @param description - Optional custom description\n * @returns ErrorResponse with 404 status code\n */\n notFound(error: unknown, description?: string): ErrorResponse {\n return this.notFoundResponder.getResponse(error, description)\n }\n\n /**\n * Convenience method to produce a Validation Error response.\n *\n * @param error - The original error (typically a ZodError)\n * @param description - Optional custom description\n * @returns ErrorResponse with 400 status code\n */\n validationError(error: unknown, description?: string): ErrorResponse {\n return this.validationErrorResponder.getResponse(error, description)\n }\n\n /**\n * Convenience method to produce an Internal Server Error response.\n *\n * @param error - The original error\n * @param description - Optional custom description\n * @returns ErrorResponse with 500 status code\n */\n internalServerError(error: unknown, description?: string): ErrorResponse {\n return this.internalServerErrorResponder.getResponse(error, description)\n }\n\n /**\n * Convenience method to produce a Forbidden error response.\n *\n * @param error - The original error\n * @param description - Optional custom description\n * @returns ErrorResponse with 403 status code\n */\n forbidden(error: unknown, description?: string): ErrorResponse {\n return this.forbiddenResponder.getResponse(error, description)\n }\n}\n","import type { ClassType, ScopedContainer } from '@navios/di'\n\nimport {\n Container,\n getInjectableToken,\n inject,\n Injectable,\n InjectableScope,\n} from '@navios/di'\n\n/**\n * Result of instance resolution attempt.\n * Contains either a cached singleton instance or a resolver function\n * that can be used to get a fresh instance per request.\n */\nexport interface InstanceResolution<T = any> {\n /**\n * Whether the instance was successfully cached as a singleton.\n * If true, `instance` contains the cached instance.\n * If false, the class has request-scoped dependencies and\n * must be resolved per-request using `resolve()`.\n */\n cached: boolean\n\n /**\n * The cached instance (only available if `cached` is true).\n */\n instance: T | null\n\n /**\n * Resolves the instance from a scoped container.\n * Use this when `cached` is false to get a fresh instance per request.\n */\n resolve: (scoped: ScopedContainer) => Promise<T>\n}\n\n/**\n * Result of resolving multiple instances.\n * Contains either all cached singleton instances or a resolver function.\n */\nexport interface MultiInstanceResolution<T = any> {\n /**\n * Whether ALL instances were successfully cached as singletons.\n * If true, `instances` contains all cached instances.\n * If false, at least one class has request-scoped dependencies.\n */\n cached: boolean\n\n /**\n * The cached instances (only available if `cached` is true).\n * Order matches the input array order.\n */\n instances: T[] | null\n\n /**\n * The original class types for dynamic resolution.\n */\n classTypes: ClassType[]\n\n /**\n * Resolves all instances from a scoped container.\n * Use this when `cached` is false to get fresh instances per request.\n */\n resolve: (scoped: ScopedContainer) => Promise<T[]>\n}\n\n/**\n * Service responsible for resolving class instances with automatic scope detection.\n *\n * This service attempts to resolve classes as singletons from the root container.\n * If resolution fails (because the class has request-scoped dependencies),\n * it automatically updates the class's scope to Request and provides a\n * resolver function for per-request instantiation.\n *\n * This enables optimal performance:\n * - Classes without request-scoped deps stay as singletons (faster)\n * - Classes with request-scoped deps are automatically promoted to request scope\n *\n * @example\n * ```ts\n * const resolution = await instanceResolver.resolve(UserController)\n *\n * if (resolution.cached) {\n * // Use cached singleton\n * return resolution.instance.handleRequest(req)\n * } else {\n * // Resolve per request\n * const controller = await resolution.resolve(scopedContainer)\n * return controller.handleRequest(req)\n * }\n * ```\n */\n@Injectable()\nexport class InstanceResolverService {\n private container = inject(Container)\n\n /**\n * Attempts to resolve a class instance, automatically detecting if it needs\n * request scope based on its dependencies.\n *\n * @param classType - The class to resolve\n * @returns A resolution result containing either a cached instance or resolver function\n */\n async resolve<T>(classType: ClassType): Promise<InstanceResolution<T>> {\n let cachedInstance: T | null = null\n\n try {\n cachedInstance = await this.container.get(classType)\n } catch {\n // Class has request-scoped dependencies, update its scope to Request\n // so it will be resolved per-request from the scoped container\n const token = getInjectableToken(classType)\n this.container.getRegistry().updateScope(token, InjectableScope.Request)\n }\n\n return {\n cached: cachedInstance !== null,\n instance: cachedInstance,\n resolve: (scoped: ScopedContainer) => scoped.get(classType) as Promise<T>,\n }\n }\n\n /**\n * Attempts to resolve multiple class instances, automatically detecting if any need\n * request scope based on their dependencies.\n *\n * Returns `cached: true` only if ALL classes can be resolved as singletons.\n * If any class has request-scoped dependencies, returns `cached: false`.\n *\n * @param classTypes - The classes to resolve\n * @returns A resolution result containing either all cached instances or resolver function\n */\n async resolveMany<T>(\n classTypes: ClassType[],\n ): Promise<MultiInstanceResolution<T>> {\n if (classTypes.length === 0) {\n return {\n cached: true,\n instances: [],\n classTypes: [],\n resolve: async () => [],\n }\n }\n\n // Resolve all classes in parallel\n const results = await Promise.all(\n classTypes.map(async (classType) => {\n try {\n const instance = await this.container.get(classType)\n return { success: true, instance: instance as T }\n } catch {\n // Class has request-scoped dependencies, update its scope to Request\n const token = getInjectableToken(classType)\n this.container\n .getRegistry()\n .updateScope(token, InjectableScope.Request)\n return { success: false, instance: null }\n }\n }),\n )\n\n const allCached = results.every((r) => r.success)\n const cachedInstances = allCached\n ? results.map((r) => r.instance as T)\n : null\n\n return {\n cached: allCached,\n instances: cachedInstances,\n classTypes,\n resolve: (scoped: ScopedContainer) =>\n Promise.all(\n classTypes.map((classType) => scoped.get(classType) as Promise<T>),\n ),\n }\n }\n}\n\n/**\n * @deprecated Use InstanceResolverService instead\n */\nexport const ControllerResolverService = InstanceResolverService\n\n/**\n * @deprecated Use InstanceResolution instead\n */\nexport type ControllerResolution<T = any> = InstanceResolution<T>\n","import type { ClassType, ScopedContainer } from '@navios/di'\nimport type { BaseEndpointOptions } from '@navios/builder'\n\nimport { inject, optional } from '@navios/di'\n\nimport type { HandlerMetadata } from '../metadata/index.mjs'\nimport type {\n ArgumentGetterFn,\n FormatArgumentsFn as InterfaceFormatArgumentsFn,\n HttpHeader,\n} from '../interfaces/index.mjs'\nimport type { NaviosApplicationOptions } from '../navios.application.mjs'\n\nimport { NaviosOptionsToken } from '../tokens/index.mjs'\nimport {\n InstanceResolverService,\n type InstanceResolution,\n} from './instance-resolver.service.mjs'\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Function type for argument getters that extract data from requests.\n * Re-exported from interface for convenience in adapter implementations.\n */\nexport type ArgumentGetter<TRequest> = ArgumentGetterFn<TRequest>\n\n/**\n * Internal alias for FormatArgumentsFn from interface.\n * Not re-exported to avoid duplicate exports - use FormatArgumentsFn from interfaces instead.\n */\ntype FormatArgumentsFn<TRequest> = InterfaceFormatArgumentsFn<TRequest>\n\n/**\n * Static handler - can be called without a scoped container.\n */\nexport type AbstractStaticHandler<TRequest, TReply = void> = {\n isStatic: true\n handler: (request: TRequest, reply: TReply) => Promise<any>\n}\n\n/**\n * Dynamic handler - requires a scoped container for resolution.\n */\nexport type AbstractDynamicHandler<TRequest, TReply = void> = {\n isStatic: false\n handler: (\n scoped: ScopedContainer,\n request: TRequest,\n reply: TReply,\n ) => Promise<any>\n}\n\n/**\n * Handler result - either static or dynamic.\n */\nexport type AbstractHandlerResult<TRequest, TReply = void> =\n | AbstractStaticHandler<TRequest, TReply>\n | AbstractDynamicHandler<TRequest, TReply>\n\n/**\n * Context passed to handler creation methods.\n */\nexport interface HandlerContext<\n TConfig extends BaseEndpointOptions = BaseEndpointOptions,\n> {\n methodName: string\n statusCode: number\n headers: Partial<Record<HttpHeader, number | string | string[] | undefined>>\n handlerMetadata: HandlerMetadata<TConfig>\n hasArguments: boolean\n}\n\n// ============================================================================\n// Default Options\n// ============================================================================\n\nconst defaultOptions: NaviosApplicationOptions = {\n adapter: [],\n validateResponses: true,\n enableRequestId: false,\n}\n\n// ============================================================================\n// Abstract Base Class\n// ============================================================================\n\n/**\n * Abstract base class for HTTP handler adapter services.\n *\n * Provides shared logic for:\n * - Controller resolution (singleton vs request-scoped)\n * - Argument formatting (sync/async detection)\n * - Handler generation with static/dynamic branching\n * - Standardized error handling\n *\n * Adapters implement abstract methods for framework-specific behavior:\n * - Request parsing (query, body, URL params)\n * - Response creation\n * - Schema provision\n *\n * Supports all adapter types:\n * - Endpoint adapters: JSON request/response with validation\n * - Stream adapters: Streaming responses with extra context\n * - Multipart adapters: Form data parsing (extends endpoint)\n *\n * @typeParam TRequest - Framework request type (BunRequest, FastifyRequest)\n * @typeParam TReply - Framework reply type (void for Bun, FastifyReply)\n * @typeParam TConfig - Endpoint configuration type\n */\nexport abstract class AbstractHandlerAdapterService<\n TRequest,\n TReply = void,\n TConfig extends BaseEndpointOptions = BaseEndpointOptions,\n> {\n protected instanceResolver = inject(InstanceResolverService)\n protected options = optional(NaviosOptionsToken) ?? defaultOptions\n\n // ==========================================================================\n // Abstract Methods - Must be implemented by adapters\n // ==========================================================================\n\n /**\n * Creates argument getter functions for extracting data from requests.\n *\n * Each getter populates a target object with data from the request\n * (query params, body, URL params, etc.).\n *\n * Implementation varies by adapter type:\n * - Endpoint: JSON body parsing with schema validation\n * - Stream: Same as endpoint (body + query + url params)\n * - Multipart: FormData/multipart stream parsing\n *\n * @param handlerMetadata - Handler metadata with schemas and configuration\n * @returns Array of getter functions\n */\n protected abstract createArgumentGetters(\n handlerMetadata: HandlerMetadata<TConfig>,\n ): ArgumentGetter<TRequest>[]\n\n /**\n * Creates a static handler for singleton controllers.\n *\n * Implementation varies by adapter type:\n * - Endpoint: Invoke method(args), serialize response as JSON\n * - Stream: Invoke method(args, streamContext), return Response/use reply\n *\n * @param boundMethod - Pre-bound controller method\n * @param formatArguments - Function to format request arguments\n * @param context - Handler context with metadata\n * @returns Static handler result\n */\n protected abstract createStaticHandler(\n boundMethod: (...args: any[]) => Promise<any>,\n formatArguments: FormatArgumentsFn<TRequest>,\n context: HandlerContext<TConfig>,\n ): AbstractStaticHandler<TRequest, TReply>\n\n /**\n * Creates a dynamic handler for request-scoped controllers.\n *\n * Implementation varies by adapter type:\n * - Endpoint: Resolve controller per-request, invoke method(args)\n * - Stream: Resolve controller per-request, invoke method(args, streamContext)\n *\n * @param resolution - Instance resolution with resolve function\n * @param formatArguments - Function to format request arguments\n * @param context - Handler context with metadata\n * @returns Dynamic handler result\n */\n protected abstract createDynamicHandler(\n resolution: InstanceResolution,\n formatArguments: FormatArgumentsFn<TRequest>,\n context: HandlerContext<TConfig>,\n ): AbstractDynamicHandler<TRequest, TReply>\n\n // ==========================================================================\n // Public Interface Methods\n // ==========================================================================\n\n /**\n * Prepares argument getters for parsing request data.\n *\n * Public alias for createArgumentGetters to satisfy interface contracts.\n * Subclasses should override createArgumentGetters instead.\n *\n * @param handlerMetadata - Handler metadata with schemas and configuration\n * @returns Array of getter functions\n */\n prepareArguments(\n handlerMetadata: HandlerMetadata<TConfig>,\n ): ArgumentGetter<TRequest>[] {\n return this.createArgumentGetters(handlerMetadata)\n }\n\n /**\n * Checks if the handler has any validation schemas defined.\n *\n * Override in subclasses to add additional schema checks\n * (e.g., response schema validation for endpoint adapters).\n *\n * @param handlerMetadata - Handler metadata with configuration\n * @returns true if handler has schemas\n */\n hasSchema(handlerMetadata: HandlerMetadata<TConfig>): boolean {\n const config = handlerMetadata.config\n return !!config.requestSchema || !!config.querySchema\n }\n\n /**\n * Provides schema information for the framework's validation system.\n *\n * Override in subclasses for frameworks that support schema registration\n * (e.g., Fastify). Default returns empty object (suitable for Bun).\n *\n * @param handlerMetadata - Handler metadata with configuration\n * @returns Schema object for framework registration\n */\n provideSchema(\n _handlerMetadata: HandlerMetadata<TConfig>,\n ): Record<string, any> {\n return {}\n }\n\n /**\n * Creates a request handler function for the endpoint.\n *\n * This method orchestrates the entire handler creation:\n * 1. Prepares argument getters for request parsing\n * 2. Builds optimized formatArguments function (sync/async)\n * 3. Resolves the controller (singleton vs request-scoped)\n * 4. Creates appropriate handler (static or dynamic)\n *\n * @param controller - Controller class containing the handler method\n * @param handlerMetadata - Handler metadata with configuration\n * @returns Handler result (static or dynamic)\n */\n async provideHandler(\n controller: ClassType,\n handlerMetadata: HandlerMetadata<TConfig>,\n ): Promise<AbstractHandlerResult<TRequest, TReply>> {\n // Prepare argument getters\n const getters = this.createArgumentGetters(handlerMetadata)\n const formatArguments = this.buildFormatArguments(getters)\n const hasArguments = getters.length > 0\n\n // Build handler context\n const context: HandlerContext<TConfig> = {\n methodName: handlerMetadata.classMethod,\n statusCode: handlerMetadata.successStatusCode,\n headers: handlerMetadata.headers,\n handlerMetadata,\n hasArguments,\n }\n\n // Resolve controller with automatic scope detection\n const resolution = await this.instanceResolver.resolve(controller)\n\n // Create appropriate handler based on resolution\n if (resolution.cached) {\n const cachedController = resolution.instance as any\n const boundMethod =\n cachedController[context.methodName].bind(cachedController)\n return this.createStaticHandler(boundMethod, formatArguments, context)\n }\n\n return this.createDynamicHandler(resolution, formatArguments, context)\n }\n\n // ==========================================================================\n // Public Utilities\n // ==========================================================================\n\n /**\n * Builds a formatArguments function from argument getters.\n *\n * Automatically detects sync vs async getters and optimizes accordingly:\n * - If all getters are sync: returns sync function (no Promise overhead)\n * - If any getter is async: returns async function with Promise.all\n * - If no getters: returns frozen empty object (zero allocation)\n *\n * This method is public to allow composition-based adapters (like XML adapter)\n * to reuse the optimized formatArguments logic without inheritance.\n *\n * @param getters - Array of argument getter functions\n * @returns Function to format arguments from request\n */\n buildFormatArguments(\n getters: ArgumentGetter<TRequest>[],\n ): FormatArgumentsFn<TRequest> {\n if (getters.length === 0) {\n const emptyArgs = Object.freeze({})\n return () => emptyArgs\n }\n\n // Detect if any getter is async at registration time\n const hasAsyncGetters = getters.some(\n (g) => g.constructor.name === 'AsyncFunction',\n )\n\n if (hasAsyncGetters) {\n return async (request: TRequest) => {\n const argument: Record<string, any> = {}\n const promises: Promise<void>[] = []\n for (const getter of getters) {\n const res = getter(argument, request)\n if (res instanceof Promise) {\n promises.push(res)\n }\n }\n await Promise.all(promises)\n return argument\n }\n }\n\n return (request: TRequest) => {\n const argument: Record<string, any> = {}\n for (const getter of getters) {\n getter(argument, request)\n }\n return argument\n }\n }\n\n // ==========================================================================\n // Protected Utilities\n // ==========================================================================\n\n /**\n * Checks if the URL pattern contains URL parameters.\n *\n * @param config - Endpoint configuration\n * @returns true if URL contains '$' parameter markers\n */\n protected hasUrlParams(config: TConfig): boolean {\n return config.url.includes('$')\n }\n\n /**\n * Wraps handler execution with standardized error handling.\n *\n * Re-throws HttpExceptions as-is for framework error handlers.\n * Other errors are re-thrown for global error handling.\n *\n * @param fn - Handler function to wrap\n * @returns Wrapped function with error handling\n */\n protected wrapWithErrorHandling<T extends (...args: any[]) => Promise<any>>(\n fn: T,\n ): T {\n return (async (...args: any[]) => {\n try {\n return await fn(...args)\n } catch (error) {\n // Re-throw HttpExceptions as-is for framework error handlers\n if (error && typeof error === 'object' && 'statusCode' in error) {\n throw error\n }\n // Re-throw unexpected errors for global error handling\n throw error\n }\n }) as T\n }\n}\n","import type { ClassTypeWithInstance, ScopedContainer } from '@navios/di'\n\nimport { inject, Injectable, InjectionToken } from '@navios/di'\n\nimport type {\n AbstractExecutionContext,\n CanActivate,\n} from '../interfaces/index.mjs'\nimport type {\n ControllerMetadata,\n HandlerMetadata,\n ModuleMetadata,\n} from '../metadata/index.mjs'\n\nimport { HttpException } from '../exceptions/index.mjs'\nimport { Logger } from '../logger/index.mjs'\nimport { FrameworkError } from '../responders/enums/framework-error.enum.mjs'\nimport { ErrorResponseProducerService } from '../responders/services/error-response-producer.service.mjs'\n\n@Injectable()\nexport class GuardRunnerService {\n private readonly errorProducer = inject(ErrorResponseProducerService)\n private readonly logger = inject(Logger, {\n context: GuardRunnerService.name,\n })\n\n /**\n * Runs guards that need to be resolved from a scoped container.\n * Use this when guards have request-scoped dependencies.\n */\n async runGuards(\n allGuards: Set<\n | ClassTypeWithInstance<CanActivate>\n | InjectionToken<CanActivate, undefined>\n >,\n executionContext: AbstractExecutionContext,\n context: ScopedContainer,\n ) {\n // Reverse order: module guards run first, then controller, then endpoint\n const guardsArray = Array.from(allGuards).reverse()\n\n // Resolve all guards in parallel\n const guardInstances = await Promise.all(\n guardsArray.map(async (guard) => {\n const guardInstance = await context.get(\n guard as InjectionToken<CanActivate, undefined>,\n )\n if (!guardInstance.canActivate) {\n throw new Error(\n `[Navios] Guard ${guard.name as string} does not implement canActivate()`,\n )\n }\n return guardInstance\n }),\n )\n\n return this.executeGuards(guardInstances, executionContext)\n }\n\n /**\n * Runs pre-resolved guard instances.\n * Use this when all guards are singletons and have been pre-resolved at startup.\n */\n async runGuardsStatic(\n guardInstances: CanActivate[],\n executionContext: AbstractExecutionContext,\n ) {\n return this.executeGuards(guardInstances, executionContext)\n }\n\n /**\n * Shared guard execution logic.\n * Iterates through guard instances and calls canActivate on each.\n */\n private async executeGuards(\n guardInstances: CanActivate[],\n executionContext: AbstractExecutionContext,\n ): Promise<boolean> {\n let canActivate = true\n for (const guardInstance of guardInstances) {\n try {\n canActivate = await guardInstance.canActivate(executionContext)\n if (!canActivate) {\n break\n }\n } catch (error) {\n if (error instanceof HttpException) {\n executionContext\n .getReply()\n .status(error.statusCode)\n .send(error.response)\n return false\n } else {\n this.logger.error('Error running guard', error)\n const errorResponse = this.errorProducer.respond(\n FrameworkError.InternalServerError,\n error,\n )\n executionContext\n .getReply()\n .status(errorResponse.statusCode)\n .send(errorResponse.payload)\n return false\n }\n }\n }\n if (!canActivate) {\n const errorResponse = this.errorProducer.respond(\n FrameworkError.Forbidden,\n null,\n )\n executionContext\n .getReply()\n .status(errorResponse.statusCode)\n .send(errorResponse.payload)\n return false\n }\n return canActivate\n }\n\n makeContext(\n moduleMetadata: ModuleMetadata,\n controllerMetadata: ControllerMetadata,\n endpoint: HandlerMetadata,\n ): Set<\n ClassTypeWithInstance<CanActivate> | InjectionToken<CanActivate, undefined>\n > {\n const guards = new Set<\n | ClassTypeWithInstance<CanActivate>\n | InjectionToken<CanActivate, undefined>\n >()\n const endpointGuards = endpoint.guards\n const controllerGuards = controllerMetadata.guards\n const moduleGuards = moduleMetadata.guards\n if (endpointGuards.size > 0) {\n for (const guard of endpointGuards) {\n guards.add(guard)\n }\n }\n if (controllerGuards.size > 0) {\n for (const guard of controllerGuards) {\n guards.add(guard)\n }\n }\n if (moduleGuards.size > 0) {\n for (const guard of moduleGuards) {\n guards.add(guard)\n }\n }\n return guards\n }\n}\n","import type { ClassType, ClassTypeWithInstance } from '@navios/di'\n\nimport { Container, getInjectableToken, inject, Injectable } from '@navios/di'\n\nimport type { NaviosModule } from '../interfaces/index.mjs'\nimport type { ModuleMetadata } from '../metadata/index.mjs'\n\nimport { Logger } from '../logger/index.mjs'\nimport { extractModuleMetadata } from '../metadata/index.mjs'\n\n/**\n * Extension definition for dynamically adding to the module tree.\n * Used by plugins to inject controllers or entire modules.\n */\nexport interface ModuleExtension {\n /**\n * Module class to add. If provided, the module and all its\n * controllers/imports will be processed.\n */\n module?: ClassTypeWithInstance<NaviosModule>\n\n /**\n * Controllers to add directly without a wrapper module.\n * Will be registered under a synthetic module named after the plugin.\n */\n controllers?: ClassType[]\n\n /**\n * Name for the synthetic module when using controllers directly.\n * Required if `controllers` is provided without `module`.\n */\n moduleName?: string\n}\n\n@Injectable()\nexport class ModuleLoaderService {\n private logger = inject(Logger, {\n context: ModuleLoaderService.name,\n })\n protected container = inject(Container)\n private modulesMetadata: Map<string, ModuleMetadata> = new Map()\n private loadedModules: Map<string, any> = new Map()\n private initialized = false\n\n async loadModules(appModule: ClassTypeWithInstance<NaviosModule>) {\n if (this.initialized) {\n return\n }\n await this.traverseModules(appModule)\n this.initialized = true\n }\n\n /**\n * Extends the module tree with additional modules or controllers.\n *\n * This method is designed to be called by plugins during registration,\n * which happens after initial module loading but before route registration.\n *\n * @param extensions - Array of module extensions to add\n * @throws Error if not initialized (loadModules must be called first)\n *\n * @example\n * ```typescript\n * // In plugin registration\n * const moduleLoader = await context.container.get(ModuleLoaderService)\n * await moduleLoader.extendModules([{\n * controllers: [OpenApiJsonController, OpenApiYamlController],\n * moduleName: 'OpenApiBunModule',\n * }])\n * ```\n */\n async extendModules(extensions: ModuleExtension[]): Promise<void> {\n if (!this.initialized) {\n throw new Error(\n 'ModuleLoaderService must be initialized before extending. Call loadModules() first.',\n )\n }\n\n for (const extension of extensions) {\n if (extension.module) {\n // Process a full module with its imports and controllers\n await this.traverseModules(extension.module)\n } else if (extension.controllers && extension.moduleName) {\n // Create synthetic module metadata for loose controllers\n await this.registerControllers(\n extension.controllers,\n extension.moduleName,\n )\n } else if (extension.controllers) {\n throw new Error(\n 'moduleName is required when providing controllers without a module',\n )\n }\n }\n }\n\n /**\n * Registers controllers under a synthetic module.\n * Used when plugins want to add controllers without a full module class.\n */\n private async registerControllers(\n controllers: ClassType[],\n moduleName: string,\n ): Promise<void> {\n if (this.modulesMetadata.has(moduleName)) {\n // Merge controllers into existing module\n const existing = this.modulesMetadata.get(moduleName)!\n for (const controller of controllers) {\n existing.controllers.add(controller)\n }\n this.logger.debug(\n `Extended module ${moduleName} with ${controllers.length} controllers`,\n )\n } else {\n // Create new synthetic module metadata\n const metadata: ModuleMetadata = {\n controllers: new Set(controllers),\n imports: new Set(),\n guards: new Set(),\n overrides: new Set(),\n customAttributes: new Map(),\n customEntries: new Map(),\n }\n this.modulesMetadata.set(moduleName, metadata)\n\n this.logger.debug(\n `Created module ${moduleName} with ${controllers.length} controllers`,\n )\n }\n }\n\n private async traverseModules(\n module: ClassTypeWithInstance<NaviosModule>,\n parentMetadata?: ModuleMetadata,\n ) {\n const metadata = extractModuleMetadata(module)\n if (parentMetadata) {\n this.mergeMetadata(metadata, parentMetadata)\n }\n const moduleToken = getInjectableToken(module)\n const moduleName = moduleToken.id\n if (this.modulesMetadata.has(moduleName)) {\n return\n }\n try {\n this.modulesMetadata.set(moduleName, metadata)\n const imports = metadata.imports ?? new Set()\n const loadingPromises = Array.from(imports).map(async (importedModule) =>\n this.traverseModules(importedModule, metadata),\n )\n await Promise.all(loadingPromises)\n this.validateOverrides(metadata, moduleName)\n const instance = await this.container.get(module)\n if (instance.onModuleInit) {\n await instance.onModuleInit()\n }\n this.logger.debug(`Module ${moduleName} loaded`)\n this.loadedModules.set(moduleName, instance)\n } catch (error) {\n this.logger.error(`Error loading module ${moduleName}`, error)\n throw error\n }\n }\n\n private validateOverrides(\n metadata: ModuleMetadata,\n moduleName: string,\n ): void {\n if (!metadata.overrides || metadata.overrides.size === 0) {\n return\n }\n\n const registry = this.container.getRegistry()\n\n for (const overrideClass of metadata.overrides) {\n try {\n // Get the token for the override class\n const overrideToken = getInjectableToken(overrideClass)\n\n // Get all registrations for this token (sorted by priority, highest first)\n const allRegistrations = registry.getAll(overrideToken)\n\n if (allRegistrations.length === 0) {\n this.logger.warn(\n `[Navios] Override ${overrideClass.name} in module ${moduleName} is not registered. ` +\n `Make sure it has @Injectable decorator.`,\n )\n continue\n }\n\n // Check if the override class has the highest priority\n const highestPriorityRegistration = allRegistrations[0]\n if (highestPriorityRegistration.target !== overrideClass) {\n const overrideRegistration = allRegistrations.find(\n (r) => r.target === overrideClass,\n )\n\n if (!overrideRegistration) {\n this.logger.warn(\n `[Navios] Override ${overrideClass.name} in module ${moduleName} is registered ` +\n `but not found in registry for token ${overrideToken.toString()}.`,\n )\n } else {\n this.logger.warn(\n `[Navios] Override ${overrideClass.name} in module ${moduleName} is not active. ` +\n `Current active service: ${highestPriorityRegistration.target.name} ` +\n `(priority: ${highestPriorityRegistration.priority}). ` +\n `Override priority: ${overrideRegistration.priority}. ` +\n `Override needs higher priority to take effect.`,\n )\n }\n } else {\n this.logger.debug(\n `[Navios] Override ${overrideClass.name} in module ${moduleName} is active ` +\n `(priority: ${highestPriorityRegistration.priority})`,\n )\n }\n } catch (error) {\n this.logger.warn(\n `[Navios] Failed to validate override ${overrideClass.name} in module ${moduleName}: ${error}`,\n )\n }\n }\n }\n\n private mergeMetadata(\n metadata: ModuleMetadata,\n parentMetadata: ModuleMetadata,\n ): void {\n if (parentMetadata.guards) {\n for (const guard of parentMetadata.guards) {\n metadata.guards.add(guard)\n }\n }\n if (parentMetadata.customAttributes) {\n for (const [key, value] of parentMetadata.customAttributes) {\n if (metadata.customAttributes.has(key)) {\n continue\n }\n metadata.customAttributes.set(key, value)\n }\n }\n }\n getAllModules(): Map<string, ModuleMetadata> {\n return this.modulesMetadata\n }\n dispose() {\n this.modulesMetadata.clear()\n this.loadedModules.clear()\n this.initialized = false\n }\n}\n","import type { AbstractAdapterInterface } from '../interfaces/index.mjs'\n\n/**\n * Type guard to check if adapter implements a specific method.\n * Narrows the adapter type to include the method.\n *\n * @example\n * ```typescript\n * if (adapterSupports(adapter, 'getServer')) {\n * const server = adapter.getServer() // TypeScript knows this exists\n * }\n * ```\n */\nexport function adapterSupports<\n TAdapter extends AbstractAdapterInterface,\n TMethod extends string,\n>(\n adapter: TAdapter | null,\n method: TMethod,\n): adapter is TAdapter & Record<TMethod, (...args: unknown[]) => unknown> {\n return (\n adapter !== null &&\n typeof (adapter as Record<string, unknown>)[method] === 'function'\n )\n}\n\n/**\n * Asserts adapter supports a method, throws if not.\n * Narrows type after assertion.\n *\n * @example\n * ```typescript\n * assertAdapterSupports(adapter, 'enableCors')\n * adapter.enableCors(options) // TypeScript knows this exists\n * ```\n */\nexport function assertAdapterSupports<\n TAdapter extends AbstractAdapterInterface,\n TMethod extends string,\n>(\n adapter: TAdapter | null,\n method: TMethod,\n): asserts adapter is TAdapter & Record<TMethod, (...args: unknown[]) => unknown> {\n if (!adapterSupports(adapter, method)) {\n throw new Error(`Current adapter does not implement '${method}()'`)\n }\n}\n","import type { AnyInjectableType, InjectionToken } from '@navios/di'\n\nimport { Injectable } from '@navios/di'\n\nimport { AdapterToken } from './tokens/index.mjs'\n\nexport interface NaviosEnvironmentOptions {\n tokens?: Map<InjectionToken<any, undefined>, AnyInjectableType>\n}\n\n@Injectable()\nexport class NaviosEnvironment {\n private adapterConfigured = false\n private tokens = new Map<InjectionToken<any, undefined>, AnyInjectableType>()\n\n setupEnvironment(\n tokens: Map<InjectionToken<any, undefined>, AnyInjectableType>,\n ) {\n const hasAdapterToken = tokens.has(AdapterToken)\n if (hasAdapterToken && this.adapterConfigured) {\n throw new Error(\n 'Adapter already configured. Only one adapter per application.',\n )\n }\n\n for (const [token, value] of tokens) {\n this.tokens.set(token, value)\n }\n\n if (hasAdapterToken) {\n this.adapterConfigured = true\n }\n }\n\n getToken(token: InjectionToken<any, undefined>) {\n return this.tokens.get(token)\n }\n\n hasAdapterSetup() {\n return this.adapterConfigured\n }\n}\n","import type {\n ClassType,\n ClassTypeWithArgument,\n ClassTypeWithInstance,\n InjectionTokenSchemaType,\n Registry,\n} from '@navios/di'\nimport type { z } from 'zod/v4'\n\nimport {\n BoundInjectionToken,\n Container,\n FactoryInjectionToken,\n inject,\n Injectable,\n InjectionToken,\n} from '@navios/di'\n\nimport type {\n AbstractAdapterInterface,\n AdapterEnvironment,\n DefaultAdapterEnvironment,\n HttpAdapterEnvironment,\n NaviosModule,\n PluginContext,\n PluginDefinition,\n} from './interfaces/index.mjs'\nimport type { LoggerService, LogLevel } from './logger/index.mjs'\nimport type { NaviosEnvironmentOptions } from './navios.environment.mjs'\n\nimport { Logger } from './logger/index.mjs'\nimport { NaviosEnvironment } from './navios.environment.mjs'\nimport { ModuleLoaderService } from './services/index.mjs'\nimport { AdapterToken } from './tokens/index.mjs'\nimport { assertAdapterSupports } from './utils/index.mjs'\n\n/**\n * Options for configuring the Navios application context.\n * These options control the application configuration.\n */\nexport interface NaviosApplicationOptions {\n /**\n * Specifies the logger to use. Pass `false` to turn off logging.\n *\n * - `LoggerService` instance: Use a custom logger implementation\n * - `LogLevel[]`: Enable specific log levels (e.g., ['error', 'warn', 'log'])\n * - `false`: Disable logging completely\n */\n logger?: LoggerService | LogLevel[] | false\n\n /**\n * Specifies a custom registry to use. Useful for testing.\n * If not provided, a new Registry will be created.\n */\n registry?: Registry\n\n /**\n * Specifies a custom container to use. Useful for testing.\n * If not provided, a new Container will be created.\n */\n container?: Container\n\n /**\n * Adapter environment(s) to use for the application.\n * Can be a single adapter or an array of adapters.\n *\n * @example\n * ```typescript\n * adapter: defineFastifyEnvironment()\n * // or\n * adapter: [defineFastifyEnvironment()]\n * ```\n */\n adapter: NaviosEnvironmentOptions | NaviosEnvironmentOptions[]\n\n /**\n * Whether to validate response schemas.\n * When `false`, response schema validation is skipped for better performance.\n * @default true\n */\n validateResponses?: boolean\n\n /**\n * Whether to enable request ID propagation via AsyncLocalStorage.\n * When `true`, request IDs are available via `getRequestId()` throughout the request.\n * @default false\n */\n enableRequestId?: boolean\n}\n\n/**\n * Main application class for Navios.\n *\n * This class represents a Navios application instance and provides methods\n * for initializing, configuring, and managing the application lifecycle.\n *\n * @example\n * ```typescript\n * const app = await NaviosFactory.create(AppModule, {\n * adapter: defineFastifyEnvironment(),\n * })\n *\n * app.setGlobalPrefix('/api')\n * app.enableCors({ origin: ['http://localhost:3000'] })\n * await app.init()\n * await app.listen({ port: 3000, host: '0.0.0.0' })\n * ```\n */\n@Injectable()\nexport class NaviosApplication<\n Environment extends AdapterEnvironment = DefaultAdapterEnvironment,\n> {\n private environment = inject(NaviosEnvironment)\n private moduleLoader = inject(ModuleLoaderService)\n private adapter: Environment['adapter'] | null = null\n private logger = inject(Logger, {\n context: NaviosApplication.name,\n })\n protected container = inject(Container)\n\n private appModule: ClassTypeWithInstance<NaviosModule> | null = null\n private options: NaviosApplicationOptions = {\n adapter: [],\n }\n private plugins: PluginDefinition<any, any>[] = []\n\n /**\n * Indicates whether the application has been initialized.\n * Set to `true` after `init()` completes successfully.\n */\n isInitialized = false\n\n /**\n * Sets up the application with the provided module and options.\n * This is called automatically by NaviosFactory.create().\n *\n * @param appModule - The root application module\n * @param options - Application configuration options\n * @internal\n */\n async setup(\n appModule: ClassTypeWithInstance<NaviosModule>,\n options: NaviosApplicationOptions = {\n adapter: [],\n },\n ) {\n this.appModule = appModule\n this.options = options\n if (this.environment.hasAdapterSetup()) {\n this.adapter = (await this.container.get(\n AdapterToken,\n )) as Environment['adapter']\n }\n }\n\n /**\n * Gets the dependency injection container used by this application.\n *\n * @returns The Container instance\n */\n getContainer() {\n return this.container\n }\n\n /**\n * Returns the current adapter instance.\n *\n * @returns The adapter instance\n * @throws Error if adapter is not initialized\n */\n getAdapter(): Environment['adapter'] {\n if (!this.adapter) {\n throw new Error('Adapter not initialized')\n }\n return this.adapter\n }\n\n /**\n * Registers a plugin to be initialized after modules are loaded.\n *\n * Plugins are initialized in the order they are registered,\n * after all modules are loaded but before the server starts listening.\n *\n * @param definition - Plugin definition with options\n * @returns this for method chaining\n *\n * @example\n * ```typescript\n * import { defineOpenApiPlugin } from '@navios/openapi-fastify'\n *\n * app.usePlugin(defineOpenApiPlugin({\n * info: { title: 'My API', version: '1.0.0' },\n * }))\n * ```\n */\n usePlugin<TOptions, TAdapter extends AbstractAdapterInterface>(\n definition: PluginDefinition<TOptions, TAdapter>,\n ): this {\n this.plugins.push(definition)\n return this\n }\n\n /**\n * Initializes the application.\n *\n * This method:\n * - Loads all modules and their dependencies\n * - Sets up the adapter if one is configured\n * - Calls onModuleInit hooks on all modules\n * - Initializes registered plugins\n * - Marks the application as initialized\n *\n * Must be called before `listen()`.\n *\n * @throws Error if app module is not set\n *\n * @example\n * ```typescript\n * const app = await NaviosFactory.create(AppModule, {\n * adapter: defineFastifyEnvironment(),\n * })\n * await app.init()\n * await app.listen({ port: 3000 })\n * ```\n */\n async init() {\n if (!this.appModule) {\n throw new Error('App module is not set. Call setAppModule() first.')\n }\n await this.moduleLoader.loadModules(this.appModule)\n\n if (this.environment.hasAdapterSetup() && this.adapter) {\n await this.adapter.setupAdapter(this.options)\n }\n\n await this.initPlugins()\n await this.initModules()\n\n if (this.adapter) {\n await this.adapter.ready()\n }\n\n this.isInitialized = true\n this.logger.debug('Navios application initialized')\n }\n\n private async initModules() {\n const modules = this.moduleLoader.getAllModules()\n if (this.adapter) {\n await this.adapter.onModulesInit(modules)\n }\n }\n\n private async initPlugins() {\n if (this.plugins.length === 0) return\n\n if (!this.adapter) {\n throw new Error('Cannot initialize plugins without an adapter')\n }\n\n const context: PluginContext = {\n modules: this.moduleLoader.getAllModules(),\n adapter: this.adapter,\n container: this.container,\n moduleLoader: this.moduleLoader,\n }\n\n for (const { plugin, options } of this.plugins) {\n this.logger.debug(`Initializing plugin: ${plugin.name}`)\n await plugin.register(context, options)\n }\n }\n\n /**\n * Gets a service instance from the dependency injection container.\n *\n * This is a shorthand for `app.getContainer().get(token)`.\n *\n * @param token - The injection token or class to resolve\n * @returns Promise resolving to the service instance\n *\n * @example\n * ```typescript\n * const userService = await app.get(UserService)\n * const config = await app.get(ConfigToken)\n * ```\n */\n get<T extends ClassType>(token: T): Promise<InstanceType<T>>\n get<T extends ClassTypeWithArgument<R>, R>(\n token: T,\n args: R,\n ): Promise<InstanceType<T>>\n get<T, S extends InjectionTokenSchemaType>(\n token: InjectionToken<T, S>,\n args: z.input<S>,\n ): Promise<T>\n get<T, S extends InjectionTokenSchemaType, R extends boolean>(\n token: InjectionToken<T, S, R>,\n ): Promise<T>\n get<T>(token: InjectionToken<T, undefined>): Promise<T>\n get<T>(token: BoundInjectionToken<T, any>): Promise<T>\n get<T>(token: FactoryInjectionToken<T, any>): Promise<T>\n async get(\n token:\n | ClassType\n | InjectionToken<any>\n | BoundInjectionToken<any, any>\n | FactoryInjectionToken<any, any>,\n args?: unknown,\n ): Promise<any> {\n return this.container.get(token as any, args)\n }\n\n /**\n * Configures the adapter with additional options before initialization.\n *\n * This method allows setting adapter-specific configuration options\n * before the adapter is initialized. Must be called before `init()`.\n *\n * @param options - Adapter-specific configuration options\n * @returns this for method chaining\n * @throws Error if called after init() or if adapter doesn't support configure\n *\n * @example\n * ```typescript\n * // With Fastify adapter\n * app.configure({ trustProxy: true, logger: true })\n *\n * // With Bun adapter\n * app.configure({ development: true })\n * ```\n */\n configure(options: Partial<Environment['options']>): this {\n if (this.isInitialized) {\n throw new Error('configure() must be called before init()')\n }\n assertAdapterSupports(this.adapter, 'configure')\n this.adapter.configure(options)\n return this\n }\n\n /**\n * Enables CORS (Cross-Origin Resource Sharing) for the application.\n *\n * @param options - CORS configuration options (adapter-specific)\n * @throws Error if adapter doesn't support enableCors\n *\n * @example\n * ```typescript\n * app.enableCors({\n * origin: ['http://localhost:3000', 'https://example.com'],\n * methods: ['GET', 'POST', 'PUT', 'DELETE'],\n * credentials: true,\n * })\n * ```\n */\n enableCors(\n options: Environment extends HttpAdapterEnvironment\n ? Environment['corsOptions']\n : never,\n ): void {\n assertAdapterSupports(this.adapter, 'enableCors')\n this.adapter.enableCors(options)\n }\n\n /**\n * Enables multipart/form-data support for file uploads.\n *\n * @param options - Multipart configuration options (adapter-specific)\n * @throws Error if adapter doesn't support enableMultipart\n *\n * @example\n * ```typescript\n * app.enableMultipart({\n * limits: {\n * fileSize: 1024 * 1024 * 10, // 10MB\n * },\n * })\n * ```\n */\n enableMultipart(\n options: Environment extends HttpAdapterEnvironment\n ? Environment['multipartOptions']\n : never,\n ): void {\n assertAdapterSupports(this.adapter, 'enableMultipart')\n this.adapter.enableMultipart(options)\n }\n\n /**\n * Sets a global prefix for all routes.\n *\n * @param prefix - The prefix to prepend to all route URLs (e.g., '/api')\n * @throws Error if adapter doesn't support setGlobalPrefix\n *\n * @example\n * ```typescript\n * app.setGlobalPrefix('/api/v1')\n * // All routes will be prefixed with /api/v1\n * ```\n */\n setGlobalPrefix(prefix: string): void {\n assertAdapterSupports(this.adapter, 'setGlobalPrefix')\n this.adapter.setGlobalPrefix(prefix)\n }\n\n /**\n * Gets the underlying HTTP server instance.\n *\n * The type of the returned server depends on the adapter used:\n * - Fastify adapter: Returns FastifyInstance\n * - Bun adapter: Returns Bun.Server\n *\n * @returns The HTTP server instance\n * @throws Error if adapter doesn't support getServer\n *\n * @example\n * ```typescript\n * const server = app.getServer()\n * // Use adapter-specific server methods\n * ```\n */\n getServer(): Environment extends HttpAdapterEnvironment\n ? Environment['server']\n : never {\n assertAdapterSupports(this.adapter, 'getServer')\n return this.adapter.getServer() as Environment extends HttpAdapterEnvironment\n ? Environment['server']\n : never\n }\n\n /**\n * Starts the HTTP server and begins listening for requests.\n *\n * @param options - Listen options (port, host, etc.)\n * @throws Error if adapter doesn't support listen\n *\n * @example\n * ```typescript\n * await app.listen({ port: 3000, host: '0.0.0.0' })\n * ```\n */\n async listen(\n options: Environment extends HttpAdapterEnvironment\n ? Environment['listenOptions']\n : never,\n ): Promise<string> {\n assertAdapterSupports(this.adapter, 'listen')\n return this.adapter.listen(options) as Promise<string>\n }\n\n /**\n * Disposes of application resources.\n *\n * Cleans up the adapter and module loader.\n * This method is called automatically by `close()`.\n */\n async dispose() {\n if (this.adapter) {\n await this.adapter.dispose()\n }\n if (this.moduleLoader) {\n this.moduleLoader.dispose()\n }\n }\n\n /**\n * Closes the application and cleans up all resources.\n *\n * This is an alias for `dispose()`.\n *\n * @example\n * ```typescript\n * // Graceful shutdown\n * process.on('SIGTERM', async () => {\n * await app.close()\n * process.exit(0)\n * })\n * ```\n */\n async close() {\n await this.dispose()\n }\n}\n","import type {\n AnyInjectableType,\n ClassTypeWithInstance,\n InjectionToken,\n} from '@navios/di'\n\nimport { Container } from '@navios/di'\n\nimport type {\n AdapterEnvironment,\n DefaultAdapterEnvironment,\n NaviosModule,\n} from './interfaces/index.mjs'\nimport type { NaviosApplicationOptions } from './navios.application.mjs'\n\nimport { ConsoleLogger, isNil, LoggerOutput } from './logger/index.mjs'\nimport { NaviosApplication } from './navios.application.mjs'\nimport { NaviosEnvironment } from './navios.environment.mjs'\nimport { setRequestIdEnabled } from './stores/index.mjs'\nimport { NaviosOptionsToken } from './tokens/index.mjs'\n\n/**\n * Factory class for creating and configuring Navios applications.\n *\n * This is the main entry point for bootstrapping a Navios application.\n * It handles dependency injection container setup, adapter registration,\n * and logger configuration.\n *\n * @example\n * ```typescript\n * import { NaviosFactory } from '@navios/core'\n * import { defineFastifyEnvironment } from '@navios/adapter-fastify'\n *\n * const app = await NaviosFactory.create(AppModule, {\n * adapter: defineFastifyEnvironment(),\n * logger: ['log', 'error', 'warn'],\n * })\n *\n * await app.init()\n * await app.listen({ port: 3000 })\n * ```\n */\nexport class NaviosFactory {\n /**\n * Creates a new Navios application instance.\n *\n * This method sets up the dependency injection container, registers the adapter,\n * configures logging, and initializes the application with the provided module.\n *\n * @typeParam Environment - Adapter environment interface for type-safe access\n * to adapter-specific features. When specified, methods like `getServer()`,\n * `enableCors()`, `listen()`, and `configure()` will have proper types.\n *\n * @param appModule - The root application module class decorated with @Module()\n * @param options - Configuration options for the application\n * @param options.adapter - Adapter environment (required for server functionality)\n * @param options.logger - Logger configuration. Can be:\n * - A LoggerService instance for custom logging\n * - An array of LogLevel strings to enable specific log levels\n * - `false` to disable logging\n * @param options.container - Optional custom dependency injection container (useful for testing)\n * @returns A configured NaviosApplication instance ready to be initialized\n *\n * @example\n * ```typescript\n * // Basic setup with Fastify adapter\n * const app = await NaviosFactory.create(AppModule, {\n * adapter: defineFastifyEnvironment(),\n * })\n *\n * // Type-safe setup with Fastify environment\n * import { FastifyEnvironment } from '@navios/adapter-fastify'\n *\n * const app = await NaviosFactory.create<FastifyEnvironment>(AppModule, {\n * adapter: defineFastifyEnvironment(),\n * })\n * app.configure({ trustProxy: true })\n * const server = app.getServer() // FastifyInstance\n *\n * // With custom logger configuration\n * const app = await NaviosFactory.create(AppModule, {\n * adapter: defineFastifyEnvironment(),\n * logger: ['error', 'warn', 'log'],\n * })\n *\n * // With custom container for testing\n * const container = new Container()\n * const app = await NaviosFactory.create(AppModule, {\n * adapter: defineFastifyEnvironment(),\n * container,\n * })\n * ```\n */\n static async create<\n Environment extends AdapterEnvironment = DefaultAdapterEnvironment,\n >(\n appModule: ClassTypeWithInstance<NaviosModule>,\n options: NaviosApplicationOptions = {\n adapter: [],\n },\n ): Promise<NaviosApplication<Environment>> {\n const container = options.container ?? new Container(options.registry)\n\n // Set request ID flag early, before any adapters are registered\n if (options.enableRequestId === true) {\n setRequestIdEnabled(true)\n }\n\n // Store options in container for DI access by adapters\n container.addInstance(NaviosOptionsToken, options)\n\n await this.registerLoggerConfiguration(container, options)\n const adapters = Array.isArray(options.adapter)\n ? options.adapter\n : [options.adapter]\n for (const adapter of adapters) {\n await this.registerEnvironment(container, adapter)\n }\n const app = (await container.get(\n NaviosApplication,\n )) as NaviosApplication<Environment>\n await app.setup(appModule, options)\n return app\n }\n\n private static async registerEnvironment(\n container: Container,\n environment: {\n tokens?: Map<InjectionToken<any, undefined>, AnyInjectableType>\n } = {},\n ) {\n const naviosEnvironment = await container.get(NaviosEnvironment)\n const { tokens } = environment\n if (tokens) {\n naviosEnvironment.setupEnvironment(tokens)\n }\n }\n\n private static async registerLoggerConfiguration(\n container: Container,\n options: NaviosApplicationOptions,\n ) {\n const { logger } = options\n if (Array.isArray(logger) || isNil(logger) || options.enableRequestId) {\n const loggerInstance = (await container.get(\n LoggerOutput,\n )) as ConsoleLogger\n loggerInstance?.setup({\n logLevels: Array.isArray(logger) ? logger : undefined,\n requestId: options.enableRequestId ?? false,\n })\n return\n }\n if ((logger as boolean) !== true && !isNil(logger)) {\n container.addInstance(LoggerOutput, logger)\n }\n }\n}\n"],"mappings":"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"}
|
package/lib/testing/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const
|
|
2
|
-
require('../
|
|
1
|
+
const require_navios_factory = require('../navios.factory-BanZIvtR.cjs');
|
|
2
|
+
require('../tokens-BuXXB01L.cjs');
|
|
3
3
|
let _navios_di_testing = require("@navios/di/testing");
|
|
4
4
|
|
|
5
5
|
//#region src/testing/testing-module.mts
|
|
@@ -60,7 +60,7 @@ let _navios_di_testing = require("@navios/di/testing");
|
|
|
60
60
|
*
|
|
61
61
|
* @returns this for chaining
|
|
62
62
|
*/ async compile() {
|
|
63
|
-
if (!this.app) this.app = await
|
|
63
|
+
if (!this.app) this.app = await require_navios_factory.NaviosFactory.create(this.appModule, {
|
|
64
64
|
...this.options,
|
|
65
65
|
container: this.container
|
|
66
66
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["TestContainer","NaviosFactory","TestingModule","app","scopedContainer","requestId","Date","now","Math","random","toString","slice","appModule","container","options","create","adapter","parentRegistry","registry","overrides","override","useValue","undefined","bind","token","toValue","useClass","toClass","compile","init","beginRequest","testingModule","getApp","Error","getContainer","getScopedContainer","overrideProvider","value","target","get","close","endRequest","dispose","expectResolved","expectNotResolved","expectSingleton","expectTransient","expectRequestScoped","expectCalled","method","expectCalledWith","expectedArgs","expectCallCount","count","recordMethodCall","args","result","error","getMethodCalls","getDependencyGraph","getSimplifiedDependencyGraph","createTestingModule","UnitTestContainer","UnitTestingModule","container","create","options","providers","allowUnregistered","logger","getContainer","get","token","close","clear","enableAutoMocking","disableAutoMocking","expectResolved","expectNotResolved","expectAutoMocked","expectNotAutoMocked","expectCalled","method","expectNotCalled","expectCalledWith","expectedArgs","expectCallCount","count","getMethodCalls","getServiceStats","clearMethodCalls","getRegisteredTokenIds","getAutoMockedTokenIds","expectInitialized","expectDestroyed","expectNotDestroyed","recordLifecycleEvent","event","instanceName"],"sources":["../../src/testing/testing-module.mts","../../src/testing/unit-testing-module.mts"],"sourcesContent":["import type {\n ClassType,\n ClassTypeWithInstance,\n InjectionToken,\n ScopedContainer,\n} from '@navios/di'\n\nimport { TestContainer } from '@navios/di/testing'\n\nimport type { NaviosModule } from '../interfaces/index.mjs'\nimport type { NaviosApplicationOptions } from '../navios.application.mjs'\n\nimport { NaviosApplication } from '../navios.application.mjs'\nimport { NaviosFactory } from '../navios.factory.mjs'\n\n/**\n * Configuration for overriding a provider in the testing module.\n *\n * @typeParam T - The type of the provider being overridden\n */\nexport interface TestingModuleOverride<T = any> {\n /**\n * The injection token or class to override.\n */\n token: ClassType | InjectionToken<T, any>\n /**\n * Value to use instead of the original provider.\n */\n useValue?: T\n /**\n * Class to use instead of the original provider.\n */\n useClass?: ClassType\n}\n\n/**\n * Options for creating a testing module.\n *\n * Extends NaviosApplicationOptions but excludes the container option,\n * as TestingModule manages its own TestContainer.\n */\nexport interface TestingModuleOptions extends Omit<\n NaviosApplicationOptions,\n 'container'\n> {\n /**\n * Initial provider overrides to apply when creating the testing module.\n *\n * You can also use `overrideProvider()` method for a fluent API.\n */\n overrides?: TestingModuleOverride[]\n /**\n * Container to use for the testing module.\n * If not provided, a new TestContainer will be created.\n */\n container?: TestContainer\n}\n\n/**\n * A testing-optimized wrapper around NaviosApplication.\n * Provides utilities for setting up test environments with mock dependencies.\n *\n * When `init()` is called, a request scope is automatically started.\n * This means `get()` calls will resolve request-scoped services correctly,\n * simulating a real HTTP request context.\n *\n * @example\n * ```typescript\n * const module = await TestingModule.create(AppModule)\n * .overrideProvider(DatabaseService)\n * .useValue(mockDatabase)\n * .init()\n *\n * const userService = await module.get(UserService)\n * // ... run tests ...\n *\n * await module.close()\n * ```\n */\nexport class TestingModule {\n private app: NaviosApplication | null = null\n private scopedContainer: ScopedContainer | null = null\n private requestId = `test-request-${Date.now()}-${Math.random().toString(36).slice(2)}`\n\n private constructor(\n private readonly appModule: ClassTypeWithInstance<NaviosModule>,\n private readonly container: TestContainer,\n private readonly options: TestingModuleOptions,\n ) {}\n\n /**\n * Creates a new TestingModule for the given app module.\n * This is the main entry point for setting up integration tests.\n *\n * @example\n * ```typescript\n * const module = await TestingModule.create(AppModule)\n * .overrideProvider(DatabaseService)\n * .useValue(mockDatabase)\n * .init()\n * ```\n */\n static create(\n appModule: ClassTypeWithInstance<NaviosModule>,\n options: TestingModuleOptions = { adapter: [] },\n ): TestingModule {\n const container =\n options.container ??\n new TestContainer({\n parentRegistry: options.registry,\n })\n\n // Apply initial overrides if provided\n if (options.overrides) {\n for (const override of options.overrides) {\n if (override.useValue !== undefined) {\n container.bind(override.token as any).toValue(override.useValue)\n } else if (override.useClass) {\n container.bind(override.token as any).toClass(override.useClass)\n }\n }\n }\n\n return new TestingModule(appModule, container, options)\n }\n\n /**\n * Compiles the testing module without initializing it.\n * Call this if you need to access the app before initialization.\n *\n * @returns this for chaining\n */\n async compile(): Promise<this> {\n if (!this.app) {\n this.app = await NaviosFactory.create(this.appModule, {\n ...this.options,\n container: this.container,\n })\n }\n return this\n }\n\n /**\n * Initializes the application and starts a request scope.\n *\n * This is equivalent to calling `compile()` followed by `app.init()`,\n * plus starting a request context for proper request-scoped service resolution.\n *\n * @returns this for chaining\n */\n async init(): Promise<this> {\n if (!this.app) {\n await this.compile()\n }\n await this.app!.init()\n\n // Begin a request scope so get() can resolve request-scoped services\n this.scopedContainer = this.container.beginRequest(this.requestId, {\n testingModule: true,\n })\n\n return this\n }\n\n /**\n * Gets the compiled application.\n *\n * @throws Error if the module has not been compiled yet\n */\n getApp(): NaviosApplication {\n if (!this.app) {\n throw new Error(\n 'TestingModule not compiled. Call compile() or init() first.',\n )\n }\n return this.app\n }\n\n /**\n * Gets the underlying TestContainer for direct manipulation.\n */\n getContainer(): TestContainer {\n return this.container\n }\n\n /**\n * Gets the scoped container for the current test request.\n * Only available after calling `init()`.\n *\n * @throws Error if init() has not been called\n */\n getScopedContainer(): ScopedContainer {\n if (!this.scopedContainer) {\n throw new Error('No scoped container available. Call init() first.')\n }\n return this.scopedContainer\n }\n\n /**\n * Override a provider with a mock value or class.\n * Must be called before `compile()` or `init()`.\n */\n overrideProvider<T>(token: ClassType | InjectionToken<T, any>): {\n useValue: (value: T) => TestingModule\n useClass: (target: ClassType) => TestingModule\n } {\n return {\n useValue: (value: T) => {\n this.container.bind(token as any).toValue(value)\n return this\n },\n useClass: (target: ClassType) => {\n this.container.bind(token as any).toClass(target)\n return this\n },\n }\n }\n\n /**\n * Gets an instance from the container.\n *\n * If `init()` has been called, this uses the scoped container\n * which properly resolves request-scoped services.\n *\n * If only `compile()` was called, this uses the root container\n * and request-scoped services will throw.\n */\n async get<T>(\n token: ClassTypeWithInstance<T> | InjectionToken<T, any>,\n ): Promise<T> {\n // Use scoped container if available (after init)\n if (this.scopedContainer) {\n return this.scopedContainer.get(token as any)\n }\n // Fall back to root container (after compile only)\n return this.container.get(token as any)\n }\n\n /**\n * Disposes the testing module and cleans up all resources.\n *\n * This will:\n * 1. End the request scope (if started)\n * 2. Close the application (if initialized)\n * 3. Dispose the container\n */\n async close(): Promise<void> {\n // End the request scope first\n if (this.scopedContainer) {\n await this.scopedContainer.endRequest()\n this.scopedContainer = null\n }\n\n // Close the app\n if (this.app) {\n await this.app.close()\n this.app = null\n }\n\n // Dispose the container\n await this.container.dispose()\n }\n\n // ===========================================================================\n // ASSERTION HELPERS (delegated to TestContainer)\n // ===========================================================================\n\n /**\n * Asserts that a service has been resolved at least once.\n */\n expectResolved(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectResolved(token)\n }\n\n /**\n * Asserts that a service has NOT been resolved.\n */\n expectNotResolved(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectNotResolved(token)\n }\n\n /**\n * Asserts that a service is registered as singleton scope.\n */\n expectSingleton(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectSingleton(token)\n }\n\n /**\n * Asserts that a service is registered as transient scope.\n */\n expectTransient(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectTransient(token)\n }\n\n /**\n * Asserts that a service is registered as request scope.\n */\n expectRequestScoped(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectRequestScoped(token)\n }\n\n /**\n * Asserts that a method was called on a service.\n * Note: You must use `recordMethodCall()` in your mocks for this to work.\n */\n expectCalled(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n ): void {\n this.container.expectCalled(token, method)\n }\n\n /**\n * Asserts that a method was called with specific arguments.\n * Note: You must use `recordMethodCall()` in your mocks for this to work.\n */\n expectCalledWith(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n expectedArgs: unknown[],\n ): void {\n this.container.expectCalledWith(token, method, expectedArgs)\n }\n\n /**\n * Asserts that a method was called a specific number of times.\n * Note: You must use `recordMethodCall()` in your mocks for this to work.\n */\n expectCallCount(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n count: number,\n ): void {\n this.container.expectCallCount(token, method, count)\n }\n\n /**\n * Records a method call for tracking.\n * Call this from your mock implementations to enable call assertions.\n */\n recordMethodCall(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n args: unknown[],\n result?: unknown,\n error?: Error,\n ): void {\n this.container.recordMethodCall(token, method, args, result, error)\n }\n\n /**\n * Gets all recorded method calls for a service.\n */\n getMethodCalls(token: ClassType | InjectionToken<any, any>) {\n return this.container.getMethodCalls(token)\n }\n\n /**\n * Gets the dependency graph for debugging or snapshot testing.\n */\n getDependencyGraph() {\n return this.container.getDependencyGraph()\n }\n\n /**\n * Gets a simplified dependency graph showing only token relationships.\n */\n getSimplifiedDependencyGraph() {\n return this.container.getSimplifiedDependencyGraph()\n }\n}\n\n/**\n * Creates a testing module for the given app module.\n *\n * @deprecated Use `TestingModule.create()` instead.\n *\n * @example\n * ```typescript\n * // Old way (deprecated)\n * const module = createTestingModule(AppModule)\n *\n * // New way\n * const module = TestingModule.create(AppModule)\n * ```\n */\nexport function createTestingModule(\n appModule: ClassTypeWithInstance<NaviosModule>,\n options: TestingModuleOptions = { adapter: [] },\n): TestingModule {\n return TestingModule.create(appModule, options)\n}\n","import type {\n ClassType,\n ClassTypeWithInstance,\n InjectionToken,\n} from '@navios/di'\nimport type {\n MethodCallRecord,\n MockServiceStats,\n ProviderConfig,\n} from '@navios/di/testing'\n\nimport { UnitTestContainer } from '@navios/di/testing'\n\n/**\n * Options for creating a UnitTestingModule.\n */\nexport interface UnitTestingModuleOptions {\n /**\n * List of providers to register. Only these services can be resolved.\n */\n providers: ProviderConfig[]\n\n /**\n * If true, unregistered dependencies will be auto-mocked instead of throwing.\n * Default: false (throws on unregistered dependencies)\n */\n allowUnregistered?: boolean\n\n /**\n * Logger for debugging.\n */\n logger?: Console | null\n\n /**\n * Container to use for the testing module.\n * If not provided, a new UnitTestContainer will be created.\n */\n container?: UnitTestContainer\n}\n\n/**\n * A lightweight testing module for isolated unit tests.\n *\n * Unlike `TestingModule`, this does NOT load Navios modules or create an application.\n * It uses `UnitTestContainer` which:\n * - Only allows explicitly provided services\n * - Automatically tracks all method calls via proxies\n * - Can auto-mock unregistered dependencies\n *\n * This is ideal for testing services in isolation without the overhead\n * of full module loading.\n *\n * @example\n * ```typescript\n * const module = UnitTestingModule.create({\n * providers: [\n * { token: UserService, useClass: UserService },\n * { token: DatabaseService, useValue: mockDatabase },\n * ],\n * })\n *\n * const userService = await module.get(UserService)\n * await userService.findUser('123')\n *\n * // Method calls are automatically tracked\n * module.expectCalled(UserService, 'findUser')\n * module.expectCalledWith(UserService, 'findUser', ['123'])\n *\n * await module.close()\n * ```\n */\nexport class UnitTestingModule {\n private constructor(private readonly container: UnitTestContainer) {}\n\n /**\n * Creates a new UnitTestingModule with the given providers.\n *\n * @example\n * ```typescript\n * const module = UnitTestingModule.create({\n * providers: [\n * { token: UserService, useClass: UserService },\n * { token: ConfigToken, useValue: { apiUrl: 'test' } },\n * ],\n * })\n * ```\n */\n static create(options: UnitTestingModuleOptions): UnitTestingModule {\n const container =\n options.container ??\n new UnitTestContainer({\n providers: options.providers,\n allowUnregistered: options.allowUnregistered,\n logger: options.logger,\n })\n\n return new UnitTestingModule(container)\n }\n\n /**\n * Gets the underlying UnitTestContainer for direct manipulation.\n */\n getContainer(): UnitTestContainer {\n return this.container\n }\n\n /**\n * Gets an instance from the container.\n *\n * All resolved instances are wrapped in tracking proxies,\n * so method calls are automatically recorded.\n *\n * @throws Error if the token is not in the providers list\n * and `allowUnregistered` is false\n */\n async get<T>(\n token: ClassTypeWithInstance<T> | InjectionToken<T, any>,\n ): Promise<T> {\n return this.container.get(token as any)\n }\n\n /**\n * Disposes the module and cleans up all resources.\n */\n async close(): Promise<void> {\n await this.container.clear()\n }\n\n /**\n * Enables auto-mocking for unregistered dependencies.\n * Unregistered services will return a proxy that throws on method access.\n */\n enableAutoMocking(): this {\n this.container.enableAutoMocking()\n return this\n }\n\n /**\n * Disables auto-mocking (strict mode).\n * Unregistered dependencies will throw immediately on resolution.\n */\n disableAutoMocking(): this {\n this.container.disableAutoMocking()\n return this\n }\n\n // ===========================================================================\n // ASSERTION HELPERS (delegated to UnitTestContainer)\n // ===========================================================================\n\n /**\n * Asserts that a service has been resolved at least once.\n */\n expectResolved(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectResolved(token)\n }\n\n /**\n * Asserts that a service has NOT been resolved.\n */\n expectNotResolved(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectNotResolved(token)\n }\n\n /**\n * Asserts that a service was auto-mocked (not in providers list).\n */\n expectAutoMocked(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectAutoMocked(token)\n }\n\n /**\n * Asserts that a service was NOT auto-mocked (is in providers list).\n */\n expectNotAutoMocked(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectNotAutoMocked(token)\n }\n\n /**\n * Asserts that a method was called on a service.\n * Method calls are automatically tracked via proxy.\n */\n expectCalled(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n ): void {\n this.container.expectCalled(token, method)\n }\n\n /**\n * Asserts that a method was NOT called on a service.\n */\n expectNotCalled(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n ): void {\n this.container.expectNotCalled(token, method)\n }\n\n /**\n * Asserts that a method was called with specific arguments.\n */\n expectCalledWith(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n expectedArgs: unknown[],\n ): void {\n this.container.expectCalledWith(token, method, expectedArgs)\n }\n\n /**\n * Asserts that a method was called a specific number of times.\n */\n expectCallCount(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n count: number,\n ): void {\n this.container.expectCallCount(token, method, count)\n }\n\n /**\n * Gets all recorded method calls for a service.\n */\n getMethodCalls(\n token: ClassType | InjectionToken<any, any>,\n ): MethodCallRecord[] {\n return this.container.getMethodCalls(token)\n }\n\n /**\n * Gets statistics about a service (instance count, method calls, lifecycle events).\n */\n getServiceStats(\n token: ClassType | InjectionToken<any, any>,\n ): MockServiceStats {\n return this.container.getServiceStats(token)\n }\n\n /**\n * Clears all recorded method calls.\n * Useful for resetting state between test assertions.\n */\n clearMethodCalls(): void {\n this.container.clearMethodCalls()\n }\n\n /**\n * Gets list of all registered provider token IDs.\n */\n getRegisteredTokenIds(): ReadonlySet<string> {\n return this.container.getRegisteredTokenIds()\n }\n\n /**\n * Gets list of all auto-mocked token IDs.\n */\n getAutoMockedTokenIds(): ReadonlySet<string> {\n return this.container.getAutoMockedTokenIds()\n }\n\n // ===========================================================================\n // LIFECYCLE ASSERTIONS\n // ===========================================================================\n\n /**\n * Asserts that a service's onServiceInit was called.\n */\n expectInitialized(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectInitialized(token)\n }\n\n /**\n * Asserts that a service's onServiceDestroy was called.\n */\n expectDestroyed(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectDestroyed(token)\n }\n\n /**\n * Asserts that a service has NOT been destroyed.\n */\n expectNotDestroyed(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectNotDestroyed(token)\n }\n\n /**\n * Records a lifecycle event for tracking.\n * Call this from your mock implementations if needed.\n */\n recordLifecycleEvent(\n token: ClassType | InjectionToken<any, any>,\n event: 'created' | 'initialized' | 'destroyed',\n instanceName: string,\n ): void {\n this.container.recordLifecycleEvent(token, event, instanceName)\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["TestContainer","NaviosFactory","TestingModule","app","scopedContainer","requestId","Date","now","Math","random","toString","slice","appModule","container","options","create","adapter","parentRegistry","registry","overrides","override","useValue","undefined","bind","token","toValue","useClass","toClass","compile","init","beginRequest","testingModule","getApp","Error","getContainer","getScopedContainer","overrideProvider","value","target","get","close","endRequest","dispose","expectResolved","expectNotResolved","expectSingleton","expectTransient","expectRequestScoped","expectCalled","method","expectCalledWith","expectedArgs","expectCallCount","count","recordMethodCall","args","result","error","getMethodCalls","getDependencyGraph","getSimplifiedDependencyGraph","createTestingModule","UnitTestContainer","UnitTestingModule","container","create","options","providers","allowUnregistered","logger","getContainer","get","token","close","clear","enableAutoMocking","disableAutoMocking","expectResolved","expectNotResolved","expectAutoMocked","expectNotAutoMocked","expectCalled","method","expectNotCalled","expectCalledWith","expectedArgs","expectCallCount","count","getMethodCalls","getServiceStats","clearMethodCalls","getRegisteredTokenIds","getAutoMockedTokenIds","expectInitialized","expectDestroyed","expectNotDestroyed","recordLifecycleEvent","event","instanceName"],"sources":["../../src/testing/testing-module.mts","../../src/testing/unit-testing-module.mts"],"sourcesContent":["import type {\n ClassType,\n ClassTypeWithInstance,\n InjectionToken,\n ScopedContainer,\n} from '@navios/di'\n\nimport { TestContainer } from '@navios/di/testing'\n\nimport type { NaviosModule } from '../interfaces/index.mjs'\nimport type { NaviosApplicationOptions } from '../navios.application.mjs'\n\nimport { NaviosApplication } from '../navios.application.mjs'\nimport { NaviosFactory } from '../navios.factory.mjs'\n\n/**\n * Configuration for overriding a provider in the testing module.\n *\n * @typeParam T - The type of the provider being overridden\n */\nexport interface TestingModuleOverride<T = any> {\n /**\n * The injection token or class to override.\n */\n token: ClassType | InjectionToken<T, any>\n /**\n * Value to use instead of the original provider.\n */\n useValue?: T\n /**\n * Class to use instead of the original provider.\n */\n useClass?: ClassType\n}\n\n/**\n * Options for creating a testing module.\n *\n * Extends NaviosApplicationOptions but excludes the container option,\n * as TestingModule manages its own TestContainer.\n */\nexport interface TestingModuleOptions extends Omit<\n NaviosApplicationOptions,\n 'container'\n> {\n /**\n * Initial provider overrides to apply when creating the testing module.\n *\n * You can also use `overrideProvider()` method for a fluent API.\n */\n overrides?: TestingModuleOverride[]\n /**\n * Container to use for the testing module.\n * If not provided, a new TestContainer will be created.\n */\n container?: TestContainer\n}\n\n/**\n * A testing-optimized wrapper around NaviosApplication.\n * Provides utilities for setting up test environments with mock dependencies.\n *\n * When `init()` is called, a request scope is automatically started.\n * This means `get()` calls will resolve request-scoped services correctly,\n * simulating a real HTTP request context.\n *\n * @example\n * ```typescript\n * const module = await TestingModule.create(AppModule)\n * .overrideProvider(DatabaseService)\n * .useValue(mockDatabase)\n * .init()\n *\n * const userService = await module.get(UserService)\n * // ... run tests ...\n *\n * await module.close()\n * ```\n */\nexport class TestingModule {\n private app: NaviosApplication | null = null\n private scopedContainer: ScopedContainer | null = null\n private requestId = `test-request-${Date.now()}-${Math.random().toString(36).slice(2)}`\n\n private constructor(\n private readonly appModule: ClassTypeWithInstance<NaviosModule>,\n private readonly container: TestContainer,\n private readonly options: TestingModuleOptions,\n ) {}\n\n /**\n * Creates a new TestingModule for the given app module.\n * This is the main entry point for setting up integration tests.\n *\n * @example\n * ```typescript\n * const module = await TestingModule.create(AppModule)\n * .overrideProvider(DatabaseService)\n * .useValue(mockDatabase)\n * .init()\n * ```\n */\n static create(\n appModule: ClassTypeWithInstance<NaviosModule>,\n options: TestingModuleOptions = { adapter: [] },\n ): TestingModule {\n const container =\n options.container ??\n new TestContainer({\n parentRegistry: options.registry,\n })\n\n // Apply initial overrides if provided\n if (options.overrides) {\n for (const override of options.overrides) {\n if (override.useValue !== undefined) {\n container.bind(override.token as any).toValue(override.useValue)\n } else if (override.useClass) {\n container.bind(override.token as any).toClass(override.useClass)\n }\n }\n }\n\n return new TestingModule(appModule, container, options)\n }\n\n /**\n * Compiles the testing module without initializing it.\n * Call this if you need to access the app before initialization.\n *\n * @returns this for chaining\n */\n async compile(): Promise<this> {\n if (!this.app) {\n this.app = await NaviosFactory.create(this.appModule, {\n ...this.options,\n container: this.container,\n })\n }\n return this\n }\n\n /**\n * Initializes the application and starts a request scope.\n *\n * This is equivalent to calling `compile()` followed by `app.init()`,\n * plus starting a request context for proper request-scoped service resolution.\n *\n * @returns this for chaining\n */\n async init(): Promise<this> {\n if (!this.app) {\n await this.compile()\n }\n await this.app!.init()\n\n // Begin a request scope so get() can resolve request-scoped services\n this.scopedContainer = this.container.beginRequest(this.requestId, {\n testingModule: true,\n })\n\n return this\n }\n\n /**\n * Gets the compiled application.\n *\n * @throws Error if the module has not been compiled yet\n */\n getApp(): NaviosApplication {\n if (!this.app) {\n throw new Error(\n 'TestingModule not compiled. Call compile() or init() first.',\n )\n }\n return this.app\n }\n\n /**\n * Gets the underlying TestContainer for direct manipulation.\n */\n getContainer(): TestContainer {\n return this.container\n }\n\n /**\n * Gets the scoped container for the current test request.\n * Only available after calling `init()`.\n *\n * @throws Error if init() has not been called\n */\n getScopedContainer(): ScopedContainer {\n if (!this.scopedContainer) {\n throw new Error('No scoped container available. Call init() first.')\n }\n return this.scopedContainer\n }\n\n /**\n * Override a provider with a mock value or class.\n * Must be called before `compile()` or `init()`.\n */\n overrideProvider<T>(token: ClassType | InjectionToken<T, any>): {\n useValue: (value: T) => TestingModule\n useClass: (target: ClassType) => TestingModule\n } {\n return {\n useValue: (value: T) => {\n this.container.bind(token as any).toValue(value)\n return this\n },\n useClass: (target: ClassType) => {\n this.container.bind(token as any).toClass(target)\n return this\n },\n }\n }\n\n /**\n * Gets an instance from the container.\n *\n * If `init()` has been called, this uses the scoped container\n * which properly resolves request-scoped services.\n *\n * If only `compile()` was called, this uses the root container\n * and request-scoped services will throw.\n */\n async get<T>(\n token: ClassTypeWithInstance<T> | InjectionToken<T, any>,\n ): Promise<T> {\n // Use scoped container if available (after init)\n if (this.scopedContainer) {\n return this.scopedContainer.get(token as any)\n }\n // Fall back to root container (after compile only)\n return this.container.get(token as any)\n }\n\n /**\n * Disposes the testing module and cleans up all resources.\n *\n * This will:\n * 1. End the request scope (if started)\n * 2. Close the application (if initialized)\n * 3. Dispose the container\n */\n async close(): Promise<void> {\n // End the request scope first\n if (this.scopedContainer) {\n await this.scopedContainer.endRequest()\n this.scopedContainer = null\n }\n\n // Close the app\n if (this.app) {\n await this.app.close()\n this.app = null\n }\n\n // Dispose the container\n await this.container.dispose()\n }\n\n // ===========================================================================\n // ASSERTION HELPERS (delegated to TestContainer)\n // ===========================================================================\n\n /**\n * Asserts that a service has been resolved at least once.\n */\n expectResolved(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectResolved(token)\n }\n\n /**\n * Asserts that a service has NOT been resolved.\n */\n expectNotResolved(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectNotResolved(token)\n }\n\n /**\n * Asserts that a service is registered as singleton scope.\n */\n expectSingleton(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectSingleton(token)\n }\n\n /**\n * Asserts that a service is registered as transient scope.\n */\n expectTransient(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectTransient(token)\n }\n\n /**\n * Asserts that a service is registered as request scope.\n */\n expectRequestScoped(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectRequestScoped(token)\n }\n\n /**\n * Asserts that a method was called on a service.\n * Note: You must use `recordMethodCall()` in your mocks for this to work.\n */\n expectCalled(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n ): void {\n this.container.expectCalled(token, method)\n }\n\n /**\n * Asserts that a method was called with specific arguments.\n * Note: You must use `recordMethodCall()` in your mocks for this to work.\n */\n expectCalledWith(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n expectedArgs: unknown[],\n ): void {\n this.container.expectCalledWith(token, method, expectedArgs)\n }\n\n /**\n * Asserts that a method was called a specific number of times.\n * Note: You must use `recordMethodCall()` in your mocks for this to work.\n */\n expectCallCount(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n count: number,\n ): void {\n this.container.expectCallCount(token, method, count)\n }\n\n /**\n * Records a method call for tracking.\n * Call this from your mock implementations to enable call assertions.\n */\n recordMethodCall(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n args: unknown[],\n result?: unknown,\n error?: Error,\n ): void {\n this.container.recordMethodCall(token, method, args, result, error)\n }\n\n /**\n * Gets all recorded method calls for a service.\n */\n getMethodCalls(token: ClassType | InjectionToken<any, any>) {\n return this.container.getMethodCalls(token)\n }\n\n /**\n * Gets the dependency graph for debugging or snapshot testing.\n */\n getDependencyGraph() {\n return this.container.getDependencyGraph()\n }\n\n /**\n * Gets a simplified dependency graph showing only token relationships.\n */\n getSimplifiedDependencyGraph() {\n return this.container.getSimplifiedDependencyGraph()\n }\n}\n\n/**\n * Creates a testing module for the given app module.\n *\n * @deprecated Use `TestingModule.create()` instead.\n *\n * @example\n * ```typescript\n * // Old way (deprecated)\n * const module = createTestingModule(AppModule)\n *\n * // New way\n * const module = TestingModule.create(AppModule)\n * ```\n */\nexport function createTestingModule(\n appModule: ClassTypeWithInstance<NaviosModule>,\n options: TestingModuleOptions = { adapter: [] },\n): TestingModule {\n return TestingModule.create(appModule, options)\n}\n","import type {\n ClassType,\n ClassTypeWithInstance,\n InjectionToken,\n} from '@navios/di'\nimport type {\n MethodCallRecord,\n MockServiceStats,\n ProviderConfig,\n} from '@navios/di/testing'\n\nimport { UnitTestContainer } from '@navios/di/testing'\n\n/**\n * Options for creating a UnitTestingModule.\n */\nexport interface UnitTestingModuleOptions {\n /**\n * List of providers to register. Only these services can be resolved.\n */\n providers: ProviderConfig[]\n\n /**\n * If true, unregistered dependencies will be auto-mocked instead of throwing.\n * Default: false (throws on unregistered dependencies)\n */\n allowUnregistered?: boolean\n\n /**\n * Logger for debugging.\n */\n logger?: Console | null\n\n /**\n * Container to use for the testing module.\n * If not provided, a new UnitTestContainer will be created.\n */\n container?: UnitTestContainer\n}\n\n/**\n * A lightweight testing module for isolated unit tests.\n *\n * Unlike `TestingModule`, this does NOT load Navios modules or create an application.\n * It uses `UnitTestContainer` which:\n * - Only allows explicitly provided services\n * - Automatically tracks all method calls via proxies\n * - Can auto-mock unregistered dependencies\n *\n * This is ideal for testing services in isolation without the overhead\n * of full module loading.\n *\n * @example\n * ```typescript\n * const module = UnitTestingModule.create({\n * providers: [\n * { token: UserService, useClass: UserService },\n * { token: DatabaseService, useValue: mockDatabase },\n * ],\n * })\n *\n * const userService = await module.get(UserService)\n * await userService.findUser('123')\n *\n * // Method calls are automatically tracked\n * module.expectCalled(UserService, 'findUser')\n * module.expectCalledWith(UserService, 'findUser', ['123'])\n *\n * await module.close()\n * ```\n */\nexport class UnitTestingModule {\n private constructor(private readonly container: UnitTestContainer) {}\n\n /**\n * Creates a new UnitTestingModule with the given providers.\n *\n * @example\n * ```typescript\n * const module = UnitTestingModule.create({\n * providers: [\n * { token: UserService, useClass: UserService },\n * { token: ConfigToken, useValue: { apiUrl: 'test' } },\n * ],\n * })\n * ```\n */\n static create(options: UnitTestingModuleOptions): UnitTestingModule {\n const container =\n options.container ??\n new UnitTestContainer({\n providers: options.providers,\n allowUnregistered: options.allowUnregistered,\n logger: options.logger,\n })\n\n return new UnitTestingModule(container)\n }\n\n /**\n * Gets the underlying UnitTestContainer for direct manipulation.\n */\n getContainer(): UnitTestContainer {\n return this.container\n }\n\n /**\n * Gets an instance from the container.\n *\n * All resolved instances are wrapped in tracking proxies,\n * so method calls are automatically recorded.\n *\n * @throws Error if the token is not in the providers list\n * and `allowUnregistered` is false\n */\n async get<T>(\n token: ClassTypeWithInstance<T> | InjectionToken<T, any>,\n ): Promise<T> {\n return this.container.get(token as any)\n }\n\n /**\n * Disposes the module and cleans up all resources.\n */\n async close(): Promise<void> {\n await this.container.clear()\n }\n\n /**\n * Enables auto-mocking for unregistered dependencies.\n * Unregistered services will return a proxy that throws on method access.\n */\n enableAutoMocking(): this {\n this.container.enableAutoMocking()\n return this\n }\n\n /**\n * Disables auto-mocking (strict mode).\n * Unregistered dependencies will throw immediately on resolution.\n */\n disableAutoMocking(): this {\n this.container.disableAutoMocking()\n return this\n }\n\n // ===========================================================================\n // ASSERTION HELPERS (delegated to UnitTestContainer)\n // ===========================================================================\n\n /**\n * Asserts that a service has been resolved at least once.\n */\n expectResolved(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectResolved(token)\n }\n\n /**\n * Asserts that a service has NOT been resolved.\n */\n expectNotResolved(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectNotResolved(token)\n }\n\n /**\n * Asserts that a service was auto-mocked (not in providers list).\n */\n expectAutoMocked(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectAutoMocked(token)\n }\n\n /**\n * Asserts that a service was NOT auto-mocked (is in providers list).\n */\n expectNotAutoMocked(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectNotAutoMocked(token)\n }\n\n /**\n * Asserts that a method was called on a service.\n * Method calls are automatically tracked via proxy.\n */\n expectCalled(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n ): void {\n this.container.expectCalled(token, method)\n }\n\n /**\n * Asserts that a method was NOT called on a service.\n */\n expectNotCalled(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n ): void {\n this.container.expectNotCalled(token, method)\n }\n\n /**\n * Asserts that a method was called with specific arguments.\n */\n expectCalledWith(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n expectedArgs: unknown[],\n ): void {\n this.container.expectCalledWith(token, method, expectedArgs)\n }\n\n /**\n * Asserts that a method was called a specific number of times.\n */\n expectCallCount(\n token: ClassType | InjectionToken<any, any>,\n method: string,\n count: number,\n ): void {\n this.container.expectCallCount(token, method, count)\n }\n\n /**\n * Gets all recorded method calls for a service.\n */\n getMethodCalls(\n token: ClassType | InjectionToken<any, any>,\n ): MethodCallRecord[] {\n return this.container.getMethodCalls(token)\n }\n\n /**\n * Gets statistics about a service (instance count, method calls, lifecycle events).\n */\n getServiceStats(\n token: ClassType | InjectionToken<any, any>,\n ): MockServiceStats {\n return this.container.getServiceStats(token)\n }\n\n /**\n * Clears all recorded method calls.\n * Useful for resetting state between test assertions.\n */\n clearMethodCalls(): void {\n this.container.clearMethodCalls()\n }\n\n /**\n * Gets list of all registered provider token IDs.\n */\n getRegisteredTokenIds(): ReadonlySet<string> {\n return this.container.getRegisteredTokenIds()\n }\n\n /**\n * Gets list of all auto-mocked token IDs.\n */\n getAutoMockedTokenIds(): ReadonlySet<string> {\n return this.container.getAutoMockedTokenIds()\n }\n\n // ===========================================================================\n // LIFECYCLE ASSERTIONS\n // ===========================================================================\n\n /**\n * Asserts that a service's onServiceInit was called.\n */\n expectInitialized(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectInitialized(token)\n }\n\n /**\n * Asserts that a service's onServiceDestroy was called.\n */\n expectDestroyed(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectDestroyed(token)\n }\n\n /**\n * Asserts that a service has NOT been destroyed.\n */\n expectNotDestroyed(token: ClassType | InjectionToken<any, any>): void {\n this.container.expectNotDestroyed(token)\n }\n\n /**\n * Records a lifecycle event for tracking.\n * Call this from your mock implementations if needed.\n */\n recordLifecycleEvent(\n token: ClassType | InjectionToken<any, any>,\n event: 'created' | 'initialized' | 'destroyed',\n instanceName: string,\n ): void {\n this.container.recordLifecycleEvent(token, event, instanceName)\n }\n}\n"],"mappings":"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"}
|
package/lib/testing/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { H as NaviosApplication, Tt as NaviosModule, U as NaviosApplicationOptions } from "../index-r0i2txmg.cjs";
|
|
2
2
|
import { ClassType, ClassTypeWithInstance, InjectionToken, ScopedContainer } from "@navios/di";
|
|
3
3
|
import * as _navios_di_testing0 from "@navios/di/testing";
|
|
4
4
|
import { MethodCallRecord, MockServiceStats, ProviderConfig, TestContainer, UnitTestContainer } from "@navios/di/testing";
|
package/lib/testing/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { H as NaviosApplication, Tt as NaviosModule, U as NaviosApplicationOptions } from "../index-6S7veHKD.mjs";
|
|
2
2
|
import { ClassType, ClassTypeWithInstance, InjectionToken, ScopedContainer } from "@navios/di";
|
|
3
3
|
import * as _navios_di_testing0 from "@navios/di/testing";
|
|
4
4
|
import { MethodCallRecord, MockServiceStats, ProviderConfig, TestContainer, UnitTestContainer } from "@navios/di/testing";
|
package/lib/testing/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { t as NaviosFactory } from "../
|
|
2
|
-
import "../
|
|
1
|
+
import { t as NaviosFactory } from "../navios.factory-C75yZCoD.mjs";
|
|
2
|
+
import "../tokens-4J9sredA.mjs";
|
|
3
3
|
import { TestContainer, UnitTestContainer } from "@navios/di/testing";
|
|
4
4
|
|
|
5
5
|
export * from "@navios/di/testing"
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { InjectionToken } from "@navios/di";
|
|
2
|
+
|
|
3
|
+
//#region src/metadata/module.metadata.mts
|
|
4
|
+
const ModuleMetadataKey = Symbol("ControllerMetadataKey");
|
|
5
|
+
function getModuleMetadata(target, context) {
|
|
6
|
+
if (context.metadata) {
|
|
7
|
+
const metadata = context.metadata[ModuleMetadataKey];
|
|
8
|
+
if (metadata) return metadata;
|
|
9
|
+
else {
|
|
10
|
+
const newMetadata = {
|
|
11
|
+
controllers: /* @__PURE__ */ new Set(),
|
|
12
|
+
imports: /* @__PURE__ */ new Set(),
|
|
13
|
+
guards: /* @__PURE__ */ new Set(),
|
|
14
|
+
overrides: /* @__PURE__ */ new Set(),
|
|
15
|
+
customAttributes: /* @__PURE__ */ new Map(),
|
|
16
|
+
customEntries: /* @__PURE__ */ new Map()
|
|
17
|
+
};
|
|
18
|
+
context.metadata[ModuleMetadataKey] = newMetadata;
|
|
19
|
+
target[ModuleMetadataKey] = newMetadata;
|
|
20
|
+
return newMetadata;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
throw new Error("[Navios] Wrong environment.");
|
|
24
|
+
}
|
|
25
|
+
function extractModuleMetadata(target) {
|
|
26
|
+
const metadata = target[ModuleMetadataKey];
|
|
27
|
+
if (!metadata) throw new Error(`[Navios] Module metadata not found for ${target.name}. Make sure to use @Module decorator.`);
|
|
28
|
+
return metadata;
|
|
29
|
+
}
|
|
30
|
+
function hasModuleMetadata(target) {
|
|
31
|
+
return !!target[ModuleMetadataKey];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Type-safe helper to get or create a custom entry in module metadata.
|
|
35
|
+
* Adapters use this to store their own metadata in modules.
|
|
36
|
+
*
|
|
37
|
+
* @param metadata - The module metadata object
|
|
38
|
+
* @param key - Symbol key for the custom entry
|
|
39
|
+
* @param defaultValue - Factory function to create default value if entry doesn't exist
|
|
40
|
+
* @returns The existing or newly created entry value
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const CommandEntryKey = Symbol('CommandEntryKey')
|
|
45
|
+
* const commands = getModuleCustomEntry<Set<ClassType>>(
|
|
46
|
+
* metadata,
|
|
47
|
+
* CommandEntryKey,
|
|
48
|
+
* () => new Set(),
|
|
49
|
+
* )
|
|
50
|
+
* commands.add(MyCommand)
|
|
51
|
+
* ```
|
|
52
|
+
*/ function getModuleCustomEntry(metadata, key, defaultValue) {
|
|
53
|
+
if (!metadata.customEntries.has(key)) metadata.customEntries.set(key, defaultValue());
|
|
54
|
+
return metadata.customEntries.get(key);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/tokens/adapter.token.mts
|
|
59
|
+
const AdapterToken = InjectionToken.create("AdapterToken");
|
|
60
|
+
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/tokens/endpoint-adapter.token.mts
|
|
63
|
+
const EndpointAdapterToken = InjectionToken.create("EndpointAdapterToken");
|
|
64
|
+
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region src/tokens/execution-context.token.mts
|
|
67
|
+
const ExecutionContextInjectionToken = "ExecutionContextInjectionToken";
|
|
68
|
+
const ExecutionContext = InjectionToken.create(ExecutionContextInjectionToken);
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/tokens/http-adapter.token.mts
|
|
72
|
+
const HttpAdapterToken = InjectionToken.create("HttpAdapterToken");
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/tokens/multipart-adapter.token.mts
|
|
76
|
+
const MultipartAdapterToken = InjectionToken.create("MultipartAdapterToken");
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/tokens/navios-options.token.mts
|
|
80
|
+
const NaviosOptionsToken = InjectionToken.create("NaviosOptionsToken");
|
|
81
|
+
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/tokens/reply.token.mts
|
|
84
|
+
const Reply = InjectionToken.create("ReplyToken");
|
|
85
|
+
|
|
86
|
+
//#endregion
|
|
87
|
+
//#region src/tokens/request.token.mts
|
|
88
|
+
const Request = InjectionToken.create("RequestToken");
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/tokens/stream-adapter.token.mts
|
|
92
|
+
const StreamAdapterToken = InjectionToken.create("StreamAdapterToken");
|
|
93
|
+
|
|
94
|
+
//#endregion
|
|
95
|
+
//#region src/tokens/xml-stream-adapter.token.mts
|
|
96
|
+
const XmlStreamAdapterToken = InjectionToken.create("XmlStreamAdapterToken");
|
|
97
|
+
|
|
98
|
+
//#endregion
|
|
99
|
+
export { NaviosOptionsToken as a, ExecutionContext as c, AdapterToken as d, ModuleMetadataKey as f, hasModuleMetadata as g, getModuleMetadata as h, Reply as i, ExecutionContextInjectionToken as l, getModuleCustomEntry as m, StreamAdapterToken as n, MultipartAdapterToken as o, extractModuleMetadata as p, Request as r, HttpAdapterToken as s, XmlStreamAdapterToken as t, EndpointAdapterToken as u };
|
|
100
|
+
//# sourceMappingURL=tokens-4J9sredA.mjs.map
|