lightspeed-retail-sdk 2.0.13 → 3.0.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.
package/README.md CHANGED
@@ -2,18 +2,65 @@
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
5
+ **Current Version: 3.0.0** - Updated with new OAuth system support and enhanced token management.
6
6
 
7
- - This package has been enhanced to support both CommonJS and module usage. I have also added methods for fetching both a gift card, and all gift cards.
8
- - I've added PUT and POST methods to many of the domains now.
7
+ ## 🚨 Important Update - New OAuth System
8
+
9
+ **Lightspeed has implemented a new OAuth authorization server.** This SDK has been updated to support the new endpoints and token rotation system.
10
+
11
+ ### Key Changes
12
+
13
+ - **New OAuth endpoints** - Updated to use `https://cloud.lightspeedapp.com/auth/oauth/token`
14
+ - **Token rotation** - Both access and refresh tokens now change with each refresh
15
+ - **Token persistence** - Tokens must be stored between application restarts
16
+ - **Longer token values** - Ensure your storage can handle the new token lengths
9
17
 
10
18
  ## Features
11
19
 
12
20
  - Easy-to-use methods for interacting with various Lightspeed Retail endpoints.
13
21
  - Built-in handling of API rate limits.
14
22
  - Automatic token management for authentication.
23
+ - **NEW: Auto-retry on authentication errors** - Automatically refreshes tokens and retries failed requests.
15
24
  - Support for paginated responses from the Lightspeed API.
16
25
  - Retry logic for handling transient network issues.
26
+ - **NEW: Flexible token storage** - File-based, database, or custom storage options.
27
+ - **NEW: Advanced search capabilities** - Search items and customers with flexible queries.
28
+ - **NEW: Bulk operations** - Update multiple items efficiently.
29
+ - **NEW: Inventory management** - Low stock alerts and category-based queries.
30
+ - Support for both CommonJS and ES modules.
31
+
32
+ ## Smart Token Management
33
+
34
+ The SDK intelligently manages tokens with these features:
35
+
36
+ - **Automatic refresh** - Tokens are refreshed before they expire (1-minute buffer)
37
+ - **Auto-retry on 401 errors** - If a token is invalid, the SDK automatically refreshes and retries the request
38
+ - **Persistent storage priority** - Always checks stored tokens first, falls back to environment variables
39
+ - **Token rotation support** - Handles Lightspeed's new token rotation system seamlessly
40
+
41
+ ### Token Priority Order
42
+
43
+ 1. **Stored tokens** (from your chosen storage method)
44
+ 2. **Environment variables** (fallback)
45
+ 3. **Automatic refresh** (when expired)
46
+
47
+ ## Environment Variables
48
+
49
+ For development and testing, you can use environment variables:
50
+
51
+ ```bash
52
+ # Required
53
+ LIGHTSPEED_ACCOUNT_ID=your_account_id
54
+ LIGHTSPEED_CLIENT_ID=your_client_id
55
+ LIGHTSPEED_CLIENT_SECRET=your_client_secret
56
+
57
+ # Optional (for initial setup)
58
+ LIGHTSPEED_ACCESS_TOKEN=your_access_token
59
+ LIGHTSPEED_REFRESH_TOKEN=your_refresh_token
60
+ LIGHTSPEED_TOKEN_EXPIRES_AT=2025-01-01T00:00:00.000Z
61
+ ```
62
+
63
+ ⚠️ **Note**: Environment variables are used as fallback when no stored tokens are found. Once tokens are stored via your chosen storage method, those take priority.
17
64
 
18
65
  ## Installation
19
66
 
@@ -21,61 +68,292 @@ A JavaScript SDK for interacting with the Lightspeed Retail API. This SDK provid
21
68
  npm install lightspeed-retail-sdk
22
69
  ```
23
70
 
24
- ## Get started:
71
+ ## Quick Start
25
72
 
26
- ```
73
+ ### Basic Usage (In-Memory Storage)
74
+
75
+ ```javascript
27
76
  import LightspeedRetailSDK from "lightspeed-retail-sdk";
28
77
 
29
78
  const api = new LightspeedRetailSDK({
30
79
  accountID: "Your Account No.",
31
80
  clientID: "Your client ID.",
32
81
  clientSecret: "Your client secret.",
33
- refreshToken: "Your refresh token.",
82
+ refreshToken: "Your initial refresh token.",
83
+ // No tokenStorage = uses InMemoryTokenStorage by default
84
+ });
85
+ ```
86
+
87
+ ⚠️ **Warning**: Basic usage stores tokens in memory only. Tokens will be lost on application restart, which may cause issues with Lightspeed's new token rotation system.
88
+
89
+ ### Recommended Usage (Persistent Storage)
90
+
91
+ #### File-Based Storage
92
+
93
+ ```javascript
94
+ import LightspeedRetailSDK, { FileTokenStorage } from "lightspeed-retail-sdk";
95
+
96
+ const api = new LightspeedRetailSDK({
97
+ accountID: "Your Account No.",
98
+ clientID: "Your client ID.",
99
+ clientSecret: "Your client secret.",
100
+ refreshToken: "Your initial refresh token.",
101
+ tokenStorage: new FileTokenStorage("./lightspeed-tokens.json"),
34
102
  });
35
103
 
36
- export default api
104
+ export default api;
37
105
  ```
38
106
 
39
- ## Example Request
107
+ #### Custom Storage (Database Example)
108
+
109
+ ```javascript
110
+ import LightspeedRetailSDK from "lightspeed-retail-sdk";
111
+
112
+ class DatabaseTokenStorage {
113
+ constructor(userId) {
114
+ this.userId = userId;
115
+ }
116
+
117
+ async getTokens() {
118
+ const user = await db.users.findById(this.userId);
119
+ return {
120
+ access_token: user.lightspeed_access_token,
121
+ refresh_token: user.lightspeed_refresh_token,
122
+ expires_at: user.lightspeed_token_expires_at,
123
+ };
124
+ }
40
125
 
126
+ async setTokens(tokens) {
127
+ await db.users.update(this.userId, {
128
+ lightspeed_access_token: tokens.access_token,
129
+ lightspeed_refresh_token: tokens.refresh_token,
130
+ lightspeed_token_expires_at: tokens.expires_at,
131
+ });
132
+ }
133
+ }
134
+
135
+ const api = new LightspeedRetailSDK({
136
+ accountID: "Your Account No.",
137
+ clientID: "Your client ID.",
138
+ clientSecret: "Your client secret.",
139
+ refreshToken: "Your initial refresh token.",
140
+ tokenStorage: new DatabaseTokenStorage(userId),
141
+ });
41
142
  ```
143
+
144
+ ## Example Requests
145
+
146
+ ```javascript
147
+ // Basic item request
42
148
  const item = await api.getItem(7947, '["Category", "Images"]');
43
149
  console.log(item);
44
150
 
45
- 7497 being the itemID. You can pass required relations as above.
151
+ // Get all items
152
+ const allItems = await api.getItems();
153
+
154
+ // Get limited number of items
155
+ const firstTenItems = await api.getItems(null, 10);
156
+
157
+ // Search for items
158
+ const searchResults = await api.searchItems("iPhone", '["Category"]');
159
+
160
+ // Get low stock items
161
+ const lowStockItems = await api.getItemsWithLowStock(10, '["Category"]');
162
+
163
+ // Bulk update items
164
+ const updates = [
165
+ { itemID: 123, data: { description: "Updated description" } },
166
+ { itemID: 456, data: { qoh: 50 } },
167
+ ];
168
+ const results = await api.updateMultipleItems(updates);
169
+
170
+ // Check API connection
171
+ const status = await api.ping();
172
+ console.log(status);
173
+
174
+ // Check API connection
175
+ const status = await api.ping();
176
+ console.log(status);
177
+ ```
178
+
179
+ ## Token Storage Options
180
+
181
+ ### Built-in Storage Classes
182
+
183
+ 1. **InMemoryTokenStorage** (default) - Stores tokens in memory only
184
+ 2. **FileTokenStorage** - Stores tokens in a JSON file
185
+
186
+ ### Custom Storage Interface
187
+
188
+ Implement your own storage by creating a class with these methods:
189
+
190
+ ```javascript
191
+ class CustomTokenStorage {
192
+ async getTokens() {
193
+ // Return an object with: { access_token, refresh_token, expires_at }
194
+ }
195
+
196
+ async setTokens(tokens) {
197
+ // Store the tokens object: { access_token, refresh_token, expires_at, expires_in }
198
+ }
199
+ }
200
+ ```
201
+
202
+ ## Migration from Previous Versions
203
+
204
+ If you're upgrading from a previous version:
205
+
206
+ 1. **Update your refresh token** by making one call to the new OAuth endpoint
207
+ 2. **Implement token storage** to persist the rotating tokens
208
+ 3. **Update token URLs** (handled automatically by the SDK)
209
+ 4. **Ensure storage can handle longer tokens** (new tokens are significantly longer)
210
+
211
+ ## API Methods
212
+
213
+ ### Core Resources
214
+
215
+ #### Customers
216
+
217
+ - `getCustomer(id, relations)` - Fetch a specific customer by ID
218
+ - `getCustomers(relations)` - Retrieve all customers
219
+ - `putCustomer(id, data)` - Update a customer
220
+ - `postCustomer(data)` - Create a new customer
221
+ - `searchCustomers(searchTerm, relations)` - Search customers by name or email
222
+
223
+ #### Items
224
+
225
+ - `getItem(id, relations)` - Fetch a specific item by ID
226
+ - `getItems(relations, limit)` - Retrieve all items (or limited number if limit specified)
227
+ - `getMultipleItems(items, relations)` - Get multiple items by IDs
228
+ - `putItem(id, data)` - Update an item
229
+ - `postItem(data)` - Create a new item
230
+ - `getVendorItems(vendorID, relations)` - Get items by vendor
231
+ - `searchItems(searchTerm, relations)` - Search items by description
232
+ - `getItemsByCategory(categoryId, relations)` - Get items in a category
233
+ - `getItemsWithLowStock(threshold, relations)` - Get items below stock threshold
234
+ - `updateMultipleItems(updates)` - Bulk update multiple items
235
+
236
+ #### Matrix Items
237
+
238
+ - `getMatrixItem(id, relations)` - Fetch a specific matrix item by ID
239
+ - `getMatrixItems(relations)` - Retrieve all matrix items
240
+ - `putMatrixItem(id, data)` - Update a matrix item
241
+ - `postMatrixItem(data)` - Create a new matrix item
242
+
243
+ #### Categories
244
+
245
+ - `getCategory(id, relations)` - Fetch a specific category by ID
246
+ - `getCategories(relations)` - Retrieve all categories
247
+ - `putCategory(id, data)` - Update a category
248
+ - `postCategory(data)` - Create a new category
249
+
250
+ #### Manufacturers
251
+
252
+ - `getManufacturer(id, relations)` - Fetch a specific manufacturer by ID
253
+ - `getManufacturers(relations)` - Retrieve all manufacturers
254
+ - `putManufacturer(id, data)` - Update a manufacturer
255
+ - `postManufacturer(data)` - Create a new manufacturer
256
+
257
+ #### Vendors
258
+
259
+ - `getVendor(id, relations)` - Fetch a specific vendor by ID
260
+ - `getVendors(relations)` - Retrieve all vendors
261
+ - `putVendor(id, data)` - Update a vendor
262
+ - `postVendor(data)` - Create a new vendor
263
+
264
+ #### Orders
265
+
266
+ - `getOrder(id, relations)` - Fetch a specific order by ID
267
+ - `getOrders(relations)` - Retrieve all orders
268
+ - `getOrdersByVendorID(id, relations)` - Get orders by vendor
269
+ - `getOpenOrdersByVendorID(id, relations)` - Get open orders by vendor
270
+
271
+ #### Sales
272
+
273
+ - `getSale(id, relations)` - Fetch a specific sale by ID
274
+ - `getSales(relations)` - Retrieve all sales
275
+ - `getMultipleSales(saleIDs, relations)` - Get multiple sales by IDs
276
+ - `getSalesByDateRange(startDate, endDate, relations)` - Get sales in date range
277
+ - `putSale(id, data)` - Update a sale
278
+ - `postSale(data)` - Create a new sale
279
+
280
+ #### Sale Lines
281
+
282
+ - `getSaleLinesByItem(itemID, relations)` - Get sale lines for an item
283
+ - `getSaleLinesByItems(ids, startDate, endDate, relations)` - Get sale lines for multiple items with date filter
284
+ - `getSaleLinesByVendorID(id, startDate, endDate, relations)` - Get sale lines by vendor with date filter
285
+
286
+ ### Account & Configuration
287
+
288
+ #### Account Information
289
+
290
+ - `getAccount(relations)` - Get account/shop information
291
+
292
+ #### Employees
293
+
294
+ - `getEmployees(relations)` - Get all employees
295
+ - `getEmployee(id, relations)` - Get a specific employee
296
+
297
+ #### System Configuration
298
+
299
+ - `getCustomerTypes(relations)` - Get customer types
300
+ - `getRegisters(relations)` - Get registers/shops
301
+ - `getPaymentTypes(relations)` - Get payment types
302
+ - `getTaxClasses(relations)` - Get tax classes
303
+ - `getItemAttributes(relations)` - Get item attributes
304
+
305
+ ### Gift Cards & Special Orders
306
+
307
+ - `getGiftCards(relations)` - Get all gift cards
308
+ - `getGiftCard(id, relations)` - Get a specific gift card by code
309
+ - `getSpecialOrders(relations)` - Get special orders
310
+
311
+ ### Images
312
+
313
+ - `getImages(relations)` - Get all images
314
+ - `postImage(imageFilePath, metadata)` - Upload an image
315
+
316
+ ### Utility Methods
317
+
318
+ - `ping()` - Test API connection and authentication
319
+ - `refreshTokens()` - Force refresh of access tokens
320
+ - `getTokenInfo()` - Get current token status information
321
+
322
+ ## Error Handling
323
+
324
+ The SDK includes comprehensive error handling with automatic retries for transient failures:
325
+
326
+ ```javascript
327
+ try {
328
+ const item = await api.getItem(123);
329
+ console.log(item);
330
+ } catch (error) {
331
+ console.error("API Error:", error.message);
332
+ // Error details are automatically logged by the SDK
333
+ }
46
334
  ```
47
335
 
48
- ## Methods
49
-
50
- - `getCustomer(id, relations)`: Fetches a specific customer by ID. Optionally, related data can be included.
51
- - `getCustomers(relations)`: Retrieves all customers. Optionally, related data can be included.
52
- - `getItem(id, relations)`: Fetches a specific item by ID. Optionally, related data can be included.
53
- - `getMultipleItems(items, relations)`: Retrieves multiple items by their IDs. Optionally, related data can be included.
54
- - `getItems(relations)`: Retrieves all items. Optionally, related data can be included.
55
- - `getvendorItems(vendorID, relations)`: Retrieves all items for a specific vendor. Optionally, related data can be included.
56
- - `getMatrixItems(relations)`: Fetches all matrix items. Optionally, related data can be included.
57
- - `getMatrixItem(id, relations)`: Fetches a specific matrix item by ID. Optionally, related data can be included.
58
- - `getCategory(id, relations)`: Retrieves a specific category by ID. Optionally, related data can be included.
59
- - `getCategories(relations)`: Retrieves all categories. Optionally, related data can be included.
60
- - `getManufacturer(id, relations)`: Fetches a specific manufacturer by ID. Optionally, related data can be included.
61
- - `getManufacturers(relations)`: Retrieves all manufacturers. Optionally, related data can be included.
62
- - `getOrder(id, relations)`: Fetches a specific order by ID. Optionally, related data can be included.
63
- - `getOrders(relations)`: Retrieves all orders. Optionally, related data can be included.
64
- - `getOrdersByVendorID(id, relations)`: Retrieves all orders for a specific vendor. Optionally, related data can be included.
65
- - `getOpenOrdersByVendorID(id, relations)`: Fetches all open orders for a specific vendor. Optionally, related data can be included.
66
- - `getVendor(id, relations)`: Fetches a specific vendor by ID. Optionally, related data can be included.
67
- - `getVendors(relations)`: Retrieves all vendors. Optionally, related data can be included.
68
- - `getSale(id, relations)`: Fetches a specific sale by ID. Optionally, related data can be included.
69
- - `getSales(relations)`: Retrieves all sales. Optionally, related data can be included.
70
- - `getMultipleSales(saleIDs, relations)`: Fetches multiple sales by their IDs. Optionally, related data can be included.
71
- - `getSaleLinesByItem(itemID, relations)`: Retrieves sale lines for a specific item. Optionally, related data can be included.
72
- - `getSaleLinesByItems(ids, startDate, endDate, relations)`: Retrieves sale lines for multiple items, filtered by date range. Optionally, related data can be included.
73
- - `getSaleLinesByVendorID(id, startDate, endDate, relations)`: Fetches sale lines for a specific vendor, filtered by date range. Optionally, related data can be included.
74
- - `getSpecialOrders(relations)`: Fetches special orders. Optionally, related data can be included.
336
+ ## Rate Limiting
337
+
338
+ The SDK automatically handles Lightspeed's API rate limits by:
339
+
340
+ - Monitoring rate limit headers
341
+ - Calculating appropriate delays
342
+ - Automatically waiting when limits are approached
343
+
344
+ ## Pagination
345
+
346
+ For endpoints that return large datasets, the SDK automatically handles pagination:
347
+
348
+ ```javascript
349
+ // This will automatically fetch all pages
350
+ const allItems = await api.getItems();
351
+ console.log(`Retrieved ${allItems.length} items`);
352
+ ```
75
353
 
76
354
  ## Contributing
77
355
 
78
- Contributions are welcome!
356
+ Contributions are welcome! Please feel free to submit a Pull Request.
79
357
 
80
358
  ## License
81
359
 
@@ -87,4 +365,5 @@ This SDK is not officially affiliated with Lightspeed HQ and is provided "as is"
87
365
 
88
366
  ## More Info
89
367
 
90
- The documentation for the Lightspeed Retail API can be found at https://developers.lightspeedhq.com/retail/introduction/introduction/
368
+ - [Lightspeed Retail API Documentation](https://developers.lightspeedhq.com/retail/introduction/introduction/)
369
+ - [New OAuth Documentation](https://developers.lightspeedhq.com/retail/authentication/oauth/)