@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.js CHANGED
@@ -69,7 +69,6 @@ __export(main_exports, {
69
69
  NotFoundException: () => NotFoundException,
70
70
  NotImplementedException: () => NotImplementedException,
71
71
  NoxApp: () => NoxApp,
72
- NoxRendererClient: () => NoxRendererClient,
73
72
  NoxSocket: () => NoxSocket,
74
73
  Patch: () => Patch,
75
74
  PaymentRequiredException: () => PaymentRequiredException,
@@ -77,7 +76,6 @@ __export(main_exports, {
77
76
  Put: () => Put,
78
77
  RENDERER_EVENT_TYPE: () => RENDERER_EVENT_TYPE,
79
78
  ROUTE_METADATA_KEY: () => ROUTE_METADATA_KEY,
80
- RendererEventRegistry: () => RendererEventRegistry,
81
79
  Request: () => Request,
82
80
  RequestTimeoutException: () => RequestTimeoutException,
83
81
  ResponseException: () => ResponseException,
@@ -91,7 +89,6 @@ __export(main_exports, {
91
89
  VariantAlsoNegotiatesException: () => VariantAlsoNegotiatesException,
92
90
  bootstrapApplication: () => bootstrapApplication,
93
91
  createRendererEventMessage: () => createRendererEventMessage,
94
- exposeNoxusBridge: () => exposeNoxusBridge,
95
92
  forwardRef: () => forwardRef,
96
93
  getControllerMetadata: () => getControllerMetadata,
97
94
  getGuardForController: () => getGuardForController,
@@ -825,41 +822,130 @@ var Logger;
825
822
  // src/DI/injector-explorer.ts
826
823
  var _InjectorExplorer = class _InjectorExplorer {
827
824
  /**
828
- * Registers the class as injectable.
829
- * When a class is instantiated, if it has dependencies and those dependencies
830
- * are listed using this method, they will be injected into the class constructor.
825
+ * Enqueues a class for deferred registration.
826
+ * Called by the @Injectable decorator at import time.
827
+ *
828
+ * If {@link processPending} has already been called (i.e. after bootstrap)
829
+ * and accumulation mode is not active, the class is registered immediately
830
+ * so that late dynamic imports (e.g. middlewares loaded after bootstrap)
831
+ * work correctly.
832
+ *
833
+ * When accumulation mode is active (between {@link beginAccumulate} and
834
+ * {@link flushAccumulated}), classes are queued instead — preserving the
835
+ * two-phase binding/resolution guarantee for lazy-loaded modules.
836
+ */
837
+ static enqueue(target, lifetime) {
838
+ if (_InjectorExplorer.processed && !_InjectorExplorer.accumulating) {
839
+ _InjectorExplorer.registerImmediate(target, lifetime);
840
+ return;
841
+ }
842
+ _InjectorExplorer.pending.push({
843
+ target,
844
+ lifetime
845
+ });
846
+ }
847
+ /**
848
+ * Enters accumulation mode. While active, all decorated classes discovered
849
+ * via dynamic imports are queued in {@link pending} rather than registered
850
+ * immediately. Call {@link flushAccumulated} to process them with the
851
+ * full two-phase (bind-then-resolve) guarantee.
852
+ */
853
+ static beginAccumulate() {
854
+ _InjectorExplorer.accumulating = true;
855
+ }
856
+ /**
857
+ * Exits accumulation mode and processes every class queued since
858
+ * {@link beginAccumulate} was called. Uses the same two-phase strategy
859
+ * as {@link processPending} (register all bindings first, then resolve
860
+ * singletons / controllers) so import ordering within a lazy batch
861
+ * does not cause resolution failures.
831
862
  */
832
- static register(target, lifetime) {
833
- if (RootInjector.bindings.has(target)) return RootInjector;
863
+ static flushAccumulated() {
864
+ _InjectorExplorer.accumulating = false;
865
+ const queue = [
866
+ ..._InjectorExplorer.pending
867
+ ];
868
+ _InjectorExplorer.pending.length = 0;
869
+ for (const { target, lifetime } of queue) {
870
+ if (!RootInjector.bindings.has(target)) {
871
+ RootInjector.bindings.set(target, {
872
+ implementation: target,
873
+ lifetime
874
+ });
875
+ }
876
+ }
877
+ for (const { target, lifetime } of queue) {
878
+ _InjectorExplorer.processRegistration(target, lifetime);
879
+ }
880
+ }
881
+ /**
882
+ * Processes all pending registrations in two phases:
883
+ * 1. Register all bindings (no instantiation) so every dependency is known.
884
+ * 2. Resolve singletons, register controllers and log module readiness.
885
+ *
886
+ * This two-phase approach makes the system resilient to import ordering:
887
+ * all bindings exist before any singleton is instantiated.
888
+ */
889
+ static processPending() {
890
+ const queue = _InjectorExplorer.pending;
891
+ for (const { target, lifetime } of queue) {
892
+ if (!RootInjector.bindings.has(target)) {
893
+ RootInjector.bindings.set(target, {
894
+ implementation: target,
895
+ lifetime
896
+ });
897
+ }
898
+ }
899
+ for (const { target, lifetime } of queue) {
900
+ _InjectorExplorer.processRegistration(target, lifetime);
901
+ }
902
+ queue.length = 0;
903
+ _InjectorExplorer.processed = true;
904
+ }
905
+ /**
906
+ * Registers a single class immediately (post-bootstrap path).
907
+ * Used for classes discovered via late dynamic imports.
908
+ */
909
+ static registerImmediate(target, lifetime) {
910
+ if (RootInjector.bindings.has(target)) {
911
+ return;
912
+ }
834
913
  RootInjector.bindings.set(target, {
835
914
  implementation: target,
836
915
  lifetime
837
916
  });
917
+ _InjectorExplorer.processRegistration(target, lifetime);
918
+ }
919
+ /**
920
+ * Performs phase-2 work for a single registration: resolve singletons,
921
+ * register controllers, and log module readiness.
922
+ */
923
+ static processRegistration(target, lifetime) {
838
924
  if (lifetime === "singleton") {
839
925
  RootInjector.resolve(target);
840
926
  }
841
927
  if (getModuleMetadata(target)) {
842
928
  Logger.log(`${target.name} dependencies initialized`);
843
- return RootInjector;
929
+ return;
844
930
  }
845
931
  const controllerMeta = getControllerMetadata(target);
846
932
  if (controllerMeta) {
847
933
  const router = RootInjector.resolve(Router);
848
934
  router?.registerController(target);
849
- return RootInjector;
935
+ return;
850
936
  }
851
- const routeMeta = getRouteMetadata(target);
852
- if (routeMeta) {
853
- return RootInjector;
937
+ if (getRouteMetadata(target).length > 0) {
938
+ return;
854
939
  }
855
940
  if (getInjectableMetadata(target)) {
856
941
  Logger.log(`Registered ${target.name} as ${lifetime}`);
857
- return RootInjector;
858
942
  }
859
- return RootInjector;
860
943
  }
861
944
  };
862
945
  __name(_InjectorExplorer, "InjectorExplorer");
946
+ __publicField(_InjectorExplorer, "pending", []);
947
+ __publicField(_InjectorExplorer, "processed", false);
948
+ __publicField(_InjectorExplorer, "accumulating", false);
863
949
  var InjectorExplorer = _InjectorExplorer;
864
950
 
865
951
  // src/decorators/injectable.decorator.ts
@@ -869,7 +955,7 @@ function Injectable(lifetime = "scope") {
869
955
  throw new Error(`@Injectable can only be used on classes, not on ${typeof target}`);
870
956
  }
871
957
  defineInjectableMetadata(target, lifetime);
872
- InjectorExplorer.register(target, lifetime);
958
+ InjectorExplorer.enqueue(target, lifetime);
873
959
  };
874
960
  }
875
961
  __name(Injectable, "Injectable");
@@ -1144,6 +1230,7 @@ var _Router = class _Router {
1144
1230
  constructor() {
1145
1231
  __publicField(this, "routes", new RadixTree());
1146
1232
  __publicField(this, "rootMiddlewares", []);
1233
+ __publicField(this, "lazyRoutes", /* @__PURE__ */ new Map());
1147
1234
  }
1148
1235
  /**
1149
1236
  * Registers a controller class with the router.
@@ -1191,6 +1278,24 @@ var _Router = class _Router {
1191
1278
  Logger.log(`Mapped ${controllerClass.name}${controllerGuardsInfo} controller's routes`);
1192
1279
  return this;
1193
1280
  }
1281
+ /**
1282
+ * Registers a lazy route. The module behind this route prefix will only
1283
+ * be imported (and its controllers/services registered in DI) the first
1284
+ * time a request targets this prefix.
1285
+ *
1286
+ * @param pathPrefix - Route prefix (e.g. "auth"). Matched against the first segment of the request path.
1287
+ * @param loadModule - A function that returns a dynamic import promise.
1288
+ */
1289
+ registerLazyRoute(pathPrefix, loadModule) {
1290
+ const normalized = pathPrefix.replace(/^\/+|\/+$/g, "");
1291
+ this.lazyRoutes.set(normalized, {
1292
+ loadModule,
1293
+ loading: null,
1294
+ loaded: false
1295
+ });
1296
+ Logger.log(`Registered lazy route prefix {${normalized}}`);
1297
+ return this;
1298
+ }
1194
1299
  /**
1195
1300
  * Defines a middleware for the root of the application.
1196
1301
  * This method allows you to register a middleware that will be applied to all requests
@@ -1223,7 +1328,7 @@ var _Router = class _Router {
1223
1328
  };
1224
1329
  let isCritical = false;
1225
1330
  try {
1226
- const routeDef = this.findRoute(request);
1331
+ const routeDef = await this.findRoute(request);
1227
1332
  await this.resolveController(request, response, routeDef);
1228
1333
  if (response.status > 400) {
1229
1334
  throw new ResponseException(response.status, response.error);
@@ -1381,16 +1486,62 @@ var _Router = class _Router {
1381
1486
  * @param request - The Request object containing the method and path to search for.
1382
1487
  * @returns The IRouteDefinition for the matched route.
1383
1488
  */
1384
- findRoute(request) {
1489
+ /**
1490
+ * Attempts to find a route definition for the given request.
1491
+ * Returns undefined instead of throwing when the route is not found,
1492
+ * so the caller can try lazy-loading first.
1493
+ */
1494
+ tryFindRoute(request) {
1385
1495
  const matchedRoutes = this.routes.search(request.path);
1386
1496
  if (matchedRoutes?.node === void 0 || matchedRoutes.node.children.length === 0) {
1387
- throw new NotFoundException(`No route matches ${request.method} ${request.path}`);
1497
+ return void 0;
1388
1498
  }
1389
1499
  const routeDef = matchedRoutes.node.findExactChild(request.method);
1390
- if (routeDef?.value === void 0) {
1391
- throw new MethodNotAllowedException(`Method Not Allowed for ${request.method} ${request.path}`);
1500
+ return routeDef?.value;
1501
+ }
1502
+ /**
1503
+ * Finds the route definition for a given request.
1504
+ * If no eagerly-registered route matches, attempts to load a lazy module
1505
+ * whose prefix matches the request path, then retries.
1506
+ */
1507
+ async findRoute(request) {
1508
+ const direct = this.tryFindRoute(request);
1509
+ if (direct) return direct;
1510
+ await this.tryLoadLazyRoute(request.path);
1511
+ const afterLazy = this.tryFindRoute(request);
1512
+ if (afterLazy) return afterLazy;
1513
+ throw new NotFoundException(`No route matches ${request.method} ${request.path}`);
1514
+ }
1515
+ /**
1516
+ * Given a request path, checks whether a lazy route prefix matches
1517
+ * and triggers the dynamic import if it hasn't been loaded yet.
1518
+ */
1519
+ async tryLoadLazyRoute(requestPath) {
1520
+ const firstSegment = requestPath.replace(/^\/+/, "").split("/")[0] ?? "";
1521
+ for (const [prefix, entry] of this.lazyRoutes) {
1522
+ if (entry.loaded) continue;
1523
+ const normalizedPath = requestPath.replace(/^\/+/, "");
1524
+ if (normalizedPath === prefix || normalizedPath.startsWith(prefix + "/") || firstSegment === prefix) {
1525
+ if (!entry.loading) {
1526
+ entry.loading = this.loadLazyModule(prefix, entry);
1527
+ }
1528
+ await entry.loading;
1529
+ return;
1530
+ }
1392
1531
  }
1393
- return routeDef.value;
1532
+ }
1533
+ /**
1534
+ * Dynamically imports a lazy module and registers its decorated classes
1535
+ * (controllers, services) in the DI container using the two-phase strategy.
1536
+ */
1537
+ async loadLazyModule(prefix, entry) {
1538
+ const t0 = performance.now();
1539
+ InjectorExplorer.beginAccumulate();
1540
+ await entry.loadModule();
1541
+ InjectorExplorer.flushAccumulated();
1542
+ entry.loaded = true;
1543
+ const t1 = performance.now();
1544
+ Logger.info(`Lazy-loaded module for prefix {${prefix}} in ${Math.round(t1 - t0)}ms`);
1394
1545
  }
1395
1546
  /**
1396
1547
  * Resolves the controller for a given route definition.
@@ -1591,6 +1742,7 @@ var _NoxApp = class _NoxApp {
1591
1742
  __publicField(this, "router");
1592
1743
  __publicField(this, "socket");
1593
1744
  __publicField(this, "app");
1745
+ __publicField(this, "mainWindow");
1594
1746
  /**
1595
1747
  *
1596
1748
  */
@@ -1697,6 +1849,48 @@ var _NoxApp = class _NoxApp {
1697
1849
  }
1698
1850
  }
1699
1851
  // ---
1852
+ /**
1853
+ * Sets the main BrowserWindow that was created early by bootstrapApplication.
1854
+ * This window will be passed to IApp.onReady when start() is called.
1855
+ * @param window - The BrowserWindow created during bootstrap.
1856
+ */
1857
+ setMainWindow(window) {
1858
+ this.mainWindow = window;
1859
+ }
1860
+ /**
1861
+ * Registers a lazy-loaded route. The module behind this path prefix
1862
+ * will only be dynamically imported when the first IPC request
1863
+ * targets this prefix — like Angular's loadChildren.
1864
+ *
1865
+ * @example
1866
+ * ```ts
1867
+ * noxApp.lazy("auth", () => import("./modules/auth/auth.module.js"));
1868
+ * noxApp.lazy("printing", () => import("./modules/printing/printing.module.js"));
1869
+ * ```
1870
+ *
1871
+ * @param pathPrefix - The route prefix (e.g. "auth", "cash-register").
1872
+ * @param loadModule - A function returning a dynamic import promise.
1873
+ * @returns NoxApp instance for method chaining.
1874
+ */
1875
+ lazy(pathPrefix, loadModule) {
1876
+ this.router.registerLazyRoute(pathPrefix, loadModule);
1877
+ return this;
1878
+ }
1879
+ /**
1880
+ * Eagerly loads one or more modules with a two-phase DI guarantee.
1881
+ * Use this when a service needed at startup lives inside a module
1882
+ * (e.g. the Application service depends on LoaderService).
1883
+ *
1884
+ * All dynamic imports run in parallel; bindings are registered first,
1885
+ * then singletons are resolved — safe regardless of import ordering.
1886
+ *
1887
+ * @param importFns - Functions returning dynamic import promises.
1888
+ */
1889
+ async loadModules(importFns) {
1890
+ InjectorExplorer.beginAccumulate();
1891
+ await Promise.all(importFns.map((fn) => fn()));
1892
+ InjectorExplorer.flushAccumulated();
1893
+ }
1700
1894
  /**
1701
1895
  * Configures the NoxApp instance with the provided application class.
1702
1896
  * This method allows you to set the application class that will handle lifecycle events.
@@ -1719,10 +1913,11 @@ var _NoxApp = class _NoxApp {
1719
1913
  }
1720
1914
  /**
1721
1915
  * Should be called after the bootstrapApplication function is called.
1916
+ * Passes the early-created BrowserWindow (if any) to the configured IApp service.
1722
1917
  * @returns NoxApp instance for method chaining.
1723
1918
  */
1724
1919
  start() {
1725
- this.app?.onReady();
1920
+ this.app?.onReady(this.mainWindow);
1726
1921
  return this;
1727
1922
  }
1728
1923
  };
@@ -1739,378 +1934,32 @@ NoxApp = _ts_decorate3([
1739
1934
 
1740
1935
  // src/bootstrap.ts
1741
1936
  var import_main2 = require("electron/main");
1742
- async function bootstrapApplication(rootModule) {
1743
- if (!getModuleMetadata(rootModule)) {
1937
+ async function bootstrapApplication(rootModule, options) {
1938
+ if (rootModule && !getModuleMetadata(rootModule)) {
1744
1939
  throw new Error(`Root module must be decorated with @Module`);
1745
1940
  }
1746
1941
  await import_main2.app.whenReady();
1747
- const noxApp = inject(NoxApp);
1748
- await noxApp.init();
1749
- return noxApp;
1750
- }
1751
- __name(bootstrapApplication, "bootstrapApplication");
1752
-
1753
- // src/preload-bridge.ts
1754
- var import_renderer = require("electron/renderer");
1755
- var DEFAULT_EXPOSE_NAME = "noxus";
1756
- var DEFAULT_INIT_EVENT = "init-port";
1757
- var DEFAULT_REQUEST_CHANNEL = "gimme-my-port";
1758
- var DEFAULT_RESPONSE_CHANNEL = "port";
1759
- function exposeNoxusBridge(options = {}) {
1760
- const { exposeAs = DEFAULT_EXPOSE_NAME, initMessageType = DEFAULT_INIT_EVENT, requestChannel = DEFAULT_REQUEST_CHANNEL, responseChannel = DEFAULT_RESPONSE_CHANNEL, targetWindow = window } = options;
1761
- const api = {
1762
- requestPort: /* @__PURE__ */ __name(() => {
1763
- import_renderer.ipcRenderer.send(requestChannel);
1764
- import_renderer.ipcRenderer.once(responseChannel, (event, message) => {
1765
- const ports = (event.ports ?? []).filter((port) => port !== void 0);
1766
- if (ports.length === 0) {
1767
- console.error("[Noxus] No MessagePort received from main process.");
1768
- return;
1769
- }
1770
- for (const port of ports) {
1771
- try {
1772
- port.start();
1773
- } catch (error) {
1774
- console.error("[Noxus] Failed to start MessagePort.", error);
1775
- }
1776
- }
1777
- targetWindow.postMessage({
1778
- type: initMessageType,
1779
- senderId: message?.senderId
1780
- }, "*", ports);
1781
- });
1782
- }, "requestPort")
1783
- };
1784
- import_renderer.contextBridge.exposeInMainWorld(exposeAs, api);
1785
- return api;
1786
- }
1787
- __name(exposeNoxusBridge, "exposeNoxusBridge");
1788
-
1789
- // src/renderer-events.ts
1790
- var _RendererEventRegistry = class _RendererEventRegistry {
1791
- constructor() {
1792
- __publicField(this, "listeners", /* @__PURE__ */ new Map());
1793
- }
1794
- /**
1795
- *
1796
- */
1797
- subscribe(eventName, handler) {
1798
- const normalizedEventName = eventName.trim();
1799
- if (normalizedEventName.length === 0) {
1800
- throw new Error("Renderer event name must be a non-empty string.");
1801
- }
1802
- const handlers = this.listeners.get(normalizedEventName) ?? /* @__PURE__ */ new Set();
1803
- handlers.add(handler);
1804
- this.listeners.set(normalizedEventName, handlers);
1805
- return {
1806
- unsubscribe: /* @__PURE__ */ __name(() => this.unsubscribe(normalizedEventName, handler), "unsubscribe")
1807
- };
1808
- }
1809
- /**
1810
- *
1811
- */
1812
- unsubscribe(eventName, handler) {
1813
- const handlers = this.listeners.get(eventName);
1814
- if (!handlers) {
1815
- return;
1816
- }
1817
- handlers.delete(handler);
1818
- if (handlers.size === 0) {
1819
- this.listeners.delete(eventName);
1820
- }
1821
- }
1822
- /**
1823
- *
1824
- */
1825
- clear(eventName) {
1826
- if (eventName) {
1827
- this.listeners.delete(eventName);
1828
- return;
1829
- }
1830
- this.listeners.clear();
1831
- }
1832
- /**
1833
- *
1834
- */
1835
- dispatch(message) {
1836
- const handlers = this.listeners.get(message.event);
1837
- if (!handlers || handlers.size === 0) {
1838
- return;
1839
- }
1840
- handlers.forEach((handler) => {
1841
- try {
1842
- handler(message.payload);
1843
- } catch (error) {
1844
- console.error(`[Noxus] Renderer event handler for "${message.event}" threw an error.`, error);
1845
- }
1942
+ let mainWindow;
1943
+ if (options?.window) {
1944
+ mainWindow = new import_main2.BrowserWindow(options.window);
1945
+ mainWindow.once("ready-to-show", () => {
1946
+ mainWindow?.show();
1846
1947
  });
1847
- }
1848
- /**
1849
- *
1850
- */
1851
- tryDispatchFromMessageEvent(event) {
1852
- if (!isRendererEventMessage(event.data)) {
1853
- return false;
1948
+ const primaryDisplay = import_main2.screen.getPrimaryDisplay();
1949
+ const { width, height } = primaryDisplay.workAreaSize;
1950
+ if (options.window.minWidth && options.window.minHeight) {
1951
+ mainWindow.setSize(Math.min(width, options.window.minWidth), Math.min(height, options.window.minHeight), true);
1854
1952
  }
1855
- this.dispatch(event.data);
1856
- return true;
1857
1953
  }
1858
- /**
1859
- *
1860
- */
1861
- hasHandlers(eventName) {
1862
- const handlers = this.listeners.get(eventName);
1863
- return !!handlers && handlers.size > 0;
1864
- }
1865
- };
1866
- __name(_RendererEventRegistry, "RendererEventRegistry");
1867
- var RendererEventRegistry = _RendererEventRegistry;
1868
-
1869
- // src/renderer-client.ts
1870
- var DEFAULT_INIT_EVENT2 = "init-port";
1871
- var DEFAULT_BRIDGE_NAMES = [
1872
- "noxus",
1873
- "ipcRenderer"
1874
- ];
1875
- function defaultRequestId() {
1876
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
1877
- return crypto.randomUUID();
1878
- }
1879
- return `${Date.now().toString(16)}-${Math.floor(Math.random() * 1e8).toString(16)}`;
1880
- }
1881
- __name(defaultRequestId, "defaultRequestId");
1882
- function normalizeBridgeNames(preferred) {
1883
- const names = [];
1884
- const add = /* @__PURE__ */ __name((name) => {
1885
- if (!name) return;
1886
- if (!names.includes(name)) {
1887
- names.push(name);
1888
- }
1889
- }, "add");
1890
- if (Array.isArray(preferred)) {
1891
- for (const name of preferred) {
1892
- add(name);
1893
- }
1894
- } else {
1895
- add(preferred);
1896
- }
1897
- for (const fallback of DEFAULT_BRIDGE_NAMES) {
1898
- add(fallback);
1899
- }
1900
- return names;
1901
- }
1902
- __name(normalizeBridgeNames, "normalizeBridgeNames");
1903
- function resolveBridgeFromWindow(windowRef, preferred) {
1904
- const names = normalizeBridgeNames(preferred);
1905
- const globalRef = windowRef;
1906
- if (!globalRef) {
1907
- return null;
1908
- }
1909
- for (const name of names) {
1910
- const candidate = globalRef[name];
1911
- if (candidate && typeof candidate.requestPort === "function") {
1912
- return candidate;
1913
- }
1954
+ InjectorExplorer.processPending();
1955
+ const noxApp = inject(NoxApp);
1956
+ if (mainWindow) {
1957
+ noxApp.setMainWindow(mainWindow);
1914
1958
  }
1915
- return null;
1959
+ await noxApp.init();
1960
+ return noxApp;
1916
1961
  }
1917
- __name(resolveBridgeFromWindow, "resolveBridgeFromWindow");
1918
- var _NoxRendererClient = class _NoxRendererClient {
1919
- constructor(options = {}) {
1920
- __publicField(this, "events", new RendererEventRegistry());
1921
- __publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
1922
- __publicField(this, "requestPort");
1923
- __publicField(this, "socketPort");
1924
- __publicField(this, "senderId");
1925
- __publicField(this, "bridge");
1926
- __publicField(this, "initMessageType");
1927
- __publicField(this, "windowRef");
1928
- __publicField(this, "generateRequestId");
1929
- __publicField(this, "isReady", false);
1930
- __publicField(this, "setupPromise");
1931
- __publicField(this, "setupResolve");
1932
- __publicField(this, "setupReject");
1933
- __publicField(this, "onWindowMessage", /* @__PURE__ */ __name((event) => {
1934
- if (event.data?.type !== this.initMessageType) {
1935
- return;
1936
- }
1937
- if (!Array.isArray(event.ports) || event.ports.length < 2) {
1938
- const error = new Error("[Noxus] Renderer expected two MessagePorts (request + socket).");
1939
- console.error(error);
1940
- this.setupReject?.(error);
1941
- this.resetSetupState();
1942
- return;
1943
- }
1944
- this.windowRef.removeEventListener("message", this.onWindowMessage);
1945
- this.requestPort = event.ports[0];
1946
- this.socketPort = event.ports[1];
1947
- this.senderId = event.data.senderId;
1948
- if (this.requestPort === void 0 || this.socketPort === void 0) {
1949
- const error = new Error("[Noxus] Renderer failed to receive valid MessagePorts.");
1950
- console.error(error);
1951
- this.setupReject?.(error);
1952
- this.resetSetupState();
1953
- return;
1954
- }
1955
- this.attachRequestPort(this.requestPort);
1956
- this.attachSocketPort(this.socketPort);
1957
- this.isReady = true;
1958
- this.setupResolve?.();
1959
- this.resetSetupState(true);
1960
- }, "onWindowMessage"));
1961
- __publicField(this, "onSocketMessage", /* @__PURE__ */ __name((event) => {
1962
- if (this.events.tryDispatchFromMessageEvent(event)) {
1963
- return;
1964
- }
1965
- console.warn("[Noxus] Received a socket message that is not a renderer event payload.", event.data);
1966
- }, "onSocketMessage"));
1967
- __publicField(this, "onRequestMessage", /* @__PURE__ */ __name((event) => {
1968
- if (this.events.tryDispatchFromMessageEvent(event)) {
1969
- return;
1970
- }
1971
- const response = event.data;
1972
- if (!response || typeof response.requestId !== "string") {
1973
- console.error("[Noxus] Renderer received an invalid response payload.", response);
1974
- return;
1975
- }
1976
- const pending = this.pendingRequests.get(response.requestId);
1977
- if (!pending) {
1978
- console.error(`[Noxus] No pending handler found for request ${response.requestId}.`);
1979
- return;
1980
- }
1981
- this.pendingRequests.delete(response.requestId);
1982
- this.onRequestCompleted(pending, response);
1983
- if (response.status >= 400) {
1984
- pending.reject(response);
1985
- return;
1986
- }
1987
- pending.resolve(response.body);
1988
- }, "onRequestMessage"));
1989
- this.windowRef = options.windowRef ?? window;
1990
- const resolvedBridge = options.bridge ?? resolveBridgeFromWindow(this.windowRef, options.bridgeName);
1991
- this.bridge = resolvedBridge ?? null;
1992
- this.initMessageType = options.initMessageType ?? DEFAULT_INIT_EVENT2;
1993
- this.generateRequestId = options.generateRequestId ?? defaultRequestId;
1994
- }
1995
- async setup() {
1996
- if (this.isReady) {
1997
- return Promise.resolve();
1998
- }
1999
- if (this.setupPromise) {
2000
- return this.setupPromise;
2001
- }
2002
- if (!this.bridge || typeof this.bridge.requestPort !== "function") {
2003
- throw new Error("[Noxus] Renderer bridge is missing requestPort().");
2004
- }
2005
- this.setupPromise = new Promise((resolve, reject) => {
2006
- this.setupResolve = resolve;
2007
- this.setupReject = reject;
2008
- });
2009
- this.windowRef.addEventListener("message", this.onWindowMessage);
2010
- this.bridge.requestPort();
2011
- return this.setupPromise;
2012
- }
2013
- dispose() {
2014
- this.windowRef.removeEventListener("message", this.onWindowMessage);
2015
- this.requestPort?.close();
2016
- this.socketPort?.close();
2017
- this.requestPort = void 0;
2018
- this.socketPort = void 0;
2019
- this.senderId = void 0;
2020
- this.isReady = false;
2021
- this.pendingRequests.clear();
2022
- }
2023
- async request(request) {
2024
- const senderId = this.senderId;
2025
- const requestId = this.generateRequestId();
2026
- if (senderId === void 0) {
2027
- return Promise.reject(this.createErrorResponse(requestId, "MessagePort is not available"));
2028
- }
2029
- const readinessError = this.validateReady(requestId);
2030
- if (readinessError) {
2031
- return Promise.reject(readinessError);
2032
- }
2033
- const message = {
2034
- requestId,
2035
- senderId,
2036
- ...request
2037
- };
2038
- return new Promise((resolve, reject) => {
2039
- const pending = {
2040
- resolve,
2041
- reject: /* @__PURE__ */ __name((response) => reject(response), "reject"),
2042
- request: message,
2043
- submittedAt: Date.now()
2044
- };
2045
- this.pendingRequests.set(message.requestId, pending);
2046
- this.requestPort.postMessage(message);
2047
- });
2048
- }
2049
- async batch(requests) {
2050
- return this.request({
2051
- method: "BATCH",
2052
- path: "",
2053
- body: {
2054
- requests
2055
- }
2056
- });
2057
- }
2058
- getSenderId() {
2059
- return this.senderId;
2060
- }
2061
- onRequestCompleted(pending, response) {
2062
- if (typeof console.groupCollapsed === "function") {
2063
- console.groupCollapsed(`${response.status} ${pending.request.method} /${pending.request.path}`);
2064
- }
2065
- if (response.error) {
2066
- console.error("error message:", response.error);
2067
- }
2068
- if (response.body !== void 0) {
2069
- console.info("response:", response.body);
2070
- }
2071
- console.info("request:", pending.request);
2072
- console.info(`Request duration: ${Date.now() - pending.submittedAt} ms`);
2073
- if (typeof console.groupCollapsed === "function") {
2074
- console.groupEnd();
2075
- }
2076
- }
2077
- attachRequestPort(port) {
2078
- port.onmessage = this.onRequestMessage;
2079
- port.start();
2080
- }
2081
- attachSocketPort(port) {
2082
- port.onmessage = this.onSocketMessage;
2083
- port.start();
2084
- }
2085
- validateReady(requestId) {
2086
- if (!this.isElectronEnvironment()) {
2087
- return this.createErrorResponse(requestId, "Not running in Electron environment");
2088
- }
2089
- if (!this.requestPort) {
2090
- return this.createErrorResponse(requestId, "MessagePort is not available");
2091
- }
2092
- return void 0;
2093
- }
2094
- createErrorResponse(requestId, message) {
2095
- return {
2096
- status: 500,
2097
- requestId,
2098
- error: message
2099
- };
2100
- }
2101
- resetSetupState(success = false) {
2102
- if (!success) {
2103
- this.setupPromise = void 0;
2104
- }
2105
- this.setupResolve = void 0;
2106
- this.setupReject = void 0;
2107
- }
2108
- isElectronEnvironment() {
2109
- return typeof window !== "undefined" && /Electron/.test(window.navigator.userAgent);
2110
- }
2111
- };
2112
- __name(_NoxRendererClient, "NoxRendererClient");
2113
- var NoxRendererClient = _NoxRendererClient;
1962
+ __name(bootstrapApplication, "bootstrapApplication");
2114
1963
  // Annotate the CommonJS export names for ESM import in node:
2115
1964
  0 && (module.exports = {
2116
1965
  AppInjector,
@@ -2144,7 +1993,6 @@ var NoxRendererClient = _NoxRendererClient;
2144
1993
  NotFoundException,
2145
1994
  NotImplementedException,
2146
1995
  NoxApp,
2147
- NoxRendererClient,
2148
1996
  NoxSocket,
2149
1997
  Patch,
2150
1998
  PaymentRequiredException,
@@ -2152,7 +2000,6 @@ var NoxRendererClient = _NoxRendererClient;
2152
2000
  Put,
2153
2001
  RENDERER_EVENT_TYPE,
2154
2002
  ROUTE_METADATA_KEY,
2155
- RendererEventRegistry,
2156
2003
  Request,
2157
2004
  RequestTimeoutException,
2158
2005
  ResponseException,
@@ -2166,7 +2013,6 @@ var NoxRendererClient = _NoxRendererClient;
2166
2013
  VariantAlsoNegotiatesException,
2167
2014
  bootstrapApplication,
2168
2015
  createRendererEventMessage,
2169
- exposeNoxusBridge,
2170
2016
  forwardRef,
2171
2017
  getControllerMetadata,
2172
2018
  getGuardForController,