rpc-express-toolkit 2.3.3 → 3.0.1
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 +221 -9
- package/examples/example.js +17 -18
- package/examples/server-client-example.js +120 -114
- package/examples/ssl-development-example.js +100 -80
- package/package.json +5 -5
- package/src/batch.js +256 -237
- package/src/clients/rpc-client.js +125 -44
- package/src/clients/rpc-client.min.js +1 -1
- package/src/clients/rpc-client.min.mjs +1 -1
- package/src/clients/rpc-client.mjs +159 -96
- package/src/index.d.ts +220 -58
- package/src/index.js +319 -115
- package/src/logger.js +184 -153
- package/src/middleware.js +229 -224
- package/src/validation.js +220 -221
package/src/validation.js
CHANGED
|
@@ -1,221 +1,220 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
*
|
|
43
|
-
* @param {
|
|
44
|
-
* @
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
valid,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
*
|
|
60
|
-
* @
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
error.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
context
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
*
|
|
89
|
-
* @param {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
{ type: 'string', format: '
|
|
116
|
-
{ type: '
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
*
|
|
163
|
-
* @param {
|
|
164
|
-
* @param {
|
|
165
|
-
* @
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
*
|
|
178
|
-
* @
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
*
|
|
190
|
-
* @
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
*
|
|
200
|
-
* @
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
this
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
*
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
};
|
|
1
|
+
const Ajv = require('ajv');
|
|
2
|
+
const addFormats = require('ajv-formats');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* JSON-RPC 2.0 Schema Validation Error
|
|
6
|
+
*/
|
|
7
|
+
class SchemaValidator {
|
|
8
|
+
constructor(options = {}) {
|
|
9
|
+
this.ajv = new Ajv({
|
|
10
|
+
allErrors: true,
|
|
11
|
+
removeAdditional: options.removeAdditional || false,
|
|
12
|
+
useDefaults: options.useDefaults !== false,
|
|
13
|
+
coerceTypes: options.coerceTypes || false,
|
|
14
|
+
...options.ajvOptions,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
addFormats(this.ajv);
|
|
18
|
+
|
|
19
|
+
// Add custom formats
|
|
20
|
+
this.addCustomFormats();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Add custom format validators
|
|
25
|
+
*/
|
|
26
|
+
addCustomFormats() {
|
|
27
|
+
// BigInt format
|
|
28
|
+
this.ajv.addFormat('bigint', {
|
|
29
|
+
type: 'string',
|
|
30
|
+
validate: (data) => /^-?\d+n?$/.test(data),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// ObjectId format (MongoDB style)
|
|
34
|
+
this.ajv.addFormat('objectid', {
|
|
35
|
+
type: 'string',
|
|
36
|
+
validate: (data) => /^[0-9a-fA-F]{24}$/.test(data),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Validate parameters against a schema
|
|
42
|
+
* @param {any} params
|
|
43
|
+
* @param {Object} schema
|
|
44
|
+
* @returns {Object} validation result
|
|
45
|
+
*/
|
|
46
|
+
validate(params, schema) {
|
|
47
|
+
const validator = this.ajv.compile(schema);
|
|
48
|
+
const valid = validator(params);
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
valid,
|
|
52
|
+
errors: valid ? null : validator.errors,
|
|
53
|
+
data: params,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Create a validation middleware
|
|
59
|
+
* @param {Object} schema
|
|
60
|
+
* @returns {Function}
|
|
61
|
+
*/
|
|
62
|
+
middleware(schema) {
|
|
63
|
+
return async (context) => {
|
|
64
|
+
const { params } = context;
|
|
65
|
+
const result = this.validate(params, schema);
|
|
66
|
+
|
|
67
|
+
if (!result.valid) {
|
|
68
|
+
const error = new Error('Validation failed');
|
|
69
|
+
error.code = -32602; // Invalid params
|
|
70
|
+
error.data = {
|
|
71
|
+
validationErrors: result.errors.map((err) => ({
|
|
72
|
+
field: err.instancePath || err.schemaPath,
|
|
73
|
+
message: err.message,
|
|
74
|
+
value: err.data,
|
|
75
|
+
})),
|
|
76
|
+
};
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Update params with validated/coerced data
|
|
81
|
+
context.params = result.data;
|
|
82
|
+
return context;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Add a custom keyword
|
|
88
|
+
* @param {string} name
|
|
89
|
+
* @param {Object} definition
|
|
90
|
+
*/
|
|
91
|
+
addKeyword(name, definition) {
|
|
92
|
+
this.ajv.addKeyword(name, definition);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Common schema definitions
|
|
98
|
+
*/
|
|
99
|
+
const commonSchemas = {
|
|
100
|
+
// Pagination parameters
|
|
101
|
+
pagination: {
|
|
102
|
+
type: 'object',
|
|
103
|
+
properties: {
|
|
104
|
+
page: { type: 'integer', minimum: 1, default: 1 },
|
|
105
|
+
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
|
106
|
+
sort: { type: 'string' },
|
|
107
|
+
order: { type: 'string', enum: ['asc', 'desc'], default: 'asc' },
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
// User identification
|
|
112
|
+
userId: {
|
|
113
|
+
oneOf: [
|
|
114
|
+
{ type: 'string', format: 'objectid' },
|
|
115
|
+
{ type: 'string', format: 'uuid' },
|
|
116
|
+
{ type: 'integer', minimum: 1 },
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
// Email validation
|
|
121
|
+
email: {
|
|
122
|
+
type: 'string',
|
|
123
|
+
format: 'email',
|
|
124
|
+
maxLength: 255,
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
// Password requirements
|
|
128
|
+
password: {
|
|
129
|
+
type: 'string',
|
|
130
|
+
minLength: 8,
|
|
131
|
+
maxLength: 128,
|
|
132
|
+
pattern: '^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)',
|
|
133
|
+
},
|
|
134
|
+
|
|
135
|
+
// BigInt validation
|
|
136
|
+
bigintString: {
|
|
137
|
+
type: 'string',
|
|
138
|
+
format: 'bigint',
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
// Date validation
|
|
142
|
+
dateString: {
|
|
143
|
+
type: 'string',
|
|
144
|
+
format: 'date-time',
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Schema builder helper
|
|
150
|
+
*/
|
|
151
|
+
class SchemaBuilder {
|
|
152
|
+
constructor() {
|
|
153
|
+
this.schema = {
|
|
154
|
+
type: 'object',
|
|
155
|
+
properties: {},
|
|
156
|
+
required: [],
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Add a property to the schema
|
|
162
|
+
* @param {string} name
|
|
163
|
+
* @param {Object} definition
|
|
164
|
+
* @param {boolean} required
|
|
165
|
+
* @returns {SchemaBuilder}
|
|
166
|
+
*/
|
|
167
|
+
property(name, definition, required = false) {
|
|
168
|
+
this.schema.properties[name] = definition;
|
|
169
|
+
if (required) {
|
|
170
|
+
this.schema.required.push(name);
|
|
171
|
+
}
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Add multiple properties
|
|
177
|
+
* @param {Object} properties
|
|
178
|
+
* @returns {SchemaBuilder}
|
|
179
|
+
*/
|
|
180
|
+
properties(properties) {
|
|
181
|
+
Object.entries(properties).forEach(([name, definition]) => {
|
|
182
|
+
this.property(name, definition);
|
|
183
|
+
});
|
|
184
|
+
return this;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Set required fields
|
|
189
|
+
* @param {string[]} fields
|
|
190
|
+
* @returns {SchemaBuilder}
|
|
191
|
+
*/
|
|
192
|
+
required(fields) {
|
|
193
|
+
this.schema.required = [...new Set([...this.schema.required, ...fields])];
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Add additional properties setting
|
|
199
|
+
* @param {boolean} allowed
|
|
200
|
+
* @returns {SchemaBuilder}
|
|
201
|
+
*/
|
|
202
|
+
additionalProperties(allowed) {
|
|
203
|
+
this.schema.additionalProperties = allowed;
|
|
204
|
+
return this;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Build and return the schema
|
|
209
|
+
* @returns {Object}
|
|
210
|
+
*/
|
|
211
|
+
build() {
|
|
212
|
+
return this.schema;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = {
|
|
217
|
+
SchemaValidator,
|
|
218
|
+
commonSchemas,
|
|
219
|
+
SchemaBuilder,
|
|
220
|
+
};
|