@noxfly/noxus 2.4.0 → 3.0.0-dev.0

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.
Files changed (48) hide show
  1. package/README.md +403 -341
  2. package/dist/app-injector-Bz3Upc0y.d.mts +125 -0
  3. package/dist/app-injector-Bz3Upc0y.d.ts +125 -0
  4. package/dist/child.d.mts +48 -22
  5. package/dist/child.d.ts +48 -22
  6. package/dist/child.js +1114 -1239
  7. package/dist/child.mjs +1090 -1193
  8. package/dist/main.d.mts +304 -261
  9. package/dist/main.d.ts +304 -261
  10. package/dist/main.js +1473 -1873
  11. package/dist/main.mjs +1423 -1791
  12. package/dist/renderer.d.mts +113 -2
  13. package/dist/renderer.d.ts +113 -2
  14. package/dist/renderer.js +144 -132
  15. package/dist/renderer.mjs +143 -132
  16. package/dist/request-BlTtiHbi.d.ts +112 -0
  17. package/dist/request-qJ9EiDZc.d.mts +112 -0
  18. package/package.json +7 -7
  19. package/src/DI/app-injector.ts +95 -106
  20. package/src/DI/injector-explorer.ts +100 -81
  21. package/src/DI/token.ts +53 -0
  22. package/src/app.ts +141 -131
  23. package/src/bootstrap.ts +79 -40
  24. package/src/decorators/controller.decorator.ts +38 -27
  25. package/src/decorators/guards.decorator.ts +5 -64
  26. package/src/decorators/injectable.decorator.ts +68 -15
  27. package/src/decorators/method.decorator.ts +40 -81
  28. package/src/decorators/middleware.decorator.ts +5 -72
  29. package/src/index.ts +3 -0
  30. package/src/main.ts +4 -11
  31. package/src/non-electron-process.ts +0 -1
  32. package/src/preload-bridge.ts +1 -1
  33. package/src/renderer-client.ts +2 -2
  34. package/src/renderer-events.ts +1 -1
  35. package/src/request.ts +3 -3
  36. package/src/router.ts +221 -369
  37. package/src/routes.ts +78 -0
  38. package/src/socket.ts +4 -4
  39. package/src/window/window-manager.ts +255 -0
  40. package/tsconfig.json +5 -10
  41. package/tsup.config.ts +2 -2
  42. package/dist/app-injector-B3MvgV3k.d.mts +0 -95
  43. package/dist/app-injector-B3MvgV3k.d.ts +0 -95
  44. package/dist/index-BxWQVi6C.d.ts +0 -253
  45. package/dist/index-DQBQQfMw.d.mts +0 -253
  46. package/src/decorators/inject.decorator.ts +0 -24
  47. package/src/decorators/injectable.metadata.ts +0 -15
  48. package/src/decorators/module.decorator.ts +0 -75
package/dist/main.d.mts CHANGED
@@ -1,9 +1,9 @@
1
- import { M as MaybeAsync, T as Type } from './app-injector-B3MvgV3k.mjs';
2
- export { A as AppInjector, F as ForwardRefFn, a as ForwardReference, I as IBinding, L as Lifetime, R as RootInjector, f as forwardRef, i as inject } from './app-injector-B3MvgV3k.mjs';
3
- import { R as Request, I as IResponse, a as IGuard, b as IPortRequester } from './index-DQBQQfMw.mjs';
4
- export { e as AtomicHttpMethod, A as Authorize, D as Delete, G as Get, H as HttpMethod, l as IBatchRequestItem, m as IBatchRequestPayload, n as IBatchResponsePayload, p as IRendererEventMessage, k as IRequest, d as IRouteMetadata, N as NoxRendererClient, i as Patch, P as Post, h as Put, o as RENDERER_EVENT_TYPE, j as ROUTE_METADATA_KEY, v as RendererClientOptions, s as RendererEventHandler, u as RendererEventRegistry, t as RendererEventSubscription, q as createRendererEventMessage, g as getGuardForController, c as getGuardForControllerAction, f as getRouteMetadata, r as isRendererEventMessage } from './index-DQBQQfMw.mjs';
1
+ import { T as Type, a as TokenKey } from './app-injector-Bz3Upc0y.mjs';
2
+ export { A as AppInjector, F as ForwardRefFn, b as ForwardReference, I as IBinding, L as Lifetime, M as MaybeAsync, R as RootInjector, c as Token, f as forwardRef, i as inject, t as token } from './app-injector-Bz3Upc0y.mjs';
3
+ import { f as Request, a as IResponse, G as Guard, M as Middleware } from './request-qJ9EiDZc.mjs';
4
+ export { A as AtomicHttpMethod, D as Delete, h as Get, H as HttpMethod, c as IBatchRequestItem, e as IBatchRequestPayload, d as IBatchResponsePayload, I as IRendererEventMessage, b as IRequest, j as IRouteMetadata, k as IRouteOptions, N as NextFunction, P as Patch, l as Post, m as Put, R as RENDERER_EVENT_TYPE, g as createRendererEventMessage, n as getRouteMetadata, o as isAtomicHttpMethod, i as isRendererEventMessage } from './request-qJ9EiDZc.mjs';
5
5
  import { BrowserWindow } from 'electron/main';
6
- export { BadGatewayException, BadRequestException, ConflictException, ForbiddenException, GatewayTimeoutException, HttpVersionNotSupportedException, INJECTABLE_METADATA_KEY, INJECT_METADATA_KEY, Inject, Injectable, InsufficientStorageException, InternalServerException, LogLevel, Logger, LoopDetectedException, MethodNotAllowedException, NetworkAuthenticationRequiredException, NetworkConnectTimeoutException, NotAcceptableException, NotExtendedException, NotFoundException, NotImplementedException, PaymentRequiredException, RequestTimeoutException, ResponseException, ServiceUnavailableException, TooManyRequestsException, UnauthorizedException, UpgradeRequiredException, VariantAlsoNegotiatesException, getInjectableMetadata, hasInjectableMetadata } from './child.mjs';
6
+ export { BadGatewayException, BadRequestException, ConflictException, ForbiddenException, GatewayTimeoutException, HttpVersionNotSupportedException, Injectable, InjectableOptions, InsufficientStorageException, InternalServerException, LogLevel, Logger, LoopDetectedException, MethodNotAllowedException, NetworkAuthenticationRequiredException, NetworkConnectTimeoutException, NotAcceptableException, NotExtendedException, NotFoundException, NotImplementedException, PaymentRequiredException, RequestTimeoutException, ResponseException, ServiceUnavailableException, TooManyRequestsException, UnauthorizedException, UpgradeRequiredException, VariantAlsoNegotiatesException } from './child.mjs';
7
7
 
8
8
  /**
9
9
  * @copyright 2025 NoxFly
@@ -11,341 +11,384 @@ export { BadGatewayException, BadRequestException, ConflictException, ForbiddenE
11
11
  * @author NoxFly
12
12
  */
13
13
 
14
- /**
15
- * NextFunction is a function that is called to continue the middleware chain.
16
- * It returns an Promise that emits when the next middleware is done.
17
- */
18
- type NextFunction = () => Promise<void>;
19
- /**
20
- * IMiddleware interface defines a middleware that can be used in the application.
21
- * It has an `invoke` method that takes a request, a response, and a next function.
22
- * The `invoke` method can return a MaybeAsync, which means it can return either a value or a Promise.
23
- *
24
- * Use it on a class that should be registered as a middleware in the application.
25
- */
26
- interface IMiddleware {
27
- invoke(request: Request, response: IResponse, next: NextFunction): MaybeAsync<void>;
14
+ interface ILazyRoute {
15
+ load: () => Promise<unknown>;
16
+ guards: Guard[];
17
+ middlewares: Middleware[];
18
+ loading: Promise<void> | null;
19
+ loaded: boolean;
28
20
  }
29
- /**
30
- * UseMiddlewares decorator can be used to register middlewares for a controller or a controller action.
31
- *
32
- * @param mdlw - The middlewares list to register for the controller or the controller action.
33
- */
34
- declare function UseMiddlewares(mdlw: Type<IMiddleware>[]): ClassDecorator & MethodDecorator;
35
- /**
36
- * Gets the middlewares for a controller or a controller action.
37
- * This function retrieves the middlewares registered with the UseMiddlewares decorator.
38
- * It returns an array of middleware classes that can be used to process requests for the specified controller.
39
- * @param controllerName The name of the controller to get the middlewares for.
40
- * @returns An array of middlewares for the controller.
41
- */
42
- declare function getMiddlewaresForController(controllerName: string): Type<IMiddleware>[];
43
- /**
44
- * Gets the middlewares for a controller action.
45
- * This function retrieves the middlewares registered with the UseMiddlewares decorator for a specific action in a controller.
46
- * It returns an array of middleware classes that can be used to process requests for the specified controller action.
47
- * @param controllerName The name of the controller to get the middlewares for.
48
- * @param actionName The name of the action to get the middlewares for.
49
- * @returns An array of middlewares for the controller action.
50
- */
51
- declare function getMiddlewaresForControllerAction(controllerName: string, actionName: string): Type<IMiddleware>[];
52
-
53
-
54
- /**
55
- * IRouteDefinition interface defines the structure of a route in the application.
56
- * It includes the HTTP method, path, controller class, handler method name,
57
- * guards, and middlewares associated with the route.
58
- */
59
21
  interface IRouteDefinition {
60
22
  method: string;
61
23
  path: string;
62
- controller: Type<any>;
24
+ controller: Type<unknown>;
63
25
  handler: string;
64
- guards: Type<IGuard>[];
65
- middlewares: Type<IMiddleware>[];
26
+ guards: Guard[];
27
+ middlewares: Middleware[];
66
28
  }
67
- /**
68
- * This type defines a function that represents an action in a controller.
69
- * It takes a Request and an IResponse as parameters and returns a value or a Promise.
70
- */
71
- type ControllerAction = (request: Request, response: IResponse) => any;
72
- /**
73
- * Router class is responsible for managing the application's routing.
74
- * It registers controllers, handles requests, and manages middlewares and guards.
75
- */
29
+ type ControllerAction = (request: Request, response: IResponse) => unknown;
76
30
  declare class Router {
77
31
  private readonly routes;
78
32
  private readonly rootMiddlewares;
79
- /**
80
- * Registers a controller class with the router.
81
- * This method extracts the route metadata from the controller class and registers it in the routing tree.
82
- * It also handles the guards and middlewares associated with the controller.
83
- * @param controllerClass - The controller class to register.
84
- */
85
- registerController(controllerClass: Type<unknown>): Router;
86
- /**
87
- * Defines a middleware for the root of the application.
88
- * This method allows you to register a middleware that will be applied to all requests
89
- * to the application, regardless of the controller or action.
90
- * @param middleware - The middleware class to register.
91
- */
92
- defineRootMiddleware(middleware: Type<IMiddleware>): Router;
93
- /**
94
- * Shuts down the message channel for a specific sender ID.
95
- * This method closes the IPC channel for the specified sender ID and
96
- * removes it from the messagePorts map.
97
- * @param channelSenderId - The ID of the sender channel to shut down.
98
- */
33
+ private readonly lazyRoutes;
34
+ registerController(controllerClass: Type<unknown>, pathPrefix: string, routeGuards?: Guard[], routeMiddlewares?: Middleware[]): this;
35
+ registerLazyRoute(pathPrefix: string, load: () => Promise<unknown>, guards?: Guard[], middlewares?: Middleware[]): this;
36
+ defineRootMiddleware(middleware: Middleware): this;
99
37
  handle(request: Request): Promise<IResponse>;
100
38
  private handleAtomic;
101
39
  private handleBatch;
40
+ private tryFindRoute;
41
+ private findRoute;
42
+ private tryLoadLazyRoute;
43
+ private loadLazyModule;
44
+ private resolveController;
45
+ private runPipeline;
46
+ private runMiddleware;
47
+ private runGuard;
48
+ private extractParams;
102
49
  private normalizeBatchPayload;
103
50
  private normalizeBatchItem;
51
+ private fillErrorResponse;
52
+ private logResponse;
53
+ }
54
+
55
+
56
+ interface WindowConfig extends Electron.BrowserWindowConstructorOptions {
104
57
  /**
105
- * Finds the route definition for a given request.
106
- * This method searches the routing tree for a matching route based on the request's path and method.
107
- * If no matching route is found, it throws a NotFoundException.
108
- * @param request - The Request object containing the method and path to search for.
109
- * @returns The IRouteDefinition for the matched route.
58
+ * If true, the window expands to fill the work area after creation
59
+ * using an animated setBounds. The content is loaded only after
60
+ * the animation completes, preventing the viewbox freeze issue.
61
+ * @default false
110
62
  */
111
- private findRoute;
63
+ expandToWorkArea?: boolean;
112
64
  /**
113
- * Resolves the controller for a given route definition.
114
- * This method creates an instance of the controller class and prepares the request parameters.
115
- * It also runs the request pipeline, which includes executing middlewares and guards.
116
- * @param request - The Request object containing the request data.
117
- * @param response - The IResponse object to populate with the response data.
118
- * @param routeDef - The IRouteDefinition for the matched route.
119
- * @return A Promise that resolves when the controller action has been executed.
120
- * @throws UnauthorizedException if the request is not authorized by the guards.
65
+ * Duration in ms to wait for the setBounds animation to complete
66
+ * before loading content. Only used when expandToWorkArea is true.
67
+ * @default 600
121
68
  */
122
- private resolveController;
69
+ expandAnimationDuration?: number;
70
+ }
71
+ interface WindowRecord {
72
+ window: BrowserWindow;
73
+ id: number;
74
+ }
75
+ /**
76
+ * WindowManager is a singleton service that centralizes BrowserWindow lifecycle.
77
+ *
78
+ * Features:
79
+ * - Creates and tracks all application windows.
80
+ * - Handles the animated expand-to-work-area pattern correctly,
81
+ * loading content only after the animation ends to avoid the viewbox freeze.
82
+ * - Provides convenience methods to get windows by id, get the main window, etc.
83
+ * - Automatically removes windows from the registry on close.
84
+ *
85
+ * @example
86
+ * // In your IApp.onReady():
87
+ * const wm = inject(WindowManager);
88
+ *
89
+ * const win = await wm.create({
90
+ * width: 600, height: 600, center: true,
91
+ * expandToWorkArea: true,
92
+ * webPreferences: { preload: path.join(__dirname, 'preload.js') },
93
+ * });
94
+ *
95
+ * win.loadFile('index.html');
96
+ */
97
+ declare class WindowManager {
98
+ private readonly _windows;
99
+ private _mainWindowId;
123
100
  /**
124
- * Runs the request pipeline for a given request.
125
- * This method executes the middlewares and guards associated with the route,
126
- * and finally calls the controller action.
127
- * @param request - The Request object containing the request data.
128
- * @param response - The IResponse object to populate with the response data.
129
- * @param routeDef - The IRouteDefinition for the matched route.
130
- * @param controllerInstance - The instance of the controller class.
131
- * @return A Promise that resolves when the request pipeline has been executed.
132
- * @throws ResponseException if the response status is not successful.
101
+ * Creates a BrowserWindow, optionally performs an animated expand to the
102
+ * work area, and registers it in the manager.
103
+ *
104
+ * If expandToWorkArea is true:
105
+ * 1. The window is created at the given initial size (defaults to 600×600, centered).
106
+ * 2. An animated setBounds expands it to the full work area.
107
+ * 3. The returned promise resolves only after the animation, so callers
108
+ * can safely call win.loadFile() without the viewbox freeze.
109
+ *
110
+ * @param config Window configuration.
111
+ * @param isMain Mark this window as the main window (accessible via getMain()).
133
112
  */
134
- private runRequestPipeline;
113
+ create(config: WindowConfig, isMain?: boolean): Promise<BrowserWindow>;
135
114
  /**
136
- * Runs a middleware function in the request pipeline.
137
- * This method creates an instance of the middleware and invokes its `invoke` method,
138
- * passing the request, response, and next function.
139
- * @param request - The Request object containing the request data.
140
- * @param response - The IResponse object to populate with the response data.
141
- * @param next - The NextFunction to call to continue the middleware chain.
142
- * @param middlewareType - The type of the middleware to run.
143
- * @return A Promise that resolves when the middleware has been executed.
115
+ * Creates the initial "splash" window that is shown immediately after
116
+ * app.whenReady(). It is displayed instantly (show: true, no preload
117
+ * loading) and then expanded to the work area with animation.
118
+ *
119
+ * After the animation completes you can call win.loadFile() without
120
+ * experiencing the viewbox freeze.
121
+ *
122
+ * This is the recommended way to get pixels on screen as fast as possible.
123
+ *
124
+ * @example
125
+ * const win = await wm.createSplash({
126
+ * webPreferences: { preload: path.join(__dirname, 'preload.js') }
127
+ * });
128
+ * win.loadFile('index.html');
144
129
  */
145
- private runMiddleware;
130
+ createSplash(options?: Electron.BrowserWindowConstructorOptions & {
131
+ animationDuration?: number;
132
+ }): Promise<BrowserWindow>;
133
+ /** Returns all currently open windows. */
134
+ getAll(): BrowserWindow[];
135
+ /** Returns the window designated as main, or undefined. */
136
+ getMain(): BrowserWindow | undefined;
137
+ /** Returns a window by its Electron id, or undefined. */
138
+ getById(id: number): BrowserWindow | undefined;
139
+ /** Returns the number of open windows. */
140
+ get count(): number;
141
+ /** Closes and destroys a window by id. */
142
+ close(id: number): void;
143
+ /** Closes all windows. */
144
+ closeAll(): void;
146
145
  /**
147
- * Runs a guard to check if the request is authorized.
148
- * This method creates an instance of the guard and calls its `canActivate` method.
149
- * If the guard returns false, it throws an UnauthorizedException.
150
- * @param request - The Request object containing the request data.
151
- * @param guardType - The type of the guard to run.
152
- * @return A Promise that resolves if the guard allows the request, or throws an UnauthorizedException if not.
153
- * @throws UnauthorizedException if the guard denies access to the request.
146
+ * Sends a message to a specific window via webContents.send.
147
+ * @param id Target window id.
148
+ * @param channel IPC channel name.
149
+ * @param args Payload.
154
150
  */
155
- private runGuard;
151
+ send(id: number, channel: string, ...args: unknown[]): void;
156
152
  /**
157
- * Extracts parameters from the actual request path based on the template path.
158
- * This method splits the actual path and the template path into segments,
159
- * then maps the segments to parameters based on the template.
160
- * @param actual - The actual request path.
161
- * @param template - The template path to extract parameters from.
162
- * @returns An object containing the extracted parameters.
153
+ * Broadcasts a message to all open windows.
163
154
  */
164
- private extractParams;
165
- }
166
-
167
- interface RendererChannels {
168
- request: Electron.MessageChannelMain;
169
- socket: Electron.MessageChannelMain;
170
- }
171
- declare class NoxSocket {
172
- private readonly channels;
173
- register(senderId: number, requestChannel: Electron.MessageChannelMain, socketChannel: Electron.MessageChannelMain): void;
174
- get(senderId: number): RendererChannels | undefined;
175
- unregister(senderId: number): void;
176
- getSenderIds(): number[];
177
- emit<TPayload = unknown>(eventName: string, payload?: TPayload, targetSenderIds?: number[]): number;
178
- emitToRenderer<TPayload = unknown>(senderId: number, eventName: string, payload?: TPayload): boolean;
155
+ broadcast(channel: string, ...args: unknown[]): void;
156
+ private _register;
157
+ /**
158
+ * Animates the window to the full work area of the primary display.
159
+ * Resolves only after the animation is complete, so that content loaded
160
+ * afterward gets the correct surface size (no viewbox freeze).
161
+ */
162
+ private _expandToWorkArea;
179
163
  }
180
164
 
181
165
 
182
166
  /**
183
- * The application service should implement this interface, as
184
- * the NoxApp class instance will use it to notify the given service
185
- * about application lifecycle events.
167
+ * Your application service should implement IApp.
168
+ * Noxus calls these lifecycle methods at the appropriate time.
169
+ *
170
+ * Unlike v2, IApp no longer receives a BrowserWindow in onReady.
171
+ * Use the injected WindowManager instead — it is more flexible and
172
+ * does not couple the lifecycle to a single pre-created window.
173
+ *
174
+ * @example
175
+ * @Injectable({ lifetime: 'singleton', deps: [WindowManager, MyService] })
176
+ * class AppService implements IApp {
177
+ * constructor(private wm: WindowManager, private svc: MyService) {}
178
+ *
179
+ * async onReady() {
180
+ * const win = await this.wm.createSplash({ webPreferences: { preload: ... } });
181
+ * win.loadFile('index.html');
182
+ * }
183
+ *
184
+ * async onActivated() { ... }
185
+ * async dispose() { ... }
186
+ * }
186
187
  */
187
188
  interface IApp {
188
189
  dispose(): Promise<void>;
189
- onReady(mainWindow?: BrowserWindow): Promise<void>;
190
+ onReady(): Promise<void>;
190
191
  onActivated(): Promise<void>;
191
192
  }
192
- /**
193
- * NoxApp is the main application class that manages the application lifecycle,
194
- * handles IPC communication, and integrates with the Router.
195
- */
196
193
  declare class NoxApp {
194
+ private appService;
197
195
  private readonly router;
198
196
  private readonly socket;
199
- private app;
200
- private mainWindow;
197
+ readonly windowManager: WindowManager;
198
+ init(): Promise<this>;
201
199
  /**
200
+ * Registers a lazy route. The file behind this prefix is dynamically
201
+ * imported on the first IPC request that targets it.
202
202
  *
203
+ * The import function should NOT statically reference heavy modules —
204
+ * the whole point is to defer their loading.
205
+ *
206
+ * @example
207
+ * noxApp.lazy('auth', () => import('./modules/auth/auth.controller.js'));
208
+ * noxApp.lazy('reporting', () => import('./modules/reporting/index.js'));
203
209
  */
204
- private readonly onRendererMessage;
205
- constructor(router: Router, socket: NoxSocket);
206
- /**
207
- * Initializes the NoxApp instance.
208
- * This method sets up the IPC communication, registers event listeners,
209
- * and prepares the application for use.
210
- */
211
- init(): Promise<NoxApp>;
210
+ lazy(pathPrefix: string, load: () => Promise<unknown>, guards?: Guard[], middlewares?: Middleware[]): this;
212
211
  /**
213
- * Handles the request from the renderer process.
214
- * This method creates a Request object from the IPC event data,
215
- * processes it through the Router, and sends the response back
216
- * to the renderer process using the MessageChannel.
212
+ * Eagerly loads a set of modules (controllers + services) before start().
213
+ * Use this for modules that provide services needed by your IApp.onReady().
214
+ *
215
+ * All imports run in parallel; DI is flushed with the two-phase guarantee.
217
216
  */
218
- private giveTheRendererAPort;
217
+ load(importFns: Array<() => Promise<unknown>>): Promise<this>;
219
218
  /**
220
- * MacOS specific behavior.
219
+ * Registers a global middleware applied to every route.
221
220
  */
222
- private onAppActivated;
221
+ use(middleware: Middleware): this;
223
222
  /**
224
- * Shuts down the message channel for a specific sender ID.
225
- * This method closes the IPC channel for the specified sender ID and
226
- * removes it from the messagePorts map.
227
- * @param channelSenderId - The ID of the sender channel to shut down.
228
- * @param remove - Whether to remove the channel from the messagePorts map.
223
+ * Sets the application service (implements IApp) that receives lifecycle events.
224
+ * @param appClass - Class decorated with @Injectable that implements IApp.
229
225
  */
230
- private shutdownChannel;
226
+ configure(appClass: Type<IApp>): this;
231
227
  /**
232
- * Handles the application shutdown process.
233
- * This method is called when all windows are closed, and it cleans up the message channels
228
+ * Calls IApp.onReady(). Should be called after configure() and any lazy()
229
+ * registrations are set up.
234
230
  */
231
+ start(): this;
232
+ private readonly onRendererMessage;
233
+ private giveTheRendererAPort;
234
+ private onAppActivated;
235
235
  private onAllWindowsClosed;
236
+ private shutdownChannel;
237
+ }
238
+
239
+
240
+ /**
241
+ * A single route entry in the application routing table.
242
+ */
243
+ interface RouteDefinition {
236
244
  /**
237
- * Sets the main BrowserWindow that was created early by bootstrapApplication.
238
- * This window will be passed to IApp.onReady when start() is called.
239
- * @param window - The BrowserWindow created during bootstrap.
240
- */
241
- setMainWindow(window: BrowserWindow): void;
242
- /**
243
- * Configures the NoxApp instance with the provided application class.
244
- * This method allows you to set the application class that will handle lifecycle events.
245
- * @param app - The application class to configure.
246
- * @returns NoxApp instance for method chaining.
245
+ * The path prefix for this route (e.g. 'users', 'orders').
246
+ * All actions defined in the controller will be prefixed with this path.
247
247
  */
248
- configure(app: Type<IApp>): NoxApp;
248
+ path: string;
249
249
  /**
250
- * Registers a middleware for the root of the application.
251
- * This method allows you to define a middleware that will be applied to all requests
252
- * @param middleware - The middleware class to register.
253
- * @returns NoxApp instance for method chaining.
250
+ * Dynamic import function returning the controller file.
251
+ * The controller is loaded lazily on the first IPC request targeting this prefix.
252
+ *
253
+ * @example
254
+ * load: () => import('./modules/users/users.controller')
254
255
  */
255
- use(middleware: Type<IMiddleware>): NoxApp;
256
+ load: () => Promise<unknown>;
256
257
  /**
257
- * Should be called after the bootstrapApplication function is called.
258
- * Passes the early-created BrowserWindow (if any) to the configured IApp service.
259
- * @returns NoxApp instance for method chaining.
258
+ * Guards applied to every action in this controller.
259
+ * Merged with action-level guards.
260
260
  */
261
- start(): NoxApp;
262
- }
263
-
264
-
265
- /**
266
- * Options for bootstrapping the Noxus application.
267
- */
268
- interface BootstrapOptions {
261
+ guards?: Guard[];
269
262
  /**
270
- * If provided, Noxus creates a BrowserWindow immediately after Electron is ready,
271
- * before any DI processing occurs. This window is passed to the configured
272
- * IApp service via onReady(). It allows the user to see a window as fast as possible,
273
- * even before the application is fully initialized.
263
+ * Middlewares applied to every action in this controller.
264
+ * Merged with action-level middlewares.
274
265
  */
275
- window?: Electron.BrowserWindowConstructorOptions;
266
+ middlewares?: Middleware[];
276
267
  }
277
268
  /**
278
- * Bootstraps the Noxus application.
279
- * This function initializes the application by creating an instance of NoxApp,
280
- * registering the root module, and starting the application.
269
+ * Defines the application routing table.
270
+ * Each entry maps a path prefix to a lazily-loaded controller.
281
271
  *
282
- * When {@link BootstrapOptions.window} is provided, a BrowserWindow is created
283
- * immediately after Electron readiness before DI resolution — so the user
284
- * sees a window as quickly as possible.
272
+ * This is the single source of truth for routing — no path is declared
273
+ * in @Controller(), preventing duplicate route prefixes across controllers.
285
274
  *
286
- * @param rootModule - The root module of the application, decorated with @Module.
287
- * @param options - Optional bootstrap configuration.
288
- * @return A promise that resolves to the NoxApp instance.
289
- * @throws Error if the root module is not decorated with @Module, or if the electron process could not start.
275
+ * @example
276
+ * export const routes = defineRoutes([
277
+ * {
278
+ * path: 'users',
279
+ * load: () => import('./modules/users/users.controller'),
280
+ * guards: [authGuard],
281
+ * },
282
+ * {
283
+ * path: 'orders',
284
+ * load: () => import('./modules/orders/orders.controller'),
285
+ * guards: [authGuard],
286
+ * middlewares: [logMiddleware],
287
+ * },
288
+ * ]);
290
289
  */
291
- declare function bootstrapApplication(rootModule: Type<any>, options?: BootstrapOptions): Promise<NoxApp>;
290
+ declare function defineRoutes(routes: RouteDefinition[]): RouteDefinition[];
292
291
 
293
292
 
294
293
  /**
295
- * The configuration that waits a controller's decorator.
294
+ * A singleton value override: provides an already-constructed instance
295
+ * for a given token, bypassing the DI factory.
296
+ *
297
+ * Useful for injecting external singletons (e.g. a database connection,
298
+ * a logger already configured, a third-party SDK wrapper) that cannot
299
+ * or should not be constructed by the DI container.
300
+ *
301
+ * @example
302
+ * { token: MikroORM, useValue: await MikroORM.init(config) }
303
+ * { token: DB_URL, useValue: process.env.DATABASE_URL }
296
304
  */
297
- interface IControllerMetadata {
298
- path: string;
299
- guards: Type<IGuard>[];
305
+ interface SingletonOverride<T = unknown> {
306
+ token: TokenKey<T>;
307
+ useValue: T;
300
308
  }
301
309
  /**
302
- * Controller decorator is used to define a controller in the application.
303
- * It is a kind of node in the routing tree, that can contains routes and middlewares.
304
- *
305
- * @param path - The path for the controller.
310
+ * Configuration object for bootstrapApplication.
306
311
  */
307
- declare function Controller(path: string): ClassDecorator;
312
+ interface BootstrapConfig {
313
+ /**
314
+ * Application routing table, produced by defineRoutes().
315
+ * All lazy routes are registered before the app starts.
316
+ */
317
+ routes?: RouteDefinition[];
318
+ /**
319
+ * Pre-built singleton instances to inject into the DI container
320
+ * before the application starts.
321
+ *
322
+ * This replaces the v2 module/provider declaration pattern for
323
+ * external singletons.
324
+ *
325
+ * @example
326
+ * singletons: [
327
+ * { token: MikroORM, useValue: await MikroORM.init(ormConfig) },
328
+ * { token: DB_URL, useValue: process.env.DATABASE_URL! },
329
+ * ]
330
+ */
331
+ singletons?: SingletonOverride[];
332
+ /**
333
+ * Controllers and services to eagerly load before NoxApp.start() is called.
334
+ * Each entry is a dynamic import function — files are imported in parallel.
335
+ *
336
+ * Use this only for things needed at startup (e.g. if your IApp service
337
+ * depends on a service in an otherwise lazy module).
338
+ *
339
+ * Everything else should be registered via noxApp.lazy().
340
+ *
341
+ * @example
342
+ * eagerLoad: [
343
+ * () => import('./modules/auth/auth.controller.js'),
344
+ * ]
345
+ */
346
+ eagerLoad?: Array<() => Promise<unknown>>;
347
+ }
308
348
  /**
309
- * Gets the controller metadata for a given target class.
310
- * This metadata includes the path and guards defined by the @Controller decorator.
311
- * @param target - The target class to get the controller metadata from.
312
- * @returns The controller metadata if it exists, otherwise undefined.
349
+ * Bootstraps the Noxus application.
313
350
  */
314
- declare function getControllerMetadata(target: Type<unknown>): IControllerMetadata | undefined;
315
- declare const CONTROLLER_METADATA_KEY: unique symbol;
351
+ declare function bootstrapApplication(config?: BootstrapConfig): Promise<NoxApp>;
316
352
 
317
353
 
318
- interface IModuleMetadata {
319
- imports?: Type<unknown>[];
320
- exports?: Type<unknown>[];
321
- providers?: Type<unknown>[];
322
- controllers?: Type<unknown>[];
354
+ interface ControllerOptions {
355
+ /**
356
+ * Explicit constructor dependencies.
357
+ */
358
+ deps?: ReadonlyArray<TokenKey>;
359
+ }
360
+ interface IControllerMetadata {
361
+ deps: ReadonlyArray<TokenKey>;
323
362
  }
324
363
  /**
325
- * Module decorator is used to define a module in the application.
326
- * It is a kind of node in the routing tree, that can contains controllers, services, and other modules.
364
+ * Marks a class as a Noxus controller.
365
+ * Controllers are always scope-scoped injectables.
366
+ * The route prefix and guards/middlewares are declared in defineRoutes(), not here.
367
+ *
368
+ * @example
369
+ * @Controller({ deps: [UserService] })
370
+ * export class UserController {
371
+ * constructor(private svc: UserService) {}
327
372
  *
328
- * @param metadata - The metadata for the module.
373
+ * @Get('byId/:userId')
374
+ * getUserById(req: Request) { ... }
375
+ * }
329
376
  */
330
- declare function Module(metadata: IModuleMetadata): ClassDecorator;
331
- declare function getModuleMetadata(target: Function): IModuleMetadata | undefined;
332
- declare const MODULE_METADATA_KEY: unique symbol;
377
+ declare function Controller(options?: ControllerOptions): ClassDecorator;
378
+ declare function getControllerMetadata(target: object): IControllerMetadata | undefined;
333
379
 
334
-
335
- interface NoxusPreloadAPI extends IPortRequester {
380
+ interface RendererChannels {
381
+ request: Electron.MessageChannelMain;
382
+ socket: Electron.MessageChannelMain;
336
383
  }
337
- interface NoxusPreloadOptions {
338
- exposeAs?: string;
339
- initMessageType?: string;
340
- requestChannel?: string;
341
- responseChannel?: string;
342
- targetWindow?: Window;
384
+ declare class NoxSocket {
385
+ private readonly channels;
386
+ register(senderId: number, requestChannel: Electron.MessageChannelMain, socketChannel: Electron.MessageChannelMain): void;
387
+ get(senderId: number): RendererChannels | undefined;
388
+ unregister(senderId: number): void;
389
+ getSenderIds(): number[];
390
+ emit<TPayload = unknown>(eventName: string, payload?: TPayload, targetSenderIds?: number[]): number;
391
+ emitToRenderer<TPayload = unknown>(senderId: number, eventName: string, payload?: TPayload): boolean;
343
392
  }
344
- /**
345
- * Exposes a minimal bridge in the isolated preload context so renderer processes
346
- * can request the two MessagePorts required by Noxus. The bridge forwards both
347
- * request/response and socket ports to the renderer via window.postMessage.
348
- */
349
- declare function exposeNoxusBridge(options?: NoxusPreloadOptions): NoxusPreloadAPI;
350
393
 
351
- export { type BootstrapOptions, CONTROLLER_METADATA_KEY, Controller, type ControllerAction, type IApp, type IControllerMetadata, IGuard, type IMiddleware, type IModuleMetadata, IPortRequester, IResponse, type IRouteDefinition, MODULE_METADATA_KEY, MaybeAsync, Module, type NextFunction, NoxApp, NoxSocket, type NoxusPreloadAPI, type NoxusPreloadOptions, Request, Router, Type, UseMiddlewares, bootstrapApplication, exposeNoxusBridge, getControllerMetadata, getMiddlewaresForController, getMiddlewaresForControllerAction, getModuleMetadata };
394
+ export { type BootstrapConfig, Controller, type ControllerAction, type ControllerOptions, Guard, type IApp, type IControllerMetadata, type ILazyRoute, IResponse, type IRouteDefinition, Middleware, NoxApp, NoxSocket, Request, type RouteDefinition, Router, type SingletonOverride, TokenKey, Type, type WindowConfig, WindowManager, type WindowRecord, bootstrapApplication, defineRoutes, getControllerMetadata };