@noxfly/noxus 2.3.2 → 2.5.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.
package/dist/main.mjs CHANGED
@@ -726,41 +726,130 @@ var Logger;
726
726
  // src/DI/injector-explorer.ts
727
727
  var _InjectorExplorer = class _InjectorExplorer {
728
728
  /**
729
- * Registers the class as injectable.
730
- * When a class is instantiated, if it has dependencies and those dependencies
731
- * are listed using this method, they will be injected into the class constructor.
729
+ * Enqueues a class for deferred registration.
730
+ * Called by the @Injectable decorator at import time.
731
+ *
732
+ * If {@link processPending} has already been called (i.e. after bootstrap)
733
+ * and accumulation mode is not active, the class is registered immediately
734
+ * so that late dynamic imports (e.g. middlewares loaded after bootstrap)
735
+ * work correctly.
736
+ *
737
+ * When accumulation mode is active (between {@link beginAccumulate} and
738
+ * {@link flushAccumulated}), classes are queued instead — preserving the
739
+ * two-phase binding/resolution guarantee for lazy-loaded modules.
740
+ */
741
+ static enqueue(target, lifetime) {
742
+ if (_InjectorExplorer.processed && !_InjectorExplorer.accumulating) {
743
+ _InjectorExplorer.registerImmediate(target, lifetime);
744
+ return;
745
+ }
746
+ _InjectorExplorer.pending.push({
747
+ target,
748
+ lifetime
749
+ });
750
+ }
751
+ /**
752
+ * Enters accumulation mode. While active, all decorated classes discovered
753
+ * via dynamic imports are queued in {@link pending} rather than registered
754
+ * immediately. Call {@link flushAccumulated} to process them with the
755
+ * full two-phase (bind-then-resolve) guarantee.
756
+ */
757
+ static beginAccumulate() {
758
+ _InjectorExplorer.accumulating = true;
759
+ }
760
+ /**
761
+ * Exits accumulation mode and processes every class queued since
762
+ * {@link beginAccumulate} was called. Uses the same two-phase strategy
763
+ * as {@link processPending} (register all bindings first, then resolve
764
+ * singletons / controllers) so import ordering within a lazy batch
765
+ * does not cause resolution failures.
732
766
  */
733
- static register(target, lifetime) {
734
- if (RootInjector.bindings.has(target)) return RootInjector;
767
+ static flushAccumulated() {
768
+ _InjectorExplorer.accumulating = false;
769
+ const queue = [
770
+ ..._InjectorExplorer.pending
771
+ ];
772
+ _InjectorExplorer.pending.length = 0;
773
+ for (const { target, lifetime } of queue) {
774
+ if (!RootInjector.bindings.has(target)) {
775
+ RootInjector.bindings.set(target, {
776
+ implementation: target,
777
+ lifetime
778
+ });
779
+ }
780
+ }
781
+ for (const { target, lifetime } of queue) {
782
+ _InjectorExplorer.processRegistration(target, lifetime);
783
+ }
784
+ }
785
+ /**
786
+ * Processes all pending registrations in two phases:
787
+ * 1. Register all bindings (no instantiation) so every dependency is known.
788
+ * 2. Resolve singletons, register controllers and log module readiness.
789
+ *
790
+ * This two-phase approach makes the system resilient to import ordering:
791
+ * all bindings exist before any singleton is instantiated.
792
+ */
793
+ static processPending() {
794
+ const queue = _InjectorExplorer.pending;
795
+ for (const { target, lifetime } of queue) {
796
+ if (!RootInjector.bindings.has(target)) {
797
+ RootInjector.bindings.set(target, {
798
+ implementation: target,
799
+ lifetime
800
+ });
801
+ }
802
+ }
803
+ for (const { target, lifetime } of queue) {
804
+ _InjectorExplorer.processRegistration(target, lifetime);
805
+ }
806
+ queue.length = 0;
807
+ _InjectorExplorer.processed = true;
808
+ }
809
+ /**
810
+ * Registers a single class immediately (post-bootstrap path).
811
+ * Used for classes discovered via late dynamic imports.
812
+ */
813
+ static registerImmediate(target, lifetime) {
814
+ if (RootInjector.bindings.has(target)) {
815
+ return;
816
+ }
735
817
  RootInjector.bindings.set(target, {
736
818
  implementation: target,
737
819
  lifetime
738
820
  });
821
+ _InjectorExplorer.processRegistration(target, lifetime);
822
+ }
823
+ /**
824
+ * Performs phase-2 work for a single registration: resolve singletons,
825
+ * register controllers, and log module readiness.
826
+ */
827
+ static processRegistration(target, lifetime) {
739
828
  if (lifetime === "singleton") {
740
829
  RootInjector.resolve(target);
741
830
  }
742
831
  if (getModuleMetadata(target)) {
743
832
  Logger.log(`${target.name} dependencies initialized`);
744
- return RootInjector;
833
+ return;
745
834
  }
746
835
  const controllerMeta = getControllerMetadata(target);
747
836
  if (controllerMeta) {
748
837
  const router = RootInjector.resolve(Router);
749
838
  router?.registerController(target);
750
- return RootInjector;
839
+ return;
751
840
  }
752
- const routeMeta = getRouteMetadata(target);
753
- if (routeMeta) {
754
- return RootInjector;
841
+ if (getRouteMetadata(target).length > 0) {
842
+ return;
755
843
  }
756
844
  if (getInjectableMetadata(target)) {
757
845
  Logger.log(`Registered ${target.name} as ${lifetime}`);
758
- return RootInjector;
759
846
  }
760
- return RootInjector;
761
847
  }
762
848
  };
763
849
  __name(_InjectorExplorer, "InjectorExplorer");
850
+ __publicField(_InjectorExplorer, "pending", []);
851
+ __publicField(_InjectorExplorer, "processed", false);
852
+ __publicField(_InjectorExplorer, "accumulating", false);
764
853
  var InjectorExplorer = _InjectorExplorer;
765
854
 
766
855
  // src/decorators/injectable.decorator.ts
@@ -770,7 +859,7 @@ function Injectable(lifetime = "scope") {
770
859
  throw new Error(`@Injectable can only be used on classes, not on ${typeof target}`);
771
860
  }
772
861
  defineInjectableMetadata(target, lifetime);
773
- InjectorExplorer.register(target, lifetime);
862
+ InjectorExplorer.enqueue(target, lifetime);
774
863
  };
775
864
  }
776
865
  __name(Injectable, "Injectable");
@@ -1045,6 +1134,7 @@ var _Router = class _Router {
1045
1134
  constructor() {
1046
1135
  __publicField(this, "routes", new RadixTree());
1047
1136
  __publicField(this, "rootMiddlewares", []);
1137
+ __publicField(this, "lazyRoutes", /* @__PURE__ */ new Map());
1048
1138
  }
1049
1139
  /**
1050
1140
  * Registers a controller class with the router.
@@ -1092,6 +1182,24 @@ var _Router = class _Router {
1092
1182
  Logger.log(`Mapped ${controllerClass.name}${controllerGuardsInfo} controller's routes`);
1093
1183
  return this;
1094
1184
  }
1185
+ /**
1186
+ * Registers a lazy route. The module behind this route prefix will only
1187
+ * be imported (and its controllers/services registered in DI) the first
1188
+ * time a request targets this prefix.
1189
+ *
1190
+ * @param pathPrefix - Route prefix (e.g. "auth"). Matched against the first segment of the request path.
1191
+ * @param loadModule - A function that returns a dynamic import promise.
1192
+ */
1193
+ registerLazyRoute(pathPrefix, loadModule) {
1194
+ const normalized = pathPrefix.replace(/^\/+|\/+$/g, "");
1195
+ this.lazyRoutes.set(normalized, {
1196
+ loadModule,
1197
+ loading: null,
1198
+ loaded: false
1199
+ });
1200
+ Logger.log(`Registered lazy route prefix {${normalized}}`);
1201
+ return this;
1202
+ }
1095
1203
  /**
1096
1204
  * Defines a middleware for the root of the application.
1097
1205
  * This method allows you to register a middleware that will be applied to all requests
@@ -1124,7 +1232,7 @@ var _Router = class _Router {
1124
1232
  };
1125
1233
  let isCritical = false;
1126
1234
  try {
1127
- const routeDef = this.findRoute(request);
1235
+ const routeDef = await this.findRoute(request);
1128
1236
  await this.resolveController(request, response, routeDef);
1129
1237
  if (response.status > 400) {
1130
1238
  throw new ResponseException(response.status, response.error);
@@ -1282,16 +1390,62 @@ var _Router = class _Router {
1282
1390
  * @param request - The Request object containing the method and path to search for.
1283
1391
  * @returns The IRouteDefinition for the matched route.
1284
1392
  */
1285
- findRoute(request) {
1393
+ /**
1394
+ * Attempts to find a route definition for the given request.
1395
+ * Returns undefined instead of throwing when the route is not found,
1396
+ * so the caller can try lazy-loading first.
1397
+ */
1398
+ tryFindRoute(request) {
1286
1399
  const matchedRoutes = this.routes.search(request.path);
1287
1400
  if (matchedRoutes?.node === void 0 || matchedRoutes.node.children.length === 0) {
1288
- throw new NotFoundException(`No route matches ${request.method} ${request.path}`);
1401
+ return void 0;
1289
1402
  }
1290
1403
  const routeDef = matchedRoutes.node.findExactChild(request.method);
1291
- if (routeDef?.value === void 0) {
1292
- throw new MethodNotAllowedException(`Method Not Allowed for ${request.method} ${request.path}`);
1404
+ return routeDef?.value;
1405
+ }
1406
+ /**
1407
+ * Finds the route definition for a given request.
1408
+ * If no eagerly-registered route matches, attempts to load a lazy module
1409
+ * whose prefix matches the request path, then retries.
1410
+ */
1411
+ async findRoute(request) {
1412
+ const direct = this.tryFindRoute(request);
1413
+ if (direct) return direct;
1414
+ await this.tryLoadLazyRoute(request.path);
1415
+ const afterLazy = this.tryFindRoute(request);
1416
+ if (afterLazy) return afterLazy;
1417
+ throw new NotFoundException(`No route matches ${request.method} ${request.path}`);
1418
+ }
1419
+ /**
1420
+ * Given a request path, checks whether a lazy route prefix matches
1421
+ * and triggers the dynamic import if it hasn't been loaded yet.
1422
+ */
1423
+ async tryLoadLazyRoute(requestPath) {
1424
+ const firstSegment = requestPath.replace(/^\/+/, "").split("/")[0] ?? "";
1425
+ for (const [prefix, entry] of this.lazyRoutes) {
1426
+ if (entry.loaded) continue;
1427
+ const normalizedPath = requestPath.replace(/^\/+/, "");
1428
+ if (normalizedPath === prefix || normalizedPath.startsWith(prefix + "/") || firstSegment === prefix) {
1429
+ if (!entry.loading) {
1430
+ entry.loading = this.loadLazyModule(prefix, entry);
1431
+ }
1432
+ await entry.loading;
1433
+ return;
1434
+ }
1293
1435
  }
1294
- return routeDef.value;
1436
+ }
1437
+ /**
1438
+ * Dynamically imports a lazy module and registers its decorated classes
1439
+ * (controllers, services) in the DI container using the two-phase strategy.
1440
+ */
1441
+ async loadLazyModule(prefix, entry) {
1442
+ const t0 = performance.now();
1443
+ InjectorExplorer.beginAccumulate();
1444
+ await entry.loadModule();
1445
+ InjectorExplorer.flushAccumulated();
1446
+ entry.loaded = true;
1447
+ const t1 = performance.now();
1448
+ Logger.info(`Lazy-loaded module for prefix {${prefix}} in ${Math.round(t1 - t0)}ms`);
1295
1449
  }
1296
1450
  /**
1297
1451
  * Resolves the controller for a given route definition.
@@ -1492,6 +1646,7 @@ var _NoxApp = class _NoxApp {
1492
1646
  __publicField(this, "router");
1493
1647
  __publicField(this, "socket");
1494
1648
  __publicField(this, "app");
1649
+ __publicField(this, "mainWindow");
1495
1650
  /**
1496
1651
  *
1497
1652
  */
@@ -1598,6 +1753,48 @@ var _NoxApp = class _NoxApp {
1598
1753
  }
1599
1754
  }
1600
1755
  // ---
1756
+ /**
1757
+ * Sets the main BrowserWindow that was created early by bootstrapApplication.
1758
+ * This window will be passed to IApp.onReady when start() is called.
1759
+ * @param window - The BrowserWindow created during bootstrap.
1760
+ */
1761
+ setMainWindow(window) {
1762
+ this.mainWindow = window;
1763
+ }
1764
+ /**
1765
+ * Registers a lazy-loaded route. The module behind this path prefix
1766
+ * will only be dynamically imported when the first IPC request
1767
+ * targets this prefix — like Angular's loadChildren.
1768
+ *
1769
+ * @example
1770
+ * ```ts
1771
+ * noxApp.lazy("auth", () => import("./modules/auth/auth.module.js"));
1772
+ * noxApp.lazy("printing", () => import("./modules/printing/printing.module.js"));
1773
+ * ```
1774
+ *
1775
+ * @param pathPrefix - The route prefix (e.g. "auth", "cash-register").
1776
+ * @param loadModule - A function returning a dynamic import promise.
1777
+ * @returns NoxApp instance for method chaining.
1778
+ */
1779
+ lazy(pathPrefix, loadModule) {
1780
+ this.router.registerLazyRoute(pathPrefix, loadModule);
1781
+ return this;
1782
+ }
1783
+ /**
1784
+ * Eagerly loads one or more modules with a two-phase DI guarantee.
1785
+ * Use this when a service needed at startup lives inside a module
1786
+ * (e.g. the Application service depends on LoaderService).
1787
+ *
1788
+ * All dynamic imports run in parallel; bindings are registered first,
1789
+ * then singletons are resolved — safe regardless of import ordering.
1790
+ *
1791
+ * @param importFns - Functions returning dynamic import promises.
1792
+ */
1793
+ async loadModules(importFns) {
1794
+ InjectorExplorer.beginAccumulate();
1795
+ await Promise.all(importFns.map((fn) => fn()));
1796
+ InjectorExplorer.flushAccumulated();
1797
+ }
1601
1798
  /**
1602
1799
  * Configures the NoxApp instance with the provided application class.
1603
1800
  * This method allows you to set the application class that will handle lifecycle events.
@@ -1620,10 +1817,11 @@ var _NoxApp = class _NoxApp {
1620
1817
  }
1621
1818
  /**
1622
1819
  * Should be called after the bootstrapApplication function is called.
1820
+ * Passes the early-created BrowserWindow (if any) to the configured IApp service.
1623
1821
  * @returns NoxApp instance for method chaining.
1624
1822
  */
1625
1823
  start() {
1626
- this.app?.onReady();
1824
+ this.app?.onReady(this.mainWindow);
1627
1825
  return this;
1628
1826
  }
1629
1827
  };
@@ -1639,379 +1837,33 @@ NoxApp = _ts_decorate3([
1639
1837
  ], NoxApp);
1640
1838
 
1641
1839
  // src/bootstrap.ts
1642
- import { app as app2 } from "electron/main";
1643
- async function bootstrapApplication(rootModule) {
1644
- if (!getModuleMetadata(rootModule)) {
1840
+ import { app as app2, BrowserWindow as BrowserWindow2, screen } from "electron/main";
1841
+ async function bootstrapApplication(rootModule, options) {
1842
+ if (rootModule && !getModuleMetadata(rootModule)) {
1645
1843
  throw new Error(`Root module must be decorated with @Module`);
1646
1844
  }
1647
1845
  await app2.whenReady();
1648
- const noxApp = inject(NoxApp);
1649
- await noxApp.init();
1650
- return noxApp;
1651
- }
1652
- __name(bootstrapApplication, "bootstrapApplication");
1653
-
1654
- // src/preload-bridge.ts
1655
- import { contextBridge, ipcRenderer } from "electron/renderer";
1656
- var DEFAULT_EXPOSE_NAME = "noxus";
1657
- var DEFAULT_INIT_EVENT = "init-port";
1658
- var DEFAULT_REQUEST_CHANNEL = "gimme-my-port";
1659
- var DEFAULT_RESPONSE_CHANNEL = "port";
1660
- function exposeNoxusBridge(options = {}) {
1661
- const { exposeAs = DEFAULT_EXPOSE_NAME, initMessageType = DEFAULT_INIT_EVENT, requestChannel = DEFAULT_REQUEST_CHANNEL, responseChannel = DEFAULT_RESPONSE_CHANNEL, targetWindow = window } = options;
1662
- const api = {
1663
- requestPort: /* @__PURE__ */ __name(() => {
1664
- ipcRenderer.send(requestChannel);
1665
- ipcRenderer.once(responseChannel, (event, message) => {
1666
- const ports = (event.ports ?? []).filter((port) => port !== void 0);
1667
- if (ports.length === 0) {
1668
- console.error("[Noxus] No MessagePort received from main process.");
1669
- return;
1670
- }
1671
- for (const port of ports) {
1672
- try {
1673
- port.start();
1674
- } catch (error) {
1675
- console.error("[Noxus] Failed to start MessagePort.", error);
1676
- }
1677
- }
1678
- targetWindow.postMessage({
1679
- type: initMessageType,
1680
- senderId: message?.senderId
1681
- }, "*", ports);
1682
- });
1683
- }, "requestPort")
1684
- };
1685
- contextBridge.exposeInMainWorld(exposeAs, api);
1686
- return api;
1687
- }
1688
- __name(exposeNoxusBridge, "exposeNoxusBridge");
1689
-
1690
- // src/renderer-events.ts
1691
- var _RendererEventRegistry = class _RendererEventRegistry {
1692
- constructor() {
1693
- __publicField(this, "listeners", /* @__PURE__ */ new Map());
1694
- }
1695
- /**
1696
- *
1697
- */
1698
- subscribe(eventName, handler) {
1699
- const normalizedEventName = eventName.trim();
1700
- if (normalizedEventName.length === 0) {
1701
- throw new Error("Renderer event name must be a non-empty string.");
1702
- }
1703
- const handlers = this.listeners.get(normalizedEventName) ?? /* @__PURE__ */ new Set();
1704
- handlers.add(handler);
1705
- this.listeners.set(normalizedEventName, handlers);
1706
- return {
1707
- unsubscribe: /* @__PURE__ */ __name(() => this.unsubscribe(normalizedEventName, handler), "unsubscribe")
1708
- };
1709
- }
1710
- /**
1711
- *
1712
- */
1713
- unsubscribe(eventName, handler) {
1714
- const handlers = this.listeners.get(eventName);
1715
- if (!handlers) {
1716
- return;
1717
- }
1718
- handlers.delete(handler);
1719
- if (handlers.size === 0) {
1720
- this.listeners.delete(eventName);
1721
- }
1722
- }
1723
- /**
1724
- *
1725
- */
1726
- clear(eventName) {
1727
- if (eventName) {
1728
- this.listeners.delete(eventName);
1729
- return;
1730
- }
1731
- this.listeners.clear();
1732
- }
1733
- /**
1734
- *
1735
- */
1736
- dispatch(message) {
1737
- const handlers = this.listeners.get(message.event);
1738
- if (!handlers || handlers.size === 0) {
1739
- return;
1740
- }
1741
- handlers.forEach((handler) => {
1742
- try {
1743
- handler(message.payload);
1744
- } catch (error) {
1745
- console.error(`[Noxus] Renderer event handler for "${message.event}" threw an error.`, error);
1746
- }
1846
+ let mainWindow;
1847
+ if (options?.window) {
1848
+ mainWindow = new BrowserWindow2(options.window);
1849
+ mainWindow.once("ready-to-show", () => {
1850
+ mainWindow?.show();
1747
1851
  });
1748
- }
1749
- /**
1750
- *
1751
- */
1752
- tryDispatchFromMessageEvent(event) {
1753
- if (!isRendererEventMessage(event.data)) {
1754
- return false;
1852
+ const primaryDisplay = screen.getPrimaryDisplay();
1853
+ const { width, height } = primaryDisplay.workAreaSize;
1854
+ if (options.window.minWidth && options.window.minHeight) {
1855
+ mainWindow.setSize(Math.min(width, options.window.minWidth), Math.min(height, options.window.minHeight), true);
1755
1856
  }
1756
- this.dispatch(event.data);
1757
- return true;
1758
1857
  }
1759
- /**
1760
- *
1761
- */
1762
- hasHandlers(eventName) {
1763
- const handlers = this.listeners.get(eventName);
1764
- return !!handlers && handlers.size > 0;
1765
- }
1766
- };
1767
- __name(_RendererEventRegistry, "RendererEventRegistry");
1768
- var RendererEventRegistry = _RendererEventRegistry;
1769
-
1770
- // src/renderer-client.ts
1771
- var DEFAULT_INIT_EVENT2 = "init-port";
1772
- var DEFAULT_BRIDGE_NAMES = [
1773
- "noxus",
1774
- "ipcRenderer"
1775
- ];
1776
- function defaultRequestId() {
1777
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
1778
- return crypto.randomUUID();
1779
- }
1780
- return `${Date.now().toString(16)}-${Math.floor(Math.random() * 1e8).toString(16)}`;
1781
- }
1782
- __name(defaultRequestId, "defaultRequestId");
1783
- function normalizeBridgeNames(preferred) {
1784
- const names = [];
1785
- const add = /* @__PURE__ */ __name((name) => {
1786
- if (!name) return;
1787
- if (!names.includes(name)) {
1788
- names.push(name);
1789
- }
1790
- }, "add");
1791
- if (Array.isArray(preferred)) {
1792
- for (const name of preferred) {
1793
- add(name);
1794
- }
1795
- } else {
1796
- add(preferred);
1797
- }
1798
- for (const fallback of DEFAULT_BRIDGE_NAMES) {
1799
- add(fallback);
1800
- }
1801
- return names;
1802
- }
1803
- __name(normalizeBridgeNames, "normalizeBridgeNames");
1804
- function resolveBridgeFromWindow(windowRef, preferred) {
1805
- const names = normalizeBridgeNames(preferred);
1806
- const globalRef = windowRef;
1807
- if (!globalRef) {
1808
- return null;
1809
- }
1810
- for (const name of names) {
1811
- const candidate = globalRef[name];
1812
- if (candidate && typeof candidate.requestPort === "function") {
1813
- return candidate;
1814
- }
1858
+ InjectorExplorer.processPending();
1859
+ const noxApp = inject(NoxApp);
1860
+ if (mainWindow) {
1861
+ noxApp.setMainWindow(mainWindow);
1815
1862
  }
1816
- return null;
1863
+ await noxApp.init();
1864
+ return noxApp;
1817
1865
  }
1818
- __name(resolveBridgeFromWindow, "resolveBridgeFromWindow");
1819
- var _NoxRendererClient = class _NoxRendererClient {
1820
- constructor(options = {}) {
1821
- __publicField(this, "events", new RendererEventRegistry());
1822
- __publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
1823
- __publicField(this, "requestPort");
1824
- __publicField(this, "socketPort");
1825
- __publicField(this, "senderId");
1826
- __publicField(this, "bridge");
1827
- __publicField(this, "initMessageType");
1828
- __publicField(this, "windowRef");
1829
- __publicField(this, "generateRequestId");
1830
- __publicField(this, "isReady", false);
1831
- __publicField(this, "setupPromise");
1832
- __publicField(this, "setupResolve");
1833
- __publicField(this, "setupReject");
1834
- __publicField(this, "onWindowMessage", /* @__PURE__ */ __name((event) => {
1835
- if (event.data?.type !== this.initMessageType) {
1836
- return;
1837
- }
1838
- if (!Array.isArray(event.ports) || event.ports.length < 2) {
1839
- const error = new Error("[Noxus] Renderer expected two MessagePorts (request + socket).");
1840
- console.error(error);
1841
- this.setupReject?.(error);
1842
- this.resetSetupState();
1843
- return;
1844
- }
1845
- this.windowRef.removeEventListener("message", this.onWindowMessage);
1846
- this.requestPort = event.ports[0];
1847
- this.socketPort = event.ports[1];
1848
- this.senderId = event.data.senderId;
1849
- if (this.requestPort === void 0 || this.socketPort === void 0) {
1850
- const error = new Error("[Noxus] Renderer failed to receive valid MessagePorts.");
1851
- console.error(error);
1852
- this.setupReject?.(error);
1853
- this.resetSetupState();
1854
- return;
1855
- }
1856
- this.attachRequestPort(this.requestPort);
1857
- this.attachSocketPort(this.socketPort);
1858
- this.isReady = true;
1859
- this.setupResolve?.();
1860
- this.resetSetupState(true);
1861
- }, "onWindowMessage"));
1862
- __publicField(this, "onSocketMessage", /* @__PURE__ */ __name((event) => {
1863
- if (this.events.tryDispatchFromMessageEvent(event)) {
1864
- return;
1865
- }
1866
- console.warn("[Noxus] Received a socket message that is not a renderer event payload.", event.data);
1867
- }, "onSocketMessage"));
1868
- __publicField(this, "onRequestMessage", /* @__PURE__ */ __name((event) => {
1869
- if (this.events.tryDispatchFromMessageEvent(event)) {
1870
- return;
1871
- }
1872
- const response = event.data;
1873
- if (!response || typeof response.requestId !== "string") {
1874
- console.error("[Noxus] Renderer received an invalid response payload.", response);
1875
- return;
1876
- }
1877
- const pending = this.pendingRequests.get(response.requestId);
1878
- if (!pending) {
1879
- console.error(`[Noxus] No pending handler found for request ${response.requestId}.`);
1880
- return;
1881
- }
1882
- this.pendingRequests.delete(response.requestId);
1883
- this.onRequestCompleted(pending, response);
1884
- if (response.status >= 400) {
1885
- pending.reject(response);
1886
- return;
1887
- }
1888
- pending.resolve(response.body);
1889
- }, "onRequestMessage"));
1890
- this.windowRef = options.windowRef ?? window;
1891
- const resolvedBridge = options.bridge ?? resolveBridgeFromWindow(this.windowRef, options.bridgeName);
1892
- this.bridge = resolvedBridge ?? null;
1893
- this.initMessageType = options.initMessageType ?? DEFAULT_INIT_EVENT2;
1894
- this.generateRequestId = options.generateRequestId ?? defaultRequestId;
1895
- }
1896
- async setup() {
1897
- if (this.isReady) {
1898
- return Promise.resolve();
1899
- }
1900
- if (this.setupPromise) {
1901
- return this.setupPromise;
1902
- }
1903
- if (!this.bridge || typeof this.bridge.requestPort !== "function") {
1904
- throw new Error("[Noxus] Renderer bridge is missing requestPort().");
1905
- }
1906
- this.setupPromise = new Promise((resolve, reject) => {
1907
- this.setupResolve = resolve;
1908
- this.setupReject = reject;
1909
- });
1910
- this.windowRef.addEventListener("message", this.onWindowMessage);
1911
- this.bridge.requestPort();
1912
- return this.setupPromise;
1913
- }
1914
- dispose() {
1915
- this.windowRef.removeEventListener("message", this.onWindowMessage);
1916
- this.requestPort?.close();
1917
- this.socketPort?.close();
1918
- this.requestPort = void 0;
1919
- this.socketPort = void 0;
1920
- this.senderId = void 0;
1921
- this.isReady = false;
1922
- this.pendingRequests.clear();
1923
- }
1924
- async request(request) {
1925
- const senderId = this.senderId;
1926
- const requestId = this.generateRequestId();
1927
- if (senderId === void 0) {
1928
- return Promise.reject(this.createErrorResponse(requestId, "MessagePort is not available"));
1929
- }
1930
- const readinessError = this.validateReady(requestId);
1931
- if (readinessError) {
1932
- return Promise.reject(readinessError);
1933
- }
1934
- const message = {
1935
- requestId,
1936
- senderId,
1937
- ...request
1938
- };
1939
- return new Promise((resolve, reject) => {
1940
- const pending = {
1941
- resolve,
1942
- reject: /* @__PURE__ */ __name((response) => reject(response), "reject"),
1943
- request: message,
1944
- submittedAt: Date.now()
1945
- };
1946
- this.pendingRequests.set(message.requestId, pending);
1947
- this.requestPort.postMessage(message);
1948
- });
1949
- }
1950
- async batch(requests) {
1951
- return this.request({
1952
- method: "BATCH",
1953
- path: "",
1954
- body: {
1955
- requests
1956
- }
1957
- });
1958
- }
1959
- getSenderId() {
1960
- return this.senderId;
1961
- }
1962
- onRequestCompleted(pending, response) {
1963
- if (typeof console.groupCollapsed === "function") {
1964
- console.groupCollapsed(`${response.status} ${pending.request.method} /${pending.request.path}`);
1965
- }
1966
- if (response.error) {
1967
- console.error("error message:", response.error);
1968
- }
1969
- if (response.body !== void 0) {
1970
- console.info("response:", response.body);
1971
- }
1972
- console.info("request:", pending.request);
1973
- console.info(`Request duration: ${Date.now() - pending.submittedAt} ms`);
1974
- if (typeof console.groupCollapsed === "function") {
1975
- console.groupEnd();
1976
- }
1977
- }
1978
- attachRequestPort(port) {
1979
- port.onmessage = this.onRequestMessage;
1980
- port.start();
1981
- }
1982
- attachSocketPort(port) {
1983
- port.onmessage = this.onSocketMessage;
1984
- port.start();
1985
- }
1986
- validateReady(requestId) {
1987
- if (!this.isElectronEnvironment()) {
1988
- return this.createErrorResponse(requestId, "Not running in Electron environment");
1989
- }
1990
- if (!this.requestPort) {
1991
- return this.createErrorResponse(requestId, "MessagePort is not available");
1992
- }
1993
- return void 0;
1994
- }
1995
- createErrorResponse(requestId, message) {
1996
- return {
1997
- status: 500,
1998
- requestId,
1999
- error: message
2000
- };
2001
- }
2002
- resetSetupState(success = false) {
2003
- if (!success) {
2004
- this.setupPromise = void 0;
2005
- }
2006
- this.setupResolve = void 0;
2007
- this.setupReject = void 0;
2008
- }
2009
- isElectronEnvironment() {
2010
- return typeof window !== "undefined" && /Electron/.test(window.navigator.userAgent);
2011
- }
2012
- };
2013
- __name(_NoxRendererClient, "NoxRendererClient");
2014
- var NoxRendererClient = _NoxRendererClient;
1866
+ __name(bootstrapApplication, "bootstrapApplication");
2015
1867
  export {
2016
1868
  AppInjector,
2017
1869
  Authorize,
@@ -2044,7 +1896,6 @@ export {
2044
1896
  NotFoundException,
2045
1897
  NotImplementedException,
2046
1898
  NoxApp,
2047
- NoxRendererClient,
2048
1899
  NoxSocket,
2049
1900
  Patch,
2050
1901
  PaymentRequiredException,
@@ -2052,7 +1903,6 @@ export {
2052
1903
  Put,
2053
1904
  RENDERER_EVENT_TYPE,
2054
1905
  ROUTE_METADATA_KEY,
2055
- RendererEventRegistry,
2056
1906
  Request,
2057
1907
  RequestTimeoutException,
2058
1908
  ResponseException,
@@ -2066,7 +1916,6 @@ export {
2066
1916
  VariantAlsoNegotiatesException,
2067
1917
  bootstrapApplication,
2068
1918
  createRendererEventMessage,
2069
- exposeNoxusBridge,
2070
1919
  forwardRef,
2071
1920
  getControllerMetadata,
2072
1921
  getGuardForController,