lightspeed-retail-sdk 2.0.7 → 2.0.8

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
@@ -2,6 +2,10 @@
2
2
 
3
3
  A JavaScript SDK for interacting with the Lightspeed Retail API. This SDK provides a convenient way to access Lightspeed Retail's functionalities, including customer, item, order management, and more.
4
4
 
5
+ ## Update
6
+
7
+ I have updated this package so it can be used with either index.cjs or index.mjs for imports.
8
+
5
9
  ## Features
6
10
 
7
11
  - Easy-to-use methods for interacting with various Lightspeed Retail endpoints.
@@ -19,7 +23,7 @@ npm install lightspeed-retail-sdk
19
23
  ## Get started:
20
24
 
21
25
  ```
22
- import LightspeedRetailSDK from "lightspeed-retail-sdk";
26
+ import LightspeedRetailSDK from "lightspeed-retail-sdk/index.mjs";
23
27
 
24
28
  const api = new LightspeedRetailSDK({
25
29
  accountID: "Your Account No.",
package/index.cjs ADDED
@@ -0,0 +1,646 @@
1
+ const axios = require("axios");
2
+
3
+ const operationUnits = { GET: 1, POST: 10, PUT: 10 };
4
+ const getRequestUnits = (operation) => operationUnits[operation] || 10;
5
+
6
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7
+
8
+ class LightspeedRetailSDK {
9
+ static BASE_URL = "https://api.lightspeedapp.com/API/V3/Account";
10
+ static TOKEN_URL = "https://cloud.lightspeedapp.com/oauth/access_token.php";
11
+
12
+ constructor(opts) {
13
+ const { clientID, clientSecret, refreshToken, accountID } = opts;
14
+
15
+ this.clientID = clientID;
16
+ this.clientSecret = clientSecret;
17
+ this.refreshToken = refreshToken;
18
+ this.accountID = accountID;
19
+ this.baseUrl = LightspeedRetailSDK.BASE_URL;
20
+ this.tokenUrl = LightspeedRetailSDK.TOKEN_URL;
21
+ this.maxRetries = 3;
22
+ this.lastResponse = null;
23
+ this.token = null;
24
+ this.tokenExpiry = null;
25
+ }
26
+
27
+ // handleError function to handle errors
28
+ handleError(context, err, shouldThrow = true) {
29
+ // Context includes information about where the error occurred
30
+ const detailedMessage = `Error in ${context}: ${err.message}`;
31
+
32
+ // Log the error message
33
+ console.error(detailedMessage);
34
+
35
+ // Log the stack trace if available
36
+ if (err.stack) {
37
+ console.error("Stack trace:", err.stack);
38
+ }
39
+
40
+ // If the error has response data, log it
41
+ if (err.response) {
42
+ console.error("Error response:", {
43
+ status: err.response.status,
44
+ headers: err.response.headers,
45
+ data: err.response.data,
46
+ });
47
+ }
48
+
49
+ // Optionally rethrow the error with the detailed message
50
+ if (shouldThrow) {
51
+ throw new Error(detailedMessage);
52
+ }
53
+ }
54
+
55
+ // Update the last response
56
+ setLastResponse = (response) => (this.lastResponse = response);
57
+
58
+ // Handle rate limits
59
+ handleRateLimit = async (options) => {
60
+ if (!this.lastResponse) return null;
61
+
62
+ const { method } = options;
63
+ const requestUnits = getRequestUnits(method);
64
+ const rateHeader = this.lastResponse.headers["x-ls-api-bucket-level"];
65
+
66
+ if (!rateHeader) return null;
67
+
68
+ const [used, available] = rateHeader.split("/");
69
+ const availableUnits = available - used;
70
+ if (requestUnits <= availableUnits) return 0;
71
+
72
+ const dripRate = parseInt(this.lastResponse.headers["x-ls-api-drip-rate"], 10);
73
+
74
+ // Check if dripRate is a valid number greater than 0
75
+ if (isNaN(dripRate) || dripRate <= 0) {
76
+ this.handleError.error("Invalid drip rate received from API");
77
+ }
78
+
79
+ const unitWait = requestUnits - availableUnits;
80
+ const delay = Math.ceil((unitWait / dripRate) * 1000);
81
+ await sleep(delay);
82
+
83
+ return unitWait;
84
+ };
85
+
86
+ // Get a new token
87
+ getToken = async () => {
88
+ const now = new Date();
89
+ const bufferTime = 1 * 60 * 1000; // 1 minute buffer
90
+
91
+ // Check if the token exists and is still valid
92
+ if (this.token && this.tokenExpiry.getTime() - now.getTime() > bufferTime) {
93
+ return this.token;
94
+ }
95
+
96
+ // Fetch a new token if needed
97
+ const body = {
98
+ grant_type: "refresh_token",
99
+ client_id: this.clientID,
100
+ client_secret: this.clientSecret,
101
+ refresh_token: this.refreshToken,
102
+ };
103
+
104
+ try {
105
+ const response = await axios({
106
+ url: this.tokenUrl,
107
+ method: "post",
108
+ headers: {
109
+ "Content-Type": "application/json",
110
+ },
111
+ data: JSON.stringify(body),
112
+ });
113
+
114
+ const tokenData = await response.data;
115
+
116
+ // Set token and expiry time
117
+ this.token = tokenData.access_token;
118
+ this.tokenExpiry = new Date(now.getTime() + tokenData.expires_in * 1000);
119
+
120
+ return this.token;
121
+ } catch (error) {
122
+ return this.handleError("GET TOKEN ERROR", error);
123
+ }
124
+ };
125
+
126
+ // Fetch a resource
127
+ executeApiRequest = async (options, retries = 0) => {
128
+ await this.handleRateLimit(options);
129
+
130
+ const token = await this.getToken();
131
+ if (!token) throw new Error("Error Fetching Token");
132
+
133
+ // Set common headers
134
+ options.headers = {
135
+ Authorization: `Bearer ${token}`,
136
+ "Content-Type": "application/json",
137
+ ...options.headers, // Merge with any additional headers passed in options
138
+ };
139
+
140
+ try {
141
+ const res = await axios(options);
142
+ this.lastResponse = res;
143
+
144
+ // Return the data
145
+ if (options.method === "GET") {
146
+ return {
147
+ data: res.data,
148
+ next: res.next,
149
+ previous: res.previous,
150
+ };
151
+ } else {
152
+ return res.data; // For POST and PUT, typically just return the data
153
+ }
154
+ } catch (err) {
155
+ if (this.isRetryableError(err) && retries < this.maxRetries) {
156
+ this.handleError(`Network Error Retrying in 2 seconds...`, err.message, false);
157
+ await sleep(2000);
158
+ return this.executeApiRequest(options, retries + 1);
159
+ } else {
160
+ this.handleError(`Failed Request statusText: ${err.response?.statusText}`);
161
+ this.handleError(`Failed data: ${err.response?.data}`);
162
+ throw err;
163
+ }
164
+ }
165
+ };
166
+
167
+ // Get paginated data
168
+ async getAllData(options) {
169
+ let allData = [];
170
+ while (options.url) {
171
+ const { data } = await this.executeApiRequest(options);
172
+ let next = data["@attributes"].next;
173
+ let selectDataArray = Object.keys(data)[1];
174
+ let selectedData = data[selectDataArray];
175
+ allData = allData.concat(selectedData);
176
+ options.url = next;
177
+ }
178
+ return allData;
179
+ }
180
+
181
+ // Check if error is retryable
182
+ isRetryableError = (err) => {
183
+ if (!err.response) {
184
+ // No response (network error or timeout)
185
+ return true;
186
+ }
187
+
188
+ // Retry for server errors (500-599)
189
+ return err.response.status >= 500 && err.response.status <= 599;
190
+ };
191
+
192
+ // Get customer by ID
193
+ async getCustomer(id, relations) {
194
+ const options = {
195
+ url: `${this.baseUrl}/${this.accountID}/Customer/${id}.json`,
196
+ method: "GET",
197
+ };
198
+
199
+ if (!id) return this.handleError("You need to provide a customerID");
200
+
201
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
202
+
203
+ try {
204
+ const response = await this.getAllData(options);
205
+ return response;
206
+ } catch (error) {
207
+ return this.handleError("GET CUSTOMERS ERROR", error);
208
+ }
209
+ }
210
+
211
+ // Get all customers
212
+ async getCustomers(relations) {
213
+ const options = {
214
+ url: `${this.baseUrl}/${this.accountID}/Customer.json`,
215
+ method: "GET",
216
+ };
217
+
218
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
219
+
220
+ try {
221
+ const response = await this.getAllData(options);
222
+ return response;
223
+ } catch (error) {
224
+ return this.handleError("GET CUSTOMERS ERROR", error);
225
+ }
226
+ }
227
+
228
+ // Get item by ID
229
+ async getItem(id, relations) {
230
+ const options = {
231
+ url: `${this.baseUrl}/${this.accountID}/Item/${id}.json`,
232
+ method: "GET",
233
+ };
234
+
235
+ if (!id) return this.handleError("You need to provide a itemID");
236
+
237
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
238
+
239
+ try {
240
+ const response = await this.getAllData(options);
241
+ return response;
242
+ } catch (error) {
243
+ return this.handleError("GET ITEM ERROR", error);
244
+ }
245
+ }
246
+
247
+ // Get multiple items by ID
248
+ async getMultipleItems(items, relations) {
249
+ const options = {
250
+ url: `${this.baseUrl}/${this.accountID}/Item.json`,
251
+ method: "GET",
252
+ };
253
+
254
+ if (!items) this.handleError("You need to provide itemID's");
255
+
256
+ if (items) options.url = options.url + `?itemID=IN,${items}`;
257
+
258
+ if (relations) options.url = options.url + `&load_relations=${relations}`;
259
+
260
+ try {
261
+ const response = await this.getAllData(options);
262
+ return response;
263
+ } catch (error) {
264
+ return this.handleError("GET ITEMS ERROR", error);
265
+ }
266
+ }
267
+
268
+ // Get all items
269
+ async getItems(relations) {
270
+ const options = {
271
+ url: `${this.baseUrl}/${this.accountID}/Item.json`,
272
+ method: "GET",
273
+ };
274
+
275
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
276
+
277
+ try {
278
+ const response = await this.getAllData(options);
279
+ return response;
280
+ } catch (error) {
281
+ return this.handleError("GET ITEMS ERROR", error);
282
+ }
283
+ }
284
+
285
+ // Get all items by vendor
286
+ async getvendorItems(vendorID, relations) {
287
+ const options = {
288
+ url: `${this.baseUrl}/${this.accountID}/Item.json?defaultVendorID=${vendorID}`,
289
+ method: "GET",
290
+ };
291
+
292
+ if (relations) options.url = options.url + `&load_relations=${relations}`;
293
+
294
+ try {
295
+ const response = await this.getAllData(options);
296
+ return response;
297
+ } catch (error) {
298
+ return this.handleError("GET ITEMS ERROR", error);
299
+ }
300
+ }
301
+
302
+ // Get all Matrix Items
303
+ async getMatrixItems(relations) {
304
+ const options = {
305
+ url: `${this.baseUrl}/${this.accountID}/ItemMatrix.json`,
306
+ method: "GET",
307
+ };
308
+
309
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
310
+
311
+ try {
312
+ const response = await this.getAllData(options);
313
+ return response;
314
+ } catch (error) {
315
+ return this.handleError("GET ITEM ERROR", error);
316
+ }
317
+ }
318
+
319
+ // Get Matrix Item by ID
320
+ async getMatrixItem(id, relations) {
321
+ const options = {
322
+ url: `${this.baseUrl}/${this.accountID}/ItemMatrix/${id}.json`,
323
+ method: "GET",
324
+ };
325
+
326
+ if (!id) return this.handleError("You need to provide a itemID");
327
+
328
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
329
+
330
+ try {
331
+ const response = await this.getAllData(options);
332
+ return response;
333
+ } catch (error) {
334
+ return this.handleError("GET ITEM ERROR", error);
335
+ }
336
+ }
337
+
338
+ // Get category by ID
339
+ async getCategory(id, relations) {
340
+ const options = {
341
+ url: `${this.baseUrl}/${this.accountID}/Category/${id}.json`,
342
+ method: "GET",
343
+ };
344
+
345
+ if (!id) return this.handleError("You need to provide a categoryID");
346
+
347
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
348
+
349
+ try {
350
+ const response = await this.getAllData(options);
351
+ return response;
352
+ } catch (error) {
353
+ return this.handleError("GET CATEGORY ERROR", error);
354
+ }
355
+ }
356
+
357
+ // Get all categories
358
+ async getCategories(relations) {
359
+ const options = {
360
+ url: `${this.baseUrl}/${this.accountID}/Category.json`,
361
+ method: "GET",
362
+ };
363
+
364
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
365
+
366
+ try {
367
+ const response = await this.getAllData(options);
368
+ return response;
369
+ } catch (error) {
370
+ return this.handleError("GET CATEGORIES ERROR", error);
371
+ }
372
+ }
373
+
374
+ // Get Manufacturer by ID
375
+ async getManufacturer(id, relations) {
376
+ const options = {
377
+ url: `${this.baseUrl}/${this.accountID}/Manufacturer/${id}.json`,
378
+ method: "GET",
379
+ };
380
+
381
+ if (!id) return this.handleError("You need to provide a manufacturerID");
382
+
383
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
384
+
385
+ try {
386
+ const response = await this.getAllData(options);
387
+ return response;
388
+ } catch (error) {
389
+ return this.handleError("GET MANUFACTURER ERROR", error);
390
+ }
391
+ }
392
+
393
+ // Get all manufacturers
394
+ async getManufacturers(relations) {
395
+ const options = {
396
+ url: `${this.baseUrl}/${this.accountID}/Manufacturer.json`,
397
+ method: "GET",
398
+ };
399
+
400
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
401
+
402
+ try {
403
+ const response = await this.getAllData(options);
404
+ return response;
405
+ } catch (error) {
406
+ return this.handleError("GET MANUFACTURERS ERROR", error);
407
+ }
408
+ }
409
+
410
+ // Get order by ID
411
+ async getOrder(id, relations) {
412
+ const options = {
413
+ url: `${this.baseUrl}/${this.accountID}/Order/${id}.json`,
414
+ method: "GET",
415
+ };
416
+
417
+ if (!id) return this.handleError("You need to provide a orderID");
418
+
419
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
420
+
421
+ try {
422
+ const response = await this.getAllData(options);
423
+ return response;
424
+ } catch (error) {
425
+ return this.handleError("GET ORDER ERROR", error);
426
+ }
427
+ }
428
+
429
+ // Get all orders
430
+ async getOrders(relations) {
431
+ const options = {
432
+ url: `${this.baseUrl}/${this.accountID}/Order.json`,
433
+ method: "GET",
434
+ };
435
+
436
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
437
+
438
+ try {
439
+ const response = await this.getAllData(options);
440
+ return response;
441
+ } catch (error) {
442
+ return this.handleError("GET ORDERS ERROR", error);
443
+ }
444
+ }
445
+
446
+ // Get all orders by vendor
447
+ async getOrdersByVendorID(id, relations) {
448
+ const options = {
449
+ url: `${this.baseUrl}/${this.accountID}/Order.json?load_relations=["Vendor"]&vendorID=${id}`,
450
+ method: "GET",
451
+ };
452
+
453
+ if (!id) return this.handleError("You need to provide a vendorID");
454
+
455
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
456
+
457
+ try {
458
+ const response = await this.getAllData(options);
459
+ return response;
460
+ } catch (error) {
461
+ return this.handleError("GET ORDER ERROR", error);
462
+ }
463
+ }
464
+
465
+ // Get all open orders by vendor
466
+ async getOpenOrdersByVendorID(id, relations) {
467
+ const options = {
468
+ url: `${this.baseUrl}/${this.accountID}/Order.json?load_relations=["Vendor", "OrderLines"]&vendorID=${id}&complete=false`,
469
+ method: "GET",
470
+ };
471
+
472
+ if (!id) return this.handleError("You need to provide a vendorID");
473
+
474
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
475
+
476
+ try {
477
+ const response = await this.getAllData(options);
478
+ return response;
479
+ } catch (error) {
480
+ return this.handleError("GET ORDER ERROR", error);
481
+ }
482
+ }
483
+
484
+ // Get vendor by ID
485
+ async getVendor(id, relations) {
486
+ const options = {
487
+ url: `${this.baseUrl}/${this.accountID}/Vendor/${id}.json`,
488
+ method: "GET",
489
+ };
490
+
491
+ if (!id) return this.handleError("You need to provide a vendorID");
492
+
493
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
494
+
495
+ try {
496
+ const response = await this.getAllData(options);
497
+ return response;
498
+ } catch (error) {
499
+ return this.handleError("GET VENDOR ERROR", error);
500
+ }
501
+ }
502
+
503
+ // Get all vendors
504
+ async getVendors(relations) {
505
+ const options = {
506
+ url: `${this.baseUrl}/${this.accountID}/Vendor.json`,
507
+ method: "GET",
508
+ };
509
+
510
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
511
+
512
+ try {
513
+ const response = await this.getAllData(options);
514
+ return response;
515
+ } catch (error) {
516
+ return this.handleError("GET VENDORS ERROR", error);
517
+ }
518
+ }
519
+
520
+ // Get sale by ID
521
+ async getSale(id, relations) {
522
+ const options = {
523
+ url: `${this.baseUrl}/${this.accountID}/Sale/${id}.json`,
524
+ method: "GET",
525
+ };
526
+
527
+ if (!id) return this.handleError("You need to provide a saleID");
528
+
529
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
530
+
531
+ try {
532
+ const response = await this.getAllData(options);
533
+ return response;
534
+ } catch (error) {
535
+ return this.handleError("GET SALE ERROR", error);
536
+ }
537
+ }
538
+
539
+ // Get all sales
540
+ async getSales(relations) {
541
+ const options = {
542
+ url: `${this.baseUrl}/${this.accountID}/Sale.json`,
543
+ method: "GET",
544
+ };
545
+
546
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
547
+
548
+ try {
549
+ const response = await this.getAllData(options);
550
+ return response;
551
+ } catch (error) {
552
+ return this.handleError("GET SALES ERROR", error);
553
+ }
554
+ }
555
+
556
+ async getMultipleSales(saleIDs, relations) {
557
+ const options = {
558
+ url: `${this.baseUrl}/${this.accountID}/Sale.json?saleID=IN,${saleIDs}`,
559
+ method: "GET",
560
+ };
561
+
562
+ if (relations) options.url = options.url + `?load_relations=${relations}`;
563
+
564
+ try {
565
+ const response = await this.getAllData(options);
566
+ return response;
567
+ } catch (error) {
568
+ return this.handleError("GET SALE ERROR", error);
569
+ }
570
+ }
571
+
572
+ async getSaleLinesByItem(itemID, relations) {
573
+ const options = {
574
+ url: `${this.baseUrl}/${this.accountID}/SaleLine.json?itemID=${itemID}`,
575
+ method: "GET",
576
+ };
577
+
578
+ if (relations) options.url = options.url + `&load_relations=${relations}`;
579
+
580
+ try {
581
+ const response = await this.getAllData(options);
582
+ return response;
583
+ } catch (error) {
584
+ return this.handleError("GET SALE ERROR", error);
585
+ }
586
+ }
587
+
588
+ // Get sales lines by item ID's and date range
589
+ async getSaleLinesByItems(ids, startDate = undefined, endDate = undefined, relations) {
590
+ const options = {
591
+ url: `${this.baseUrl}/${this.accountID}/SaleLine.json?itemID=IN,[${ids}]`,
592
+ method: "GET",
593
+ };
594
+
595
+ if (!ids) return this.handleError("You need to provide itemIDs");
596
+ if (startDate && !endDate) return this.handleError("You need to provide an end date");
597
+ if (endDate && !startDate)
598
+ return this.handleError("You need to provide a start date");
599
+
600
+ if (relations) options.url = options.url + `&load_relations=${relations}`;
601
+
602
+ if (startDate && endDate)
603
+ options.url =
604
+ options.url + `&timeStamp=%3E%3C%2C${startDate}%2C${endDate}&sort=timeStamp`;
605
+
606
+ try {
607
+ const response = await this.getAllData(options);
608
+ return response;
609
+ } catch (error) {
610
+ return this.handleError("GET SALE ERROR", error);
611
+ }
612
+ }
613
+
614
+ // Get sales lines by vendor ID's and date range
615
+ async getSaleLinesByVendorID(
616
+ id,
617
+ startDate = undefined,
618
+ endDate = undefined,
619
+ relations
620
+ ) {
621
+ const options = {
622
+ url: `${this.baseUrl}/${this.accountID}/SaleLine.json?load_relations=${
623
+ relations ? relations : `["Item"]`
624
+ }&Item.defaultVendorID=${id}`,
625
+ method: "GET",
626
+ };
627
+
628
+ if (!id) return this.handleError("You need to provide a vendorID");
629
+ if (startDate && !endDate) return this.handleError("You need to provide an end date");
630
+ if (endDate && !startDate)
631
+ return this.handleError("You need to provide a start date");
632
+
633
+ if (startDate && endDate)
634
+ options.url =
635
+ options.url + `&timeStamp=%3E%3C%2C${startDate}%2C${endDate}&sort=timeStamp`;
636
+
637
+ try {
638
+ const response = await this.getAllData(options);
639
+ return response;
640
+ } catch (error) {
641
+ return this.handleError("GET SALE ERROR", error);
642
+ }
643
+ }
644
+ }
645
+
646
+ module.exports = LightspeedRetailSDK;
@@ -6,6 +6,9 @@ const getRequestUnits = (operation) => operationUnits[operation] || 10;
6
6
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7
7
 
8
8
  class LightspeedRetailSDK {
9
+ static BASE_URL = "https://api.lightspeedapp.com/API/V3/Account";
10
+ static TOKEN_URL = "https://cloud.lightspeedapp.com/oauth/access_token.php";
11
+
9
12
  constructor(opts) {
10
13
  const { clientID, clientSecret, refreshToken, accountID } = opts;
11
14
 
@@ -13,7 +16,8 @@ class LightspeedRetailSDK {
13
16
  this.clientSecret = clientSecret;
14
17
  this.refreshToken = refreshToken;
15
18
  this.accountID = accountID;
16
- this.baseUrl = "https://api.lightspeedapp.com/API/V3/Account";
19
+ this.baseUrl = LightspeedRetailSDK.BASE_URL;
20
+ this.tokenUrl = LightspeedRetailSDK.TOKEN_URL;
17
21
  this.maxRetries = 3;
18
22
  this.lastResponse = null;
19
23
  this.token = null;
@@ -21,12 +25,30 @@ class LightspeedRetailSDK {
21
25
  }
22
26
 
23
27
  // handleError function to handle errors
24
- handleError(msg, err, shouldThrow = true) {
25
- const errorMessage = `${msg} - ${err.message || err}`;
26
- console.error(errorMessage);
28
+ handleError(context, err, shouldThrow = true) {
29
+ // Context includes information about where the error occurred
30
+ const detailedMessage = `Error in ${context}: ${err.message}`;
31
+
32
+ // Log the error message
33
+ console.error(detailedMessage);
34
+
35
+ // Log the stack trace if available
36
+ if (err.stack) {
37
+ console.error("Stack trace:", err.stack);
38
+ }
39
+
40
+ // If the error has response data, log it
41
+ if (err.response) {
42
+ console.error("Error response:", {
43
+ status: err.response.status,
44
+ headers: err.response.headers,
45
+ data: err.response.data,
46
+ });
47
+ }
27
48
 
49
+ // Optionally rethrow the error with the detailed message
28
50
  if (shouldThrow) {
29
- throw new Error(errorMessage);
51
+ throw new Error(detailedMessage);
30
52
  }
31
53
  }
32
54
 
@@ -64,9 +86,10 @@ class LightspeedRetailSDK {
64
86
  // Get a new token
65
87
  getToken = async () => {
66
88
  const now = new Date();
89
+ const bufferTime = 1 * 60 * 1000; // 1 minute buffer
67
90
 
68
91
  // Check if the token exists and is still valid
69
- if (this.token && this.tokenExpiry > now) {
92
+ if (this.token && this.tokenExpiry.getTime() - now.getTime() > bufferTime) {
70
93
  return this.token;
71
94
  }
72
95
 
@@ -80,7 +103,7 @@ class LightspeedRetailSDK {
80
103
 
81
104
  try {
82
105
  const response = await axios({
83
- url: "https://cloud.lightspeedapp.com/oauth/access_token.php",
106
+ url: this.tokenUrl,
84
107
  method: "post",
85
108
  headers: {
86
109
  "Content-Type": "application/json",
package/package.json CHANGED
@@ -1,28 +1,28 @@
1
1
  {
2
2
  "name": "lightspeed-retail-sdk",
3
- "version": "2.0.7",
3
+ "version": "2.0.8",
4
4
  "description": "Another unofficial Lightspeed Retail API SDK for Node.js",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "jest"
5
+ "type": "module",
6
+ "main": "index.cjs",
7
+ "module": "index.mjs",
8
+ "exports": {
9
+ ".": {
10
+ "require": "./index.cjs",
11
+ "default": "./index.mjs"
12
+ }
8
13
  },
9
- "author": "@morley_darryl",
14
+ "author": "https://github.com/darrylmorley",
10
15
  "license": "ISC",
11
16
  "dependencies": {
12
17
  "axios": "^1.3.4",
13
- "qs": "^6.11.1",
14
- "retry": "^0.13.1"
18
+ "dotenv": "^16.4.4"
15
19
  },
16
- "type": "module",
17
20
  "repository": {
18
21
  "type": "git",
19
- "url": "https://github.com/darrylmorley/lightspeed-retail-sdk"
22
+ "url": "git+https://github.com/darrylmorley/lightspeed-retail-sdk.git"
20
23
  },
21
24
  "keywords": [
22
25
  "lightspeed retail",
23
26
  "node"
24
- ],
25
- "devDependencies": {
26
- "dotenv": "^16.3.1"
27
- }
27
+ ]
28
28
  }