@devrev/ts-adaas 1.8.0 → 1.8.1-beta.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.
@@ -8,6 +8,7 @@
8
8
  * 1. Network errors (where no response is received).
9
9
  * 2. Idempotent requests (defaults include GET, HEAD, OPTIONS, PUT).
10
10
  * 3. All 5xx server errors.
11
+ * 4. 429 Too Many Requests (respects Retry-After header when present).
11
12
  *
12
13
  * Retry Strategy:
13
14
  * - A maximum of 5 retries are attempted.
@@ -9,6 +9,7 @@
9
9
  * 1. Network errors (where no response is received).
10
10
  * 2. Idempotent requests (defaults include GET, HEAD, OPTIONS, PUT).
11
11
  * 3. All 5xx server errors.
12
+ * 4. 429 Too Many Requests (respects Retry-After header when present).
12
13
  *
13
14
  * Retry Strategy:
14
15
  * - A maximum of 5 retries are attempted.
@@ -35,16 +36,25 @@ exports.axiosClient = axiosClient;
35
36
  (0, axios_retry_1.default)(axiosClient, {
36
37
  retries: 5,
37
38
  retryDelay: (retryCount, error) => {
38
- var _a, _b, _c;
39
- // exponential backoff algorithm: 1 * 2 ^ retryCount * 1000ms
39
+ var _a, _b, _c, _d, _e, _f, _g;
40
+ // Handle 429 by using the Retry-After header
41
+ if (((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 429) {
42
+ const retryAfter = (_b = error.response.headers) === null || _b === void 0 ? void 0 : _b['retry-after'];
43
+ if (retryAfter) {
44
+ const delay = parseInt(retryAfter, 10) * 1000;
45
+ console.warn(`Request to ${(_c = error.config) === null || _c === void 0 ? void 0 : _c.url} failed with 429 Too Many Requests. Method ${(_d = error.config) === null || _d === void 0 ? void 0 : _d.method}. Retry count: ${retryCount}. Retrying after ${Math.round(delay / 1000)}s as specified by Retry-After header.`);
46
+ return delay;
47
+ }
48
+ }
49
+ // Default exponential backoff algorithm: 1 * 2 ^ retryCount * 1000ms
40
50
  const delay = axios_retry_1.default.exponentialDelay(retryCount, error, 1000);
41
- console.warn(`Request to ${(_a = error.config) === null || _a === void 0 ? void 0 : _a.url} failed with response status code ${(_b = error.response) === null || _b === void 0 ? void 0 : _b.status}. Method ${(_c = error.config) === null || _c === void 0 ? void 0 : _c.method}. Retry count: ${retryCount}. Retrying in ${Math.round(delay / 1000)}s.`);
51
+ console.warn(`Request to ${(_e = error.config) === null || _e === void 0 ? void 0 : _e.url} failed with response status code ${(_f = error.response) === null || _f === void 0 ? void 0 : _f.status}. Method ${(_g = error.config) === null || _g === void 0 ? void 0 : _g.method}. Retry count: ${retryCount}. Retrying in ${Math.round(delay / 1000)}s.`);
42
52
  return delay;
43
53
  },
44
54
  retryCondition: (error) => {
45
55
  var _a, _b, _c;
46
- return ((axios_retry_1.default.isNetworkOrIdempotentRequestError(error) &&
47
- ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) !== 429) ||
56
+ return (axios_retry_1.default.isNetworkOrIdempotentRequestError(error) ||
57
+ ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 429 ||
48
58
  ((_c = (_b = error.response) === null || _b === void 0 ? void 0 : _b.status) !== null && _c !== void 0 ? _c : 0) >= 500);
49
59
  },
50
60
  onMaxRetryTimesExceeded(error) {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const axios_retry_1 = __importDefault(require("axios-retry"));
7
+ describe('axios-client', () => {
8
+ describe('429 response', () => {
9
+ it('should identify 429 as retryable', () => {
10
+ var _a, _b, _c;
11
+ const error429 = {
12
+ response: {
13
+ status: 429,
14
+ data: {},
15
+ statusText: 'Too Many Requests',
16
+ headers: {},
17
+ config: {},
18
+ },
19
+ config: { url: '/test', method: 'GET' },
20
+ };
21
+ // Test our retry condition logic directly
22
+ const shouldRetry = axios_retry_1.default.isNetworkOrIdempotentRequestError(error429) ||
23
+ ((_a = error429.response) === null || _a === void 0 ? void 0 : _a.status) === 429 ||
24
+ ((_c = (_b = error429.response) === null || _b === void 0 ? void 0 : _b.status) !== null && _c !== void 0 ? _c : 0) >= 500;
25
+ expect(shouldRetry).toBe(true);
26
+ });
27
+ it('should calculate delay for 429 with Retry-After header', () => {
28
+ var _a, _b;
29
+ const retryAfterSeconds = 5;
30
+ const error429WithRetryAfter = {
31
+ response: {
32
+ status: 429,
33
+ headers: { 'retry-after': retryAfterSeconds.toString() },
34
+ data: {},
35
+ statusText: 'Too Many Requests',
36
+ config: {},
37
+ },
38
+ config: { url: '/test', method: 'GET' },
39
+ };
40
+ // Test delay calculation logic for 429 with Retry-After
41
+ let delay;
42
+ if (((_a = error429WithRetryAfter.response) === null || _a === void 0 ? void 0 : _a.status) === 429) {
43
+ const retryAfter = (_b = error429WithRetryAfter.response.headers) === null || _b === void 0 ? void 0 : _b['retry-after'];
44
+ if (retryAfter) {
45
+ delay = parseInt(retryAfter, 10) * 1000;
46
+ }
47
+ else {
48
+ delay = axios_retry_1.default.exponentialDelay(1, error429WithRetryAfter, 1000);
49
+ }
50
+ }
51
+ else {
52
+ delay = axios_retry_1.default.exponentialDelay(1, error429WithRetryAfter, 1000);
53
+ }
54
+ expect(delay).toBe(retryAfterSeconds * 1000);
55
+ });
56
+ });
57
+ describe('5xx response', () => {
58
+ it('should identify 500 as retryable', () => {
59
+ var _a, _b, _c;
60
+ const error500 = {
61
+ response: {
62
+ status: 500,
63
+ data: {},
64
+ statusText: 'Internal Server Error',
65
+ headers: {},
66
+ config: {},
67
+ },
68
+ config: { url: '/test', method: 'GET' },
69
+ };
70
+ const shouldRetry = axios_retry_1.default.isNetworkOrIdempotentRequestError(error500) ||
71
+ ((_a = error500.response) === null || _a === void 0 ? void 0 : _a.status) === 429 ||
72
+ ((_c = (_b = error500.response) === null || _b === void 0 ? void 0 : _b.status) !== null && _c !== void 0 ? _c : 0) >= 500;
73
+ expect(shouldRetry).toBe(true);
74
+ });
75
+ it('should identify 502 as retryable', () => {
76
+ var _a, _b, _c;
77
+ const error502 = {
78
+ response: {
79
+ status: 502,
80
+ data: {},
81
+ statusText: 'Bad Gateway',
82
+ headers: {},
83
+ config: {},
84
+ },
85
+ config: { url: '/test', method: 'POST' },
86
+ };
87
+ const shouldRetry = axios_retry_1.default.isNetworkOrIdempotentRequestError(error502) ||
88
+ ((_a = error502.response) === null || _a === void 0 ? void 0 : _a.status) === 429 ||
89
+ ((_c = (_b = error502.response) === null || _b === void 0 ? void 0 : _b.status) !== null && _c !== void 0 ? _c : 0) >= 500;
90
+ expect(shouldRetry).toBe(true);
91
+ });
92
+ });
93
+ describe('4xx response', () => {
94
+ it('should NOT retry 400 Bad Request', () => {
95
+ var _a, _b, _c;
96
+ const error400 = {
97
+ response: {
98
+ status: 400,
99
+ data: {},
100
+ statusText: 'Bad Request',
101
+ headers: {},
102
+ config: {},
103
+ },
104
+ config: { url: '/test', method: 'GET' },
105
+ };
106
+ const shouldRetry = axios_retry_1.default.isNetworkOrIdempotentRequestError(error400) ||
107
+ ((_a = error400.response) === null || _a === void 0 ? void 0 : _a.status) === 429 ||
108
+ ((_c = (_b = error400.response) === null || _b === void 0 ? void 0 : _b.status) !== null && _c !== void 0 ? _c : 0) >= 500;
109
+ expect(shouldRetry).toBe(false);
110
+ });
111
+ it('should NOT retry 404 Not Found', () => {
112
+ var _a, _b, _c;
113
+ const error404 = {
114
+ response: {
115
+ status: 404,
116
+ data: {},
117
+ statusText: 'Not Found',
118
+ headers: {},
119
+ config: {},
120
+ },
121
+ config: { url: '/test', method: 'GET' },
122
+ };
123
+ const shouldRetry = axios_retry_1.default.isNetworkOrIdempotentRequestError(error404) ||
124
+ ((_a = error404.response) === null || _a === void 0 ? void 0 : _a.status) === 429 ||
125
+ ((_c = (_b = error404.response) === null || _b === void 0 ? void 0 : _b.status) !== null && _c !== void 0 ? _c : 0) >= 500;
126
+ expect(shouldRetry).toBe(false);
127
+ });
128
+ });
129
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devrev/ts-adaas",
3
- "version": "1.8.0",
3
+ "version": "1.8.1-beta.0",
4
4
  "description": "Typescript library containing the ADaaS(AirDrop as a Service) control protocol.",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/index.js",