@appium/base-driver 9.17.0 → 10.0.0-beta.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/build/lib/basedriver/capabilities.d.ts.map +1 -1
- package/build/lib/basedriver/capabilities.js +2 -4
- package/build/lib/basedriver/capabilities.js.map +1 -1
- package/build/lib/basedriver/commands/timeout.js +7 -25
- package/build/lib/basedriver/commands/timeout.js.map +1 -1
- package/build/lib/basedriver/core.d.ts +0 -8
- package/build/lib/basedriver/core.d.ts.map +1 -1
- package/build/lib/basedriver/core.js +8 -18
- package/build/lib/basedriver/core.js.map +1 -1
- package/build/lib/basedriver/driver.js +2 -2
- package/build/lib/basedriver/driver.js.map +1 -1
- package/build/lib/basedriver/helpers.d.ts +9 -1
- package/build/lib/basedriver/helpers.d.ts.map +1 -1
- package/build/lib/basedriver/helpers.js +56 -142
- package/build/lib/basedriver/helpers.js.map +1 -1
- package/build/lib/basedriver/validation.d.ts +7 -0
- package/build/lib/basedriver/validation.d.ts.map +1 -0
- package/build/lib/basedriver/validation.js +130 -0
- package/build/lib/basedriver/validation.js.map +1 -0
- package/build/lib/express/middleware.d.ts +0 -6
- package/build/lib/express/middleware.d.ts.map +1 -1
- package/build/lib/express/middleware.js +12 -64
- package/build/lib/express/middleware.js.map +1 -1
- package/build/lib/express/server.d.ts.map +1 -1
- package/build/lib/express/server.js +1 -2
- package/build/lib/express/server.js.map +1 -1
- package/build/lib/helpers/capabilities.d.ts +13 -6
- package/build/lib/helpers/capabilities.d.ts.map +1 -1
- package/build/lib/helpers/capabilities.js +7 -0
- package/build/lib/helpers/capabilities.js.map +1 -1
- package/build/lib/index.d.ts +1 -0
- package/build/lib/index.d.ts.map +1 -1
- package/build/lib/index.js +3 -1
- package/build/lib/index.js.map +1 -1
- package/build/lib/jsonwp-proxy/proxy.d.ts +0 -8
- package/build/lib/jsonwp-proxy/proxy.d.ts.map +1 -1
- package/build/lib/jsonwp-proxy/proxy.js +1 -29
- package/build/lib/jsonwp-proxy/proxy.js.map +1 -1
- package/build/lib/protocol/errors.d.ts +171 -277
- package/build/lib/protocol/errors.d.ts.map +1 -1
- package/build/lib/protocol/errors.js +201 -421
- package/build/lib/protocol/errors.js.map +1 -1
- package/build/lib/protocol/helpers.d.ts +6 -6
- package/build/lib/protocol/helpers.d.ts.map +1 -1
- package/build/lib/protocol/helpers.js +11 -7
- package/build/lib/protocol/helpers.js.map +1 -1
- package/build/lib/protocol/protocol.d.ts +5 -0
- package/build/lib/protocol/protocol.d.ts.map +1 -1
- package/build/lib/protocol/protocol.js +23 -23
- package/build/lib/protocol/protocol.js.map +1 -1
- package/build/lib/protocol/routes.d.ts +6 -715
- package/build/lib/protocol/routes.d.ts.map +1 -1
- package/build/lib/protocol/routes.js +16 -481
- package/build/lib/protocol/routes.js.map +1 -1
- package/build/lib/protocol/validators.d.ts +4 -7
- package/build/lib/protocol/validators.d.ts.map +1 -1
- package/build/lib/protocol/validators.js +4 -24
- package/build/lib/protocol/validators.js.map +1 -1
- package/lib/basedriver/capabilities.ts +2 -4
- package/lib/basedriver/commands/timeout.ts +11 -34
- package/lib/basedriver/core.ts +10 -19
- package/lib/basedriver/driver.ts +3 -3
- package/lib/basedriver/helpers.js +61 -167
- package/lib/basedriver/validation.ts +145 -0
- package/lib/express/middleware.js +16 -75
- package/lib/express/server.js +1 -3
- package/lib/helpers/capabilities.js +9 -4
- package/lib/index.js +2 -0
- package/lib/jsonwp-proxy/proxy.js +2 -33
- package/lib/protocol/{errors.js → errors.ts} +322 -436
- package/lib/protocol/helpers.js +12 -8
- package/lib/protocol/protocol.js +25 -23
- package/lib/protocol/routes.js +18 -491
- package/lib/protocol/validators.ts +19 -0
- package/package.json +10 -10
- package/build/lib/basedriver/desired-caps.d.ts +0 -5
- package/build/lib/basedriver/desired-caps.d.ts.map +0 -1
- package/build/lib/basedriver/desired-caps.js +0 -92
- package/build/lib/basedriver/desired-caps.js.map +0 -1
- package/lib/basedriver/desired-caps.js +0 -103
- package/lib/protocol/validators.js +0 -41
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import type { Constraint } from '@appium/types';
|
|
2
|
+
import log from './logger';
|
|
3
|
+
import _ from 'lodash';
|
|
4
|
+
|
|
5
|
+
export class Validator {
|
|
6
|
+
private readonly _validators: Record<
|
|
7
|
+
keyof Constraint,
|
|
8
|
+
(value: any, options?: any, key?: string) => string | null
|
|
9
|
+
> = {
|
|
10
|
+
isString: (value: any, options?: any): string | null => {
|
|
11
|
+
if (_.isUndefined(value) || _.isNil(options)) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (_.isString(value)) {
|
|
16
|
+
return options ? null : 'must not be of type string';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return options ? 'must be of type string' : null;
|
|
20
|
+
},
|
|
21
|
+
isNumber: (value: any, options?: any): string | null => {
|
|
22
|
+
if (_.isUndefined(value) || _.isNil(options)) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (_.isNumber(value)) {
|
|
27
|
+
return options ? null : 'must not be of type number';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// allow a string value
|
|
31
|
+
if (options && _.isString(value) && !isNaN(Number(value))) {
|
|
32
|
+
log.warn('Number capability passed in as string. Functionality may be compromised.');
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return options ? 'must be of type number' : null;
|
|
37
|
+
},
|
|
38
|
+
isBoolean: (value: any, options?: any): string | null => {
|
|
39
|
+
if (_.isUndefined(value) || _.isNil(options)) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (_.isBoolean(value)) {
|
|
44
|
+
return options ? null : 'must not be of type boolean';
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// allow a string value
|
|
48
|
+
if (options && _.isString(value) && ['true', 'false', ''].includes(value)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return options ? 'must be of type boolean' : null;
|
|
53
|
+
},
|
|
54
|
+
isObject: (value: any, options?: any): string | null => {
|
|
55
|
+
if (_.isUndefined(value) || _.isNil(options)) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (_.isPlainObject(value)) {
|
|
60
|
+
return options ? null : 'must not be a plain object';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return options ? 'must be a plain object' : null;
|
|
64
|
+
},
|
|
65
|
+
isArray: (value: any, options?: any): string | null => {
|
|
66
|
+
if (_.isUndefined(value) || _.isNil(options)) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (_.isArray(value)) {
|
|
71
|
+
return options ? null : 'must not be of type array';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return options ? 'must be of type array' : null;
|
|
75
|
+
},
|
|
76
|
+
deprecated: (value: any, options?: any, key?: string): string | null => {
|
|
77
|
+
if (!_.isUndefined(value) && options) {
|
|
78
|
+
log.warn(
|
|
79
|
+
`The '${key}' capability has been deprecated and must not be used anymore. ` +
|
|
80
|
+
`Please check the driver documentation for possible alternatives.`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
},
|
|
85
|
+
inclusion: (value: any, options?: any): string | null => {
|
|
86
|
+
if (_.isUndefined(value) || !options) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
const optionsArr = _.isArray(options) ? options : [options];
|
|
90
|
+
if (optionsArr.some((opt) => opt === value)) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
return `must be contained by ${JSON.stringify(optionsArr)}`;
|
|
94
|
+
},
|
|
95
|
+
inclusionCaseInsensitive: (value: any, options?: any): string | null => {
|
|
96
|
+
if (_.isUndefined(value) || !options) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
const optionsArr = _.isArray(options) ? options : [options];
|
|
100
|
+
if (optionsArr.some((opt) => _.toLower(opt) === _.toLower(value))) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
return `must be contained by ${JSON.stringify(optionsArr)}`;
|
|
104
|
+
},
|
|
105
|
+
presence: (value: any, options?: any): string | null => {
|
|
106
|
+
if (_.isUndefined(value) && options) {
|
|
107
|
+
return 'is required to be present';
|
|
108
|
+
}
|
|
109
|
+
if (
|
|
110
|
+
!options?.allowEmpty &&
|
|
111
|
+
((!_.isUndefined(value) && _.isEmpty(value)) || (_.isString(value) && !_.trim(value)))
|
|
112
|
+
) {
|
|
113
|
+
return 'must not be empty or blank';
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
validate(values: Record<string, any>, constraints: Record<string, Constraint>): Record<string, string[]> | null {
|
|
120
|
+
const result: Record<string, string[]> = {};
|
|
121
|
+
for (const [key, constraint] of _.toPairs(constraints)) {
|
|
122
|
+
const value = values[key];
|
|
123
|
+
for (const [validatorName, options] of _.toPairs(constraint)) {
|
|
124
|
+
if (!(validatorName in this._validators)) {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const validationError = this._validators[validatorName](value, options, key);
|
|
129
|
+
if (_.isNil(validationError)) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (key in result) {
|
|
134
|
+
result[key].push(validationError);
|
|
135
|
+
} else {
|
|
136
|
+
result[key] = [validationError];
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return _.isEmpty(result) ? null : result;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export const validator = new Validator();
|
|
@@ -5,6 +5,9 @@ export {handleIdempotency} from './idempotency';
|
|
|
5
5
|
import {match} from 'path-to-regexp';
|
|
6
6
|
import {util} from '@appium/support';
|
|
7
7
|
import {calcSignature} from '../helpers/session';
|
|
8
|
+
import {getResponseForW3CError} from '../protocol/errors';
|
|
9
|
+
|
|
10
|
+
const SESSION_ID_PATTERN = /\/session\/([^/]+)/;
|
|
8
11
|
|
|
9
12
|
/**
|
|
10
13
|
*
|
|
@@ -14,20 +17,16 @@ import {calcSignature} from '../helpers/session';
|
|
|
14
17
|
* @returns {any}
|
|
15
18
|
*/
|
|
16
19
|
export function allowCrossDomain(req, res, next) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
);
|
|
20
|
+
res.header('Access-Control-Allow-Origin', '*');
|
|
21
|
+
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS, DELETE');
|
|
22
|
+
res.header(
|
|
23
|
+
'Access-Control-Allow-Headers',
|
|
24
|
+
'Cache-Control, Pragma, Origin, X-Requested-With, Content-Type, Accept, User-Agent'
|
|
25
|
+
);
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
} catch (err) {
|
|
30
|
-
log.error(`Unexpected error: ${err.stack}`);
|
|
27
|
+
// need to respond 200 to OPTIONS
|
|
28
|
+
if ('OPTIONS' === req.method) {
|
|
29
|
+
return res.sendStatus(200);
|
|
31
30
|
}
|
|
32
31
|
next();
|
|
33
32
|
}
|
|
@@ -50,26 +49,6 @@ export function allowCrossDomainAsyncExecute(basePath) {
|
|
|
50
49
|
};
|
|
51
50
|
}
|
|
52
51
|
|
|
53
|
-
/**
|
|
54
|
-
*
|
|
55
|
-
* @param {string} basePath
|
|
56
|
-
* @returns {import('express').RequestHandler}
|
|
57
|
-
*/
|
|
58
|
-
export function fixPythonContentType(basePath) {
|
|
59
|
-
return (req, res, next) => {
|
|
60
|
-
// hack because python client library gives us wrong content-type
|
|
61
|
-
if (
|
|
62
|
-
new RegExp(`^${_.escapeRegExp(basePath)}`).test(req.path) &&
|
|
63
|
-
/^Python/.test(req.headers['user-agent'] ?? '')
|
|
64
|
-
) {
|
|
65
|
-
if (req.headers['content-type'] === 'application/x-www-form-urlencoded') {
|
|
66
|
-
req.headers['content-type'] = 'application/json; charset=utf-8';
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
next();
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
52
|
/**
|
|
74
53
|
*
|
|
75
54
|
* @param {import('express').Request} req
|
|
@@ -147,19 +126,8 @@ export function catchAllHandler(err, req, res, next) {
|
|
|
147
126
|
}
|
|
148
127
|
|
|
149
128
|
log.error(`Uncaught error: ${err.message}`);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
res.status(error.w3cStatus()).json(
|
|
153
|
-
patchWithSessionId(req, {
|
|
154
|
-
status: error.code(),
|
|
155
|
-
value: {
|
|
156
|
-
error: error.error(),
|
|
157
|
-
message: `An unknown server-side error occurred while processing the command: ${err.message}`,
|
|
158
|
-
stacktrace: err.stack,
|
|
159
|
-
},
|
|
160
|
-
})
|
|
161
|
-
);
|
|
162
|
-
log.error(err);
|
|
129
|
+
const [status, body] = getResponseForW3CError(err);
|
|
130
|
+
res.status(status).json(body);
|
|
163
131
|
}
|
|
164
132
|
|
|
165
133
|
/**
|
|
@@ -168,35 +136,8 @@ export function catchAllHandler(err, req, res, next) {
|
|
|
168
136
|
*/
|
|
169
137
|
export function catch404Handler(req, res) {
|
|
170
138
|
log.debug(`No route found for ${req.url}`);
|
|
171
|
-
const
|
|
172
|
-
res.status(
|
|
173
|
-
patchWithSessionId(req, {
|
|
174
|
-
status: error.code(),
|
|
175
|
-
value: {
|
|
176
|
-
error: error.error(),
|
|
177
|
-
message:
|
|
178
|
-
'The requested resource could not be found, or a request was ' +
|
|
179
|
-
'received using an HTTP method that is not supported by the mapped ' +
|
|
180
|
-
'resource',
|
|
181
|
-
stacktrace: '',
|
|
182
|
-
},
|
|
183
|
-
})
|
|
184
|
-
);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const SESSION_ID_PATTERN = /\/session\/([^/]+)/;
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* @param {import('express').Request} req
|
|
191
|
-
* @param {any} body
|
|
192
|
-
* @returns {any}
|
|
193
|
-
*/
|
|
194
|
-
function patchWithSessionId(req, body) {
|
|
195
|
-
const match = SESSION_ID_PATTERN.exec(req.url);
|
|
196
|
-
if (match) {
|
|
197
|
-
body.sessionId = match[1];
|
|
198
|
-
}
|
|
199
|
-
return body;
|
|
139
|
+
const [status, body] = getResponseForW3CError(new errors.UnknownCommandError());
|
|
140
|
+
res.status(status).json(body);
|
|
200
141
|
}
|
|
201
142
|
|
|
202
143
|
/**
|
package/lib/express/server.js
CHANGED
|
@@ -9,7 +9,6 @@ import log from './logger';
|
|
|
9
9
|
import {startLogFormatter, endLogFormatter} from './express-logging';
|
|
10
10
|
import {
|
|
11
11
|
allowCrossDomain,
|
|
12
|
-
fixPythonContentType,
|
|
13
12
|
defaultToJSONContentType,
|
|
14
13
|
catchAllHandler,
|
|
15
14
|
allowCrossDomainAsyncExecute,
|
|
@@ -122,7 +121,7 @@ export async function server(opts) {
|
|
|
122
121
|
// once all configurations and updaters have been applied, make sure to set up a catchall
|
|
123
122
|
// handler so that anything unknown 404s. But do this after everything else since we don't
|
|
124
123
|
// want to block extensions' ability to add routes if they want.
|
|
125
|
-
app.all('
|
|
124
|
+
app.all('/*all', catch404Handler);
|
|
126
125
|
|
|
127
126
|
await startServer({
|
|
128
127
|
httpServer,
|
|
@@ -172,7 +171,6 @@ export function configureServer({
|
|
|
172
171
|
app.use(allowCrossDomainAsyncExecute(basePath));
|
|
173
172
|
}
|
|
174
173
|
app.use(handleIdempotency);
|
|
175
|
-
app.use(fixPythonContentType(basePath));
|
|
176
174
|
app.use(defaultToJSONContentType);
|
|
177
175
|
app.use(bodyParser.urlencoded({extended: true}));
|
|
178
176
|
app.use(methodOverride());
|
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
import _ from 'lodash';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Determine whether the given agument is valid
|
|
7
|
+
* W3C capabilities instance.
|
|
8
|
+
*
|
|
9
|
+
* @param {any} caps
|
|
10
|
+
* @returns {caps is import('@appium/types').W3CCapabilities}
|
|
11
|
+
*/
|
|
12
|
+
export function isW3cCaps(caps) {
|
|
6
13
|
if (!_.isPlainObject(caps)) {
|
|
7
14
|
return false;
|
|
8
15
|
}
|
|
@@ -32,7 +39,7 @@ function isW3cCaps(caps) {
|
|
|
32
39
|
* @param {AppiumLogger} log
|
|
33
40
|
* @returns {Capabilities<C>}
|
|
34
41
|
*/
|
|
35
|
-
function fixCaps(oldCaps, desiredCapConstraints, log) {
|
|
42
|
+
export function fixCaps(oldCaps, desiredCapConstraints, log) {
|
|
36
43
|
let caps = _.clone(oldCaps);
|
|
37
44
|
|
|
38
45
|
// boolean capabilities can be passed in as strings 'false' and 'true'
|
|
@@ -73,8 +80,6 @@ function fixCaps(oldCaps, desiredCapConstraints, log) {
|
|
|
73
80
|
return caps;
|
|
74
81
|
}
|
|
75
82
|
|
|
76
|
-
export {isW3cCaps, fixCaps};
|
|
77
|
-
|
|
78
83
|
/**
|
|
79
84
|
* @typedef {import('@appium/types').Constraints} Constraints
|
|
80
85
|
* @typedef {import('@appium/types').AppiumLogger} AppiumLogger
|
package/lib/index.js
CHANGED
|
@@ -54,6 +54,8 @@ export {BIDI_COMMANDS} from './protocol/bidi-commands';
|
|
|
54
54
|
|
|
55
55
|
export {generateDriverLogPrefix} from './basedriver/helpers';
|
|
56
56
|
|
|
57
|
+
export {isW3cCaps} from './helpers/capabilities';
|
|
58
|
+
|
|
57
59
|
/**
|
|
58
60
|
* @typedef {import('./express/server').ServerOpts} ServerOpts
|
|
59
61
|
*/
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import {isSessionCommand, routeToCommandName} from '../protocol';
|
|
12
12
|
import {MAX_LOG_BODY_LENGTH, DEFAULT_BASE_PATH, PROTOCOLS} from '../constants';
|
|
13
13
|
import ProtocolConverter from './protocol-converter';
|
|
14
|
-
import {formatResponseValue,
|
|
14
|
+
import {formatResponseValue, ensureW3cResponse} from '../protocol/helpers';
|
|
15
15
|
import http from 'http';
|
|
16
16
|
import https from 'https';
|
|
17
17
|
import { match as pathToRegexMatch } from 'path-to-regexp';
|
|
@@ -290,37 +290,6 @@ export class JWProxy {
|
|
|
290
290
|
}
|
|
291
291
|
}
|
|
292
292
|
|
|
293
|
-
/**
|
|
294
|
-
* @deprecated This method is not used anymore and will be removed
|
|
295
|
-
*
|
|
296
|
-
* @param {string} url
|
|
297
|
-
* @param {import('@appium/types').HTTPMethod} method
|
|
298
|
-
* @returns {string|undefined}
|
|
299
|
-
*/
|
|
300
|
-
requestToCommandName(url, method) {
|
|
301
|
-
/**
|
|
302
|
-
*
|
|
303
|
-
* @param {RegExp} pattern
|
|
304
|
-
* @returns {string|undefined}
|
|
305
|
-
*/
|
|
306
|
-
const extractCommandName = (pattern) => {
|
|
307
|
-
const pathMatch = pattern.exec(url);
|
|
308
|
-
if (pathMatch) {
|
|
309
|
-
return routeToCommandName(pathMatch[1], method, this.reqBasePath);
|
|
310
|
-
}
|
|
311
|
-
};
|
|
312
|
-
let commandName = routeToCommandName(url, method, this.reqBasePath);
|
|
313
|
-
if (!commandName && _.includes(url, `${this.reqBasePath}/session/`)) {
|
|
314
|
-
commandName = extractCommandName(
|
|
315
|
-
new RegExp(`${_.escapeRegExp(this.reqBasePath)}/session/[^/]+(.+)`)
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
if (!commandName && _.includes(url, this.reqBasePath)) {
|
|
319
|
-
commandName = extractCommandName(new RegExp(`${_.escapeRegExp(this.reqBasePath)}(/.+)`));
|
|
320
|
-
}
|
|
321
|
-
return commandName;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
293
|
/**
|
|
325
294
|
*
|
|
326
295
|
* @param {string} url
|
|
@@ -457,7 +426,7 @@ export class JWProxy {
|
|
|
457
426
|
}
|
|
458
427
|
}
|
|
459
428
|
resBodyObj.value = formatResponseValue(resBodyObj.value);
|
|
460
|
-
res.status(statusCode).
|
|
429
|
+
res.status(statusCode).json(ensureW3cResponse(resBodyObj));
|
|
461
430
|
}
|
|
462
431
|
|
|
463
432
|
/**
|