@appium/base-driver 10.5.2 → 10.7.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/build/lib/basedriver/capabilities.d.ts +1 -1
- package/build/lib/basedriver/capabilities.d.ts.map +1 -1
- package/build/lib/basedriver/capabilities.js +58 -50
- package/build/lib/basedriver/capabilities.js.map +1 -1
- package/build/lib/basedriver/commands/bidi.d.ts.map +1 -1
- package/build/lib/basedriver/commands/bidi.js +10 -14
- package/build/lib/basedriver/commands/bidi.js.map +1 -1
- package/build/lib/basedriver/commands/event.d.ts.map +1 -1
- package/build/lib/basedriver/commands/event.js +4 -7
- package/build/lib/basedriver/commands/event.js.map +1 -1
- package/build/lib/basedriver/commands/execute.js +3 -6
- package/build/lib/basedriver/commands/execute.js.map +1 -1
- package/build/lib/basedriver/commands/find.d.ts.map +1 -1
- package/build/lib/basedriver/commands/find.js +2 -1
- package/build/lib/basedriver/commands/find.js.map +1 -1
- package/build/lib/basedriver/commands/log.d.ts.map +1 -1
- package/build/lib/basedriver/commands/log.js +1 -5
- package/build/lib/basedriver/commands/log.js.map +1 -1
- package/build/lib/basedriver/commands/timeout.d.ts.map +1 -1
- package/build/lib/basedriver/commands/timeout.js +9 -13
- package/build/lib/basedriver/commands/timeout.js.map +1 -1
- package/build/lib/basedriver/core.d.ts.map +1 -1
- package/build/lib/basedriver/core.js +17 -14
- package/build/lib/basedriver/core.js.map +1 -1
- package/build/lib/basedriver/device-settings.d.ts.map +1 -1
- package/build/lib/basedriver/device-settings.js +3 -7
- package/build/lib/basedriver/device-settings.js.map +1 -1
- package/build/lib/basedriver/driver.d.ts.map +1 -1
- package/build/lib/basedriver/driver.js +34 -38
- package/build/lib/basedriver/driver.js.map +1 -1
- package/build/lib/basedriver/extension-core.d.ts +4 -1
- package/build/lib/basedriver/extension-core.d.ts.map +1 -1
- package/build/lib/basedriver/extension-core.js +37 -13
- package/build/lib/basedriver/extension-core.js.map +1 -1
- package/build/lib/basedriver/helpers.d.ts.map +1 -1
- package/build/lib/basedriver/helpers.js +47 -33
- package/build/lib/basedriver/helpers.js.map +1 -1
- package/build/lib/basedriver/ipc.d.ts +36 -0
- package/build/lib/basedriver/ipc.d.ts.map +1 -0
- package/build/lib/basedriver/ipc.js +157 -0
- package/build/lib/basedriver/ipc.js.map +1 -0
- package/build/lib/basedriver/validation.d.ts.map +1 -1
- package/build/lib/basedriver/validation.js +27 -29
- package/build/lib/basedriver/validation.js.map +1 -1
- package/build/lib/express/express-logging.d.ts +0 -1
- package/build/lib/express/express-logging.d.ts.map +1 -1
- package/build/lib/express/express-logging.js +11 -11
- package/build/lib/express/express-logging.js.map +1 -1
- package/build/lib/express/idempotency.js +3 -6
- package/build/lib/express/idempotency.js.map +1 -1
- package/build/lib/express/middleware.d.ts.map +1 -1
- package/build/lib/express/middleware.js +6 -10
- package/build/lib/express/middleware.js.map +1 -1
- package/build/lib/express/server.d.ts +1 -1
- package/build/lib/express/server.d.ts.map +1 -1
- package/build/lib/express/server.js +82 -73
- package/build/lib/express/server.js.map +1 -1
- package/build/lib/express/websocket.d.ts.map +1 -1
- package/build/lib/express/websocket.js +6 -9
- package/build/lib/express/websocket.js.map +1 -1
- package/build/lib/helpers/capabilities.d.ts.map +1 -1
- package/build/lib/helpers/capabilities.js +14 -17
- package/build/lib/helpers/capabilities.js.map +1 -1
- package/build/lib/helpers/extension-command-name.js +2 -5
- package/build/lib/helpers/extension-command-name.js.map +1 -1
- package/build/lib/helpers/levenshtein-match.d.ts.map +1 -1
- package/build/lib/helpers/levenshtein-match.js +6 -7
- package/build/lib/helpers/levenshtein-match.js.map +1 -1
- package/build/lib/index.d.ts +2 -1
- package/build/lib/index.d.ts.map +1 -1
- package/build/lib/index.js +6 -16
- package/build/lib/index.js.map +1 -1
- package/build/lib/jsonwp-proxy/protocol-converter.d.ts.map +1 -1
- package/build/lib/jsonwp-proxy/protocol-converter.js +21 -18
- package/build/lib/jsonwp-proxy/protocol-converter.js.map +1 -1
- package/build/lib/jsonwp-proxy/proxy-request.d.ts +2 -2
- package/build/lib/jsonwp-proxy/proxy-request.d.ts.map +1 -1
- package/build/lib/jsonwp-proxy/proxy-request.js +25 -21
- package/build/lib/jsonwp-proxy/proxy-request.js.map +1 -1
- package/build/lib/jsonwp-proxy/proxy.d.ts.map +1 -1
- package/build/lib/jsonwp-proxy/proxy.js +45 -36
- package/build/lib/jsonwp-proxy/proxy.js.map +1 -1
- package/build/lib/protocol/errors.d.ts.map +1 -1
- package/build/lib/protocol/errors.js +33 -37
- package/build/lib/protocol/errors.js.map +1 -1
- package/build/lib/protocol/helpers.d.ts.map +1 -1
- package/build/lib/protocol/helpers.js +9 -8
- package/build/lib/protocol/helpers.js.map +1 -1
- package/build/lib/protocol/protocol.d.ts +1 -1
- package/build/lib/protocol/protocol.d.ts.map +1 -1
- package/build/lib/protocol/protocol.js +73 -61
- package/build/lib/protocol/protocol.js.map +1 -1
- package/build/lib/protocol/routes.d.ts +1 -1
- package/build/lib/protocol/routes.d.ts.map +1 -1
- package/build/lib/protocol/routes.js +16 -17
- package/build/lib/protocol/routes.js.map +1 -1
- package/build/lib/protocol/validators.d.ts.map +1 -1
- package/build/lib/protocol/validators.js +1 -5
- package/build/lib/protocol/validators.js.map +1 -1
- package/build/lib/test-pages/crash.d.ts.map +1 -0
- package/build/lib/test-pages/crash.js.map +1 -0
- package/build/lib/test-pages/env.d.ts +5 -0
- package/build/lib/test-pages/env.d.ts.map +1 -0
- package/build/lib/test-pages/env.js +12 -0
- package/build/lib/test-pages/env.js.map +1 -0
- package/build/lib/{express/static.d.ts → test-pages/handlers.d.ts} +1 -2
- package/build/lib/test-pages/handlers.d.ts.map +1 -0
- package/build/lib/{express/static.js → test-pages/handlers.js} +9 -12
- package/build/lib/test-pages/handlers.js.map +1 -0
- package/build/lib/test-pages/index.d.ts +6 -0
- package/build/lib/test-pages/index.d.ts.map +1 -0
- package/build/lib/test-pages/index.js +35 -0
- package/build/lib/test-pages/index.js.map +1 -0
- package/build/lib/test-pages/static-dir.d.ts +8 -0
- package/build/lib/test-pages/static-dir.d.ts.map +1 -0
- package/build/lib/test-pages/static-dir.js +24 -0
- package/build/lib/test-pages/static-dir.js.map +1 -0
- package/build/lib/test-pages/template.d.ts +3 -0
- package/build/lib/test-pages/template.d.ts.map +1 -0
- package/build/lib/test-pages/template.js +19 -0
- package/build/lib/test-pages/template.js.map +1 -0
- package/build/lib/utils.d.ts +14 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js +55 -0
- package/build/lib/utils.js.map +1 -0
- package/lib/basedriver/capabilities.ts +126 -115
- package/lib/basedriver/commands/bidi.ts +11 -11
- package/lib/basedriver/commands/event.ts +17 -11
- package/lib/basedriver/commands/execute.ts +15 -12
- package/lib/basedriver/commands/find.ts +20 -12
- package/lib/basedriver/commands/log.ts +4 -3
- package/lib/basedriver/commands/timeout.ts +22 -14
- package/lib/basedriver/core.ts +26 -26
- package/lib/basedriver/device-settings.ts +7 -12
- package/lib/basedriver/driver.ts +62 -50
- package/lib/basedriver/extension-core.ts +60 -18
- package/lib/basedriver/helpers.ts +81 -52
- package/lib/basedriver/ipc.ts +198 -0
- package/lib/basedriver/validation.ts +37 -30
- package/lib/express/express-logging.ts +16 -20
- package/lib/express/idempotency.ts +9 -9
- package/lib/express/middleware.ts +14 -18
- package/lib/express/server.ts +118 -120
- package/lib/express/websocket.ts +11 -15
- package/lib/helpers/capabilities.ts +21 -16
- package/lib/helpers/extension-command-name.ts +3 -3
- package/lib/helpers/levenshtein-match.ts +20 -14
- package/lib/index.js +3 -12
- package/lib/jsonwp-proxy/protocol-converter.ts +58 -35
- package/lib/jsonwp-proxy/proxy-request.ts +26 -26
- package/lib/jsonwp-proxy/proxy.ts +74 -75
- package/lib/protocol/errors.ts +69 -88
- package/lib/protocol/helpers.ts +9 -5
- package/lib/protocol/protocol.ts +149 -107
- package/lib/protocol/routes.ts +17 -17
- package/lib/protocol/validators.ts +1 -3
- package/lib/test-pages/env.ts +9 -0
- package/lib/{express/static.ts → test-pages/handlers.ts} +10 -22
- package/lib/test-pages/index.ts +34 -0
- package/lib/test-pages/static-dir.ts +19 -0
- package/lib/test-pages/template.ts +17 -0
- package/lib/utils.ts +65 -0
- package/package.json +10 -13
- package/tsconfig.json +1 -0
- package/build/lib/express/crash.d.ts.map +0 -1
- package/build/lib/express/crash.js.map +0 -1
- package/build/lib/express/static.d.ts.map +0 -1
- package/build/lib/express/static.js.map +0 -1
- /package/build/lib/{express → test-pages}/crash.d.ts +0 -0
- /package/build/lib/{express → test-pages}/crash.js +0 -0
- /package/lib/{express → test-pages}/crash.ts +0 -0
- /package/{static → test-fixtures/static}/appium.png +0 -0
- /package/{static → test-fixtures/static}/favicon.ico +0 -0
- /package/{static → test-fixtures/static}/js/jquery.min.js +0 -0
- /package/{static → test-fixtures/static}/test/frameset.html +0 -0
- /package/{static → test-fixtures/static}/test/guinea-pig-app-banner.html +0 -0
- /package/{static → test-fixtures/static}/test/guinea-pig-scrollable.html +0 -0
- /package/{static → test-fixtures/static}/test/guinea-pig.html +0 -0
- /package/{static → test-fixtures/static}/test/guinea-pig2.html +0 -0
- /package/{static → test-fixtures/static}/test/guinea-pig3.html +0 -0
- /package/{static → test-fixtures/static}/test/guinea-pig4.html +0 -0
- /package/{static → test-fixtures/static}/test/guinea-pig5.html +0 -0
- /package/{static → test-fixtures/static}/test/iframes.html +0 -0
- /package/{static → test-fixtures/static}/test/shadow-dom.html +0 -0
- /package/{static → test-fixtures/static}/test/subframe1.html +0 -0
- /package/{static → test-fixtures/static}/test/subframe2.html +0 -0
- /package/{static → test-fixtures/static}/test/subframe3.html +0 -0
- /package/{static → test-fixtures/static}/test/touch.html +0 -0
- /package/{static → test-fixtures/static}/test/welcome.html +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {Constraint} from '@appium/types';
|
|
2
|
+
import {util} from '@appium/support';
|
|
2
3
|
import {log} from './logger';
|
|
3
|
-
import _ from 'lodash';
|
|
4
4
|
|
|
5
5
|
export class Validator {
|
|
6
6
|
private readonly _validators: Record<
|
|
@@ -8,27 +8,27 @@ export class Validator {
|
|
|
8
8
|
(value: any, options?: any, key?: string) => string | null
|
|
9
9
|
> = {
|
|
10
10
|
isString: (value: any, options?: any): string | null => {
|
|
11
|
-
if (
|
|
11
|
+
if (value === undefined || options == null) {
|
|
12
12
|
return null;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
if (
|
|
15
|
+
if (typeof value === 'string') {
|
|
16
16
|
return options ? null : 'must not be of type string';
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
return options ? 'must be of type string' : null;
|
|
20
20
|
},
|
|
21
21
|
isNumber: (value: any, options?: any): string | null => {
|
|
22
|
-
if (
|
|
22
|
+
if (value === undefined || options == null) {
|
|
23
23
|
return null;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
if (
|
|
26
|
+
if (typeof value === 'number') {
|
|
27
27
|
return options ? null : 'must not be of type number';
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// allow a string value
|
|
31
|
-
if (options &&
|
|
31
|
+
if (options && typeof value === 'string' && !isNaN(Number(value))) {
|
|
32
32
|
log.warn('Number capability passed in as string. Functionality may be compromised.');
|
|
33
33
|
return null;
|
|
34
34
|
}
|
|
@@ -36,97 +36,105 @@ export class Validator {
|
|
|
36
36
|
return options ? 'must be of type number' : null;
|
|
37
37
|
},
|
|
38
38
|
isBoolean: (value: any, options?: any): string | null => {
|
|
39
|
-
if (
|
|
39
|
+
if (value === undefined || options == null) {
|
|
40
40
|
return null;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
if (
|
|
43
|
+
if (typeof value === 'boolean') {
|
|
44
44
|
return options ? null : 'must not be of type boolean';
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
// allow a string value
|
|
48
|
-
if (options &&
|
|
48
|
+
if (options && typeof value === 'string' && ['true', 'false', ''].includes(value)) {
|
|
49
49
|
return null;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
return options ? 'must be of type boolean' : null;
|
|
53
53
|
},
|
|
54
54
|
isObject: (value: any, options?: any): string | null => {
|
|
55
|
-
if (
|
|
55
|
+
if (value === undefined || options == null) {
|
|
56
56
|
return null;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
if (
|
|
59
|
+
if (util.isPlainObject(value)) {
|
|
60
60
|
return options ? null : 'must not be a plain object';
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
return options ? 'must be a plain object' : null;
|
|
64
64
|
},
|
|
65
65
|
isArray: (value: any, options?: any): string | null => {
|
|
66
|
-
if (
|
|
66
|
+
if (value === undefined || options == null) {
|
|
67
67
|
return null;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
if (
|
|
70
|
+
if (Array.isArray(value)) {
|
|
71
71
|
return options ? null : 'must not be of type array';
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
return options ? 'must be of type array' : null;
|
|
75
75
|
},
|
|
76
76
|
deprecated: (value: any, options?: any, key?: string): string | null => {
|
|
77
|
-
if (
|
|
77
|
+
if (value !== undefined && options) {
|
|
78
78
|
log.warn(
|
|
79
79
|
`The '${key}' capability has been deprecated and must not be used anymore. ` +
|
|
80
|
-
|
|
80
|
+
`Please check the driver documentation for possible alternatives.`,
|
|
81
81
|
);
|
|
82
82
|
}
|
|
83
83
|
return null;
|
|
84
84
|
},
|
|
85
85
|
inclusion: (value: any, options?: any): string | null => {
|
|
86
|
-
if (
|
|
86
|
+
if (value === undefined || !options) {
|
|
87
87
|
return null;
|
|
88
88
|
}
|
|
89
|
-
const optionsArr =
|
|
89
|
+
const optionsArr = Array.isArray(options) ? options : [options];
|
|
90
90
|
if (optionsArr.some((opt) => opt === value)) {
|
|
91
91
|
return null;
|
|
92
92
|
}
|
|
93
93
|
return `must be contained by ${JSON.stringify(optionsArr)}`;
|
|
94
94
|
},
|
|
95
95
|
inclusionCaseInsensitive: (value: any, options?: any): string | null => {
|
|
96
|
-
if (
|
|
96
|
+
if (value === undefined || !options) {
|
|
97
97
|
return null;
|
|
98
98
|
}
|
|
99
|
-
const optionsArr =
|
|
100
|
-
if (optionsArr.some((opt) =>
|
|
99
|
+
const optionsArr = Array.isArray(options) ? options : [options];
|
|
100
|
+
if (optionsArr.some((opt) => String(opt).toLowerCase() === String(value).toLowerCase())) {
|
|
101
101
|
return null;
|
|
102
102
|
}
|
|
103
103
|
return `must be contained by ${JSON.stringify(optionsArr)}`;
|
|
104
104
|
},
|
|
105
105
|
presence: (value: any, options?: any): string | null => {
|
|
106
|
-
if (
|
|
106
|
+
if (value === undefined && options) {
|
|
107
107
|
return 'is required to be present';
|
|
108
108
|
}
|
|
109
109
|
if (
|
|
110
110
|
!options?.allowEmpty &&
|
|
111
|
-
((
|
|
111
|
+
((value !== undefined && util.isEmpty(value)) ||
|
|
112
|
+
(typeof value === 'string' && !value.trim()))
|
|
112
113
|
) {
|
|
113
114
|
return 'must not be empty or blank';
|
|
114
115
|
}
|
|
115
116
|
return null;
|
|
116
|
-
}
|
|
117
|
+
},
|
|
117
118
|
};
|
|
118
119
|
|
|
119
|
-
validate(
|
|
120
|
+
validate(
|
|
121
|
+
values: Record<string, any>,
|
|
122
|
+
constraints: Record<string, Constraint>,
|
|
123
|
+
): Record<string, string[]> | null {
|
|
120
124
|
const result: Record<string, string[]> = {};
|
|
121
|
-
for (const [key, constraint] of
|
|
125
|
+
for (const [key, constraint] of Object.entries(constraints)) {
|
|
122
126
|
const value = values[key];
|
|
123
|
-
for (const [validatorName, options] of
|
|
127
|
+
for (const [validatorName, options] of Object.entries(constraint)) {
|
|
124
128
|
if (!(validatorName in this._validators)) {
|
|
125
129
|
continue;
|
|
126
130
|
}
|
|
127
131
|
|
|
128
|
-
const validationError = this._validators[validatorName](
|
|
129
|
-
|
|
132
|
+
const validationError = this._validators[validatorName as keyof Constraint](
|
|
133
|
+
value,
|
|
134
|
+
options,
|
|
135
|
+
key,
|
|
136
|
+
);
|
|
137
|
+
if (validationError == null) {
|
|
130
138
|
continue;
|
|
131
139
|
}
|
|
132
140
|
|
|
@@ -137,9 +145,8 @@ export class Validator {
|
|
|
137
145
|
}
|
|
138
146
|
}
|
|
139
147
|
}
|
|
140
|
-
return
|
|
148
|
+
return util.isEmpty(result) ? null : result;
|
|
141
149
|
}
|
|
142
|
-
|
|
143
150
|
}
|
|
144
151
|
|
|
145
152
|
export const validator = new Validator();
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import
|
|
2
|
-
import '@colors/colors';
|
|
1
|
+
import {console, logger, util} from '@appium/support';
|
|
3
2
|
import morgan from 'morgan';
|
|
4
3
|
import type {Request, RequestHandler, Response} from 'express';
|
|
5
4
|
import {log} from './logger';
|
|
6
5
|
import {MAX_LOG_BODY_LENGTH} from '../constants';
|
|
7
|
-
import {logger} from '@appium/support';
|
|
8
6
|
|
|
9
7
|
/**
|
|
10
8
|
* Morgan middleware that logs when the HTTP response finishes.
|
|
@@ -24,17 +22,18 @@ export const startLogFormatter: RequestHandler = morgan(startLogFormatterHandler
|
|
|
24
22
|
type MorganTokens = unknown;
|
|
25
23
|
type FormatFn = (tokens: MorganTokens, req: Request, res: Response) => string;
|
|
26
24
|
|
|
27
|
-
function endLogFormatterHandler(tokens: MorganTokens, req: Request, res: Response):
|
|
25
|
+
function endLogFormatterHandler(tokens: MorganTokens, req: Request, res: Response): undefined {
|
|
28
26
|
log.info(requestEndLoggingFormat(tokens, req, res));
|
|
27
|
+
return undefined;
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
function startLogFormatterHandler(tokens: unknown, req: Request, res: Response):
|
|
30
|
+
function startLogFormatterHandler(tokens: unknown, req: Request, res: Response): undefined {
|
|
32
31
|
let reqBody = '';
|
|
33
32
|
if (req.body) {
|
|
34
33
|
try {
|
|
35
|
-
reqBody =
|
|
36
|
-
|
|
37
|
-
{length: MAX_LOG_BODY_LENGTH}
|
|
34
|
+
reqBody = util.truncateString(
|
|
35
|
+
typeof req.body === 'string' ? req.body : JSON.stringify(req.body),
|
|
36
|
+
{length: MAX_LOG_BODY_LENGTH},
|
|
38
37
|
);
|
|
39
38
|
} catch {
|
|
40
39
|
// ignore
|
|
@@ -42,8 +41,9 @@ function startLogFormatterHandler(tokens: unknown, req: Request, res: Response):
|
|
|
42
41
|
}
|
|
43
42
|
log.info(
|
|
44
43
|
requestStartLoggingFormat(tokens, req, res),
|
|
45
|
-
logger.markSensitive(
|
|
44
|
+
logger.markSensitive(console.styleText('grey', reqBody)),
|
|
46
45
|
);
|
|
46
|
+
return undefined;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
// Copied the morgan compile function over so that cooler formats may be configured
|
|
@@ -56,29 +56,25 @@ function compile(fmt: string): FormatFn {
|
|
|
56
56
|
return new Function('tokens', 'req', 'res', js) as FormatFn;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
function requestEndLoggingFormat(
|
|
60
|
-
tokens: MorganTokens,
|
|
61
|
-
req: Request,
|
|
62
|
-
res: Response
|
|
63
|
-
): string {
|
|
59
|
+
function requestEndLoggingFormat(tokens: MorganTokens, req: Request, res: Response): string {
|
|
64
60
|
const status = res.statusCode;
|
|
65
61
|
let statusStr = ':status';
|
|
66
62
|
if (status >= 500) {
|
|
67
|
-
statusStr =
|
|
63
|
+
statusStr = console.styleText('red', statusStr);
|
|
68
64
|
} else if (status >= 400) {
|
|
69
|
-
statusStr =
|
|
65
|
+
statusStr = console.styleText('yellow', statusStr);
|
|
70
66
|
} else if (status >= 300) {
|
|
71
|
-
statusStr =
|
|
67
|
+
statusStr = console.styleText('cyan', statusStr);
|
|
72
68
|
} else {
|
|
73
|
-
statusStr =
|
|
69
|
+
statusStr = console.styleText('green', statusStr);
|
|
74
70
|
}
|
|
75
71
|
const fn = compile(
|
|
76
|
-
`${'<-- :method :url '
|
|
72
|
+
`${console.styleText('white', '<-- :method :url ')}${statusStr} ${console.styleText('grey', ':response-time ms - :res[content-length]')}`,
|
|
77
73
|
);
|
|
78
74
|
return fn(tokens, req, res);
|
|
79
75
|
}
|
|
80
76
|
|
|
81
77
|
const requestStartLoggingFormat = compile(
|
|
82
|
-
`${'-->'
|
|
78
|
+
`${console.styleText('white', '-->')} ${console.styleText('white', ':method')} ${console.styleText('white', ':url')}`,
|
|
83
79
|
);
|
|
84
80
|
// #endregion
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {log} from './logger';
|
|
2
2
|
import {LRUCache} from 'lru-cache';
|
|
3
|
-
import
|
|
3
|
+
import {util} from '@appium/support';
|
|
4
4
|
import {EventEmitter} from 'node:events';
|
|
5
5
|
import type {Request, Response, NextFunction} from 'express';
|
|
6
6
|
|
|
@@ -31,15 +31,15 @@ const MAX_CACHED_PAYLOAD_SIZE_BYTES = 1 * 1024 * 1024; // 1 MiB
|
|
|
31
31
|
export async function handleIdempotency(
|
|
32
32
|
req: Request,
|
|
33
33
|
res: Response,
|
|
34
|
-
next: NextFunction
|
|
34
|
+
next: NextFunction,
|
|
35
35
|
): Promise<void> {
|
|
36
36
|
const keyOrArr = req.headers[IDEMPOTENCY_KEY_HEADER];
|
|
37
|
-
if (
|
|
37
|
+
if (util.isEmpty(keyOrArr) || !keyOrArr) {
|
|
38
38
|
next();
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
const key =
|
|
42
|
+
const key = Array.isArray(keyOrArr) ? keyOrArr[0] : keyOrArr;
|
|
43
43
|
|
|
44
44
|
log.updateAsyncContext({idempotencyKey: key});
|
|
45
45
|
|
|
@@ -114,7 +114,7 @@ function cacheResponse(key: string, req: Request, res: Response): void {
|
|
|
114
114
|
const patchedWriter = (
|
|
115
115
|
chunk: unknown,
|
|
116
116
|
encoding: BufferEncoding | (() => void),
|
|
117
|
-
next?: (() => void) | ((err?: Error) => void)
|
|
117
|
+
next?: (() => void) | ((err?: Error) => void),
|
|
118
118
|
): boolean => {
|
|
119
119
|
if (errorMessage || !responseRef.deref()) {
|
|
120
120
|
responseChunks = [];
|
|
@@ -122,7 +122,7 @@ function cacheResponse(key: string, req: Request, res: Response): void {
|
|
|
122
122
|
return originalSocketWriter(
|
|
123
123
|
chunk as string | Buffer | Uint8Array,
|
|
124
124
|
encoding as BufferEncoding,
|
|
125
|
-
next as (err?: Error) => void
|
|
125
|
+
next as (err?: Error | null) => void,
|
|
126
126
|
);
|
|
127
127
|
}
|
|
128
128
|
|
|
@@ -139,7 +139,7 @@ function cacheResponse(key: string, req: Request, res: Response): void {
|
|
|
139
139
|
return originalSocketWriter(
|
|
140
140
|
chunk as string | Buffer | Uint8Array,
|
|
141
141
|
encoding as BufferEncoding,
|
|
142
|
-
next as (err?: Error) => void
|
|
142
|
+
next as (err?: Error | null) => void,
|
|
143
143
|
);
|
|
144
144
|
};
|
|
145
145
|
socket.write = patchedWriter as typeof socket.write;
|
|
@@ -153,7 +153,7 @@ function cacheResponse(key: string, req: Request, res: Response): void {
|
|
|
153
153
|
if (!IDEMPOTENT_RESPONSES.has(key)) {
|
|
154
154
|
log.info(
|
|
155
155
|
`Could not cache the response identified by '${key}'. ` +
|
|
156
|
-
`Cache consistency has been damaged
|
|
156
|
+
`Cache consistency has been damaged`,
|
|
157
157
|
);
|
|
158
158
|
} else {
|
|
159
159
|
log.info(`Could not cache the response identified by '${key}': ${errorMessage}`);
|
|
@@ -175,7 +175,7 @@ function cacheResponse(key: string, req: Request, res: Response): void {
|
|
|
175
175
|
if (!IDEMPOTENT_RESPONSES.has(key)) {
|
|
176
176
|
log.info(
|
|
177
177
|
`Could not cache the response identified by '${key}'. ` +
|
|
178
|
-
`Cache consistency has been damaged
|
|
178
|
+
`Cache consistency has been damaged`,
|
|
179
179
|
);
|
|
180
180
|
} else if (errorMessage) {
|
|
181
181
|
log.info(`Could not cache the response identified by '${key}': ${errorMessage}`);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {util} from '@appium/support';
|
|
2
2
|
import type {NextFunction, Request, RequestHandler, Response} from 'express';
|
|
3
3
|
import type {IncomingMessage} from 'node:http';
|
|
4
4
|
import type {Duplex} from 'node:stream';
|
|
@@ -6,7 +6,6 @@ import {log} from './logger';
|
|
|
6
6
|
import {errors} from '../protocol';
|
|
7
7
|
export {handleIdempotency} from './idempotency';
|
|
8
8
|
import {match} from 'path-to-regexp';
|
|
9
|
-
import {util} from '@appium/support';
|
|
10
9
|
import {calcSignature} from '../helpers/session';
|
|
11
10
|
import {getResponseForW3CError} from '../protocol/errors';
|
|
12
11
|
import type {StringRecord, WSServer} from '@appium/types';
|
|
@@ -22,7 +21,7 @@ export function allowCrossDomain(req: Request, res: Response, next: NextFunction
|
|
|
22
21
|
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS, DELETE');
|
|
23
22
|
res.header(
|
|
24
23
|
'Access-Control-Allow-Headers',
|
|
25
|
-
'Cache-Control, Pragma, Origin, X-Requested-With, Content-Type, Accept, User-Agent'
|
|
24
|
+
'Cache-Control, Pragma, Origin, X-Requested-With, Content-Type, Accept, User-Agent',
|
|
26
25
|
);
|
|
27
26
|
|
|
28
27
|
if (req.method === 'OPTIONS') {
|
|
@@ -43,10 +42,10 @@ export function allowCrossDomainAsyncExecute(basePath: string): RequestHandler {
|
|
|
43
42
|
function allowCrossDomainAsyncExecuteHandler(
|
|
44
43
|
req: Request,
|
|
45
44
|
res: Response,
|
|
46
|
-
next: NextFunction
|
|
45
|
+
next: NextFunction,
|
|
47
46
|
): void {
|
|
48
47
|
const receiveAsyncResponseRegExp = new RegExp(
|
|
49
|
-
`${
|
|
48
|
+
`${util.escapeRegExp(basePath)}/session/[a-f0-9-]+/(appium/)?receive_async_response`,
|
|
50
49
|
);
|
|
51
50
|
if (!receiveAsyncResponseRegExp.test(req.url)) {
|
|
52
51
|
next();
|
|
@@ -73,9 +72,11 @@ export function handleLogContext(req: Request, _res: Response, next: NextFunctio
|
|
|
73
72
|
{
|
|
74
73
|
requestId,
|
|
75
74
|
...sessionInfo,
|
|
76
|
-
isSensitive: ['true', '1', 'yes'].includes(
|
|
75
|
+
isSensitive: ['true', '1', 'yes'].includes(
|
|
76
|
+
String(isSensitiveHeaderValue ?? '').toLowerCase(),
|
|
77
|
+
),
|
|
77
78
|
},
|
|
78
|
-
true
|
|
79
|
+
true,
|
|
79
80
|
);
|
|
80
81
|
|
|
81
82
|
next();
|
|
@@ -84,11 +85,7 @@ export function handleLogContext(req: Request, _res: Response, next: NextFunctio
|
|
|
84
85
|
/**
|
|
85
86
|
* Ensures requests default to JSON content-type when none is provided.
|
|
86
87
|
*/
|
|
87
|
-
export function defaultToJSONContentType(
|
|
88
|
-
req: Request,
|
|
89
|
-
_res: Response,
|
|
90
|
-
next: NextFunction
|
|
91
|
-
): void {
|
|
88
|
+
export function defaultToJSONContentType(req: Request, _res: Response, next: NextFunction): void {
|
|
92
89
|
if (!req.headers['content-type']) {
|
|
93
90
|
req.headers['content-type'] = 'application/json; charset=utf-8';
|
|
94
91
|
}
|
|
@@ -108,9 +105,9 @@ export function tryHandleWebSocketUpgrade(
|
|
|
108
105
|
req: IncomingMessage,
|
|
109
106
|
socket: Duplex,
|
|
110
107
|
head: Buffer,
|
|
111
|
-
webSocketsMapping: StringRecord<WSServer
|
|
108
|
+
webSocketsMapping: StringRecord<WSServer>,
|
|
112
109
|
): boolean {
|
|
113
|
-
if (
|
|
110
|
+
if (String(req.headers?.upgrade ?? '').toLowerCase() !== 'websocket') {
|
|
114
111
|
return false;
|
|
115
112
|
}
|
|
116
113
|
|
|
@@ -120,7 +117,7 @@ export function tryHandleWebSocketUpgrade(
|
|
|
120
117
|
} catch {
|
|
121
118
|
currentPathname = req.url ?? '';
|
|
122
119
|
}
|
|
123
|
-
for (const [pathname, wsServer] of
|
|
120
|
+
for (const [pathname, wsServer] of Object.entries(webSocketsMapping)) {
|
|
124
121
|
if (match(pathname)(currentPathname)) {
|
|
125
122
|
wsServer.handleUpgrade(req, socket, head, (ws) => {
|
|
126
123
|
wsServer.emit('connection', ws, req);
|
|
@@ -158,7 +155,7 @@ export function catchAllHandler(
|
|
|
158
155
|
err: Error,
|
|
159
156
|
_req: Request,
|
|
160
157
|
res: Response,
|
|
161
|
-
next: NextFunction
|
|
158
|
+
next: NextFunction,
|
|
162
159
|
): void {
|
|
163
160
|
if (res.headersSent) {
|
|
164
161
|
next(err);
|
|
@@ -182,6 +179,5 @@ export function catch404Handler(req: Request, res: Response): void {
|
|
|
182
179
|
|
|
183
180
|
function fetchHeaderValue(req: Request, name: string): string | undefined {
|
|
184
181
|
const value = req.headers[name];
|
|
185
|
-
return
|
|
182
|
+
return Array.isArray(value) ? value[0] : (value as string | undefined);
|
|
186
183
|
}
|
|
187
|
-
|