rpc-express-toolkit 2.0.3 → 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 +38 -1
- package/examples/ssl-development-example.js +83 -0
- package/package.json +3 -1
- package/src/clients/rpc-client.js +32 -1
- package/src/clients/rpc-client.min.js +1 -1
- package/src/clients/rpc-client.min.mjs +1 -1
- package/src/clients/rpc-client.mjs +32 -1
- package/src/index.d.ts +13 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](LICENSE)
|
|
4
4
|
[](https://www.npmjs.com/package/rpc-express-toolkit)
|
|
5
|
-
[](https://github.com/n-car/rpc-express-toolkit/actions/workflows/ci.yml)
|
|
6
6
|
[](https://coveralls.io/github/n-car/rpc-express-toolkit?branch=main)
|
|
7
7
|
|
|
8
8
|
An enterprise-ready JSON-RPC 2.0 toolkit for Express.js applications with simplified APIs, structured logging, middleware system, schema validation, batch processing, and comprehensive BigInt/Date serialization support.
|
|
@@ -514,6 +514,43 @@ logger.error('Database error', {
|
|
|
514
514
|
// [2024-01-01T10:00:00.050Z] INFO: RPC success - {"method":"getUser","id":"req-123","duration":50,"resultSize":245}
|
|
515
515
|
```
|
|
516
516
|
|
|
517
|
+
### Client Configuration
|
|
518
|
+
|
|
519
|
+
The `RpcClient` supports various configuration options for different environments, **inclusa la gestione di certificati self-signed**:
|
|
520
|
+
|
|
521
|
+
```javascript
|
|
522
|
+
const fs = require('fs');
|
|
523
|
+
const { RpcClient } = require('rpc-express-toolkit');
|
|
524
|
+
|
|
525
|
+
// Basic client
|
|
526
|
+
const client = new RpcClient('https://api.example.com/rpc');
|
|
527
|
+
|
|
528
|
+
// Client con header personalizzati
|
|
529
|
+
const clientWithHeaders = new RpcClient('https://api.example.com/rpc', {
|
|
530
|
+
'Authorization': 'Bearer your-token',
|
|
531
|
+
'X-API-Key': 'your-api-key',
|
|
532
|
+
'User-Agent': 'MyApp/1.0'
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// Client per sviluppo con certificato self-signed (accetta qualsiasi certificato, NON usare in produzione)
|
|
536
|
+
const devClient = new RpcClient('https://localhost:3000/api', {
|
|
537
|
+
'Authorization': 'Bearer dev-token'
|
|
538
|
+
}, {
|
|
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 })
|
|
549
|
+
});
|
|
550
|
+
```
|
|
551
|
+
|
|
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.
|
|
553
|
+
|
|
517
554
|
### Built-in Middlewares
|
|
518
555
|
|
|
519
556
|
```javascript
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Example demonstrating how to use RpcClient with self-signed certificates
|
|
3
|
+
* in development environments.
|
|
4
|
+
*
|
|
5
|
+
* WARNING: Only use rejectUnauthorized: false in development!
|
|
6
|
+
* Never use this in production as it disables SSL certificate validation.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { RpcClient } = require('../src/index.js');
|
|
10
|
+
|
|
11
|
+
async function demonstrateSSLOptions() {
|
|
12
|
+
console.log('=== RPC Client SSL Configuration Example ===\n');
|
|
13
|
+
|
|
14
|
+
// Example 1: Standard production client (default - strict SSL)
|
|
15
|
+
console.log('1. Production Client (strict SSL validation):');
|
|
16
|
+
const productionClient = new RpcClient('https://api.example.com/rpc', {
|
|
17
|
+
'Authorization': 'Bearer prod-token'
|
|
18
|
+
});
|
|
19
|
+
console.log(' ✓ Created client with strict SSL validation (default)\n');
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
// Example 2: Development client for self-signed certificates (bypasses ALL SSL validation)
|
|
23
|
+
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');
|
|
32
|
+
|
|
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:');
|
|
48
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
49
|
+
const baseUrl = isDevelopment ? 'https://localhost:3000/api' : 'https://api.production.com/rpc';
|
|
50
|
+
const environmentClient = new RpcClient(baseUrl, {
|
|
51
|
+
'Authorization': `Bearer ${process.env.API_TOKEN || 'default-token'}`,
|
|
52
|
+
'X-Environment': process.env.NODE_ENV || 'development'
|
|
53
|
+
}, isDevelopment ? { ca } : {});
|
|
54
|
+
console.log(` ✓ Created client for ${isDevelopment ? 'development' : 'production'} environment`);
|
|
55
|
+
console.log(` ✓ SSL validation: ${isDevelopment ? 'custom CA (dev only)' : 'enabled (secure)'}\n`);
|
|
56
|
+
|
|
57
|
+
// Example usage (commented out since we don't have a real server)
|
|
58
|
+
/*
|
|
59
|
+
try {
|
|
60
|
+
// This would work with a real server
|
|
61
|
+
const result = await developmentClient.call('ping', {});
|
|
62
|
+
console.log('Server response:', result);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error('Error calling server:', error.message);
|
|
65
|
+
}
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
console.log('4. Best Practices:');
|
|
69
|
+
console.log(' ✓ Always use strict SSL validation in production');
|
|
70
|
+
console.log(' ✓ Only disable SSL validation for development with self-signed certificates');
|
|
71
|
+
console.log(' ✓ Use environment variables to control SSL behavior');
|
|
72
|
+
console.log(' ✓ Never commit rejectUnauthorized: false to production code');
|
|
73
|
+
console.log(' ✓ Consider using proper development certificates instead of disabling validation\n');
|
|
74
|
+
|
|
75
|
+
console.log('=== Example Complete ===');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Run the example if this file is executed directly
|
|
79
|
+
if (require.main === module) {
|
|
80
|
+
demonstrateSSLOptions().catch(console.error);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = { demonstrateSSLOptions };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rpc-express-toolkit",
|
|
3
|
-
"version": "2.0
|
|
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",
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
],
|
|
13
13
|
"scripts": {
|
|
14
14
|
"test": "jest",
|
|
15
|
+
"test:coverage": "jest --coverage",
|
|
16
|
+
"test:watch": "jest --watch",
|
|
15
17
|
"lint": "eslint src/ examples/",
|
|
16
18
|
"lint:fix": "eslint src/ examples/ --fix",
|
|
17
19
|
"clean": "node -e \"require('fs').existsSync('dist') && require('fs').rmSync('dist', {recursive: true})\"",
|
|
@@ -33,12 +33,15 @@ class RpcClient {
|
|
|
33
33
|
#endpoint;
|
|
34
34
|
#defaultHeaders;
|
|
35
35
|
#requestId;
|
|
36
|
+
#fetchOptions;
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
39
|
* @param {string} endpoint The JSON-RPC endpoint URL.
|
|
39
40
|
* @param {Object} [defaultHeaders={}] Optional default headers to include in requests.
|
|
41
|
+
* @param {Object} [options={}] Optional configuration options.
|
|
42
|
+
* @param {boolean} [options.rejectUnauthorized=true] Whether to reject unauthorized SSL certificates. Set to false for development with self-signed certificates.
|
|
40
43
|
*/
|
|
41
|
-
constructor(endpoint, defaultHeaders = {}) {
|
|
44
|
+
constructor(endpoint, defaultHeaders = {}, options = {}) {
|
|
42
45
|
this.#endpoint = endpoint;
|
|
43
46
|
this.#defaultHeaders = {
|
|
44
47
|
"Content-Type": "application/json", // Default header
|
|
@@ -46,6 +49,32 @@ class RpcClient {
|
|
|
46
49
|
};
|
|
47
50
|
// Initialize request ID counter with timestamp + random component for uniqueness
|
|
48
51
|
this.#requestId = Date.now() * 1000 + Math.floor(Math.random() * 1000);
|
|
52
|
+
|
|
53
|
+
// Store fetch options for Node.js environments
|
|
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
|
+
}
|
|
49
78
|
}
|
|
50
79
|
|
|
51
80
|
/**
|
|
@@ -85,6 +114,7 @@ class RpcClient {
|
|
|
85
114
|
// Since we have BigInt.prototype.toJSON, we don't need manual serialization
|
|
86
115
|
// JSON.stringify will handle BigInt and Date automatically
|
|
87
116
|
body: JSON.stringify(requestBody),
|
|
117
|
+
...this.#fetchOptions, // Include any additional fetch options (e.g., SSL settings)
|
|
88
118
|
});
|
|
89
119
|
|
|
90
120
|
if (!response.ok) {
|
|
@@ -136,6 +166,7 @@ class RpcClient {
|
|
|
136
166
|
...overrideHeaders,
|
|
137
167
|
},
|
|
138
168
|
body: JSON.stringify(batchRequests),
|
|
169
|
+
...this.#fetchOptions, // Include any additional fetch options (e.g., SSL settings)
|
|
139
170
|
});
|
|
140
171
|
|
|
141
172
|
if (!response.ok) {
|
|
@@ -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;constructor(t,e={}){this.#t=t,this.#e={"Content-Type":"application/json",...e},this.#r=1e3*Date.now()+Math.floor(1e3*Math.random())}
|
|
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 +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;constructor(t,e={}){this.#t=t,this.#e={"Content-Type":"application/json",...e},this.#r=1e3*Date.now()+Math.floor(1e3*Math.random())}async call(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;#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}}
|
|
@@ -34,12 +34,15 @@ export class RpcClient {
|
|
|
34
34
|
#endpoint;
|
|
35
35
|
#defaultHeaders;
|
|
36
36
|
#requestId;
|
|
37
|
+
#fetchOptions;
|
|
37
38
|
|
|
38
39
|
/**
|
|
39
40
|
* @param {string} endpoint The JSON-RPC endpoint URL.
|
|
40
41
|
* @param {Object} [defaultHeaders={}] Optional default headers to include in requests.
|
|
42
|
+
* @param {Object} [options={}] Optional configuration options.
|
|
43
|
+
* @param {boolean} [options.rejectUnauthorized=true] Whether to reject unauthorized SSL certificates. Set to false for development with self-signed certificates.
|
|
41
44
|
*/
|
|
42
|
-
constructor(endpoint, defaultHeaders = {}) {
|
|
45
|
+
constructor(endpoint, defaultHeaders = {}, options = {}) {
|
|
43
46
|
this.#endpoint = endpoint;
|
|
44
47
|
this.#defaultHeaders = {
|
|
45
48
|
"Content-Type": "application/json", // Default header
|
|
@@ -47,6 +50,31 @@ export class RpcClient {
|
|
|
47
50
|
};
|
|
48
51
|
// Initialize request ID counter with timestamp + random component for uniqueness
|
|
49
52
|
this.#requestId = Date.now() * 1000 + Math.floor(Math.random() * 1000);
|
|
53
|
+
|
|
54
|
+
// Store fetch options for Node.js environments
|
|
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
|
+
}
|
|
50
78
|
}
|
|
51
79
|
|
|
52
80
|
/**
|
|
@@ -80,6 +108,7 @@ export class RpcClient {
|
|
|
80
108
|
// Since we have BigInt.prototype.toJSON, we don't need manual serialization
|
|
81
109
|
// JSON.stringify will handle BigInt and Date automatically
|
|
82
110
|
body: JSON.stringify(requestBody),
|
|
111
|
+
...this.#fetchOptions, // Include any additional fetch options (e.g., SSL settings)
|
|
83
112
|
});
|
|
84
113
|
|
|
85
114
|
if (!response.ok) {
|
|
@@ -121,6 +150,7 @@ export class RpcClient {
|
|
|
121
150
|
...overrideHeaders,
|
|
122
151
|
},
|
|
123
152
|
body: JSON.stringify(requestBody),
|
|
153
|
+
...this.#fetchOptions, // Include any additional fetch options (e.g., SSL settings)
|
|
124
154
|
});
|
|
125
155
|
|
|
126
156
|
if (!response.ok) {
|
|
@@ -162,6 +192,7 @@ export class RpcClient {
|
|
|
162
192
|
...overrideHeaders,
|
|
163
193
|
},
|
|
164
194
|
body: JSON.stringify(requestBodies),
|
|
195
|
+
...this.#fetchOptions, // Include any additional fetch options (e.g., SSL settings)
|
|
165
196
|
});
|
|
166
197
|
|
|
167
198
|
if (!response.ok) {
|
package/src/index.d.ts
CHANGED
|
@@ -90,8 +90,20 @@ declare class RpcClient {
|
|
|
90
90
|
*
|
|
91
91
|
* @param endpoint - JSON-RPC endpoint URL
|
|
92
92
|
* @param defaultHeaders - Default headers to include in requests
|
|
93
|
+
* @param options - Configuration options
|
|
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)
|
|
93
97
|
*/
|
|
94
|
-
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
|
+
);
|
|
95
107
|
|
|
96
108
|
/**
|
|
97
109
|
* Make a JSON-RPC call to the server.
|