message-nexus 1.1.1 → 1.1.3

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 CHANGED
@@ -22,7 +22,8 @@ pnpm add message-nexus
22
22
  - **Retry Mechanism**: Automatic retry on request failure, configurable retry counts and delays
23
23
  - **Message Validation**: Runtime message format validation to prevent illegal messages
24
24
  - **Monitoring Metrics**: Built-in message statistics and performance monitoring
25
- - **Structured Logging**: Supports custom log handlers for easy debugging and production monitoring
25
+ - **Structured Logging**: Supports adjustable log levels (DEBUG, INFO, WARN, ERROR) and custom log handlers or simple loggers (like `console`) for easy debugging and production monitoring.
26
+
26
27
  - **Resource Management**: All drivers support the `destroy()` method to properly clean up resources.
27
28
 
28
29
  ## Quick Start
@@ -156,19 +157,39 @@ receiverNexus.handle('SYNC_STATE', (params, context) => {
156
157
  #### Constructor
157
158
 
158
159
  ```typescript
159
- new MessageNexus<RequestPayload, ResponsePayload>(
160
+ new MessageNexus<InvokeMap, NotificationMap>(
160
161
  driver: BaseDriver,
161
162
  options?: MessageNexusOptions
162
163
  )
163
164
  ```
164
165
 
166
+ **Generics:**
167
+
168
+ - `InvokeMap`: A record mapping method names to `{ params: any; result: any }`. Defaults to `DefaultRegistry`.
169
+ - `NotificationMap`: A record mapping notification method names to their parameter types. Defaults to `Record<string, any>`.
170
+
165
171
  **Options:**
166
172
 
167
- | Parameter | Type | Default Value | Description |
168
- | ---------- | ------ | -------------- | ------------------------------------- |
169
- | instanceId | string | auto-generated | Instance ID, used for message routing |
170
- | timeout | number | 10000 | Request timeout (milliseconds) |
171
- | logger | Logger | new Logger() | Logger instance |
173
+ | Parameter | Type | Default Value | Description |
174
+ | ------------- | ---------------------------- | -------------- | ------------------------------------------ |
175
+ | instanceId | string | auto-generated | Instance ID, used for message routing |
176
+ | timeout | number | 10000 | Request timeout (milliseconds) |
177
+ | logger | LoggerInterface \| SimpleLogger | new Logger() | Logger instance or simple logger (e.g. `console`) |
178
+ | loggerEnabled | boolean | false | Whether to enable logging |
179
+ | logLevel | LogLevel | LogLevel.INFO | Minimum log level to report |
180
+
181
+ **LogLevel:** `DEBUG`, `INFO`, `WARN`, `ERROR`
182
+
183
+ **SimpleLogger Interface:**
184
+
185
+ ```typescript
186
+ interface SimpleLogger {
187
+ debug(message: string, metadata?: Record<string, unknown>): void
188
+ info(message: string, metadata?: Record<string, unknown>): void
189
+ warn(message: string, metadata?: Record<string, unknown>): void
190
+ error(message: string, metadata?: Record<string, unknown>): void
191
+ }
192
+ ```
172
193
 
173
194
  #### Methods
174
195
 
@@ -177,15 +198,17 @@ new MessageNexus<RequestPayload, ResponsePayload>(
177
198
  Send request and wait for response.
178
199
 
179
200
  ```typescript
180
- nexus.invoke<T>(methodOrOptions: string | InvokeOptions): Promise<T>
201
+ nexus.invoke<K extends keyof InvokeMap>(
202
+ methodOrOptions: K | InvokeOptions<K, InvokeMap[K]['params']>
203
+ ): Promise<InvokeMap[K]['result']>
181
204
  ```
182
205
 
183
206
  **Options:**
184
207
 
185
208
  | Parameter | Type | Required | Description |
186
209
  | ---------- | ----------------------- | -------- | ---------------------------- |
187
- | method | string | Yes | Message method |
188
- | params | unknown | No | Request data |
210
+ | method | K | Yes | Message method |
211
+ | params | InvokeMap[K]['params'] | No | Request data |
189
212
  | to | string | No | Target instance ID |
190
213
  | metadata | Record<string, unknown> | No | Metadata |
191
214
  | timeout | number | No | Timeout (overrides global) |
@@ -214,15 +237,17 @@ const result = await nexus.invoke({
214
237
  Send a one-way notification (Fire-and-Forget). Does not wait for a response and does not generate an ID. Complies with JSON-RPC 2.0 Notification specification.
215
238
 
216
239
  ```typescript
217
- nexus.notify(methodOrOptions: string | Omit<InvokeOptions, 'timeout' | 'retryCount' | 'retryDelay'>): void
240
+ nexus.notify<K extends keyof NotificationMap>(
241
+ methodOrOptions: K | NotificationOptions<K, NotificationMap[K]>
242
+ ): void
218
243
  ```
219
244
 
220
245
  **Options:**
221
246
 
222
247
  | Parameter | Type | Required | Description |
223
248
  | --------- | ----------------------- | -------- | ------------------- |
224
- | method | string | Yes | Notification method |
225
- | params | unknown | No | Notification data |
249
+ | method | K | Yes | Notification method |
250
+ | params | NotificationMap[K] | No | Notification data |
226
251
  | to | string | No | Target instance ID |
227
252
  | metadata | Record<string, unknown> | No | Metadata |
228
253
 
@@ -245,7 +270,10 @@ nexus.notify({
245
270
  Register a request handler for a specific method. The return value (or resolved value of a returned Promise) is automatically sent back as the response.
246
271
 
247
272
  ```typescript
248
- nexus.handle<Params, Result>(method: string, handler: InvokeHandler<Params, Result>): () => void
273
+ nexus.handle<K extends keyof InvokeMap>(
274
+ method: K,
275
+ handler: InvokeHandler<InvokeMap[K]['params'], InvokeMap[K]['result']>
276
+ ): () => void
249
277
  ```
250
278
 
251
279
  **Parameters:**
@@ -279,7 +307,10 @@ unsubscribe()
279
307
  Register a handler for a specific notification method (one-way messages).
280
308
 
281
309
  ```typescript
282
- nexus.onNotification<Params>(method: string, handler: NotificationHandler<Params>): () => void
310
+ nexus.onNotification<K extends keyof NotificationMap>(
311
+ method: K,
312
+ handler: NotificationHandler<NotificationMap[K]>
313
+ ): () => void
283
314
  ```
284
315
 
285
316
  **Example:**
@@ -295,22 +326,56 @@ unsubscribe()
295
326
 
296
327
  ##### onError()
297
328
 
298
- Register error handler.
329
+ Register a global error handler for background errors (e.g., driver failures, invalid incoming messages). For request-specific errors, use `try/catch` with `invoke()`.
299
330
 
300
331
  ```typescript
301
- nexus.onError(handler: ErrorHandler): () => void
332
+ nexus.onError(handler: (error: Error | NexusError, context?: Record<string, unknown>) => void): () => void
302
333
  ```
303
334
 
304
335
  **Example:**
305
336
 
306
337
  ```typescript
307
338
  nexus.onError((error, context) => {
308
- console.error('Bridge error:', error.message, context)
339
+ if (error instanceof NexusError) {
340
+ console.error(`Bridge error [${error.code}]: ${error.message}`, error.data)
341
+ } else {
342
+ console.error('System error:', error.message)
343
+ }
309
344
  // Send to error tracking service
310
345
  Sentry.captureException(error, { extra: context })
311
346
  })
312
347
  ```
313
348
 
349
+ #### Errors
350
+
351
+ MessageNexus provides a structured error system based on the JSON-RPC 2.0 specification.
352
+
353
+ ##### NexusError
354
+
355
+ A custom error class that includes a numeric code and optional data.
356
+
357
+ ```typescript
358
+ class NexusError<D = any> extends Error {
359
+ code: number // JSON-RPC or Nexus-specific error code
360
+ data?: D // Optional additional error information
361
+ }
362
+ ```
363
+
364
+ ##### NexusErrorCode
365
+
366
+ Common error codes exported by the library:
367
+
368
+ | Code | Name | Description |
369
+ | --- | --- | --- |
370
+ | -32700 | `ParseError` | Invalid JSON received by the server |
371
+ | -32600 | `InvalidRequest` | The JSON sent is not a valid Request object |
372
+ | -32601 | `MethodNotFound` | The method does not exist / is not registered |
373
+ | -32602 | `InvalidParams` | Invalid method parameter(s) |
374
+ | -32603 | `InternalError` | Internal JSON-RPC error (e.g., handler threw an exception) |
375
+ | -32001 | `Timeout` | Request timed out |
376
+ | -32002 | `SendFailed` | Failed to send message via driver |
377
+ | -32003 | `InvalidResponse` | Received a response that doesn't match the request |
378
+
314
379
  ##### getMetrics()
315
380
 
316
381
  Get monitoring metrics.
@@ -547,28 +612,33 @@ function onUserConfirm(id: string) {
547
612
 
548
613
  ### 1. Type Safety
549
614
 
550
- MessageNexus uses TypeScript generics to provide full type inference:
615
+ MessageNexus uses TypeScript generics and Schema mapping to provide full type inference across method names, parameters, and results:
551
616
 
552
617
  ```typescript
553
- interface UserRequest {
554
- userId: number
618
+ // 1. Define your protocol schemas
619
+ interface MyInvokeMap {
620
+ 'getUser': { params: { id: number }; result: { name: string; age: number } };
621
+ 'calculate': { params: { a: number; b: number }; result: number };
555
622
  }
556
623
 
557
- interface UserResponse {
558
- id: number
559
- name: string
624
+ interface MyNotificationMap {
625
+ 'onLog': { message: string; level: 'info' | 'warn' | 'error' };
560
626
  }
561
627
 
562
- const nexus = new MessageNexus<UserRequest, UserResponse>(driver)
628
+ // 2. Initialize with your schemas
629
+ const nexus = new MessageNexus<MyInvokeMap, MyNotificationMap>(driver)
563
630
 
564
- // Full type inference
565
- const response = await nexus.invoke({
566
- method: 'GET_USER',
567
- params: { userId: 123 }, // Type: UserRequest
568
- })
631
+ // 3. Enjoy full type inference and autocompletion
632
+ const response = await nexus.invoke('getUser', { id: 123 })
633
+ // response Type: { name: string; age: number }
569
634
 
570
- // response Type: UserResponse
571
- console.log(response.name)
635
+ nexus.notify('onLog', { message: 'Ready', level: 'info' })
636
+
637
+ // 4. Type-safe handlers
638
+ nexus.handle('calculate', (params) => {
639
+ // params Type: { a: number; b: number }
640
+ return params.a + params.b // result Type must be number
641
+ })
572
642
  ```
573
643
 
574
644
  ### 2. Memory Safety
@@ -581,12 +651,13 @@ console.log(response.name)
581
651
  - **Driver Lifecycle**: Each driver implements the `destroy()` method to correctly release resources
582
652
  - **Emitter Isolation**: Recommended to use `createEmitter()` to create independent instances, avoiding memory leaks caused by shared singletons
583
653
 
584
- ### 3. Error Recovery
654
+ ### 3. Error Recovery & Handling
585
655
 
586
656
  - **Auto Reconnect**: WebSocket automatic reconnection mechanism with exponential backoff strategy
587
657
  - **Request Retry**: Automatic retry on request failure, configurable retry counts and delays
588
658
  - **Message Queue**: Offline message caching, automatically sent after connection recovery
589
- - **Error Callback**: Unified error handling mechanism
659
+ - **Structured Error Handling**: Dedicated `NexusError` class and standard codes (JSON-RPC 2.0 compatible) for precise diagnostic and fault recovery
660
+ - **Unified Error Callback**: Global `onError` listener for non-request background errors
590
661
 
591
662
  ### 4. Security Hardening
592
663
 
@@ -610,15 +681,6 @@ console.log(`Avg latency: ${metrics.averageLatency}ms`)
610
681
  console.log(`Pending: ${metrics.pendingMessages}, Queued: ${metrics.queuedMessages}`)
611
682
  ```
612
683
 
613
- ## Testing
614
-
615
- Run unit tests:
616
-
617
- ```bash
618
- cd packages/message-nexus
619
- pnpm test:run
620
- ```
621
-
622
684
  ## License
623
685
 
624
686
  MIT