repzo 1.0.227 → 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 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 _fetch(baseUrl, path, params) {
2346
- if (params) {
2347
- params = normalizeParams(params);
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
- let res = await axios.get(`${baseUrl}/${path}`, {
2350
- params,
2351
- headers: this.headers,
2352
- timeout: this.timeout,
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
- let res = await axios.post(`${baseUrl}/${path}`, body, {
2358
- params,
2359
- headers: this.headers,
2360
- timeout: this.timeout,
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
- let res = await axios.put(`${baseUrl}/${path}`, body, {
2366
- params,
2367
- headers: this.headers,
2368
- timeout: this.timeout,
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
- let res = await axios.put(`${baseUrl}/${path}`, body, {
2374
- params,
2375
- headers: this.headers,
2376
- timeout: this.timeout,
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
- let res = await axios.delete(`${baseUrl}/${path}`, {
2382
- params,
2383
- headers: this.headers,
2384
- timeout: this.timeout,
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;
@@ -12,6 +12,7 @@ export interface Options {
12
12
  [key: string]: string;
13
13
  };
14
14
  timeout?: number | undefined;
15
+ retryAttempts?: number;
15
16
  }
16
17
  export interface Headers {
17
18
  "api-key": string;
@@ -6631,6 +6632,8 @@ export declare namespace Service {
6631
6632
  shipping_charge?: number;
6632
6633
  payment_charge?: number;
6633
6634
  total_with_charges?: number;
6635
+ media?: StringId[];
6636
+ signature?: StringId;
6634
6637
  createdAt: string;
6635
6638
  updatedAt: string;
6636
6639
  __v: number;
@@ -6738,6 +6741,8 @@ export declare namespace Service {
6738
6741
  shipping_charge?: number;
6739
6742
  payment_charge?: number;
6740
6743
  total_with_charges?: number;
6744
+ media?: StringId[];
6745
+ signature?: StringId;
6741
6746
  }
6742
6747
  export interface UpdateBody {
6743
6748
  _id?: string;
@@ -6848,6 +6853,8 @@ export declare namespace Service {
6848
6853
  shipping_charge?: number;
6849
6854
  payment_charge?: number;
6850
6855
  total_with_charges?: number;
6856
+ media?: StringId[];
6857
+ signature?: StringId;
6851
6858
  createdAt?: string;
6852
6859
  updatedAt?: string;
6853
6860
  __v?: number;
@@ -7010,8 +7017,10 @@ export declare namespace Service {
7010
7017
  return_reason?: string | ReturnReason.Schema;
7011
7018
  teams?: string[] | Team.TeamSchema[];
7012
7019
  route?: string | Route.RouteSchema;
7020
+ media?: StringId[] | PopulatedMediaStorage[];
7021
+ signature?: StringId | PopulatedMediaStorage;
7013
7022
  };
7014
- type PopulatedKeys = "custom_status" | "return_reason" | "teams" | "route";
7023
+ type PopulatedKeys = "custom_status" | "return_reason" | "teams" | "route" | "media" | "signature";
7015
7024
  type ProformaStatus = "pending" | "approved" | "processing" | "rejected";
7016
7025
  type VariantSortingKeys = "product_sku" | "product_barcode" | "variant_name" | "product_name" | "variant_sku" | "variant_barcode";
7017
7026
  export namespace Find {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "repzo",
3
- "version": "1.0.227",
3
+ "version": "1.0.229",
4
4
  "description": "Repzo TypeScript SDK",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
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
- private async _fetch(baseUrl: string, path: string, params?: Params) {
261
- if (params) {
262
- params = normalizeParams(params);
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
- let res: any = await axios.get(`${baseUrl}/${path}`, {
265
- params,
266
- headers: this.headers,
267
- timeout: this.timeout,
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
- let res: any = await axios.post(`${baseUrl}/${path}`, body, {
279
- params,
280
- headers: this.headers,
281
- timeout: this.timeout,
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
- let res: any = await axios.put(`${baseUrl}/${path}`, body, {
293
- params,
294
- headers: this.headers,
295
- timeout: this.timeout,
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
- let res: any = await axios.put(`${baseUrl}/${path}`, body, {
307
- params,
308
- headers: this.headers,
309
- timeout: this.timeout,
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
- let res: any = await axios.delete(`${baseUrl}/${path}`, {
316
- params,
317
- headers: this.headers,
318
- timeout: this.timeout,
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;
@@ -11,6 +11,7 @@ export interface Options {
11
11
  env?: "staging" | "local" | "production";
12
12
  headers?: { [key: string]: string };
13
13
  timeout?: number | undefined;
14
+ retryAttempts?: number;
14
15
  }
15
16
  export interface Headers {
16
17
  "api-key": string;
@@ -7191,6 +7192,8 @@ export namespace Service {
7191
7192
  shipping_charge?: number;
7192
7193
  payment_charge?: number;
7193
7194
  total_with_charges?: number;
7195
+ media?: StringId[];
7196
+ signature?: StringId;
7194
7197
  createdAt: string;
7195
7198
  updatedAt: string;
7196
7199
  __v: number;
@@ -7290,6 +7293,8 @@ export namespace Service {
7290
7293
  shipping_charge?: number;
7291
7294
  payment_charge?: number;
7292
7295
  total_with_charges?: number;
7296
+ media?: StringId[];
7297
+ signature?: StringId;
7293
7298
  }
7294
7299
  export interface UpdateBody {
7295
7300
  _id?: string;
@@ -7392,6 +7397,8 @@ export namespace Service {
7392
7397
  shipping_charge?: number;
7393
7398
  payment_charge?: number;
7394
7399
  total_with_charges?: number;
7400
+ media?: StringId[];
7401
+ signature?: StringId;
7395
7402
  createdAt?: string;
7396
7403
  updatedAt?: string;
7397
7404
  __v?: number;
@@ -7539,8 +7546,16 @@ export namespace Service {
7539
7546
  return_reason?: string | ReturnReason.Schema;
7540
7547
  teams?: string[] | Team.TeamSchema[];
7541
7548
  route?: string | Route.RouteSchema;
7549
+ media?: StringId[] | PopulatedMediaStorage[];
7550
+ signature?: StringId | PopulatedMediaStorage;
7542
7551
  };
7543
- type PopulatedKeys = "custom_status" | "return_reason" | "teams" | "route";
7552
+ type PopulatedKeys =
7553
+ | "custom_status"
7554
+ | "return_reason"
7555
+ | "teams"
7556
+ | "route"
7557
+ | "media"
7558
+ | "signature";
7544
7559
  type ProformaStatus = "pending" | "approved" | "processing" | "rejected";
7545
7560
  type VariantSortingKeys =
7546
7561
  | "product_sku"