@carbonorm/carbonreact 2.0.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.
@@ -1,494 +0,0 @@
1
- import axios, {AxiosInstance, AxiosRequestConfig, AxiosRequestHeaders, AxiosResponse} from "axios";
2
- import {isTest, isVerbose} from "@carbonorm/carbonnode";
3
- import CarbonReact from "CarbonReact";
4
- import {iAlert} from "components/Alert/Alert";
5
- import Qs from "qs";
6
-
7
-
8
- import {parseMultipleJson} from "hoc/parseMultipleJson";
9
-
10
- import addValidSQL from "hoc/addValidSQL";
11
-
12
- export function HandleResponseCodes(data: any): void {
13
-
14
- const bootstrap: CarbonReact = CarbonReact.instance;
15
-
16
- if (undefined === data?.data?.alert) {
17
- return;
18
- }
19
-
20
- if (Array.isArray(data.data.alert) === false) {
21
-
22
- throw new Error("data.data.alert is not an array (" + JSON.stringify(data.data.alert) + ")");
23
-
24
- }
25
-
26
- console.log("handleResponseCodes ∈ Bootstrap");
27
-
28
- let stack: Array<iAlert> = data.data.alert;
29
-
30
- if (stack.length === 0) {
31
-
32
- return;
33
-
34
- }
35
-
36
- bootstrap.setState(previousState => {
37
-
38
- previousState.alertsWaiting.push(...stack)
39
-
40
- return {
41
-
42
- alertsWaiting: previousState.alertsWaiting
43
-
44
- }
45
- });
46
-
47
- }
48
- export function setCookies(cookies: string[], req: AxiosResponse | undefined = undefined): void {
49
-
50
- console.log("Setting cookies", cookies);
51
-
52
- cookies.map(cookie => {
53
-
54
- const newCookie = cookie
55
- .replace("HttpOnly", "")
56
- .replace("secure", "");
57
-
58
- if (document === undefined || document === null) {
59
-
60
- const getStackTrace = function () {
61
- let obj: any = {};
62
- Error.captureStackTrace(obj, getStackTrace);
63
- return obj.stack;
64
- };
65
-
66
- console.error(req)
67
-
68
- console.log('Testing error, document not defined', req)
69
-
70
- throw new Error("Document is undefined while trying to set cookie: (" + newCookie + ") in axiosInterceptors.tsx after (" + JSON.stringify([req?.config, req?.data], undefined, 4) + ") Please make sure all requests are wrapped in an act() from import {act} from '@testing-library/react'; (" + JSON.stringify(getStackTrace(), undefined, 4) + ")");
71
-
72
- }
73
-
74
- document.cookie = newCookie
75
-
76
- });
77
-
78
- }
79
-
80
- function axiosInterceptors(axios: AxiosInstance): void {
81
-
82
-
83
- if (isTest) {
84
-
85
- axios.defaults.adapter = require('axios/lib/adapters/http')
86
-
87
- }
88
-
89
- axios.interceptors.request.use(
90
- req => {
91
-
92
- setCookies([
93
- 'github_revision=' + process.env.REACT_APP_GITHUB_REVISION + '; path=/',
94
- ])
95
-
96
- if (isTest) {
97
-
98
- setCookies([
99
- 'dropDeveloper=554378!@#$(K-asSfdsf-fd!@#$439; path=/',
100
- 'XDEBUG_SESSION=start; path=/'
101
- ])
102
-
103
- req.headers ??= ({} as AxiosRequestHeaders)
104
-
105
- req.headers['Cookie'] = document.cookie;
106
-
107
- }
108
-
109
- if (true === isVerbose) {
110
-
111
- console.log(req.method, req.url, req.data)
112
-
113
- const log = {
114
- baseURL: req.baseURL,
115
- url: req.url,
116
- method: req.method,
117
- headers: req.headers,
118
- data: req.data,
119
- params: req.params,
120
- };
121
-
122
- console.groupCollapsed("Every Axios request is logged in axiosInterceptors.tsx :: <" + req.method + ">(" + req.url + ")");
123
-
124
- console.log(log);
125
-
126
- console.groupEnd();
127
-
128
- }
129
-
130
- return req;
131
-
132
- }
133
- );
134
-
135
- function logResponseSetCookiesForTests(response: AxiosResponse | any) {
136
-
137
- // axios sets cookies correctly; just not in jest tests
138
- if (isTest && response?.headers?.['set-cookie']) {
139
-
140
- setCookies(response?.headers?.['set-cookie'], response)
141
-
142
- }
143
-
144
- if (true === isVerbose) {
145
-
146
- if (response?.response) {
147
-
148
- response = response.response;
149
-
150
- }
151
-
152
- // JSON is so it prints completely in intellij run console
153
- if (isTest && isVerbose) {
154
-
155
- console.debug(
156
- "Every Axios response is logged in axiosInterceptors.tsx :: ",
157
- JSON.stringify({
158
- baseURL: response.config.baseURL,
159
- uri: response.config?.url,
160
- status: response?.status,
161
- statusText: response?.statusText,
162
- headers: response?.headers,
163
- data: response?.data,
164
- }, undefined, 4)
165
- );
166
-
167
- }
168
-
169
- }
170
-
171
- }
172
-
173
- axios.interceptors.response.use(
174
- response => {
175
-
176
- logResponseSetCookiesForTests(response);
177
-
178
- if (undefined !== response?.data?.TRACE) {
179
-
180
- if (isTest) {
181
-
182
- throw new Error(JSON.stringify(response.data, undefined, 4))
183
-
184
- }
185
-
186
- CarbonReact.instance.setState((previous) => (
187
- {
188
- backendThrowable: [
189
- ...previous.backendThrowable,
190
- response?.data
191
- ]
192
- }))
193
-
194
- return response;
195
-
196
- }
197
-
198
- if (isTest) {
199
-
200
- if (Array.isArray(response?.data?.sql)) {
201
-
202
- addValidSQL(response.data.sql)
203
-
204
- }
205
-
206
- }
207
-
208
- // DO NOT REMOVE THIS - if an alert annoys you, fix it; it annoys our users too
209
- if (response?.data?.alert) {
210
-
211
- console.log("alert ∈ response");
212
-
213
- HandleResponseCodes(response);
214
-
215
- }
216
-
217
- return response;
218
-
219
- },// @link https://stackoverflow.com/posts/75956421
220
- async error => {
221
-
222
- // @link https://stackoverflow.com/questions/56074531/how-to-retry-5xx-requests-using-axios/75956421#75956421
223
- if (error?.config?.headers?.['X-Retry-Count'] !== undefined) {
224
-
225
- console.log('X-Retry-Count', error?.config?.headers?.['X-Retry-Count'])
226
-
227
- if (false === isTest || true === isVerbose) {
228
-
229
- console.log(error)
230
-
231
- }
232
-
233
- return error;
234
-
235
- }
236
-
237
- logResponseSetCookiesForTests(error);
238
-
239
- error.response ??= {};
240
-
241
- error.response.status ??= 520;
242
-
243
- const shouldRetry = (error) => undefined !== error.config && error?.response?.status >= 500 && error?.response?.status < 600
244
-
245
- const firstRetry = shouldRetry(error)
246
-
247
- if (false === isTest || true === isVerbose) {
248
-
249
- console.group("Retrying request ", error.config?.url ?? error.config);
250
- console.log(error);
251
- console.groupEnd();
252
-
253
- } else if (isTest) {
254
-
255
- console.log('AXIOS ERROR', error.code, error.baseURL, error.config?.url, error.headers, error.data, error.params, error.path, error.response?.status, error.response?.statusText, error.response?.headers, error.response?.data)
256
-
257
- if (false === firstRetry) {
258
-
259
- throw new Error(error?.response?.status + ' ' + JSON.stringify(error?.response?.data, undefined, 4))
260
-
261
- }
262
-
263
- }
264
-
265
- if (false === firstRetry) {
266
-
267
- console.error("Error in axiosInterceptors.tsx (Not attempting retry)", error);
268
-
269
- if (undefined !== error?.response?.data?.TRACE ||
270
- undefined === error?.response?.data?.alert) {
271
-
272
- if (isTest) {
273
-
274
- throw new Error(error?.response.data['CarbonPHP\\Error\\PublicAlert'] ?? error?.response.data['TRACE'] ?? JSON.stringify(error?.response.data, undefined, 4))
275
-
276
- }
277
-
278
- console.log('backend throwable', error?.response?.data || error?.response)
279
-
280
- if (undefined !== error?.response?.data
281
- && Array.isArray(error.response.data)) {
282
-
283
- error.response.data.status = error?.response?.status
284
-
285
- }
286
-
287
- // if string try to see if malformed json
288
- const jsonErrors = parseMultipleJson(error?.response?.data || error?.response || error)
289
-
290
- CarbonReact.instance.setState((previous) => (
291
- {
292
- backendThrowable: [
293
- ...previous.backendThrowable,
294
- ...jsonErrors
295
- ]
296
- }))
297
-
298
-
299
- return Promise.reject(error);
300
-
301
- }
302
-
303
- /* Do something with response error
304
- this changes from project to project depending on how your server uses response codes.
305
- when you can control all errors universally from a single api, return Promise.reject(error);
306
- is the way to go.
307
- */
308
- HandleResponseCodes(error.response);
309
-
310
-
311
- return Promise.reject(error);
312
-
313
- }
314
-
315
- console.warn("Error in axiosInterceptors.tsx - Attempting retry!!!");
316
-
317
- const config: AxiosRequestConfig = error.config
318
-
319
- // @link https://stackoverflow.com/questions/3561381/custom-http-headers-naming-conventions
320
- let retries = parseInt(config.headers?.['X-Retry-Count'] ?? '0');
321
-
322
- const maxRetries = isTest ? 5 : 3;
323
-
324
- // todo - handle retries better
325
- while (retries < maxRetries) {
326
-
327
- config.headers = {
328
- ...config.headers,
329
- 'X-Retry-Count': `${++retries}`
330
- }
331
-
332
- try {
333
-
334
- // @link https://stackoverflow.com/questions/51563821/axios-interceptors-retry-original-request-and-access-original-promise
335
- return axios(config)
336
-
337
- } catch (err) {
338
-
339
- error = err;
340
-
341
- console.log('AXIOS ERROR', error.code, error.baseURL, error.config?.url, error.headers, error.data, error.params, error.path, error.response?.status, error.response?.statusText, error.response?.headers, error.response?.data)
342
-
343
- if (false === shouldRetry(error)) {
344
-
345
- break;
346
-
347
- }
348
-
349
- }
350
-
351
- }
352
-
353
- console.log(`Too many request retries.`);
354
-
355
- return Promise.reject(error);
356
-
357
- });
358
-
359
- }
360
-
361
-
362
-
363
-
364
-
365
- // noinspection SpellCheckingInspection
366
- const axiosInstance = axios.create({
367
-
368
- // `baseURL` will be prepended to `url` unless `url` is absolute.
369
- // It can be convenient to set `baseURL` for an instance of axios to pass relative URLs
370
- // to methods of that instance.
371
- baseURL: '',
372
-
373
- /**
374
- * These headers are important to use here at dig.
375
- * XMLHttpRequest - is a standard header all jquery ajax requests send by default. This allows our php side to return
376
- * nothing while running the get_header() and get_footer() functions with (bool) DropVariables::$ajax;
377
- *
378
- * application/json - is for the error catcher in php; this header will cause a JSON response instead of the default HTML
379
- */
380
- headers: {
381
- 'X-Requested-With': 'XMLHttpRequest',
382
- 'X-Drop-In-Developer': '346991',
383
- 'X-Github-Revision': '5671a0b5d2f37a35098327abbf3ed9518c103b88',
384
- 'Content-Type': 'application/json'
385
- },
386
-
387
-
388
- // `paramsSerializer` is an optional function in charge of serializing `params`
389
- // (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
390
- paramsSerializer: {
391
- encode: function(params) {
392
- // Nested get params [][][,,,] do not serialize correctly without Qs
393
- return Qs.stringify(params, {
394
- arrayFormat: 'indices',
395
- indices: true,
396
- skipNulls: false,
397
- strictNullHandling: true
398
- })
399
- },
400
- },
401
-
402
- // `data` is the data to be sent as the request body
403
- // Only applicable for request methods 'PUT', 'POST', and 'PATCH'
404
- // When no `transformRequest` is set, must be of one of the following types:
405
- // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
406
- // - Browser only: FormData, File, Blob
407
- // - Node only: Stream, Buffer
408
- // data should be default to empty for get request to serialize correctly
409
- data: {}, // do not change
410
-
411
-
412
- // `timeout` specifies the number of milliseconds before the request times out.
413
- // If the request takes longer than `timeout`, the request will be aborted.
414
- // Default is 1000, this will fail for DIG
415
- timeout: 120000, // shit fails
416
-
417
- // `withCredentials` indicates weather cross-site Access-Control requests
418
- // should be made using credentials
419
- withCredentials: false,
420
-
421
- // `adapter` allows custom handling of requests which makes testing easier.
422
- // Return a promise and supply a valid response (see lib/adapters/README.md).
423
- adapter: isTest ? 'http' : 'xhr',
424
-
425
- // `auth` indicates that HTTP Basic auth should be used, and supplies credentials.
426
- // This will set an `Authorization` header, overwriting any existing
427
- // `Authorization` custom headers you have set using `headers`.
428
- /*
429
- auth: {
430
- username: 'janedoe',
431
- password: 's00pers3cret'
432
- },
433
- */
434
- // `responseType` indicates the type of data that the server will respond with
435
- // options are 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
436
- // responseType: 'json', // default
437
-
438
- // `responseEncoding` indicates encoding to use for decoding responses
439
- // Note: Ignored for `responseType` of 'stream' or client-side requests
440
-
441
- // `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
442
- //xsrfCookieName: 'XSRF-TOKEN', // default
443
-
444
- // `xsrfHeaderName` is the name of the http header that carries the xsrf token value
445
- //xsrfHeaderName: 'X-XSRF-TOKEN', // default
446
-
447
- // `onUploadProgress` allows handling of progress events for uploads
448
- onUploadProgress: function () { // progressEvent
449
- // Do whatever you want with the native progress event
450
- },
451
-
452
- // `onDownloadProgress` allows handling of progress events for downloads
453
- onDownloadProgress: function () { // progressEvent
454
- // Do whatever you want with the native progress event
455
- },
456
-
457
- // `maxContentLength` defines the max size of the http response content in bytes allowed
458
- /*maxContentLength: 2000,*/
459
-
460
- // `validateStatus` defines whether to resolve or reject the promise for a given
461
- // HTTP response status code. If `validateStatus` returns `true` (or is set to `null`
462
- // or `undefined`), the promise will be resolved; otherwise, the promise will be
463
- // rejected.
464
- /* validateStatus: function (status) {
465
- return status >= 200 && status < 300;
466
- },*/
467
-
468
- // `maxRedirects` defines the maximum number of redirects to follow in node.js.
469
- // If set to 0, no redirects will be followed.
470
- maxRedirects: 2, // default
471
-
472
- // `socketPath` defines a UNIX Socket to be used in node.js.
473
- // e.g. '/var/run/docker.sock' to send requests to the docker daemon.
474
- // Only either `socketPath` or `proxy` can be specified.
475
- // If both are specified, `socketPath` is used.
476
- socketPath: null, // default
477
-
478
- // `httpAgent` and `httpsAgent` define a custom agent to be used when performing http
479
- // and https requests, respectively, in node.js. This allows options to be added like
480
- // `keepAlive` that are not enabled by default.
481
-
482
- /*
483
- httpAgent: new http.Agent({ keepAlive: true }),
484
- httpsAgent: new https.Agent({ keepAlive: true }),
485
- */
486
-
487
- });
488
-
489
- axiosInterceptors(axiosInstance)
490
-
491
- export default axiosInstance
492
-
493
-
494
-