rpc-express-toolkit 3.0.2 β 4.0.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 +32 -1027
- package/examples/server-client-example.js +26 -26
- package/examples/ssl-development-example.js +18 -49
- package/package.json +18 -5
- package/src/batch.js +10 -1
- package/src/clients/rpc-client.js +139 -86
- package/src/clients/rpc-client.min.js +1 -1
- package/src/clients/rpc-client.min.mjs +1 -1
- package/src/clients/rpc-client.mjs +82 -37
- package/src/index.d.ts +16 -15
- package/src/index.js +118 -60
- package/src/logger.js +35 -15
- package/src/middleware.js +40 -25
- package/src/validation.js +1 -0
|
@@ -10,7 +10,7 @@ const context = {
|
|
|
10
10
|
userId: 'system',
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
// Create JSON-RPC endpoint
|
|
13
|
+
// Create JSON-RPC endpoint
|
|
14
14
|
const rpc = new RpcEndpoint(app, context);
|
|
15
15
|
|
|
16
16
|
// Add some methods
|
|
@@ -29,12 +29,12 @@ rpc.addMethod('getData', (req, ctx, params) => {
|
|
|
29
29
|
return { key, value };
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
rpc.addMethod('getAllData', (req, ctx) =>
|
|
33
|
-
|
|
32
|
+
rpc.addMethod('getAllData', (req, ctx) =>
|
|
33
|
+
Array.from(ctx.database.entries()).map(([key, value]) => ({
|
|
34
34
|
key,
|
|
35
35
|
value,
|
|
36
|
-
}))
|
|
37
|
-
|
|
36
|
+
}))
|
|
37
|
+
);
|
|
38
38
|
|
|
39
39
|
rpc.addMethod('testBigInt', (req, ctx, params) => {
|
|
40
40
|
const bigNumber = BigInt(params.number || '123456789012345678901234567890');
|
|
@@ -49,61 +49,61 @@ rpc.addMethod('testBigInt', (req, ctx, params) => {
|
|
|
49
49
|
// Start server
|
|
50
50
|
const PORT = process.env.PORT || 3000;
|
|
51
51
|
const server = app.listen(PORT, () => {
|
|
52
|
-
console.log(
|
|
53
|
-
console.log(
|
|
52
|
+
console.log(`Server running on http://localhost:${PORT}`);
|
|
53
|
+
console.log(`Endpoint: http://localhost:${PORT}/api`);
|
|
54
54
|
|
|
55
55
|
// === CLIENT DEMO ===
|
|
56
56
|
setTimeout(async () => {
|
|
57
|
-
console.log('\
|
|
57
|
+
console.log('\nTesting client...');
|
|
58
58
|
|
|
59
59
|
const client = new RpcClient(`http://localhost:${PORT}/api`);
|
|
60
60
|
|
|
61
61
|
try {
|
|
62
62
|
// Test 1: Save some data
|
|
63
|
-
console.log('
|
|
63
|
+
console.log('Saving data...');
|
|
64
64
|
const saveResult = await client.call('saveData', {
|
|
65
65
|
key: 'test',
|
|
66
66
|
value: 'Hello World!',
|
|
67
67
|
});
|
|
68
|
-
console.log('
|
|
68
|
+
console.log('Save result:', saveResult);
|
|
69
69
|
|
|
70
70
|
// Test 2: Get data back
|
|
71
|
-
console.log('\
|
|
71
|
+
console.log('\nGetting data...');
|
|
72
72
|
const getData = await client.call('getData', { key: 'test' });
|
|
73
|
-
console.log('
|
|
73
|
+
console.log('Get result:', getData);
|
|
74
74
|
|
|
75
75
|
// Test 3: Test BigInt handling
|
|
76
|
-
console.log('\
|
|
76
|
+
console.log('\nTesting BigInt...');
|
|
77
77
|
const bigIntResult = await client.call('testBigInt', {
|
|
78
78
|
number: '999999999999999999999999999999',
|
|
79
79
|
});
|
|
80
|
-
console.log('
|
|
81
|
-
console.log(' -
|
|
82
|
-
console.log(' -
|
|
83
|
-
console.log(' -
|
|
80
|
+
console.log('BigInt result:', bigIntResult);
|
|
81
|
+
console.log(' - bigint type:', typeof bigIntResult.bigint);
|
|
82
|
+
console.log(' - doubled type:', typeof bigIntResult.doubled);
|
|
83
|
+
console.log(' - timestamp type:', typeof bigIntResult.timestamp);
|
|
84
84
|
|
|
85
85
|
// Test 4: Get all data
|
|
86
|
-
console.log('\
|
|
86
|
+
console.log('\nGetting all data...');
|
|
87
87
|
const allData = await client.call('getAllData');
|
|
88
|
-
console.log('
|
|
88
|
+
console.log('All data:', allData);
|
|
89
89
|
|
|
90
90
|
// Test 5: Test error handling
|
|
91
|
-
console.log('\
|
|
91
|
+
console.log('\nTesting error handling...');
|
|
92
92
|
try {
|
|
93
93
|
await client.call('getData', { key: 'nonexistent' });
|
|
94
94
|
} catch (error) {
|
|
95
|
-
console.log('
|
|
95
|
+
console.log('Error caught correctly:', error.message);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
console.log('\
|
|
98
|
+
console.log('\nAll tests completed successfully!');
|
|
99
99
|
} catch (error) {
|
|
100
|
-
console.error('
|
|
100
|
+
console.error('Client error:', error);
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
// Close server after demo
|
|
104
104
|
setTimeout(() => {
|
|
105
105
|
server.close(() => {
|
|
106
|
-
console.log('\
|
|
106
|
+
console.log('\nServer closed');
|
|
107
107
|
process.exit(0);
|
|
108
108
|
});
|
|
109
109
|
}, 1000);
|
|
@@ -112,9 +112,9 @@ const server = app.listen(PORT, () => {
|
|
|
112
112
|
|
|
113
113
|
// Handle graceful shutdown
|
|
114
114
|
process.on('SIGINT', () => {
|
|
115
|
-
console.log('\
|
|
115
|
+
console.log('\nShutting down server...');
|
|
116
116
|
server.close(() => {
|
|
117
|
-
console.log('
|
|
117
|
+
console.log('Server closed');
|
|
118
118
|
process.exit(0);
|
|
119
119
|
});
|
|
120
120
|
});
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars, no-console */
|
|
1
2
|
/**
|
|
2
|
-
* Example
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
console.log(' β Disable validation only for development with self-signed certificates');
|
|
6
|
-
console.log(' β Use environment variables to control SSL behavior');
|
|
7
|
-
console.log(' β Never commit process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0" to production');
|
|
8
|
-
console.log(' β Consider using valid development certificates instead of disabling validation\n');o use RpcClient with self-signed certificates
|
|
9
|
-
* in development environments.
|
|
10
|
-
*
|
|
11
|
-
* WARNING: Only use rejectUnauthorized: false in development!
|
|
12
|
-
* Never use this in production as it disables SSL certificate validation.
|
|
3
|
+
* Example: Using RpcClient with self-signed certificates in development.
|
|
4
|
+
*
|
|
5
|
+
* WARNING: Do not disable SSL validation in production.
|
|
13
6
|
*/
|
|
14
7
|
|
|
15
8
|
const { RpcClient } = require('../src/index.js');
|
|
@@ -22,35 +15,33 @@ async function demonstrateSSLOptions() {
|
|
|
22
15
|
const productionClient = new RpcClient('https://api.example.com/rpc', {
|
|
23
16
|
Authorization: 'Bearer prod-token',
|
|
24
17
|
});
|
|
25
|
-
console.log('
|
|
18
|
+
console.log(' - Created client with strict SSL validation (default)\n');
|
|
26
19
|
|
|
27
|
-
// Example 2: Development client for self-signed certificates (
|
|
28
|
-
console.log('2. Development Client (
|
|
20
|
+
// Example 2: Development client for self-signed certificates (bypass validation)
|
|
21
|
+
console.log('2. Development Client (bypass SSL validation):');
|
|
29
22
|
console.log(
|
|
30
|
-
'
|
|
23
|
+
' To bypass SSL validation in Node.js, set BEFORE starting the client:'
|
|
31
24
|
);
|
|
32
25
|
console.log(' process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";');
|
|
33
26
|
console.log(
|
|
34
|
-
'
|
|
27
|
+
' - All requests will accept self-signed certificates (development only!)\n'
|
|
35
28
|
);
|
|
36
29
|
|
|
37
|
-
// Example 3: Best
|
|
30
|
+
// Example 3: Best practices summary
|
|
38
31
|
console.log('3. Best Practices:');
|
|
39
|
-
console.log('
|
|
40
|
-
console.log(
|
|
41
|
-
' β Disabilita la validazione solo per sviluppo con self-signed'
|
|
42
|
-
);
|
|
32
|
+
console.log(' - Always use SSL validation in production');
|
|
43
33
|
console.log(
|
|
44
|
-
'
|
|
34
|
+
' - Disable validation only for development with self-signed certificates'
|
|
45
35
|
);
|
|
36
|
+
console.log(' - Use environment variables to control SSL behavior');
|
|
46
37
|
console.log(
|
|
47
|
-
'
|
|
38
|
+
' - Never commit process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0" to production'
|
|
48
39
|
);
|
|
49
40
|
console.log(
|
|
50
|
-
'
|
|
41
|
+
' - Consider using valid development certificates instead of disabling validation\n'
|
|
51
42
|
);
|
|
52
43
|
|
|
53
|
-
// Example 4:
|
|
44
|
+
// Example 4: Choose configuration based on environment
|
|
54
45
|
console.log('4. Environment-based Configuration:');
|
|
55
46
|
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
56
47
|
const baseUrl = isDevelopment
|
|
@@ -61,32 +52,10 @@ async function demonstrateSSLOptions() {
|
|
|
61
52
|
'X-Environment': process.env.NODE_ENV || 'development',
|
|
62
53
|
});
|
|
63
54
|
console.log(
|
|
64
|
-
`
|
|
65
|
-
);
|
|
66
|
-
console.log(
|
|
67
|
-
` β SSL validation: ${isDevelopment ? 'controlled by NODE_TLS_REJECT_UNAUTHORIZED' : 'enabled (secure)'}\n`
|
|
68
|
-
);
|
|
69
|
-
|
|
70
|
-
// Example usage (commented out since we don't have a real server)
|
|
71
|
-
/*
|
|
72
|
-
try {
|
|
73
|
-
// This would work with a real server
|
|
74
|
-
const result = await developmentClient.call('ping', {});
|
|
75
|
-
console.log('Server response:', result);
|
|
76
|
-
} catch (error) {
|
|
77
|
-
console.error('Error calling server:', error.message);
|
|
78
|
-
}
|
|
79
|
-
*/
|
|
80
|
-
|
|
81
|
-
console.log('5. Best Practices Summary:');
|
|
82
|
-
console.log(' β Always use strict SSL validation in production');
|
|
83
|
-
console.log(
|
|
84
|
-
' β Only disable SSL validation for development with self-signed certificates'
|
|
55
|
+
` - Created client for ${isDevelopment ? 'development' : 'production'} environment`
|
|
85
56
|
);
|
|
86
|
-
console.log(' β Use environment variables to control SSL behavior');
|
|
87
|
-
console.log(' β Never commit rejectUnauthorized: false to production code');
|
|
88
57
|
console.log(
|
|
89
|
-
|
|
58
|
+
` - SSL validation: ${isDevelopment ? 'controlled by NODE_TLS_REJECT_UNAUTHORIZED' : 'enabled (secure)'}\n`
|
|
90
59
|
);
|
|
91
60
|
|
|
92
61
|
console.log('=== Example Complete ===');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rpc-express-toolkit",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.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",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"clean": "node -e \"require('fs').existsSync('dist') && require('fs').rmSync('dist', {recursive: true})\"",
|
|
20
20
|
"build": "npm run build:minify",
|
|
21
21
|
"build:minify": "npm run build:js && npm run build:mjs",
|
|
22
|
-
"build:js": "terser src/clients/rpc-client.js -o src/clients/rpc-client.min.js --compress --mangle --comments false",
|
|
23
|
-
"build:mjs": "terser src/clients/rpc-client.mjs -o src/clients/rpc-client.min.mjs --compress --mangle --comments false --module",
|
|
22
|
+
"build:js": "terser src/clients/rpc-client.js -o src/clients/rpc-client.min.js --compress --mangle --comments false --ecma 2020",
|
|
23
|
+
"build:mjs": "terser src/clients/rpc-client.mjs -o src/clients/rpc-client.min.mjs --compress --mangle --comments false --module --ecma 2020",
|
|
24
24
|
"prepublishOnly": "npm run build",
|
|
25
25
|
"precommit": "npm run lint && npm test"
|
|
26
26
|
},
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
},
|
|
31
31
|
"keywords": [
|
|
32
32
|
"json-rpc",
|
|
33
|
+
"jsonrpc",
|
|
34
|
+
"json-rpc-2.0",
|
|
33
35
|
"express",
|
|
34
36
|
"toolkit",
|
|
35
37
|
"rpc",
|
|
@@ -37,13 +39,24 @@
|
|
|
37
39
|
"client",
|
|
38
40
|
"middleware",
|
|
39
41
|
"validation",
|
|
42
|
+
"schema",
|
|
43
|
+
"ajv",
|
|
40
44
|
"bigint",
|
|
45
|
+
"date",
|
|
41
46
|
"enterprise",
|
|
42
47
|
"nodejs",
|
|
48
|
+
"node",
|
|
49
|
+
"browser",
|
|
43
50
|
"ssl",
|
|
44
51
|
"self-signed",
|
|
45
52
|
"secure",
|
|
46
|
-
"fetch"
|
|
53
|
+
"fetch",
|
|
54
|
+
"batch",
|
|
55
|
+
"typescript",
|
|
56
|
+
"logging",
|
|
57
|
+
"cors",
|
|
58
|
+
"rate-limit",
|
|
59
|
+
"authentication"
|
|
47
60
|
],
|
|
48
61
|
"author": "Nicola Carpanese <nicola.carpanese@gmail.com>",
|
|
49
62
|
"license": "MIT",
|
|
@@ -52,7 +65,7 @@
|
|
|
52
65
|
},
|
|
53
66
|
"homepage": "https://github.com/n-car/rpc-express-toolkit#readme",
|
|
54
67
|
"engines": {
|
|
55
|
-
"node": ">=
|
|
68
|
+
"node": ">=18.0.0"
|
|
56
69
|
},
|
|
57
70
|
"devDependencies": {
|
|
58
71
|
"eslint": "^8.57.1",
|
package/src/batch.js
CHANGED
|
@@ -156,12 +156,21 @@ class BatchHandler {
|
|
|
156
156
|
// If no id is provided, this is a notification - don't return response
|
|
157
157
|
const isNotification = id === undefined || id === null;
|
|
158
158
|
|
|
159
|
+
// Determine client safe mode from headers and deserialize params accordingly
|
|
160
|
+
const clientSafeHeader = req.headers['x-rpc-safe-enabled'];
|
|
161
|
+
const clientSafeEnabled = clientSafeHeader === 'true';
|
|
162
|
+
const deserializedParams = params
|
|
163
|
+
? this.endpoint.deserializeBigIntsAndDates(params, {
|
|
164
|
+
safeEnabled: clientSafeEnabled,
|
|
165
|
+
})
|
|
166
|
+
: params;
|
|
167
|
+
|
|
159
168
|
// Initialize middleware context
|
|
160
169
|
let middlewareContext = {
|
|
161
170
|
req,
|
|
162
171
|
res: null, // No response object for batch items
|
|
163
172
|
method,
|
|
164
|
-
params,
|
|
173
|
+
params: deserializedParams,
|
|
165
174
|
context,
|
|
166
175
|
batchIndex,
|
|
167
176
|
isNotification,
|