@noxfly/noxus 1.2.0 → 2.1.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 +36 -127
- package/dist/{index-5OkVPHfI.d.mts → index-CI3OMzNR.d.mts} +52 -2
- package/dist/{index-5OkVPHfI.d.ts → index-CI3OMzNR.d.ts} +52 -2
- package/dist/main.d.mts +62 -16
- package/dist/main.d.ts +62 -16
- package/dist/main.js +586 -99
- package/dist/main.mjs +573 -99
- package/dist/renderer.d.mts +1 -1
- package/dist/renderer.d.ts +1 -1
- package/dist/renderer.js +251 -1
- package/dist/renderer.mjs +250 -1
- package/package.json +2 -2
- package/src/DI/injector-explorer.ts +1 -1
- package/src/app.ts +24 -15
- package/src/decorators/injectable.decorator.ts +6 -17
- package/src/decorators/injectable.metadata.ts +15 -0
- package/src/index.ts +1 -0
- package/src/main.ts +6 -0
- package/src/preload-bridge.ts +75 -0
- package/src/renderer-client.ts +338 -0
- package/src/request.ts +1 -0
- package/src/router.ts +45 -11
- package/src/socket.ts +14 -9
- package/src/utils/logger.ts +266 -87
package/dist/renderer.d.mts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { p as IBatchRequestItem, q as IBatchRequestPayload, r as IBatchResponsePayload, b as IPortRequester, t as IRendererEventMessage, o as IRequest, I as IResponse, N as NoxRendererClient, s as RENDERER_EVENT_TYPE, z as RendererClientOptions, w as RendererEventHandler, y as RendererEventRegistry, x as RendererEventSubscription, R as Request, u as createRendererEventMessage, v as isRendererEventMessage } from './index-CI3OMzNR.mjs';
|
package/dist/renderer.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { p as IBatchRequestItem, q as IBatchRequestPayload, r as IBatchResponsePayload, b as IPortRequester, t as IRendererEventMessage, o as IRequest, I as IResponse, N as NoxRendererClient, s as RENDERER_EVENT_TYPE, z as RendererClientOptions, w as RendererEventHandler, y as RendererEventRegistry, x as RendererEventSubscription, R as Request, u as createRendererEventMessage, v as isRendererEventMessage } from './index-CI3OMzNR.js';
|
package/dist/renderer.js
CHANGED
|
@@ -28,6 +28,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
28
28
|
// src/index.ts
|
|
29
29
|
var src_exports = {};
|
|
30
30
|
__export(src_exports, {
|
|
31
|
+
NoxRendererClient: () => NoxRendererClient,
|
|
31
32
|
RENDERER_EVENT_TYPE: () => RENDERER_EVENT_TYPE,
|
|
32
33
|
RendererEventRegistry: () => RendererEventRegistry,
|
|
33
34
|
Request: () => Request,
|
|
@@ -134,8 +135,9 @@ var RootInjector = new AppInjector("root");
|
|
|
134
135
|
|
|
135
136
|
// src/request.ts
|
|
136
137
|
var _Request = class _Request {
|
|
137
|
-
constructor(event, id, method, path, body) {
|
|
138
|
+
constructor(event, senderId, id, method, path, body) {
|
|
138
139
|
__publicField(this, "event");
|
|
140
|
+
__publicField(this, "senderId");
|
|
139
141
|
__publicField(this, "id");
|
|
140
142
|
__publicField(this, "method");
|
|
141
143
|
__publicField(this, "path");
|
|
@@ -143,6 +145,7 @@ var _Request = class _Request {
|
|
|
143
145
|
__publicField(this, "context", RootInjector.createScope());
|
|
144
146
|
__publicField(this, "params", {});
|
|
145
147
|
this.event = event;
|
|
148
|
+
this.senderId = senderId;
|
|
146
149
|
this.id = id;
|
|
147
150
|
this.method = method;
|
|
148
151
|
this.path = path;
|
|
@@ -249,8 +252,255 @@ var _RendererEventRegistry = class _RendererEventRegistry {
|
|
|
249
252
|
};
|
|
250
253
|
__name(_RendererEventRegistry, "RendererEventRegistry");
|
|
251
254
|
var RendererEventRegistry = _RendererEventRegistry;
|
|
255
|
+
|
|
256
|
+
// src/renderer-client.ts
|
|
257
|
+
var DEFAULT_INIT_EVENT = "init-port";
|
|
258
|
+
var DEFAULT_BRIDGE_NAMES = [
|
|
259
|
+
"noxus",
|
|
260
|
+
"ipcRenderer"
|
|
261
|
+
];
|
|
262
|
+
function defaultRequestId() {
|
|
263
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
264
|
+
return crypto.randomUUID();
|
|
265
|
+
}
|
|
266
|
+
return `${Date.now().toString(16)}-${Math.floor(Math.random() * 1e8).toString(16)}`;
|
|
267
|
+
}
|
|
268
|
+
__name(defaultRequestId, "defaultRequestId");
|
|
269
|
+
function normalizeBridgeNames(preferred) {
|
|
270
|
+
const names = [];
|
|
271
|
+
const add = /* @__PURE__ */ __name((name) => {
|
|
272
|
+
if (!name) return;
|
|
273
|
+
if (!names.includes(name)) {
|
|
274
|
+
names.push(name);
|
|
275
|
+
}
|
|
276
|
+
}, "add");
|
|
277
|
+
if (Array.isArray(preferred)) {
|
|
278
|
+
for (const name of preferred) {
|
|
279
|
+
add(name);
|
|
280
|
+
}
|
|
281
|
+
} else {
|
|
282
|
+
add(preferred);
|
|
283
|
+
}
|
|
284
|
+
for (const fallback of DEFAULT_BRIDGE_NAMES) {
|
|
285
|
+
add(fallback);
|
|
286
|
+
}
|
|
287
|
+
return names;
|
|
288
|
+
}
|
|
289
|
+
__name(normalizeBridgeNames, "normalizeBridgeNames");
|
|
290
|
+
function resolveBridgeFromWindow(windowRef, preferred) {
|
|
291
|
+
const names = normalizeBridgeNames(preferred);
|
|
292
|
+
const globalRef = windowRef;
|
|
293
|
+
if (!globalRef) {
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
for (const name of names) {
|
|
297
|
+
const candidate = globalRef[name];
|
|
298
|
+
if (candidate && typeof candidate.requestPort === "function") {
|
|
299
|
+
return candidate;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
__name(resolveBridgeFromWindow, "resolveBridgeFromWindow");
|
|
305
|
+
var _NoxRendererClient = class _NoxRendererClient {
|
|
306
|
+
constructor(options = {}) {
|
|
307
|
+
__publicField(this, "events", new RendererEventRegistry());
|
|
308
|
+
__publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
|
|
309
|
+
__publicField(this, "requestPort");
|
|
310
|
+
__publicField(this, "socketPort");
|
|
311
|
+
__publicField(this, "senderId");
|
|
312
|
+
__publicField(this, "bridge");
|
|
313
|
+
__publicField(this, "initMessageType");
|
|
314
|
+
__publicField(this, "windowRef");
|
|
315
|
+
__publicField(this, "generateRequestId");
|
|
316
|
+
__publicField(this, "isReady", false);
|
|
317
|
+
__publicField(this, "setupPromise");
|
|
318
|
+
__publicField(this, "setupResolve");
|
|
319
|
+
__publicField(this, "setupReject");
|
|
320
|
+
__publicField(this, "onWindowMessage", /* @__PURE__ */ __name((event) => {
|
|
321
|
+
if (event.data?.type !== this.initMessageType) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (!Array.isArray(event.ports) || event.ports.length < 2) {
|
|
325
|
+
const error = new Error("[Noxus] Renderer expected two MessagePorts (request + socket).");
|
|
326
|
+
console.error(error);
|
|
327
|
+
this.setupReject?.(error);
|
|
328
|
+
this.resetSetupState();
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
this.windowRef.removeEventListener("message", this.onWindowMessage);
|
|
332
|
+
this.requestPort = event.ports[0];
|
|
333
|
+
this.socketPort = event.ports[1];
|
|
334
|
+
this.senderId = event.data.senderId;
|
|
335
|
+
if (this.requestPort === void 0 || this.socketPort === void 0) {
|
|
336
|
+
const error = new Error("[Noxus] Renderer failed to receive valid MessagePorts.");
|
|
337
|
+
console.error(error);
|
|
338
|
+
this.setupReject?.(error);
|
|
339
|
+
this.resetSetupState();
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
this.attachRequestPort(this.requestPort);
|
|
343
|
+
this.attachSocketPort(this.socketPort);
|
|
344
|
+
this.isReady = true;
|
|
345
|
+
this.setupResolve?.();
|
|
346
|
+
this.resetSetupState(true);
|
|
347
|
+
}, "onWindowMessage"));
|
|
348
|
+
__publicField(this, "onSocketMessage", /* @__PURE__ */ __name((event) => {
|
|
349
|
+
if (this.events.tryDispatchFromMessageEvent(event)) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
console.warn("[Noxus] Received a socket message that is not a renderer event payload.", event.data);
|
|
353
|
+
}, "onSocketMessage"));
|
|
354
|
+
__publicField(this, "onRequestMessage", /* @__PURE__ */ __name((event) => {
|
|
355
|
+
if (this.events.tryDispatchFromMessageEvent(event)) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const response = event.data;
|
|
359
|
+
if (!response || typeof response.requestId !== "string") {
|
|
360
|
+
console.error("[Noxus] Renderer received an invalid response payload.", response);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
const pending = this.pendingRequests.get(response.requestId);
|
|
364
|
+
if (!pending) {
|
|
365
|
+
console.error(`[Noxus] No pending handler found for request ${response.requestId}.`);
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
this.pendingRequests.delete(response.requestId);
|
|
369
|
+
this.onRequestCompleted(pending, response);
|
|
370
|
+
if (response.status >= 400) {
|
|
371
|
+
pending.reject(response);
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
pending.resolve(response.body);
|
|
375
|
+
}, "onRequestMessage"));
|
|
376
|
+
this.windowRef = options.windowRef ?? window;
|
|
377
|
+
const resolvedBridge = options.bridge ?? resolveBridgeFromWindow(this.windowRef, options.bridgeName);
|
|
378
|
+
this.bridge = resolvedBridge ?? null;
|
|
379
|
+
this.initMessageType = options.initMessageType ?? DEFAULT_INIT_EVENT;
|
|
380
|
+
this.generateRequestId = options.generateRequestId ?? defaultRequestId;
|
|
381
|
+
}
|
|
382
|
+
async setup() {
|
|
383
|
+
if (this.isReady) {
|
|
384
|
+
return Promise.resolve();
|
|
385
|
+
}
|
|
386
|
+
if (this.setupPromise) {
|
|
387
|
+
return this.setupPromise;
|
|
388
|
+
}
|
|
389
|
+
if (!this.bridge || typeof this.bridge.requestPort !== "function") {
|
|
390
|
+
throw new Error("[Noxus] Renderer bridge is missing requestPort().");
|
|
391
|
+
}
|
|
392
|
+
this.setupPromise = new Promise((resolve, reject) => {
|
|
393
|
+
this.setupResolve = resolve;
|
|
394
|
+
this.setupReject = reject;
|
|
395
|
+
});
|
|
396
|
+
this.windowRef.addEventListener("message", this.onWindowMessage);
|
|
397
|
+
this.bridge.requestPort();
|
|
398
|
+
return this.setupPromise;
|
|
399
|
+
}
|
|
400
|
+
dispose() {
|
|
401
|
+
this.windowRef.removeEventListener("message", this.onWindowMessage);
|
|
402
|
+
this.requestPort?.close();
|
|
403
|
+
this.socketPort?.close();
|
|
404
|
+
this.requestPort = void 0;
|
|
405
|
+
this.socketPort = void 0;
|
|
406
|
+
this.senderId = void 0;
|
|
407
|
+
this.isReady = false;
|
|
408
|
+
this.pendingRequests.clear();
|
|
409
|
+
}
|
|
410
|
+
async request(request) {
|
|
411
|
+
const senderId = this.senderId;
|
|
412
|
+
const requestId = this.generateRequestId();
|
|
413
|
+
if (senderId === void 0) {
|
|
414
|
+
return Promise.reject(this.createErrorResponse(requestId, "MessagePort is not available"));
|
|
415
|
+
}
|
|
416
|
+
const readinessError = this.validateReady(requestId);
|
|
417
|
+
if (readinessError) {
|
|
418
|
+
return Promise.reject(readinessError);
|
|
419
|
+
}
|
|
420
|
+
const message = {
|
|
421
|
+
requestId,
|
|
422
|
+
senderId,
|
|
423
|
+
...request
|
|
424
|
+
};
|
|
425
|
+
return new Promise((resolve, reject) => {
|
|
426
|
+
const pending = {
|
|
427
|
+
resolve,
|
|
428
|
+
reject: /* @__PURE__ */ __name((response) => reject(response), "reject"),
|
|
429
|
+
request: message,
|
|
430
|
+
submittedAt: Date.now()
|
|
431
|
+
};
|
|
432
|
+
this.pendingRequests.set(message.requestId, pending);
|
|
433
|
+
this.requestPort.postMessage(message);
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
async batch(requests) {
|
|
437
|
+
return this.request({
|
|
438
|
+
method: "BATCH",
|
|
439
|
+
path: "",
|
|
440
|
+
body: {
|
|
441
|
+
requests
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
getSenderId() {
|
|
446
|
+
return this.senderId;
|
|
447
|
+
}
|
|
448
|
+
onRequestCompleted(pending, response) {
|
|
449
|
+
if (typeof console.groupCollapsed === "function") {
|
|
450
|
+
console.groupCollapsed(`${response.status} ${pending.request.method} /${pending.request.path}`);
|
|
451
|
+
}
|
|
452
|
+
if (response.error) {
|
|
453
|
+
console.error("error message:", response.error);
|
|
454
|
+
}
|
|
455
|
+
if (response.body !== void 0) {
|
|
456
|
+
console.info("response:", response.body);
|
|
457
|
+
}
|
|
458
|
+
console.info("request:", pending.request);
|
|
459
|
+
console.info(`Request duration: ${Date.now() - pending.submittedAt} ms`);
|
|
460
|
+
if (typeof console.groupCollapsed === "function") {
|
|
461
|
+
console.groupEnd();
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
attachRequestPort(port) {
|
|
465
|
+
port.onmessage = this.onRequestMessage;
|
|
466
|
+
port.start();
|
|
467
|
+
}
|
|
468
|
+
attachSocketPort(port) {
|
|
469
|
+
port.onmessage = this.onSocketMessage;
|
|
470
|
+
port.start();
|
|
471
|
+
}
|
|
472
|
+
validateReady(requestId) {
|
|
473
|
+
if (!this.isElectronEnvironment()) {
|
|
474
|
+
return this.createErrorResponse(requestId, "Not running in Electron environment");
|
|
475
|
+
}
|
|
476
|
+
if (!this.requestPort) {
|
|
477
|
+
return this.createErrorResponse(requestId, "MessagePort is not available");
|
|
478
|
+
}
|
|
479
|
+
return void 0;
|
|
480
|
+
}
|
|
481
|
+
createErrorResponse(requestId, message) {
|
|
482
|
+
return {
|
|
483
|
+
status: 500,
|
|
484
|
+
requestId,
|
|
485
|
+
error: message
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
resetSetupState(success = false) {
|
|
489
|
+
if (!success) {
|
|
490
|
+
this.setupPromise = void 0;
|
|
491
|
+
}
|
|
492
|
+
this.setupResolve = void 0;
|
|
493
|
+
this.setupReject = void 0;
|
|
494
|
+
}
|
|
495
|
+
isElectronEnvironment() {
|
|
496
|
+
return typeof window !== "undefined" && /Electron/.test(window.navigator.userAgent);
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
__name(_NoxRendererClient, "NoxRendererClient");
|
|
500
|
+
var NoxRendererClient = _NoxRendererClient;
|
|
252
501
|
// Annotate the CommonJS export names for ESM import in node:
|
|
253
502
|
0 && (module.exports = {
|
|
503
|
+
NoxRendererClient,
|
|
254
504
|
RENDERER_EVENT_TYPE,
|
|
255
505
|
RendererEventRegistry,
|
|
256
506
|
Request,
|
package/dist/renderer.mjs
CHANGED
|
@@ -106,8 +106,9 @@ var RootInjector = new AppInjector("root");
|
|
|
106
106
|
|
|
107
107
|
// src/request.ts
|
|
108
108
|
var _Request = class _Request {
|
|
109
|
-
constructor(event, id, method, path, body) {
|
|
109
|
+
constructor(event, senderId, id, method, path, body) {
|
|
110
110
|
__publicField(this, "event");
|
|
111
|
+
__publicField(this, "senderId");
|
|
111
112
|
__publicField(this, "id");
|
|
112
113
|
__publicField(this, "method");
|
|
113
114
|
__publicField(this, "path");
|
|
@@ -115,6 +116,7 @@ var _Request = class _Request {
|
|
|
115
116
|
__publicField(this, "context", RootInjector.createScope());
|
|
116
117
|
__publicField(this, "params", {});
|
|
117
118
|
this.event = event;
|
|
119
|
+
this.senderId = senderId;
|
|
118
120
|
this.id = id;
|
|
119
121
|
this.method = method;
|
|
120
122
|
this.path = path;
|
|
@@ -221,7 +223,254 @@ var _RendererEventRegistry = class _RendererEventRegistry {
|
|
|
221
223
|
};
|
|
222
224
|
__name(_RendererEventRegistry, "RendererEventRegistry");
|
|
223
225
|
var RendererEventRegistry = _RendererEventRegistry;
|
|
226
|
+
|
|
227
|
+
// src/renderer-client.ts
|
|
228
|
+
var DEFAULT_INIT_EVENT = "init-port";
|
|
229
|
+
var DEFAULT_BRIDGE_NAMES = [
|
|
230
|
+
"noxus",
|
|
231
|
+
"ipcRenderer"
|
|
232
|
+
];
|
|
233
|
+
function defaultRequestId() {
|
|
234
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
235
|
+
return crypto.randomUUID();
|
|
236
|
+
}
|
|
237
|
+
return `${Date.now().toString(16)}-${Math.floor(Math.random() * 1e8).toString(16)}`;
|
|
238
|
+
}
|
|
239
|
+
__name(defaultRequestId, "defaultRequestId");
|
|
240
|
+
function normalizeBridgeNames(preferred) {
|
|
241
|
+
const names = [];
|
|
242
|
+
const add = /* @__PURE__ */ __name((name) => {
|
|
243
|
+
if (!name) return;
|
|
244
|
+
if (!names.includes(name)) {
|
|
245
|
+
names.push(name);
|
|
246
|
+
}
|
|
247
|
+
}, "add");
|
|
248
|
+
if (Array.isArray(preferred)) {
|
|
249
|
+
for (const name of preferred) {
|
|
250
|
+
add(name);
|
|
251
|
+
}
|
|
252
|
+
} else {
|
|
253
|
+
add(preferred);
|
|
254
|
+
}
|
|
255
|
+
for (const fallback of DEFAULT_BRIDGE_NAMES) {
|
|
256
|
+
add(fallback);
|
|
257
|
+
}
|
|
258
|
+
return names;
|
|
259
|
+
}
|
|
260
|
+
__name(normalizeBridgeNames, "normalizeBridgeNames");
|
|
261
|
+
function resolveBridgeFromWindow(windowRef, preferred) {
|
|
262
|
+
const names = normalizeBridgeNames(preferred);
|
|
263
|
+
const globalRef = windowRef;
|
|
264
|
+
if (!globalRef) {
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
for (const name of names) {
|
|
268
|
+
const candidate = globalRef[name];
|
|
269
|
+
if (candidate && typeof candidate.requestPort === "function") {
|
|
270
|
+
return candidate;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
__name(resolveBridgeFromWindow, "resolveBridgeFromWindow");
|
|
276
|
+
var _NoxRendererClient = class _NoxRendererClient {
|
|
277
|
+
constructor(options = {}) {
|
|
278
|
+
__publicField(this, "events", new RendererEventRegistry());
|
|
279
|
+
__publicField(this, "pendingRequests", /* @__PURE__ */ new Map());
|
|
280
|
+
__publicField(this, "requestPort");
|
|
281
|
+
__publicField(this, "socketPort");
|
|
282
|
+
__publicField(this, "senderId");
|
|
283
|
+
__publicField(this, "bridge");
|
|
284
|
+
__publicField(this, "initMessageType");
|
|
285
|
+
__publicField(this, "windowRef");
|
|
286
|
+
__publicField(this, "generateRequestId");
|
|
287
|
+
__publicField(this, "isReady", false);
|
|
288
|
+
__publicField(this, "setupPromise");
|
|
289
|
+
__publicField(this, "setupResolve");
|
|
290
|
+
__publicField(this, "setupReject");
|
|
291
|
+
__publicField(this, "onWindowMessage", /* @__PURE__ */ __name((event) => {
|
|
292
|
+
if (event.data?.type !== this.initMessageType) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
if (!Array.isArray(event.ports) || event.ports.length < 2) {
|
|
296
|
+
const error = new Error("[Noxus] Renderer expected two MessagePorts (request + socket).");
|
|
297
|
+
console.error(error);
|
|
298
|
+
this.setupReject?.(error);
|
|
299
|
+
this.resetSetupState();
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
this.windowRef.removeEventListener("message", this.onWindowMessage);
|
|
303
|
+
this.requestPort = event.ports[0];
|
|
304
|
+
this.socketPort = event.ports[1];
|
|
305
|
+
this.senderId = event.data.senderId;
|
|
306
|
+
if (this.requestPort === void 0 || this.socketPort === void 0) {
|
|
307
|
+
const error = new Error("[Noxus] Renderer failed to receive valid MessagePorts.");
|
|
308
|
+
console.error(error);
|
|
309
|
+
this.setupReject?.(error);
|
|
310
|
+
this.resetSetupState();
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
this.attachRequestPort(this.requestPort);
|
|
314
|
+
this.attachSocketPort(this.socketPort);
|
|
315
|
+
this.isReady = true;
|
|
316
|
+
this.setupResolve?.();
|
|
317
|
+
this.resetSetupState(true);
|
|
318
|
+
}, "onWindowMessage"));
|
|
319
|
+
__publicField(this, "onSocketMessage", /* @__PURE__ */ __name((event) => {
|
|
320
|
+
if (this.events.tryDispatchFromMessageEvent(event)) {
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
console.warn("[Noxus] Received a socket message that is not a renderer event payload.", event.data);
|
|
324
|
+
}, "onSocketMessage"));
|
|
325
|
+
__publicField(this, "onRequestMessage", /* @__PURE__ */ __name((event) => {
|
|
326
|
+
if (this.events.tryDispatchFromMessageEvent(event)) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const response = event.data;
|
|
330
|
+
if (!response || typeof response.requestId !== "string") {
|
|
331
|
+
console.error("[Noxus] Renderer received an invalid response payload.", response);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const pending = this.pendingRequests.get(response.requestId);
|
|
335
|
+
if (!pending) {
|
|
336
|
+
console.error(`[Noxus] No pending handler found for request ${response.requestId}.`);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
this.pendingRequests.delete(response.requestId);
|
|
340
|
+
this.onRequestCompleted(pending, response);
|
|
341
|
+
if (response.status >= 400) {
|
|
342
|
+
pending.reject(response);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
pending.resolve(response.body);
|
|
346
|
+
}, "onRequestMessage"));
|
|
347
|
+
this.windowRef = options.windowRef ?? window;
|
|
348
|
+
const resolvedBridge = options.bridge ?? resolveBridgeFromWindow(this.windowRef, options.bridgeName);
|
|
349
|
+
this.bridge = resolvedBridge ?? null;
|
|
350
|
+
this.initMessageType = options.initMessageType ?? DEFAULT_INIT_EVENT;
|
|
351
|
+
this.generateRequestId = options.generateRequestId ?? defaultRequestId;
|
|
352
|
+
}
|
|
353
|
+
async setup() {
|
|
354
|
+
if (this.isReady) {
|
|
355
|
+
return Promise.resolve();
|
|
356
|
+
}
|
|
357
|
+
if (this.setupPromise) {
|
|
358
|
+
return this.setupPromise;
|
|
359
|
+
}
|
|
360
|
+
if (!this.bridge || typeof this.bridge.requestPort !== "function") {
|
|
361
|
+
throw new Error("[Noxus] Renderer bridge is missing requestPort().");
|
|
362
|
+
}
|
|
363
|
+
this.setupPromise = new Promise((resolve, reject) => {
|
|
364
|
+
this.setupResolve = resolve;
|
|
365
|
+
this.setupReject = reject;
|
|
366
|
+
});
|
|
367
|
+
this.windowRef.addEventListener("message", this.onWindowMessage);
|
|
368
|
+
this.bridge.requestPort();
|
|
369
|
+
return this.setupPromise;
|
|
370
|
+
}
|
|
371
|
+
dispose() {
|
|
372
|
+
this.windowRef.removeEventListener("message", this.onWindowMessage);
|
|
373
|
+
this.requestPort?.close();
|
|
374
|
+
this.socketPort?.close();
|
|
375
|
+
this.requestPort = void 0;
|
|
376
|
+
this.socketPort = void 0;
|
|
377
|
+
this.senderId = void 0;
|
|
378
|
+
this.isReady = false;
|
|
379
|
+
this.pendingRequests.clear();
|
|
380
|
+
}
|
|
381
|
+
async request(request) {
|
|
382
|
+
const senderId = this.senderId;
|
|
383
|
+
const requestId = this.generateRequestId();
|
|
384
|
+
if (senderId === void 0) {
|
|
385
|
+
return Promise.reject(this.createErrorResponse(requestId, "MessagePort is not available"));
|
|
386
|
+
}
|
|
387
|
+
const readinessError = this.validateReady(requestId);
|
|
388
|
+
if (readinessError) {
|
|
389
|
+
return Promise.reject(readinessError);
|
|
390
|
+
}
|
|
391
|
+
const message = {
|
|
392
|
+
requestId,
|
|
393
|
+
senderId,
|
|
394
|
+
...request
|
|
395
|
+
};
|
|
396
|
+
return new Promise((resolve, reject) => {
|
|
397
|
+
const pending = {
|
|
398
|
+
resolve,
|
|
399
|
+
reject: /* @__PURE__ */ __name((response) => reject(response), "reject"),
|
|
400
|
+
request: message,
|
|
401
|
+
submittedAt: Date.now()
|
|
402
|
+
};
|
|
403
|
+
this.pendingRequests.set(message.requestId, pending);
|
|
404
|
+
this.requestPort.postMessage(message);
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
async batch(requests) {
|
|
408
|
+
return this.request({
|
|
409
|
+
method: "BATCH",
|
|
410
|
+
path: "",
|
|
411
|
+
body: {
|
|
412
|
+
requests
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
getSenderId() {
|
|
417
|
+
return this.senderId;
|
|
418
|
+
}
|
|
419
|
+
onRequestCompleted(pending, response) {
|
|
420
|
+
if (typeof console.groupCollapsed === "function") {
|
|
421
|
+
console.groupCollapsed(`${response.status} ${pending.request.method} /${pending.request.path}`);
|
|
422
|
+
}
|
|
423
|
+
if (response.error) {
|
|
424
|
+
console.error("error message:", response.error);
|
|
425
|
+
}
|
|
426
|
+
if (response.body !== void 0) {
|
|
427
|
+
console.info("response:", response.body);
|
|
428
|
+
}
|
|
429
|
+
console.info("request:", pending.request);
|
|
430
|
+
console.info(`Request duration: ${Date.now() - pending.submittedAt} ms`);
|
|
431
|
+
if (typeof console.groupCollapsed === "function") {
|
|
432
|
+
console.groupEnd();
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
attachRequestPort(port) {
|
|
436
|
+
port.onmessage = this.onRequestMessage;
|
|
437
|
+
port.start();
|
|
438
|
+
}
|
|
439
|
+
attachSocketPort(port) {
|
|
440
|
+
port.onmessage = this.onSocketMessage;
|
|
441
|
+
port.start();
|
|
442
|
+
}
|
|
443
|
+
validateReady(requestId) {
|
|
444
|
+
if (!this.isElectronEnvironment()) {
|
|
445
|
+
return this.createErrorResponse(requestId, "Not running in Electron environment");
|
|
446
|
+
}
|
|
447
|
+
if (!this.requestPort) {
|
|
448
|
+
return this.createErrorResponse(requestId, "MessagePort is not available");
|
|
449
|
+
}
|
|
450
|
+
return void 0;
|
|
451
|
+
}
|
|
452
|
+
createErrorResponse(requestId, message) {
|
|
453
|
+
return {
|
|
454
|
+
status: 500,
|
|
455
|
+
requestId,
|
|
456
|
+
error: message
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
resetSetupState(success = false) {
|
|
460
|
+
if (!success) {
|
|
461
|
+
this.setupPromise = void 0;
|
|
462
|
+
}
|
|
463
|
+
this.setupResolve = void 0;
|
|
464
|
+
this.setupReject = void 0;
|
|
465
|
+
}
|
|
466
|
+
isElectronEnvironment() {
|
|
467
|
+
return typeof window !== "undefined" && /Electron/.test(window.navigator.userAgent);
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
__name(_NoxRendererClient, "NoxRendererClient");
|
|
471
|
+
var NoxRendererClient = _NoxRendererClient;
|
|
224
472
|
export {
|
|
473
|
+
NoxRendererClient,
|
|
225
474
|
RENDERER_EVENT_TYPE,
|
|
226
475
|
RendererEventRegistry,
|
|
227
476
|
Request,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noxfly/noxus",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"main": "dist/main.js",
|
|
5
5
|
"module": "dist/main.mjs",
|
|
6
6
|
"types": "dist/main.d.ts",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"homepage": "https://github.com/NoxFly/noxus",
|
|
50
50
|
"repository": {
|
|
51
51
|
"type": "git",
|
|
52
|
-
"url": "https://github.com/NoxFly/noxus.git"
|
|
52
|
+
"url": "git+https://github.com/NoxFly/noxus.git"
|
|
53
53
|
},
|
|
54
54
|
"engines": {
|
|
55
55
|
"node": ">= 20"
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { getControllerMetadata } from "src/decorators/controller.decorator";
|
|
8
|
-
import { getInjectableMetadata } from "src/decorators/injectable.
|
|
8
|
+
import { getInjectableMetadata } from "src/decorators/injectable.metadata";
|
|
9
9
|
import { getRouteMetadata } from "src/decorators/method.decorator";
|
|
10
10
|
import { getModuleMetadata } from "src/decorators/module.decorator";
|
|
11
11
|
import { Lifetime, RootInjector } from "src/DI/app-injector";
|
package/src/app.ts
CHANGED
|
@@ -32,20 +32,24 @@ export interface IApp {
|
|
|
32
32
|
@Injectable('singleton')
|
|
33
33
|
export class NoxApp {
|
|
34
34
|
private app: IApp | undefined;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
*
|
|
38
|
+
*/
|
|
35
39
|
private readonly onRendererMessage = async (event: Electron.MessageEvent): Promise<void> => {
|
|
36
40
|
const { senderId, requestId, path, method, body }: IRequest = event.data;
|
|
37
41
|
|
|
38
|
-
const
|
|
42
|
+
const channels = this.socket.get(senderId);
|
|
39
43
|
|
|
40
|
-
if(!
|
|
44
|
+
if(!channels) {
|
|
41
45
|
Logger.error(`No message channel found for sender ID: ${senderId}`);
|
|
42
46
|
return;
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
try {
|
|
46
|
-
const request = new Request(event, requestId, method, path, body);
|
|
50
|
+
const request = new Request(event, senderId, requestId, method, path, body);
|
|
47
51
|
const response = await this.router.handle(request);
|
|
48
|
-
|
|
52
|
+
channels.request.port1.postMessage(response);
|
|
49
53
|
}
|
|
50
54
|
catch(err: any) {
|
|
51
55
|
const response: IResponse = {
|
|
@@ -55,7 +59,7 @@ export class NoxApp {
|
|
|
55
59
|
error: err.message || 'Internal Server Error',
|
|
56
60
|
};
|
|
57
61
|
|
|
58
|
-
|
|
62
|
+
channels.request.port1.postMessage(response);
|
|
59
63
|
}
|
|
60
64
|
};
|
|
61
65
|
|
|
@@ -93,14 +97,16 @@ export class NoxApp {
|
|
|
93
97
|
this.shutdownChannel(senderId);
|
|
94
98
|
}
|
|
95
99
|
|
|
96
|
-
const
|
|
100
|
+
const requestChannel = new MessageChannelMain();
|
|
101
|
+
const socketChannel = new MessageChannelMain();
|
|
97
102
|
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
requestChannel.port1.on('message', this.onRendererMessage);
|
|
104
|
+
requestChannel.port1.start();
|
|
105
|
+
socketChannel.port1.start();
|
|
100
106
|
|
|
101
|
-
this.socket.register(senderId,
|
|
107
|
+
this.socket.register(senderId, requestChannel, socketChannel);
|
|
102
108
|
|
|
103
|
-
event.sender.postMessage('port', { senderId }, [
|
|
109
|
+
event.sender.postMessage('port', { senderId }, [requestChannel.port2, socketChannel.port2]);
|
|
104
110
|
}
|
|
105
111
|
|
|
106
112
|
/**
|
|
@@ -120,16 +126,19 @@ export class NoxApp {
|
|
|
120
126
|
* @param remove - Whether to remove the channel from the messagePorts map.
|
|
121
127
|
*/
|
|
122
128
|
private shutdownChannel(channelSenderId: number): void {
|
|
123
|
-
const
|
|
129
|
+
const channels = this.socket.get(channelSenderId);
|
|
124
130
|
|
|
125
|
-
if(!
|
|
131
|
+
if(!channels) {
|
|
126
132
|
Logger.warn(`No message channel found for sender ID: ${channelSenderId}`);
|
|
127
133
|
return;
|
|
128
134
|
}
|
|
129
135
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
136
|
+
channels.request.port1.off('message', this.onRendererMessage);
|
|
137
|
+
channels.request.port1.close();
|
|
138
|
+
channels.request.port2.close();
|
|
139
|
+
|
|
140
|
+
channels.socket.port1.close();
|
|
141
|
+
channels.socket.port2.close();
|
|
133
142
|
|
|
134
143
|
this.socket.unregister(channelSenderId);
|
|
135
144
|
}
|