@navios/commander 0.9.0 → 1.0.0-alpha.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@navios/commander",
3
- "version": "0.9.0",
3
+ "version": "1.0.0-alpha.2",
4
4
  "author": {
5
5
  "name": "Oleksandr Hanzha",
6
6
  "email": "alex@granted.name"
@@ -35,6 +35,6 @@
35
35
  "zod": "^4.2.1"
36
36
  },
37
37
  "dependencies": {
38
- "@navios/di": "^0.9.0"
38
+ "@navios/di": "^0.9.2"
39
39
  }
40
40
  }
@@ -20,6 +20,13 @@ export interface CliModuleOptions {
20
20
  * Imported modules' commands will be available in this module.
21
21
  */
22
22
  imports?: ClassType[] | Set<ClassType>
23
+ /**
24
+ * Service override classes to import for side effects.
25
+ * These classes are imported to ensure their @Injectable decorators execute,
26
+ * allowing them to register with the DI system. Overrides should use the same
27
+ * InjectionToken as the original service with a higher priority.
28
+ */
29
+ overrides?: ClassType[] | Set<ClassType>
23
30
  /**
24
31
  * Priority level for the module.
25
32
  * Higher priority modules will be loaded first.
@@ -55,9 +62,16 @@ export interface CliModuleOptions {
55
62
  * ```
56
63
  */
57
64
  export function CliModule(
58
- { commands = [], imports = [], priority, registry }: CliModuleOptions = {
65
+ {
66
+ commands = [],
67
+ imports = [],
68
+ overrides = [],
69
+ priority,
70
+ registry,
71
+ }: CliModuleOptions = {
59
72
  commands: [],
60
73
  imports: [],
74
+ overrides: [],
61
75
  },
62
76
  ) {
63
77
  return (target: ClassType, context: ClassDecoratorContext) => {
@@ -75,6 +89,9 @@ export function CliModule(
75
89
  for (const importedModule of imports) {
76
90
  moduleMetadata.imports.add(importedModule)
77
91
  }
92
+ for (const override of overrides) {
93
+ moduleMetadata.overrides.add(override)
94
+ }
78
95
 
79
96
  return Injectable({
80
97
  token,
@@ -20,6 +20,10 @@ export interface CliModuleMetadata {
20
20
  * Set of other modules imported by this module.
21
21
  */
22
22
  imports: Set<ClassType>
23
+ /**
24
+ * Set of service override classes imported for side effects.
25
+ */
26
+ overrides: Set<ClassType>
23
27
  /**
24
28
  * Map of custom attributes that can be attached to the module.
25
29
  */
@@ -48,6 +52,7 @@ export function getCliModuleMetadata(
48
52
  const newMetadata: CliModuleMetadata = {
49
53
  commands: new Set<ClassType>(),
50
54
  imports: new Set<ClassType>(),
55
+ overrides: new Set<ClassType>(),
51
56
  customAttributes: new Map<string | symbol, any>(),
52
57
  }
53
58
  context.metadata[CliModuleMetadataKey] = newMetadata
@@ -1,6 +1,12 @@
1
1
  import type { ClassTypeWithInstance, NaviosModule } from '@navios/core'
2
2
 
3
- import { Container, getInjectableToken, inject, Injectable } from '@navios/core'
3
+ import {
4
+ Container,
5
+ getInjectableToken,
6
+ inject,
7
+ Injectable,
8
+ Logger,
9
+ } from '@navios/core'
4
10
 
5
11
  import type { CommandHandler } from '../interfaces/index.mjs'
6
12
  import type { CliModuleMetadata, CommandMetadata } from '../metadata/index.mjs'
@@ -36,6 +42,9 @@ export interface CommandWithMetadata {
36
42
  */
37
43
  @Injectable()
38
44
  export class CliModuleLoaderService {
45
+ private logger = inject(Logger, {
46
+ context: CliModuleLoaderService.name,
47
+ })
39
48
  protected container = inject(Container)
40
49
  private modulesMetadata: Map<string, CliModuleMetadata> = new Map()
41
50
  private loadedModules: Map<string, any> = new Map()
@@ -86,6 +95,7 @@ export class CliModuleLoaderService {
86
95
  this.traverseModules(importedModule, metadata),
87
96
  )
88
97
  await Promise.all(loadingPromises)
98
+ this.validateOverrides(metadata, moduleName)
89
99
  const instance = await this.container.get(module)
90
100
  if (instance.onModuleInit) {
91
101
  await instance.onModuleInit()
@@ -93,6 +103,67 @@ export class CliModuleLoaderService {
93
103
  this.loadedModules.set(moduleName, instance)
94
104
  }
95
105
 
106
+ private validateOverrides(
107
+ metadata: CliModuleMetadata,
108
+ moduleName: string,
109
+ ): void {
110
+ if (!metadata.overrides || metadata.overrides.size === 0) {
111
+ return
112
+ }
113
+
114
+ const registry = this.container.getRegistry()
115
+
116
+ for (const overrideClass of metadata.overrides) {
117
+ try {
118
+ // Get the token for the override class
119
+ const overrideToken = getInjectableToken(overrideClass)
120
+
121
+ // Get all registrations for this token (sorted by priority, highest first)
122
+ const allRegistrations = registry.getAll(overrideToken)
123
+
124
+ if (allRegistrations.length === 0) {
125
+ this.logger.warn(
126
+ `[Navios Commander] Override ${overrideClass.name} in module ${moduleName} is not registered. ` +
127
+ `Make sure it has @Injectable decorator.`,
128
+ )
129
+ continue
130
+ }
131
+
132
+ // Check if the override class has the highest priority
133
+ const highestPriorityRegistration = allRegistrations[0]
134
+ if (highestPriorityRegistration.target !== overrideClass) {
135
+ const overrideRegistration = allRegistrations.find(
136
+ (r) => r.target === overrideClass,
137
+ )
138
+
139
+ if (!overrideRegistration) {
140
+ this.logger.warn(
141
+ `[Navios Commander] Override ${overrideClass.name} in module ${moduleName} is registered ` +
142
+ `but not found in registry for token ${overrideToken.toString()}.`,
143
+ )
144
+ } else {
145
+ this.logger.warn(
146
+ `[Navios Commander] Override ${overrideClass.name} in module ${moduleName} is not active. ` +
147
+ `Current active service: ${highestPriorityRegistration.target.name} ` +
148
+ `(priority: ${highestPriorityRegistration.priority}). ` +
149
+ `Override priority: ${overrideRegistration.priority}. ` +
150
+ `Override needs higher priority to take effect.`,
151
+ )
152
+ }
153
+ } else {
154
+ this.logger.debug(
155
+ `[Navios Commander] Override ${overrideClass.name} in module ${moduleName} is active ` +
156
+ `(priority: ${highestPriorityRegistration.priority})`,
157
+ )
158
+ }
159
+ } catch (error) {
160
+ this.logger.warn(
161
+ `[Navios Commander] Failed to validate override ${overrideClass.name} in module ${moduleName}: ${error}`,
162
+ )
163
+ }
164
+ }
165
+ }
166
+
96
167
  private mergeMetadata(
97
168
  metadata: CliModuleMetadata,
98
169
  parentMetadata: CliModuleMetadata,