@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/child.js +173 -19
- package/dist/child.mjs +173 -19
- package/dist/main.d.mts +100 -22
- package/dist/main.d.ts +100 -22
- package/dist/main.js +236 -390
- package/dist/main.mjs +237 -388
- package/dist/renderer.d.mts +112 -1
- package/dist/renderer.d.ts +112 -1
- package/dist/renderer.js +40 -2
- package/dist/renderer.mjs +39 -2
- package/dist/{index-BxWQVi6C.d.ts → request-CdpZ9qZL.d.ts} +1 -87
- package/dist/{index-DQBQQfMw.d.mts → request-Dx_5Prte.d.mts} +1 -87
- package/package.json +1 -1
- package/src/DI/injector-explorer.ts +120 -15
- package/src/app.ts +50 -2
- package/src/bootstrap.ts +53 -3
- package/src/decorators/injectable.decorator.ts +1 -1
- package/src/index.ts +1 -0
- package/src/main.ts +0 -3
- package/src/router.ts +99 -6
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
|
-
*
|
|
730
|
-
*
|
|
731
|
-
*
|
|
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
|
|
734
|
-
|
|
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
|
|
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
|
|
839
|
+
return;
|
|
751
840
|
}
|
|
752
|
-
|
|
753
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
1401
|
+
return void 0;
|
|
1289
1402
|
}
|
|
1290
1403
|
const routeDef = matchedRoutes.node.findExactChild(request.method);
|
|
1291
|
-
|
|
1292
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1863
|
+
await noxApp.init();
|
|
1864
|
+
return noxApp;
|
|
1817
1865
|
}
|
|
1818
|
-
__name(
|
|
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,
|