ibm-cloud-sdk-core 5.0.1 → 5.0.2
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/.secrets.baseline +15 -15
- package/CHANGELOG.md +7 -0
- package/auth/authenticators/basic-authenticator.d.ts +1 -1
- package/auth/authenticators/basic-authenticator.js +3 -1
- package/auth/authenticators/bearer-token-authenticator.js +2 -0
- package/auth/authenticators/token-request-based-authenticator.js +3 -0
- package/auth/token-managers/cp4d-token-manager.js +6 -1
- package/auth/token-managers/iam-request-based-token-manager.js +5 -1
- package/auth/token-managers/mcsp-token-manager.js +6 -1
- package/auth/token-managers/token-manager.js +7 -3
- package/auth/token-managers/vpc-instance-token-manager.js +4 -1
- package/auth/utils/read-external-sources.js +2 -0
- package/es/auth/authenticators/basic-authenticator.d.ts +1 -1
- package/es/auth/authenticators/basic-authenticator.js +3 -1
- package/es/auth/authenticators/bearer-token-authenticator.js +2 -0
- package/es/auth/authenticators/token-request-based-authenticator.js +2 -0
- package/es/auth/token-managers/cp4d-token-manager.js +6 -1
- package/es/auth/token-managers/iam-request-based-token-manager.js +5 -1
- package/es/auth/token-managers/mcsp-token-manager.js +6 -1
- package/es/auth/token-managers/token-manager.js +7 -3
- package/es/auth/token-managers/vpc-instance-token-manager.js +4 -1
- package/es/auth/utils/read-external-sources.js +2 -0
- package/es/lib/base-service.js +2 -0
- package/es/lib/private-helpers.d.ts +22 -0
- package/es/lib/private-helpers.js +58 -0
- package/es/lib/request-wrapper.d.ts +43 -1
- package/es/lib/request-wrapper.js +113 -14
- package/ibm-cloud-sdk-core.d.ts +42 -0
- package/lib/base-service.js +2 -0
- package/lib/private-helpers.d.ts +22 -0
- package/lib/private-helpers.js +62 -0
- package/lib/request-wrapper.d.ts +43 -1
- package/lib/request-wrapper.js +113 -14
- package/package.json +4 -3
- package/sdk-test-utilities/package-lock.json +8 -5
- package/sdk-test-utilities/package.json +3 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* (C) Copyright IBM Corp. 2014,
|
|
2
|
+
* (C) Copyright IBM Corp. 2014, 2024.
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -33,6 +33,42 @@ export declare class RequestWrapper {
|
|
|
33
33
|
private retryInterceptorId;
|
|
34
34
|
private raxConfig;
|
|
35
35
|
constructor(axiosOptions?: any);
|
|
36
|
+
/**
|
|
37
|
+
* Formats the specified Axios request for debug logging.
|
|
38
|
+
* @param request - the request to be logged
|
|
39
|
+
* @returns the string representation of the request
|
|
40
|
+
*/
|
|
41
|
+
private formatAxiosRequest;
|
|
42
|
+
/**
|
|
43
|
+
* Formats the specified Axios response for debug logging.
|
|
44
|
+
* @param response - the response to be logged
|
|
45
|
+
* @returns the string representation of the response
|
|
46
|
+
*/
|
|
47
|
+
private formatAxiosResponse;
|
|
48
|
+
/**
|
|
49
|
+
* Formats the specified Axios error for debug logging.
|
|
50
|
+
* @param error - the error to be logged
|
|
51
|
+
* @returns the string representation of the error
|
|
52
|
+
*/
|
|
53
|
+
private formatAxiosError;
|
|
54
|
+
/**
|
|
55
|
+
* Formats 'headers' to be included in the debug output
|
|
56
|
+
* like this:
|
|
57
|
+
* Accept: application/json
|
|
58
|
+
* Content-Type: application/json
|
|
59
|
+
* My-Header: my-value
|
|
60
|
+
* ...
|
|
61
|
+
* @param headers - the headers associated with an Axios request or response
|
|
62
|
+
* @returns the formatted output to be included in the HTTP message traces
|
|
63
|
+
*/
|
|
64
|
+
private formatAxiosHeaders;
|
|
65
|
+
/**
|
|
66
|
+
* Formats 'body' (either a string or object/array) to be included in the debug output
|
|
67
|
+
*
|
|
68
|
+
* @param body - a string, object or array that contains the request or response body
|
|
69
|
+
* @returns the formatted output to be included in the HTTP message traces
|
|
70
|
+
*/
|
|
71
|
+
private formatAxiosBody;
|
|
36
72
|
setCompressRequestData(setting: boolean): void;
|
|
37
73
|
/**
|
|
38
74
|
* Creates the request.
|
|
@@ -54,5 +90,11 @@ export declare class RequestWrapper {
|
|
|
54
90
|
private static getRaxConfig;
|
|
55
91
|
enableRetries(retryOptions?: RetryOptions): void;
|
|
56
92
|
disableRetries(): void;
|
|
93
|
+
/**
|
|
94
|
+
* Returns true iff the previously-failed request contained in "error" should be retried.
|
|
95
|
+
* @param error - an AxiosError instance that contains a previously-failed request
|
|
96
|
+
* @returns true iff the request should be retried
|
|
97
|
+
*/
|
|
98
|
+
private static retryPolicy;
|
|
57
99
|
private gzipRequestBody;
|
|
58
100
|
}
|
|
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
/**
|
|
12
|
-
* (C) Copyright IBM Corp. 2014,
|
|
12
|
+
* (C) Copyright IBM Corp. 2014, 2024.
|
|
13
13
|
*
|
|
14
14
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
15
15
|
* you may not use this file except in compliance with the License.
|
|
@@ -32,6 +32,7 @@ import isStream from 'isstream';
|
|
|
32
32
|
import { stringify } from 'querystring';
|
|
33
33
|
import { gzipSync } from 'zlib';
|
|
34
34
|
import { buildRequestFileObject, isEmptyObject, isFileData, isFileWithMetadata, isJsonMimeType, stripTrailingSlash, } from './helper';
|
|
35
|
+
import { redactSecrets } from './private-helpers';
|
|
35
36
|
import logger from './logger';
|
|
36
37
|
import { streamToPromise } from './stream-to-promise';
|
|
37
38
|
import { createCookieInterceptor } from './cookie-support';
|
|
@@ -86,28 +87,96 @@ export class RequestWrapper {
|
|
|
86
87
|
}
|
|
87
88
|
this.enableRetries(retryOptions);
|
|
88
89
|
}
|
|
89
|
-
//
|
|
90
|
-
if (process.env.NODE_DEBUG === 'axios'
|
|
91
|
-
this.axiosInstance.interceptors.request.use((
|
|
92
|
-
logger.debug(
|
|
93
|
-
|
|
94
|
-
return config;
|
|
90
|
+
// If debug logging is requested, set up interceptors to log http request/response messages.
|
|
91
|
+
if (logger.debug.enabled || process.env.NODE_DEBUG === 'axios') {
|
|
92
|
+
this.axiosInstance.interceptors.request.use((request) => {
|
|
93
|
+
logger.debug(`--> HTTP Request:\n${this.formatAxiosRequest(request)}`);
|
|
94
|
+
return request;
|
|
95
95
|
}, (error) => {
|
|
96
|
-
logger.
|
|
97
|
-
logger.error(error);
|
|
96
|
+
logger.debug(`<-- HTTP Error:\n${this.formatAxiosError(error)}`);
|
|
98
97
|
return Promise.reject(error);
|
|
99
98
|
});
|
|
100
99
|
this.axiosInstance.interceptors.response.use((response) => {
|
|
101
|
-
logger.debug(
|
|
102
|
-
logger.debug(response);
|
|
100
|
+
logger.debug(`<-- HTTP Response:\n${this.formatAxiosResponse(response)}`);
|
|
103
101
|
return response;
|
|
104
102
|
}, (error) => {
|
|
105
|
-
logger.
|
|
106
|
-
logger.error(error);
|
|
103
|
+
logger.debug(`<-- HTTP Error:\n${this.formatAxiosError(error)}`);
|
|
107
104
|
return Promise.reject(error);
|
|
108
105
|
});
|
|
109
106
|
}
|
|
110
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Formats the specified Axios request for debug logging.
|
|
110
|
+
* @param request - the request to be logged
|
|
111
|
+
* @returns the string representation of the request
|
|
112
|
+
*/
|
|
113
|
+
formatAxiosRequest(request) {
|
|
114
|
+
const { method, url, data, headers } = request;
|
|
115
|
+
const headersOutput = this.formatAxiosHeaders(headers);
|
|
116
|
+
const body = this.formatAxiosBody(data);
|
|
117
|
+
const output = `${(method || '??').toUpperCase()} ${url || '??'}\n${headersOutput}\n${body}`;
|
|
118
|
+
return redactSecrets(output);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Formats the specified Axios response for debug logging.
|
|
122
|
+
* @param response - the response to be logged
|
|
123
|
+
* @returns the string representation of the response
|
|
124
|
+
*/
|
|
125
|
+
formatAxiosResponse(response) {
|
|
126
|
+
const { status, statusText, headers, data } = response;
|
|
127
|
+
const headersOutput = this.formatAxiosHeaders(headers);
|
|
128
|
+
const body = this.formatAxiosBody(data);
|
|
129
|
+
const statusMsg = statusText || `status_code_${status}`;
|
|
130
|
+
const output = `${status} ${statusMsg}\n${headersOutput}\n${body}`;
|
|
131
|
+
return redactSecrets(output);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Formats the specified Axios error for debug logging.
|
|
135
|
+
* @param error - the error to be logged
|
|
136
|
+
* @returns the string representation of the error
|
|
137
|
+
*/
|
|
138
|
+
formatAxiosError(error) {
|
|
139
|
+
const { response } = error;
|
|
140
|
+
let output = `HTTP error message=${error.message || ''}, code=${error.code || ''}`;
|
|
141
|
+
if (response) {
|
|
142
|
+
output = this.formatAxiosResponse(response);
|
|
143
|
+
}
|
|
144
|
+
return output;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Formats 'headers' to be included in the debug output
|
|
148
|
+
* like this:
|
|
149
|
+
* Accept: application/json
|
|
150
|
+
* Content-Type: application/json
|
|
151
|
+
* My-Header: my-value
|
|
152
|
+
* ...
|
|
153
|
+
* @param headers - the headers associated with an Axios request or response
|
|
154
|
+
* @returns the formatted output to be included in the HTTP message traces
|
|
155
|
+
*/
|
|
156
|
+
formatAxiosHeaders(headers) {
|
|
157
|
+
let output = '';
|
|
158
|
+
if (headers) {
|
|
159
|
+
const lines = [];
|
|
160
|
+
Object.keys(headers).forEach((key) => {
|
|
161
|
+
lines.push(`${key}: ${headers[key]}`);
|
|
162
|
+
});
|
|
163
|
+
output = lines.join('\n');
|
|
164
|
+
}
|
|
165
|
+
return output;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Formats 'body' (either a string or object/array) to be included in the debug output
|
|
169
|
+
*
|
|
170
|
+
* @param body - a string, object or array that contains the request or response body
|
|
171
|
+
* @returns the formatted output to be included in the HTTP message traces
|
|
172
|
+
*/
|
|
173
|
+
formatAxiosBody(body) {
|
|
174
|
+
let output = '';
|
|
175
|
+
if (body) {
|
|
176
|
+
output = typeof body === 'string' ? body : JSON.stringify(body);
|
|
177
|
+
}
|
|
178
|
+
return output;
|
|
179
|
+
}
|
|
111
180
|
setCompressRequestData(setting) {
|
|
112
181
|
this.compressRequestData = setting;
|
|
113
182
|
}
|
|
@@ -293,7 +362,8 @@ export class RequestWrapper {
|
|
|
293
362
|
instance: axiosInstance,
|
|
294
363
|
backoffType: 'exponential',
|
|
295
364
|
checkRetryAfter: true,
|
|
296
|
-
maxRetryDelay: 30 * 1000,
|
|
365
|
+
maxRetryDelay: 30 * 1000,
|
|
366
|
+
shouldRetry: this.retryPolicy,
|
|
297
367
|
};
|
|
298
368
|
if (retryOptions) {
|
|
299
369
|
if (typeof retryOptions.maxRetries === 'number') {
|
|
@@ -314,13 +384,42 @@ export class RequestWrapper {
|
|
|
314
384
|
}
|
|
315
385
|
this.raxConfig = RequestWrapper.getRaxConfig(this.axiosInstance, retryOptions);
|
|
316
386
|
this.retryInterceptorId = rax.attach(this.axiosInstance);
|
|
387
|
+
logger.debug(`Enabled retries; maxRetries=${this.raxConfig.retry}, maxRetryInterval=${this.raxConfig.maxRetryDelay}`);
|
|
317
388
|
}
|
|
318
389
|
disableRetries() {
|
|
319
390
|
if (typeof this.retryInterceptorId === 'number') {
|
|
320
391
|
rax.detach(this.retryInterceptorId, this.axiosInstance);
|
|
321
392
|
delete this.retryInterceptorId;
|
|
322
393
|
delete this.raxConfig;
|
|
394
|
+
logger.debug('Disabled retries');
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Returns true iff the previously-failed request contained in "error" should be retried.
|
|
399
|
+
* @param error - an AxiosError instance that contains a previously-failed request
|
|
400
|
+
* @returns true iff the request should be retried
|
|
401
|
+
*/
|
|
402
|
+
static retryPolicy(error) {
|
|
403
|
+
if (logger.debug.enabled) {
|
|
404
|
+
const details = [];
|
|
405
|
+
if (error.response) {
|
|
406
|
+
const statusText = error.response.statusText || ``;
|
|
407
|
+
details.push(`status_code=${error.response.status} (${statusText})`);
|
|
408
|
+
}
|
|
409
|
+
if (error.config) {
|
|
410
|
+
if (error.config.method) {
|
|
411
|
+
details.push(`method=${error.config.method.toUpperCase()}`);
|
|
412
|
+
}
|
|
413
|
+
if (error.config.url) {
|
|
414
|
+
details.push(`url=${error.config.url}`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
logger.debug(`Considering retry attempt; ${details.join(', ')}`);
|
|
323
418
|
}
|
|
419
|
+
// Delegate to the default function defined by retry-axios.
|
|
420
|
+
const shouldRetry = rax.shouldRetryRequest(error);
|
|
421
|
+
logger.debug(`Retry will ${shouldRetry ? '' : 'not '}be attempted`);
|
|
422
|
+
return shouldRetry;
|
|
324
423
|
}
|
|
325
424
|
gzipRequestBody(data, headers) {
|
|
326
425
|
return __awaiter(this, void 0, void 0, function* () {
|
package/ibm-cloud-sdk-core.d.ts
CHANGED
|
@@ -1230,6 +1230,42 @@ declare class RequestWrapper {
|
|
|
1230
1230
|
private retryInterceptorId;
|
|
1231
1231
|
private raxConfig;
|
|
1232
1232
|
constructor(axiosOptions?: any);
|
|
1233
|
+
/**
|
|
1234
|
+
* Formats the specified Axios request for debug logging.
|
|
1235
|
+
* @param request - the request to be logged
|
|
1236
|
+
* @returns the string representation of the request
|
|
1237
|
+
*/
|
|
1238
|
+
private formatAxiosRequest;
|
|
1239
|
+
/**
|
|
1240
|
+
* Formats the specified Axios response for debug logging.
|
|
1241
|
+
* @param response - the response to be logged
|
|
1242
|
+
* @returns the string representation of the response
|
|
1243
|
+
*/
|
|
1244
|
+
private formatAxiosResponse;
|
|
1245
|
+
/**
|
|
1246
|
+
* Formats the specified Axios error for debug logging.
|
|
1247
|
+
* @param error - the error to be logged
|
|
1248
|
+
* @returns the string representation of the error
|
|
1249
|
+
*/
|
|
1250
|
+
private formatAxiosError;
|
|
1251
|
+
/**
|
|
1252
|
+
* Formats 'headers' to be included in the debug output
|
|
1253
|
+
* like this:
|
|
1254
|
+
* Accept: application/json
|
|
1255
|
+
* Content-Type: application/json
|
|
1256
|
+
* My-Header: my-value
|
|
1257
|
+
* ...
|
|
1258
|
+
* @param headers - the headers associated with an Axios request or response
|
|
1259
|
+
* @returns the formatted output to be included in the HTTP message traces
|
|
1260
|
+
*/
|
|
1261
|
+
private formatAxiosHeaders;
|
|
1262
|
+
/**
|
|
1263
|
+
* Formats 'body' (either a string or object/array) to be included in the debug output
|
|
1264
|
+
*
|
|
1265
|
+
* @param body - a string, object or array that contains the request or response body
|
|
1266
|
+
* @returns the formatted output to be included in the HTTP message traces
|
|
1267
|
+
*/
|
|
1268
|
+
private formatAxiosBody;
|
|
1233
1269
|
setCompressRequestData(setting: boolean): void;
|
|
1234
1270
|
/**
|
|
1235
1271
|
* Creates the request.
|
|
@@ -1251,6 +1287,12 @@ declare class RequestWrapper {
|
|
|
1251
1287
|
private static getRaxConfig;
|
|
1252
1288
|
enableRetries(retryOptions?: RetryOptions): void;
|
|
1253
1289
|
disableRetries(): void;
|
|
1290
|
+
/**
|
|
1291
|
+
* Returns true iff the previously-failed request contained in "error" should be retried.
|
|
1292
|
+
* @param error - an AxiosError instance that contains a previously-failed request
|
|
1293
|
+
* @returns true iff the request should be retried
|
|
1294
|
+
*/
|
|
1295
|
+
private static retryPolicy;
|
|
1254
1296
|
private gzipRequestBody;
|
|
1255
1297
|
}
|
|
1256
1298
|
|
package/lib/base-service.js
CHANGED
|
@@ -107,6 +107,7 @@ var BaseService = /** @class */ (function () {
|
|
|
107
107
|
BaseService.prototype.setServiceUrl = function (url) {
|
|
108
108
|
if (url) {
|
|
109
109
|
this.baseOptions.serviceUrl = (0, helper_1.stripTrailingSlash)(url);
|
|
110
|
+
logger_1.default.debug("Set service URL: ".concat(this.baseOptions.serviceUrl));
|
|
110
111
|
}
|
|
111
112
|
};
|
|
112
113
|
/**
|
|
@@ -181,6 +182,7 @@ var BaseService = /** @class */ (function () {
|
|
|
181
182
|
* configuration.
|
|
182
183
|
*/
|
|
183
184
|
BaseService.prototype.configureService = function (serviceName) {
|
|
185
|
+
logger_1.default.debug("Configuring BaseService instance with service name: ".concat(serviceName));
|
|
184
186
|
if (!serviceName) {
|
|
185
187
|
var err = 'Error configuring service. Service name is required.';
|
|
186
188
|
logger_1.default.error(err);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* (C) Copyright IBM Corp. 2024.
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Redacts secrets found in "input" so that the resulting string
|
|
18
|
+
* is suitable for debug logging.
|
|
19
|
+
* @param input - the string that potentially contains secrets
|
|
20
|
+
* @returns the input string with secrets replaced with "[redacted]"
|
|
21
|
+
*/
|
|
22
|
+
export declare function redactSecrets(input: string): string;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* (C) Copyright IBM Corp. 2024.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.redactSecrets = void 0;
|
|
19
|
+
// Keywords that should be redacted.
|
|
20
|
+
var redactedKeywords = [
|
|
21
|
+
'apikey',
|
|
22
|
+
'api_key',
|
|
23
|
+
'passcode',
|
|
24
|
+
'password',
|
|
25
|
+
'token',
|
|
26
|
+
'aadClientId',
|
|
27
|
+
'aadClientSecret',
|
|
28
|
+
'auth',
|
|
29
|
+
'auth_provider_x509_cert_url',
|
|
30
|
+
'auth_uri',
|
|
31
|
+
'client_email',
|
|
32
|
+
'client_id',
|
|
33
|
+
'client_x509_cert_url',
|
|
34
|
+
'key',
|
|
35
|
+
'project_id',
|
|
36
|
+
'secret',
|
|
37
|
+
'subscriptionId',
|
|
38
|
+
'tenantId',
|
|
39
|
+
'thumbprint',
|
|
40
|
+
'token_uri',
|
|
41
|
+
];
|
|
42
|
+
var redactedTokens = redactedKeywords.join('|');
|
|
43
|
+
// Pre-compiled regular expressions used by redactSecrets().
|
|
44
|
+
var reAuthHeader = new RegExp("^(Authorization|X-Auth\\S*): .*$", 'gim');
|
|
45
|
+
var rePropertySetting = new RegExp("(".concat(redactedTokens, ")=[^&]*(&|$)"), 'gi');
|
|
46
|
+
var reJsonField = new RegExp("\"([^\"]*(".concat(redactedTokens, ")[^\"_]*)\":\\s*\"[^\\,]*\""), 'gi');
|
|
47
|
+
// RedactSecrets() returns the input string with secrets redacted.
|
|
48
|
+
/**
|
|
49
|
+
* Redacts secrets found in "input" so that the resulting string
|
|
50
|
+
* is suitable for debug logging.
|
|
51
|
+
* @param input - the string that potentially contains secrets
|
|
52
|
+
* @returns the input string with secrets replaced with "[redacted]"
|
|
53
|
+
*/
|
|
54
|
+
function redactSecrets(input) {
|
|
55
|
+
var redacted = '[redacted]';
|
|
56
|
+
var redactedString = input;
|
|
57
|
+
redactedString = redactedString.replace(reAuthHeader, "$1: ".concat(redacted));
|
|
58
|
+
redactedString = redactedString.replace(rePropertySetting, "$1=".concat(redacted, "$2"));
|
|
59
|
+
redactedString = redactedString.replace(reJsonField, "\"$1\":\"".concat(redacted, "\""));
|
|
60
|
+
return redactedString;
|
|
61
|
+
}
|
|
62
|
+
exports.redactSecrets = redactSecrets;
|
package/lib/request-wrapper.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* (C) Copyright IBM Corp. 2014,
|
|
2
|
+
* (C) Copyright IBM Corp. 2014, 2024.
|
|
3
3
|
*
|
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
5
|
* you may not use this file except in compliance with the License.
|
|
@@ -33,6 +33,42 @@ export declare class RequestWrapper {
|
|
|
33
33
|
private retryInterceptorId;
|
|
34
34
|
private raxConfig;
|
|
35
35
|
constructor(axiosOptions?: any);
|
|
36
|
+
/**
|
|
37
|
+
* Formats the specified Axios request for debug logging.
|
|
38
|
+
* @param request - the request to be logged
|
|
39
|
+
* @returns the string representation of the request
|
|
40
|
+
*/
|
|
41
|
+
private formatAxiosRequest;
|
|
42
|
+
/**
|
|
43
|
+
* Formats the specified Axios response for debug logging.
|
|
44
|
+
* @param response - the response to be logged
|
|
45
|
+
* @returns the string representation of the response
|
|
46
|
+
*/
|
|
47
|
+
private formatAxiosResponse;
|
|
48
|
+
/**
|
|
49
|
+
* Formats the specified Axios error for debug logging.
|
|
50
|
+
* @param error - the error to be logged
|
|
51
|
+
* @returns the string representation of the error
|
|
52
|
+
*/
|
|
53
|
+
private formatAxiosError;
|
|
54
|
+
/**
|
|
55
|
+
* Formats 'headers' to be included in the debug output
|
|
56
|
+
* like this:
|
|
57
|
+
* Accept: application/json
|
|
58
|
+
* Content-Type: application/json
|
|
59
|
+
* My-Header: my-value
|
|
60
|
+
* ...
|
|
61
|
+
* @param headers - the headers associated with an Axios request or response
|
|
62
|
+
* @returns the formatted output to be included in the HTTP message traces
|
|
63
|
+
*/
|
|
64
|
+
private formatAxiosHeaders;
|
|
65
|
+
/**
|
|
66
|
+
* Formats 'body' (either a string or object/array) to be included in the debug output
|
|
67
|
+
*
|
|
68
|
+
* @param body - a string, object or array that contains the request or response body
|
|
69
|
+
* @returns the formatted output to be included in the HTTP message traces
|
|
70
|
+
*/
|
|
71
|
+
private formatAxiosBody;
|
|
36
72
|
setCompressRequestData(setting: boolean): void;
|
|
37
73
|
/**
|
|
38
74
|
* Creates the request.
|
|
@@ -54,5 +90,11 @@ export declare class RequestWrapper {
|
|
|
54
90
|
private static getRaxConfig;
|
|
55
91
|
enableRetries(retryOptions?: RetryOptions): void;
|
|
56
92
|
disableRetries(): void;
|
|
93
|
+
/**
|
|
94
|
+
* Returns true iff the previously-failed request contained in "error" should be retried.
|
|
95
|
+
* @param error - an AxiosError instance that contains a previously-failed request
|
|
96
|
+
* @returns true iff the request should be retried
|
|
97
|
+
*/
|
|
98
|
+
private static retryPolicy;
|
|
57
99
|
private gzipRequestBody;
|
|
58
100
|
}
|
package/lib/request-wrapper.js
CHANGED
|
@@ -76,7 +76,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
76
76
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
77
77
|
exports.RequestWrapper = void 0;
|
|
78
78
|
/**
|
|
79
|
-
* (C) Copyright IBM Corp. 2014,
|
|
79
|
+
* (C) Copyright IBM Corp. 2014, 2024.
|
|
80
80
|
*
|
|
81
81
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
82
82
|
* you may not use this file except in compliance with the License.
|
|
@@ -99,6 +99,7 @@ var isstream_1 = __importDefault(require("isstream"));
|
|
|
99
99
|
var querystring_1 = require("querystring");
|
|
100
100
|
var zlib_1 = require("zlib");
|
|
101
101
|
var helper_1 = require("./helper");
|
|
102
|
+
var private_helpers_1 = require("./private-helpers");
|
|
102
103
|
var logger_1 = __importDefault(require("./logger"));
|
|
103
104
|
var stream_to_promise_1 = require("./stream-to-promise");
|
|
104
105
|
var cookie_support_1 = require("./cookie-support");
|
|
@@ -154,28 +155,96 @@ var RequestWrapper = /** @class */ (function () {
|
|
|
154
155
|
}
|
|
155
156
|
this.enableRetries(retryOptions);
|
|
156
157
|
}
|
|
157
|
-
//
|
|
158
|
-
if (process.env.NODE_DEBUG === 'axios'
|
|
159
|
-
this.axiosInstance.interceptors.request.use(function (
|
|
160
|
-
logger_1.default.debug(
|
|
161
|
-
|
|
162
|
-
return config;
|
|
158
|
+
// If debug logging is requested, set up interceptors to log http request/response messages.
|
|
159
|
+
if (logger_1.default.debug.enabled || process.env.NODE_DEBUG === 'axios') {
|
|
160
|
+
this.axiosInstance.interceptors.request.use(function (request) {
|
|
161
|
+
logger_1.default.debug("--> HTTP Request:\n".concat(_this.formatAxiosRequest(request)));
|
|
162
|
+
return request;
|
|
163
163
|
}, function (error) {
|
|
164
|
-
logger_1.default.
|
|
165
|
-
logger_1.default.error(error);
|
|
164
|
+
logger_1.default.debug("<-- HTTP Error:\n".concat(_this.formatAxiosError(error)));
|
|
166
165
|
return Promise.reject(error);
|
|
167
166
|
});
|
|
168
167
|
this.axiosInstance.interceptors.response.use(function (response) {
|
|
169
|
-
logger_1.default.debug(
|
|
170
|
-
logger_1.default.debug(response);
|
|
168
|
+
logger_1.default.debug("<-- HTTP Response:\n".concat(_this.formatAxiosResponse(response)));
|
|
171
169
|
return response;
|
|
172
170
|
}, function (error) {
|
|
173
|
-
logger_1.default.
|
|
174
|
-
logger_1.default.error(error);
|
|
171
|
+
logger_1.default.debug("<-- HTTP Error:\n".concat(_this.formatAxiosError(error)));
|
|
175
172
|
return Promise.reject(error);
|
|
176
173
|
});
|
|
177
174
|
}
|
|
178
175
|
}
|
|
176
|
+
/**
|
|
177
|
+
* Formats the specified Axios request for debug logging.
|
|
178
|
+
* @param request - the request to be logged
|
|
179
|
+
* @returns the string representation of the request
|
|
180
|
+
*/
|
|
181
|
+
RequestWrapper.prototype.formatAxiosRequest = function (request) {
|
|
182
|
+
var method = request.method, url = request.url, data = request.data, headers = request.headers;
|
|
183
|
+
var headersOutput = this.formatAxiosHeaders(headers);
|
|
184
|
+
var body = this.formatAxiosBody(data);
|
|
185
|
+
var output = "".concat((method || '??').toUpperCase(), " ").concat(url || '??', "\n").concat(headersOutput, "\n").concat(body);
|
|
186
|
+
return (0, private_helpers_1.redactSecrets)(output);
|
|
187
|
+
};
|
|
188
|
+
/**
|
|
189
|
+
* Formats the specified Axios response for debug logging.
|
|
190
|
+
* @param response - the response to be logged
|
|
191
|
+
* @returns the string representation of the response
|
|
192
|
+
*/
|
|
193
|
+
RequestWrapper.prototype.formatAxiosResponse = function (response) {
|
|
194
|
+
var status = response.status, statusText = response.statusText, headers = response.headers, data = response.data;
|
|
195
|
+
var headersOutput = this.formatAxiosHeaders(headers);
|
|
196
|
+
var body = this.formatAxiosBody(data);
|
|
197
|
+
var statusMsg = statusText || "status_code_".concat(status);
|
|
198
|
+
var output = "".concat(status, " ").concat(statusMsg, "\n").concat(headersOutput, "\n").concat(body);
|
|
199
|
+
return (0, private_helpers_1.redactSecrets)(output);
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* Formats the specified Axios error for debug logging.
|
|
203
|
+
* @param error - the error to be logged
|
|
204
|
+
* @returns the string representation of the error
|
|
205
|
+
*/
|
|
206
|
+
RequestWrapper.prototype.formatAxiosError = function (error) {
|
|
207
|
+
var response = error.response;
|
|
208
|
+
var output = "HTTP error message=".concat(error.message || '', ", code=").concat(error.code || '');
|
|
209
|
+
if (response) {
|
|
210
|
+
output = this.formatAxiosResponse(response);
|
|
211
|
+
}
|
|
212
|
+
return output;
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Formats 'headers' to be included in the debug output
|
|
216
|
+
* like this:
|
|
217
|
+
* Accept: application/json
|
|
218
|
+
* Content-Type: application/json
|
|
219
|
+
* My-Header: my-value
|
|
220
|
+
* ...
|
|
221
|
+
* @param headers - the headers associated with an Axios request or response
|
|
222
|
+
* @returns the formatted output to be included in the HTTP message traces
|
|
223
|
+
*/
|
|
224
|
+
RequestWrapper.prototype.formatAxiosHeaders = function (headers) {
|
|
225
|
+
var output = '';
|
|
226
|
+
if (headers) {
|
|
227
|
+
var lines_1 = [];
|
|
228
|
+
Object.keys(headers).forEach(function (key) {
|
|
229
|
+
lines_1.push("".concat(key, ": ").concat(headers[key]));
|
|
230
|
+
});
|
|
231
|
+
output = lines_1.join('\n');
|
|
232
|
+
}
|
|
233
|
+
return output;
|
|
234
|
+
};
|
|
235
|
+
/**
|
|
236
|
+
* Formats 'body' (either a string or object/array) to be included in the debug output
|
|
237
|
+
*
|
|
238
|
+
* @param body - a string, object or array that contains the request or response body
|
|
239
|
+
* @returns the formatted output to be included in the HTTP message traces
|
|
240
|
+
*/
|
|
241
|
+
RequestWrapper.prototype.formatAxiosBody = function (body) {
|
|
242
|
+
var output = '';
|
|
243
|
+
if (body) {
|
|
244
|
+
output = typeof body === 'string' ? body : JSON.stringify(body);
|
|
245
|
+
}
|
|
246
|
+
return output;
|
|
247
|
+
};
|
|
179
248
|
RequestWrapper.prototype.setCompressRequestData = function (setting) {
|
|
180
249
|
this.compressRequestData = setting;
|
|
181
250
|
};
|
|
@@ -381,7 +450,8 @@ var RequestWrapper = /** @class */ (function () {
|
|
|
381
450
|
instance: axiosInstance,
|
|
382
451
|
backoffType: 'exponential',
|
|
383
452
|
checkRetryAfter: true,
|
|
384
|
-
maxRetryDelay: 30 * 1000,
|
|
453
|
+
maxRetryDelay: 30 * 1000,
|
|
454
|
+
shouldRetry: this.retryPolicy,
|
|
385
455
|
};
|
|
386
456
|
if (retryOptions) {
|
|
387
457
|
if (typeof retryOptions.maxRetries === 'number') {
|
|
@@ -402,13 +472,42 @@ var RequestWrapper = /** @class */ (function () {
|
|
|
402
472
|
}
|
|
403
473
|
this.raxConfig = RequestWrapper.getRaxConfig(this.axiosInstance, retryOptions);
|
|
404
474
|
this.retryInterceptorId = rax.attach(this.axiosInstance);
|
|
475
|
+
logger_1.default.debug("Enabled retries; maxRetries=".concat(this.raxConfig.retry, ", maxRetryInterval=").concat(this.raxConfig.maxRetryDelay));
|
|
405
476
|
};
|
|
406
477
|
RequestWrapper.prototype.disableRetries = function () {
|
|
407
478
|
if (typeof this.retryInterceptorId === 'number') {
|
|
408
479
|
rax.detach(this.retryInterceptorId, this.axiosInstance);
|
|
409
480
|
delete this.retryInterceptorId;
|
|
410
481
|
delete this.raxConfig;
|
|
482
|
+
logger_1.default.debug('Disabled retries');
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
/**
|
|
486
|
+
* Returns true iff the previously-failed request contained in "error" should be retried.
|
|
487
|
+
* @param error - an AxiosError instance that contains a previously-failed request
|
|
488
|
+
* @returns true iff the request should be retried
|
|
489
|
+
*/
|
|
490
|
+
RequestWrapper.retryPolicy = function (error) {
|
|
491
|
+
if (logger_1.default.debug.enabled) {
|
|
492
|
+
var details = [];
|
|
493
|
+
if (error.response) {
|
|
494
|
+
var statusText = error.response.statusText || "";
|
|
495
|
+
details.push("status_code=".concat(error.response.status, " (").concat(statusText, ")"));
|
|
496
|
+
}
|
|
497
|
+
if (error.config) {
|
|
498
|
+
if (error.config.method) {
|
|
499
|
+
details.push("method=".concat(error.config.method.toUpperCase()));
|
|
500
|
+
}
|
|
501
|
+
if (error.config.url) {
|
|
502
|
+
details.push("url=".concat(error.config.url));
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
logger_1.default.debug("Considering retry attempt; ".concat(details.join(', ')));
|
|
411
506
|
}
|
|
507
|
+
// Delegate to the default function defined by retry-axios.
|
|
508
|
+
var shouldRetry = rax.shouldRetryRequest(error);
|
|
509
|
+
logger_1.default.debug("Retry will ".concat(shouldRetry ? '' : 'not ', "be attempted"));
|
|
510
|
+
return shouldRetry;
|
|
412
511
|
};
|
|
413
512
|
RequestWrapper.prototype.gzipRequestBody = function (data, headers) {
|
|
414
513
|
return __awaiter(this, void 0, void 0, function () {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ibm-cloud-sdk-core",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2",
|
|
4
4
|
"description": "Core functionality to support SDKs generated with IBM's OpenAPI SDK Generator.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "./es/index.d.ts",
|
|
@@ -51,7 +51,8 @@
|
|
|
51
51
|
"tough-cookie": "^4.1.3"
|
|
52
52
|
},
|
|
53
53
|
"overrides": {
|
|
54
|
-
"semver": "^7.5.3"
|
|
54
|
+
"semver": "^7.5.3",
|
|
55
|
+
"micromatch": "4.0.8"
|
|
55
56
|
},
|
|
56
57
|
"browser": {
|
|
57
58
|
"./auth/utils/read-credentials-file": "./auth/utils/read-credentials-file.browser"
|
|
@@ -60,7 +61,7 @@
|
|
|
60
61
|
"node": ">=18"
|
|
61
62
|
},
|
|
62
63
|
"scripts": {
|
|
63
|
-
"clean": "rm -fr node_modules",
|
|
64
|
+
"clean": "rm -fr node_modules sdk-test-utilities/node_modules",
|
|
64
65
|
"commitmsg": "commitlint -E GIT_PARAMS",
|
|
65
66
|
"eslint:config": "eslint --print-config .eslintrc.js | eslint-config-prettier-check",
|
|
66
67
|
"eslint:fix": "eslint . --fix",
|