rpc-express-toolkit 4.2.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
@@ -105,10 +105,57 @@ const { createSafeClient } = require('rpc-express-toolkit-safe');
105
105
  const client = createSafeClient('http://localhost:3000/api');
106
106
  ```
107
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
+
108
147
  ## Full Details
109
148
 
110
149
  For advanced configuration, middleware, structured logging, safe serialization, error handling, and more, see `README_ADVANCED.md`.
111
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
+
112
159
  ## Contributing
113
160
 
114
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
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rpc-express-toolkit",
3
- "version": "4.2.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