message-nexus 1.0.1 → 1.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/README.md +271 -242
- package/dist/index.cjs +256 -87
- package/dist/index.d.cts +76 -28
- package/dist/index.d.ts +76 -28
- package/dist/index.js +256 -87
- package/package.json +9 -9
package/dist/index.cjs
CHANGED
|
@@ -94,7 +94,7 @@ var BroadcastDriver = class extends BaseDriver {
|
|
|
94
94
|
};
|
|
95
95
|
|
|
96
96
|
// src/drivers/MittDriver.ts
|
|
97
|
-
var eventIndicator = "
|
|
97
|
+
var eventIndicator = "message_nexus_message_event";
|
|
98
98
|
var MittDriver = class extends BaseDriver {
|
|
99
99
|
constructor(emitter) {
|
|
100
100
|
super();
|
|
@@ -163,11 +163,26 @@ var PostMessageDriver = class extends BaseDriver {
|
|
|
163
163
|
};
|
|
164
164
|
|
|
165
165
|
// src/utils/logger.ts
|
|
166
|
+
function isLogger(value) {
|
|
167
|
+
if (value == null || typeof value !== "object") return false;
|
|
168
|
+
const logger = value;
|
|
169
|
+
return typeof logger.addHandler === "function" && typeof logger.setMinLevel === "function" && typeof logger.enable === "function" && typeof logger.disable === "function" && typeof logger.isEnabled === "function" && typeof logger.debug === "function" && typeof logger.info === "function" && typeof logger.warn === "function" && typeof logger.error === "function";
|
|
170
|
+
}
|
|
166
171
|
var Logger = class {
|
|
167
|
-
constructor(context, minLevel = "info" /* INFO
|
|
172
|
+
constructor(context, minLevel = "info" /* INFO */, enabled = false) {
|
|
168
173
|
this.handlers = [];
|
|
169
174
|
this.context = context;
|
|
170
175
|
this.minLevel = minLevel;
|
|
176
|
+
this.enabled = enabled;
|
|
177
|
+
}
|
|
178
|
+
enable() {
|
|
179
|
+
this.enabled = true;
|
|
180
|
+
}
|
|
181
|
+
disable() {
|
|
182
|
+
this.enabled = false;
|
|
183
|
+
}
|
|
184
|
+
isEnabled() {
|
|
185
|
+
return this.enabled;
|
|
171
186
|
}
|
|
172
187
|
addHandler(handler) {
|
|
173
188
|
this.handlers.push(handler);
|
|
@@ -180,7 +195,7 @@ var Logger = class {
|
|
|
180
195
|
return levels.indexOf(level) >= levels.indexOf(this.minLevel);
|
|
181
196
|
}
|
|
182
197
|
log(level, message, metadata) {
|
|
183
|
-
if (!this.shouldLog(level)) return;
|
|
198
|
+
if (!this.enabled || !this.shouldLog(level)) return;
|
|
184
199
|
const entry = {
|
|
185
200
|
level,
|
|
186
201
|
timestamp: Date.now(),
|
|
@@ -203,9 +218,19 @@ var Logger = class {
|
|
|
203
218
|
this.log("error" /* ERROR */, message, metadata);
|
|
204
219
|
}
|
|
205
220
|
};
|
|
221
|
+
function genTimestamp() {
|
|
222
|
+
const now = /* @__PURE__ */ new Date();
|
|
223
|
+
return now.toLocaleTimeString("zh-CN", {
|
|
224
|
+
hour12: false,
|
|
225
|
+
hour: "2-digit",
|
|
226
|
+
minute: "2-digit",
|
|
227
|
+
second: "2-digit",
|
|
228
|
+
fractionalSecondDigits: 3
|
|
229
|
+
});
|
|
230
|
+
}
|
|
206
231
|
var createConsoleHandler = () => {
|
|
207
232
|
return (entry) => {
|
|
208
|
-
const timestamp =
|
|
233
|
+
const timestamp = genTimestamp();
|
|
209
234
|
const prefix = `[${timestamp}] [${entry.level.toUpperCase()}] [${entry.context || "app"}]`;
|
|
210
235
|
const logFn = entry.level === "debug" /* DEBUG */ ? console.debug : entry.level === "info" /* INFO */ ? console.info : entry.level === "warn" /* WARN */ ? console.warn : console.error;
|
|
211
236
|
if (entry.metadata) {
|
|
@@ -231,13 +256,16 @@ var WebSocketDriver = class extends BaseDriver {
|
|
|
231
256
|
this.retryInterval = (typeof options.reconnect === "object" ? options.reconnect.retryInterval : void 0) ?? 5e3;
|
|
232
257
|
this.logger = options.logger || new Logger("WebSocketDriver");
|
|
233
258
|
this.logger.addHandler(createConsoleHandler());
|
|
259
|
+
this.onStatusChange = options.onStatusChange;
|
|
234
260
|
this.connect();
|
|
235
261
|
}
|
|
236
262
|
connect() {
|
|
263
|
+
this.onStatusChange?.("connecting");
|
|
237
264
|
this.ws = new WebSocket(this.url);
|
|
238
265
|
this.ws.addEventListener("open", () => {
|
|
239
266
|
this.logger.info("WebSocket connected", { url: this.url });
|
|
240
267
|
this.retryCount = 0;
|
|
268
|
+
this.onStatusChange?.("connected");
|
|
241
269
|
});
|
|
242
270
|
this.ws.addEventListener("message", (event) => {
|
|
243
271
|
try {
|
|
@@ -255,6 +283,7 @@ var WebSocketDriver = class extends BaseDriver {
|
|
|
255
283
|
});
|
|
256
284
|
this.ws.addEventListener("error", (event) => {
|
|
257
285
|
this.logger.error("WebSocket error", { event });
|
|
286
|
+
this.onStatusChange?.("error");
|
|
258
287
|
});
|
|
259
288
|
this.ws.addEventListener("close", () => {
|
|
260
289
|
this.logger.info("WebSocket connection closed", {
|
|
@@ -264,6 +293,8 @@ var WebSocketDriver = class extends BaseDriver {
|
|
|
264
293
|
});
|
|
265
294
|
if (!this.isManuallyClosed && this.reconnectEnabled && this.retryCount < this.maxRetries) {
|
|
266
295
|
this.scheduleReconnect();
|
|
296
|
+
} else {
|
|
297
|
+
this.onStatusChange?.("disconnected");
|
|
267
298
|
}
|
|
268
299
|
});
|
|
269
300
|
}
|
|
@@ -276,6 +307,7 @@ var WebSocketDriver = class extends BaseDriver {
|
|
|
276
307
|
maxRetries: this.maxRetries,
|
|
277
308
|
url: this.url
|
|
278
309
|
});
|
|
310
|
+
this.onStatusChange?.("connecting");
|
|
279
311
|
this.reconnectTimer = window.setTimeout(() => {
|
|
280
312
|
this.connect();
|
|
281
313
|
}, delay);
|
|
@@ -306,6 +338,7 @@ var WebSocketDriver = class extends BaseDriver {
|
|
|
306
338
|
this.ws.close();
|
|
307
339
|
this.ws = null;
|
|
308
340
|
}
|
|
341
|
+
this.onStatusChange?.("disconnected");
|
|
309
342
|
}
|
|
310
343
|
destroy() {
|
|
311
344
|
this.close();
|
|
@@ -339,45 +372,45 @@ var MessageNexus = class {
|
|
|
339
372
|
this.driver = driver;
|
|
340
373
|
this.instanceId = options?.instanceId || crypto.randomUUID();
|
|
341
374
|
this.timeout = options?.timeout ?? 1e4;
|
|
342
|
-
|
|
343
|
-
|
|
375
|
+
if (options?.logger && isLogger(options.logger)) {
|
|
376
|
+
this.logger = options.logger;
|
|
377
|
+
} else {
|
|
378
|
+
this.logger = new Logger("MessageNexus");
|
|
379
|
+
}
|
|
380
|
+
const loggerEnabled = options?.loggerEnabled ?? false;
|
|
381
|
+
if (loggerEnabled) {
|
|
382
|
+
this.logger.enable();
|
|
383
|
+
this.logger.addHandler(createConsoleHandler());
|
|
384
|
+
this.logger.info("MessageNexus initialized", {
|
|
385
|
+
instanceId: this.instanceId,
|
|
386
|
+
timeout: this.timeout
|
|
387
|
+
});
|
|
388
|
+
}
|
|
344
389
|
this.pendingTasks = /* @__PURE__ */ new Map();
|
|
345
|
-
this.
|
|
346
|
-
this.
|
|
390
|
+
this.invokeHandlers = /* @__PURE__ */ new Map();
|
|
391
|
+
this.notificationHandlers = /* @__PURE__ */ new Map();
|
|
347
392
|
this.cleanupInterval = null;
|
|
348
393
|
this.driver.onMessage = (data) => this._handleIncoming(data);
|
|
349
|
-
this.logger.info("MessageNexus initialized", {
|
|
350
|
-
instanceId: this.instanceId,
|
|
351
|
-
timeout: this.timeout
|
|
352
|
-
});
|
|
353
|
-
this.cleanupInterval = window.setInterval(() => {
|
|
354
|
-
const now = Date.now();
|
|
355
|
-
for (const [id, msg] of this.incomingMessages.entries()) {
|
|
356
|
-
if (now - msg.timestamp > this.timeout * 2) {
|
|
357
|
-
this.incomingMessages.delete(id);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}, 6e4);
|
|
361
394
|
}
|
|
362
|
-
async
|
|
395
|
+
async invoke(methodOrOptions) {
|
|
363
396
|
const id = crypto.randomUUID();
|
|
364
|
-
let
|
|
365
|
-
let
|
|
397
|
+
let method;
|
|
398
|
+
let params;
|
|
366
399
|
let to;
|
|
367
400
|
let metadata;
|
|
368
401
|
let timeout;
|
|
369
402
|
let retryCount = 0;
|
|
370
403
|
let retryDelay = 1e3;
|
|
371
|
-
if (typeof
|
|
372
|
-
|
|
373
|
-
|
|
404
|
+
if (typeof methodOrOptions === "string") {
|
|
405
|
+
method = methodOrOptions;
|
|
406
|
+
params = void 0;
|
|
374
407
|
to = void 0;
|
|
375
408
|
metadata = {};
|
|
376
409
|
timeout = this.timeout;
|
|
377
410
|
} else {
|
|
378
|
-
const opts =
|
|
379
|
-
|
|
380
|
-
|
|
411
|
+
const opts = methodOrOptions;
|
|
412
|
+
method = opts.method;
|
|
413
|
+
params = opts.params;
|
|
381
414
|
to = opts.to;
|
|
382
415
|
metadata = opts.metadata || {};
|
|
383
416
|
timeout = opts.timeout ?? this.timeout;
|
|
@@ -390,16 +423,20 @@ var MessageNexus = class {
|
|
|
390
423
|
this.pendingTasks.delete(id);
|
|
391
424
|
this.metrics.messagesFailed++;
|
|
392
425
|
this.metrics.pendingMessages--;
|
|
393
|
-
reject(new Error(`Message timeout: ${
|
|
426
|
+
reject(new Error(`Message timeout: ${method} (${id})`));
|
|
394
427
|
}, timeout);
|
|
395
428
|
this.pendingTasks.set(id, { resolve, reject, timer, timestamp: Date.now() });
|
|
429
|
+
const rpcRequest = {
|
|
430
|
+
jsonrpc: "2.0",
|
|
431
|
+
method,
|
|
432
|
+
params,
|
|
433
|
+
id
|
|
434
|
+
};
|
|
396
435
|
const message = {
|
|
397
|
-
id,
|
|
398
|
-
type,
|
|
399
|
-
payload,
|
|
400
436
|
from: this.instanceId,
|
|
401
437
|
to,
|
|
402
|
-
metadata: { ...metadata, timestamp: Date.now() }
|
|
438
|
+
metadata: { ...metadata, timestamp: Date.now() },
|
|
439
|
+
payload: rpcRequest
|
|
403
440
|
};
|
|
404
441
|
this._sendMessage(message);
|
|
405
442
|
}).catch((error) => {
|
|
@@ -416,20 +453,26 @@ var MessageNexus = class {
|
|
|
416
453
|
return attempt(0);
|
|
417
454
|
}
|
|
418
455
|
_sendMessage(message) {
|
|
456
|
+
const payload = message.payload;
|
|
457
|
+
const isRequest = "method" in payload;
|
|
458
|
+
const messageId = "id" in payload ? String(payload.id) : void 0;
|
|
459
|
+
const typeOrMethod = isRequest ? payload.method : "RESPONSE";
|
|
419
460
|
try {
|
|
420
461
|
this.driver.send(message);
|
|
421
462
|
this.metrics.messagesSent++;
|
|
422
|
-
|
|
423
|
-
|
|
463
|
+
if (isRequest && messageId !== void 0) {
|
|
464
|
+
this.metrics.pendingMessages++;
|
|
465
|
+
}
|
|
466
|
+
this.logger.debug("Message sent", { messageId, type: typeOrMethod });
|
|
424
467
|
} catch (error) {
|
|
425
468
|
const err = error instanceof Error ? error : new Error(String(error));
|
|
426
469
|
this.metrics.messagesFailed++;
|
|
427
|
-
this.logger.error("Failed to send message", { error: err.message, messageId
|
|
470
|
+
this.logger.error("Failed to send message", { error: err.message, messageId });
|
|
428
471
|
this.errorHandler?.(err, { message });
|
|
429
472
|
if (this.messageQueue.length < this.maxQueueSize) {
|
|
430
473
|
this.messageQueue.push(message);
|
|
431
474
|
this.logger.debug("Message queued", {
|
|
432
|
-
messageId
|
|
475
|
+
messageId,
|
|
433
476
|
queueSize: this.messageQueue.length + 1
|
|
434
477
|
});
|
|
435
478
|
} else {
|
|
@@ -462,55 +505,145 @@ var MessageNexus = class {
|
|
|
462
505
|
}
|
|
463
506
|
}
|
|
464
507
|
}
|
|
508
|
+
notify(methodOrOptions) {
|
|
509
|
+
let method;
|
|
510
|
+
let params;
|
|
511
|
+
let to;
|
|
512
|
+
let metadata;
|
|
513
|
+
if (typeof methodOrOptions === "string") {
|
|
514
|
+
method = methodOrOptions;
|
|
515
|
+
params = void 0;
|
|
516
|
+
to = void 0;
|
|
517
|
+
metadata = {};
|
|
518
|
+
} else {
|
|
519
|
+
const opts = methodOrOptions;
|
|
520
|
+
method = opts.method;
|
|
521
|
+
params = opts.params;
|
|
522
|
+
to = opts.to;
|
|
523
|
+
metadata = opts.metadata || {};
|
|
524
|
+
}
|
|
525
|
+
const rpcNotification = {
|
|
526
|
+
jsonrpc: "2.0",
|
|
527
|
+
method,
|
|
528
|
+
params
|
|
529
|
+
};
|
|
530
|
+
const message = {
|
|
531
|
+
from: this.instanceId,
|
|
532
|
+
to,
|
|
533
|
+
metadata: { ...metadata, timestamp: Date.now() },
|
|
534
|
+
payload: rpcNotification
|
|
535
|
+
};
|
|
536
|
+
this._sendMessage(message);
|
|
537
|
+
}
|
|
465
538
|
_validateMessage(data) {
|
|
466
539
|
if (!data || typeof data !== "object") return false;
|
|
467
|
-
const
|
|
468
|
-
if (typeof
|
|
469
|
-
if (typeof
|
|
470
|
-
if (
|
|
471
|
-
|
|
472
|
-
if (
|
|
473
|
-
if (
|
|
540
|
+
const env = data;
|
|
541
|
+
if (typeof env.from !== "string") return false;
|
|
542
|
+
if (env.to !== void 0 && typeof env.to !== "string") return false;
|
|
543
|
+
if (env.metadata !== void 0 && typeof env.metadata !== "object") return false;
|
|
544
|
+
const payload = env.payload;
|
|
545
|
+
if (!payload || typeof payload !== "object") return false;
|
|
546
|
+
if (payload.jsonrpc !== "2.0") return false;
|
|
547
|
+
const isRequest = "method" in payload;
|
|
548
|
+
const isResponse = "result" in payload || "error" in payload;
|
|
549
|
+
if (!isRequest && !isResponse) return false;
|
|
474
550
|
return true;
|
|
475
551
|
}
|
|
476
|
-
_handleIncoming(data) {
|
|
552
|
+
async _handleIncoming(data) {
|
|
477
553
|
if (!this._validateMessage(data)) {
|
|
478
554
|
this.logger.error("Invalid message format received", { data });
|
|
479
555
|
this.errorHandler?.(new Error("Invalid message format received"), { data });
|
|
480
556
|
this.metrics.messagesFailed++;
|
|
481
557
|
return;
|
|
482
558
|
}
|
|
483
|
-
const
|
|
484
|
-
|
|
559
|
+
const envelope = data;
|
|
560
|
+
const payload = envelope.payload;
|
|
561
|
+
if (envelope.to && envelope.to !== this.instanceId) {
|
|
485
562
|
this.logger.debug("Message filtered: not for this instance", {
|
|
486
|
-
messageId: id,
|
|
487
|
-
to,
|
|
563
|
+
messageId: "id" in payload ? payload.id : void 0,
|
|
564
|
+
to: envelope.to,
|
|
488
565
|
instanceId: this.instanceId
|
|
489
566
|
});
|
|
490
567
|
return;
|
|
491
568
|
}
|
|
492
|
-
if (
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
this.pendingTasks.
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
569
|
+
if ("result" in payload || "error" in payload) {
|
|
570
|
+
const response = payload;
|
|
571
|
+
const id = String(response.id);
|
|
572
|
+
if (this.pendingTasks.has(id)) {
|
|
573
|
+
const { resolve, reject, timer, timestamp } = this.pendingTasks.get(id);
|
|
574
|
+
clearTimeout(timer);
|
|
575
|
+
this.pendingTasks.delete(id);
|
|
576
|
+
const latency = Date.now() - timestamp;
|
|
577
|
+
this.metrics.messagesReceived++;
|
|
578
|
+
this.metrics.pendingMessages--;
|
|
579
|
+
this.metrics.totalLatency += latency;
|
|
580
|
+
this.metrics.averageLatency = this.metrics.totalLatency / this.metrics.messagesReceived;
|
|
581
|
+
this.logger.debug("Response received", { messageId: id, latency });
|
|
582
|
+
if (response.error) {
|
|
583
|
+
const err = new Error(response.error.message);
|
|
584
|
+
err.code = response.error.code;
|
|
585
|
+
err.data = response.error.data;
|
|
586
|
+
reject(err);
|
|
587
|
+
} else {
|
|
588
|
+
resolve(response.result);
|
|
589
|
+
}
|
|
590
|
+
this._notifyMetrics();
|
|
591
|
+
} else {
|
|
592
|
+
this.logger.warn("Orphaned response received", { messageId: id });
|
|
593
|
+
}
|
|
505
594
|
return;
|
|
506
595
|
}
|
|
507
|
-
if (
|
|
508
|
-
|
|
509
|
-
|
|
596
|
+
if ("method" in payload) {
|
|
597
|
+
if ("id" in payload) {
|
|
598
|
+
const request = payload;
|
|
599
|
+
const id = String(request.id);
|
|
600
|
+
this.logger.debug("Invoke message received", {
|
|
601
|
+
messageId: id,
|
|
602
|
+
type: request.method,
|
|
603
|
+
from: envelope.from
|
|
604
|
+
});
|
|
605
|
+
const context = {
|
|
606
|
+
messageId: id,
|
|
607
|
+
from: envelope.from,
|
|
608
|
+
to: envelope.to,
|
|
609
|
+
metadata: envelope.metadata
|
|
610
|
+
};
|
|
611
|
+
const handler = this.invokeHandlers.get(request.method);
|
|
612
|
+
if (handler) {
|
|
613
|
+
try {
|
|
614
|
+
const result = await handler(request.params, context);
|
|
615
|
+
this._reply(id, envelope.from, result);
|
|
616
|
+
} catch (error) {
|
|
617
|
+
this._replyError(id, envelope.from, error);
|
|
618
|
+
}
|
|
619
|
+
} else {
|
|
620
|
+
const err = new Error(`Method not found: ${request.method}`);
|
|
621
|
+
err.code = -32601;
|
|
622
|
+
this._replyError(id, envelope.from, err);
|
|
623
|
+
}
|
|
624
|
+
} else {
|
|
625
|
+
const notification = payload;
|
|
626
|
+
this.logger.debug("Notification message received", {
|
|
627
|
+
type: notification.method,
|
|
628
|
+
from: envelope.from
|
|
629
|
+
});
|
|
630
|
+
const context = {
|
|
631
|
+
from: envelope.from,
|
|
632
|
+
to: envelope.to,
|
|
633
|
+
metadata: envelope.metadata
|
|
634
|
+
};
|
|
635
|
+
const handlers = this.notificationHandlers.get(notification.method);
|
|
636
|
+
if (handlers) {
|
|
637
|
+
handlers.forEach((handler) => {
|
|
638
|
+
try {
|
|
639
|
+
handler(notification.params, context);
|
|
640
|
+
} catch (error) {
|
|
641
|
+
this.logger.error("Error in notification handler", { error: String(error) });
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
}
|
|
510
646
|
}
|
|
511
|
-
this.logger.debug("Command message received", { messageId: id, type, from });
|
|
512
|
-
this.incomingMessages.set(id, { from, type, timestamp: Date.now() });
|
|
513
|
-
this.messageHandlers.forEach((handler) => handler(data));
|
|
514
647
|
}
|
|
515
648
|
getMetrics() {
|
|
516
649
|
return { ...this.metrics, pendingMessages: this.pendingTasks.size };
|
|
@@ -523,27 +656,62 @@ var MessageNexus = class {
|
|
|
523
656
|
const metrics = this.getMetrics();
|
|
524
657
|
this.metricsCallbacks.forEach((callback) => callback(metrics));
|
|
525
658
|
}
|
|
526
|
-
|
|
527
|
-
this.
|
|
528
|
-
|
|
659
|
+
handle(method, handler) {
|
|
660
|
+
if (this.invokeHandlers.has(method)) {
|
|
661
|
+
this.logger.warn(`Overriding existing handler for method: ${method}`);
|
|
662
|
+
}
|
|
663
|
+
this.invokeHandlers.set(method, handler);
|
|
664
|
+
return () => this.invokeHandlers.delete(method);
|
|
665
|
+
}
|
|
666
|
+
removeHandler(method) {
|
|
667
|
+
this.invokeHandlers.delete(method);
|
|
529
668
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
669
|
+
onNotification(method, handler) {
|
|
670
|
+
if (!this.notificationHandlers.has(method)) {
|
|
671
|
+
this.notificationHandlers.set(method, /* @__PURE__ */ new Set());
|
|
672
|
+
}
|
|
673
|
+
this.notificationHandlers.get(method).add(handler);
|
|
674
|
+
return () => this.offNotification(method, handler);
|
|
675
|
+
}
|
|
676
|
+
offNotification(method, handler) {
|
|
677
|
+
const handlers = this.notificationHandlers.get(method);
|
|
678
|
+
if (handlers) {
|
|
679
|
+
handlers.delete(handler);
|
|
680
|
+
if (handlers.size === 0) {
|
|
681
|
+
this.notificationHandlers.delete(method);
|
|
682
|
+
}
|
|
534
683
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
684
|
+
}
|
|
685
|
+
_reply(messageId, to, payload) {
|
|
686
|
+
const rpcResponse = {
|
|
687
|
+
jsonrpc: "2.0",
|
|
538
688
|
id: messageId,
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
isResponse: true,
|
|
689
|
+
result: payload
|
|
690
|
+
};
|
|
691
|
+
const message = {
|
|
543
692
|
from: this.instanceId,
|
|
544
|
-
to
|
|
545
|
-
|
|
546
|
-
|
|
693
|
+
to,
|
|
694
|
+
payload: rpcResponse
|
|
695
|
+
};
|
|
696
|
+
this.driver.send(message);
|
|
697
|
+
}
|
|
698
|
+
_replyError(messageId, to, error) {
|
|
699
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
700
|
+
const rpcResponse = {
|
|
701
|
+
jsonrpc: "2.0",
|
|
702
|
+
id: messageId,
|
|
703
|
+
error: {
|
|
704
|
+
code: err.code || -32e3,
|
|
705
|
+
message: err.message,
|
|
706
|
+
data: err.data
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
const message = {
|
|
710
|
+
from: this.instanceId,
|
|
711
|
+
to,
|
|
712
|
+
payload: rpcResponse
|
|
713
|
+
};
|
|
714
|
+
this.driver.send(message);
|
|
547
715
|
}
|
|
548
716
|
destroy() {
|
|
549
717
|
this.logger.info("MessageNexus destroying", {
|
|
@@ -557,7 +725,8 @@ var MessageNexus = class {
|
|
|
557
725
|
clearInterval(this.cleanupInterval);
|
|
558
726
|
this.cleanupInterval = null;
|
|
559
727
|
}
|
|
560
|
-
this.
|
|
728
|
+
this.invokeHandlers.clear();
|
|
729
|
+
this.notificationHandlers.clear();
|
|
561
730
|
this.metricsCallbacks.clear();
|
|
562
731
|
}
|
|
563
732
|
};
|
package/dist/index.d.cts
CHANGED
|
@@ -1,15 +1,34 @@
|
|
|
1
1
|
import { Emitter } from 'mitt';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
type JsonRpcId = string | number | null;
|
|
4
|
+
interface JsonRpcRequest {
|
|
5
|
+
jsonrpc: '2.0';
|
|
6
|
+
method: string;
|
|
7
|
+
params?: unknown;
|
|
8
|
+
id: JsonRpcId;
|
|
9
|
+
}
|
|
10
|
+
interface JsonRpcNotification {
|
|
11
|
+
jsonrpc: '2.0';
|
|
12
|
+
method: string;
|
|
13
|
+
params?: unknown;
|
|
14
|
+
}
|
|
15
|
+
interface JsonRpcResponse {
|
|
16
|
+
jsonrpc: '2.0';
|
|
17
|
+
result?: unknown;
|
|
18
|
+
error?: {
|
|
19
|
+
code: number;
|
|
20
|
+
message: string;
|
|
21
|
+
data?: unknown;
|
|
22
|
+
};
|
|
23
|
+
id: JsonRpcId;
|
|
24
|
+
}
|
|
25
|
+
interface NexusEnvelope<T = JsonRpcRequest | JsonRpcResponse | JsonRpcNotification> {
|
|
7
26
|
from: string;
|
|
8
27
|
to?: string;
|
|
9
28
|
metadata?: Record<string, unknown>;
|
|
10
|
-
|
|
11
|
-
error?: unknown;
|
|
29
|
+
payload: T;
|
|
12
30
|
}
|
|
31
|
+
type Message = NexusEnvelope;
|
|
13
32
|
declare class BaseDriver {
|
|
14
33
|
onMessage: ((data: Message) => void) | null;
|
|
15
34
|
constructor();
|
|
@@ -59,11 +78,26 @@ interface LogEntry {
|
|
|
59
78
|
context?: string;
|
|
60
79
|
}
|
|
61
80
|
type LogHandler = (entry: LogEntry) => void;
|
|
62
|
-
|
|
81
|
+
interface LoggerInterface {
|
|
82
|
+
addHandler(handler: LogHandler): void;
|
|
83
|
+
setMinLevel(level: LogLevel): void;
|
|
84
|
+
enable(): void;
|
|
85
|
+
disable(): void;
|
|
86
|
+
isEnabled(): boolean;
|
|
87
|
+
debug(message: string, metadata?: Record<string, unknown>): void;
|
|
88
|
+
info(message: string, metadata?: Record<string, unknown>): void;
|
|
89
|
+
warn(message: string, metadata?: Record<string, unknown>): void;
|
|
90
|
+
error(message: string, metadata?: Record<string, unknown>): void;
|
|
91
|
+
}
|
|
92
|
+
declare class Logger implements LoggerInterface {
|
|
63
93
|
private handlers;
|
|
64
94
|
private context;
|
|
65
95
|
private minLevel;
|
|
66
|
-
|
|
96
|
+
private enabled;
|
|
97
|
+
constructor(context: string, minLevel?: LogLevel, enabled?: boolean);
|
|
98
|
+
enable(): void;
|
|
99
|
+
disable(): void;
|
|
100
|
+
isEnabled(): boolean;
|
|
67
101
|
addHandler(handler: LogHandler): void;
|
|
68
102
|
setMinLevel(level: LogLevel): void;
|
|
69
103
|
private shouldLog;
|
|
@@ -83,6 +117,7 @@ interface WebSocketDriverOptions {
|
|
|
83
117
|
url: string;
|
|
84
118
|
reconnect?: boolean | ReconnectOptions;
|
|
85
119
|
logger?: Logger;
|
|
120
|
+
onStatusChange?: (status: 'connecting' | 'connected' | 'disconnected' | 'error') => void;
|
|
86
121
|
}
|
|
87
122
|
declare class WebSocketDriver extends BaseDriver {
|
|
88
123
|
private url;
|
|
@@ -94,6 +129,7 @@ declare class WebSocketDriver extends BaseDriver {
|
|
|
94
129
|
private reconnectTimer;
|
|
95
130
|
private isManuallyClosed;
|
|
96
131
|
private logger;
|
|
132
|
+
private onStatusChange?;
|
|
97
133
|
constructor(options: WebSocketDriverOptions);
|
|
98
134
|
private connect;
|
|
99
135
|
private scheduleReconnect;
|
|
@@ -107,21 +143,32 @@ declare function createEmitter(): Emitter<Record<string, Message>>;
|
|
|
107
143
|
interface MessageNexusOptions {
|
|
108
144
|
instanceId?: string;
|
|
109
145
|
timeout?: number;
|
|
110
|
-
logger?:
|
|
146
|
+
logger?: LoggerInterface;
|
|
147
|
+
loggerEnabled?: boolean;
|
|
111
148
|
}
|
|
112
|
-
interface
|
|
113
|
-
|
|
114
|
-
|
|
149
|
+
interface InvokeOptions {
|
|
150
|
+
method: string;
|
|
151
|
+
params?: unknown;
|
|
115
152
|
to?: string;
|
|
116
153
|
metadata?: Record<string, unknown>;
|
|
117
154
|
timeout?: number;
|
|
118
155
|
retryCount?: number;
|
|
119
156
|
retryDelay?: number;
|
|
120
157
|
}
|
|
121
|
-
interface
|
|
122
|
-
|
|
123
|
-
|
|
158
|
+
interface NotificationOptions {
|
|
159
|
+
method: string;
|
|
160
|
+
params?: unknown;
|
|
161
|
+
to?: string;
|
|
162
|
+
metadata?: Record<string, unknown>;
|
|
163
|
+
}
|
|
164
|
+
interface InvokeContext {
|
|
165
|
+
messageId?: string;
|
|
166
|
+
from: string;
|
|
167
|
+
to?: string;
|
|
168
|
+
metadata?: Record<string, unknown>;
|
|
124
169
|
}
|
|
170
|
+
type InvokeHandler<Params = any, Result = any> = (params: Params, context: InvokeContext) => Result | Promise<Result>;
|
|
171
|
+
type NotificationHandler<Params = any> = (params: Params, context: InvokeContext) => void;
|
|
125
172
|
type ErrorHandler = (error: Error, context?: Record<string, unknown>) => void;
|
|
126
173
|
interface Metrics {
|
|
127
174
|
messagesSent: number;
|
|
@@ -133,21 +180,17 @@ interface Metrics {
|
|
|
133
180
|
averageLatency: number;
|
|
134
181
|
}
|
|
135
182
|
type MetricsCallback = (metrics: Metrics) => void;
|
|
136
|
-
declare class MessageNexus<
|
|
183
|
+
declare class MessageNexus<GlobalRequestPayload = unknown, GlobalResponsePayload = unknown> {
|
|
137
184
|
driver: BaseDriver;
|
|
138
185
|
pendingTasks: Map<string, {
|
|
139
|
-
resolve: (value:
|
|
186
|
+
resolve: (value: any) => void;
|
|
140
187
|
reject: (reason?: unknown) => void;
|
|
141
188
|
timer: ReturnType<typeof setTimeout>;
|
|
142
189
|
to?: string;
|
|
143
190
|
timestamp: number;
|
|
144
191
|
}>;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
type: string;
|
|
148
|
-
timestamp: number;
|
|
149
|
-
}>;
|
|
150
|
-
messageHandlers: Set<(data: CommandMessage) => void>;
|
|
192
|
+
invokeHandlers: Map<string, InvokeHandler>;
|
|
193
|
+
notificationHandlers: Map<string, Set<NotificationHandler>>;
|
|
151
194
|
timeout: number;
|
|
152
195
|
instanceId: string;
|
|
153
196
|
private cleanupInterval;
|
|
@@ -158,18 +201,23 @@ declare class MessageNexus<RequestPayload = unknown, ResponsePayload = unknown>
|
|
|
158
201
|
private metrics;
|
|
159
202
|
private metricsCallbacks;
|
|
160
203
|
constructor(driver: BaseDriver, options?: MessageNexusOptions);
|
|
161
|
-
|
|
204
|
+
invoke<T = GlobalResponsePayload>(methodOrOptions: string | InvokeOptions): Promise<T>;
|
|
162
205
|
private _sendMessage;
|
|
163
206
|
onError(handler: ErrorHandler): () => void;
|
|
164
207
|
flushQueue(): void;
|
|
208
|
+
notify(methodOrOptions: string | NotificationOptions): void;
|
|
165
209
|
private _validateMessage;
|
|
166
|
-
_handleIncoming(data: unknown): void
|
|
210
|
+
_handleIncoming(data: unknown): Promise<void>;
|
|
167
211
|
getMetrics(): Metrics;
|
|
168
212
|
onMetrics(callback: MetricsCallback): () => boolean;
|
|
169
213
|
private _notifyMetrics;
|
|
170
|
-
|
|
171
|
-
|
|
214
|
+
handle<Params = any, Result = any>(method: string, handler: InvokeHandler<Params, Result>): () => boolean;
|
|
215
|
+
removeHandler(method: string): void;
|
|
216
|
+
onNotification<Params = any>(method: string, handler: NotificationHandler<Params>): () => void;
|
|
217
|
+
offNotification(method: string, handler: NotificationHandler<any>): void;
|
|
218
|
+
private _reply;
|
|
219
|
+
private _replyError;
|
|
172
220
|
destroy(): void;
|
|
173
221
|
}
|
|
174
222
|
|
|
175
|
-
export { BaseDriver, BroadcastDriver, type
|
|
223
|
+
export { BaseDriver, BroadcastDriver, type ErrorHandler, type InvokeContext, type InvokeHandler, type InvokeOptions, type LoggerInterface, type Message, type MessageNexusOptions, type Metrics, type MetricsCallback, MittDriver, type NotificationHandler, type NotificationOptions, PostMessageDriver, WebSocketDriver, createEmitter, MessageNexus as default };
|