repzo 1.0.228 → 1.0.229
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/README.md +34 -0
- package/changelog.md +5 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +59 -28
- package/lib/types/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/index.ts +66 -28
- package/src/types/index.ts +1 -0
package/README.md
CHANGED
|
@@ -26,7 +26,21 @@ npm install repzo
|
|
|
26
26
|
|
|
27
27
|
```typescript
|
|
28
28
|
import Repzo from "repzo";
|
|
29
|
+
|
|
30
|
+
// Basic initialization
|
|
29
31
|
const repzo = new Repzo("my-repzo-api-key");
|
|
32
|
+
|
|
33
|
+
// With options (staging environment, custom timeout, retry logic)
|
|
34
|
+
const repzoWithOptions = new Repzo("my-repzo-api-key", {
|
|
35
|
+
env: "staging", // 'production', 'staging', or 'local'
|
|
36
|
+
timeout: 60000, // Request timeout in milliseconds
|
|
37
|
+
retryAttempts: 3, // Number of retry attempts (default: 3)
|
|
38
|
+
headers: {
|
|
39
|
+
"Custom-Header": "value",
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Find clients
|
|
30
44
|
let clients = repzo.client.find({ search: "Mecca" });
|
|
31
45
|
|
|
32
46
|
// Example usage with type safety
|
|
@@ -39,6 +53,26 @@ const params: Service.Client.Find.Params = {
|
|
|
39
53
|
// Your API implementation here
|
|
40
54
|
```
|
|
41
55
|
|
|
56
|
+
### Retry Logic
|
|
57
|
+
|
|
58
|
+
The SDK includes automatic retry logic for failed requests:
|
|
59
|
+
|
|
60
|
+
- **Default Behavior**: Automatically retries failed requests up to 3 times
|
|
61
|
+
- **Exponential Backoff**: Uses exponential backoff strategy (2^attempt seconds)
|
|
62
|
+
- **401 Protection**: Never retries on 401 (Unauthorized) errors
|
|
63
|
+
- **Configurable**: Set custom retry attempts via `retryAttempts` option
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// Default: 3 retry attempts
|
|
67
|
+
const repzo = new Repzo("api-key");
|
|
68
|
+
|
|
69
|
+
// Custom: 5 retry attempts
|
|
70
|
+
const repzoCustom = new Repzo("api-key", { retryAttempts: 5 });
|
|
71
|
+
|
|
72
|
+
// Disable retries: 1 attempt only
|
|
73
|
+
const repzoNoRetry = new Repzo("api-key", { retryAttempts: 1 });
|
|
74
|
+
```
|
|
75
|
+
|
|
42
76
|
## 📖 Documentation
|
|
43
77
|
|
|
44
78
|
This SDK provides **three levels of documentation**:
|
package/changelog.md
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
### Added
|
|
6
6
|
|
|
7
|
+
- add: Automatic retry logic for HTTP requests with exponential backoff (default: 3 attempts, configurable via `retryAttempts` option)
|
|
8
|
+
- add: `retryAttempts` option to SDK constructor for configuring retry behavior @mkhamis
|
|
9
|
+
- add: 401 error protection - authentication errors are never retried @mkhamis
|
|
7
10
|
- add: asset-part-type, asset-part, asset-part-unit, asset-part-transfer, asset-part-receival, return-asset-part-unit & store-asset-part-unit @maramalshen
|
|
8
11
|
- update adjustInventory @maramalshen
|
|
9
12
|
- update FullInvoice with ubl keys @maramalshen
|
|
@@ -14,6 +17,8 @@
|
|
|
14
17
|
|
|
15
18
|
### Changed
|
|
16
19
|
|
|
20
|
+
- All HTTP methods (\_fetch, \_create, \_update, \_patch, \_delete) now support automatic retry with exponential backoff @mkhamis
|
|
21
|
+
|
|
17
22
|
### Fixed
|
|
18
23
|
|
|
19
24
|
### Removed
|
package/lib/index.d.ts
CHANGED
|
@@ -123,6 +123,7 @@ export default class Repzo {
|
|
|
123
123
|
private svAPIEndpoint;
|
|
124
124
|
headers: Headers;
|
|
125
125
|
private timeout;
|
|
126
|
+
private retryAttempts;
|
|
126
127
|
constructor(apiKey: string, options?: Options);
|
|
127
128
|
private static _end_points;
|
|
128
129
|
static get END_POINTS(): {
|
|
@@ -242,6 +243,7 @@ export default class Repzo {
|
|
|
242
243
|
readonly PROMOTIONS: "promotions";
|
|
243
244
|
readonly COMPARE_INVOICE_TO_WAREHOUSE: "compare-invoice-to-warehouse";
|
|
244
245
|
};
|
|
246
|
+
private _retryRequest;
|
|
245
247
|
private _fetch;
|
|
246
248
|
private _create;
|
|
247
249
|
private _update;
|
package/lib/index.js
CHANGED
|
@@ -2338,52 +2338,83 @@ class Repzo {
|
|
|
2338
2338
|
else {
|
|
2339
2339
|
this.timeout = 180000;
|
|
2340
2340
|
}
|
|
2341
|
+
this.retryAttempts = options?.retryAttempts ?? 3;
|
|
2341
2342
|
}
|
|
2342
2343
|
static get END_POINTS() {
|
|
2343
2344
|
return Repzo._end_points;
|
|
2344
2345
|
}
|
|
2345
|
-
async
|
|
2346
|
-
|
|
2347
|
-
|
|
2346
|
+
async _retryRequest(requestFn, attempt = 1) {
|
|
2347
|
+
try {
|
|
2348
|
+
return await requestFn();
|
|
2349
|
+
}
|
|
2350
|
+
catch (error) {
|
|
2351
|
+
// Don't retry on 401 (Unauthorized) errors
|
|
2352
|
+
if (error?.response?.status === 401) {
|
|
2353
|
+
throw error;
|
|
2354
|
+
}
|
|
2355
|
+
// Retry if we haven't exceeded the retry attempts
|
|
2356
|
+
if (attempt < this.retryAttempts) {
|
|
2357
|
+
// Exponential backoff: wait 2^attempt seconds before retrying
|
|
2358
|
+
const delay = Math.pow(2, attempt) * 1000;
|
|
2359
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
2360
|
+
return this._retryRequest(requestFn, attempt + 1);
|
|
2361
|
+
}
|
|
2362
|
+
// If all retries failed, throw the error
|
|
2363
|
+
throw error;
|
|
2348
2364
|
}
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2365
|
+
}
|
|
2366
|
+
async _fetch(baseUrl, path, params) {
|
|
2367
|
+
return this._retryRequest(async () => {
|
|
2368
|
+
if (params) {
|
|
2369
|
+
params = normalizeParams(params);
|
|
2370
|
+
}
|
|
2371
|
+
let res = await axios.get(`${baseUrl}/${path}`, {
|
|
2372
|
+
params,
|
|
2373
|
+
headers: this.headers,
|
|
2374
|
+
timeout: this.timeout,
|
|
2375
|
+
});
|
|
2376
|
+
return res.data;
|
|
2353
2377
|
});
|
|
2354
|
-
return res.data;
|
|
2355
2378
|
}
|
|
2356
2379
|
async _create(baseUrl, path, body, params) {
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2380
|
+
return this._retryRequest(async () => {
|
|
2381
|
+
let res = await axios.post(`${baseUrl}/${path}`, body, {
|
|
2382
|
+
params,
|
|
2383
|
+
headers: this.headers,
|
|
2384
|
+
timeout: this.timeout,
|
|
2385
|
+
});
|
|
2386
|
+
return res.data;
|
|
2361
2387
|
});
|
|
2362
|
-
return res.data;
|
|
2363
2388
|
}
|
|
2364
2389
|
async _update(baseUrl, path, body, params) {
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2390
|
+
return this._retryRequest(async () => {
|
|
2391
|
+
let res = await axios.put(`${baseUrl}/${path}`, body, {
|
|
2392
|
+
params,
|
|
2393
|
+
headers: this.headers,
|
|
2394
|
+
timeout: this.timeout,
|
|
2395
|
+
});
|
|
2396
|
+
return res.data;
|
|
2369
2397
|
});
|
|
2370
|
-
return res.data;
|
|
2371
2398
|
}
|
|
2372
2399
|
async _patch(baseUrl, path, body, params) {
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2400
|
+
return this._retryRequest(async () => {
|
|
2401
|
+
let res = await axios.put(`${baseUrl}/${path}`, body, {
|
|
2402
|
+
params,
|
|
2403
|
+
headers: this.headers,
|
|
2404
|
+
timeout: this.timeout,
|
|
2405
|
+
});
|
|
2406
|
+
return res.data;
|
|
2377
2407
|
});
|
|
2378
|
-
return res.data;
|
|
2379
2408
|
}
|
|
2380
2409
|
async _delete(baseUrl, path, params) {
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2410
|
+
return this._retryRequest(async () => {
|
|
2411
|
+
let res = await axios.delete(`${baseUrl}/${path}`, {
|
|
2412
|
+
params,
|
|
2413
|
+
headers: this.headers,
|
|
2414
|
+
timeout: this.timeout,
|
|
2415
|
+
});
|
|
2416
|
+
return res.data;
|
|
2385
2417
|
});
|
|
2386
|
-
return res.data;
|
|
2387
2418
|
}
|
|
2388
2419
|
}
|
|
2389
2420
|
Repzo._end_points = end_points;
|
package/lib/types/index.d.ts
CHANGED
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -230,6 +230,7 @@ export default class Repzo {
|
|
|
230
230
|
private svAPIEndpoint: string;
|
|
231
231
|
headers: Headers;
|
|
232
232
|
private timeout: number;
|
|
233
|
+
private retryAttempts: number;
|
|
233
234
|
constructor(apiKey: string, options?: Options) {
|
|
234
235
|
this.svAPIEndpoint =
|
|
235
236
|
!options?.env || options?.env == "production"
|
|
@@ -251,22 +252,51 @@ export default class Repzo {
|
|
|
251
252
|
} else {
|
|
252
253
|
this.timeout = 180000;
|
|
253
254
|
}
|
|
255
|
+
this.retryAttempts = options?.retryAttempts ?? 3;
|
|
254
256
|
}
|
|
255
257
|
|
|
256
258
|
private static _end_points = end_points;
|
|
257
259
|
public static get END_POINTS() {
|
|
258
260
|
return Repzo._end_points;
|
|
259
261
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
262
|
+
|
|
263
|
+
private async _retryRequest<T>(
|
|
264
|
+
requestFn: () => Promise<T>,
|
|
265
|
+
attempt: number = 1,
|
|
266
|
+
): Promise<T> {
|
|
267
|
+
try {
|
|
268
|
+
return await requestFn();
|
|
269
|
+
} catch (error: any) {
|
|
270
|
+
// Don't retry on 401 (Unauthorized) errors
|
|
271
|
+
if (error?.response?.status === 401) {
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Retry if we haven't exceeded the retry attempts
|
|
276
|
+
if (attempt < this.retryAttempts) {
|
|
277
|
+
// Exponential backoff: wait 2^attempt seconds before retrying
|
|
278
|
+
const delay = Math.pow(2, attempt) * 1000;
|
|
279
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
280
|
+
return this._retryRequest(requestFn, attempt + 1);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// If all retries failed, throw the error
|
|
284
|
+
throw error;
|
|
263
285
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
private async _fetch(baseUrl: string, path: string, params?: Params) {
|
|
289
|
+
return this._retryRequest(async () => {
|
|
290
|
+
if (params) {
|
|
291
|
+
params = normalizeParams(params);
|
|
292
|
+
}
|
|
293
|
+
let res: any = await axios.get(`${baseUrl}/${path}`, {
|
|
294
|
+
params,
|
|
295
|
+
headers: this.headers,
|
|
296
|
+
timeout: this.timeout,
|
|
297
|
+
});
|
|
298
|
+
return res.data;
|
|
268
299
|
});
|
|
269
|
-
return res.data;
|
|
270
300
|
}
|
|
271
301
|
|
|
272
302
|
private async _create(
|
|
@@ -275,12 +305,14 @@ export default class Repzo {
|
|
|
275
305
|
body: Data,
|
|
276
306
|
params?: Params,
|
|
277
307
|
) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
308
|
+
return this._retryRequest(async () => {
|
|
309
|
+
let res: any = await axios.post(`${baseUrl}/${path}`, body, {
|
|
310
|
+
params,
|
|
311
|
+
headers: this.headers,
|
|
312
|
+
timeout: this.timeout,
|
|
313
|
+
});
|
|
314
|
+
return res.data;
|
|
282
315
|
});
|
|
283
|
-
return res.data;
|
|
284
316
|
}
|
|
285
317
|
|
|
286
318
|
private async _update(
|
|
@@ -289,12 +321,14 @@ export default class Repzo {
|
|
|
289
321
|
body: Data,
|
|
290
322
|
params?: Params,
|
|
291
323
|
) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
324
|
+
return this._retryRequest(async () => {
|
|
325
|
+
let res: any = await axios.put(`${baseUrl}/${path}`, body, {
|
|
326
|
+
params,
|
|
327
|
+
headers: this.headers,
|
|
328
|
+
timeout: this.timeout,
|
|
329
|
+
});
|
|
330
|
+
return res.data;
|
|
296
331
|
});
|
|
297
|
-
return res.data;
|
|
298
332
|
}
|
|
299
333
|
|
|
300
334
|
private async _patch(
|
|
@@ -303,21 +337,25 @@ export default class Repzo {
|
|
|
303
337
|
body: Data,
|
|
304
338
|
params?: Params,
|
|
305
339
|
) {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
340
|
+
return this._retryRequest(async () => {
|
|
341
|
+
let res: any = await axios.put(`${baseUrl}/${path}`, body, {
|
|
342
|
+
params,
|
|
343
|
+
headers: this.headers,
|
|
344
|
+
timeout: this.timeout,
|
|
345
|
+
});
|
|
346
|
+
return res.data;
|
|
310
347
|
});
|
|
311
|
-
return res.data;
|
|
312
348
|
}
|
|
313
349
|
|
|
314
350
|
private async _delete(baseUrl: string, path: string, params?: Params) {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
351
|
+
return this._retryRequest(async () => {
|
|
352
|
+
let res: any = await axios.delete(`${baseUrl}/${path}`, {
|
|
353
|
+
params,
|
|
354
|
+
headers: this.headers,
|
|
355
|
+
timeout: this.timeout,
|
|
356
|
+
});
|
|
357
|
+
return res.data;
|
|
319
358
|
});
|
|
320
|
-
return res.data;
|
|
321
359
|
}
|
|
322
360
|
|
|
323
361
|
available_services = availableService;
|
package/src/types/index.ts
CHANGED