@noxfly/noxus 1.2.0 → 2.0.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.
@@ -0,0 +1,32 @@
1
+ # Copilot Instructions
2
+ ## Core Architecture
3
+ - bootstrapApplication in [src/bootstrap.ts](src/bootstrap.ts) waits for Electron app readiness, resolves NoxApp via DI, and returns a configured instance.
4
+ - [src/app.ts](src/app.ts) wires ipcMain events, spawns paired request/socket MessageChannels per renderer, and delegates handling to Router and NoxSocket.
5
+ - Package exports are split between renderer and main targets in [package.json](package.json); import Electron main APIs from @noxfly/noxus/main and renderer helpers from @noxfly/noxus or @noxfly/noxus/renderer.
6
+ - Dependency injection centers on RootInjector in [src/DI/app-injector.ts](src/DI/app-injector.ts); @Injectable triggers auto-registration through [src/DI/injector-explorer.ts](src/DI/injector-explorer.ts) and supports singleton, scope, and transient lifetimes.
7
+ - Modules decorated via [src/decorators/module.decorator.ts](src/decorators/module.decorator.ts) compose providers, controllers, and nested modules; bootstrapApplication rejects roots lacking Module metadata.
8
+ ## Request Lifecycle
9
+ - Request objects from [src/request.ts](src/request.ts) wrap Electron MessageEvents and spawn per-request DI scopes on Request.context.
10
+ - Router in [src/router.ts](src/router.ts) indexes routes in a radix tree, merges controller-level and method-level decorators, and enforces root middlewares, route middlewares, then guards before invoking controller actions.
11
+ - ResponseException subclasses in [src/exceptions.ts](src/exceptions.ts) propagate status codes; throwing one short-circuits the pipeline so Router returns a structured error payload.
12
+ - Batch requests use HTTP method BATCH and normalization logic in Router.handleBatch; payloads must satisfy IBatchRequestPayload to fan out atomic subrequests.
13
+ ## Communication Channels
14
+ - ipcMain listens for gimme-my-port and posts two transferable ports back to the renderer: index 0 carries request/response traffic, index 1 is reserved for socket-style push messages.
15
+ - NoxSocket in [src/socket.ts](src/socket.ts) maps sender IDs to {request, socket} channels and emits renderer events exclusively through channels.socket.port1.
16
+ - Renderer helpers in [src/renderer-events.ts](src/renderer-events.ts) expose RendererEventRegistry.tryDispatchFromMessageEvent to route push events; the preload script must start both ports and hand the second to this registry.
17
+ - Renderer-facing bootstrap lives in [src/renderer-client.ts](src/renderer-client.ts); NoxRendererClient requests ports, wires request/socket handlers, tracks pending promises, and surfaces RendererEventRegistry for push consumption.
18
+ - Preload scripts should call exposeNoxusBridge from [src/preload-bridge.ts](src/preload-bridge.ts) to publish window.noxus.requestPort; the helper sends 'gimme-my-port' and forwards both transferable ports with the configured init message.
19
+ - When adjusting preload or renderer glue, ensure window.postMessage('init-port', ...) forwards both ports so the socket channel stays alive alongside the request channel.
20
+ ## Decorator Conventions
21
+ - Controller paths omit leading/trailing slashes; method decorators (Get, Post, etc.) auto-trim segments via [src/decorators/method.decorator.ts](src/decorators/method.decorator.ts).
22
+ - Guards registered through Authorize in [src/decorators/guards.decorator.ts](src/decorators/guards.decorator.ts) aggregate at controller and action scope; they must resolve truthy or Router throws UnauthorizedException.
23
+ - Injectable lifetimes default to scope; use singleton for app-wide utilities (window managers, sockets) and transient for short-lived resources.
24
+ ## Logging and Utilities
25
+ - Logger in [src/utils/logger.ts](src/utils/logger.ts) standardizes color-coded log, warn, error, and comment output; use it when extending framework behavior.
26
+ - Path resolution relies on RadixTree from [src/utils/radix-tree.ts](src/utils/radix-tree.ts); normalize controller and route paths to avoid duplicate slashes.
27
+ - Request.params are filled by Router.extractParams; controllers read route params directly from Request without decorator helpers yet.
28
+ ## Build and Tooling
29
+ - Run npm run build to invoke tsup with dual ESM/CJS outputs configured in [tsup.config.ts](tsup.config.ts); the postbuild script at [scripts/postbuild.js](scripts/postbuild.js) deduplicates license banners.
30
+ - Node 20 or newer is required; reflect-metadata is a peer dependency so host apps must install and import it before using decorators.
31
+ - Source uses baseUrl ./ with tsc-alias, so prefer absolute imports like src/module/file when editing framework code to match existing style.
32
+ - Dist artifacts live under dist/ and are published outputs; regenerate them via the build script rather than editing directly.
package/README.md CHANGED
@@ -34,20 +34,12 @@ Noxus fills that gap.
34
34
 
35
35
  ## Installation
36
36
 
37
- Install the package in your main process application :
37
+ Install the package in your main process application, and in your renderer as well :
38
38
 
39
39
  ```sh
40
40
  npm i @noxfly/noxus
41
41
  ```
42
42
 
43
- If you have a separated renderer from the main process, you'd like to install the package as well to get typed requests/responses models, for development purposes :
44
-
45
- ```sh
46
- npm i -D @noxfly/noxus
47
- ```
48
-
49
- Because you only need types during development, using the `-D` argument will make this package a `devDependency`, thus won't be present on your build.
50
-
51
43
  > ⚠️ The default entry (`@noxfly/noxus`) only exposes renderer-friendly helpers and types. Import Electron main-process APIs from `@noxfly/noxus/main`.
52
44
 
53
45
  ## Basic use
@@ -202,145 +194,62 @@ We need some configuration on the preload so the main process can give the rende
202
194
  ```ts
203
195
  // main/preload.ts
204
196
 
205
- import { contextBridge, ipcRenderer } from 'electron/renderer';
206
-
207
- // .invoke -> front sends to back
208
- // .on -> back sends to front
209
-
210
- type fn = (...args: any[]) => void;
197
+ import { exposeNoxusBridge } from '@noxfly/noxus';
211
198
 
212
- contextBridge.exposeInMainWorld('ipcRenderer', {
213
- requestPort: () => ipcRenderer.send('gimme-my-port'),
214
-
215
- hereIsMyPort: () => ipcRenderer.once('port', (e, message) => {
216
- e.ports[0]?.start();
217
- window.postMessage({ type: 'init-port', senderId: message.senderId }, '*', [e.ports[0]!]);
218
- }),
219
- });
199
+ exposeNoxusBridge();
220
200
  ```
221
201
 
222
- > ⚠️ As the Electron documentation warns well, you should NEVER expose the whole ipcRenderer to the renderer. Expose only restricted API that your renderer could use.
202
+ The helper uses `ipcRenderer.send('gimme-my-port')`, waits for the `'port'` response, starts both transferred `MessagePort`s, and forwards them to the renderer with `window.postMessage({ type: 'init-port', ... }, '*', [requestPort, socketPort])`. If you need to customise any channel names or the exposed property, pass `exposeNoxusBridge({ exposeAs: 'customNoxus', requestChannel: 'my-port', responseChannel: 'my-port-ready', initMessageType: 'custom-init' })`.
223
203
 
224
- We need to use `window.postMessage()` and not a custom callback function, otherwise the port would have been structuredCloned and would only arrive to the renderer with the `onmessage` function, and nothing else (a bit frustrating to not request, isn't it).
204
+ > ⚠️ As the Electron documentation warns, never expose the full `ipcRenderer` object. The helper only reveals a minimal `{ requestPort }` surface under `window.noxus` by default.
225
205
 
226
206
 
227
207
  ### Setup Renderer
228
208
 
229
- I am personnally using Angular as renderer, so there might be some changes if you use another framework or vanilla js, but it is only about typescript's configuration and types.
230
-
231
- Maybe this should become a class directly available from @noxfly/noxus;
209
+ Noxus ships with a `NoxRendererClient` helper that performs the renderer bootstrap: it asks the preload bridge for a port, expects two transferable `MessagePort`s (index `0` for request/response and index `1` for socket pushes), wires both, and exposes a promise-based `request`/`batch` API plus the `RendererEventRegistry` instance.
232
210
 
233
- ```ts
234
- // renderer/anyFileAtStartup.ts
211
+ By default it calls `window.noxus.requestPort()`—the value registered by `exposeNoxusBridge()`—but you can pass a custom bridge through the constructor options if needed.
235
212
 
236
- import { IRequest, IResponse } from '@noxfly/noxus';
213
+ Call `await client.setup()` early in your renderer startup (for example inside the first Angular service that needs IPC). Once the promise resolves, `client.request(...)` automatically includes the negotiated `senderId`, and socket events are routed through `client.events`.
237
214
 
238
- interface PendingRequestHandlers<T> {
239
- resolve: (value: IResponse<T>) => void;
240
- reject: (reason?: IResponse<T>) => void;
241
- request: IRequest;
242
- }
243
-
244
- // might be a singleton service
245
- class ElectronService {
246
- private readonly bridge: any;
247
- private readonly ipcRenderer: any; // if you know how to get a type, tell me
248
-
249
- private port: MessagePort | undefined;
250
- private senderId: number | undefined;
251
- private readonly pendingRequests = new Map<string, PendingRequestsHandlers<any>>();
252
-
253
- constructor() {
254
- this.bridge = window as any;
255
- this.ipcRenderer = this.bridge.ipcRenderer;
256
-
257
- // when receiving the port given by the main renderer -> preload -> renderer
258
- window.addEventListener('message', (event: MessageEvent) => {
259
- if(event.data?.type === 'init-port' && event.ports.length > 0) {
260
- this.port = event.ports[0]!;
261
- this.senderId = event.data.senderId;
262
- this.port.onmessage = onResponse;
263
- }
264
- });
265
-
266
- ipcRenderer.requestPort();
215
+ ```ts
216
+ // renderer/services/noxus.service.ts
217
+
218
+ import { Injectable } from '@angular/core';
219
+ import { from, Observable } from 'rxjs';
220
+ import {
221
+ IBatchRequestItem,
222
+ IBatchResponsePayload,
223
+ IRequest,
224
+ NoxRendererClient,
225
+ } from '@noxfly/noxus';
226
+
227
+ @Injectable({ providedIn: 'root' })
228
+ export class NoxusService extends NoxRendererClient {
229
+ public async init(): Promise<void> {
230
+ await this.setup();
267
231
  }
268
232
 
269
- /**
270
- * Resolve the signal-based response
271
- */
272
- private onResponse(event: MessageEvent): void {
273
- const response: IResponse<unknown> = event.data;
274
-
275
- if(!response || !response.requestId) {
276
- console.error('Received invalid response:', response);
277
- return;
278
- }
279
-
280
- const pending = this.pendingRequests.get(response.requestId);
281
-
282
- if(!pending) {
283
- console.error(`No handler found for request ID: ${response.requestId}`);
284
- return;
285
- }
286
-
287
- this.pendingRequests.delete(response.requestId);
288
-
289
- let fn: (response: IResponse<unknown>) => void = pending.resolve;
290
-
291
- console.groupCollapsed(`${response.status} ${pending.request.method} /${pending.request.path}`);
292
-
293
- if(response.error) {
294
- console.error('error message:', response.error);
295
- fn = pending.reject;
296
- }
297
-
298
- console.info('response:', response.body);
299
- console.info('request:', pending.request);
300
-
301
- console.groupEnd();
302
-
303
- fn(response);
233
+ public request$<T, U = unknown>(request: Omit<IRequest<U>, 'requestId' | 'senderId'>): Observable<T> {
234
+ return from(this.request<T, U>(request));
304
235
  }
305
236
 
306
- /**
307
- * Initiate a request to the main process
308
- */
309
- public request<T>(request: Omit<IRequest, 'requestId' | 'senderId'>): Promise<T> {
310
- return new Promise<T>((resolve, reject) => {
311
- if(!this.port || !this.senderId) {
312
- return reject(new Error("MessagePort is not available"));
313
- }
314
-
315
- const req: IRequest = {
316
- requestId: /* Create a random ID with the function of your choice */,
317
- senderId: this.senderId,
318
- ...request,
319
- };
320
-
321
- this.pendingRequests.set(req.requestId, {
322
- resolve: (response: IResponse<T>) => (response.status < 400)
323
- ? resolve(response.body as T)
324
- : reject(response);
325
- reject: (response?: IResponse<T>) => reject(response),
326
- request: req,
327
- });
328
-
329
- this.port.postMessage(req);
330
- });
237
+ public batch$<T = IBatchResponsePayload>(requests: Omit<IBatchRequestItem<unknown>, 'requestId'>[]): Observable<T> {
238
+ return from(this.batch(requests) as Promise<T>);
331
239
  }
332
240
  }
333
- ```
334
241
 
335
- Use it like that :
242
+ // Somewhere during app bootstrap
243
+ await noxusService.init();
336
244
 
337
- ```ts
338
- const response: User[] = await electronService.request<User[]>({
339
- method: 'GET',
340
- path: 'users/all',
245
+ // Subscribe to push notifications
246
+ const subscription = noxusService.events.subscribe('users.updated', (payload) => {
247
+ console.log('Users updated:', payload);
341
248
  });
342
249
  ```
343
250
 
251
+ If you need a custom bridge (for example a different preload shape), pass it via the constructor: `super({ bridge: window.customBridge })`. The class keeps promise-based semantics so frameworks can layer their own reactive wrappers as shown above.
252
+
344
253
  ![Startup image](./images/screenshot-requests.png)
345
254
 
346
255
 
@@ -354,7 +263,7 @@ If you throw any of these exception, the response to the renderer will contains
354
263
 
355
264
  You can specify a message in the constructor.
356
265
 
357
- You throw it as follow :
266
+ You throw it as follow :
358
267
  ```ts
359
268
  throw new UnauthorizedException("Invalid credentials");
360
269
  throw new BadRequestException("id is missing in the body");
@@ -176,13 +176,14 @@ declare const RootInjector: AppInjector;
176
176
  */
177
177
  declare class Request {
178
178
  readonly event: Electron.MessageEvent;
179
+ readonly senderId: number;
179
180
  readonly id: string;
180
181
  readonly method: HttpMethod;
181
182
  readonly path: string;
182
183
  readonly body: any;
183
184
  readonly context: AppInjector;
184
185
  readonly params: Record<string, string>;
185
- constructor(event: Electron.MessageEvent, id: string, method: HttpMethod, path: string, body: any);
186
+ constructor(event: Electron.MessageEvent, senderId: number, id: string, method: HttpMethod, path: string, body: any);
186
187
  }
187
188
  /**
188
189
  * The IRequest interface defines the structure of a request object.
@@ -265,4 +266,53 @@ declare class RendererEventRegistry {
265
266
  hasHandlers(eventName: string): boolean;
266
267
  }
267
268
 
268
- export { AppInjector as A, Delete as D, Get as G, type HttpMethod as H, type IResponse as I, type Lifetime as L, type MaybeAsync as M, Post as P, Request as R, type Type as T, type IGuard as a, type IBinding as b, RootInjector as c, Authorize as d, getGuardForControllerAction as e, type IRouteMetadata as f, getGuardForController as g, type AtomicHttpMethod as h, inject as i, getRouteMetadata as j, Put as k, Patch as l, ROUTE_METADATA_KEY as m, type IRequest as n, type IBatchRequestItem as o, type IBatchRequestPayload as p, type IBatchResponsePayload as q, RENDERER_EVENT_TYPE as r, type IRendererEventMessage as s, createRendererEventMessage as t, isRendererEventMessage as u, type RendererEventHandler as v, type RendererEventSubscription as w, RendererEventRegistry as x };
269
+
270
+ interface IPortRequester {
271
+ requestPort(): void;
272
+ }
273
+ interface RendererClientOptions {
274
+ bridge?: IPortRequester | null;
275
+ bridgeName?: string | string[];
276
+ initMessageType?: string;
277
+ windowRef?: Window;
278
+ generateRequestId?: () => string;
279
+ }
280
+ interface PendingRequest<T = unknown> {
281
+ resolve: (value: T) => void;
282
+ reject: (reason: IResponse<T>) => void;
283
+ request: IRequest;
284
+ submittedAt: number;
285
+ }
286
+ declare class NoxRendererClient {
287
+ readonly events: RendererEventRegistry;
288
+ protected readonly pendingRequests: Map<string, PendingRequest<unknown>>;
289
+ protected requestPort: MessagePort | undefined;
290
+ protected socketPort: MessagePort | undefined;
291
+ protected senderId: number | undefined;
292
+ private readonly bridge;
293
+ private readonly initMessageType;
294
+ private readonly windowRef;
295
+ private readonly generateRequestId;
296
+ private isReady;
297
+ private setupPromise;
298
+ private setupResolve;
299
+ private setupReject;
300
+ constructor(options?: RendererClientOptions);
301
+ setup(): Promise<void>;
302
+ dispose(): void;
303
+ request<TResponse, TBody = unknown>(request: Omit<IRequest<TBody>, 'requestId' | 'senderId'>): Promise<TResponse>;
304
+ batch(requests: Omit<IBatchRequestItem<unknown>, 'requestId'>[]): Promise<IBatchResponsePayload>;
305
+ getSenderId(): number | undefined;
306
+ private readonly onWindowMessage;
307
+ private readonly onSocketMessage;
308
+ private readonly onRequestMessage;
309
+ protected onRequestCompleted(pending: PendingRequest, response: IResponse): void;
310
+ private attachRequestPort;
311
+ private attachSocketPort;
312
+ private validateReady;
313
+ private createErrorResponse;
314
+ private resetSetupState;
315
+ isElectronEnvironment(): boolean;
316
+ }
317
+
318
+ export { AppInjector as A, Delete as D, Get as G, type HttpMethod as H, type IResponse as I, type Lifetime as L, type MaybeAsync as M, NoxRendererClient as N, Post as P, Request as R, type Type as T, type IGuard as a, type IPortRequester as b, type IBinding as c, RootInjector as d, Authorize as e, getGuardForControllerAction as f, getGuardForController as g, type IRouteMetadata as h, inject as i, type AtomicHttpMethod as j, getRouteMetadata as k, Put as l, Patch as m, ROUTE_METADATA_KEY as n, type IRequest as o, type IBatchRequestItem as p, type IBatchRequestPayload as q, type IBatchResponsePayload as r, RENDERER_EVENT_TYPE as s, type IRendererEventMessage as t, createRendererEventMessage as u, isRendererEventMessage as v, type RendererEventHandler as w, type RendererEventSubscription as x, RendererEventRegistry as y, type RendererClientOptions as z };
@@ -176,13 +176,14 @@ declare const RootInjector: AppInjector;
176
176
  */
177
177
  declare class Request {
178
178
  readonly event: Electron.MessageEvent;
179
+ readonly senderId: number;
179
180
  readonly id: string;
180
181
  readonly method: HttpMethod;
181
182
  readonly path: string;
182
183
  readonly body: any;
183
184
  readonly context: AppInjector;
184
185
  readonly params: Record<string, string>;
185
- constructor(event: Electron.MessageEvent, id: string, method: HttpMethod, path: string, body: any);
186
+ constructor(event: Electron.MessageEvent, senderId: number, id: string, method: HttpMethod, path: string, body: any);
186
187
  }
187
188
  /**
188
189
  * The IRequest interface defines the structure of a request object.
@@ -265,4 +266,53 @@ declare class RendererEventRegistry {
265
266
  hasHandlers(eventName: string): boolean;
266
267
  }
267
268
 
268
- export { AppInjector as A, Delete as D, Get as G, type HttpMethod as H, type IResponse as I, type Lifetime as L, type MaybeAsync as M, Post as P, Request as R, type Type as T, type IGuard as a, type IBinding as b, RootInjector as c, Authorize as d, getGuardForControllerAction as e, type IRouteMetadata as f, getGuardForController as g, type AtomicHttpMethod as h, inject as i, getRouteMetadata as j, Put as k, Patch as l, ROUTE_METADATA_KEY as m, type IRequest as n, type IBatchRequestItem as o, type IBatchRequestPayload as p, type IBatchResponsePayload as q, RENDERER_EVENT_TYPE as r, type IRendererEventMessage as s, createRendererEventMessage as t, isRendererEventMessage as u, type RendererEventHandler as v, type RendererEventSubscription as w, RendererEventRegistry as x };
269
+
270
+ interface IPortRequester {
271
+ requestPort(): void;
272
+ }
273
+ interface RendererClientOptions {
274
+ bridge?: IPortRequester | null;
275
+ bridgeName?: string | string[];
276
+ initMessageType?: string;
277
+ windowRef?: Window;
278
+ generateRequestId?: () => string;
279
+ }
280
+ interface PendingRequest<T = unknown> {
281
+ resolve: (value: T) => void;
282
+ reject: (reason: IResponse<T>) => void;
283
+ request: IRequest;
284
+ submittedAt: number;
285
+ }
286
+ declare class NoxRendererClient {
287
+ readonly events: RendererEventRegistry;
288
+ protected readonly pendingRequests: Map<string, PendingRequest<unknown>>;
289
+ protected requestPort: MessagePort | undefined;
290
+ protected socketPort: MessagePort | undefined;
291
+ protected senderId: number | undefined;
292
+ private readonly bridge;
293
+ private readonly initMessageType;
294
+ private readonly windowRef;
295
+ private readonly generateRequestId;
296
+ private isReady;
297
+ private setupPromise;
298
+ private setupResolve;
299
+ private setupReject;
300
+ constructor(options?: RendererClientOptions);
301
+ setup(): Promise<void>;
302
+ dispose(): void;
303
+ request<TResponse, TBody = unknown>(request: Omit<IRequest<TBody>, 'requestId' | 'senderId'>): Promise<TResponse>;
304
+ batch(requests: Omit<IBatchRequestItem<unknown>, 'requestId'>[]): Promise<IBatchResponsePayload>;
305
+ getSenderId(): number | undefined;
306
+ private readonly onWindowMessage;
307
+ private readonly onSocketMessage;
308
+ private readonly onRequestMessage;
309
+ protected onRequestCompleted(pending: PendingRequest, response: IResponse): void;
310
+ private attachRequestPort;
311
+ private attachSocketPort;
312
+ private validateReady;
313
+ private createErrorResponse;
314
+ private resetSetupState;
315
+ isElectronEnvironment(): boolean;
316
+ }
317
+
318
+ export { AppInjector as A, Delete as D, Get as G, type HttpMethod as H, type IResponse as I, type Lifetime as L, type MaybeAsync as M, NoxRendererClient as N, Post as P, Request as R, type Type as T, type IGuard as a, type IPortRequester as b, type IBinding as c, RootInjector as d, Authorize as e, getGuardForControllerAction as f, getGuardForController as g, type IRouteMetadata as h, inject as i, type AtomicHttpMethod as j, getRouteMetadata as k, Put as l, Patch as m, ROUTE_METADATA_KEY as n, type IRequest as o, type IBatchRequestItem as p, type IBatchRequestPayload as q, type IBatchResponsePayload as r, RENDERER_EVENT_TYPE as s, type IRendererEventMessage as t, createRendererEventMessage as u, isRendererEventMessage as v, type RendererEventHandler as w, type RendererEventSubscription as x, RendererEventRegistry as y, type RendererClientOptions as z };
package/dist/main.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as Request, I as IResponse, M as MaybeAsync, T as Type, a as IGuard, L as Lifetime } from './index-5OkVPHfI.mjs';
2
- export { A as AppInjector, h as AtomicHttpMethod, d as Authorize, D as Delete, G as Get, H as HttpMethod, o as IBatchRequestItem, p as IBatchRequestPayload, q as IBatchResponsePayload, b as IBinding, s as IRendererEventMessage, n as IRequest, f as IRouteMetadata, l as Patch, P as Post, k as Put, r as RENDERER_EVENT_TYPE, m as ROUTE_METADATA_KEY, v as RendererEventHandler, x as RendererEventRegistry, w as RendererEventSubscription, c as RootInjector, t as createRendererEventMessage, g as getGuardForController, e as getGuardForControllerAction, j as getRouteMetadata, i as inject, u as isRendererEventMessage } from './index-5OkVPHfI.mjs';
1
+ import { R as Request, I as IResponse, M as MaybeAsync, T as Type, a as IGuard, L as Lifetime, b as IPortRequester } from './index-CI3OMzNR.mjs';
2
+ export { A as AppInjector, j as AtomicHttpMethod, e as Authorize, D as Delete, G as Get, H as HttpMethod, p as IBatchRequestItem, q as IBatchRequestPayload, r as IBatchResponsePayload, c as IBinding, t as IRendererEventMessage, o as IRequest, h as IRouteMetadata, N as NoxRendererClient, m as Patch, P as Post, l as Put, s as RENDERER_EVENT_TYPE, n as ROUTE_METADATA_KEY, z as RendererClientOptions, w as RendererEventHandler, y as RendererEventRegistry, x as RendererEventSubscription, d as RootInjector, u as createRendererEventMessage, g as getGuardForController, f as getGuardForControllerAction, k as getRouteMetadata, i as inject, v as isRendererEventMessage } from './index-CI3OMzNR.mjs';
3
3
 
4
4
  /**
5
5
  * @copyright 2025 NoxFly
@@ -160,10 +160,14 @@ declare class Router {
160
160
  private extractParams;
161
161
  }
162
162
 
163
+ interface RendererChannels {
164
+ request: Electron.MessageChannelMain;
165
+ socket: Electron.MessageChannelMain;
166
+ }
163
167
  declare class NoxSocket {
164
- private readonly messagePorts;
165
- register(senderId: number, channel: Electron.MessageChannelMain): void;
166
- get(senderId: number): Electron.MessageChannelMain | undefined;
168
+ private readonly channels;
169
+ register(senderId: number, requestChannel: Electron.MessageChannelMain, socketChannel: Electron.MessageChannelMain): void;
170
+ get(senderId: number): RendererChannels | undefined;
167
171
  unregister(senderId: number): void;
168
172
  getSenderIds(): number[];
169
173
  emit<TPayload = unknown>(eventName: string, payload?: TPayload, targetSenderIds?: number[]): number;
@@ -189,6 +193,9 @@ declare class NoxApp {
189
193
  private readonly router;
190
194
  private readonly socket;
191
195
  private app;
196
+ /**
197
+ *
198
+ */
192
199
  private readonly onRendererMessage;
193
200
  constructor(router: Router, socket: NoxSocket);
194
201
  /**
@@ -352,6 +359,10 @@ declare function Controller(path: string): ClassDecorator;
352
359
  declare function getControllerMetadata(target: Type<unknown>): IControllerMetadata | undefined;
353
360
  declare const CONTROLLER_METADATA_KEY: unique symbol;
354
361
 
362
+ declare const INJECTABLE_METADATA_KEY: unique symbol;
363
+ declare function getInjectableMetadata(target: Function): Lifetime | undefined;
364
+ declare function hasInjectableMetadata(target: Function): boolean;
365
+
355
366
 
356
367
  /**
357
368
  * The Injectable decorator marks a class as injectable.
@@ -361,14 +372,6 @@ declare const CONTROLLER_METADATA_KEY: unique symbol;
361
372
  * @param lifetime - The lifetime of the injectable. Can be 'singleton', 'scope', or 'transient'.
362
373
  */
363
374
  declare function Injectable(lifetime?: Lifetime): ClassDecorator;
364
- /**
365
- * Gets the injectable metadata for a given target class.
366
- * This metadata includes the lifetime of the injectable defined by the @Injectable decorator.
367
- * @param target - The target class to get the injectable metadata from.
368
- * @returns The lifetime of the injectable if it exists, otherwise undefined.
369
- */
370
- declare function getInjectableMetadata(target: Type<unknown>): Lifetime | undefined;
371
- declare const INJECTABLE_METADATA_KEY: unique symbol;
372
375
 
373
376
 
374
377
  interface IModuleMetadata {
@@ -387,6 +390,23 @@ declare function Module(metadata: IModuleMetadata): ClassDecorator;
387
390
  declare function getModuleMetadata(target: Function): IModuleMetadata | undefined;
388
391
  declare const MODULE_METADATA_KEY: unique symbol;
389
392
 
393
+
394
+ interface NoxusPreloadAPI extends IPortRequester {
395
+ }
396
+ interface NoxusPreloadOptions {
397
+ exposeAs?: string;
398
+ initMessageType?: string;
399
+ requestChannel?: string;
400
+ responseChannel?: string;
401
+ targetWindow?: Window;
402
+ }
403
+ /**
404
+ * Exposes a minimal bridge in the isolated preload context so renderer processes
405
+ * can request the two MessagePorts required by Noxus. The bridge forwards both
406
+ * request/response and socket ports to the renderer via window.postMessage.
407
+ */
408
+ declare function exposeNoxusBridge(options?: NoxusPreloadOptions): NoxusPreloadAPI;
409
+
390
410
  /**
391
411
  * Logger is a utility class for logging messages to the console.
392
412
  */
@@ -462,4 +482,4 @@ declare namespace Logger {
462
482
  };
463
483
  }
464
484
 
465
- export { BadGatewayException, BadRequestException, CONTROLLER_METADATA_KEY, ConflictException, Controller, type ControllerAction, ForbiddenException, GatewayTimeoutException, HttpVersionNotSupportedException, type IApp, type IControllerMetadata, IGuard, type IMiddleware, type IModuleMetadata, INJECTABLE_METADATA_KEY, IResponse, type IRouteDefinition, Injectable, InsufficientStorageException, InternalServerException, Lifetime, type LogLevel, Logger, LoopDetectedException, MODULE_METADATA_KEY, MaybeAsync, MethodNotAllowedException, Module, NetworkAuthenticationRequiredException, NetworkConnectTimeoutException, type NextFunction, NotAcceptableException, NotExtendedException, NotFoundException, NotImplementedException, NoxApp, NoxSocket, PaymentRequiredException, Request, RequestTimeoutException, ResponseException, Router, ServiceUnavailableException, TooManyRequestsException, Type, UnauthorizedException, UpgradeRequiredException, UseMiddlewares, VariantAlsoNegotiatesException, bootstrapApplication, getControllerMetadata, getInjectableMetadata, getMiddlewaresForController, getMiddlewaresForControllerAction, getModuleMetadata };
485
+ export { BadGatewayException, BadRequestException, CONTROLLER_METADATA_KEY, ConflictException, Controller, type ControllerAction, ForbiddenException, GatewayTimeoutException, HttpVersionNotSupportedException, type IApp, type IControllerMetadata, IGuard, type IMiddleware, type IModuleMetadata, INJECTABLE_METADATA_KEY, IPortRequester, IResponse, type IRouteDefinition, Injectable, InsufficientStorageException, InternalServerException, Lifetime, type LogLevel, Logger, LoopDetectedException, MODULE_METADATA_KEY, MaybeAsync, MethodNotAllowedException, Module, NetworkAuthenticationRequiredException, NetworkConnectTimeoutException, type NextFunction, NotAcceptableException, NotExtendedException, NotFoundException, NotImplementedException, NoxApp, NoxSocket, type NoxusPreloadAPI, type NoxusPreloadOptions, PaymentRequiredException, Request, RequestTimeoutException, ResponseException, Router, ServiceUnavailableException, TooManyRequestsException, Type, UnauthorizedException, UpgradeRequiredException, UseMiddlewares, VariantAlsoNegotiatesException, bootstrapApplication, exposeNoxusBridge, getControllerMetadata, getInjectableMetadata, getMiddlewaresForController, getMiddlewaresForControllerAction, getModuleMetadata, hasInjectableMetadata };
package/dist/main.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as Request, I as IResponse, M as MaybeAsync, T as Type, a as IGuard, L as Lifetime } from './index-5OkVPHfI.js';
2
- export { A as AppInjector, h as AtomicHttpMethod, d as Authorize, D as Delete, G as Get, H as HttpMethod, o as IBatchRequestItem, p as IBatchRequestPayload, q as IBatchResponsePayload, b as IBinding, s as IRendererEventMessage, n as IRequest, f as IRouteMetadata, l as Patch, P as Post, k as Put, r as RENDERER_EVENT_TYPE, m as ROUTE_METADATA_KEY, v as RendererEventHandler, x as RendererEventRegistry, w as RendererEventSubscription, c as RootInjector, t as createRendererEventMessage, g as getGuardForController, e as getGuardForControllerAction, j as getRouteMetadata, i as inject, u as isRendererEventMessage } from './index-5OkVPHfI.js';
1
+ import { R as Request, I as IResponse, M as MaybeAsync, T as Type, a as IGuard, L as Lifetime, b as IPortRequester } from './index-CI3OMzNR.js';
2
+ export { A as AppInjector, j as AtomicHttpMethod, e as Authorize, D as Delete, G as Get, H as HttpMethod, p as IBatchRequestItem, q as IBatchRequestPayload, r as IBatchResponsePayload, c as IBinding, t as IRendererEventMessage, o as IRequest, h as IRouteMetadata, N as NoxRendererClient, m as Patch, P as Post, l as Put, s as RENDERER_EVENT_TYPE, n as ROUTE_METADATA_KEY, z as RendererClientOptions, w as RendererEventHandler, y as RendererEventRegistry, x as RendererEventSubscription, d as RootInjector, u as createRendererEventMessage, g as getGuardForController, f as getGuardForControllerAction, k as getRouteMetadata, i as inject, v as isRendererEventMessage } from './index-CI3OMzNR.js';
3
3
 
4
4
  /**
5
5
  * @copyright 2025 NoxFly
@@ -160,10 +160,14 @@ declare class Router {
160
160
  private extractParams;
161
161
  }
162
162
 
163
+ interface RendererChannels {
164
+ request: Electron.MessageChannelMain;
165
+ socket: Electron.MessageChannelMain;
166
+ }
163
167
  declare class NoxSocket {
164
- private readonly messagePorts;
165
- register(senderId: number, channel: Electron.MessageChannelMain): void;
166
- get(senderId: number): Electron.MessageChannelMain | undefined;
168
+ private readonly channels;
169
+ register(senderId: number, requestChannel: Electron.MessageChannelMain, socketChannel: Electron.MessageChannelMain): void;
170
+ get(senderId: number): RendererChannels | undefined;
167
171
  unregister(senderId: number): void;
168
172
  getSenderIds(): number[];
169
173
  emit<TPayload = unknown>(eventName: string, payload?: TPayload, targetSenderIds?: number[]): number;
@@ -189,6 +193,9 @@ declare class NoxApp {
189
193
  private readonly router;
190
194
  private readonly socket;
191
195
  private app;
196
+ /**
197
+ *
198
+ */
192
199
  private readonly onRendererMessage;
193
200
  constructor(router: Router, socket: NoxSocket);
194
201
  /**
@@ -352,6 +359,10 @@ declare function Controller(path: string): ClassDecorator;
352
359
  declare function getControllerMetadata(target: Type<unknown>): IControllerMetadata | undefined;
353
360
  declare const CONTROLLER_METADATA_KEY: unique symbol;
354
361
 
362
+ declare const INJECTABLE_METADATA_KEY: unique symbol;
363
+ declare function getInjectableMetadata(target: Function): Lifetime | undefined;
364
+ declare function hasInjectableMetadata(target: Function): boolean;
365
+
355
366
 
356
367
  /**
357
368
  * The Injectable decorator marks a class as injectable.
@@ -361,14 +372,6 @@ declare const CONTROLLER_METADATA_KEY: unique symbol;
361
372
  * @param lifetime - The lifetime of the injectable. Can be 'singleton', 'scope', or 'transient'.
362
373
  */
363
374
  declare function Injectable(lifetime?: Lifetime): ClassDecorator;
364
- /**
365
- * Gets the injectable metadata for a given target class.
366
- * This metadata includes the lifetime of the injectable defined by the @Injectable decorator.
367
- * @param target - The target class to get the injectable metadata from.
368
- * @returns The lifetime of the injectable if it exists, otherwise undefined.
369
- */
370
- declare function getInjectableMetadata(target: Type<unknown>): Lifetime | undefined;
371
- declare const INJECTABLE_METADATA_KEY: unique symbol;
372
375
 
373
376
 
374
377
  interface IModuleMetadata {
@@ -387,6 +390,23 @@ declare function Module(metadata: IModuleMetadata): ClassDecorator;
387
390
  declare function getModuleMetadata(target: Function): IModuleMetadata | undefined;
388
391
  declare const MODULE_METADATA_KEY: unique symbol;
389
392
 
393
+
394
+ interface NoxusPreloadAPI extends IPortRequester {
395
+ }
396
+ interface NoxusPreloadOptions {
397
+ exposeAs?: string;
398
+ initMessageType?: string;
399
+ requestChannel?: string;
400
+ responseChannel?: string;
401
+ targetWindow?: Window;
402
+ }
403
+ /**
404
+ * Exposes a minimal bridge in the isolated preload context so renderer processes
405
+ * can request the two MessagePorts required by Noxus. The bridge forwards both
406
+ * request/response and socket ports to the renderer via window.postMessage.
407
+ */
408
+ declare function exposeNoxusBridge(options?: NoxusPreloadOptions): NoxusPreloadAPI;
409
+
390
410
  /**
391
411
  * Logger is a utility class for logging messages to the console.
392
412
  */
@@ -462,4 +482,4 @@ declare namespace Logger {
462
482
  };
463
483
  }
464
484
 
465
- export { BadGatewayException, BadRequestException, CONTROLLER_METADATA_KEY, ConflictException, Controller, type ControllerAction, ForbiddenException, GatewayTimeoutException, HttpVersionNotSupportedException, type IApp, type IControllerMetadata, IGuard, type IMiddleware, type IModuleMetadata, INJECTABLE_METADATA_KEY, IResponse, type IRouteDefinition, Injectable, InsufficientStorageException, InternalServerException, Lifetime, type LogLevel, Logger, LoopDetectedException, MODULE_METADATA_KEY, MaybeAsync, MethodNotAllowedException, Module, NetworkAuthenticationRequiredException, NetworkConnectTimeoutException, type NextFunction, NotAcceptableException, NotExtendedException, NotFoundException, NotImplementedException, NoxApp, NoxSocket, PaymentRequiredException, Request, RequestTimeoutException, ResponseException, Router, ServiceUnavailableException, TooManyRequestsException, Type, UnauthorizedException, UpgradeRequiredException, UseMiddlewares, VariantAlsoNegotiatesException, bootstrapApplication, getControllerMetadata, getInjectableMetadata, getMiddlewaresForController, getMiddlewaresForControllerAction, getModuleMetadata };
485
+ export { BadGatewayException, BadRequestException, CONTROLLER_METADATA_KEY, ConflictException, Controller, type ControllerAction, ForbiddenException, GatewayTimeoutException, HttpVersionNotSupportedException, type IApp, type IControllerMetadata, IGuard, type IMiddleware, type IModuleMetadata, INJECTABLE_METADATA_KEY, IPortRequester, IResponse, type IRouteDefinition, Injectable, InsufficientStorageException, InternalServerException, Lifetime, type LogLevel, Logger, LoopDetectedException, MODULE_METADATA_KEY, MaybeAsync, MethodNotAllowedException, Module, NetworkAuthenticationRequiredException, NetworkConnectTimeoutException, type NextFunction, NotAcceptableException, NotExtendedException, NotFoundException, NotImplementedException, NoxApp, NoxSocket, type NoxusPreloadAPI, type NoxusPreloadOptions, PaymentRequiredException, Request, RequestTimeoutException, ResponseException, Router, ServiceUnavailableException, TooManyRequestsException, Type, UnauthorizedException, UpgradeRequiredException, UseMiddlewares, VariantAlsoNegotiatesException, bootstrapApplication, exposeNoxusBridge, getControllerMetadata, getInjectableMetadata, getMiddlewaresForController, getMiddlewaresForControllerAction, getModuleMetadata, hasInjectableMetadata };