rpc-express-toolkit 4.0.1 → 4.1.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
@@ -59,6 +59,27 @@ Safe type disambiguation is disabled by default for maximum JSON-RPC 2.0 compati
59
59
  - `client.batch([...])`: batch.
60
60
  - `client.notify(method, params?)`: notification.
61
61
 
62
+ ### Safe Import (opt-in)
63
+
64
+ When you control both client and server and want safer type round-trips, import the safe preset. It enables safe serialization by default (and strict mode on the server):
65
+
66
+ ```js
67
+ // Server (safe preset)
68
+ const express = require('express');
69
+ const { createSafeEndpoint } = require('rpc-express-toolkit/safe');
70
+
71
+ const app = express();
72
+ app.use(express.json());
73
+
74
+ const rpc = createSafeEndpoint(app, {}, { endpoint: '/api' /* strictMode: true by default */ });
75
+
76
+ // Client (safe preset)
77
+ const { createSafeClient } = require('rpc-express-toolkit/safe');
78
+ const client = createSafeClient('http://localhost:3000/api');
79
+ ```
80
+
81
+ This keeps JSON-RPC 2.0 compliance as default for the main entrypoint, while offering a convenient safe-mode import for projects that prefer explicit type disambiguation.
82
+
62
83
  ## Full Details
63
84
 
64
85
  For advanced configuration, middleware, structured logging, safe serialization, error handling, and more, see `README_ADVANCED.md`.
@@ -0,0 +1,45 @@
1
+ const express = require('express');
2
+ /* eslint-disable import/no-unresolved, prettier/prettier */
3
+ const { createSafeEndpoint, createSafeClient } = require('rpc-express-toolkit/safe');
4
+ /* eslint-enable import/no-unresolved, prettier/prettier */
5
+
6
+ async function main() {
7
+ const app = express();
8
+ app.use(express.json());
9
+
10
+ // Server with safe defaults (safeEnabled=true, strictMode=true)
11
+ const rpc = createSafeEndpoint(app, {}, { endpoint: '/api' });
12
+
13
+ rpc.addMethod('sum', (req, ctx, params) => {
14
+ // params are already deserialized according to the client's safe header
15
+ const a =
16
+ typeof params.a === 'string' && params.a.endsWith('n')
17
+ ? BigInt(params.a.slice(0, -1))
18
+ : BigInt(params.a);
19
+ const b =
20
+ typeof params.b === 'string' && params.b.endsWith('n')
21
+ ? BigInt(params.b.slice(0, -1))
22
+ : BigInt(params.b);
23
+ return a + b; // will be serialized as "<value>n" safely
24
+ });
25
+
26
+ const server = app.listen(0, async () => {
27
+ const { port } = server.address();
28
+ const url = `http://localhost:${port}/api`;
29
+ console.log('Safe server listening on', url);
30
+
31
+ // Safe client (sends header and expects safe response)
32
+ const client = createSafeClient(url);
33
+ const res = await client.call('sum', { a: '10n', b: '32n' });
34
+ console.log('sum result (BigInt):', res.toString());
35
+
36
+ server.close();
37
+ });
38
+ }
39
+
40
+ if (require.main === module) {
41
+ main().catch((err) => {
42
+ console.error(err);
43
+ process.exit(1);
44
+ });
45
+ }
package/package.json CHANGED
@@ -1,114 +1,126 @@
1
- {
2
- "name": "rpc-express-toolkit",
3
- "version": "4.0.1",
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
- "main": "src/index.js",
6
- "types": "src/index.d.ts",
7
- "files": [
8
- "src/",
9
- "examples/",
10
- "README.md",
11
- "LICENSE"
12
- ],
13
- "scripts": {
14
- "test": "jest",
15
- "test:coverage": "jest --coverage",
16
- "test:watch": "jest --watch",
17
- "lint": "eslint src/ examples/",
18
- "lint:fix": "eslint src/ examples/ --fix",
19
- "clean": "node -e \"require('fs').existsSync('dist') && require('fs').rmSync('dist', {recursive: true})\"",
20
- "build": "npm run build:minify",
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 --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
- "prepublishOnly": "npm run build",
25
- "precommit": "npm run lint && npm test"
26
- },
27
- "repository": {
28
- "type": "git",
29
- "url": "git+https://github.com/n-car/rpc-express-toolkit.git"
30
- },
31
- "keywords": [
32
- "json-rpc",
33
- "jsonrpc",
34
- "json-rpc-2.0",
35
- "express",
36
- "toolkit",
37
- "rpc",
38
- "server",
39
- "client",
40
- "middleware",
41
- "validation",
42
- "schema",
43
- "ajv",
44
- "bigint",
45
- "date",
46
- "enterprise",
47
- "nodejs",
48
- "node",
49
- "browser",
50
- "ssl",
51
- "self-signed",
52
- "secure",
53
- "fetch",
54
- "batch",
55
- "typescript",
56
- "logging",
57
- "cors",
58
- "rate-limit",
59
- "authentication"
60
- ],
61
- "author": "Nicola Carpanese <nicola.carpanese@gmail.com>",
62
- "license": "MIT",
63
- "bugs": {
64
- "url": "https://github.com/n-car/rpc-express-toolkit/issues"
65
- },
66
- "homepage": "https://github.com/n-car/rpc-express-toolkit#readme",
67
- "engines": {
68
- "node": ">=18.0.0"
69
- },
70
- "devDependencies": {
71
- "eslint": "^8.57.1",
72
- "eslint-config-airbnb-base": "^15.0.0",
73
- "eslint-config-prettier": "^9.1.2",
74
- "eslint-plugin-import": "^2.31.0",
75
- "eslint-plugin-prettier": "^5.5.3",
76
- "husky": "^8.0.0",
77
- "jest": "^29.7.0",
78
- "lint-staged": "^13.0.0",
79
- "prettier": "^3.6.2",
80
- "supertest": "^6.3.3",
81
- "terser": "^5.43.1"
82
- },
83
- "dependencies": {
84
- "ajv": "^8.12.0",
85
- "ajv-formats": "^2.1.1",
86
- "express": "^4.21.2",
87
- "nested-error-stacks": "^2.1.1"
88
- },
89
- "optionalDependencies": {
90
- "node-fetch": "^2.7.0"
91
- },
92
- "contributors": [
93
- {
94
- "name": "Nicola Carpanese",
95
- "email": "nicola.carpanese@gmail.com",
96
- "url": "https://github.com/n-car"
97
- }
98
- ],
99
- "husky": {
100
- "hooks": {
101
- "pre-commit": "lint-staged"
102
- }
103
- },
104
- "lint-staged": {
105
- "src/**/*.js": [
106
- "eslint --fix",
107
- "prettier --write"
108
- ],
109
- "examples/**/*.js": [
110
- "eslint --fix",
111
- "prettier --write"
112
- ]
113
- }
114
- }
1
+ {
2
+ "name": "rpc-express-toolkit",
3
+ "version": "4.1.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. JSON middleware validation and explicit configuration.",
5
+ "main": "src/index.js",
6
+ "types": "src/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./src/index.d.ts",
10
+ "require": "./src/index.js",
11
+ "import": "./src/index.js"
12
+ },
13
+ "./safe": {
14
+ "types": "./src/safe.d.ts",
15
+ "require": "./src/safe.js",
16
+ "import": "./src/safe.js"
17
+ }
18
+ },
19
+ "files": [
20
+ "src/",
21
+ "examples/",
22
+ "README.md",
23
+ "LICENSE"
24
+ ],
25
+ "scripts": {
26
+ "test": "jest",
27
+ "test:coverage": "jest --coverage",
28
+ "test:watch": "jest --watch",
29
+ "lint": "eslint src/ examples/",
30
+ "lint:fix": "eslint src/ examples/ --fix",
31
+ "clean": "node -e \"require(\u0027fs\u0027).existsSync(\u0027dist\u0027) \u0026\u0026 require(\u0027fs\u0027).rmSync(\u0027dist\u0027, {recursive: true})\"",
32
+ "build": "npm run build:minify",
33
+ "build:minify": "npm run build:js \u0026\u0026 npm run build:mjs",
34
+ "build:js": "terser src/clients/rpc-client.js -o src/clients/rpc-client.min.js --compress --mangle --comments false --ecma 2020",
35
+ "build:mjs": "terser src/clients/rpc-client.mjs -o src/clients/rpc-client.min.mjs --compress --mangle --comments false --module --ecma 2020",
36
+ "prepublishOnly": "npm run build",
37
+ "precommit": "npm run lint \u0026\u0026 npm test"
38
+ },
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "git+https://github.com/n-car/rpc-express-toolkit.git"
42
+ },
43
+ "keywords": [
44
+ "json-rpc",
45
+ "jsonrpc",
46
+ "json-rpc-2.0",
47
+ "express",
48
+ "toolkit",
49
+ "rpc",
50
+ "server",
51
+ "client",
52
+ "middleware",
53
+ "validation",
54
+ "schema",
55
+ "ajv",
56
+ "bigint",
57
+ "date",
58
+ "enterprise",
59
+ "nodejs",
60
+ "node",
61
+ "browser",
62
+ "ssl",
63
+ "self-signed",
64
+ "secure",
65
+ "fetch",
66
+ "batch",
67
+ "typescript",
68
+ "logging",
69
+ "cors",
70
+ "rate-limit",
71
+ "authentication"
72
+ ],
73
+ "author": "Nicola Carpanese \u003cnicola.carpanese@gmail.com\u003e",
74
+ "license": "MIT",
75
+ "bugs": {
76
+ "url": "https://github.com/n-car/rpc-express-toolkit/issues"
77
+ },
78
+ "homepage": "https://github.com/n-car/rpc-express-toolkit#readme",
79
+ "engines": {
80
+ "node": "\u003e=18.0.0"
81
+ },
82
+ "devDependencies": {
83
+ "eslint": "^8.57.1",
84
+ "eslint-config-airbnb-base": "^15.0.0",
85
+ "eslint-config-prettier": "^9.1.2",
86
+ "eslint-plugin-import": "^2.31.0",
87
+ "eslint-plugin-prettier": "^5.5.3",
88
+ "husky": "^8.0.0",
89
+ "jest": "^29.7.0",
90
+ "lint-staged": "^13.0.0",
91
+ "prettier": "^3.6.2",
92
+ "supertest": "^6.3.3",
93
+ "terser": "^5.43.1"
94
+ },
95
+ "dependencies": {
96
+ "ajv": "^8.12.0",
97
+ "ajv-formats": "^2.1.1",
98
+ "express": "^4.21.2",
99
+ "nested-error-stacks": "^2.1.1"
100
+ },
101
+ "optionalDependencies": {
102
+ "node-fetch": "^2.7.0"
103
+ },
104
+ "contributors": [
105
+ {
106
+ "name": "Nicola Carpanese",
107
+ "email": "nicola.carpanese@gmail.com",
108
+ "url": "https://github.com/n-car"
109
+ }
110
+ ],
111
+ "husky": {
112
+ "hooks": {
113
+ "pre-commit": "lint-staged"
114
+ }
115
+ },
116
+ "lint-staged": {
117
+ "src/**/*.js": [
118
+ "eslint --fix",
119
+ "prettier --write"
120
+ ],
121
+ "examples/**/*.js": [
122
+ "eslint --fix",
123
+ "prettier --write"
124
+ ]
125
+ }
126
+ }
package/src/safe.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ import type { Router } from 'express';
2
+ import type { RpcEndpoint, RpcClient, RpcEndpointOptions, RpcClientOptions } from './index';
3
+
4
+ /**
5
+ * Factory: create a RpcEndpoint with safe defaults (safeEnabled=true, strictMode=true).
6
+ */
7
+ export function createSafeEndpoint<C = any>(
8
+ router: Router,
9
+ context: C,
10
+ endpoint?: string,
11
+ options?: RpcEndpointOptions
12
+ ): RpcEndpoint<C>;
13
+
14
+ export function createSafeEndpoint<C = any>(
15
+ router: Router,
16
+ context: C,
17
+ options?: RpcEndpointOptions
18
+ ): RpcEndpoint<C>;
19
+
20
+ /**
21
+ * Factory: create a RpcClient with safe defaults (safeEnabled=true).
22
+ */
23
+ export function createSafeClient(
24
+ endpoint: string,
25
+ defaultHeaders?: Record<string, string>,
26
+ options?: RpcClientOptions
27
+ ): RpcClient;
28
+
29
+ export * from './index';
30
+
package/src/safe.js ADDED
@@ -0,0 +1,54 @@
1
+ const Main = require('./index');
2
+
3
+ // Default safe options applied unless explicitly overridden
4
+ const defaultSafeOptions = {
5
+ safeEnabled: true,
6
+ strictMode: true,
7
+ };
8
+
9
+ /**
10
+ * Create a RpcEndpoint with safe defaults (safeEnabled=true, strictMode=true).
11
+ * Preserves both constructor signatures supported by RpcEndpoint.
12
+ *
13
+ * @param {import('express').Router} router
14
+ * @param {any} context
15
+ * @param {string|object} [endpointOrOptions='/api']
16
+ * @param {object} [options]
17
+ */
18
+ function createSafeEndpoint(
19
+ router,
20
+ context,
21
+ endpointOrOptions = '/api',
22
+ options = {}
23
+ ) {
24
+ if (typeof endpointOrOptions === 'string') {
25
+ const finalOptions = { ...defaultSafeOptions, ...options };
26
+ return new Main.RpcEndpoint(
27
+ router,
28
+ context,
29
+ endpointOrOptions,
30
+ finalOptions
31
+ );
32
+ }
33
+ // options object form
34
+ const final = { ...defaultSafeOptions, ...endpointOrOptions };
35
+ return new Main.RpcEndpoint(router, context, final);
36
+ }
37
+
38
+ /**
39
+ * Create a RpcClient with safe defaults (safeEnabled=true).
40
+ * @param {string} endpoint
41
+ * @param {Record<string,string>} [defaultHeaders]
42
+ * @param {object} [options]
43
+ */
44
+ function createSafeClient(endpoint, defaultHeaders = {}, options = {}) {
45
+ const finalOptions = { safeEnabled: true, ...options };
46
+ return new Main.RpcClient(endpoint, defaultHeaders, finalOptions);
47
+ }
48
+
49
+ module.exports = {
50
+ // Re-export everything for convenience
51
+ ...Main,
52
+ createSafeEndpoint,
53
+ createSafeClient,
54
+ };