@mablhq/mabl-cli 1.13.14 → 1.13.21

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.
@@ -28,9 +28,13 @@ const httpUtil_1 = require("../util/httpUtil");
28
28
  const axios_1 = __importDefault(require("axios"));
29
29
  const os = __importStar(require("os"));
30
30
  const async_retry_1 = __importDefault(require("async-retry"));
31
+ const logUtils_1 = require("../util/logUtils");
31
32
  const asyncUtil_1 = require("../util/asyncUtil");
32
33
  const MABL_ENTITY_VERSION_HEADER = 'x-mabl-entity-version';
33
- const DEFAULT_MAX_TOTAL_RETRY_TIME_MILLISECONDS = 300000;
34
+ const DEFAULT_RETRYABLE_REQUEST_TIMEOUT_MILLISECONDS = 60000;
35
+ const DEFAULT_NONRETRYABLE_REQUEST_TIMEOUT_MILLISECONDS = 600000;
36
+ const DEFAULT_RETRIES = 5;
37
+ const DEFAULT_MAX_TOTAL_RETRY_TIME_MILLISECONDS = DEFAULT_RETRYABLE_REQUEST_TIMEOUT_MILLISECONDS * DEFAULT_RETRIES;
34
38
  const DEFAULT_MIN_RETRY_TIMEOUT_MILLISECONDS = 100;
35
39
  const DEFAULT_MAX_RETRY_TIMEOUT_MILLISECONDS = 1000;
36
40
  var AuthType;
@@ -40,10 +44,12 @@ var AuthType;
40
44
  })(AuthType = exports.AuthType || (exports.AuthType = {}));
41
45
  class BasicApiClient {
42
46
  constructor(options) {
47
+ var _a, _b;
43
48
  const config = httpUtil_1.axiosProxyConfig({
44
49
  sslVerify: options.sslVerify,
45
50
  proxyHost: options.proxyUrl,
46
51
  });
52
+ config.timeout = (_a = options.requestTimeoutMillis) !== null && _a !== void 0 ? _a : DEFAULT_RETRYABLE_REQUEST_TIMEOUT_MILLISECONDS;
47
53
  switch (options.authType) {
48
54
  case AuthType.ApiKey:
49
55
  config.auth = {
@@ -68,23 +74,33 @@ class BasicApiClient {
68
74
  if (options.userAgentOverride) {
69
75
  config.headers[httpUtil_1.USER_AGENT_HEADER] = options.userAgentOverride;
70
76
  }
77
+ this.httpRequestConfig = config;
71
78
  this.httpClient = axios_1.default.create(config);
72
79
  this.retryConfig = options.retryConfig;
80
+ this.debugLogger = (_b = options.debugLogger) !== null && _b !== void 0 ? _b : logUtils_1.logInternal;
73
81
  }
74
- async makeGetRequest(path) {
75
- return this.retryWrappedRequest(async () => this.getRequest(path));
82
+ getNonRetryableRequestConfig(override) {
83
+ const overrideWithTimeout = { ...(override !== null && override !== void 0 ? override : {}) };
84
+ if (!overrideWithTimeout.timeout) {
85
+ overrideWithTimeout.timeout =
86
+ DEFAULT_NONRETRYABLE_REQUEST_TIMEOUT_MILLISECONDS;
87
+ }
88
+ return { ...this.httpRequestConfig, ...overrideWithTimeout };
89
+ }
90
+ makeGetRequest(path) {
91
+ return this.retryWrappedRequest(`makeGetRequest('${path}')`, () => this.getRequest(path));
76
92
  }
77
93
  async getRequest(path) {
78
- const response = await this.httpClient.get(path);
94
+ const response = await this.debugRequest('GET', path, () => this.httpClient.get(path));
79
95
  BasicApiClient.checkResponseStatusCode(response);
80
96
  return response.data;
81
97
  }
82
- async makeGetRequestWithETag(path) {
83
- return this.retryWrappedRequest(async () => this.getRequestWithETag(path));
98
+ makeGetRequestWithETag(path) {
99
+ return this.retryWrappedRequest(`makeGetRequestWithETag('${path}')`, () => this.getRequestWithETag(path));
84
100
  }
85
101
  async getRequestWithETag(path) {
86
102
  var _a;
87
- const response = await this.httpClient.get(path);
103
+ const response = await this.debugRequest('GET', path, () => this.httpClient.get(path));
88
104
  BasicApiClient.checkResponseStatusCode(response);
89
105
  const headers = response.headers;
90
106
  const result = response.data;
@@ -95,42 +111,63 @@ class BasicApiClient {
95
111
  return { ...result, entity_version: versionHeader };
96
112
  }
97
113
  async makePostRequest(path, requestBody, requestConfig) {
98
- const response = await this.httpClient.post(path, requestBody, requestConfig);
114
+ const response = await this.debugRequest('POST', path, () => this.httpClient.post(path, requestBody, this.getNonRetryableRequestConfig(requestConfig)));
99
115
  BasicApiClient.checkResponseStatusCode(response);
100
116
  return response.data;
101
117
  }
102
118
  async makePutRequest(path, requestBody) {
103
- const response = await this.httpClient.put(path, requestBody);
119
+ const response = await this.debugRequest('PUT', path, () => this.httpClient.put(path, requestBody, this.getNonRetryableRequestConfig()));
104
120
  BasicApiClient.checkResponseStatusCode(response);
105
121
  return response.data;
106
122
  }
107
- async makeDeleteRequest(path) {
108
- return this.retryWrappedRequest(async () => this.deleteRequest(path));
123
+ makeDeleteRequest(path) {
124
+ return this.retryWrappedRequest(`makeDeleteRequest('${path}')`, () => this.deleteRequest(path));
109
125
  }
110
126
  async deleteRequest(path) {
111
- const response = await this.httpClient.delete(path);
127
+ const response = await this.debugRequest('DELETE', path, () => this.deleteRequest(path));
112
128
  BasicApiClient.checkResponseStatusCode(response);
113
129
  return response.data;
114
130
  }
115
131
  async makePatchRequest(path, requestBody, ifMatch) {
116
132
  const extraConfig = ifMatch ? { headers: { 'If-Match': ifMatch } } : {};
117
- const response = await this.httpClient.patch(path, requestBody, extraConfig);
133
+ const response = await this.debugRequest('PATCH', path, () => this.httpClient.patch(path, requestBody, extraConfig));
118
134
  BasicApiClient.checkResponseStatusCode(response);
119
135
  return response.data;
120
136
  }
137
+ async debugRequest(method, path, request) {
138
+ const startTimeMillis = Date.now();
139
+ let responseCode;
140
+ let error;
141
+ try {
142
+ this.debugLogger(`API Client: Sending ${method} ${path}`);
143
+ const response = await request();
144
+ responseCode = response.status;
145
+ return response;
146
+ }
147
+ catch (e) {
148
+ error = e;
149
+ throw e;
150
+ }
151
+ finally {
152
+ this.debugLogger(`API Client: ${method} ${path} ${error ? 'failed' : 'completed'} in ${Date.now() - startTimeMillis}ms with ${responseCode !== null && responseCode !== void 0 ? responseCode : error}`);
153
+ }
154
+ }
121
155
  static checkResponseStatusCode(response) {
122
156
  const statusCode = response.status;
123
157
  if (!statusCode || statusCode >= 400) {
124
158
  throw new ApiError_1.ApiError(`[${statusCode} - ${response.statusText}]`, statusCode);
125
159
  }
126
160
  }
127
- retryWrappedRequest(requestFunc) {
161
+ retryWrappedRequest(description, requestFunc) {
128
162
  var _a, _b, _c, _d, _e, _f, _g, _h;
129
163
  const retryOptions = {
130
- retries: (_b = (_a = this.retryConfig) === null || _a === void 0 ? void 0 : _a.retryCount) !== null && _b !== void 0 ? _b : 0,
164
+ retries: (_b = (_a = this.retryConfig) === null || _a === void 0 ? void 0 : _a.retryCount) !== null && _b !== void 0 ? _b : DEFAULT_RETRIES,
131
165
  minTimeout: (_d = (_c = this.retryConfig) === null || _c === void 0 ? void 0 : _c.minTimeoutMillis) !== null && _d !== void 0 ? _d : DEFAULT_MIN_RETRY_TIMEOUT_MILLISECONDS,
132
166
  maxTimeout: (_f = (_e = this.retryConfig) === null || _e === void 0 ? void 0 : _e.maxTimeoutMillis) !== null && _f !== void 0 ? _f : DEFAULT_MAX_RETRY_TIMEOUT_MILLISECONDS,
133
167
  maxRetryTime: (_h = (_g = this.retryConfig) === null || _g === void 0 ? void 0 : _g.maxRetryTimeMillis) !== null && _h !== void 0 ? _h : DEFAULT_MAX_TOTAL_RETRY_TIME_MILLISECONDS,
168
+ onRetry: (error) => {
169
+ this.debugLogger(`Retrying failed API request "${description}"`, error);
170
+ },
134
171
  forever: false,
135
172
  };
136
173
  return asyncUtil_1.promiseWithTimeout(async_retry_1.default(async (bail) => {
@@ -152,7 +189,7 @@ class BasicApiClient {
152
189
  return {};
153
190
  }
154
191
  }
155
- }, retryOptions), DEFAULT_MAX_TOTAL_RETRY_TIME_MILLISECONDS + 1000, 'Retryable API request');
192
+ }, retryOptions), retryOptions.maxRetryTime + retryOptions.maxTimeout, 'Retryable API request');
156
193
  }
157
194
  }
158
195
  exports.BasicApiClient = BasicApiClient;
@@ -127,7 +127,7 @@ class MablApiClient extends basicApiClient_1.BasicApiClient {
127
127
  }
128
128
  async createDeployment(deployment) {
129
129
  try {
130
- return await this.makePostRequest(`${env_1.BASE_API_URL}/deployments`, deployment);
130
+ return await this.makePostRequest(`${env_1.BASE_API_URL}/deployments`, deployment, { timeout: 0 });
131
131
  }
132
132
  catch (error) {
133
133
  throw toApiError(`Failed to create deployment`, error);
@@ -22,6 +22,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
22
22
  exports.PlaywrightFrame = void 0;
23
23
  const browserLauncher_1 = require("../browserLauncher");
24
24
  const playwright = __importStar(require("@playwright/test"));
25
+ const types_1 = require("../types");
25
26
  const utils_1 = require("../utils");
26
27
  const playwrightHttpResponse_1 = require("./playwrightHttpResponse");
27
28
  const playwrightDom_1 = require("./playwrightDom");
@@ -117,7 +118,16 @@ class PlaywrightFrame extends browserLauncher_1.Frame {
117
118
  }
118
119
  async goto(url, options) {
119
120
  try {
121
+ const waitForNetworkIdle = (options === null || options === void 0 ? void 0 : options.waitUntil) === types_1.LifecycleEvent.NetworkIdle;
122
+ if (options && waitForNetworkIdle) {
123
+ options.waitUntil = types_1.LifecycleEvent.Load;
124
+ }
120
125
  const response = await this.frame.goto(url, options);
126
+ if (waitForNetworkIdle) {
127
+ await this.frame.waitForLoadState('networkidle', {
128
+ timeout: types_1.DefaultTimeouts.quickActionTimeoutMs,
129
+ });
130
+ }
121
131
  return utils_1.mapIfNotNull(response, (response) => new playwrightHttpResponse_1.PlaywrightHttpResponse(this.parentPage, response));
122
132
  }
123
133
  catch (e) {