@noxfly/noxus 1.1.10 → 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.
- package/.github/copilot-instructions.md +32 -0
- package/README.md +104 -135
- package/dist/index-CI3OMzNR.d.mts +318 -0
- package/dist/index-CI3OMzNR.d.ts +318 -0
- package/dist/{noxus.d.mts → main.d.mts} +45 -233
- package/dist/{noxus.d.ts → main.d.ts} +45 -233
- package/dist/{noxus.js → main.js} +536 -59
- package/dist/{noxus.mjs → main.mjs} +523 -54
- package/dist/renderer.d.mts +1 -0
- package/dist/renderer.d.ts +1 -0
- package/dist/renderer.js +515 -0
- package/dist/renderer.mjs +485 -0
- package/package.json +73 -48
- package/scripts/postbuild.js +10 -5
- package/src/DI/injector-explorer.ts +1 -1
- package/src/app.ts +51 -46
- package/src/decorators/injectable.decorator.ts +6 -17
- package/src/decorators/injectable.metadata.ts +15 -0
- package/src/index.ts +2 -13
- package/src/main.ts +28 -0
- package/src/preload-bridge.ts +75 -0
- package/src/renderer-client.ts +338 -0
- package/src/renderer-events.ts +110 -0
- package/src/request.ts +27 -0
- package/src/router.ts +1 -1
- package/src/socket.ts +73 -0
- package/tsup.config.ts +2 -1
|
@@ -315,6 +315,21 @@ function getGuardForControllerAction(controllerName, actionName) {
|
|
|
315
315
|
__name(getGuardForControllerAction, "getGuardForControllerAction");
|
|
316
316
|
var authorizations = /* @__PURE__ */ new Map();
|
|
317
317
|
|
|
318
|
+
// src/decorators/injectable.metadata.ts
|
|
319
|
+
var INJECTABLE_METADATA_KEY = Symbol("INJECTABLE_METADATA_KEY");
|
|
320
|
+
function defineInjectableMetadata(target, lifetime) {
|
|
321
|
+
Reflect.defineMetadata(INJECTABLE_METADATA_KEY, lifetime, target);
|
|
322
|
+
}
|
|
323
|
+
__name(defineInjectableMetadata, "defineInjectableMetadata");
|
|
324
|
+
function getInjectableMetadata(target) {
|
|
325
|
+
return Reflect.getMetadata(INJECTABLE_METADATA_KEY, target);
|
|
326
|
+
}
|
|
327
|
+
__name(getInjectableMetadata, "getInjectableMetadata");
|
|
328
|
+
function hasInjectableMetadata(target) {
|
|
329
|
+
return Reflect.hasMetadata(INJECTABLE_METADATA_KEY, target);
|
|
330
|
+
}
|
|
331
|
+
__name(hasInjectableMetadata, "hasInjectableMetadata");
|
|
332
|
+
|
|
318
333
|
// src/decorators/method.decorator.ts
|
|
319
334
|
function createRouteDecorator(verb) {
|
|
320
335
|
return (path) => {
|
|
@@ -562,16 +577,11 @@ function Injectable(lifetime = "scope") {
|
|
|
562
577
|
if (typeof target !== "function" || !target.prototype) {
|
|
563
578
|
throw new Error(`@Injectable can only be used on classes, not on ${typeof target}`);
|
|
564
579
|
}
|
|
565
|
-
|
|
580
|
+
defineInjectableMetadata(target, lifetime);
|
|
566
581
|
InjectorExplorer.register(target, lifetime);
|
|
567
582
|
};
|
|
568
583
|
}
|
|
569
584
|
__name(Injectable, "Injectable");
|
|
570
|
-
function getInjectableMetadata(target) {
|
|
571
|
-
return Reflect.getMetadata(INJECTABLE_METADATA_KEY, target);
|
|
572
|
-
}
|
|
573
|
-
__name(getInjectableMetadata, "getInjectableMetadata");
|
|
574
|
-
var INJECTABLE_METADATA_KEY = Symbol("INJECTABLE_METADATA_KEY");
|
|
575
585
|
|
|
576
586
|
// src/decorators/controller.decorator.ts
|
|
577
587
|
function Controller(path) {
|
|
@@ -625,8 +635,9 @@ var middlewares = /* @__PURE__ */ new Map();
|
|
|
625
635
|
// src/request.ts
|
|
626
636
|
import "reflect-metadata";
|
|
627
637
|
var _Request = class _Request {
|
|
628
|
-
constructor(event, id, method, path, body) {
|
|
638
|
+
constructor(event, senderId, id, method, path, body) {
|
|
629
639
|
__publicField(this, "event");
|
|
640
|
+
__publicField(this, "senderId");
|
|
630
641
|
__publicField(this, "id");
|
|
631
642
|
__publicField(this, "method");
|
|
632
643
|
__publicField(this, "path");
|
|
@@ -634,6 +645,7 @@ var _Request = class _Request {
|
|
|
634
645
|
__publicField(this, "context", RootInjector.createScope());
|
|
635
646
|
__publicField(this, "params", {});
|
|
636
647
|
this.event = event;
|
|
648
|
+
this.senderId = senderId;
|
|
637
649
|
this.id = id;
|
|
638
650
|
this.method = method;
|
|
639
651
|
this.path = path;
|
|
@@ -643,6 +655,23 @@ var _Request = class _Request {
|
|
|
643
655
|
};
|
|
644
656
|
__name(_Request, "Request");
|
|
645
657
|
var Request = _Request;
|
|
658
|
+
var RENDERER_EVENT_TYPE = "noxus:event";
|
|
659
|
+
function createRendererEventMessage(event, payload) {
|
|
660
|
+
return {
|
|
661
|
+
type: RENDERER_EVENT_TYPE,
|
|
662
|
+
event,
|
|
663
|
+
payload
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
__name(createRendererEventMessage, "createRendererEventMessage");
|
|
667
|
+
function isRendererEventMessage(value) {
|
|
668
|
+
if (value === null || typeof value !== "object") {
|
|
669
|
+
return false;
|
|
670
|
+
}
|
|
671
|
+
const possibleMessage = value;
|
|
672
|
+
return possibleMessage.type === RENDERER_EVENT_TYPE && typeof possibleMessage.event === "string";
|
|
673
|
+
}
|
|
674
|
+
__name(isRendererEventMessage, "isRendererEventMessage");
|
|
646
675
|
|
|
647
676
|
// src/utils/radix-tree.ts
|
|
648
677
|
var _a;
|
|
@@ -952,7 +981,7 @@ var _Router = class _Router {
|
|
|
952
981
|
const batchResponses = [];
|
|
953
982
|
for (const [index, item] of payload.requests.entries()) {
|
|
954
983
|
const subRequestId = item.requestId ?? `${request.id}:${index}`;
|
|
955
|
-
const atomicRequest = new Request(request.event, subRequestId, item.method, item.path, item.body);
|
|
984
|
+
const atomicRequest = new Request(request.event, request.senderId, subRequestId, item.method, item.path, item.body);
|
|
956
985
|
batchResponses.push(await this.handleAtomic(atomicRequest));
|
|
957
986
|
}
|
|
958
987
|
response.body.responses = batchResponses;
|
|
@@ -1161,6 +1190,8 @@ Router = _ts_decorate([
|
|
|
1161
1190
|
|
|
1162
1191
|
// src/app.ts
|
|
1163
1192
|
import { app, BrowserWindow, ipcMain, MessageChannelMain } from "electron/main";
|
|
1193
|
+
|
|
1194
|
+
// src/socket.ts
|
|
1164
1195
|
function _ts_decorate2(decorators, target, key, desc) {
|
|
1165
1196
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1166
1197
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1168,16 +1199,104 @@ function _ts_decorate2(decorators, target, key, desc) {
|
|
|
1168
1199
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1169
1200
|
}
|
|
1170
1201
|
__name(_ts_decorate2, "_ts_decorate");
|
|
1202
|
+
var _NoxSocket = class _NoxSocket {
|
|
1203
|
+
constructor() {
|
|
1204
|
+
__publicField(this, "channels", /* @__PURE__ */ new Map());
|
|
1205
|
+
}
|
|
1206
|
+
register(senderId, requestChannel, socketChannel) {
|
|
1207
|
+
this.channels.set(senderId, {
|
|
1208
|
+
request: requestChannel,
|
|
1209
|
+
socket: socketChannel
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
get(senderId) {
|
|
1213
|
+
return this.channels.get(senderId);
|
|
1214
|
+
}
|
|
1215
|
+
unregister(senderId) {
|
|
1216
|
+
this.channels.delete(senderId);
|
|
1217
|
+
}
|
|
1218
|
+
getSenderIds() {
|
|
1219
|
+
return [
|
|
1220
|
+
...this.channels.keys()
|
|
1221
|
+
];
|
|
1222
|
+
}
|
|
1223
|
+
emit(eventName, payload, targetSenderIds) {
|
|
1224
|
+
const normalizedEvent = eventName.trim();
|
|
1225
|
+
if (normalizedEvent.length === 0) {
|
|
1226
|
+
throw new Error("Renderer event name must be a non-empty string.");
|
|
1227
|
+
}
|
|
1228
|
+
const recipients = targetSenderIds ?? this.getSenderIds();
|
|
1229
|
+
let delivered = 0;
|
|
1230
|
+
for (const senderId of recipients) {
|
|
1231
|
+
const channel = this.channels.get(senderId);
|
|
1232
|
+
if (!channel) {
|
|
1233
|
+
Logger.warn(`No message channel found for sender ID: ${senderId} while emitting "${normalizedEvent}".`);
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
try {
|
|
1237
|
+
channel.socket.port1.postMessage(createRendererEventMessage(normalizedEvent, payload));
|
|
1238
|
+
delivered++;
|
|
1239
|
+
} catch (error) {
|
|
1240
|
+
Logger.error(`[Noxus] Failed to emit "${normalizedEvent}" to sender ${senderId}.`, error);
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
return delivered;
|
|
1244
|
+
}
|
|
1245
|
+
emitToRenderer(senderId, eventName, payload) {
|
|
1246
|
+
return this.emit(eventName, payload, [
|
|
1247
|
+
senderId
|
|
1248
|
+
]) > 0;
|
|
1249
|
+
}
|
|
1250
|
+
};
|
|
1251
|
+
__name(_NoxSocket, "NoxSocket");
|
|
1252
|
+
var NoxSocket = _NoxSocket;
|
|
1253
|
+
NoxSocket = _ts_decorate2([
|
|
1254
|
+
Injectable("singleton")
|
|
1255
|
+
], NoxSocket);
|
|
1256
|
+
|
|
1257
|
+
// src/app.ts
|
|
1258
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
1259
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1260
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1261
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1262
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1263
|
+
}
|
|
1264
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
1171
1265
|
function _ts_metadata(k, v) {
|
|
1172
1266
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1173
1267
|
}
|
|
1174
1268
|
__name(_ts_metadata, "_ts_metadata");
|
|
1175
1269
|
var _NoxApp = class _NoxApp {
|
|
1176
|
-
constructor(router) {
|
|
1270
|
+
constructor(router, socket) {
|
|
1177
1271
|
__publicField(this, "router");
|
|
1178
|
-
__publicField(this, "
|
|
1272
|
+
__publicField(this, "socket");
|
|
1179
1273
|
__publicField(this, "app");
|
|
1274
|
+
/**
|
|
1275
|
+
*
|
|
1276
|
+
*/
|
|
1277
|
+
__publicField(this, "onRendererMessage", /* @__PURE__ */ __name(async (event) => {
|
|
1278
|
+
const { senderId, requestId, path, method, body } = event.data;
|
|
1279
|
+
const channels = this.socket.get(senderId);
|
|
1280
|
+
if (!channels) {
|
|
1281
|
+
Logger.error(`No message channel found for sender ID: ${senderId}`);
|
|
1282
|
+
return;
|
|
1283
|
+
}
|
|
1284
|
+
try {
|
|
1285
|
+
const request = new Request(event, senderId, requestId, method, path, body);
|
|
1286
|
+
const response = await this.router.handle(request);
|
|
1287
|
+
channels.request.port1.postMessage(response);
|
|
1288
|
+
} catch (err) {
|
|
1289
|
+
const response = {
|
|
1290
|
+
requestId,
|
|
1291
|
+
status: 500,
|
|
1292
|
+
body: null,
|
|
1293
|
+
error: err.message || "Internal Server Error"
|
|
1294
|
+
};
|
|
1295
|
+
channels.request.port1.postMessage(response);
|
|
1296
|
+
}
|
|
1297
|
+
}, "onRendererMessage"));
|
|
1180
1298
|
this.router = router;
|
|
1299
|
+
this.socket = socket;
|
|
1181
1300
|
}
|
|
1182
1301
|
/**
|
|
1183
1302
|
* Initializes the NoxApp instance.
|
|
@@ -1199,44 +1318,22 @@ var _NoxApp = class _NoxApp {
|
|
|
1199
1318
|
*/
|
|
1200
1319
|
giveTheRendererAPort(event) {
|
|
1201
1320
|
const senderId = event.sender.id;
|
|
1202
|
-
if (this.
|
|
1321
|
+
if (this.socket.get(senderId)) {
|
|
1203
1322
|
this.shutdownChannel(senderId);
|
|
1204
1323
|
}
|
|
1205
|
-
const
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1324
|
+
const requestChannel = new MessageChannelMain();
|
|
1325
|
+
const socketChannel = new MessageChannelMain();
|
|
1326
|
+
requestChannel.port1.on("message", this.onRendererMessage);
|
|
1327
|
+
requestChannel.port1.start();
|
|
1328
|
+
socketChannel.port1.start();
|
|
1329
|
+
this.socket.register(senderId, requestChannel, socketChannel);
|
|
1209
1330
|
event.sender.postMessage("port", {
|
|
1210
1331
|
senderId
|
|
1211
1332
|
}, [
|
|
1212
|
-
|
|
1333
|
+
requestChannel.port2,
|
|
1334
|
+
socketChannel.port2
|
|
1213
1335
|
]);
|
|
1214
1336
|
}
|
|
1215
|
-
/**
|
|
1216
|
-
* Electron specific message handling.
|
|
1217
|
-
* Replaces HTTP calls by using Electron's IPC mechanism.
|
|
1218
|
-
*/
|
|
1219
|
-
async onRendererMessage(event) {
|
|
1220
|
-
const { senderId, requestId, path, method, body } = event.data;
|
|
1221
|
-
const channel = this.messagePorts.get(senderId);
|
|
1222
|
-
if (!channel) {
|
|
1223
|
-
Logger.error(`No message channel found for sender ID: ${senderId}`);
|
|
1224
|
-
return;
|
|
1225
|
-
}
|
|
1226
|
-
try {
|
|
1227
|
-
const request = new Request(event, requestId, method, path, body);
|
|
1228
|
-
const response = await this.router.handle(request);
|
|
1229
|
-
channel.port1.postMessage(response);
|
|
1230
|
-
} catch (err) {
|
|
1231
|
-
const response = {
|
|
1232
|
-
requestId,
|
|
1233
|
-
status: 500,
|
|
1234
|
-
body: null,
|
|
1235
|
-
error: err.message || "Internal Server Error"
|
|
1236
|
-
};
|
|
1237
|
-
channel.port1.postMessage(response);
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
1337
|
/**
|
|
1241
1338
|
* MacOS specific behavior.
|
|
1242
1339
|
*/
|
|
@@ -1253,25 +1350,26 @@ var _NoxApp = class _NoxApp {
|
|
|
1253
1350
|
* @param remove - Whether to remove the channel from the messagePorts map.
|
|
1254
1351
|
*/
|
|
1255
1352
|
shutdownChannel(channelSenderId) {
|
|
1256
|
-
const
|
|
1257
|
-
if (!
|
|
1353
|
+
const channels = this.socket.get(channelSenderId);
|
|
1354
|
+
if (!channels) {
|
|
1258
1355
|
Logger.warn(`No message channel found for sender ID: ${channelSenderId}`);
|
|
1259
1356
|
return;
|
|
1260
1357
|
}
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1358
|
+
channels.request.port1.off("message", this.onRendererMessage);
|
|
1359
|
+
channels.request.port1.close();
|
|
1360
|
+
channels.request.port2.close();
|
|
1361
|
+
channels.socket.port1.close();
|
|
1362
|
+
channels.socket.port2.close();
|
|
1363
|
+
this.socket.unregister(channelSenderId);
|
|
1265
1364
|
}
|
|
1266
1365
|
/**
|
|
1267
1366
|
* Handles the application shutdown process.
|
|
1268
1367
|
* This method is called when all windows are closed, and it cleans up the message channels
|
|
1269
1368
|
*/
|
|
1270
1369
|
async onAllWindowsClosed() {
|
|
1271
|
-
this.
|
|
1370
|
+
for (const senderId of this.socket.getSenderIds()) {
|
|
1272
1371
|
this.shutdownChannel(senderId);
|
|
1273
|
-
}
|
|
1274
|
-
this.messagePorts.clear();
|
|
1372
|
+
}
|
|
1275
1373
|
Logger.info("All windows closed, shutting down application...");
|
|
1276
1374
|
await this.app?.dispose();
|
|
1277
1375
|
if (process.platform !== "darwin") {
|
|
@@ -1310,11 +1408,12 @@ var _NoxApp = class _NoxApp {
|
|
|
1310
1408
|
};
|
|
1311
1409
|
__name(_NoxApp, "NoxApp");
|
|
1312
1410
|
var NoxApp = _NoxApp;
|
|
1313
|
-
NoxApp =
|
|
1411
|
+
NoxApp = _ts_decorate3([
|
|
1314
1412
|
Injectable("singleton"),
|
|
1315
1413
|
_ts_metadata("design:type", Function),
|
|
1316
1414
|
_ts_metadata("design:paramtypes", [
|
|
1317
|
-
typeof Router === "undefined" ? Object : Router
|
|
1415
|
+
typeof Router === "undefined" ? Object : Router,
|
|
1416
|
+
typeof NoxSocket === "undefined" ? Object : NoxSocket
|
|
1318
1417
|
])
|
|
1319
1418
|
], NoxApp);
|
|
1320
1419
|
|
|
@@ -1330,6 +1429,368 @@ async function bootstrapApplication(rootModule) {
|
|
|
1330
1429
|
return noxApp;
|
|
1331
1430
|
}
|
|
1332
1431
|
__name(bootstrapApplication, "bootstrapApplication");
|
|
1432
|
+
|
|
1433
|
+
// src/preload-bridge.ts
|
|
1434
|
+
import { contextBridge, ipcRenderer } from "electron/renderer";
|
|
1435
|
+
var DEFAULT_EXPOSE_NAME = "noxus";
|
|
1436
|
+
var DEFAULT_INIT_EVENT = "init-port";
|
|
1437
|
+
var DEFAULT_REQUEST_CHANNEL = "gimme-my-port";
|
|
1438
|
+
var DEFAULT_RESPONSE_CHANNEL = "port";
|
|
1439
|
+
function exposeNoxusBridge(options = {}) {
|
|
1440
|
+
const { exposeAs = DEFAULT_EXPOSE_NAME, initMessageType = DEFAULT_INIT_EVENT, requestChannel = DEFAULT_REQUEST_CHANNEL, responseChannel = DEFAULT_RESPONSE_CHANNEL, targetWindow = window } = options;
|
|
1441
|
+
const api = {
|
|
1442
|
+
requestPort: /* @__PURE__ */ __name(() => {
|
|
1443
|
+
ipcRenderer.send(requestChannel);
|
|
1444
|
+
ipcRenderer.once(responseChannel, (event, message) => {
|
|
1445
|
+
const ports = (event.ports ?? []).filter((port) => port !== void 0);
|
|
1446
|
+
if (ports.length === 0) {
|
|
1447
|
+
console.error("[Noxus] No MessagePort received from main process.");
|
|
1448
|
+
return;
|
|
1449
|
+
}
|
|
1450
|
+
for (const port of ports) {
|
|
1451
|
+
try {
|
|
1452
|
+
port.start();
|
|
1453
|
+
} catch (error) {
|
|
1454
|
+
console.error("[Noxus] Failed to start MessagePort.", error);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
targetWindow.postMessage({
|
|
1458
|
+
type: initMessageType,
|
|
1459
|
+
senderId: message?.senderId
|
|
1460
|
+
}, "*", ports);
|
|
1461
|
+
});
|
|
1462
|
+
}, "requestPort")
|
|
1463
|
+
};
|
|
1464
|
+
contextBridge.exposeInMainWorld(exposeAs, api);
|
|
1465
|
+
return api;
|
|
1466
|
+
}
|
|
1467
|
+
__name(exposeNoxusBridge, "exposeNoxusBridge");
|
|
1468
|
+
|
|
1469
|
+
// src/renderer-events.ts
|
|
1470
|
+
var _RendererEventRegistry = class _RendererEventRegistry {
|
|
1471
|
+
constructor() {
|
|
1472
|
+
__publicField(this, "listeners", /* @__PURE__ */ new Map());
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
*
|
|
1476
|
+
*/
|
|
1477
|
+
subscribe(eventName, handler) {
|
|
1478
|
+
const normalizedEventName = eventName.trim();
|
|
1479
|
+
if (normalizedEventName.length === 0) {
|
|
1480
|
+
throw new Error("Renderer event name must be a non-empty string.");
|
|
1481
|
+
}
|
|
1482
|
+
const handlers = this.listeners.get(normalizedEventName) ?? /* @__PURE__ */ new Set();
|
|
1483
|
+
handlers.add(handler);
|
|
1484
|
+
this.listeners.set(normalizedEventName, handlers);
|
|
1485
|
+
return {
|
|
1486
|
+
unsubscribe: /* @__PURE__ */ __name(() => this.unsubscribe(normalizedEventName, handler), "unsubscribe")
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
*
|
|
1491
|
+
*/
|
|
1492
|
+
unsubscribe(eventName, handler) {
|
|
1493
|
+
const handlers = this.listeners.get(eventName);
|
|
1494
|
+
if (!handlers) {
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
handlers.delete(handler);
|
|
1498
|
+
if (handlers.size === 0) {
|
|
1499
|
+
this.listeners.delete(eventName);
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
/**
|
|
1503
|
+
*
|
|
1504
|
+
*/
|
|
1505
|
+
clear(eventName) {
|
|
1506
|
+
if (eventName) {
|
|
1507
|
+
this.listeners.delete(eventName);
|
|
1508
|
+
return;
|
|
1509
|
+
}
|
|
1510
|
+
this.listeners.clear();
|
|
1511
|
+
}
|
|
1512
|
+
/**
|
|
1513
|
+
*
|
|
1514
|
+
*/
|
|
1515
|
+
dispatch(message) {
|
|
1516
|
+
const handlers = this.listeners.get(message.event);
|
|
1517
|
+
if (!handlers || handlers.size === 0) {
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
handlers.forEach((handler) => {
|
|
1521
|
+
try {
|
|
1522
|
+
handler(message.payload);
|
|
1523
|
+
} catch (error) {
|
|
1524
|
+
console.error(`[Noxus] Renderer event handler for "${message.event}" threw an error.`, error);
|
|
1525
|
+
}
|
|
1526
|
+
});
|
|
1527
|
+
}
|
|
1528
|
+
/**
|
|
1529
|
+
*
|
|
1530
|
+
*/
|
|
1531
|
+
tryDispatchFromMessageEvent(event) {
|
|
1532
|
+
if (!isRendererEventMessage(event.data)) {
|
|
1533
|
+
return false;
|
|
1534
|
+
}
|
|
1535
|
+
this.dispatch(event.data);
|
|
1536
|
+
return true;
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1539
|
+
*
|
|
1540
|
+
*/
|
|
1541
|
+
hasHandlers(eventName) {
|
|
1542
|
+
const handlers = this.listeners.get(eventName);
|
|
1543
|
+
return !!handlers && handlers.size > 0;
|
|
1544
|
+
}
|
|
1545
|
+
};
|
|
1546
|
+
__name(_RendererEventRegistry, "RendererEventRegistry");
|
|
1547
|
+
var RendererEventRegistry = _RendererEventRegistry;
|
|
1548
|
+
|
|
1549
|
+
// src/renderer-client.ts
|
|
1550
|
+
var DEFAULT_INIT_EVENT2 = "init-port";
|
|
1551
|
+
var DEFAULT_BRIDGE_NAMES = [
|
|
1552
|
+
"noxus",
|
|
1553
|
+
"ipcRenderer"
|
|
1554
|
+
];
|
|
1555
|
+
function defaultRequestId() {
|
|
1556
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
1557
|
+
return crypto.randomUUID();
|
|
1558
|
+
}
|
|
1559
|
+
return `${Date.now().toString(16)}-${Math.floor(Math.random() * 1e8).toString(16)}`;
|
|
1560
|
+
}
|
|
1561
|
+
__name(defaultRequestId, "defaultRequestId");
|
|
1562
|
+
function normalizeBridgeNames(preferred) {
|
|
1563
|
+
const names = [];
|
|
1564
|
+
const add = /* @__PURE__ */ __name((name) => {
|
|
1565
|
+
if (!name) return;
|
|
1566
|
+
if (!names.includes(name)) {
|
|
1567
|
+
names.push(name);
|
|
1568
|
+
}
|
|
1569
|
+
}, "add");
|
|
1570
|
+
if (Array.isArray(preferred)) {
|
|
1571
|
+
for (const name of preferred) {
|
|
1572
|
+
add(name);
|
|
1573
|
+
}
|
|
1574
|
+
} else {
|
|
1575
|
+
add(preferred);
|
|
1576
|
+
}
|
|
1577
|
+
for (const fallback of DEFAULT_BRIDGE_NAMES) {
|
|
1578
|
+
add(fallback);
|
|
1579
|
+
}
|
|
1580
|
+
return names;
|
|
1581
|
+
}
|
|
1582
|
+
__name(normalizeBridgeNames, "normalizeBridgeNames");
|
|
1583
|
+
function resolveBridgeFromWindow(windowRef, preferred) {
|
|
1584
|
+
const names = normalizeBridgeNames(preferred);
|
|
1585
|
+
const globalRef = windowRef;
|
|
1586
|
+
if (!globalRef) {
|
|
1587
|
+
return null;
|
|
1588
|
+
}
|
|
1589
|
+
for (const name of names) {
|
|
1590
|
+
const candidate = globalRef[name];
|
|
1591
|
+
if (candidate && typeof candidate.requestPort === "function") {
|
|
1592
|
+
return candidate;
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
return null;
|
|
1596
|
+
}
|
|
1597
|
+
__name(resolveBridgeFromWindow, "resolveBridgeFromWindow");
|
|
1598
|
+
var _NoxRendererClient = class _NoxRendererClient {
|
|
1599
|
+
constructor(options = {}) {
|
|
1600
|
+
__publicField(this, "events", new RendererEventRegistry());
|
|
1601
|
+
__publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
|
|
1602
|
+
__publicField(this, "requestPort");
|
|
1603
|
+
__publicField(this, "socketPort");
|
|
1604
|
+
__publicField(this, "senderId");
|
|
1605
|
+
__publicField(this, "bridge");
|
|
1606
|
+
__publicField(this, "initMessageType");
|
|
1607
|
+
__publicField(this, "windowRef");
|
|
1608
|
+
__publicField(this, "generateRequestId");
|
|
1609
|
+
__publicField(this, "isReady", false);
|
|
1610
|
+
__publicField(this, "setupPromise");
|
|
1611
|
+
__publicField(this, "setupResolve");
|
|
1612
|
+
__publicField(this, "setupReject");
|
|
1613
|
+
__publicField(this, "onWindowMessage", /* @__PURE__ */ __name((event) => {
|
|
1614
|
+
if (event.data?.type !== this.initMessageType) {
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
if (!Array.isArray(event.ports) || event.ports.length < 2) {
|
|
1618
|
+
const error = new Error("[Noxus] Renderer expected two MessagePorts (request + socket).");
|
|
1619
|
+
console.error(error);
|
|
1620
|
+
this.setupReject?.(error);
|
|
1621
|
+
this.resetSetupState();
|
|
1622
|
+
return;
|
|
1623
|
+
}
|
|
1624
|
+
this.windowRef.removeEventListener("message", this.onWindowMessage);
|
|
1625
|
+
this.requestPort = event.ports[0];
|
|
1626
|
+
this.socketPort = event.ports[1];
|
|
1627
|
+
this.senderId = event.data.senderId;
|
|
1628
|
+
if (this.requestPort === void 0 || this.socketPort === void 0) {
|
|
1629
|
+
const error = new Error("[Noxus] Renderer failed to receive valid MessagePorts.");
|
|
1630
|
+
console.error(error);
|
|
1631
|
+
this.setupReject?.(error);
|
|
1632
|
+
this.resetSetupState();
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
this.attachRequestPort(this.requestPort);
|
|
1636
|
+
this.attachSocketPort(this.socketPort);
|
|
1637
|
+
this.isReady = true;
|
|
1638
|
+
this.setupResolve?.();
|
|
1639
|
+
this.resetSetupState(true);
|
|
1640
|
+
}, "onWindowMessage"));
|
|
1641
|
+
__publicField(this, "onSocketMessage", /* @__PURE__ */ __name((event) => {
|
|
1642
|
+
if (this.events.tryDispatchFromMessageEvent(event)) {
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1645
|
+
console.warn("[Noxus] Received a socket message that is not a renderer event payload.", event.data);
|
|
1646
|
+
}, "onSocketMessage"));
|
|
1647
|
+
__publicField(this, "onRequestMessage", /* @__PURE__ */ __name((event) => {
|
|
1648
|
+
if (this.events.tryDispatchFromMessageEvent(event)) {
|
|
1649
|
+
return;
|
|
1650
|
+
}
|
|
1651
|
+
const response = event.data;
|
|
1652
|
+
if (!response || typeof response.requestId !== "string") {
|
|
1653
|
+
console.error("[Noxus] Renderer received an invalid response payload.", response);
|
|
1654
|
+
return;
|
|
1655
|
+
}
|
|
1656
|
+
const pending = this.pendingRequests.get(response.requestId);
|
|
1657
|
+
if (!pending) {
|
|
1658
|
+
console.error(`[Noxus] No pending handler found for request ${response.requestId}.`);
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
this.pendingRequests.delete(response.requestId);
|
|
1662
|
+
this.onRequestCompleted(pending, response);
|
|
1663
|
+
if (response.status >= 400) {
|
|
1664
|
+
pending.reject(response);
|
|
1665
|
+
return;
|
|
1666
|
+
}
|
|
1667
|
+
pending.resolve(response.body);
|
|
1668
|
+
}, "onRequestMessage"));
|
|
1669
|
+
this.windowRef = options.windowRef ?? window;
|
|
1670
|
+
const resolvedBridge = options.bridge ?? resolveBridgeFromWindow(this.windowRef, options.bridgeName);
|
|
1671
|
+
this.bridge = resolvedBridge ?? null;
|
|
1672
|
+
this.initMessageType = options.initMessageType ?? DEFAULT_INIT_EVENT2;
|
|
1673
|
+
this.generateRequestId = options.generateRequestId ?? defaultRequestId;
|
|
1674
|
+
}
|
|
1675
|
+
async setup() {
|
|
1676
|
+
if (this.isReady) {
|
|
1677
|
+
return Promise.resolve();
|
|
1678
|
+
}
|
|
1679
|
+
if (this.setupPromise) {
|
|
1680
|
+
return this.setupPromise;
|
|
1681
|
+
}
|
|
1682
|
+
if (!this.bridge || typeof this.bridge.requestPort !== "function") {
|
|
1683
|
+
throw new Error("[Noxus] Renderer bridge is missing requestPort().");
|
|
1684
|
+
}
|
|
1685
|
+
this.setupPromise = new Promise((resolve, reject) => {
|
|
1686
|
+
this.setupResolve = resolve;
|
|
1687
|
+
this.setupReject = reject;
|
|
1688
|
+
});
|
|
1689
|
+
this.windowRef.addEventListener("message", this.onWindowMessage);
|
|
1690
|
+
this.bridge.requestPort();
|
|
1691
|
+
return this.setupPromise;
|
|
1692
|
+
}
|
|
1693
|
+
dispose() {
|
|
1694
|
+
this.windowRef.removeEventListener("message", this.onWindowMessage);
|
|
1695
|
+
this.requestPort?.close();
|
|
1696
|
+
this.socketPort?.close();
|
|
1697
|
+
this.requestPort = void 0;
|
|
1698
|
+
this.socketPort = void 0;
|
|
1699
|
+
this.senderId = void 0;
|
|
1700
|
+
this.isReady = false;
|
|
1701
|
+
this.pendingRequests.clear();
|
|
1702
|
+
}
|
|
1703
|
+
async request(request) {
|
|
1704
|
+
const senderId = this.senderId;
|
|
1705
|
+
const requestId = this.generateRequestId();
|
|
1706
|
+
if (senderId === void 0) {
|
|
1707
|
+
return Promise.reject(this.createErrorResponse(requestId, "MessagePort is not available"));
|
|
1708
|
+
}
|
|
1709
|
+
const readinessError = this.validateReady(requestId);
|
|
1710
|
+
if (readinessError) {
|
|
1711
|
+
return Promise.reject(readinessError);
|
|
1712
|
+
}
|
|
1713
|
+
const message = {
|
|
1714
|
+
requestId,
|
|
1715
|
+
senderId,
|
|
1716
|
+
...request
|
|
1717
|
+
};
|
|
1718
|
+
return new Promise((resolve, reject) => {
|
|
1719
|
+
const pending = {
|
|
1720
|
+
resolve,
|
|
1721
|
+
reject: /* @__PURE__ */ __name((response) => reject(response), "reject"),
|
|
1722
|
+
request: message,
|
|
1723
|
+
submittedAt: Date.now()
|
|
1724
|
+
};
|
|
1725
|
+
this.pendingRequests.set(message.requestId, pending);
|
|
1726
|
+
this.requestPort.postMessage(message);
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
async batch(requests) {
|
|
1730
|
+
return this.request({
|
|
1731
|
+
method: "BATCH",
|
|
1732
|
+
path: "",
|
|
1733
|
+
body: {
|
|
1734
|
+
requests
|
|
1735
|
+
}
|
|
1736
|
+
});
|
|
1737
|
+
}
|
|
1738
|
+
getSenderId() {
|
|
1739
|
+
return this.senderId;
|
|
1740
|
+
}
|
|
1741
|
+
onRequestCompleted(pending, response) {
|
|
1742
|
+
if (typeof console.groupCollapsed === "function") {
|
|
1743
|
+
console.groupCollapsed(`${response.status} ${pending.request.method} /${pending.request.path}`);
|
|
1744
|
+
}
|
|
1745
|
+
if (response.error) {
|
|
1746
|
+
console.error("error message:", response.error);
|
|
1747
|
+
}
|
|
1748
|
+
if (response.body !== void 0) {
|
|
1749
|
+
console.info("response:", response.body);
|
|
1750
|
+
}
|
|
1751
|
+
console.info("request:", pending.request);
|
|
1752
|
+
console.info(`Request duration: ${Date.now() - pending.submittedAt} ms`);
|
|
1753
|
+
if (typeof console.groupCollapsed === "function") {
|
|
1754
|
+
console.groupEnd();
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
attachRequestPort(port) {
|
|
1758
|
+
port.onmessage = this.onRequestMessage;
|
|
1759
|
+
port.start();
|
|
1760
|
+
}
|
|
1761
|
+
attachSocketPort(port) {
|
|
1762
|
+
port.onmessage = this.onSocketMessage;
|
|
1763
|
+
port.start();
|
|
1764
|
+
}
|
|
1765
|
+
validateReady(requestId) {
|
|
1766
|
+
if (!this.isElectronEnvironment()) {
|
|
1767
|
+
return this.createErrorResponse(requestId, "Not running in Electron environment");
|
|
1768
|
+
}
|
|
1769
|
+
if (!this.requestPort) {
|
|
1770
|
+
return this.createErrorResponse(requestId, "MessagePort is not available");
|
|
1771
|
+
}
|
|
1772
|
+
return void 0;
|
|
1773
|
+
}
|
|
1774
|
+
createErrorResponse(requestId, message) {
|
|
1775
|
+
return {
|
|
1776
|
+
status: 500,
|
|
1777
|
+
requestId,
|
|
1778
|
+
error: message
|
|
1779
|
+
};
|
|
1780
|
+
}
|
|
1781
|
+
resetSetupState(success = false) {
|
|
1782
|
+
if (!success) {
|
|
1783
|
+
this.setupPromise = void 0;
|
|
1784
|
+
}
|
|
1785
|
+
this.setupResolve = void 0;
|
|
1786
|
+
this.setupReject = void 0;
|
|
1787
|
+
}
|
|
1788
|
+
isElectronEnvironment() {
|
|
1789
|
+
return typeof window !== "undefined" && /Electron/.test(window.navigator.userAgent);
|
|
1790
|
+
}
|
|
1791
|
+
};
|
|
1792
|
+
__name(_NoxRendererClient, "NoxRendererClient");
|
|
1793
|
+
var NoxRendererClient = _NoxRendererClient;
|
|
1333
1794
|
export {
|
|
1334
1795
|
AppInjector,
|
|
1335
1796
|
Authorize,
|
|
@@ -1359,11 +1820,15 @@ export {
|
|
|
1359
1820
|
NotFoundException,
|
|
1360
1821
|
NotImplementedException,
|
|
1361
1822
|
NoxApp,
|
|
1823
|
+
NoxRendererClient,
|
|
1824
|
+
NoxSocket,
|
|
1362
1825
|
Patch,
|
|
1363
1826
|
PaymentRequiredException,
|
|
1364
1827
|
Post,
|
|
1365
1828
|
Put,
|
|
1829
|
+
RENDERER_EVENT_TYPE,
|
|
1366
1830
|
ROUTE_METADATA_KEY,
|
|
1831
|
+
RendererEventRegistry,
|
|
1367
1832
|
Request,
|
|
1368
1833
|
RequestTimeoutException,
|
|
1369
1834
|
ResponseException,
|
|
@@ -1376,6 +1841,8 @@ export {
|
|
|
1376
1841
|
UseMiddlewares,
|
|
1377
1842
|
VariantAlsoNegotiatesException,
|
|
1378
1843
|
bootstrapApplication,
|
|
1844
|
+
createRendererEventMessage,
|
|
1845
|
+
exposeNoxusBridge,
|
|
1379
1846
|
getControllerMetadata,
|
|
1380
1847
|
getGuardForController,
|
|
1381
1848
|
getGuardForControllerAction,
|
|
@@ -1384,11 +1851,13 @@ export {
|
|
|
1384
1851
|
getMiddlewaresForControllerAction,
|
|
1385
1852
|
getModuleMetadata,
|
|
1386
1853
|
getRouteMetadata,
|
|
1387
|
-
|
|
1854
|
+
hasInjectableMetadata,
|
|
1855
|
+
inject,
|
|
1856
|
+
isRendererEventMessage
|
|
1388
1857
|
};
|
|
1389
1858
|
/**
|
|
1390
1859
|
* @copyright 2025 NoxFly
|
|
1391
1860
|
* @license MIT
|
|
1392
1861
|
* @author NoxFly
|
|
1393
1862
|
*/
|
|
1394
|
-
//# sourceMappingURL=
|
|
1863
|
+
//# sourceMappingURL=main.mjs.map
|