rpc-express-toolkit 2.1.0 → 2.2.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 +15 -5
- package/examples/ssl-development-example.js +20 -12
- package/package.json +1 -1
- package/src/clients/rpc-client.js +17 -9
- package/src/clients/rpc-client.min.js +1 -1
- package/src/index.d.ts +11 -1
package/README.md
CHANGED
|
@@ -516,30 +516,40 @@ logger.error('Database error', {
|
|
|
516
516
|
|
|
517
517
|
### Client Configuration
|
|
518
518
|
|
|
519
|
-
The `RpcClient` supports various configuration options for different environments
|
|
519
|
+
The `RpcClient` supports various configuration options for different environments, **inclusa la gestione di certificati self-signed**:
|
|
520
520
|
|
|
521
521
|
```javascript
|
|
522
|
+
const fs = require('fs');
|
|
522
523
|
const { RpcClient } = require('rpc-express-toolkit');
|
|
523
524
|
|
|
524
525
|
// Basic client
|
|
525
526
|
const client = new RpcClient('https://api.example.com/rpc');
|
|
526
527
|
|
|
527
|
-
// Client
|
|
528
|
+
// Client con header personalizzati
|
|
528
529
|
const clientWithHeaders = new RpcClient('https://api.example.com/rpc', {
|
|
529
530
|
'Authorization': 'Bearer your-token',
|
|
530
531
|
'X-API-Key': 'your-api-key',
|
|
531
532
|
'User-Agent': 'MyApp/1.0'
|
|
532
533
|
});
|
|
533
534
|
|
|
534
|
-
// Client
|
|
535
|
+
// Client per sviluppo con certificato self-signed (accetta qualsiasi certificato, NON usare in produzione)
|
|
535
536
|
const devClient = new RpcClient('https://localhost:3000/api', {
|
|
536
537
|
'Authorization': 'Bearer dev-token'
|
|
537
538
|
}, {
|
|
538
|
-
rejectUnauthorized: false //
|
|
539
|
+
rejectUnauthorized: false // Solo per sviluppo!
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
// Client per sviluppo con CA self-signed (modo sicuro: accetta solo la tua CA)
|
|
543
|
+
const ca = fs.readFileSync('path/to/your/selfsigned-ca.pem');
|
|
544
|
+
const devClientWithCA = new RpcClient('https://localhost:3000/api', {
|
|
545
|
+
'Authorization': 'Bearer dev-token'
|
|
546
|
+
}, {
|
|
547
|
+
ca // Passa il certificato della tua CA self-signed
|
|
548
|
+
// oppure: agent: new require('https').Agent({ ca, rejectUnauthorized: true })
|
|
539
549
|
});
|
|
540
550
|
```
|
|
541
551
|
|
|
542
|
-
**⚠️ Security Warning**:
|
|
552
|
+
**⚠️ Security Warning**: Usa `rejectUnauthorized: false` solo in sviluppo. Per maggiore sicurezza, preferisci sempre la soluzione con `ca` per accettare solo la tua CA self-signed. In produzione usa sempre certificati validi e firmati da una CA attendibile.
|
|
543
553
|
|
|
544
554
|
### Built-in Middlewares
|
|
545
555
|
|
|
@@ -18,33 +18,41 @@ async function demonstrateSSLOptions() {
|
|
|
18
18
|
});
|
|
19
19
|
console.log(' ✓ Created client with strict SSL validation (default)\n');
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
// Example 2: Development client for self-signed certificates (bypasses ALL SSL validation)
|
|
22
23
|
console.log('2. Development Client (bypasses SSL validation):');
|
|
23
24
|
const developmentClient = new RpcClient('https://localhost:3000/api', {
|
|
24
25
|
'Authorization': 'Bearer dev-token',
|
|
25
26
|
'X-Environment': 'development'
|
|
26
27
|
}, {
|
|
27
|
-
rejectUnauthorized: false //
|
|
28
|
+
rejectUnauthorized: false // Solo per sviluppo!
|
|
28
29
|
});
|
|
29
30
|
console.log(' ✓ Created client that bypasses SSL certificate validation');
|
|
30
31
|
console.log(' ⚠️ WARNING: Only use this for development with self-signed certificates!\n');
|
|
31
32
|
|
|
32
|
-
// Example 3:
|
|
33
|
-
console.log('3.
|
|
34
|
-
|
|
33
|
+
// Example 3: Development client with custom CA (accepts only your self-signed CA)
|
|
34
|
+
console.log('3. Development Client with custom CA:');
|
|
35
|
+
const fs = require('fs');
|
|
36
|
+
const ca = fs.readFileSync('path/to/your/selfsigned-ca.pem');
|
|
37
|
+
const devClientWithCA = new RpcClient('https://localhost:3000/api', {
|
|
38
|
+
'Authorization': 'Bearer dev-token',
|
|
39
|
+
'X-Environment': 'development'
|
|
40
|
+
}, {
|
|
41
|
+
ca // Passa il certificato della tua CA self-signed
|
|
42
|
+
});
|
|
43
|
+
console.log(' ✓ Created client that accepts only your self-signed CA');
|
|
44
|
+
console.log(' ⚠️ WARNING: This is safer than disabling validation, but use valid certificates in production!\n');
|
|
45
|
+
|
|
46
|
+
// Example 4: Demonstrate how to choose configuration based on environment
|
|
47
|
+
console.log('4. Environment-based Configuration:');
|
|
35
48
|
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
36
49
|
const baseUrl = isDevelopment ? 'https://localhost:3000/api' : 'https://api.production.com/rpc';
|
|
37
|
-
|
|
38
50
|
const environmentClient = new RpcClient(baseUrl, {
|
|
39
51
|
'Authorization': `Bearer ${process.env.API_TOKEN || 'default-token'}`,
|
|
40
52
|
'X-Environment': process.env.NODE_ENV || 'development'
|
|
41
|
-
}, {
|
|
42
|
-
// Only bypass SSL validation in development
|
|
43
|
-
...(isDevelopment && { rejectUnauthorized: false })
|
|
44
|
-
});
|
|
45
|
-
|
|
53
|
+
}, isDevelopment ? { ca } : {});
|
|
46
54
|
console.log(` ✓ Created client for ${isDevelopment ? 'development' : 'production'} environment`);
|
|
47
|
-
console.log(` ✓ SSL validation: ${isDevelopment ? '
|
|
55
|
+
console.log(` ✓ SSL validation: ${isDevelopment ? 'custom CA (dev only)' : 'enabled (secure)'}\n`);
|
|
48
56
|
|
|
49
57
|
// Example usage (commented out since we don't have a real server)
|
|
50
58
|
/*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rpc-express-toolkit",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "Enterprise-ready JSON-RPC 2.0 toolkit for Express.js with simplified APIs, structured logging, middleware system, schema validation, and comprehensive BigInt/Date support.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
@@ -52,19 +52,27 @@ class RpcClient {
|
|
|
52
52
|
|
|
53
53
|
// Store fetch options for Node.js environments
|
|
54
54
|
this.#fetchOptions = {};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
// Support for custom https.Agent (e.g. for self-signed CA)
|
|
56
|
+
if (typeof process !== 'undefined' && process.env && typeof require !== 'undefined') {
|
|
57
|
+
try {
|
|
58
|
+
const https = require('https');
|
|
59
|
+
// If options.agent is provided, use it directly
|
|
60
|
+
if (options.agent) {
|
|
61
|
+
this.#fetchOptions.agent = options.agent;
|
|
62
|
+
} else if (options.ca) {
|
|
63
|
+
// If options.ca is provided, create an agent with the custom CA
|
|
64
|
+
this.#fetchOptions.agent = new https.Agent({
|
|
65
|
+
ca: options.ca,
|
|
66
|
+
rejectUnauthorized: options.rejectUnauthorized !== false // true by default
|
|
67
|
+
});
|
|
68
|
+
} else if (options.rejectUnauthorized === false) {
|
|
69
|
+
// Legacy: allow disabling SSL validation for dev
|
|
62
70
|
this.#fetchOptions.agent = new https.Agent({
|
|
63
71
|
rejectUnauthorized: false
|
|
64
72
|
});
|
|
65
|
-
} catch (e) {
|
|
66
|
-
// Ignore if https module is not available
|
|
67
73
|
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
// Ignore if https module is not available
|
|
68
76
|
}
|
|
69
77
|
}
|
|
70
78
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
let fetchFn;if("undefined"==typeof BigInt||BigInt.prototype.toJSON||(BigInt.prototype.toJSON=function(){return this.toString()}),"undefined"!=typeof fetch)fetchFn=fetch;else try{fetchFn=require("node-fetch")}catch(t){if("undefined"==typeof globalThis||!globalThis.fetch)throw new Error("fetch is not available. Please install node-fetch or use Node.js 18+");fetchFn=globalThis.fetch}class RpcClient{#t;#e;#r;#i;constructor(t,e={},r={}){if(this.#t=t,this.#e={"Content-Type":"application/json",...e},this.#r=1e3*Date.now()+Math.floor(1e3*Math.random()),this.#i={},"undefined"!=typeof process&&process.env
|
|
1
|
+
let fetchFn;if("undefined"==typeof BigInt||BigInt.prototype.toJSON||(BigInt.prototype.toJSON=function(){return this.toString()}),"undefined"!=typeof fetch)fetchFn=fetch;else try{fetchFn=require("node-fetch")}catch(t){if("undefined"==typeof globalThis||!globalThis.fetch)throw new Error("fetch is not available. Please install node-fetch or use Node.js 18+");fetchFn=globalThis.fetch}class RpcClient{#t;#e;#r;#i;constructor(t,e={},r={}){if(this.#t=t,this.#e={"Content-Type":"application/json",...e},this.#r=1e3*Date.now()+Math.floor(1e3*Math.random()),this.#i={},"undefined"!=typeof process&&process.env&&"undefined"!=typeof require)try{const t=require("https");r.agent?this.#i.agent=r.agent:r.ca?this.#i.agent=new t.Agent({ca:r.ca,rejectUnauthorized:!1!==r.rejectUnauthorized}):!1===r.rejectUnauthorized&&(this.#i.agent=new t.Agent({rejectUnauthorized:!1}))}catch(t){}}#n(){return++this.#r}async call(t,e={},r=void 0,i={}){const n={jsonrpc:"2.0",method:t,params:e,id:void 0===r?this.#n():r};try{const t=await fetchFn(this.#t,{method:"POST",headers:{...this.#e,...i},body:JSON.stringify(n),...this.#i});if(!t.ok)throw new Error(`HTTP Error: ${t.status} ${t.statusText}`);const e=await t.json();if(e.error)throw e.error;return this.deserializeBigIntsAndDates(e.result)}catch(t){throw console.error("RPC call failed:",t),t}}async notify(t,e={},r={}){await this.call(t,e,null,r)}async batch(t,e={}){const r=t.map(t=>({jsonrpc:"2.0",method:t.method,params:t.params||{},id:void 0!==t.id?t.id:this.#n()}));try{const t=await fetchFn(this.#t,{method:"POST",headers:{...this.#e,...e},body:JSON.stringify(r),...this.#i});if(!t.ok)throw new Error(`HTTP Error: ${t.status} ${t.statusText}`);const i=await t.json();if(Array.isArray(i))return i.map(t=>{if(t.error)throw t.error;return this.deserializeBigIntsAndDates(t.result)});if(i.error)throw i.error;return[this.deserializeBigIntsAndDates(i.result)]}catch(t){throw console.error("Batch RPC call failed:",t),t}}serializeBigIntsAndDates(t){if("bigint"==typeof t)return t.toString();if(Array.isArray(t))return t.map(t=>this.serializeBigIntsAndDates(t));if(t instanceof Date)return t.toISOString();if(t&&"object"==typeof t){const e={};for(const[r,i]of Object.entries(t))e[r]=this.serializeBigIntsAndDates(i);return e}return t}deserializeBigIntsAndDates(t){const e=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})?$/;if("string"==typeof t){if(/^-?\d+n?$/.test(t))return BigInt(t.replace(/n$/,""));if(e.test(t)){const e=new Date(t);if(!isNaN(e.getTime()))return e}}return Array.isArray(t)?t.map(t=>this.deserializeBigIntsAndDates(t)):t&&"object"==typeof t?Object.fromEntries(Object.entries(t).map(([t,e])=>[t,this.deserializeBigIntsAndDates(e)])):t}}module.exports=RpcClient,module.exports.RpcClient=RpcClient;
|
package/src/index.d.ts
CHANGED
|
@@ -92,8 +92,18 @@ declare class RpcClient {
|
|
|
92
92
|
* @param defaultHeaders - Default headers to include in requests
|
|
93
93
|
* @param options - Configuration options
|
|
94
94
|
* @param options.rejectUnauthorized - Whether to reject unauthorized SSL certificates (default: true). Set to false for development with self-signed certificates.
|
|
95
|
+
* @param options.ca - Buffer or string of a custom CA certificate to trust (for self-signed CA)
|
|
96
|
+
* @param options.agent - Custom https.Agent instance (advanced usage)
|
|
95
97
|
*/
|
|
96
|
-
constructor(
|
|
98
|
+
constructor(
|
|
99
|
+
endpoint: string,
|
|
100
|
+
defaultHeaders?: Record<string, string>,
|
|
101
|
+
options?: {
|
|
102
|
+
rejectUnauthorized?: boolean;
|
|
103
|
+
ca?: string | Buffer;
|
|
104
|
+
agent?: any;
|
|
105
|
+
}
|
|
106
|
+
);
|
|
97
107
|
|
|
98
108
|
/**
|
|
99
109
|
* Make a JSON-RPC call to the server.
|