rpc-express-toolkit 4.1.0 → 4.2.1

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
@@ -5,6 +5,7 @@
5
5
  [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
6
6
  [![npm version](https://img.shields.io/npm/v/rpc-express-toolkit.svg)](https://www.npmjs.com/package/rpc-express-toolkit)
7
7
  [![npm downloads](https://img.shields.io/npm/dm/rpc-express-toolkit.svg)](https://www.npmjs.com/package/rpc-express-toolkit)
8
+ [![node](https://img.shields.io/node/v/rpc-express-toolkit.svg)](https://www.npmjs.com/package/rpc-express-toolkit)
8
9
 
9
10
  Enterprise-ready JSON-RPC 2.0 toolkit for Express.js with simplified APIs, middleware, schema validation, batch support, and optional safe type disambiguation.
10
11
 
@@ -61,6 +62,9 @@ Safe type disambiguation is disabled by default for maximum JSON-RPC 2.0 compati
61
62
 
62
63
  ### Safe Import (opt-in)
63
64
 
65
+ [![npm (proxy)](https://img.shields.io/npm/v/rpc-express-toolkit-safe.svg)](https://www.npmjs.com/package/rpc-express-toolkit-safe)
66
+ [![safe preset](https://img.shields.io/badge/safe%20preset-available-blue)](#safe-import-opt-in)
67
+
64
68
  When you control both client and server and want safer type round-trips, import the safe preset. It enables safe serialization by default (and strict mode on the server):
65
69
 
66
70
  ```js
@@ -80,10 +84,78 @@ const client = createSafeClient('http://localhost:3000/api');
80
84
 
81
85
  This keeps JSON-RPC 2.0 compliance as default for the main entrypoint, while offering a convenient safe-mode import for projects that prefer explicit type disambiguation.
82
86
 
87
+ Alternative: npm proxy package
88
+
89
+ If you prefer a dedicated package name, you can install the thin proxy `rpc-express-toolkit-safe` which simply re-exports the safe preset:
90
+
91
+ ```bash
92
+ npm install rpc-express-toolkit-safe
93
+ ```
94
+
95
+ ```js
96
+ // Server
97
+ const express = require('express');
98
+ const { createSafeEndpoint } = require('rpc-express-toolkit-safe');
99
+ const app = express();
100
+ app.use(express.json());
101
+ const rpc = createSafeEndpoint(app, {}, { endpoint: '/api' });
102
+
103
+ // Client
104
+ const { createSafeClient } = require('rpc-express-toolkit-safe');
105
+ const client = createSafeClient('http://localhost:3000/api');
106
+ ```
107
+
108
+ ## Introspection Methods
109
+
110
+ Enable introspection to expose metadata about registered methods via reserved `__rpc.*` methods:
111
+
112
+ ```javascript
113
+ const rpc = new RpcEndpoint(app, context, {
114
+ enableIntrospection: true // Enable __rpc.* methods
115
+ });
116
+
117
+ // Register methods with public schemas
118
+ rpc.addMethod('add', async (req, ctx, params) => {
119
+ return params.a + params.b;
120
+ }, {
121
+ schema: {
122
+ type: 'object',
123
+ properties: {
124
+ a: { type: 'number' },
125
+ b: { type: 'number' }
126
+ },
127
+ required: ['a', 'b']
128
+ },
129
+ exposeSchema: true, // Make schema publicly queryable
130
+ description: 'Add two numbers'
131
+ });
132
+
133
+ // Available introspection methods:
134
+ // __rpc.listMethods() → ["add", "multiply", ...]
135
+ // __rpc.describe({method: "add"}) → {name, schema, description}
136
+ // __rpc.describeAll() → [{name, schema, description}, ...]
137
+ // __rpc.version() → {toolkit, version, expressVersion, nodeVersion}
138
+ // __rpc.capabilities() → {safeMode, batch, introspection, ...}
139
+
140
+ // Client usage
141
+ const methods = await client.call('__rpc.listMethods');
142
+ const addInfo = await client.call('__rpc.describe', { method: 'add' });
143
+ ```
144
+
145
+ **Note:** The introspection prefix is configurable via `introspectionPrefix` option (default: `__rpc`). User methods starting with this prefix are rejected to prevent conflicts.
146
+
83
147
  ## Full Details
84
148
 
85
149
  For advanced configuration, middleware, structured logging, safe serialization, error handling, and more, see `README_ADVANCED.md`.
86
150
 
151
+ ## 🔗 Related Projects
152
+
153
+ - [rpc-php-toolkit](https://github.com/n-car/rpc-php-toolkit) - PHP implementation
154
+ - [rpc-dotnet-toolkit](https://github.com/n-car/rpc-dotnet-toolkit) - .NET implementation
155
+ - [rpc-arduino-toolkit](https://github.com/n-car/rpc-arduino-toolkit) - Arduino/ESP32 implementation
156
+ - [rpc-java-toolkit](https://github.com/n-car/rpc-java-toolkit) - Java & Android implementation
157
+ - [node-red-contrib-rpc-toolkit](https://github.com/n-car/node-red-contrib-rpc-toolkit) - Node-RED visual programming
158
+
87
159
  ## Contributing
88
160
 
89
161
  ```bash
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Introspection Example - Client
3
+ * Demonstrates how to use __rpc.* introspection methods
4
+ */
5
+
6
+ const { RpcClient } = require('../..');
7
+
8
+ async function main() {
9
+ const client = new RpcClient('http://localhost:3000/api');
10
+
11
+ console.log('=== RPC Introspection Demo ===\n');
12
+
13
+ // 1. List all methods
14
+ console.log('1. __rpc.listMethods():');
15
+ const methods = await client.call('__rpc.listMethods');
16
+ console.log(' Available methods:', methods);
17
+ console.log('');
18
+
19
+ // 2. Get version info
20
+ console.log('2. __rpc.version():');
21
+ const version = await client.call('__rpc.version');
22
+ console.log(' Toolkit:', version.toolkit);
23
+ console.log(' Version:', version.version);
24
+ console.log(' Express:', version.expressVersion);
25
+ console.log(' Node:', version.nodeVersion);
26
+ console.log('');
27
+
28
+ // 3. Get server capabilities
29
+ console.log('3. __rpc.capabilities():');
30
+ const caps = await client.call('__rpc.capabilities');
31
+ console.log(' Safe Mode:', caps.safeMode);
32
+ console.log(' Batch Support:', caps.batch);
33
+ console.log(' Introspection:', caps.introspection);
34
+ console.log(' Method Count:', caps.methodCount);
35
+ console.log('');
36
+
37
+ // 4. Describe a specific method
38
+ console.log('4. __rpc.describe({ method: "add" }):');
39
+ const addInfo = await client.call('__rpc.describe', { method: 'add' });
40
+ console.log(' Name:', addInfo.name);
41
+ console.log(' Description:', addInfo.description);
42
+ console.log(' Schema:', JSON.stringify(addInfo.schema, null, 2));
43
+ console.log('');
44
+
45
+ // 5. Describe all public methods
46
+ console.log('5. __rpc.describeAll():');
47
+ const allMethods = await client.call('__rpc.describeAll');
48
+ allMethods.forEach((method) => {
49
+ console.log(` - ${method.name}: ${method.description}`);
50
+ });
51
+ console.log('');
52
+
53
+ // 6. Try to describe a private method (should fail)
54
+ console.log('6. Try to describe private method:');
55
+ try {
56
+ await client.call('__rpc.describe', { method: 'internalCalculation' });
57
+ } catch (error) {
58
+ console.log(' Error:', error.message);
59
+ }
60
+ console.log('');
61
+
62
+ // 7. Test a public method
63
+ console.log('7. Call add method:');
64
+ const sum = await client.call('add', { a: 5, b: 3 });
65
+ console.log(' 5 + 3 =', sum);
66
+ }
67
+
68
+ main().catch(console.error);
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Introspection Example - Server
3
+ * Demonstrates how to enable and use __rpc.* introspection methods
4
+ */
5
+
6
+ const express = require('express');
7
+ const { RpcEndpoint } = require('../..');
8
+
9
+ const app = express();
10
+ app.use(express.json());
11
+
12
+ // Context for methods
13
+ const context = {
14
+ database: 'mock-db',
15
+ config: { maxValue: 1000 },
16
+ };
17
+
18
+ // Create endpoint with introspection enabled
19
+ const rpc = new RpcEndpoint(app, context, {
20
+ endpoint: '/api',
21
+ enableIntrospection: true, // Enable __rpc.* methods
22
+ introspectionPrefix: '__rpc', // Optional: customize prefix (default: __rpc)
23
+ });
24
+
25
+ // Public method with exposed schema
26
+ rpc.addMethod('add', async (req, ctx, params) => params.a + params.b, {
27
+ schema: {
28
+ type: 'object',
29
+ properties: {
30
+ a: { type: 'number' },
31
+ b: { type: 'number' },
32
+ },
33
+ required: ['a', 'b'],
34
+ },
35
+ exposeSchema: true,
36
+ description: 'Add two numbers and return the sum',
37
+ });
38
+
39
+ // Public method with exposed schema
40
+ rpc.addMethod('multiply', async (req, ctx, params) => params.a * params.b, {
41
+ schema: {
42
+ type: 'object',
43
+ properties: {
44
+ a: { type: 'number' },
45
+ b: { type: 'number' },
46
+ },
47
+ required: ['a', 'b'],
48
+ },
49
+ exposeSchema: true,
50
+ description: 'Multiply two numbers',
51
+ });
52
+
53
+ // Private method (schema not exposed)
54
+ rpc.addMethod(
55
+ 'internalCalculation',
56
+ async (req, ctx, params) => params.value * 2 + 42,
57
+ {
58
+ schema: {
59
+ type: 'object',
60
+ properties: {
61
+ value: { type: 'number' },
62
+ },
63
+ required: ['value'],
64
+ },
65
+ exposeSchema: false, // Schema is private
66
+ description: 'Internal calculation (not exposed)',
67
+ }
68
+ );
69
+
70
+ // Public method without schema
71
+ rpc.addMethod('echo', async (req, ctx, params) => params, {
72
+ exposeSchema: true,
73
+ description: 'Echo back the parameters',
74
+ });
75
+
76
+ // Start server
77
+ const PORT = process.env.PORT || 3000;
78
+ app.listen(PORT, () => {
79
+ console.log(
80
+ `RPC Server with introspection running on http://localhost:${PORT}/api`
81
+ );
82
+ console.log('\nAvailable introspection methods:');
83
+ console.log('- __rpc.listMethods()');
84
+ console.log('- __rpc.describe({method: "add"})');
85
+ console.log('- __rpc.describeAll()');
86
+ console.log('- __rpc.version()');
87
+ console.log('- __rpc.capabilities()');
88
+ console.log('\nTry: node client.js');
89
+ });
@@ -1,6 +1,6 @@
1
1
  const express = require('express');
2
2
  /* eslint-disable import/no-unresolved, prettier/prettier */
3
- const { createSafeEndpoint, createSafeClient } = require('rpc-express-toolkit/safe');
3
+ const { RpcSafeEndpoint, RpcSafeClient } = require('rpc-express-toolkit/safe');
4
4
  /* eslint-enable import/no-unresolved, prettier/prettier */
5
5
 
6
6
  async function main() {
@@ -8,7 +8,7 @@ async function main() {
8
8
  app.use(express.json());
9
9
 
10
10
  // Server with safe defaults (safeEnabled=true, strictMode=true)
11
- const rpc = createSafeEndpoint(app, {}, { endpoint: '/api' });
11
+ const rpc = new RpcSafeEndpoint(app, {}, { endpoint: '/api' });
12
12
 
13
13
  rpc.addMethod('sum', (req, ctx, params) => {
14
14
  // params are already deserialized according to the client's safe header
@@ -29,7 +29,7 @@ async function main() {
29
29
  console.log('Safe server listening on', url);
30
30
 
31
31
  // Safe client (sends header and expects safe response)
32
- const client = createSafeClient(url);
32
+ const client = new RpcSafeClient(url);
33
33
  const res = await client.call('sum', { a: '10n', b: '32n' });
34
34
  console.log('sum result (BigInt):', res.toString());
35
35
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rpc-express-toolkit",
3
- "version": "4.1.0",
3
+ "version": "4.2.1",
4
4
  "description": "Enterprise-ready JSON-RPC 2.0 toolkit for Express.js with simplified APIs, structured logging, middleware system, schema validation, comprehensive BigInt/Date support. JSON middleware validation and explicit configuration.",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
package/src/batch.js CHANGED
@@ -140,8 +140,8 @@ class BatchHandler {
140
140
  };
141
141
  }
142
142
 
143
- const handler = this.endpoint.methods[method];
144
- if (!handler) {
143
+ const methodConfig = this.endpoint.methods[method];
144
+ if (!methodConfig) {
145
145
  return {
146
146
  jsonrpc: '2.0',
147
147
  id: id || null,
@@ -153,6 +153,10 @@ class BatchHandler {
153
153
  };
154
154
  }
155
155
 
156
+ // Extract handler (support both function and config object)
157
+ const handler =
158
+ typeof methodConfig === 'function' ? methodConfig : methodConfig.handler;
159
+
156
160
  // If no id is provided, this is a notification - don't return response
157
161
  const isNotification = id === undefined || id === null;
158
162