rpc-express-toolkit 2.2.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 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
@@ -19,29 +19,20 @@ async function demonstrateSSLOptions() {
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
+ // Example 2: Development client per self-signed certificates (bypassa TUTTA la validazione SSL)
23
24
  console.log('2. Development Client (bypasses SSL validation):');
24
- const developmentClient = new RpcClient('https://localhost:3000/api', {
25
- 'Authorization': 'Bearer dev-token',
26
- 'X-Environment': 'development'
27
- }, {
28
- rejectUnauthorized: false // Solo per sviluppo!
29
- });
30
- console.log(' ✓ Created client that bypasses SSL certificate validation');
31
- 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');
32
28
 
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');
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');
45
36
 
46
37
  // Example 4: Demonstrate how to choose configuration based on environment
47
38
  console.log('4. Environment-based Configuration:');
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rpc-express-toolkit",
3
- "version": "2.2.0",
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.",
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,29 +52,10 @@ class RpcClient {
52
52
 
53
53
  // Store fetch options for Node.js environments
54
54
  this.#fetchOptions = {};
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
70
- this.#fetchOptions.agent = new https.Agent({
71
- rejectUnauthorized: false
72
- });
73
- }
74
- } catch (e) {
75
- // Ignore if https module is not available
76
- }
77
- }
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.
78
59
  }
79
60
 
80
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={}){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;
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;#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===r.rejectUnauthorized&&"undefined"!=typeof require)try{const t=require("https");this.#i.agent=new t.Agent({rejectUnauthorized:!1})}catch(t){import("https").then(t=>{this.#i.agent=new t.Agent({rejectUnauthorized:!1})}).catch(()=>{})}}async call(e,r={},i=null,s={}){null===i&&(i=++this.#r);const n={jsonrpc:"2.0",method:e,params:r,id:i};try{const e=await t(this.#t,{method:"POST",headers:{...this.#e,...s},body:JSON.stringify(n),...this.#i});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={},i={}){const s={jsonrpc:"2.0",method:e,params:r};try{const e=await t(this.#t,{method:"POST",headers:{...this.#e,...i},body:JSON.stringify(s),...this.#i});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 i=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(i),...this.#i});if(!e.ok)throw new Error(`HTTP Error: ${e.status} ${e.statusText}`);const s=await e.json();if(Array.isArray(s))return s.map(t=>{if(t.error)throw t.error;return this.deserializeBigIntsAndDates(t.result)});if(s.error)throw s.error;return[this.deserializeBigIntsAndDates(s.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,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}}
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
- // Handle SSL certificate validation option for Node.js
58
- if (typeof process !== 'undefined' && process.env && options.rejectUnauthorized === false) {
59
- // Set up agent for Node.js fetch implementations
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
@@ -99,9 +99,7 @@ declare class RpcClient {
99
99
  endpoint: string,
100
100
  defaultHeaders?: Record<string, string>,
101
101
  options?: {
102
- rejectUnauthorized?: boolean;
103
- ca?: string | Buffer;
104
- agent?: any;
102
+ // Opzioni SSL avanzate rimosse: usa process.env.NODE_TLS_REJECT_UNAUTHORIZED per sviluppo
105
103
  }
106
104
  );
107
105