rpc-express-toolkit 2.1.0 → 2.3.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 +31 -5
- package/examples/ssl-development-example.js +18 -19
- package/package.json +7 -3
- package/src/clients/rpc-client.js +4 -15
- package/src/clients/rpc-client.min.js +1 -1
- package/src/clients/rpc-client.min.mjs +1 -1
- package/src/clients/rpc-client.mjs +4 -22
- package/src/index.d.ts +9 -1
package/README.md
CHANGED
|
@@ -91,6 +91,7 @@ app.listen(3000, () => {
|
|
|
91
91
|
});
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
+
|
|
94
95
|
### Client Usage
|
|
95
96
|
|
|
96
97
|
```javascript
|
|
@@ -108,6 +109,21 @@ const client = new RpcClient('/api');
|
|
|
108
109
|
const user = await client.call('getUser', { userId: 123 });
|
|
109
110
|
```
|
|
110
111
|
|
|
112
|
+
#### SSL e certificati self-signed in sviluppo (Node.js)
|
|
113
|
+
|
|
114
|
+
Per bypassare la validazione dei certificati SSL (ad esempio con certificati self-signed in sviluppo), imposta **prima** di avviare il client:
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Attenzione:**
|
|
121
|
+
- Questa impostazione disabilita la validazione SSL per tutte le richieste nel processo Node.js.
|
|
122
|
+
- Usala solo in ambienti di sviluppo!
|
|
123
|
+
- Non committare mai questa impostazione in produzione.
|
|
124
|
+
|
|
125
|
+
Le opzioni avanzate `agent` e `ca` sono state rimosse per semplicità e compatibilità con Node.js moderno.
|
|
126
|
+
|
|
111
127
|
## Advanced Usage
|
|
112
128
|
|
|
113
129
|
### Configuration Options
|
|
@@ -516,30 +532,40 @@ logger.error('Database error', {
|
|
|
516
532
|
|
|
517
533
|
### Client Configuration
|
|
518
534
|
|
|
519
|
-
The `RpcClient` supports various configuration options for different environments
|
|
535
|
+
The `RpcClient` supports various configuration options for different environments, **inclusa la gestione di certificati self-signed**:
|
|
520
536
|
|
|
521
537
|
```javascript
|
|
538
|
+
const fs = require('fs');
|
|
522
539
|
const { RpcClient } = require('rpc-express-toolkit');
|
|
523
540
|
|
|
524
541
|
// Basic client
|
|
525
542
|
const client = new RpcClient('https://api.example.com/rpc');
|
|
526
543
|
|
|
527
|
-
// Client
|
|
544
|
+
// Client con header personalizzati
|
|
528
545
|
const clientWithHeaders = new RpcClient('https://api.example.com/rpc', {
|
|
529
546
|
'Authorization': 'Bearer your-token',
|
|
530
547
|
'X-API-Key': 'your-api-key',
|
|
531
548
|
'User-Agent': 'MyApp/1.0'
|
|
532
549
|
});
|
|
533
550
|
|
|
534
|
-
// Client
|
|
551
|
+
// Client per sviluppo con certificato self-signed (accetta qualsiasi certificato, NON usare in produzione)
|
|
535
552
|
const devClient = new RpcClient('https://localhost:3000/api', {
|
|
536
553
|
'Authorization': 'Bearer dev-token'
|
|
537
554
|
}, {
|
|
538
|
-
rejectUnauthorized: false //
|
|
555
|
+
rejectUnauthorized: false // Solo per sviluppo!
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// Client per sviluppo con CA self-signed (modo sicuro: accetta solo la tua CA)
|
|
559
|
+
const ca = fs.readFileSync('path/to/your/selfsigned-ca.pem');
|
|
560
|
+
const devClientWithCA = new RpcClient('https://localhost:3000/api', {
|
|
561
|
+
'Authorization': 'Bearer dev-token'
|
|
562
|
+
}, {
|
|
563
|
+
ca // Passa il certificato della tua CA self-signed
|
|
564
|
+
// oppure: agent: new require('https').Agent({ ca, rejectUnauthorized: true })
|
|
539
565
|
});
|
|
540
566
|
```
|
|
541
567
|
|
|
542
|
-
**⚠️ Security Warning**:
|
|
568
|
+
**⚠️ 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
569
|
|
|
544
570
|
### Built-in Middlewares
|
|
545
571
|
|
|
@@ -18,33 +18,32 @@ async function demonstrateSSLOptions() {
|
|
|
18
18
|
});
|
|
19
19
|
console.log(' ✓ Created client with strict SSL validation (default)\n');
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
// Example 2: Development client per self-signed certificates (bypassa TUTTA la validazione SSL)
|
|
22
24
|
console.log('2. Development Client (bypasses SSL validation):');
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}, {
|
|
27
|
-
rejectUnauthorized: false // Only for development!
|
|
28
|
-
});
|
|
29
|
-
console.log(' ✓ Created client that bypasses SSL certificate validation');
|
|
30
|
-
console.log(' ⚠️ WARNING: Only use this for development with self-signed certificates!\n');
|
|
25
|
+
console.log(' ⚠️ Per bypassare la validazione SSL in Node.js, imposta PRIMA di avviare il client:');
|
|
26
|
+
console.log(' process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";');
|
|
27
|
+
console.log(' ✓ Tutte le richieste accetteranno certificati self-signed (solo per sviluppo!)\n');
|
|
31
28
|
|
|
32
|
-
// Example 3:
|
|
33
|
-
console.log('3.
|
|
34
|
-
|
|
29
|
+
// Example 3: Best practice
|
|
30
|
+
console.log('3. Best Practices:');
|
|
31
|
+
console.log(' ✓ Usa sempre la validazione SSL in produzione');
|
|
32
|
+
console.log(' ✓ Disabilita la validazione solo per sviluppo con self-signed');
|
|
33
|
+
console.log(' ✓ Usa variabili d’ambiente per controllare il comportamento SSL');
|
|
34
|
+
console.log(' ✓ Non committare mai process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0" in produzione');
|
|
35
|
+
console.log(' ✓ Considera l’uso di certificati di sviluppo validi invece di disabilitare la validazione\n');
|
|
36
|
+
|
|
37
|
+
// Example 4: Demonstrate how to choose configuration based on environment
|
|
38
|
+
console.log('4. Environment-based Configuration:');
|
|
35
39
|
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
36
40
|
const baseUrl = isDevelopment ? 'https://localhost:3000/api' : 'https://api.production.com/rpc';
|
|
37
|
-
|
|
38
41
|
const environmentClient = new RpcClient(baseUrl, {
|
|
39
42
|
'Authorization': `Bearer ${process.env.API_TOKEN || 'default-token'}`,
|
|
40
43
|
'X-Environment': process.env.NODE_ENV || 'development'
|
|
41
|
-
}, {
|
|
42
|
-
// Only bypass SSL validation in development
|
|
43
|
-
...(isDevelopment && { rejectUnauthorized: false })
|
|
44
|
-
});
|
|
45
|
-
|
|
44
|
+
}, isDevelopment ? { ca } : {});
|
|
46
45
|
console.log(` ✓ Created client for ${isDevelopment ? 'development' : 'production'} environment`);
|
|
47
|
-
console.log(` ✓ SSL validation: ${isDevelopment ? '
|
|
46
|
+
console.log(` ✓ SSL validation: ${isDevelopment ? 'custom CA (dev only)' : 'enabled (secure)'}\n`);
|
|
48
47
|
|
|
49
48
|
// Example usage (commented out since we don't have a real server)
|
|
50
49
|
/*
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rpc-express-toolkit",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Enterprise-ready JSON-RPC 2.0 toolkit for Express.js with simplified APIs, structured logging, middleware system, schema validation,
|
|
3
|
+
"version": "2.3.0",
|
|
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. Semplificato: gestione SSL avanzata rimossa, vedi README.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"types": "src/index.d.ts",
|
|
7
7
|
"files": [
|
|
@@ -39,7 +39,11 @@
|
|
|
39
39
|
"validation",
|
|
40
40
|
"bigint",
|
|
41
41
|
"enterprise",
|
|
42
|
-
"nodejs"
|
|
42
|
+
"nodejs",
|
|
43
|
+
"ssl",
|
|
44
|
+
"self-signed",
|
|
45
|
+
"secure",
|
|
46
|
+
"fetch"
|
|
43
47
|
],
|
|
44
48
|
"author": "Nicola Carpanese <nicola.carpanese@gmail.com>",
|
|
45
49
|
"license": "MIT",
|
|
@@ -52,21 +52,10 @@ class RpcClient {
|
|
|
52
52
|
|
|
53
53
|
// Store fetch options for Node.js environments
|
|
54
54
|
this.#fetchOptions = {};
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (typeof require !== 'undefined') {
|
|
60
|
-
try {
|
|
61
|
-
const https = require('https');
|
|
62
|
-
this.#fetchOptions.agent = new https.Agent({
|
|
63
|
-
rejectUnauthorized: false
|
|
64
|
-
});
|
|
65
|
-
} catch (e) {
|
|
66
|
-
// Ignore if https module is not available
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
55
|
+
// SSL validation: la gestione avanzata (agent/ca) è rimossa per semplicità e compatibilità.
|
|
56
|
+
// Per bypassare i certificati self-signed in sviluppo, imposta:
|
|
57
|
+
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
58
|
+
// Vedi README per dettagli e best practice.
|
|
70
59
|
}
|
|
71
60
|
|
|
72
61
|
/**
|
|
@@ -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={}){
|
|
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={}){this.#t=t,this.#e={"Content-Type":"application/json",...e},this.#r=1e3*Date.now()+Math.floor(1e3*Math.random()),this.#i={}}#s(){return++this.#r}async call(t,e={},r=void 0,i={}){const s={jsonrpc:"2.0",method:t,params:e,id:void 0===r?this.#s():r};try{const t=await fetchFn(this.#t,{method:"POST",headers:{...this.#e,...i},body:JSON.stringify(s),...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.#s()}));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;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
let t;if("undefined"==typeof BigInt||BigInt.prototype.toJSON||(BigInt.prototype.toJSON=function(){return this.toString()}),"undefined"!=typeof fetch)t=fetch;else try{const{default:e}=await import("node-fetch");t=e}catch(e){if("undefined"==typeof globalThis||!globalThis.fetch)throw new Error("fetch is not available. Please install node-fetch or use Node.js 18+");t=globalThis.fetch}export class RpcClient{#t;#e;#r;#
|
|
1
|
+
let t;if("undefined"==typeof BigInt||BigInt.prototype.toJSON||(BigInt.prototype.toJSON=function(){return this.toString()}),"undefined"!=typeof fetch)t=fetch;else try{const{default:e}=await import("node-fetch");t=e}catch(e){if("undefined"==typeof globalThis||!globalThis.fetch)throw new Error("fetch is not available. Please install node-fetch or use Node.js 18+");t=globalThis.fetch}export class RpcClient{#t;#e;#r;#s;constructor(t,e={},r={}){this.#t=t,this.#e={"Content-Type":"application/json",...e},this.#r=1e3*Date.now()+Math.floor(1e3*Math.random()),this.#s={}}async call(e,r={},s=null,i={}){null===s&&(s=++this.#r);const n={jsonrpc:"2.0",method:e,params:r,id:s};try{const e=await t(this.#t,{method:"POST",headers:{...this.#e,...i},body:JSON.stringify(n),...this.#s});if(!e.ok)throw new Error(`HTTP Error: ${e.status} ${e.statusText}`);const r=await e.json();if(r.error)throw r.error;return this.deserializeBigIntsAndDates(r.result)}catch(t){throw console.error("RPC call failed:",t),t}}async notify(e,r={},s={}){const i={jsonrpc:"2.0",method:e,params:r};try{const e=await t(this.#t,{method:"POST",headers:{...this.#e,...s},body:JSON.stringify(i),...this.#s});if(!e.ok)throw new Error(`HTTP Error: ${e.status} ${e.statusText}`)}catch(t){throw console.error("RPC notification failed:",t),t}}async batch(e,r={}){const s=e.map(t=>{const e={jsonrpc:"2.0",method:t.method,params:t.params||{}};return t.notification||(e.id=void 0!==t.id?t.id:++this.#r),e});try{const e=await t(this.#t,{method:"POST",headers:{...this.#e,...r},body:JSON.stringify(s),...this.#s});if(!e.ok)throw new Error(`HTTP Error: ${e.status} ${e.statusText}`);const i=await e.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("RPC batch 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,s]of Object.entries(t))e[r]=this.serializeBigIntsAndDates(s);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}}
|
|
@@ -53,28 +53,10 @@ export class RpcClient {
|
|
|
53
53
|
|
|
54
54
|
// Store fetch options for Node.js environments
|
|
55
55
|
this.#fetchOptions = {};
|
|
56
|
-
|
|
57
|
-
//
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (typeof require !== 'undefined') {
|
|
61
|
-
try {
|
|
62
|
-
const https = require('https');
|
|
63
|
-
this.#fetchOptions.agent = new https.Agent({
|
|
64
|
-
rejectUnauthorized: false
|
|
65
|
-
});
|
|
66
|
-
} catch (e) {
|
|
67
|
-
// For ES modules, we'll try dynamic import
|
|
68
|
-
import('https').then(httpsModule => {
|
|
69
|
-
this.#fetchOptions.agent = new httpsModule.Agent({
|
|
70
|
-
rejectUnauthorized: false
|
|
71
|
-
});
|
|
72
|
-
}).catch(() => {
|
|
73
|
-
// Ignore if https module is not available
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
56
|
+
// SSL validation: la gestione avanzata (agent/ca) è rimossa per semplicità e compatibilità.
|
|
57
|
+
// Per bypassare i certificati self-signed in sviluppo, imposta:
|
|
58
|
+
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
59
|
+
// Vedi README per dettagli e best practice.
|
|
78
60
|
}
|
|
79
61
|
|
|
80
62
|
/**
|
package/src/index.d.ts
CHANGED
|
@@ -92,8 +92,16 @@ 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
|
+
// Opzioni SSL avanzate rimosse: usa process.env.NODE_TLS_REJECT_UNAUTHORIZED per sviluppo
|
|
103
|
+
}
|
|
104
|
+
);
|
|
97
105
|
|
|
98
106
|
/**
|
|
99
107
|
* Make a JSON-RPC call to the server.
|